Check in prebuilt protoc compiler and protobuf python lib

Updated to latest protobuf version 21.9, proceeding as follow:

1. Download libprotobuf from
https://github.com/protocolbuffers/protobuf/releases/download/v21.9/protobuf-all-21.9.zip

2. Goto protobuf-all-21.9/python

3. python setup.py build

4. Copy `python` folder from protobuf-all-21.9 to
   the local path for `prebuilts/libprotobuf/linux`

5. Copy `src` folder from protobuf-all-21.9 to
   the local path for `prebuilts/libprotobuf/linux`,
   this is necessary for unit tests.

6. Copy `LICENSE`, `CHANGES.txt` from protobuf-all-21.9 to
   the local path for `prebuilts/libprotobuf/linux`

6. Download the prebuilt protoc compiler from
   https://github.com/protocolbuffers/protobuf/releases/download/v21.9/protoc-21.9-linux-x86_64.zip

7. Copy `bin` folder, `include` folder, `readme.txt`
   from protoc-21.9-linux-x86_64 into
   the local path for `prebuilts/libprotobuf/linux`

8. Update `METADATA` file

Bug: None
Change-Id: I8bfee218492ca001e951cb4adcc8929d14259767
(cherry picked from commit fbc6810e0ea7322e5ed7c80662ddc4aad97fe60d)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 0000000..79c5b29
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,3475 @@
+2022-10-26 version 21.9 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  C++

+  * Update zlib to 1.2.13 (#10819)

+

+  Python

+  * Target MacOS 10.9 to fix #10799 (#10807)

+

+  Ruby

+  * Replace libc strdup usage with internal impl to restore musl compat (#10818)

+

+2022-10-18 version 21.8 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  Other

+  * Fix for grpc.tools #17995 & protobuf #7474 (handle UTF-8 paths in argumentfile) (#10721)

+

+  C++

+  * 21.x No longer define no_threadlocal on OpenBSD (#10743)

+

+  Java

+  * Mark default instance as immutable first to avoid race during static initialization of default instances (#10771)

+

+  Ruby

+  * Auto capitalize enums name in Ruby (#10454) (#10763)

+

+

+2022-09-29 version 21.7 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+  Java

+  * Refactoring java full runtime to reuse sub-message builders and prepare to

+    migrate parsing logic from parse constructor to builder.

+  * Move proto wireformat parsing functionality from the private "parsing

+    constructor" to the Builder class.

+  * Change the Lite runtime to prefer merging from the wireformat into mutable

+    messages rather than building up a new immutable object before merging. This

+    way results in fewer allocations and copy operations.

+  * Make message-type extensions merge from wire-format instead of building up

+    instances and merging afterwards. This has much better performance.

+  * Fix TextFormat parser to build up recurring (but supposedly not repeated)

+    sub-messages directly from text rather than building a new sub-message and

+    merging the fully formed message into the existing field.

+

+2022-09-13 version 21.6 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+C++

+* Reduce memory consumption of MessageSet parsing

+

+2022-08-09 version 21.5 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  PHP

+  * Added getContainingOneof and getRealContainingOneof to descriptor.

+  * fix PHP readonly legacy files for nested messages

+

+  Python

+  * Fixed comparison of maps in Python.

+

+

+2022-07-25 version 21.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  C++

+  * Reduce the required alignment of ArenaString from 8 to 4 (#10298)

+

+

+2022-07-19 version 21.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+  C++

+  * Add header search paths to Protobuf-C++.podspec (#10024)

+  * Fixed Visual Studio constinit errors (#10232)

+  * Fix #9947: make the ABI compatible between debug and non-debug builds (#10271)

+

+  UPB

+  * Allow empty package names (fixes behavior regression in 4.21.0)

+  * Fix a SEGV bug when comparing a non-materialized sub-message (#10208)

+  * Fix several bugs in descriptor mapping containers (eg. descriptor.services_by_name)

+    * for x in mapping now yields keys rather than values, to match Python conventions and the behavior of the old library.

+    * Lookup operations now correctly reject unhashable types as map keys.

+    * We implement repr() to use the same format as dict.

+  * Fix maps to use the ScalarMapContainer class when appropriate

+  * Fix bug when parsing an unknown value in a proto2 enum extension (protocolbuffers/upb#717)

+

+  PHP

+  * Add "readonly" as a keyword for PHP and add previous classnames to descriptor pool (#10041)

+

+  Python

+  * Make //:protobuf_python and //:well_known_types_py_pb2 public (#10118)

+

+  Bazel

+  * Add back a filegroup for :well_known_protos (#10061)

+

+2022-06-27 version 21.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+  C++

+  * ArenaString improvements (fix alignment issue)

+

+  PHP

+  * API changes for OneOf  (#10102)

+

+

+2022-05-27 version 21.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  C++

+  * cmake: Revert "Fix cmake install targets (#9822)" (#10060)

+  * Remove Abseil dependency from CMake build (#10056)

+

+  Python

+  * Update python wheel metadata with more information incl. required python version (#10058)

+  * Fix segmentation fault when instantiating field via repeated field assignment (#10066)

+

+2022-05-25 version 21.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  C++

+  * cmake: Call get_filename_component() with DIRECTORY mode instead of PATH mode (#9614)

+  * Escape GetObject macro inside protoc-generated code (#9739)

+  * Update CMake configuration to add a dependency on Abseil (#9793)

+  * Fix cmake install targets (#9822)

+  * Use __constinit only in GCC 12.2 and up (#9936)

+

+  Java

+  * Update protobuf_version.bzl to separate protoc and per-language java … (#9900)

+

+  Python

+  * Increment python major version to 4 in version.json for python upb (#9926)

+  * The C extension module for Python has been rewritten to use the upb library.

+    This is expected to deliver significant performance benefits, especially when

+    parsing large payloads.  There are some minor breaking changes, but these

+    should not impact most users.  For more information see:

+    https://developers.google.com/protocol-buffers/docs/news/2022-05-06#python-updates

+  * Fixed win32 build and fixed str(message) on all Windows platforms. (#9976)

+  * The binary wheel for macOS now supports Apple silicon.

+

+  PHP

+  * [PHP] fix PHP build system (#9571)

+  * Fix building packaged PHP extension (#9727)

+  * fix: reserve "ReadOnly" keyword for PHP 8.1 and add compatibility (#9633)

+  * fix: phpdoc syntax for repeatedfield parameters (#9784)

+  * fix: phpdoc for repeatedfield (#9783)

+  * Change enum string name for reserved words (#9780)

+  * chore: [PHP] fix phpdoc for MapField keys (#9536)

+  * Fixed PHP SEGV by not writing to shared memory for zend_class_entry. (#9996)

+

+  Ruby

+  * Allow pre-compiled binaries for ruby 3.1.0 (#9566)

+  * Implement `respond_to?` in RubyMessage (#9677)

+  * [Ruby] Fix RepeatedField#last, #first inconsistencies (#9722)

+  * Do not use range based UTF-8 validation in truffleruby (#9769)

+  * Improve range handling logic of `RepeatedField` (#9799)

+  * Support x64-mingw-ucrt platform

+

+  Other

+  * [Kotlin] remove redundant public modifiers for compiled code (#9642)

+  * [C#] Update GetExtension to support getting typed value (#9655)

+  * Fix invalid dependency manifest when using `descriptor_set_out` (#9647)

+  * Fix C# generator handling of a field named "none" in a oneof (#9636)

+  * Add initial version.json file for 21-dev (#9840)

+  * Remove duplicate java generated code (#9909)

+  * Cherry-pick PR #9981 into 21.x branch (#10000)

+

+

+2022-05-19 version 21.0-rc2(C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  Python

+  * Fix windows builds

+  * Throw more helpful error if generated code is out of date

+  * Fixed two reference leaks

+

+  Ruby

+  * Support x64-mingw-ucrt platform

+

+  PHP

+  * Fix SEGV by not writing to shared memory for zend_class_entry

+

+  C#

+  * Suppress warning CS8981

+

+  Other

+  * Fix Maven release to release actual osx_aarch64 binary

+  * Fix protoc zips to have the proto files for well known types

+

+2022-05-10 version 21.0-rc1 (C++/Java/Python/PHP/Objective-C/C#/Ruby)

+

+  C++

+  * Rename main cmake/CMakeLists.txt to CMakeLists.txt (#9603)

+  * avoid allocating memory if all extension are cleared (#9345)

+  * cmake: Call get_filename_component() with DIRECTORY mode instead of PATH mode (#9614)

+  * Escape GetObject macro inside protoc-generated code (#9739)

+  * Update CMake configuration to add a dependency on Abseil (#9793)

+  * Use __constinit only in GCC 12.2 and up (#9936)

+  * Refactor generated message class layout

+  * Optimize tokenizer ParseInteger by removing division

+  * Reserve exactly the right amount of capacity in ExtensionSet::MergeFrom

+  * Parse FLT_MAX correctly when represented in JSON

+

+  Java

+  * Update protobuf_version.bzl to separate protoc and per-language java … (#9900)

+  * 6x speedup in ArrayEncoder.writeUInt32NotTag

+

+  Python

+  * Increment python major version to 4 in version.json for python upb (#9926)

+  * The C extension module for Python has been rewritten to use the upb library.

+    This is expected to deliver significant performance benefits, especially when

+    parsing large payloads.  There are some minor breaking changes, but these

+    should not impact most users.  For more information see:

+    https://developers.google.com/protocol-buffers/docs/news/2022-05-06#python-updates

+  * Due to the breaking changes for Python, the major version number for Python

+    has been incremented.

+  * The binary wheel for macOS now supports Apple silicon.

+

+

+  PHP

+  * chore: [PHP] fix phpdoc for MapField keys (#9536)

+  * [PHP] Remove unnecessary zval initialization (#9600)

+  * [PHP] fix PHP build system (#9571)

+  * Fix building packaged PHP extension (#9727)

+  * fix: reserve "ReadOnly" keyword for PHP 8.1 and add compatibility (#9633)

+  * fix: phpdoc syntax for repeatedfield parameters (#9784)

+  * fix: phpdoc for repeatedfield (#9783)

+  * Change enum string name for reserved words (#9780)

+  * Fixed composer.json to only advertise compatibility with PHP 7.0+.  (#9819)

+

+  Ruby

+  * Allow pre-compiled binaries for ruby 3.1.0 (#9566)

+  * Implement `respond_to?` in RubyMessage (#9677)

+  * [Ruby] Fix RepeatedField#last, #first inconsistencies (#9722)

+  * Do not use range based UTF-8 validation in truffleruby (#9769)

+  * Improve range handling logic of `RepeatedField` (#9799)

+  * Disable the aarch64 build on macOS until it can be fixed. (#9816)

+

+  Other

+  * [Kotlin] remove redundant public modifiers for compiled code (#9642)

+  * [C#] Update GetExtension to support getting typed value (#9655)

+  * Fix invalid dependency manifest when using `descriptor_set_out` (#9647)

+  * Fix C# generator handling of a field named "none" in a oneof (#9636)

+  * Add initial version.json file for 21-dev (#9840)

+  * Remove duplicate java generated code (#9909)

+  * Fix versioning issues in 3.20.0

+

+  Compiler

+  * Protoc outputs the list of suggested field numbers when invalid field

+    numbers are specified in the .proto file.

+  * Require package names to be less than 512 bytes in length

+

+2022-04-21 version 3.20.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  PHP

+  * Fix building packaged PHP extension (#9727)

+

+  Other

+  * Fix versioning issues in 3.20.0

+

+2022-03-04 version 3.20.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Dropped Ruby 2.3 and 2.4 support for CI and releases. (#9311)

+  * Added Ruby 3.1 support for CI and releases (#9566).

+  * Message.decode/encode: Add recursion_limit option (#9218/#9486)

+  * Allocate with xrealloc()/xfree() so message allocation is visible to the

+    Ruby GC.  In certain tests this leads to much lower memory usage due to more

+    frequent GC runs (#9586).

+  * Fix conversion of singleton classes in Ruby (#9342)

+  * Suppress warning for intentional circular require (#9556)

+  * JSON will now output shorter strings for double and float fields when possible

+    without losing precision.

+  * Encoding and decoding of binary format will now work properly on big-endian

+    systems.

+  * UTF-8 verification was fixed to properly reject surrogate code points.

+  * Unknown enums for proto2 protos now properly implement proto2's behavior of

+    putting such values in unknown fields.

+

+  Java

+  * Revert "Standardize on Array copyOf" (#9400)

+  * Resolve more java field accessor name conflicts (#8198)

+  * Don't support map fields in DynamicMessage.Builder.{getFieldBuilder,getRepeatedFieldBuilder}

+  * Fix parseFrom to only throw InvalidProtocolBufferException

+  * InvalidProtocolBufferException now allows arbitrary wrapped Exception types.

+  * Fix bug in `FieldSet.Builder.mergeFrom`

+  * Flush CodedOutputStream also flushes underlying OutputStream

+  * When oneof case is the same and the field type is Message, merge the

+    subfield. (previously it was replaced.)’

+  * Add @CheckReturnValue to some protobuf types

+  * Report original exceptions when parsing JSON

+  * Add more info to @deprecated javadoc for set/get/has methods

+  * Fix initialization bug in doc comment line numbers

+  * Fix comments for message set wire format.

+

+  Kotlin

+  * Add test scope to kotlin-test for protobuf-kotlin-lite (#9518)

+  * Add orNull extensions for optional message fields.

+  * Add orNull extensions to all proto3 message fields.

+

+  Python

+  * Dropped support for Python < 3.7 (#9480)

+  * Protoc is now able to generate python stubs (.pyi) with --pyi_out

+  * Pin multibuild scripts to get manylinux1 wheels back (#9216)

+  * Fix type annotations of some Duration and Timestamp methods.

+  * Repeated field containers are now generic in field types and could be used

+    in type annotations.

+  * Protobuf python generated codes are simplified. Descriptors and message

+    classes' definitions are now dynamic created in internal/builder.py.

+    Insertion Points for messages classes are discarded.

+  * has_presence is added for FieldDescriptor in python

+  * Loosen indexing type requirements to allow valid __index__() implementations

+    rather than only PyLongObjects.

+  * Fix the deepcopy bug caused by not copying message_listener.

+  * Added python JSON parse recursion limit (default 100)

+  * Path info is added for python JSON parse errors

+  * Pure python repeated scalar fields will not able to pickle. Convert to list

+    first.

+  * Timestamp.ToDatetime() now accepts an optional tzinfo parameter. If

+    specified, the function returns a timezone-aware datetime in the given time

+    zone. If omitted or None, the function returns a timezone-naive UTC datetime

+    (as previously).

+  * Adds client_streaming and server_streaming fields to MethodDescriptor.

+  * Add "ensure_ascii" parameter to json_format.MessageToJson. This allows smaller

+    JSON serializations with UTF-8 or other non-ASCII encodings.

+  * Added experimental support for directly assigning numpy scalars and array.

+  * Improve the calculation of public_dependencies in DescriptorPool.

+  * [Breaking Change] Disallow setting fields to numpy singleton arrays or repeated fields to numpy

+    multi-dimensional arrays. Numpy arrays should be indexed or flattened explicitly before assignment.

+

+  Compiler

+  * Migrate IsDefault(const std::string*) and UnsafeSetDefault(const std::string*)

+  * Implement strong qualified tags for TaggedPtr

+  * Rework allocations to power-of-two byte sizes.

+  * Migrate IsDefault(const std::string*) and UnsafeSetDefault(const std::string*)

+  * Implement strong qualified tags for TaggedPtr

+  * Make TaggedPtr Set...() calls explicitly spell out the content type.

+  * Check for parsing error before verifying UTF8.

+  * Enforce a maximum message nesting limit of 32 in the descriptor builder to

+    guard against stack overflows

+  * Fixed bugs in operators for RepeatedPtrIterator

+  * Assert a maximum map alignment for allocated values

+  * Fix proto1 group extension protodb parsing error

+  * Do not log/report the same descriptor symbol multiple times if it contains

+    more than one invalid character.

+  * Add UnknownFieldSet::SerializeToString and SerializeToCodedStream.

+  * Remove explicit default pointers and deprecated API from protocol compiler

+

+  Arenas

+  * Change Repeated*Field to reuse memory when using arenas.

+  * Implements pbarenaz for profiling proto arenas

+  * Introduce CreateString() and CreateArenaString() for cleaner semantics

+  * Fix unreferenced parameter for MSVC builds

+  * Add UnsafeSetAllocated to be used for one-of string fields.

+  * Make Arena::AllocateAligned() a public function.

+  * Determine if ArenaDtor related code generation is necessary in one place.

+  * Implement on demand register ArenaDtor for InlinedStringField

+

+  C++

+  * Enable testing via CTest (#8737)

+  * Add option to use external GTest in CMake (#8736)

+  * CMake: Set correct sonames for libprotobuf-lite.so and libprotoc.so (#8635) (#9529)

+  * Add cmake option `protobuf_INSTALL` to not install files (#7123)

+  * CMake: Allow custom plugin options e.g. to generate mocks (#9105)

+  * CMake: Use linker version scripts (#9545)

+  * Manually *struct Cord fields to work better with arenas.

+  * Manually destruct map fields.

+  * Generate narrower code

+  * Fix https://github.com/protocolbuffers/protobuf/issues/9378 by removing

+    shadowed _cached_size_ field

+  * Remove GetPointer() and explicit nullptr defaults.

+  * Add proto_h flag for speeding up large builds

+  * Add missing overload for reference wrapped fields.

+  * Add MergedDescriptorDatabase::FindAllFileNames()

+  * RepeatedField now defines an iterator type instead of using a pointer.

+  * Remove obsolete macros GOOGLE_PROTOBUF_HAS_ONEOF and GOOGLE_PROTOBUF_HAS_ARENAS.

+

+  PHP

+  * Fix: add missing reserved classnames (#9458)

+  * PHP 8.1 compatibility (#9370)

+

+  C#

+  * Fix trim warnings (#9182)

+  * Fixes NullReferenceException when accessing FieldDescriptor.IsPacked (#9430)

+  * Add ToProto() method to all descriptor classes (#9426)

+  * Add an option to preserve proto names in JsonFormatter (#6307)

+

+  Objective-C

+  * Add prefix_to_proto_package_mappings_path option. (#9498)

+  * Rename `proto_package_to_prefix_mappings_path` to `package_to_prefix_mappings_path`. (#9552)

+  * Add a generation option to control use of forward declarations in headers. (#9568)

+

+2022-01-28 version 3.19.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Python

+  * Make libprotobuf symbols local on OSX to fix issue #9395 (#9435)

+

+  Ruby

+  * Fixed a data loss bug that could occur when the number of `optional`

+    fields in a message is an exact multiple of 32. (#9440).

+

+  PHP

+  * Fixed a data loss bug that could occur when the number of `optional`

+    fields in a message is an exact multiple of 32. (#9440).

+

+2022-01-10 version 3.19.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Python

+  * Fix missing Windows wheel for Python 3.10 on PyPI

+

+2022-01-05 version 3.19.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Java

+  * Improve performance characteristics of UnknownFieldSet parsing (#9371)

+  * This release addresses a Security Advisory for Java users

+   (https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-wrvw-hg22-4m67)

+

+2022-01-05 version 3.18.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Java

+  * Improve performance characteristics of UnknownFieldSet parsing (#9371)

+  * This release addresses a Security Advisory for Java users

+   (https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-wrvw-hg22-4m67)

+

+2022-01-05 version 3.16.1 (Java)

+

+  Java

+  * Improve performance characteristics of UnknownFieldSet parsing (#9371)

+  * This release addresses a Security Advisory for Java users

+   (https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-wrvw-hg22-4m67)

+

+2021-10-28 version 3.19.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Bazel

+  * Ensure that release archives contain everything needed for Bazel (#9131)

+  * Align dependency handling with Bazel best practices (#9165)

+

+  JavaScript

+  * Fix `ReferenceError: window is not defined` when getting the global object (#9156)

+

+  Ruby

+  * Fix memory leak in MessageClass.encode (#9150)

+

+2021-10-15 version 3.19.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Make proto2::Message::DiscardUnknownFields() non-virtual

+  * Separate RepeatedPtrField into its own header file

+  * For default floating point values of 0, consider all bits significant

+  * cmake: support `MSVC_RUNTIME_LIBRARY` property (#8851)

+  * Fix shadowing warnings (#8926)

+  * Fix for issue #8484, constant initialization doesn't compile in msvc clang-cl environment (#8993)

+  * Fix build on AIX and SunOS (#8373) (#9065)

+  * Add Android stlport and default toolchains to BUILD. (#8290)

+

+  Java

+  * For default floating point values of 0, consider all bits significant

+  * Annotate `//java/com/google/protobuf/util/...` with nullness annotations

+  * Use ArrayList copy constructor (#7853)

+

+  Kotlin

+  * Switch Kotlin proto DSLs to be implemented with inline value classes

+  * Fix inlining and deprecation for repeated string fields in kotlin (#9120)

+

+  Python

+  * Proto2 DecodeError now includes message name in error message

+  * Make MessageToDict convert map keys to strings (#8122)

+  * Add python-requires in setup.py (#8989)

+  * Add python 3.10 (#9034)

+

+  JavaScript

+  * Skip exports if not available by CommonJS (#8856)

+  * JS: Comply with CSP no-unsafe-eval. (#8864)

+

+  PHP

+  * Added "object" as a reserved name for PHP (#8962)

+

+  Ruby

+  * Override Map.clone to use Map's dup method (#7938)

+  * Ruby: build extensions for arm64-darwin (#8232)

+  * Add class method Timestamp.from_time to ruby well known types (#8562)

+  * Adopt pure ruby DSL implementation for JRuby (#9047)

+  * Add size to Map class (#8068)

+  * Fix for descriptor_pb.rb: google/protobuf should be required first (#9121)

+

+  C#

+  * Correctly set ExtensionRegistry when parsing with MessageParser, but using an already existing CodedInputStream (#7246)

+  * [C#] Make FieldDescriptor propertyName public (#7642)

+

+2021-10-04 version 3.18.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Python

+  * Update setup.py to reflect that we now require at least Python 3.5 (#8989)

+  * Performance fix for DynamicMessage: force GetRaw() to be inlined (#9023)

+

+  Ruby

+  * Update ruby_generator.cc to allow proto2 imports in proto3 (#9003)

+

+2021-09-13 version 3.18.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Python

+  * Removed Python 2.x support.

+  * Pure python descriptor_pool.AddSerializedFile() will always build the

+    file and return FileDescriptor which is same with python c++ extension

+  * type errors thrown by MergeFrom now report fully qualified class names

+  * Protobuf python generated code are simplified. Some platforms that uses

+    "is"("is not") to compare the enum or descriptor's label/type may fail,

+    should use "=="("!=") instead.

+

+  C++

+  * Generated code now uses the c++11 standard integer types int{32,64}_t and

+    uint{32,64}_t

+  * Reduce memory usage of the DescriptorPool type.

+  * Moved the zero-argument New() method on messages to the base class (internal

+    optimization).

+  * Unused return values marked with `PROTOBUF_MUST_USE_RESULT` are now

+    correctly attributed.

+  * Demotes PrintPath log for maps in MessageDifferencer down from WARNING to

+    INFO.

+  * Make sure FullMessageName() is always private.

+  * Fix race condition in EnumDescriptor.

+  * Remove MessageLite::GetMaybeArenaPointer.

+

+  Java

+  * Add @deprecated javadoc for set/get/has methods

+  * correctly decode \? escape sequence in text protos

+  * Avoid depending on Objects.requireNonNull() until we can verify that no

+    users are depending on older Android versions.

+  * disallow null string map values in put and putAll

+  * Add `@CheckReturnValue` to `ByteString` API.

+  * Make the `hasPresence` method public in `FieldDescriptor`.

+  * Report more detailed messages in Duration and Timestamp proto parsing

+    errors.

+  * New Timestamps.fromDate utility method that converts a java.util.Date to a

+    Timestamp proto object.

+

+  Kotlin

+  * Generated Kotlin code is Explicit API mode compatible

+

+2021-09-13 version 3.18.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  C++

+  * Fix warnings raised by clang 11 (#8664)

+  * Make StringPiece constructible from std::string_view (#8707)

+  * Add missing capability attributes for LLVM 12 (#8714)

+  * Stop using std::iterator (deprecated in C++17). (#8741)

+  * Move field_access_listener from libprotobuf-lite to libprotobuf (#8775)

+  * Fix #7047 Safely handle setlocale (#8735)

+  * Remove deprecated version of SetTotalBytesLimit() (#8794)

+  * Support arena allocation of google::protobuf::AnyMetadata (#8758)

+  * Fix undefined symbol error around SharedCtor() (#8827)

+  * Fix default value of enum(int) in json_util with proto2 (#8835)

+  * Better Smaller ByteSizeLong

+  * Introduce event filters for inject_field_listener_events

+  * Reduce memory usage of DescriptorPool

+  * For lazy fields copy serialized form when allowed.

+  * Re-introduce the InlinedStringField class

+  * v2 access listener

+  * Reduce padding in the proto's ExtensionRegistry map.

+  * GetExtension performance optimizations

+  * Make tracker a static variable rather than call static functions

+  * Support extensions in field access listener

+  * Annotate MergeFrom for field access listener

+  * Fix incomplete types for field access listener

+  * Add map_entry/new_map_entry to SpecificField in MessageDifferencer. They

+    record the map items which are different in MessageDifferencer's reporter.

+  * Reduce binary size due to fieldless proto messages

+  * TextFormat: ParseInfoTree supports getting field end location in addition to

+    start.

+  * Fix repeated enum extension size in field listener

+  * Enable Any Text Expansion for Descriptors::DebugString()

+  * Switch from int{8,16,32,64} to int{8,16,32,64}_t

+  * Reduce memory usage of the DescriptorPool type.

+

+  Java

+  * Fix errorprone conflict (#8723)

+  * Removing deprecated TimeUtil class. (#8749)

+  * Optimized FieldDescriptor.valueOf() to avoid array copying.

+  * Removing deprecated TimeUtil class.

+  * Add Durations.parseUnchecked(String) and Timestamps.parseUnchecked(String)

+  * FieldMaskUtil: Add convenience method to mask the fields out of a given proto.

+

+  JavaScript

+  * Optimize binary parsing of repeated float64

+  * Fix for optimization when reading doubles from binary wire format

+  * Replace toArray implementation with toJSON.

+

+  Python

+  * Drops support for 2.7 and 3.5.

+

+  PHP

+  * Migrate PHP & Ruby to ABSL wyhash (#8854)

+  * Added support for PHP 8.1 (currently in RC1) to the C extension (#8964)

+  * Fixed PHP SEGV when constructing messages from a destructor. (#8969)

+

+  Ruby

+  * Move DSL implementation from C to pure Ruby (#8850)

+  * Fixed a memory bug with RepeatedField#+. (#8970)

+

+  Other

+  * [csharp] ByteString.CreateCodedInput should use ArraySegment offset and count (#8740)

+  * [ObjC] Add support for using the proto package to prefix symbols. (#8760)

+  * field_presence.md: fix Go example (#8788)

+

+

+  Kotlin

+  * Suppress NOTHING_TO_INLINE in Kotlin generated inline functions.

+

+2021-06-04 version 3.17.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Python

+  * Note: This is the last release to support Python 2.7. Future releases will

+    require Python >= 3.5.

+

+  C++

+  * Introduce FieldAccessListener.

+  * Stop emitting boilerplate {Copy/Merge}From in each ProtoBuf class

+  * Fixed some uninitialized variable warnings in generated_message_reflection.cc.

+

+  Kotlin

+  * Fix duplicate proto files error (#8699)

+

+  Java

+  * Fixed parser to check that we are at a proper limit when a sub-message has

+    finished parsing.

+

+2021-05-25 version 3.17.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Kotlin

+  * Fix duplicate class error (#8653)

+

+  PHP

+  * Fixed SEGV in sub-message getters for well-known types when message is unset

+    (#8670)

+

+2021-05-07 version 3.17.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  PHP

+  * Fixed PHP memory leaks and arginfo errors. (#8614)

+  * Fixed JSON parser to allow multiple values from the same oneof as long as

+    all but one are null.

+

+  Ruby

+  * Fixed memory bug: properly root repeated/map field when assigning. (#8639)

+  * Fixed JSON parser to allow multiple values from the same oneof as long as

+    all but one are null.

+

+

+2021-05-07 version 3.17.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Protocol Compiler

+  * Fix the generated source information for reserved values in Enums.

+

+  C++

+  * Fix -Wunused-parameter in map<string, int> fields (fixes #8494) (#8500)

+  * Use byteswap.h when building against musl libc (#8503)

+  * Fix -Wundefined-inline error when using SharedCtor() or SharedDtor() (#8532)

+  * Fix bug where `Descriptor::DebugString()` printed proto3 synthetic oneofs.

+  * Provide stable versions of `SortAndUnique()`.

+  * Make sure to cache proto3 optional message fields when they are cleared.

+  * Expose UnsafeArena methods to Reflection.

+  * Use std::string::empty() rather than std::string::size() > 0.

+

+  Kotlin

+  * Restrict extension setter and getter operators to non-nullable T.

+

+  Java

+  * updating GSON and Guava to more recent versions (#8524)

+  * Reduce the time spent evaluating isExtensionNumber by storing the extension

+    ranges in a TreeMap for faster queries. This is particularly relevant for

+    protos which define a large number of extension ranges, for example when

+    each tag is defined as an extension.

+  * Fix java bytecode estimation logic for optional fields.

+  * Optimize Descriptor.isExtensionNumber.

+

+  Python

+  * Add MethodDescriptor.CopyToProto() (#8327)

+  * Remove unused python_protobuf.{cc,h} (#8513)

+  * Start publishing python aarch64 manylinux wheels normally (#8530)

+  * Fix constness issue detected by MSVC standard conforming mode (#8568)

+  * Make JSON parsing match C++ and Java when multiple fields from the same

+    oneof are present and all but one is null.

+

+  Ruby

+  * Add support for proto3 json_name in compiler and field definitions (#8356)

+  * Fixed memory leak of Ruby arena objects. (#8461)

+  * Fix source gem compilation (#8471)

+  * Fix various exceptions in Ruby on 64-bit Windows (#8563)

+  * Fix crash when calculating Message hash values on 64-bit Windows (#8565)

+

+  Conformance Tests

+  * Added a conformance test for the case of multiple fields from the same

+    oneof.

+

+2021-04-06 version 3.16.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Other

+  * Opensourcing kotlin protos (#8272)

+  * Use a newer version of rules_proto, with the new rule `proto_descriptor_set` (#8469)

+

+  C++

+  * Fix compiler warnings issue found in conformance_test_runner #8189 (#8190)

+  * Fix MinGW-w64 build issues. (#8286)

+  * [Protoc] C++ Resolved an issue where NO_DESTROY and CONSTINIT are in incorrect order (#8296)

+  * Fix PROTOBUF_CONSTINIT macro redefinition (#8323)

+  * Delete StringPiecePod (#8353)

+  * Fix gcc error: comparison of unsigned expression in '>= 0' is always … (#8309)

+  * Fix cmake install on iOS (#8301)

+  * Create a CMake option to control whether or not RTTI is enabled (#8347)

+  * Fix endian.h location on FreeBSD (#8351)

+  * Refactor util::Status (#8354)

+  * Make util::Status more similar to absl::Status (#8405)

+  * Fix -Wsuggest-destructor-override for generated C++ proto classes. (#8408)

+  * Refactor StatusOr and StringPiece (#8406)

+  * Refactor uint128 (#8416)

+  * The ::pb namespace is no longer exposed due to conflicts.

+  * Allow MessageDifferencer::TreatAsSet() (and friends) to override previous

+    calls instead of crashing.

+  * Reduce the size of generated proto headers for protos with `string` or

+    `bytes` fields.

+  * Move arena() operation on uncommon path to out-of-line routine

+  * For iterator-pair function parameter types, take both iterators by value.

+  * Code-space savings and perhaps some modest performance improvements in

+    RepeatedPtrField.

+  * Eliminate nullptr check from every tag parse.

+  * Remove unused _$name$_cached_byte_size_ fields.

+  * Serialize extension ranges together when not broken by a proto field in the

+    middle.

+  * Do out-of-line allocation and deallocation of string object in ArenaString.

+  * Streamline ParseContext::ParseMessage<T> to avoid code bloat and improve

+    performance.

+  * New member functions RepeatedField::Assign, RepeatedPtrField::{Add, Assign}.

+  * Fix undefined behavior warning due to innocuous uninitialization of value

+    on an error path.

+  * Avoid expensive inlined code space for encoding message length for messages

+    >= 128 bytes and instead do a procedure call to a shared out-of-line routine.

+  * util::DefaultFieldComparator will be final in a future version of protobuf.

+    Subclasses should inherit from SimpleFieldComparator instead.

+

+  C#

+  * Add .NET 5 target and improve WriteString performance with SIMD (#8147)

+

+  Java

+  * deps: update JUnit and Truth (#8319)

+  * Detect invalid overflow of byteLimit and return InvalidProtocolBufferException as documented.

+  * Exceptions thrown while reading from an InputStream in parseFrom are now

+    included as causes.

+  * Support potentially more efficient proto parsing from RopeByteStrings.

+  * Clarify runtime of ByteString.Output.toStringBuffer().

+  * Added UnsafeByteOperations to protobuf-lite (#8426)

+

+  JavaScript

+  * Make Any.pack() chainable.

+

+  Python

+  * Fix some constness / char literal issues being found by MSVC standard conforming mode (#8344)

+  * Switch on "new" buffer API (#8339)

+  * Enable crosscompiling aarch64 python wheels under dockcross manylinux docker image (#8280)

+  * Fixed a bug in text format where a trailing colon was printed for repeated field.

+  * When TextFormat encounters a duplicate message map key, replace the current

+    one instead of merging.

+

+  Objective-C

+  * Move the class map to a CFDictionary. (#8328)

+

+  PHP

+  * read_property() handler is not supposed to return NULL (#8362)

+  * Changed parameter type from long to integer (#7613)

+  * fix: README supported PHP version for C extension (#8236)

+

+  Ruby

+  * Fixed quadratic memory usage when appending to arrays. (#8364)

+  * Fixed memory leak of Ruby arena objects. (#8461)

+  * Add support for proto3 json_name in compiler and field definitions. (#8356)

+

+  Other

+  * Some doc on AOT compilation and protobuf (#8294)

+  * [CMake] Ability to pass options to protoc executable from cmake (#8374)

+  * Add --fatal_warnings flag to treat warnings as errors (#8131)

+  * [bazel] Remove deprecated way to depend on googletest (#8396)

+  * add error returns missing from protoc to prevent it from exiting with… (#8409)

+

+

+2021-04-07 version 3.15.8 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Fixed memory leak of Ruby arena objects (#8461)

+

+2021-04-02 version 3.15.7 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Remove the ::pb namespace (alias) (#8423)

+

+  Ruby

+  * Fix unbounded memory growth for Ruby <2.7 (#8429)

+  * Fixed message equality in cases where the message type is different (#8434)

+

+2021-03-10 version 3.15.6 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Fixed bug in string comparison logic (#8386)

+

+2021-03-04 version 3.15.5 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Fixed quadratic memory use in array append (#8379)

+

+  PHP

+  * Fixed quadratic memory use in array append (#8379)

+

+  C++

+  * Do not disable RTTI by default in the CMake build (#8377)

+

+2021-03-02 version 3.15.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Fixed SEGV when users pass nil messages (#8363)

+  * Fixed quadratic memory usage when appending to arrays (#8364)

+

+  C++

+  * Create a CMake option to control whether or not RTTI is enabled (#8361)

+

+  PHP

+  * read_property() handler is not supposed to return NULL (#8362)

+

+2021-02-25 version 3.15.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Ruby <2.7 now uses WeakMap too, which prevents memory leaks. (#8341)

+

+2021-02-23 version 3.15.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Fix for FieldDescriptor.get(msg) (#8330)

+

+  C++

+  * Fix PROTOBUF_CONSTINIT macro redefinition (#8323)

+

+2021-02-05 version 3.15.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Bugfix for Message.[] for repeated or map fields (#8313)

+

+2021-02-05 version 3.15.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Protocol Compiler

+  * Optional fields for proto3 are enabled by default, and no longer require

+    the --experimental_allow_proto3_optional flag.

+

+  C++

+  * MessageDifferencer: fixed bug when using custom ignore with multiple

+    unknown fields

+  * Use init_seg in MSVC to push initialization to an earlier phase.

+  * Runtime no longer triggers -Wsign-compare warnings.

+  * Fixed -Wtautological-constant-out-of-range-compare warning.

+  * DynamicCastToGenerated works for nullptr input for even if RTTI is disabled

+  * Arena is refactored and optimized.

+  * Clarified/specified that the exact value of Arena::SpaceAllocated() is an

+    implementation detail users must not rely on. It should not be used in

+    unit tests.

+  * Change the signature of Any::PackFrom() to return false on error.

+  * Add fast reflection getter API for strings.

+  * Constant initialize the global message instances

+  * Avoid potential for missed wakeup in UnknownFieldSet

+  * Now Proto3 Oneof fields have "has" methods for checking their presence in

+    C++.

+  * Bugfix for NVCC

+  * Return early in _InternalSerialize for empty maps.

+  * Adding functionality for outputting map key values in proto path logging

+    output (does not affect comparison logic) and stop printing 'value' in the

+    path. The modified print functionality is in the

+    MessageDifferencer::StreamReporter.

+  * Fixed https://github.com/protocolbuffers/protobuf/issues/8129

+  * Ensure that null char symbol, package and file names do not result in a

+    crash.

+  * Constant initialize the global message instances

+  * Pretty print 'max' instead of numeric values in reserved ranges.

+  * Removed remaining instances of std::is_pod, which is deprecated in C++20.

+  * Changes to reduce code size for unknown field handling by making uncommon

+    cases out of line.

+  * Fix std::is_pod deprecated in C++20 (#7180)

+  * Fix some -Wunused-parameter warnings (#8053)

+  * Fix detecting file as directory on zOS issue #8051 (#8052)

+  * Don't include sys/param.h for _BYTE_ORDER (#8106)

+  * remove CMAKE_THREAD_LIBS_INIT from pkgconfig CFLAGS (#8154)

+  * Fix TextFormatMapTest.DynamicMessage issue#5136 (#8159)

+  * Fix for compiler warning issue#8145 (#8160)

+  * fix: support deprecated enums for GCC < 6 (#8164)

+  * Fix some warning when compiling with Visual Studio 2019 on x64 target (#8125)

+

+  Python

+  * Provided an override for the reverse() method that will reverse the internal

+    collection directly instead of using the other methods of the BaseContainer.

+  * MessageFactory.CreateProtoype can be overridden to customize class creation.

+  * Fix PyUnknownFields memory leak (#7928)

+  * Add macOS Big Sur compatibility (#8126)

+

+  JavaScript

+  * Generate `getDescriptor` methods with `*` as their `this` type.

+  * Enforce `let/const` for generated messages.

+  * js/binary/utils.js: Fix jspb.utils.joinUnsignedDecimalString to work with negative bitsLow and low but non-zero bitsHigh parameter. (#8170)

+

+  PHP

+  * Added support for PHP 8. (#8105)

+  * unregister INI entries and fix invalid read on shutdown (#8042)

+  * Fix PhpDoc comments for message accessors to include "|null". (#8136)

+  * fix: convert native PHP floats to single precision (#8187)

+  * Fixed PHP to support field numbers >=2**28. (#8235)

+  * feat: add support for deprecated fields to PHP compiler (#8223)

+  * Protect against stack overflow if the user derives from Message. (#8248)

+  * Fixed clone for Message, RepeatedField, and MapField. (#8245)

+  * Updated upb to allow nonzero offset minutes in JSON timestamps. (#8258)

+

+  Ruby

+  * Added support for Ruby 3. (#8184)

+  * Rewrote the data storage layer to be based on upb_msg objects from the

+    upb library. This should lead to much better parsing performance,

+    particularly for large messages. (#8184).

+  * Fill out JRuby support (#7923)

+  * [Ruby] Fix: (SIGSEGV) gRPC-Ruby issue on Windows. memory alloc infinite

+    recursion/run out of memory (#8195)

+  * Fix jruby support to handle messages nested more than 1 level deep (#8194)

+

+  Java

+  * Avoid possible UnsupportedOperationException when using CodedInputSteam

+    with a direct ByteBuffer.

+  * Make Durations.comparator() and Timestamps.comparator() Serializable.

+  * Add more detailed error information for dynamic message field type

+    validation failure

+  * Removed declarations of functions declared in java_names.h from

+    java_helpers.h.

+  * Now Proto3 Oneof fields have "has" methods for checking their presence in

+    Java.

+  * Annotates Java proto generated *_FIELD_NUMBER constants.

+  * Add -assumevalues to remove JvmMemoryAccessor on Android.

+

+  C#

+  * Fix parsing negative Int32Value that crosses segment boundary (#8035)

+  * Change ByteString to use memory and support unsafe create without copy (#7645)

+  * Optimize MapField serialization by removing MessageAdapter (#8143)

+  * Allow FileDescriptors to be parsed with extension registries (#8220)

+  * Optimize writing small strings (#8149)

+

+2020-11-11 version 3.14.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Protocol Compiler

+  * The proto compiler no longer requires a .proto filename when it is not

+    generating code.

+  * Added flag `--deterministic_output` to `protoc --encode=...`.

+  * Fixed deadlock when using google.protobuf.Any embedded in aggregate options.

+

+  C++

+  * Arenas are now unconditionally enabled. cc_enable_arenas no longer has

+    any effect.

+  * Removed inlined string support, which is incompatible with arenas.

+  * Fix a memory corruption bug in reflection when mixing optional and

+    non-optional fields.

+  * Make SpaceUsed() calculation more thorough for map fields.

+  * Add stack overflow protection for text format with unknown field values.

+  * FieldPath::FollowAll() now returns a bool to signal if an out-of-bounds

+    error was encountered.

+  * Performance improvements for Map.

+  * Minor formatting fix when dumping a descriptor to .proto format with

+    DebugString.

+  * UBSAN fix in RepeatedField (#2073).

+  * When running under ASAN, skip a test that makes huge allocations.

+  * Fixed a crash that could happen when creating more than 256 extensions in

+    a single message.

+  * Fix a crash in BuildFile when passing in invalid descriptor proto.

+  * Parser security fix when operating with CodedInputStream.

+  * Warn against the use of AllowUnknownExtension.

+  * Migrated to C++11 for-range loops instead of index-based loops where

+    possible. This fixes a lot of warnings when compiling with -Wsign-compare.

+  * Fix segment fault for proto3 optional (#7805)

+  * Adds a CMake option to build `libprotoc` separately (#7949)

+

+  Java

+  * Bugfix in mergeFrom() when a oneof has multiple message fields.

+  * Fix RopeByteString.RopeInputStream.read() returning -1 when told to read

+    0 bytes when not at EOF.

+  * Redefine remove(Object) on primitive repeated field Lists to avoid

+    autoboxing.

+  * Support "\u" escapes in textformat string literals.

+  * Trailing empty spaces are no longer ignored for FieldMask.

+  * Fix FieldMaskUtil.subtract to recursively remove mask.

+  * Mark enums with `@java.lang.Deprecated` if the proto enum has option

+    `deprecated = true;`.

+  * Adding forgotten duration.proto to the lite library (#7738)

+

+  Python

+  * Print google.protobuf.NullValue as null instead of "NULL_VALUE" when it is

+    used outside WKT Value/Struct.

+  * Fix bug occurring when attempting to deep copy an enum type in python 3.

+  * Add a setuptools extension for generating Python protobufs (#7783)

+  * Remove uses of pkg_resources in non-namespace packages. (#7902)

+  * [bazel/py] Omit google/__init__.py from the Protobuf runtime. (#7908)

+  * Removed the unnecessary setuptools package dependency for Python package (#7511)

+  * Fix PyUnknownFields memory leak (#7928)

+

+  PHP

+  * Added support for "==" to the PHP C extension (#7883)

+  * Added `==` operators for Map and Array. (#7900)

+  * Native C well-known types (#7944)

+  * Optimized away hex2bin() call in generated code (#8006)

+  * New version of upb, and a new hash function wyhash in third_party. (#8000)

+  * add missing hasOneof method to check presence of oneof fields (#8003)

+

+  Go:

+  * Update go_package options to reference google.golang.org/protobuf module.

+

+  C#:

+  * annotate ByteString.CopyFrom(ReadOnlySpan<byte>) as SecuritySafeCritical (#7701)

+  * Fix C# optional field reflection when there are regular fields too (#7705)

+  * Fix parsing negative Int32Value that crosses segment boundary (#8035)

+

+  Javascript:

+  * JS: parse (un)packed fields conditionally (#7379)

+

+2020-07-14 version 3.13.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  PHP:

+  * The C extension is completely rewritten. The new C extension has significantly

+    better parsing performance and fixes a handful of conformance issues. It will

+    also make it easier to add support for more features like proto2 and proto3 presence.

+  * The new C extension does not support PHP 5.x. PHP 5.x users can still use pure-PHP.

+

+  C++:

+  * Removed deprecated unsafe arena string accessors

+  * Enabled heterogeneous lookup for std::string keys in maps.

+  * Removed implicit conversion from StringPiece to std::string

+  * Fix use-after-destroy bug when the Map is allocated in the arena.

+  * Improved the randomness of map ordering

+  * Added stack overflow protection for text format with unknown fields

+  * Use std::hash for proto maps to help with portability.

+  * Added more Windows macros to proto whitelist.

+  * Arena constructors for map entry messages are now marked "explicit"

+    (for regular messages they were already explicit).

+  * Fix subtle aliasing bug in RepeatedField::Add

+  * Fix mismatch between MapEntry ByteSize and Serialize with respect to unset

+    fields.

+

+  Python:

+  * JSON format conformance fixes:

+    * Reject lowercase t for Timestamp json format.

+    * Print full_name directly for extensions (no camelCase).

+    * Reject boolean values for integer fields.

+    * Reject NaN, Infinity, -Infinity that is not quoted.

+    * Base64 fixes for bytes fields: accept URL-safe base64 and missing padding.

+  * Bugfix for fields/files named "async" or "await".

+  * Improved the error message when AttributeError is returned from __getattr__

+    in EnumTypeWrapper.

+

+  Java:

+  * Fixed a bug where setting optional proto3 enums with setFooValue() would

+    not mark the value as present.

+  * Add Subtract function to FieldMaskUtil.

+

+  C#:

+  * Dropped support for netstandard1.0 (replaced by support for netstandard1.1).

+    This was required to modernize the parsing stack to use the `Span<byte>`

+    type internally. (#7351)

+  * Add `ParseFrom(ReadOnlySequence<byte>)` method to enable GC friendly

+    parsing with reduced allocations and buffer copies. (#7351)

+  * Add support for serialization directly to a `IBufferWriter<byte>` or

+    to a `Span<byte>` to enable GC friendly serialization.

+    The new API is available as extension methods on the `IMessage` type. (#7576)

+  * Add `GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE` define to make

+    generated code compatible with old C# compilers (pre-roslyn compilers

+    from .NET framework and old versions of mono) that do not support

+    ref structs. Users that are still on a legacy stack that does

+    not support C# 7.2 compiler might need to use the new define

+    in their projects to be able to build the newly generated code. (#7490)

+  * Due to the major overhaul of parsing and serialization internals (#7351 and #7576),

+    it is recommended to regenerate your generated code to achieve the best

+    performance (the legacy generated code will still work, but might incur

+    a slight performance penalty).

+

+2020-07-28 version 3.12.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+This release contains no significant changes, but exists because 3.12.3 was

+mistakenly tagged at the wrong commit.

+

+2020-06-01 version 3.12.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Objective-C

+  * Tweak the union used for Extensions to support old generated code. #7573

+

+2020-05-26 version 3.12.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Simplified the template export macros to fix the build for mingw32. (#7539)

+

+  Objective-C

+  * Fix for the :protobuf_objc target in the Bazel BUILD file. (#7538)

+

+2020-05-20 version 3.12.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Ruby

+  * Re-add binary gems for Ruby 2.3 and 2.4. These are EOL upstream, however

+    many people still use them and dropping support will require more

+    coordination.

+

+2020-05-12 version 3.12.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  Protocol Compiler

+  * [experimental] Singular, non-message typed fields in proto3 now support

+    presence tracking. This is enabled by adding the "optional" field label and

+    passing the --experimental_allow_proto3_optional flag to protoc.

+    * For usage info, see docs/field_presence.md.

+    * During this experimental phase, code generators should update to support

+      proto3 presence, see docs/implementing_proto3_presence.md for instructions.

+  * Allow duplicate symbol names when multiple descriptor sets are passed on

+    the command-line, to match the behavior when multiple .proto files are passed.

+  * Deterministic `protoc --descriptor_set_out` (#7175)

+

+  C++

+  * [experimental] Added proto3 presence support.

+  * New descriptor APIs to support proto3 presence.

+  * Enable Arenas by default on all .proto files.

+  * Documented that users are not allowed to subclass Message or MessageLite.

+  * Mark generated classes as final; inheriting from protos is strongly discouraged.

+  * Add stack overflow protection for text format with unknown fields.

+  * Add accessors for map key and value FieldDescriptors.

+  * Add FieldMaskUtil::FromFieldNumbers().

+  * MessageDifferencer: use ParsePartial() on Any fields so the diff does not

+    fail when there are missing required fields.

+  * ReflectionOps::Merge(): lookup messages in the right factory, if it can.

+  * Added Descriptor::WellKnownTypes enum and Descriptor::well_known_type()

+    accessor as an easier way of determining if a message is a Well-Known Type.

+  * Optimized RepeatedField::Add() when it is used in a loop.

+  * Made proto move/swap more efficient.

+  * De-virtualize the GetArena() method in MessageLite.

+  * Improves performance of json_stream_parser.cc by factor 1000 (#7230)

+  * bug: #7076 undefine Windows OUT and OPTIONAL macros (#7087)

+  * Fixed a bug in FieldDescriptor::DebugString() that would erroneously print

+    an "optional" label for a field in a oneof.

+  * Fix bug in parsing bool extensions that assumed they are always 1 byte.

+  * Fix off-by-one error in FieldOptions::ByteSize() when extensions are present.

+  * Clarified the comments to show an example of the difference between

+    Descriptor::extension and DescriptorPool::FindAllExtensions.

+  * Add a compiler option 'code_size' to force optimize_for=code_size on all

+    protos where this is possible.

+

+  Java

+  * [experimental] Added proto3 presence support.

+  * Mark java enum _VALUE constants as @Deprecated if the enum field is deprecated

+  * reduce <clinit> size for enums with allow_alias set to true.

+  * Sort map fields alphabetically by the field's key when printing textproto.

+  * Fixed a bug in map sorting that appeared in -rc1 and -rc2 (#7508).

+  * TextFormat.merge() handles Any as top level type.

+  * Throw a descriptive IllegalArgumentException when calling

+    getValueDescriptor() on enum special value UNRECOGNIZED instead of

+    ArrayIndexOutOfBoundsException.

+  * Fixed an issue with JsonFormat.printer() where setting printingEnumsAsInts()

+    would override the configuration passed into includingDefaultValueFields().

+  * Implement overrides of indexOf() and contains() on primitive lists returned

+    for repeated fields to avoid autoboxing the list contents.

+  * Add overload to FieldMaskUtil.fromStringList that accepts a descriptor.

+  * [bazel] Move Java runtime/toolchains into //java (#7190)

+

+  Python

+  * [experimental] Added proto3 presence support.

+  * [experimental] fast import protobuf module, only works with cpp generated code linked in.

+  * Truncate 'float' fields to 4 bytes of precision in setters for pure-Python

+    implementation (C++ extension was already doing this).

+  * Fixed a memory leak in C++ bindings.

+  * Added a deprecation warning when code tries to create Descriptor objects

+    directly.

+  * Fix unintended comparison between bytes and string in descriptor.py.

+  * Avoid printing excess digits for float fields in TextFormat.

+  * Remove Python 2.5 syntax compatibility from the proto compiler generated _pb2.py module code.

+  * Drop 3.3, 3.4 and use single version docker images for all python tests (#7396)

+

+  JavaScript

+  * Fix js message pivot selection (#6813)

+

+  PHP

+  * Persistent Descriptor Pool (#6899)

+  * Implement lazy loading of php class for proto messages (#6911)

+  * Correct @return in Any.unpack docblock (#7089)

+  * Ignore unknown enum value when ignore_unknown specified (#7455)

+

+  Ruby

+  * [experimental] Implemented proto3 presence for Ruby. (#7406)

+  * Stop building binary gems for ruby <2.5 (#7453)

+  * Fix for wrappers with a zero value (#7195)

+  * Fix for JSON serialization of 0/empty-valued wrapper types (#7198)

+  * Call "Class#new" over rb_class_new_instance in decoding (#7352)

+  * Build extensions for Ruby 2.7 (#7027)

+  * assigning 'nil' to submessage should clear the field. (#7397)

+

+  C#

+  * [experimental] Add support for proto3 presence fields in C# (#7382)

+  * Mark GetOption API as obsolete and expose the "GetOptions()" method on descriptors instead (#7491)

+  * Remove Has/Clear members for C# message fields in proto2 (#7429)

+  * Enforce recursion depth checking for unknown fields (#7132)

+  * Fix conformance test failures for Google.Protobuf (#6910)

+  * Cleanup various bits of Google.Protobuf (#6674)

+  * Fix latest ArgumentException for C# extensions (#6938)

+  * Remove unnecessary branch from ReadTag (#7289)

+

+  Objective-C

+  * [experimental] ObjC Proto3 optional support (#7421)

+  * Block subclassing of generated classes (#7124)

+  * Use references to Obj C classes instead of names in descriptors. (#7026)

+  * Revisit how the WKTs are bundled with ObjC. (#7173)

+

+  Other

+  * Add a proto_lang_toolchain for javalite (#6882)

+  * [bazel] Update gtest and deprecate //external:{gtest,gtest_main} (#7237)

+  * Add application note for explicit presence tracking. (#7390)

+  * Howto doc for implementing proto3 presence in a code generator. (#7407)

+

+

+2020-02-14 version 3.11.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C#

+  * Fix latest ArgumentException for C# extensions (#7188)

+  * Enforce recursion depth checking for unknown fields (#7210)

+

+  Ruby

+  * Fix wrappers with a zero value (#7195)

+  * Fix JSON serialization of 0/empty-valued wrapper types (#7198)

+

+2020-01-31 version 3.11.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Add OUT and OPTIONAL to windows portability files (#7087)

+

+  PHP

+  * Refactored ulong to zend_ulong for php7.4 compatibility (#7147)

+  * Call register_class before getClass from desc to fix segfault (#7077)

+

+

+2019-12-10 version 3.11.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  PHP

+  * Make c extension portable for php 7.4 (#6968)

+

+

+2019-12-02 version 3.11.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  PHP

+  * Extern declare protobuf_globals (#6946)

+

+

+2019-11-19 version 3.11.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Make serialization method naming consistent

+  * Make proto runtime + generated code free of deprecation warnings

+  * Moved ShutdownProtobufLibrary() to message_lite.h.  For backward compatibility a declaration is still available in stubs/common.h, but users should prefer message_lite.h

+  * Removed non-namespace macro EXPECT_OK()

+  * Removed mathlimits.h from stubs in favor of using std::numeric_limits from C++11

+  * Fixed bug in parser when ending on a group tag

+  * Add a helper function to UnknownFieldSet to deal with the changing return value of message::unknown_fields()

+  * Fix incorrect use of string_view iterators

+  * Support direct pickling of nested messages

+  * Skip extension tag validation for MessageSet if unknown dependencies are allowed

+  * Updated deprecation macros to annotate deprecated code (#6612)

+  * Remove conversion warning in MapEntryFuncs::ByteSizeLong (#6766)

+  * Revert "Make shared libraries be able to link to MSVC static runtime libraries, so that VC runtime is not required." (#6914)

+

+  Java

+  * Remove the usage of MethodHandle, so that Android users prior to API version 26 can use protobuf-java

+  * Publish ProGuard config for javalite

+  * Fix for StrictMode disk read violation in ExtensionRegistryLite

+  * Include part of the ByteString's content in its toString().

+  * Include unknown fields when merging proto3 messages in Java lite builders

+

+  Python

+  * Add float_precision option in json format printer

+  * Optionally print bytes fields as messages in unknown fields, if possible

+  * FieldPath: fix testing IsSet on root path ''

+  * Experimental code gen (fast import protobuf module) which only work with cpp generated code linked in

+

+  JavaScript

+  * Remove guard for Symbol iterator for jspb.Map

+

+  PHP

+  * Avoid too much overhead in layout_init (#6716)

+  * Lazily Create Singular Wrapper Message (#6833)

+  * Implement lazy loading of php class for proto messages (#6911)

+

+  Ruby

+  * Ruby lazy wrappers optimization (#6797)

+

+  C#

+  * (RepeatedField): Capacity property to resize the internal array (#6530)

+  * Experimental proto2 support is now officially available (#4642, #5183, #5350, #5936)

+  * Getting started doc: https://github.com/protocolbuffers/protobuf/blob/master/docs/csharp/proto2.md

+  * Add length checks to ExtensionCollection (#6759)

+  * Optimize parsing of some primitive and wrapper types (#6843)

+  * Use 3 parameter Encoding.GetString for default string values (#6828)

+  * Change _Extensions property to normal body rather than expression (#6856)

+

+  Objective C

+  * Fixed unaligned reads for 32bit arm with newer Xcode versions (#6678)

+

+

+2019-09-03 version 3.10.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Switch the proto parser to the faster MOMI parser.

+  * Properly escape Struct keys in the proto3 JSON serializer.

+  * Fix crash on uninitialized map entries.

+  * Informed the compiler of has-bit invariant to produce better code

+  * Unused imports of files defining descriptor extensions will now be reported

+  * Add proto2::util::RemoveSubranges to remove multiple subranges in linear time.

+  * Added BaseTextGenerator::GetCurrentIndentationSize()

+  * Made implicit weak fields compatible with the Apple linker

+  * Support 32 bit values for ProtoStreamObjectWriter to Struct.

+  * Removed the internal-only header coded_stream_inl.h and the internal-only methods defined there.

+  * Enforced no SWIG wrapping of descriptor_database.h (other headers already had this restriction).

+  * Implementation of the equivalent of the MOMI parser for serialization. This removes one of the two serialization routines, by making the fast array serialization routine completely general. SerializeToCodedStream can now be implemented in terms of the much much faster array serialization. The array serialization regresses slightly, but when array serialization is not possible this wins big.

+  * Do not convert unknown field name to snake case to accurately report error.

+  * Fix a UBSAN warnings. (#6333)

+  * Add podspec for C++ (#6404)

+  * protoc: fix source code info location for missing label (#6436)

+  * C++ Add move constructor for Reflection's SetString (#6477)

+

+  Java

+  * Call loadDescriptor outside of synchronized block to remove one possible source of deadlock.

+  * Have oneof enums implement a separate interface (other than EnumLite) for clarity.

+  * Opensource Android Memory Accessors

+  * Update TextFormat to make use of the new TypeRegistry.

+  * Support getFieldBuilder and getRepeatedFieldBuilder in ExtendableBuilder

+  * Update JsonFormat to make use of the new TypeRegistry.

+  * Add proguard config generator for GmmBenchmarkSuiteLite.

+  * Change ProtobufArrayList to use Object[] instead of ArrayList for 5-10% faster parsing

+  * Implement ProtobufArrayList.add(E) for 20% (5%-40%) faster overall protolite2 parsing

+  * Make a copy of JsonFormat.TypeRegistry at the protobuf top level package. This will eventually replace JsonFormat.TypeRegistry.

+  * Fix javadoc warnings in generated files (#6231)

+  * Java: Add Automatic-Module-Name entries to the Manifest (#6568)

+

+  Python

+  * Add descriptor methods in descriptor_pool are deprecated.

+  * Uses explicit imports to prevent multithread test failures in py3.

+  * Added __delitem__ for Python extension dict

+  * Update six version to 1.12.0 and fix legacy_create_init issue (#6391)

+

+  JavaScript

+  * Remove deprecated boolean option to getResultBase64String().

+  * Fix sint64 zig-zag encoding.

+  * Simplify hash64 string conversion to avoid DIGIT array. Should reduce overhead if these functions aren't used, and be more efficient by avoiding linear array searches.

+  * Change the parameter types of binaryReaderFn in ExtensionFieldBinaryInfo to (number, ?, ?).

+  * Create dates.ts and time_of_days.ts to mirror Java versions. This is a near-identical conversion of c.g.type.util.{Dates,TimeOfDays} respectively.

+  * Migrate moneys to TypeScript.

+

+  PHP

+  * Fix incorrect leap day for Timestamp (#6696)

+  * Initialize well known type values (#6713)

+

+  Ruby

+  * Fix scope resolution for Google namespace (#5878)

+  * Support hashes for struct initializers (#5716)

+  * Optimized away the creation of empty string objects. (#6502)

+  * Roll forward Ruby upb changes now that protobuf Ruby build is fixed (#5866)

+  * Optimized layout_mark() for Ruby (#6521)

+  * Optimization for layout_init() (#6547)

+  * Fix for GC of Ruby map frames. (#6533)

+  * Fixed leap year handling by reworking upb_mktime() -> upb_timegm(). (#6695)

+

+  Objective C

+  * Remove OSReadLittle* due to alignment requirements (#6678)

+  * Don't use unions and instead use memcpy for the type swaps. (#6672)

+

+  Other

+  * Override CocoaPods module to lowercase (#6464)

+

+

+2019-06-28 version 3.9.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Optimize and simplify implementation of RepeatedPtrFieldBase

+  * Don't create unnecessary unknown field sets.

+  * Remove branch from accessors to repeated field element array.

+  * Added delimited parse and serialize util.

+  * Reduce size by not emitting constants for fieldnumbers

+  * Fix a bug when comparing finite and infinite field values with explicit tolerances.

+  * TextFormat::Parser should use a custom Finder to look up extensions by number if one is provided.

+  * Add MessageLite::Utf8DebugString() to make MessageLite more compatible with Message.

+  * Fail fast for better performance in DescriptorPool::FindExtensionByNumber() if descriptor has no defined extensions.

+  * Adding the file name to help debug colliding extensions

+  * Added FieldDescriptor::PrintableNameForExtension() and DescriptorPool::FindExtensionByPrintableName().

+    The latter will replace Reflection::FindKnownExtensionByName().

+  * Replace NULL with nullptr

+  * Created a new Add method in repeated field that allows adding a range of elements all at once.

+  * Enabled enum name-to-value mapping functions for C++ lite

+  * Avoid dynamic initialization in descriptor.proto generated code

+  * Move stream functions to MessageLite from Message.

+  * Move all zero_copy_stream functionality to io_lite.

+  * Do not create array of matched fields for simple repeated fields

+  * Enabling silent mode by default to reduce make compilation noise. (#6237)

+

+  Java

+  * Expose TextFormat.Printer and make it configurable. Deprecate the static methods.

+  * Library for constructing google.protobuf.Struct and google.protobuf.Value

+  * Make OneofDescriptor extend GenericDescriptor.

+  * Expose streamingness of service methods from MethodDescriptor.

+  * Fix a bug where TextFormat fails to parse Any filed with > 1 embedded message sub-fields.

+  * Establish consistent JsonFormat behavior for nulls in oneofs, regardless of order.

+  * Update GSON version to 3.8.5. (#6268)

+  * Add `protobuf_java_lite` Bazel target. (#6177)

+

+  Python

+  * Change implementation of Name() for enums that allow aliases in proto2 in Python

+    to be in line with claims in C++ implementation (to return first value).

+  * Explicitly say what field cannot be set when the new value fails a type check.

+  * Duplicate register in descriptor pool will raise errors

+  * Add __slots__ to all well_known_types classes, custom attributes are not allowed anymore.

+  * text_format only present 8 valid digits for float fields by default

+

+  JavaScript

+  * Add Oneof enum to the list of goog.provide

+

+  PHP

+  * Make php message class final to avoid mocking. (#6277)

+  * Rename get/setXXXValue to get/setXXXWrapper. (#6295)

+

+  Ruby

+  * Remove to_hash methods. (#6166)

+

+

+2019-04-29 version 3.8.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Use std::atomic<int32> in case of myriad2 platform

+  * Always declare enums to be int-sized

+  * Added DebugString() and ShortDebugString() methods on MessageLite

+  * Specialized different parse loop control flows

+  * Make hasbits potentially in register. The or's start forming an obstacle because it's a read modify store on the same mem address on each iteration.

+  * Move to an internal MACRO for parser validity checks.

+  * Improve map parsing performance.

+  * Make MergePartialFromCodedStream non virtual. This allows direct calls, potential inlining and is also a code health improvement

+  * Add an overall limit to parse_context to prevent reading past it. This allows to remove a annoying level of indirection.

+  * Fix a mistake, we shouldn't verify map key/value strings for utf8 in opt mode for proto2.

+  * Further improvements to cut binary size.

+  * Prepare to make MergePartialFromCodedStream non-virtual.

+  * A report on some interesting behavior change in python (caused by b/27494216) made me realize there is a check that needs to be done in case the parse ended on a end group tag.

+  * Add a note of caution to the comments around skip in CodedOutputStream.

+  * Simplify end check.

+  * Add overload for ParseMessage for MessageLite/Message types. If the explicit type is not known inlining won't help de-virtualizing the virtual call.

+  * Reduce linker input. It turns out that ParseMessage is not inlined, producing  template instantiations that are used only once and save nothing but cost more.

+  * Improve the parser.

+  * [c++17] Changed proto2::RepeatedPtrField iterators to no longer derive from the deprecated std::iterator class.

+  * Change the default value of case_insensitive_enum_parsing to false for JsonStringToMessage.

+  * Add a warning if a field name doesn't match the style guide.

+  * Fix TextFormat not round-trip correctly when float value is max float.

+  * Added locationed info for some errors at compiler

+  * Python reserved keywords are now working with getattr()/setattr() for most descriptors.

+  * Added AllowUnknownField() in text_format

+  * Append '_' to C++ reserved keywords for message, enum, extension

+  * Fix MSVC warning C4244 in protobuf's parse_context.h.

+  * Updating Iterators to be compatible with C++17 in MSVC.

+  * Use capability annotation in mutex.h

+  * Fix "UndefinedBehaviorSanitizer: cfi-bad-type"

+  * CriticalSectionLock class as a lightweight replacement for std::mutex on Windows platforms.

+  * Removed vestigial wire_format_lite_inl.h

+

+  C#

+  * Added System.Memory dependency.

+

+  Java

+  * Make Java protoc code generator ignore optimize_for LITE_RUNTIME. Users should instead use the Java lite protoc plugin.

+  * Change Extension getMessageDefaultInstance() to return Message instead of MessageLite.

+  * Prevent malicious input streams from leaking buffers for ByteString or ByteBuffer parsing.

+  * Release new Javalite runtime.

+  * Show warning in case potential file name conflict.

+  * Allow Java reserved keywords to be used in extensions.

+  * Added setAllowUnknownFields() in text format

+  * Add memoization to ExtensionRegistryLite.getEmptyRegistry()

+  * Improve performance of CodedOutputStream.writeUInt32NoTag

+  * Add an optimized mismatch-finding algorithm to UnsafeUtil.

+  * When serializing uint32 varints, check that we have MAX_VARINT32_SIZE bytes left, not just MAX_VARINT_SIZE.

+  * Minor optimization to RopeByteString.PieceIterator

+

+  JavaScript

+  * Simplify generated toObject code when the default value is used.

+

+  Python

+  * Changes implementation of Name() for enums that allow aliases in proto2 in Python to be in line with claims in C++ implementation (to return first value).

+  * Added double_format option in text format printer.

+  * Added iter and __contains__ to extension dict

+  * Added allow_unknown_field option in python text format parser

+  * Fixed Timestamp.ToDatetime() loses precision issue

+  * Support unknown field in text format printer.

+  * Float field will be convert to inf if bigger than struct.unpack('f', b'\xff\xff\x7f\x7f')[0] which is about 3.4028234664e+38,

+  convert to -inf if smaller than -3.4028234664e+38

+  * Allowed casting str->bytes in Message.__setstate__

+

+  Ruby

+  * Helper methods to get enum name for Ruby.

+

+

+2019-01-24 version 3.7.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Introduced new MOMI (maybe-outside-memory-interval) parser.

+  * Add an option to json_util to parse enum as case-insensitive. In the future, enum parsing in json_util will become case-sensitive.

+  * Added conformance test for enum aliases

+  * Added support for --cpp_out=speed:...

+  * Added use of C++ override keyword where appropriate

+  * Many other cleanups and fixes.

+

+  Java

+  * Fix illegal reflective access warning in JDK 9+

+  * Add BOM

+

+  Python

+  * Added Python 3.7 compatibility.

+  * Modified ParseFromString to return bytes parsed .

+  * Introduce Proto C API.

+  * FindFileContainingSymbol in descriptor pool is now able to find field and enum values.

+  * reflection.MakeClass()  and  reflection.ParseMessage() are deprecated.

+  * Added DescriptorPool.FindMethodByName() method in pure python (c extension already has it)

+  * Flipped proto3 to preserve unknown fields by default.

+  * Added support for memoryview in python3 proto message parsing.

+  * Added MergeFrom for repeated scalar fields in c extension (pure python already has it)

+  * Surrogates are now rejected at setters in python3.

+  * Added public unknown field API.

+  * RecursionLimit is also set to max if allow_oversize_protos is enabled.

+  * Disallow duplicate scalars in proto3 text_format parse.

+  * Fix some segment faults for c extension map field.

+

+  PHP

+  * Most issues for json encoding/decoding in the c extension have been fixed. There are still some edge cases not fixed. For more details, check conformance/failure_list_php_c.txt.

+  * Supports php 7.3

+  * Added helper methods to convert between enum values and names.

+  * Allow setting/getting wrapper message fields using primitive values.

+  * Various bug fixes.

+

+  Ruby

+  * Ruby 2.6 support.

+  * Drops support for ruby < 2.3.

+  * Most issues for json encoding/decoding in the c extension have been fixed. There are still some edge cases not fixed. For more details, check conformance/failure_list_ruby.txt.

+  * Json parsing can specify an option to ignore unknown fields: msg.decode_json(data, {ignore_unknown_fields: true}).

+  * Added support for proto2 syntax (partially).

+  * Various bug fixes.

+

+  Csharp

+  * More support for FieldMask include merge, intersect and more.

+  * Increasing the default recursion limit to 100.

+  * Support loading FileDescriptors dynamically.

+  * Provide access to comments from descriptors.

+  * Added Any.Is method.

+  * Compatible with C# 6

+  * Added IComparable and comparison operators on Timestamp.

+

+  Objective C

+  * Add ability to introspect list of enum values (#4678)

+  * Copy the value when setting message/data fields (#5215)

+  * Support suppressing the objc package prefix checks on a list of files (#5309)

+  * More complete keyword and NSObject method (via categories) checks for field names, can result in more fields being rename, but avoids the collisions at runtime (#5289)

+  * Small fixes to TextFormat generation for extensions (#5362)

+  * Provide more details/context in deprecation messages (#5412)

+  * Array/Dictionary enumeration blocks NS_NOESCAPE annotation for Swift (#5421)

+  * Properly annotate extensions for ARC when their names imply behaviors (#5427)

+  * Enum alias name collision improvements (#5480)

+

+

+2018-07-27 version 3.6.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Introduced workaround for Windows issue with std::atomic and std::once_flag

+    initialization (#4777, #4773).

+

+  PHP

+  * Added compatibility with PHP 7.3 (#4898).

+

+  Ruby

+  * Fixed Ruby crash involving Any encoding (#4718).

+

+2018-06-01 version 3.6.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+

+  C++

+  * Starting from this release, we now require C++11. For those we cannot yet

+    upgrade to C++11, we will try to keep the 3.5.x branch updated with

+    critical bug fixes only. If you have any concerns about this, please

+    comment on issue #2780.

+  * Moved to C++11 types like std::atomic and std::unique_ptr and away from our

+    old custom-built equivalents.

+  * Added support for repeated message fields in lite protos using implicit

+    weak fields. This is an experimental feature that allows the linker to

+    strip out more unused messages than previously was possible.

+  * Fixed SourceCodeInfo for interpreted options and extension range options.

+  * Fixed always_print_enums_as_ints option for JSON serialization.

+  * Added support for ignoring unknown enum values when parsing JSON.

+  * Create std::string in Arena memory.

+  * Fixed ValidateDateTime to correctly check the day.

+  * Fixed bug in ZeroCopyStreamByteSink.

+  * Various other cleanups and fixes.

+

+  Java

+  * Dropped support for Java 6.

+  * Added a UTF-8 decoder that uses Unsafe to directly decode a byte buffer.

+  * Added deprecation annotations to generated code for deprecated oneof

+    fields.

+  * Fixed map field serialization in DynamicMessage.

+  * Cleanup and documentation for Java Lite runtime.

+  * Various other fixes and cleanups

+  * Fixed unboxed arraylists to handle an edge case

+  * Improved performance for copying between unboxed arraylists

+  * Fixed lite protobuf to avoid Java compiler warnings

+  * Improved test coverage for lite runtime

+  * Performance improvements for lite runtime

+

+  Python

+  * Fixed bytes/string map key incompatibility between C++ and pure-Python

+    implementations (issue #4029)

+  * Added __init__.py files to compiler and util subpackages

+  * Use /MT for all Windows versions

+  * Fixed an issue affecting the Python-C++ implementation when used with

+    Cython (issue #2896)

+  * Various text format fixes

+  * Various fixes to resolve behavior differences between the pure-Python and

+    Python-C++ implementations

+

+  PHP

+  * Added php_metadata_namespace to control the file path of generated metadata

+    file.

+  * Changed generated classes of nested message/enum. E.g., Foo.Bar, which

+    previously generates Foo_Bar, now generates Foo/Bar

+  * Added array constructor. When creating a message, users can pass a php

+    array whose content is field name to value pairs into constructor. The

+    created message will be initialized according to the array. Note that

+    message field should use a message value instead of a sub-array.

+  * Various bug fixes.

+

+  Objective-C

+  * We removed some helper class methods from GPBDictionary to shrink the size

+    of the library, the functionary is still there, but you may need to do some

+    specific +alloc / -init… methods instead.

+  * Minor improvements in the performance of object field getters/setters by

+    avoiding some memory management overhead.

+  * Fix a memory leak during the raising of some errors.

+  * Make header importing completely order independent.

+  * Small code improvements for things the undefined behaviors compiler option

+    was flagging.

+

+  Ruby

+  * Added ruby_package file option to control the module of generated class.

+  * Various bug fixes.

+

+  Javascript

+  * Allow setting string to int64 field.

+

+  Csharp

+  * Unknown fields are now parsed and then sent back on the wire. They can be

+    discarded at parse time via a CodedInputStream option.

+  * Movement towards working with .NET 3.5 and Unity

+  * Expression trees are no longer used

+  * AOT generics issues in Unity/il2cpp have a workaround (see this commit for

+    details)

+  * Floating point values are now compared bitwise (affects NaN value

+    comparisons)

+  * The default size limit when parsing is now 2GB rather than 64MB

+  * MessageParser now supports parsing from a slice of a byte array

+  * JSON list parsing now accepts null values where the underlying proto

+    representation does

+

+2017-12-20 version 3.5.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Planned Future Changes

+  * Make C++ implementation C++11 only: we plan to require C++11 to build

+    protobuf code starting from 3.6.0 release. Please join this github issue:

+    https://github.com/protocolbuffers/protobuf/issues/2780 to provide your feedback.

+

+  protoc

+  * Fixed a bug introduced in 3.5.0 and protoc in Windows now accepts non-ascii

+    characters in paths again.

+

+  C++

+  * Removed several usages of C++11 features in the code base.

+  * Fixed some compiler warnings.

+

+  PHP

+  * Fixed memory leak in C-extension implementation.

+  * Added discardUnknokwnFields API.

+  * Removed duplicated typedef in C-extension headers.

+  * Avoided calling private php methods (timelib_update_ts).

+  * Fixed Any.php to use fully-qualified name for DescriptorPool.

+

+  Ruby

+  * Added Google_Protobuf_discard_unknown for discarding unknown fields in

+    messages.

+

+  C#

+  * Unknown fields are now preserved by default.

+  * Floating point values are now bitwise compared, affecting message equality

+    check and Contains() API in map and repeated fields.

+

+

+2017-11-13 version 3.5.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Planned Future Changes

+  * Make C++ implementation C++11 only: we plan to require C++11 to build

+    protobuf code starting from 3.6.0 release. Please join this github issue:

+    https://github.com/protocolbuffers/protobuf/issues/2780 to provide your feedback.

+

+  General

+  * Unknown fields are now preserved in proto3 for most of the language

+    implementations for proto3 by default. See the per-language section for

+    details.

+  * reserve keyword are now supported in enums

+

+  C++

+  * Proto3 messages are now preserving unknown fields by default. If you rely on

+    unknowns fields being dropped. Please use DiscardUnknownFields() explicitly.

+  * Deprecated the unsafe_arena_release_* and unsafe_arena_add_allocated_*

+    methods for string fields.

+  * Added move constructor and move assignment to RepeatedField,

+    RepeatedPtrField and google::protobuf::Any.

+  * Added perfect forwarding in Arena::CreateMessage

+  * In-progress experimental support for implicit weak fields with lite protos.

+    This feature allows the linker to strip out more unused messages and reduce

+    binary size.

+  * Various performance optimizations.

+

+  Java

+  * Proto3 messages are now preserving unknown fields by default. If you’d like

+    to drop unknown fields, please use the DiscardUnknownFieldsParser API. For

+    example:

+      Parser<Foo> parser = DiscardUnknownFieldsParser.wrap(Foo.parser());

+      Foo foo = parser.parseFrom(input);

+  * Added a new CodedInputStream decoder for Iterable<ByteBuffer> with direct

+    ByteBuffers.

+  * TextFormat now prints unknown length-delimited fields as messages if

+    possible.

+  * FieldMaskUtil.merge() no longer creates unnecessary empty messages when a

+    message field is unset in both source message and destination message.

+  * Various performance optimizations.

+

+  Python

+  * Proto3 messages are now preserving unknown fields by default. Use

+    message.DiscardUnknownFields() to drop unknown fields.

+  * Add FieldDescriptor.file in generated code.

+  * Add descriptor pool FindOneofByName in pure python.

+  * Change unknown enum values into unknown field set .

+  * Add more Python dict/list compatibility for Struct/ListValue.

+  * Add utf-8 support for text_format.Merge()/Parse().

+  * Support numeric unknown enum values for proto3 JSON format.

+  * Add warning for Unexpected end-group tag in cpp extension.

+

+  PHP

+  * Proto3 messages are now preserving unknown fields.

+  * Provide well known type messages in runtime.

+  * Add prefix ‘PB’ to generated class of reserved names.

+  * Fixed all conformance tests for encode/decode json in php runtime. C

+    extension needs more work.

+

+  Objective-C

+  * Fixed some issues around copying of messages with unknown fields and then

+    mutating the unknown fields in the copy.

+

+  C#

+  * Added unknown field support in JsonParser.

+  * Fixed oneof message field merge.

+  * Simplify parsing messages from array slices.

+

+  Ruby

+  * Unknown fields are now preserved by default.

+  * Fixed several bugs for segment fault.

+

+  Javascript

+  * Decoder can handle both paced and unpacked data no matter how the proto is

+    defined.

+  * Decoder now accept long varint for 32 bit integers.

+

+

+2017-08-14 version 3.4.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Planned Future Changes

+  * There are some changes that are not included in this release but are planned

+    for the near future

+      - Preserve unknown fields in proto3: We are going to bring unknown fields

+        back into proto3. In this release, some languages start to support

+        preserving unknown fields in proto3, controlled by flags/options. Some

+        languages also introduce explicit APIs to drop unknown fields for

+        migration. Please read the change log sections by languages for details.

+        For general timeline and plan:

+

+          https://docs.google.com/document/d/1KMRX-G91Aa-Y2FkEaHeeviLRRNblgIahbsk4wA14gRk/view

+

+        For issues and discussions:

+

+          https://github.com/protocolbuffers/protobuf/issues/272

+

+      - Make C++ implementation C++11 only: we plan to require C++11 to build

+        protobuf code starting from 3.5.0 or 3.6.0 release, after unknown fields

+        semantic changes are finished. Please join this

+        github issue:

+

+          https://github.com/protocolbuffers/protobuf/issues/2780

+

+        to provide your feedback.

+

+  General

+  * Extension ranges now accept options and are customizable.

+  * "reserve" keyword now supports “max” in field number ranges,

+    e.g.  reserve 1000 to max;

+

+  C++

+  * Proto3 messages are now able to preserve unknown fields. The default

+    behavior is still to drop unknowns, which will be flipped in a future

+    release. If you rely on unknowns fields being dropped. Please use

+    Message::DiscardUnknownFields() explicitly.

+  * Packable proto3 fields are now packed by default in serialization.

+  * Following C++11 features are introduced when C++11 is available:

+      - move-constructor and move-assignment are introduced to messages

+      - Repeated fields constructor now takes std::initializer_list

+      - rvalue setters are introduced for string fields

+  * Experimental Table-Driven parsing and serialization available to test. To

+    enable it, pass in table_driven_parsing table_driven_serialization protoc

+    generator flags for C++

+

+      $ protoc --cpp_out=table_driven_parsing,table_driven_serialization:./ \

+        test.proto

+

+  * lite generator parameter supported by the generator. Once set, all generated

+    files, use lite runtime regardless of the optimizer_for setting in the

+    .proto file.

+  * Various optimizations to make C++ code more performant on PowerPC platform

+  * Fixed maps data corruption when the maps are modified by both reflection API

+    and generated API.

+  * Deterministic serialization on maps reflection now uses stable sort.

+  * file() accessors are introduced to various *Descriptor classes to make

+    writing template function easier.

+  * ByteSize() and SpaceUsed() are deprecated.Use ByteSizeLong() and

+    SpaceUsedLong() instead

+  * Consistent hash function is used for maps in DEBUG and NDEBUG build.

+  * "using namespace std" is removed from stubs/common.h

+  * Various performance optimizations and bug fixes

+

+  Java

+  * Introduced new parser API DiscardUnknownFieldsParser in preparation of

+    proto3 unknown fields preservation change. Users who want to drop unknown

+    fields should migrate to use this new parser API. For example:

+

+      Parser<Foo> parser = DiscardUnknownFieldsParser.wrap(Foo.parser());

+      Foo foo = parser.parseFrom(input);

+

+  * Introduced new TextFormat API printUnicodeFieldValue() that prints field

+    value without escaping unicode characters.

+  * Added Durations.compare(Duration, Duration) and

+    Timestamps.compare(Timestamp, Timestamp).

+  * JsonFormat now accepts base64url encoded bytes fields.

+  * Optimized CodedInputStream to do less copies when parsing large bytes

+    fields.

+  * Optimized TextFormat to allocate less memory when printing.

+

+  Python

+  * SerializeToString API is changed to SerializeToString(self, **kwargs),

+    deterministic parameter is accepted for deterministic serialization.

+  * Added sort_keys parameter in json format to make the output deterministic.

+  * Added indent parameter in json format.

+  * Added extension support in json format.

+  * Added __repr__ support for repeated field in cpp implementation.

+  * Added file in FieldDescriptor.

+  * Added pretty-print filter to text format.

+  * Services and method descriptors are always printed even if generic_service

+    option is turned off.

+  * Note: AppEngine 2.5 is deprecated on June 2017 that AppEngine 2.5 will

+    never update protobuf runtime. Users who depend on AppEngine 2.5 should use

+    old protoc.

+

+  PHP

+  * Support PHP generic services. Specify file option php_generic_service=true

+    to enable generating service interface.

+  * Message, repeated and map fields setters take value instead of reference.

+  * Added map iterator in c extension.

+  * Support json  encode/decode.

+  * Added more type info in getter/setter phpdoc

+  * Fixed the problem that c extension and php implementation cannot be used

+    together.

+  * Added file option php_namespace to use custom php namespace instead of

+    package.

+  * Added fluent setter.

+  * Added descriptor API in runtime for custom encode/decode.

+  * Various bug fixes.

+

+  Objective-C

+  * Fix for GPBExtensionRegistry copying and add tests.

+  * Optimize GPBDictionary.m codegen to reduce size of overall library by 46K

+    per architecture.

+  * Fix some cases of reading of 64bit map values.

+  * Properly error on a tag with field number zero.

+  * Preserve unknown fields in proto3 syntax files.

+  * Document the exceptions on some of the writing apis.

+

+  C#

+  * Implemented IReadOnlyDictionary<K,V> in MapField<K,V>

+  * Added TryUnpack method for Any message in addition to Unpack.

+  * Converted C# projects to MSBuild (csproj) format.

+

+  Ruby

+  * Several bug fixes.

+

+  Javascript

+  * Added support of field option js_type. Now one can specify the JS type of a

+    64-bit integer field to be string in the generated code by adding option

+    [jstype = JS_STRING] on the field.

+

+2017-04-05 version 3.3.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

+  Planned Future Changes

+  * There are some changes that are not included in this release but are

+    planned for the near future:

+      - Preserve unknown fields in proto3: please read this doc:

+

+          https://docs.google.com/document/d/1KMRX-G91Aa-Y2FkEaHeeviLRRNblgIahbsk4wA14gRk/view

+

+        for the timeline and follow up this github issue:

+

+          https://github.com/protocolbuffers/protobuf/issues/272

+

+        for discussion.

+      - Make C++ implementation C++11 only: we plan to require C++11 to build

+        protobuf code starting from 3.4.0 or 3.5.0 release. Please join this

+        github issue:

+

+          https://github.com/protocolbuffers/protobuf/issues/2780

+

+        to provide your feedback.

+

+  C++

+  * Fixed map fields serialization of DynamicMessage to correctly serialize

+    both key and value regardless of their presence.

+  * Parser now rejects field number 0 correctly.

+  * New API Message::SpaceUsedLong() that’s equivalent to

+    Message::SpaceUsed() but returns the value in size_t.

+  * JSON support

+    - New flag always_print_enums_as_ints in JsonPrintOptions.

+    - New flag preserve_proto_field_names in JsonPrintOptions. It will instruct

+      the JSON printer to use the original field name declared in the .proto

+      file instead of converting them to lowerCamelCase when printing JSON.

+    - JsonPrintOptions.always_print_primtive_fields now works for oneof message

+      fields.

+    - Fixed a bug that doesn’t allow different fields to set the same json_name

+      value.

+    - Fixed a performance bug that causes excessive memory copy when printing

+      large messages.

+  * Various performance optimizations.

+

+  Java

+  * Map field setters eagerly validate inputs and throw NullPointerExceptions

+    as appropriate.

+  * Added ByteBuffer overloads to the generated parsing methods and the Parser

+    interface.

+  * proto3 enum's getNumber() method now throws on UNRECOGNIZED values.

+  * Output of JsonFormat is now locale independent.

+

+  Python

+  * Added FindServiceByName() in the pure-Python DescriptorPool. This works only

+    for descriptors added with DescriptorPool.Add(). Generated descriptor_pool

+    does not support this yet.

+  * Added a descriptor_pool parameter for parsing Any in text_format.Parse().

+  * descriptor_pool.FindFileContainingSymbol() now is able to find nested

+    extensions.

+  * Extending empty [] to repeated field now sets parent message presence.

+

+  PHP

+  * Added file option php_class_prefix. The prefix will be prepended to all

+    generated classes defined in the file.

+  * When encoding, negative int32 values are sign-extended to int64.

+  * Repeated/Map field setter accepts a regular PHP array. Type checking is

+    done on the array elements.

+  * encode/decode are renamed to serializeToString/mergeFromString.

+  * Added mergeFrom, clear method on Message.

+  * Fixed a bug that oneof accessor didn’t return the field name that is

+    actually set.

+  * C extension now works with php7.

+  * This is the first GA release of PHP. We guarantee that old generated code

+    can always work with new runtime and new generated code.

+

+  Objective-C

+  * Fixed help for GPBTimestamp for dates before the epoch that contain

+    fractional seconds.

+  * Added GPBMessageDropUnknownFieldsRecursively() to remove unknowns from a

+    message and any sub messages.

+  * Addressed a threading race in extension registration/lookup.

+  * Increased the max message parsing depth to 100 to match the other languages.

+  * Removed some use of dispatch_once in favor of atomic compare/set since it

+    needs to be heap based.

+  * Fixes for new Xcode 8.3 warnings.

+

+  C#

+  * Fixed MapField.Values.CopyTo, which would throw an exception unnecessarily

+    if provided exactly the right size of array to copy to.

+  * Fixed enum JSON formatting when multiple names mapped to the same numeric

+    value.

+  * Added JSON formatting option to format enums as integers.

+  * Modified RepeatedField<T> to implement IReadOnlyList<T>.

+  * Introduced the start of custom option handling; it's not as pleasant as it

+    might be, but the information is at least present. We expect to extend code

+    generation to improve this in the future.

+  * Introduced ByteString.FromStream and ByteString.FromStreamAsync to

+    efficiently create a ByteString from a stream.

+  * Added whole-message deprecation, which decorates the class with [Obsolete].

+

+  Ruby

+  * Fixed Message#to_h for messages with map fields.

+  * Fixed memcpy() in binary gems to work for old glibc, without breaking the

+    build for non-glibc libc’s like musl.

+

+  Javascript

+  * Added compatibility tests for version 3.0.0.

+  * Added conformance tests.

+  * Fixed serialization of extensions: we need to emit a value even if it is

+    falsy (like the number 0).

+  * Use closurebuilder.py in favor of calcdeps.py for compiling JavaScript.

+

+2017-01-23 version 3.2.0 (C++/Java/Python/PHP/Ruby/Objective-C/C#/JavaScript/Lite)

+  General

+  * Added protoc version number to protoc plugin protocol. It can be used by

+    protoc plugin to detect which version of protoc is used with the plugin and

+    mitigate known problems in certain version of protoc.

+

+  C++

+  * The default parsing byte size limit has been raised from 64MB to 2GB.

+  * Added rvalue setters for non-arena string fields.

+  * Enabled debug logging for Android.

+  * Fixed a double-free problem when using Reflection::SetAllocatedMessage()

+    with extension fields.

+  * Fixed several deterministic serialization bugs:

+    * MessageLite::SerializeAsString() now respects the global deterministic

+      serialization flag.

+    * Extension fields are serialized deterministically as well.  Fixed protocol

+      compiler to correctly report importing-self as an error.

+  * Fixed FileDescriptor::DebugString() to print custom options correctly.

+  * Various performance/codesize optimizations and cleanups.

+

+  Java

+  * The default parsing byte size limit has been raised from 64MB to 2GB.

+  * Added recursion limit when parsing JSON.

+  * Fixed a bug that enumType.getDescriptor().getOptions() doesn't have custom

+    options.

+  * Fixed generated code to support field numbers up to 2^29-1.

+

+  Python

+  * You can now assign NumPy scalars/arrays (np.int32, np.int64) to protobuf

+    fields, and assigning other numeric types has been optimized for

+    performance.

+  * Pure-Python: message types are now garbage-collectable.

+  * Python/C++: a lot of internal cleanup/refactoring.

+

+  PHP (Alpha)

+  * For 64-bit integers type (int64/uint64/sfixed64/fixed64/sint64), use PHP

+    integer on 64-bit environment and PHP string on 32-bit environment.

+  * PHP generated code also conforms to PSR-4 now.

+  * Fixed ZTS build for c extension.

+  * Fixed c extension build on Mac.

+  * Fixed c extension build on 32-bit linux.

+  * Fixed the bug that message without namespace is not found in the descriptor

+    pool. (#2240)

+  * Fixed the bug that repeated field is not iterable in c extension.

+  * Message names Empty will be converted to GPBEmpty in generated code.

+  * Added phpdoc in generated files.

+  * The released API is almost stable. Unless there is large problem, we won't

+    change it. See

+    https://developers.google.com/protocol-buffers/docs/reference/php-generated

+    for more details.

+

+  Objective-C

+  * Added support for push/pop of the stream limit on CodedInputStream for

+    anyone doing manual parsing.

+

+  C#

+  * No changes.

+

+  Ruby

+  * Message objects now support #respond_to? for field getters/setters.

+  * You can now compare “message == non_message_object” and it will return false

+    instead of throwing an exception.

+  * JRuby: fixed #hashCode to properly reflect the values in the message.

+

+  Javascript

+  * Deserialization of repeated fields no longer has quadratic performance

+    behavior.

+  * UTF-8 encoding/decoding now properly supports high codepoints.

+  * Added convenience methods for some well-known types: Any, Struct, and

+    Timestamp. These make it easier to convert data between native JavaScript

+    types and the well-known protobuf types.

+

+2016-09-23 version 3.1.0 (C++/Java/Python/PHP/Ruby/Objective-C/C#/JavaScript/Lite)

+  General

+  * Proto3 support in PHP (alpha).

+  * Various bug fixes.

+

+  C++

+  * Added MessageLite::ByteSizeLong() that’s equivalent to

+    MessageLite::ByteSize() but returns the value in size_t. Useful to check

+    whether a message is over the 2G size limit that protobuf can support.

+  * Moved default_instances to global variables. This allows default_instance

+    addresses to be known at compile time.

+  * Adding missing generic gcc 64-bit atomicops.

+  * Restore New*Callback into google::protobuf namespace since these are used

+    by the service stubs code

+  * JSON support.

+    * Fixed some conformance issues.

+  * Fixed a JSON serialization bug for bytes fields.

+

+  Java

+  * Fixed a bug in TextFormat that doesn’t accept empty repeated fields (i.e.,

+    “field: [ ]”).

+  * JSON support

+    * Fixed JsonFormat to do correct snake_case-to-camelCase conversion for

+      non-style-conforming field names.

+    * Fixed JsonFormat to parse empty Any message correctly.

+    * Added an option to JsonFormat.Parser to ignore unknown fields.

+  * Experimental API

+    * Added UnsafeByteOperations.unsafeWrap(byte[]) to wrap a byte array into

+      ByteString without copy.

+

+  Python

+  * JSON support

+    * Fixed some conformance issues.

+

+  PHP (Alpha)

+  * We have added the proto3 support for PHP via both a pure PHP package and a

+    native c extension. The pure PHP package is intended to provide usability

+    to wider range of PHP platforms, while the c extension is intended to

+    provide higher performance. Both implementations provide the same runtime

+    APIs and share the same generated code. Users don’t need to re-generate

+    code for the same proto definition when they want to switch the

+    implementation later. The pure PHP package is included in the php/src

+    directory, and the c extension is included in the php/ext directory.

+

+    Both implementations provide idiomatic PHP APIs:

+    * All messages and enums are defined as PHP classes.

+    * All message fields can only be accessed via getter/setter.

+    * Both repeated field elements and map elements are stored in containers

+      that act like a normal PHP array.

+

+    Unlike several existing third-party PHP implementations for protobuf, our

+    implementations are built on a "strongly-typed" philosophy: message fields

+    and array/map containers will throw exceptions eagerly when values of the

+    incorrect type (not including those that can be type converted, e.g.,

+    double <-> integer <-> numeric string) are inserted.

+

+    Currently, pure PHP runtime supports php5.5, 5.6 and 7 on linux. C

+    extension runtime supports php5.5 and 5.6 on linux.

+

+    See php/README.md for more details about installment. See

+    https://developers.google.com/protocol-buffers/docs/phptutorial for more

+    details about APIs.

+

+  Objective-C

+  * Helpers are now provided for working the Any well known type (see

+    GPBWellKnownTypes.h for the api additions).

+  * Some improvements in startup code (especially when extensions aren’t used).

+

+  Javascript

+  * Fixed missing import of jspb.Map

+  * Fixed valueWriterFn variable name

+

+  Ruby

+  * Fixed hash computation for JRuby's RubyMessage

+  * Make sure map parsing frames are GC-rooted.

+  * Added API support for well-known types.

+

+  C#

+  * Removed check on dependency in the C# reflection API.

+

+2016-09-06 version 3.0.2 (C++/Java/Python/Ruby/Objective-C/C#/JavaScript/Lite)

+  General

+  * Various bug fixes.

+

+  Objective C

+  * Fix for oneofs in proto3 syntax files where fields were set to the zero

+    value.

+  * Fix for embedded null character in strings.

+  * CocoaDocs support

+

+  Ruby

+  * Fixed memory corruption bug in parsing that could occur under GC pressure.

+

+  Javascript

+  * jspb.Map is now properly exported to CommonJS modules.

+

+  C#

+  * Removed legacy_enum_values flag.

+

+

+2016-07-27 version 3.0.0 (C++/Java/Python/Ruby/Objective-C/C#/JavaScript/Lite)

+  General

+  * This log only contains changes since the beta-4 release. Summarized change

+    log since the last stable release (v2.6.1) can be found in the github

+    release page.

+

+  Compatibility Notice

+  * v3.0.0 is the first API stable release of the v3.x series. We do not expect

+    any future API breaking changes.

+  * For C++, Java Lite and Objective-C, source level compatibility is

+    guaranteed.  Upgrading from v3.0.0 to newer minor version releases will be

+    source compatible. For example, if your code compiles against protobuf

+    v3.0.0, it will continue to compile after you upgrade protobuf library to

+    v3.1.0.

+  * For other languages, both source level compatibility and binary level

+    compatibility are guaranteed. For example, if you have a Java binary built

+    against protobuf v3.0.0. After switching the protobuf runtime binary to

+    v3.1.0, your built binary should continue to work.

+  * Compatibility is only guaranteed for documented API and documented

+    behaviors. If you are using undocumented API (e.g., use anything in the C++

+    internal namespace), it can be broken by minor version releases in an

+    undetermined manner.

+

+  Ruby

+  * When you assign a string field `a.string_field = "X"`, we now call

+    #encode(UTF-8) on the string and freeze the copy. This saves you from

+    needing to ensure the string is already encoded as UTF-8. It also prevents

+    you from mutating the string after it has been assigned (this is how we

+    ensure it stays valid UTF-8).

+  * The generated file for `foo.proto` is now `foo_pb.rb` instead of just

+    `foo.rb`. This makes it easier to see which imports/requires are from

+    protobuf generated code, and also prevents conflicts with any `foo.rb` file

+    you might have written directly in Ruby. It is a backward-incompatible

+    change: you will need to update all of your `require` statements.

+  * For package names like `foo_bar`, we now translate this to the Ruby module

+    `FooBar`. This is more idiomatic Ruby than what we used to do (`Foo_bar`).

+

+  JavaScript

+  * Scalar fields like numbers and boolean now return defaults instead of

+    `undefined` or `null` when they are unset. You can test for presence

+    explicitly by calling `hasFoo()`, which we now generate for scalar fields.

+

+  Java Lite

+  * Java Lite is now implemented as a separate plugin, maintained in the

+    `javalite` branch. Both lite runtime and protoc artifacts will be available

+    in Maven.

+

+  C#

+  * Target platforms now .NET 4.5, selected portable subsets and .NET Core.

+  * legacy_enum_values option is no longer supported.

+

+2016-07-15 version 3.0.0-beta-4 (C++/Java/Python/Ruby/Objective-C/C#/JavaScript)

+  General

+  * Added a deterministic serialization API for C++. The deterministic

+    serialization guarantees that given a binary, equal messages will be

+    serialized to the same bytes. This allows applications like MapReduce to

+    group equal messages based on the serialized bytes. The deterministic

+    serialization is, however, NOT canonical across languages; it is also

+    unstable across different builds with schema changes due to unknown fields.

+    Users who need canonical serialization, e.g. persistent storage in a

+    canonical form, fingerprinting, etc, should define their own

+    canonicalization specification and implement the serializer using reflection

+    APIs rather than relying on this API.

+  * Added OneofOptions. You can now define custom options for oneof groups.

+      import "google/protobuf/descriptor.proto";

+      extend google.protobuf.OneofOptions {

+        optional int32 my_oneof_extension = 12345;

+      }

+      message Foo {

+        oneof oneof_group {

+          (my_oneof_extension) = 54321;

+          ...

+        }

+      }

+

+  C++ (beta)

+  * Introduced a deterministic serialization API in

+    CodedOutputStream::SetSerializationDeterministic(bool). See the notes about

+    deterministic serialization in the General section.

+  * Added google::protobuf::Map::swap() to swap two map fields.

+  * Fixed a memory leak when calling Reflection::ReleaseMessage() on a message

+    allocated on arena.

+  * Improved error reporting when parsing text format protos.

+  * JSON

+      - Added a new parser option to ignore unknown fields when parsing JSON.

+      - Added convenient methods for message to/from JSON conversion.

+  * Various performance optimizations.

+

+  Java (beta)

+  * File option "java_generate_equals_and_hash" is now deprecated. equals() and

+    hashCode() methods are generated by default.

+  * Added a new JSON printer option "omittingInsignificantWhitespace" to produce

+    a more compact JSON output. The printer will pretty-print by default.

+  * Updated Java runtime to be compatible with 2.5.0/2.6.1 generated protos.

+

+  Python (beta)

+  * Added support to pretty print Any messages in text format.

+  * Added a flag to ignore unknown fields when parsing JSON.

+  * Bugfix: "@type" field of a JSON Any message is now correctly put before

+    other fields.

+

+  Objective-C (beta)

+  * Updated the code to support compiling with more compiler warnings

+    enabled. (Issue 1616)

+  * Exposing more detailed errors for parsing failures. (PR 1623)

+  * Small (breaking) change to the naming of some methods on the support classes

+    for map<>. There were collisions with the system provided KVO support, so

+    the names were changed to avoid those issues.  (PR 1699)

+  * Fixed for proper Swift bridging of error handling during parsing. (PR 1712)

+  * Complete support for generating sources that will go into a Framework and

+    depend on generated sources from other Frameworks. (Issue 1457)

+

+  C# (beta)

+  * RepeatedField optimizations.

+  * Support for .NET Core.

+  * Minor bug fixes.

+  * Ability to format a single value in JsonFormatter (advanced usage only).

+  * Modifications to attributes applied to generated code.

+

+  Javascript (alpha)

+  * Maps now have a real map API instead of being treated as repeated fields.

+  * Well-known types are now provided in the google-protobuf package, and the

+    code generator knows to require() them from that package.

+  * Bugfix: non-canonical varints are correctly decoded.

+

+  Ruby (alpha)

+  * Accessors for oneof fields now return default values instead of nil.

+

+  Java Lite

+  * Java lite support is removed from protocol compiler. It will be supported

+    as a protocol compiler plugin in a separate code branch.

+

+2016-05-16 version 3.0.0-beta-3 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)

+  General

+  * Supported Proto3 lite-runtime in C++/Java for mobile platforms.

+  * Any type now supports APIs to specify prefixes other than

+    type.googleapis.com

+  * Removed javanano_use_deprecated_package option; Nano will always has its own

+    ".nano" package.

+

+  C++ (Beta)

+  * Improved hash maps.

+      - Improved hash maps comments. In particular, please note that equal hash

+        maps will not necessarily have the same iteration order and

+        serialization.

+      - Added a new hash maps implementation that will become the default in a

+        later release.

+  * Arenas

+      - Several inlined methods in Arena were moved to out-of-line to improve

+        build performance and code size.

+      - Added SpaceAllocatedAndUsed() to report both space used and allocated

+      - Added convenient class UnsafeArenaAllocatedRepeatedPtrFieldBackInserter

+  * Any

+      - Allow custom type URL prefixes in Any packing.

+      - TextFormat now expand the Any type rather than printing bytes.

+  * Performance optimizations and various bug fixes.

+

+  Java (Beta)

+  * Introduced an ExperimentalApi annotation. Annotated APIs are experimental

+    and are subject to change in a backward incompatible way in future releases.

+  * Introduced zero-copy serialization as an ExperimentalApi

+      - Introduction of the `ByteOutput` interface. This is similar to

+        `OutputStream` but provides semantics for lazy writing (i.e. no

+        immediate copy required) of fields that are considered to be immutable.

+      - `ByteString` now supports writing to a `ByteOutput`, which will directly

+        expose the internals of the `ByteString` (i.e. `byte[]` or `ByteBuffer`)

+        to the `ByteOutput` without copying.

+      - `CodedOutputStream` now supports writing to a `ByteOutput`. `ByteString`

+        instances that are too large to fit in the internal buffer will be

+        (lazily) written to the `ByteOutput` directly.

+      - This allows applications using large `ByteString` fields to avoid

+        duplication of these fields entirely. Such an application can supply a

+        `ByteOutput` that chains together the chunks received from

+        `CodedOutputStream` before forwarding them onto the IO system.

+  * Other related changes to `CodedOutputStream`

+      - Additional use of `sun.misc.Unsafe` where possible to perform fast

+        access to `byte[]` and `ByteBuffer` values and avoiding unnecessary

+        range checking.

+      - `ByteBuffer`-backed `CodedOutputStream` now writes directly to the

+        `ByteBuffer` rather than to an intermediate array.

+  * Improved lite-runtime.

+      - Lite protos now implement deep equals/hashCode/toString

+      - Significantly improved the performance of Builder#mergeFrom() and

+        Builder#mergeDelimitedFrom()

+  * Various bug fixes and small feature enhancement.

+      - Fixed stack overflow when in hashCode() for infinite recursive oneofs.

+      - Fixed the lazy field parsing in lite to merge rather than overwrite.

+      - TextFormat now supports reporting line/column numbers on errors.

+      - Updated to add appropriate @Override for better compiler errors.

+

+  Python (Beta)

+  * Added JSON format for Any, Struct, Value and ListValue

+  * [ ] is now accepted for both repeated scalar fields and repeated message

+    fields in text format parser.

+  * Numerical field name is now supported in text format.

+  * Added DiscardUnknownFields API for python protobuf message.

+

+  Objective-C (Beta)

+  * Proto comments now come over as HeaderDoc comments in the generated sources

+    so Xcode can pick them up and display them.

+  * The library headers have been updated to use HeaderDoc comments so Xcode can

+    pick them up and display them.

+  * The per message and per field overhead in both generated code and runtime

+    object sizes was reduced.

+  * Generated code now include deprecated annotations when the proto file

+    included them.

+

+  C# (Beta)

+  In general: some changes are breaking, which require regenerating messages.

+  Most user-written code will not be impacted *except* for the renaming of enum

+  values.

+

+  * Allow custom type URL prefixes in `Any` packing, and ignore them when

+    unpacking

+  * `protoc` is now in a separate NuGet package (Google.Protobuf.Tools)

+  * New option: `internal_access` to generate internal classes

+  * Enum values are now PascalCased, and if there's a prefix which matches the

+    name of the enum, that is removed (so an enum `COLOR` with a value

+    `COLOR_BLUE` would generate a value of just `Blue`). An option

+    (`legacy_enum_values`) is temporarily available to disable this, but the

+    option will be removed for GA.

+  * `json_name` option is now honored

+  * If group tags are encountered when parsing, they are validated more

+    thoroughly (although we don't support actual groups)

+  * NuGet dependencies are better specified

+  * Breaking: `Preconditions` is renamed to `ProtoPreconditions`

+  * Breaking: `GeneratedCodeInfo` is renamed to `GeneratedClrTypeInfo`

+  * `JsonFormatter` now allows writing to a `TextWriter`

+  * New interface, `ICustomDiagnosticMessage` to allow more compact

+    representations from `ToString`

+  * `CodedInputStream` and `CodedOutputStream` now implement `IDisposable`,

+    which simply disposes of the streams they were constructed with

+  * Map fields no longer support null values (in line with other languages)

+  * Improvements in JSON formatting and parsing

+

+  Javascript (Alpha)

+  * Better support for "bytes" fields: bytes fields can be read as either a

+    base64 string or UInt8Array (in environments where TypedArray is supported).

+  * New support for CommonJS imports.  This should make it easier to use the

+    JavaScript support in Node.js and tools like WebPack.  See js/README.md for

+    more information.

+  * Some significant internal refactoring to simplify and modularize the code.

+

+  Ruby (Alpha)

+  * JSON serialization now properly uses camelCased names, with a runtime option

+    that will preserve original names from .proto files instead.

+  * Well-known types are now included in the distribution.

+  * Release now includes binary gems for Windows, Mac, and Linux instead of just

+    source gems.

+  * Bugfix for serializing oneofs.

+

+  C++/Java Lite (Alpha)

+    A new "lite" generator parameter was introduced in the protoc for C++ and

+    Java for Proto3 syntax messages. Example usage:

+

+     ./protoc --cpp_out=lite:$OUTPUT_PATH foo.proto

+

+    The protoc will treat the current input and all the transitive dependencies

+    as LITE. The same generator parameter must be used to generate the

+    dependencies.

+

+    In Proto3 syntax files, "optimized_for=LITE_RUNTIME" is no longer supported.

+

+

+2015-12-30 version 3.0.0-beta-2 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)

+  General

+  * Introduced a new language implementation: JavaScript.

+  * Added a new field option "json_name". By default proto field names are

+    converted to "lowerCamelCase" in proto3 JSON format. This option can be

+    used to override this behavior and specify a different JSON name for the

+    field.

+  * Added conformance tests to ensure implementations are following proto3 JSON

+    specification.

+

+  C++ (Beta)

+  * Various bug fixes and improvements to the JSON support utility:

+      - Duplicate map keys in JSON are now rejected (i.e., translation will

+        fail).

+      - Fixed wire-format for google.protobuf.Value/ListValue.

+      - Fixed precision loss when converting google.protobuf.Timestamp.

+      - Fixed a bug when parsing invalid UTF-8 code points.

+      - Fixed a memory leak.

+      - Reduced call stack usage.

+

+  Java (Beta)

+  * Cleaned up some unused methods on CodedOutputStream.

+  * Presized lists for packed fields during parsing in the lite runtime to

+    reduce allocations and improve performance.

+  * Improved the performance of unknown fields in the lite runtime.

+  * Introduced UnsafeByteStrings to support zero-copy ByteString creation.

+  * Various bug fixes and improvements to the JSON support utility:

+      - Fixed a thread-safety bug.

+      - Added a new option “preservingProtoFieldNames” to JsonFormat.

+      - Added a new option “includingDefaultValueFields” to JsonFormat.

+      - Updated the JSON utility to comply with proto3 JSON specification.

+

+  Python (Beta)

+  * Added proto3 JSON format utility. It includes support for all field types

+    and a few well-known types except for Any and Struct.

+  * Added runtime support for Any, Timestamp, Duration and FieldMask.

+  * [ ] is now accepted for repeated scalar fields in text format parser.

+  * Map fields now have proper O(1) performance for lookup/insert/delete

+    when using the Python/C++ implementation. They were previously using O(n)

+    search-based algorithms because the C++ reflection interface didn't

+    support true map operations.

+

+  Objective-C (Beta)

+  * Various bug-fixes and code tweaks to pass more strict compiler warnings.

+  * Now has conformance test coverage and is passing all tests.

+

+  C# (Beta)

+  * Various bug-fixes.

+  * Code generation: Files generated in directories based on namespace.

+  * Code generation: Include comments from .proto files in XML doc

+    comments (naively)

+  * Code generation: Change organization/naming of "reflection class" (access

+    to file descriptor)

+  * Code generation and library: Add Parser property to MessageDescriptor,

+    and introduce a non-generic parser type.

+  * Library: Added TypeRegistry to support JSON parsing/formatting of Any.

+  * Library: Added Any.Pack/Unpack support.

+  * Library: Implemented JSON parsing.

+

+  Javascript (Alpha)

+  * Added proto3 support for JavaScript. The runtime is written in pure

+    JavaScript and works in browsers and in Node.js. To generate JavaScript

+    code for your proto, invoke protoc with "--js_out". See js/README.md

+    for more build instructions.

+

+2015-08-26 version 3.0.0-beta-1 (C++/Java/Python/Ruby/Nano/Objective-C/C#)

+  About Beta

+  * This is the first beta release of protobuf v3.0.0. Not all languages

+    have reached beta stage. Languages not marked as beta are still in

+    alpha (i.e., be prepared for API breaking changes).

+

+  General

+  * Proto3 JSON is supported in several languages (fully supported in C++

+    and Java, partially supported in Ruby/C#). The JSON spec is defined in

+    the proto3 language guide:

+

+      https://developers.google.com/protocol-buffers/docs/proto3#json

+

+    We will publish a more detailed spec to define the exact behavior of

+    proto3-conformant JSON serializers and parsers. Until then, do not rely

+    on specific behaviors of the implementation if it’s not documented in

+    the above spec. More specifically, the behavior is not yet finalized for

+    the following:

+      - Parsing invalid JSON input (e.g., input with trailing commas).

+      - Non-camelCase names in JSON input.

+      - The same field appears multiple times in JSON input.

+      - JSON arrays contain “null” values.

+      - The message has unknown fields.

+

+  * Proto3 now enforces strict UTF-8 checking. Parsing will fail if a string

+    field contains non UTF-8 data.

+

+  C++ (Beta)

+  * Introduced new utility functions/classes in the google/protobuf/util

+    directory:

+      - MessageDifferencer: compare two proto messages and report their

+                            differences.

+      - JsonUtil: support converting protobuf binary format to/from JSON.

+      - TimeUtil: utility functions to work with well-known types Timestamp

+                  and Duration.

+      - FieldMaskUtil: utility functions to work with FieldMask.

+

+  * Performance optimization of arena construction and destruction.

+  * Bug fixes for arena and maps support.

+  * Changed to use cmake for Windows Visual Studio builds.

+  * Added Bazel support.

+

+  Java (Beta)

+  * Introduced a new util package that will be distributed as a separate

+    artifact in maven. It contains:

+      - JsonFormat: convert proto messages to/from JSON.

+      - TimeUtil: utility functions to work with Timestamp and Duration.

+      - FieldMaskUtil: utility functions to work with FieldMask.

+

+  * The static PARSER in each generated message is deprecated, and it will

+    be removed in a future release. A static parser() getter is generated

+    for each message type instead.

+  * Performance optimizations for String fields serialization.

+  * Performance optimizations for Lite runtime on Android:

+      - Reduced allocations

+      - Reduced method overhead after ProGuarding

+      - Reduced code size after ProGuarding

+

+  Python (Alpha)

+  * Removed legacy Python 2.5 support.

+  * Moved to a single Python 2.x/3.x-compatible codebase, instead of using 2to3.

+  * Fixed build/tests on Python 2.6, 2.7, 3.3, and 3.4.

+      - Pure-Python works on all four.

+      - Python/C++ implementation works on all but 3.4, due to changes in the

+        Python/C++ API in 3.4.

+  * Some preliminary work has been done to allow for multiple DescriptorPools

+    with Python/C++.

+

+  Ruby (Alpha)

+  * Many bugfixes:

+      - fixed parsing/serialization of bytes, sint, sfixed types

+      - other parser bugfixes

+      - fixed memory leak affecting Ruby 2.2

+

+  JavaNano (Alpha)

+  * JavaNano generated code now will be put in a nano package by default to

+    avoid conflicts with Java generated code.

+

+  Objective-C (Alpha)

+  * Added non-null markup to ObjC library. Requires SDK 8.4+ to build.

+  * Many bugfixes:

+      - Removed the class/enum filter.

+      - Renamed some internal types to avoid conflicts with the well-known types

+        protos.

+      - Added missing support for parsing repeated primitive fields in packed or

+        unpacked forms.

+      - Added *Count for repeated and map<> fields to avoid auto-create when

+        checking for them being set.

+

+  C# (Alpha)

+  * Namespace changed to Google.Protobuf (and NuGet package will be named

+    correspondingly).

+  * Target platforms now .NET 4.5 and selected portable subsets only.

+  * Removed lite runtime.

+  * Reimplementation to use mutable message types.

+  * Null references used to represent "no value" for message type fields.

+  * Proto3 semantics supported; proto2 files are prohibited for C# codegen.

+    Most proto3 features supported:

+      - JSON formatting (a.k.a. serialization to JSON), including well-known

+        types (except for Any).

+      - Wrapper types mapped to nullable value types (or string/ByteString

+        allowing nullability). JSON parsing is not supported yet.

+      - maps

+      - oneof

+      - enum unknown value preservation

+

+2015-05-25 version 3.0.0-alpha-3 (Objective-C/C#):

+  General

+  * Introduced two new language implementations (Objective-C, C#) to proto3.

+  * Explicit "optional" keyword are disallowed in proto3 syntax, as fields are

+    optional by default.

+  * Group fields are no longer supported in proto3 syntax.

+  * Changed repeated primitive fields to use packed serialization by default in

+    proto3 (implemented for C++, Java, Python in this release).  The user can

+    still disable packed serialization by setting packed to false for now.

+  * Added well-known type protos (any.proto, empty.proto, timestamp.proto,

+    duration.proto, etc.). Users can import and use these protos just like

+    regular proto files. Additional runtime support will be added for them in

+    future releases (in the form of utility helper functions, or having them

+    replaced by language specific types in generated code).

+  * Added a "reserved" keyword in both proto2 and proto3 syntax. User can use

+    this keyword to declare reserved field numbers and names to prevent them

+    from being reused by other fields in the same message.

+

+    To reserve field numbers, add a reserved declaration in your message:

+

+      message TestMessage {

+        reserved 2, 15, 9 to 11, 3;

+      }

+

+    This reserves field numbers 2, 3, 9, 10, 11 and 15. If a user uses any of

+    these as field numbers, the protocol buffer compiler will report an error.

+

+    Field names can also be reserved:

+

+      message TestMessage {

+        reserved "foo", "bar";

+      }

+

+  * Various bug fixes since 3.0.0-alpha-2

+

+  Objective-C

+    Objective-C includes a code generator and a native objective-c runtime

+    library.  By adding “--objc_out” to protoc, the code generator will generate

+    a header(*.pbobjc.h) and an implementation file(*.pbobjc.m) for each proto

+    file.

+

+    In this first release, the generated interface provides: enums, messages,

+    field support(single, repeated, map, oneof), proto2 and proto3 syntax

+    support, parsing and serialization. It’s  compatible with ARC and non-ARC

+    usage. Besides, user can also access it via the swift bridging header.

+

+    See objectivec/README.md for details.

+

+  C#

+    * C# protobufs are based on project

+      https://github.com/jskeet/protobuf-csharp-port. The original project was

+      frozen and all the new development will happen here.

+    * Codegen plugin for C# was completely rewritten to C++ and is now an

+      integral part of protoc.

+    * Some refactorings and cleanup has been applied to the C# runtime library.

+    * Only proto2 is supported in C# at the moment, proto3 support is in

+      progress and will likely bring significant breaking changes to the API.

+

+    See csharp/README.md for details.

+

+  C++

+    * Added runtime support for Any type. To use Any in your proto file, first

+      import the definition of Any:

+

+        // foo.proto

+        import "google/protobuf/any.proto";

+        message Foo {

+          google.protobuf.Any any_field = 1;

+        }

+        message Bar {

+          int32 value = 1;

+        }

+

+      Then in C++ you can access the Any field using PackFrom()/UnpackTo()

+      methods:

+

+        Foo foo;

+        Bar bar = ...;

+        foo.mutable_any_field()->PackFrom(bar);

+        ...

+        if (foo.any_field().IsType<Bar>()) {

+          foo.any_field().UnpackTo(&bar);

+          ...

+        }

+    * In text format, entries of a map field will be sorted by key.

+

+  Java

+    * Continued optimizations on the lite runtime to improve performance for

+      Android.

+

+  Python

+    * Added map support.

+      - maps now have a dict-like interface (msg.map_field[key] = value)

+      - existing code that modifies maps via the repeated field interface

+        will need to be updated.

+

+  Ruby

+    * Improvements to RepeatedField's emulation of the Ruby Array API.

+    * Various speedups and internal cleanups.

+

+2015-02-26 version 3.0.0-alpha-2 (Python/Ruby/JavaNano):

+  General

+  * Introduced three new language implementations (Ruby, JavaNano, and

+    Python) to proto3.

+  * Various bug fixes since 3.0.0-alpha-1

+

+  Python:

+    Python has received several updates, most notably support for proto3

+    semantics in any .proto file that declares syntax="proto3".

+    Messages declared in proto3 files no longer represent field presence

+    for scalar fields (number, enums, booleans, or strings).  You can

+    no longer call HasField() for such fields, and they are serialized

+    based on whether they have a non-zero/empty/false value.

+

+    One other notable change is in the C++-accelerated implementation.

+    Descriptor objects (which describe the protobuf schema and allow

+    reflection over it) are no longer duplicated between the Python

+    and C++ layers.  The Python descriptors are now simple wrappers

+    around the C++ descriptors.  This change should significantly

+    reduce the memory usage of programs that use a lot of message

+    types.

+

+  Ruby:

+    We have added proto3 support for Ruby via a native C extension.

+

+    The Ruby extension itself is included in the ruby/ directory, and details on

+    building and installing the extension are in ruby/README.md. The extension

+    will also be published as a Ruby gem. Code generator support is included as

+    part of `protoc` with the `--ruby_out` flag.

+

+    The Ruby extension implements a user-friendly DSL to define message types

+    (also generated by the code generator from `.proto` files).  Once a message

+    type is defined, the user may create instances of the message that behave in

+    ways idiomatic to Ruby. For example:

+

+    - Message fields are present as ordinary Ruby properties (getter method

+      `foo` and setter method `foo=`).

+    - Repeated field elements are stored in a container that acts like a native

+      Ruby array, and map elements are stored in a container that acts like a

+      native Ruby hashmap.

+    - The usual well-known methods, such as `#to_s`, `#dup`, and the like, are

+      present.

+

+    Unlike several existing third-party Ruby extensions for protobuf, this

+    extension is built on a "strongly-typed" philosophy: message fields and

+    array/map containers will throw exceptions eagerly when values of the

+    incorrect type are inserted.

+

+    See ruby/README.md for details.

+

+  JavaNano:

+    JavaNano is a special code generator and runtime library designed especially

+    for resource-restricted systems, like Android. It is very resource-friendly

+    in both the amount of code and the runtime overhead. Here is an an overview

+    of JavaNano features compared with the official Java protobuf:

+

+    - No descriptors or message builders.

+    - All messages are mutable; fields are public Java fields.

+    - For optional fields only, encapsulation behind setter/getter/hazzer/

+      clearer functions is opt-in, which provide proper 'has' state support.

+    - For proto2, if not opted in, has state (field presence) is not available.

+      Serialization outputs all fields not equal to their defaults.

+      The behavior is consistent with proto3 semantics.

+    - Required fields (proto2 only) are always serialized.

+    - Enum constants are integers; protection against invalid values only

+      when parsing from the wire.

+    - Enum constants can be generated into container interfaces bearing

+      the enum's name (so the referencing code is in Java style).

+    - CodedInputByteBufferNano can only take byte[] (not InputStream).

+    - Similarly CodedOutputByteBufferNano can only write to byte[].

+    - Repeated fields are in arrays, not ArrayList or Vector. Null array

+      elements are allowed and silently ignored.

+    - Full support for serializing/deserializing repeated packed fields.

+    - Support  extensions (in proto2).

+    - Unset messages/groups are null, not an immutable empty default

+      instance.

+    - toByteArray(...) and mergeFrom(...) are now static functions of

+      MessageNano.

+    - The 'bytes' type translates to the Java type byte[].

+

+    See javanano/README.txt for details.

+

+2014-12-01 version 3.0.0-alpha-1 (C++/Java):

+

+  General

+  * Introduced Protocol Buffers language version 3 (aka proto3).

+

+    When protobuf was initially opensourced it implemented Protocol Buffers

+    language version 2 (aka proto2), which is why the version number

+    started from v2.0.0. From v3.0.0, a new language version (proto3) is

+    introduced while the old version (proto2) will continue to be supported.

+

+    The main intent of introducing proto3 is to clean up protobuf before

+    pushing the language as the foundation of Google's new API platform.

+    In proto3, the language is simplified, both for ease of use and  to

+    make it available in a wider range of programming languages. At the

+    same time a few features are added to better support common idioms

+    found in APIs.

+

+    The following are the main new features in language version 3:

+

+      1. Removal of field presence logic for primitive value fields, removal

+         of required fields, and removal of default values. This makes proto3

+         significantly easier to implement with open struct representations,

+         as in languages like Android Java, Objective C, or Go.

+      2. Removal of unknown fields.

+      3. Removal of extensions, which are instead replaced by a new standard

+         type called Any.

+      4. Fix semantics for unknown enum values.

+      5. Addition of maps.

+      6. Addition of a small set of standard types for representation of time,

+         dynamic data, etc.

+      7. A well-defined encoding in JSON as an alternative to binary proto

+         encoding.

+

+    This release (v3.0.0-alpha-1) includes partial proto3 support for C++ and

+    Java. Items 6 (well-known types) and 7 (JSON format) in the above feature

+    list are not implemented.

+

+    A new notion "syntax" is introduced to specify whether a .proto file

+    uses proto2 or proto3:

+

+      // foo.proto

+      syntax = "proto3";

+      message Bar {...}

+

+    If omitted, the protocol compiler will generate a warning and "proto2" will

+    be used as the default. This warning will be turned into an error in a

+    future release.

+

+    We recommend that new Protocol Buffers users use proto3. However, we do not

+    generally recommend that existing users migrate from proto2 from proto3 due

+    to API incompatibility, and we will continue to support proto2 for a long

+    time.

+

+  * Added support for map fields (implemented in C++/Java for both proto2 and

+    proto3).

+

+    Map fields can be declared using the following syntax:

+

+      message Foo {

+        map<string, string> values = 1;

+      }

+

+    Data of a map field will be stored in memory as an unordered map and it

+    can be accessed through generated accessors.

+

+  C++

+  * Added arena allocation support (for both proto2 and proto3).

+

+    Profiling shows memory allocation and deallocation constitutes a significant

+    fraction of CPU-time spent in protobuf code and arena allocation is a

+    technique introduced to reduce this cost. With arena allocation, new

+    objects will be allocated from a large piece of preallocated memory and

+    deallocation of these objects is almost free. Early adoption shows 20% to

+    50% improvement in some Google binaries.

+

+    To enable arena support, add the following option to your .proto file:

+

+      option cc_enable_arenas = true;

+

+    Protocol compiler will generate additional code to make the generated

+    message classes work with arenas. This does not change the existing API

+    of protobuf messages and does not affect wire format. Your existing code

+    should continue to work after adding this option. In the future we will

+    make this option enabled by default.

+

+    To actually take advantage of arena allocation, you need to use the arena

+    APIs when creating messages. A quick example of using the arena API:

+

+      {

+        google::protobuf::Arena arena;

+        // Allocate a protobuf message in the arena.

+        MyMessage* message = Arena::CreateMessage<MyMessage>(&arena);

+        // All submessages will be allocated in the same arena.

+        if (!message->ParseFromString(data)) {

+          // Deal with malformed input data.

+        }

+        // Must not delete the message here. It will be deleted automatically

+        // when the arena is destroyed.

+      }

+

+    Currently arena does not work with map fields. Enabling arena in a .proto

+    file containing map fields will result in compile errors in the generated

+    code. This will be addressed in a future release.

+

+2014-10-20 version 2.6.1:

+

+  C++

+  * Added atomicops support for Solaris.

+  * Released memory allocated by InitializeDefaultRepeatedFields() and

+    GetEmptyString(). Some memory sanitizers reported them as memory leaks.

+

+  Java

+  * Updated DynamicMessage.setField() to handle repeated enum values

+    correctly.

+  * Fixed a bug that caused NullPointerException to be thrown when

+    converting manually constructed FileDescriptorProto to

+    FileDescriptor.

+

+  Python

+  * Fixed WhichOneof() to work with de-serialized protobuf messages.

+  * Fixed a missing file problem of Python C++ implementation.

+

+2014-08-15 version 2.6.0:

+

+  General

+  * Added oneofs(unions) feature. Fields in the same oneof will share

+    memory and at most one field can be set at the same time. Use the

+    oneof keyword to define a oneof like:

+      message SampleMessage {

+        oneof test_oneof {

+          string name = 4;

+          YourMessage sub_message = 9;

+        }

+      }

+  * Files, services, enums, messages, methods and enum values can be marked

+    as deprecated now.

+  * Added Support for list values, including lists of messages, when

+    parsing text-formatted protos in C++ and Java.

+      For example:  foo: [1, 2, 3]

+

+  C++

+  * Enhanced customization on TestFormat printing.

+  * Added SwapFields() in reflection API to swap a subset of fields.

+    Added SetAllocatedMessage() in reflection API.

+  * Repeated primitive extensions are now packable. The

+    [packed=true] option only affects serializers. Therefore, it is

+    possible to switch a repeated extension field to packed format

+    without breaking backwards-compatibility.

+  * Various speed optimizations.

+

+  Java

+  * writeTo() method in ByteString can now write a substring to an

+    output stream. Added endWith() method for ByteString.

+  * ByteString and ByteBuffer are now supported in CodedInputStream

+    and CodedOutputStream.

+  * java_generate_equals_and_hash can now be used with the LITE_RUNTIME.

+

+  Python

+  * A new C++-backed extension module (aka "cpp api v2") that replaces the

+    old ("cpp api v1") one.  Much faster than the pure Python code.  This one

+    resolves many bugs and is recommended for general use over the

+    pure Python when possible.

+  * Descriptors now have enum_types_by_name and extension_types_by_name dict

+    attributes.

+  * Support for Python 3.

+

+2013-02-27 version 2.5.0:

+

+  General

+  * New notion "import public" that allows a proto file to forward the content

+    it imports to its importers. For example,

+      // foo.proto

+      import public "bar.proto";

+      import "baz.proto";

+

+      // qux.proto

+      import "foo.proto";

+      // Stuff defined in bar.proto may be used in this file, but stuff from

+      // baz.proto may NOT be used without importing it explicitly.

+    This is useful for moving proto files. To move a proto file, just leave

+    a single "import public" in the old proto file.

+  * New enum option "allow_alias" that specifies whether different symbols can

+    be assigned the same numeric value. Default value is "true". Setting it to

+    false causes the compiler to reject enum definitions where multiple symbols

+    have the same numeric value.

+    Note: We plan to flip the default value to "false" in a future release.

+    Projects using enum aliases should set the option to "true" in their .proto

+    files.

+

+  C++

+  * New generated method set_allocated_foo(Type* foo) for message and string

+    fields. This method allows you to set the field to a pre-allocated object

+    and the containing message takes the ownership of that object.

+  * Added SetAllocatedExtension() and ReleaseExtension() to extensions API.

+  * Custom options are now formatted correctly when descriptors are printed in

+    text format.

+  * Various speed optimizations.

+

+  Java

+  * Comments in proto files are now collected and put into generated code as

+    comments for corresponding classes and data members.

+  * Added Parser to parse directly into messages without a Builder. For

+    example,

+      Foo foo = Foo.PARSER.ParseFrom(input);

+    Using Parser is ~25% faster than using Builder to parse messages.

+  * Added getters/setters to access the underlying ByteString of a string field

+    directly.

+  * ByteString now supports more operations: substring(), prepend(), and

+    append(). The implementation of ByteString uses a binary tree structure

+    to support these operations efficiently.

+  * New method findInitializationErrors() that lists all missing required

+    fields.

+  * Various code size and speed optimizations.

+

+  Python

+  * Added support for dynamic message creation. DescriptorDatabase,

+    DescriptorPool, and MessageFactory work like their C++ counterparts to

+    simplify Descriptor construction from *DescriptorProtos, and MessageFactory

+    provides a message instance from a Descriptor.

+  * Added pickle support for protobuf messages.

+  * Unknown fields are now preserved after parsing.

+  * Fixed bug where custom options were not correctly populated. Custom

+    options can be accessed now.

+  * Added EnumTypeWrapper that provides better accessibility to enum types.

+  * Added ParseMessage(descriptor, bytes) to generate a new Message instance

+    from a descriptor and a byte string.

+

+2011-05-01 version 2.4.1:

+

+  C++

+  * Fixed the friendship problem for old compilers to make the library now gcc 3

+    compatible again.

+  * Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h.

+

+  Java

+  * Removed usages of JDK 1.6 only features to make the library now JDK 1.5

+    compatible again.

+  * Fixed a bug about negative enum values.

+  * serialVersionUID is now defined in generated messages for java serializing.

+  * Fixed protoc to use java.lang.Object, which makes "Object" now a valid

+    message name again.

+

+  Python

+  * Experimental C++ implementation now requires C++ protobuf library installed.

+    See the README.txt in the python directory for details.

+

+2011-02-02 version 2.4.0:

+

+  General

+  * The RPC (cc|java|py)_generic_services default value is now false instead of

+    true.

+  * Custom options can have aggregate types. For example,

+      message MyOption {

+        optional string comment = 1;

+        optional string author = 2;

+      }

+      extend google.protobuf.FieldOptions {

+        optional MyOption myoption = 12345;

+      }

+    This option can now be set as follows:

+      message SomeType {

+        optional int32 field = 1 [(myoption) = { comment:'x' author:'y' }];

+      }

+

+  C++

+  * Various speed and code size optimizations.

+  * Added a release_foo() method on string and message fields.

+  * Fixed gzip_output_stream sub-stream handling.

+

+  Java

+  * Builders now maintain sub-builders for sub-messages. Use getFooBuilder() to

+    get the builder for the sub-message "foo". This allows you to repeatedly

+    modify deeply-nested sub-messages without rebuilding them.

+  * Builder.build() no longer invalidates the Builder for generated messages

+    (You may continue to modify it and then build another message).

+  * Code generator will generate efficient equals() and hashCode()

+    implementations if new option java_generate_equals_and_hash is enabled.

+    (Otherwise, reflection-based implementations are used.)

+  * Generated messages now implement Serializable.

+  * Fields with [deprecated=true] will be marked with @Deprecated in Java.

+  * Added lazy conversion of UTF-8 encoded strings to String objects to improve

+    performance.

+  * Various optimizations.

+  * Enum value can be accessed directly, instead of calling getNumber() on the

+    enum member.

+  * For each enum value, an integer constant is also generated with the suffix

+    _VALUE.

+

+  Python

+  * Added an experimental  C++ implementation for Python messages via a Python

+    extension. Implementation type is controlled by an environment variable

+    PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION (valid values: "cpp" and "python")

+    The default value is currently "python" but will be changed to "cpp" in

+    future release.

+  * Improved performance on message instantiation significantly.

+    Most of the work on message instantiation is done just once per message

+    class, instead of once per message instance.

+  * Improved performance on text message parsing.

+  * Allow add() to forward keyword arguments to the concrete class.

+      E.g. instead of

+        item = repeated_field.add()

+        item.foo = bar

+        item.baz = quux

+      You can do:

+        repeated_field.add(foo=bar, baz=quux)

+  * Added a sort() interface to the BaseContainer.

+  * Added an extend() method to repeated composite fields.

+  * Added UTF8 debug string support.

+

+2010-01-08 version 2.3.0:

+

+  General

+  * Parsers for repeated numeric fields now always accept both packed and

+    unpacked input.  The [packed=true] option only affects serializers.

+    Therefore, it is possible to switch a field to packed format without

+    breaking backwards-compatibility -- as long as all parties are using

+    protobuf 2.3.0 or above, at least.

+  * The generic RPC service code generated by the C++, Java, and Python

+    generators can be disabled via file options:

+      option cc_generic_services = false;

+      option java_generic_services = false;

+      option py_generic_services = false;

+    This allows plugins to generate alternative code, possibly specific to some

+    particular RPC implementation.

+

+  protoc

+  * Now supports a plugin system for code generators.  Plugins can generate

+    code for new languages or inject additional code into the output of other

+    code generators.  Plugins are just binaries which accept a protocol buffer

+    on stdin and write a protocol buffer to stdout, so they may be written in

+    any language.  See src/google/protobuf/compiler/plugin.proto.

+    **WARNING**:  Plugins are experimental.  The interface may change in a

+    future version.

+  * If the output location ends in .zip or .jar, protoc will write its output

+    to a zip/jar archive instead of a directory.  For example:

+      protoc --java_out=myproto_srcs.jar --python_out=myproto.zip myproto.proto

+    Currently the archive contents are not compressed, though this could change

+    in the future.

+  * inf, -inf, and nan can now be used as default values for float and double

+    fields.

+

+  C++

+  * Various speed and code size optimizations.

+  * DynamicMessageFactory is now fully thread-safe.

+  * Message::Utf8DebugString() method is like DebugString() but avoids escaping

+    UTF-8 bytes.

+  * Compiled-in message types can now contain dynamic extensions, through use

+    of CodedInputStream::SetExtensionRegistry().

+  * Now compiles shared libraries (DLLs) by default on Cygwin and MinGW, to

+    match other platforms.  Use --disable-shared to avoid this.

+

+  Java

+  * parseDelimitedFrom() and mergeDelimitedFrom() now detect EOF and return

+    false/null instead of throwing an exception.

+  * Fixed some initialization ordering bugs.

+  * Fixes for OpenJDK 7.

+

+  Python

+  * 10-25 times faster than 2.2.0, still pure-Python.

+  * Calling a mutating method on a sub-message always instantiates the message

+    in its parent even if the mutating method doesn't actually mutate anything

+    (e.g. parsing from an empty string).

+  * Expanded descriptors a bit.

+

+2009-08-11 version 2.2.0:

+

+  C++

+  * Lite mode:  The "optimize_for = LITE_RUNTIME" option causes the compiler

+    to generate code which only depends libprotobuf-lite, which is much smaller

+    than libprotobuf but lacks descriptors, reflection, and some other features.

+  * Fixed bug where Message.Swap(Message) was only implemented for

+    optimize_for_speed.  Swap now properly implemented in both modes

+    (Issue 91).

+  * Added RemoveLast and SwapElements(index1, index2) to Reflection

+    interface for repeated elements.

+  * Added Swap(Message) to Reflection interface.

+  * Floating-point literals in generated code that are intended to be

+    single-precision now explicitly have 'f' suffix to avoid pedantic warnings

+    produced by some compilers.

+  * The [deprecated=true] option now causes the C++ code generator to generate

+    a GCC-style deprecation annotation (no-op on other compilers).

+  * google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the

+    EnumDescriptor for that type -- useful for templates which cannot call

+    SomeGeneratedEnumType_descriptor().

+  * Various optimizations and obscure bug fixes.

+

+  Java

+  * Lite mode:  The "optimize_for = LITE_RUNTIME" option causes the compiler

+    to generate code which only depends libprotobuf-lite, which is much smaller

+    than libprotobuf but lacks descriptors, reflection, and some other features.

+  * Lots of style cleanups.

+

+  Python

+  * Fixed endianness bug with floats and doubles.

+  * Text format parsing support.

+  * Fix bug with parsing packed repeated fields in embedded messages.

+  * Ability to initialize fields by passing keyword args to constructor.

+  * Support iterators in extend and __setslice__ for containers.

+

+2009-05-13 version 2.1.0:

+

+  General

+  * Repeated fields of primitive types (types other that string, group, and

+    nested messages) may now use the option [packed = true] to get a more

+    efficient encoding.  In the new encoding, the entire list is written

+    as a single byte blob using the "length-delimited" wire type.  Within

+    this blob, the individual values are encoded the same way they would

+    be normally except without a tag before each value (thus, they are

+    tightly "packed").

+  * For each field, the generated code contains an integer constant assigned

+    to the field number.  For example, the .proto file:

+      message Foo { optional int bar_baz = 123; }

+    would generate the following constants, all with the integer value 123:

+      C++:     Foo::kBarBazFieldNumber

+      Java:    Foo.BAR_BAZ_FIELD_NUMBER

+      Python:  Foo.BAR_BAZ_FIELD_NUMBER

+    Constants are also generated for extensions, with the same naming scheme.

+    These constants may be used as switch cases.

+  * Updated bundled Google Test to version 1.3.0.  Google Test is now bundled

+    in its verbatim form as a nested autoconf package, so you can drop in any

+    other version of Google Test if needed.

+  * optimize_for = SPEED is now the default, by popular demand.  Use

+    optimize_for = CODE_SIZE if code size is more important in your app.

+  * It is now an error to define a default value for a repeated field.

+    Previously, this was silently ignored (it had no effect on the generated

+    code).

+  * Fields can now be marked deprecated like:

+      optional int32 foo = 1 [deprecated = true];

+    Currently this does not have any actual effect, but in the future the code

+    generators may generate deprecation annotations in each language.

+  * Cross-compiling should now be possible using the --with-protoc option to

+    configure.  See README.txt for more info.

+

+  protoc

+  * --error_format=msvs option causes errors to be printed in Visual Studio

+    format, which should allow them to be clicked on in the build log to go

+    directly to the error location.

+  * The type name resolver will no longer resolve type names to fields.  For

+    example, this now works:

+      message Foo {}

+      message Bar {

+        optional int32 Foo = 1;

+        optional Foo baz = 2;

+      }

+    Previously, the type of "baz" would resolve to "Bar.Foo", and you'd get

+    an error because Bar.Foo is a field, not a type.  Now the type of "baz"

+    resolves to the message type Foo.  This change is unlikely to make a

+    difference to anyone who follows the Protocol Buffers style guide.

+

+  C++

+  * Several optimizations, including but not limited to:

+    - Serialization, especially to flat arrays, is 10%-50% faster, possibly

+      more for small objects.

+    - Several descriptor operations which previously required locking no longer

+      do.

+    - Descriptors are now constructed lazily on first use, rather than at

+      process startup time.  This should save memory in programs which do not

+      use descriptors or reflection.

+    - UnknownFieldSet completely redesigned to be more efficient (especially in

+      terms of memory usage).

+    - Various optimizations to reduce code size (though the serialization speed

+      optimizations increased code size).

+  * Message interface has method ParseFromBoundedZeroCopyStream() which parses

+    a limited number of bytes from an input stream rather than parsing until

+    EOF.

+  * GzipInputStream and GzipOutputStream support reading/writing gzip- or

+    zlib-compressed streams if zlib is available.

+    (google/protobuf/io/gzip_stream.h)

+  * DescriptorPool::FindAllExtensions() and corresponding

+    DescriptorDatabase::FindAllExtensions() can be used to enumerate all

+    extensions of a given type.

+  * For each enum type Foo, protoc will generate functions:

+      const string& Foo_Name(Foo value);

+      bool Foo_Parse(const string& name, Foo* result);

+    The former returns the name of the enum constant corresponding to the given

+    value while the latter finds the value corresponding to a name.

+  * RepeatedField and RepeatedPtrField now have back-insertion iterators.

+  * String fields now have setters that take a char* and a size, in addition

+    to the existing ones that took char* or const string&.

+  * DescriptorPool::AllowUnknownDependencies() may be used to tell

+    DescriptorPool to create placeholder descriptors for unknown entities

+    referenced in a FileDescriptorProto.  This can allow you to parse a .proto

+    file without having access to other .proto files that it imports, for

+    example.

+  * Updated gtest to latest version.  The gtest package is now included as a

+    nested autoconf package, so it should be able to drop new versions into the

+    "gtest" subdirectory without modification.

+

+  Java

+  * Fixed bug where Message.mergeFrom(Message) failed to merge extensions.

+  * Message interface has new method toBuilder() which is equivalent to

+    newBuilderForType().mergeFrom(this).

+  * All enums now implement the ProtocolMessageEnum interface.

+  * Setting a field to null now throws NullPointerException.

+  * Fixed tendency for TextFormat's parsing to overflow the stack when

+    parsing large string values.  The underlying problem is with Java's

+    regex implementation (which unfortunately uses recursive backtracking

+    rather than building an NFA).  Worked around by making use of possessive

+    quantifiers.

+  * Generated service classes now also generate pure interfaces.  For a service

+    Foo, Foo.Interface is a pure interface containing all of the service's

+    defined methods.  Foo.newReflectiveService() can be called to wrap an

+    instance of this interface in a class that implements the generic

+    RpcService interface, which provides reflection support that is usually

+    needed by RPC server implementations.

+  * RPC interfaces now support blocking operation in addition to non-blocking.

+    The protocol compiler generates separate blocking and non-blocking stubs

+    which operate against separate blocking and non-blocking RPC interfaces.

+    RPC implementations will have to implement the new interfaces in order to

+    support blocking mode.

+  * New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and

+    writeDelimitedTo() read and write "delimited" messages from/to a stream,

+    meaning that the message size precedes the data.  This way, you can write

+    multiple messages to a stream without having to worry about delimiting

+    them yourself.

+  * Throw a more descriptive exception when build() is double-called.

+  * Add a method to query whether CodedInputStream is at the end of the input

+    stream.

+  * Add a method to reset a CodedInputStream's size counter; useful when

+    reading many messages with the same stream.

+  * equals() and hashCode() now account for unknown fields.

+

+  Python

+  * Added slicing support for repeated scalar fields. Added slice retrieval and

+    removal of repeated composite fields.

+  * Updated RPC interfaces to allow for blocking operation.  A client may

+    now pass None for a callback when making an RPC, in which case the

+    call will block until the response is received, and the response

+    object will be returned directly to the caller.  This interface change

+    cannot be used in practice until RPC implementations are updated to

+    implement it.

+  * Changes to input_stream.py should make protobuf compatible with appengine.

+

+2008-11-25 version 2.0.3:

+

+  protoc

+  * Enum values may now have custom options, using syntax similar to field

+    options.

+  * Fixed bug where .proto files which use custom options but don't actually

+    define them (i.e. they import another .proto file defining the options)

+    had to explicitly import descriptor.proto.

+  * Adjacent string literals in .proto files will now be concatenated, like in

+    C.

+  * If an input file is a Windows absolute path (e.g. "C:\foo\bar.proto") and

+    the import path only contains "." (or contains "." but does not contain

+    the file), protoc incorrectly thought that the file was under ".", because

+    it thought that the path was relative (since it didn't start with a slash).

+    This has been fixed.

+

+  C++

+  * Generated message classes now have a Swap() method which efficiently swaps

+    the contents of two objects.

+  * All message classes now have a SpaceUsed() method which returns an estimate

+    of the number of bytes of allocated memory currently owned by the object.

+    This is particularly useful when you are reusing a single message object

+    to improve performance but want to make sure it doesn't bloat up too large.

+  * New method Message::SerializeAsString() returns a string containing the

+    serialized data.  May be more convenient than calling

+    SerializeToString(string*).

+  * In debug mode, log error messages when string-type fields are found to

+    contain bytes that are not valid UTF-8.

+  * Fixed bug where a message with multiple extension ranges couldn't parse

+    extensions.

+  * Fixed bug where MergeFrom(const Message&) didn't do anything if invoked on

+    a message that contained no fields (but possibly contained extensions).

+  * Fixed ShortDebugString() to not be O(n^2).  Durr.

+  * Fixed crash in TextFormat parsing if the first token in the input caused a

+    tokenization error.

+  * Fixed obscure bugs in zero_copy_stream_impl.cc.

+  * Added support for HP C++ on Tru64.

+  * Only build tests on "make check", not "make".

+  * Fixed alignment issue that caused crashes when using DynamicMessage on

+    64-bit Sparc machines.

+  * Simplify template usage to work with MSVC 2003.

+  * Work around GCC 4.3.x x86_64 compiler bug that caused crashes on startup.

+    (This affected Fedora 9 in particular.)

+  * Now works on "Solaris 10 using recent Sun Studio".

+

+  Java

+  * New overload of mergeFrom() which parses a slice of a byte array instead

+    of the whole thing.

+  * New method ByteString.asReadOnlyByteBuffer() does what it sounds like.

+  * Improved performance of isInitialized() when optimizing for code size.

+

+  Python

+  * Corrected ListFields() signature in Message base class to match what

+    subclasses actually implement.

+  * Some minor refactoring.

+  * Don't pass self as first argument to superclass constructor (no longer

+    allowed in Python 2.6).

+

+2008-09-29 version 2.0.2:

+

+  General

+  * License changed from Apache 2.0 to 3-Clause BSD.

+  * It is now possible to define custom "options", which are basically

+    annotations which may be placed on definitions in a .proto file.

+    For example, you might define a field option called "foo" like so:

+      import "google/protobuf/descriptor.proto"

+      extend google.protobuf.FieldOptions {

+        optional string foo = 12345;

+      }

+    Then you annotate a field using the "foo" option:

+      message MyMessage {

+        optional int32 some_field = 1 [(foo) = "bar"]

+      }

+    The value of this option is then visible via the message's

+    Descriptor:

+      const FieldDescriptor* field =

+        MyMessage::descriptor()->FindFieldByName("some_field");

+      assert(field->options().GetExtension(foo) == "bar");

+    This feature has been implemented and tested in C++ and Java.

+    Other languages may or may not need to do extra work to support

+    custom options, depending on how they construct descriptors.

+

+  C++

+  * Fixed some GCC warnings that only occur when using -pedantic.

+  * Improved static initialization code, making ordering more

+    predictable among other things.

+  * TextFormat will no longer accept messages which contain multiple

+    instances of a singular field.  Previously, the latter instance

+    would overwrite the former.

+  * Now works on systems that don't have hash_map.

+

+  Java

+  * Print @Override annotation in generated code where appropriate.

+

+  Python

+  * Strings now use the "unicode" type rather than the "str" type.

+    String fields may still be assigned ASCII "str" values; they will

+    automatically be converted.

+  * Adding a property to an object representing a repeated field now

+    raises an exception.  For example:

+      # No longer works (and never should have).

+      message.some_repeated_field.foo = 1

+

+  Windows

+  * We now build static libraries rather than DLLs by default on MSVC.

+    See vsprojects/readme.txt for more information.

+

+2008-08-15 version 2.0.1:

+

+  protoc

+  * New flags --encode and --decode can be used to convert between protobuf text

+    format and binary format from the command-line.

+  * New flag --descriptor_set_out can be used to write FileDescriptorProtos for

+    all parsed files directly into a single output file.  This is particularly

+    useful if you wish to parse .proto files from programs written in languages

+    other than C++: just run protoc as a background process and have it output

+    a FileDescriptorList, then parse that natively.

+  * Improved error message when an enum value's name conflicts with another

+    symbol defined in the enum type's scope, e.g. if two enum types declared

+    in the same scope have values with the same name.  This is disallowed for

+    compatibility with C++, but this wasn't clear from the error.

+  * Fixed absolute output paths on Windows.

+  * Allow trailing slashes in --proto_path mappings.

+

+  C++

+  * Reflection objects are now per-class rather than per-instance.  To make this

+    possible, the Reflection interface had to be changed such that all methods

+    take the Message instance as a parameter.  This change improves performance

+    significantly in memory-bandwidth-limited use cases, since it makes the

+    message objects smaller.  Note that source-incompatible interface changes

+    like this will not be made again after the library leaves beta.

+  * Heuristically detect sub-messages when printing unknown fields.

+  * Fix static initialization ordering bug that caused crashes at startup when

+    compiling on Mac with static linking.

+  * Fixed TokenizerTest when compiling with -DNDEBUG on Linux.

+  * Fixed incorrect definition of kint32min.

+  * Fix bytes type setter to work with byte sequences with embedded NULLs.

+  * Other irrelevant tweaks.

+

+  Java

+  * Fixed UnknownFieldSet's parsing of varints larger than 32 bits.

+  * Fixed TextFormat's parsing of "inf" and "nan".

+  * Fixed TextFormat's parsing of comments.

+  * Added info to Java POM that will be required when we upload the

+    package to a Maven repo.

+

+  Python

+  * MergeFrom(message) and CopyFrom(message) are now implemented.

+  * SerializeToString() raises an exception if the message is missing required

+    fields.

+  * Code organization improvements.

+  * Fixed doc comments for RpcController and RpcChannel, which had somehow been

+    swapped.

+  * Fixed text_format_test on Windows where floating-point exponents sometimes

+    contain extra zeros.

+  * Fix Python service CallMethod() implementation.

+

+  Other

+  * Improved readmes.

+  * VIM syntax highlighting improvements.

+

+2008-07-07 version 2.0.0:

+

+  * First public release.

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..19b305b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+Copyright 2008 Google Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Code generated by the Protocol Buffer compiler is owned by the owner
+of the input file used when generating it.  This code is not
+standalone and requires a support library to be linked with it.  This
+support library is itself covered by the above license.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..cb22baf
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,12 @@
+name: "protobuf"
+description:
+    "Prebuilts protoc binary and protobuf python library."
+
+third_party {
+  url {
+    type: GIT
+    value: "https://github.com/protocolbuffers/protobuf/releases/download/v21.9/"
+  }
+  version: "21.9"
+  last_upgrade_date { year: 2022 month: 10 }
+}
diff --git a/bin/protoc b/bin/protoc
new file mode 100755
index 0000000..01cfb64
--- /dev/null
+++ b/bin/protoc
Binary files differ
diff --git a/include/google/protobuf/any.proto b/include/google/protobuf/any.proto
new file mode 100644
index 0000000..e2c2042
--- /dev/null
+++ b/include/google/protobuf/any.proto
@@ -0,0 +1,158 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "google.golang.org/protobuf/types/known/anypb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// `Any` contains an arbitrary serialized protocol buffer message along with a
+// URL that describes the type of the serialized message.
+//
+// Protobuf library provides support to pack/unpack Any values in the form
+// of utility functions or additional generated methods of the Any type.
+//
+// Example 1: Pack and unpack a message in C++.
+//
+//     Foo foo = ...;
+//     Any any;
+//     any.PackFrom(foo);
+//     ...
+//     if (any.UnpackTo(&foo)) {
+//       ...
+//     }
+//
+// Example 2: Pack and unpack a message in Java.
+//
+//     Foo foo = ...;
+//     Any any = Any.pack(foo);
+//     ...
+//     if (any.is(Foo.class)) {
+//       foo = any.unpack(Foo.class);
+//     }
+//
+// Example 3: Pack and unpack a message in Python.
+//
+//     foo = Foo(...)
+//     any = Any()
+//     any.Pack(foo)
+//     ...
+//     if any.Is(Foo.DESCRIPTOR):
+//       any.Unpack(foo)
+//       ...
+//
+// Example 4: Pack and unpack a message in Go
+//
+//      foo := &pb.Foo{...}
+//      any, err := anypb.New(foo)
+//      if err != nil {
+//        ...
+//      }
+//      ...
+//      foo := &pb.Foo{}
+//      if err := any.UnmarshalTo(foo); err != nil {
+//        ...
+//      }
+//
+// The pack methods provided by protobuf library will by default use
+// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+// methods only use the fully qualified type name after the last '/'
+// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+// name "y.z".
+//
+//
+// JSON
+//
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+//     package google.profile;
+//     message Person {
+//       string first_name = 1;
+//       string last_name = 2;
+//     }
+//
+//     {
+//       "@type": "type.googleapis.com/google.profile.Person",
+//       "firstName": <string>,
+//       "lastName": <string>
+//     }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
+//
+//     {
+//       "@type": "type.googleapis.com/google.protobuf.Duration",
+//       "value": "1.212s"
+//     }
+//
+message Any {
+  // A URL/resource name that uniquely identifies the type of the serialized
+  // protocol buffer message. This string must contain at least
+  // one "/" character. The last segment of the URL's path must represent
+  // the fully qualified name of the type (as in
+  // `path/google.protobuf.Duration`). The name should be in a canonical form
+  // (e.g., leading "." is not accepted).
+  //
+  // In practice, teams usually precompile into the binary all types that they
+  // expect it to use in the context of Any. However, for URLs which use the
+  // scheme `http`, `https`, or no scheme, one can optionally set up a type
+  // server that maps type URLs to message definitions as follows:
+  //
+  // * If no scheme is provided, `https` is assumed.
+  // * 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.)
+  //
+  // Note: this functionality is not currently available in the official
+  // protobuf release, and it is not used for type URLs beginning with
+  // type.googleapis.com.
+  //
+  // Schemes other than `http`, `https` (or the empty scheme) might be
+  // used with implementation specific semantics.
+  //
+  string type_url = 1;
+
+  // Must be a valid serialized protocol buffer of the above specified type.
+  bytes value = 2;
+}
diff --git a/include/google/protobuf/api.proto b/include/google/protobuf/api.proto
new file mode 100644
index 0000000..3d598fc
--- /dev/null
+++ b/include/google/protobuf/api.proto
@@ -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.
+
+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 objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/apipb";
+
+// Api is a light-weight descriptor for an API Interface.
+//
+// Interfaces are also described as "protocol buffer services" in some contexts,
+// such as by the "service" keyword in a .proto file, but they are different
+// from API Services, which represent a concrete implementation of an interface
+// as opposed to simply a description of methods and bindings. They are also
+// sometimes simply referred to as "APIs" in other contexts, such as the name of
+// this message itself. See https://cloud.google.com/apis/design/glossary for
+// detailed terminology.
+message Api {
+  // The fully qualified name of this interface, including package name
+  // followed by the interface's simple name.
+  string name = 1;
+
+  // The methods of this interface, in unspecified order.
+  repeated Method methods = 2;
+
+  // Any metadata attached to the interface.
+  repeated Option options = 3;
+
+  // A version string for this interface. 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
+  // interface, 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, non-GA interfaces.
+  //
+  //
+  string version = 4;
+
+  // Source context for the protocol buffer service represented by this
+  // message.
+  SourceContext source_context = 5;
+
+  // Included interfaces. See [Mixin][].
+  repeated Mixin mixins = 6;
+
+  // The source syntax of the service.
+  Syntax syntax = 7;
+}
+
+// Method represents a method of an API interface.
+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 Interface to be included in this interface. The including
+// interface must redeclare all the methods from the included interface, 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 interface 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 inheriting
+// 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 interface 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/include/google/protobuf/compiler/plugin.proto b/include/google/protobuf/compiler/plugin.proto
new file mode 100644
index 0000000..9242aac
--- /dev/null
+++ b/include/google/protobuf/compiler/plugin.proto
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// WARNING:  The plugin interface is currently EXPERIMENTAL and is subject to
+//   change.
+//
+// protoc (aka the Protocol Compiler) can be extended via plugins.  A plugin is
+// just a program that reads a CodeGeneratorRequest from stdin and writes a
+// CodeGeneratorResponse to stdout.
+//
+// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead
+// of dealing with the raw protocol defined here.
+//
+// A plugin executable needs only to be placed somewhere in the path.  The
+// plugin should be named "protoc-gen-$NAME", and will then be used when the
+// flag "--${NAME}_out" is passed to protoc.
+
+syntax = "proto2";
+
+package google.protobuf.compiler;
+option java_package = "com.google.protobuf.compiler";
+option java_outer_classname = "PluginProtos";
+
+option go_package = "google.golang.org/protobuf/types/pluginpb";
+
+import "google/protobuf/descriptor.proto";
+
+// The version number of protocol compiler.
+message Version {
+  optional int32 major = 1;
+  optional int32 minor = 2;
+  optional int32 patch = 3;
+  // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
+  // be empty for mainline stable releases.
+  optional string suffix = 4;
+}
+
+// An encoded CodeGeneratorRequest is written to the plugin's stdin.
+message CodeGeneratorRequest {
+  // The .proto files that were explicitly listed on the command-line.  The
+  // code generator should generate code only for these files.  Each file's
+  // descriptor will be included in proto_file, below.
+  repeated string file_to_generate = 1;
+
+  // The generator parameter passed on the command-line.
+  optional string parameter = 2;
+
+  // FileDescriptorProtos for all files in files_to_generate and everything
+  // they import.  The files will appear in topological order, so each file
+  // appears before any file that imports it.
+  //
+  // protoc guarantees that all proto_files will be written after
+  // the fields above, even though this is not technically guaranteed by the
+  // protobuf wire format.  This theoretically could allow a plugin to stream
+  // in the FileDescriptorProtos and handle them one by one rather than read
+  // the entire set into memory at once.  However, as of this writing, this
+  // is not similarly optimized on protoc's end -- it will store all fields in
+  // memory at once before sending them to the plugin.
+  //
+  // Type names of fields and extensions in the FileDescriptorProto are always
+  // fully qualified.
+  repeated FileDescriptorProto proto_file = 15;
+
+  // The version number of protocol compiler.
+  optional Version compiler_version = 3;
+
+}
+
+// The plugin writes an encoded CodeGeneratorResponse to stdout.
+message CodeGeneratorResponse {
+  // Error message.  If non-empty, code generation failed.  The plugin process
+  // should exit with status code zero even if it reports an error in this way.
+  //
+  // This should be used to indicate errors in .proto files which prevent the
+  // code generator from generating correct code.  Errors which indicate a
+  // problem in protoc itself -- such as the input CodeGeneratorRequest being
+  // unparseable -- should be reported by writing a message to stderr and
+  // exiting with a non-zero status code.
+  optional string error = 1;
+
+  // A bitmask of supported features that the code generator supports.
+  // This is a bitwise "or" of values from the Feature enum.
+  optional uint64 supported_features = 2;
+
+  // Sync with code_generator.h.
+  enum Feature {
+    FEATURE_NONE = 0;
+    FEATURE_PROTO3_OPTIONAL = 1;
+  }
+
+  // Represents a single generated file.
+  message File {
+    // The file name, relative to the output directory.  The name must not
+    // contain "." or ".." components and must be relative, not be absolute (so,
+    // the file cannot lie outside the output directory).  "/" must be used as
+    // the path separator, not "\".
+    //
+    // If the name is omitted, the content will be appended to the previous
+    // file.  This allows the generator to break large files into small chunks,
+    // and allows the generated text to be streamed back to protoc so that large
+    // files need not reside completely in memory at one time.  Note that as of
+    // this writing protoc does not optimize for this -- it will read the entire
+    // CodeGeneratorResponse before writing files to disk.
+    optional string name = 1;
+
+    // If non-empty, indicates that the named file should already exist, and the
+    // content here is to be inserted into that file at a defined insertion
+    // point.  This feature allows a code generator to extend the output
+    // produced by another code generator.  The original generator may provide
+    // insertion points by placing special annotations in the file that look
+    // like:
+    //   @@protoc_insertion_point(NAME)
+    // The annotation can have arbitrary text before and after it on the line,
+    // which allows it to be placed in a comment.  NAME should be replaced with
+    // an identifier naming the point -- this is what other generators will use
+    // as the insertion_point.  Code inserted at this point will be placed
+    // immediately above the line containing the insertion point (thus multiple
+    // insertions to the same point will come out in the order they were added).
+    // The double-@ is intended to make it unlikely that the generated code
+    // could contain things that look like insertion points by accident.
+    //
+    // For example, the C++ code generator places the following line in the
+    // .pb.h files that it generates:
+    //   // @@protoc_insertion_point(namespace_scope)
+    // This line appears within the scope of the file's package namespace, but
+    // outside of any particular class.  Another plugin can then specify the
+    // insertion_point "namespace_scope" to generate additional classes or
+    // other declarations that should be placed in this scope.
+    //
+    // Note that if the line containing the insertion point begins with
+    // whitespace, the same whitespace will be added to every line of the
+    // inserted text.  This is useful for languages like Python, where
+    // indentation matters.  In these languages, the insertion point comment
+    // should be indented the same amount as any inserted code will need to be
+    // in order to work correctly in that context.
+    //
+    // The code generator that generates the initial file and the one which
+    // inserts into it must both run as part of a single invocation of protoc.
+    // Code generators are executed in the order in which they appear on the
+    // command line.
+    //
+    // If |insertion_point| is present, |name| must also be present.
+    optional string insertion_point = 2;
+
+    // The file contents.
+    optional string content = 15;
+
+    // Information describing the file content being inserted. If an insertion
+    // point is used, this information will be appropriately offset and inserted
+    // into the code generation metadata for the generated files.
+    optional GeneratedCodeInfo generated_code_info = 16;
+  }
+  repeated File file = 15;
+}
diff --git a/include/google/protobuf/descriptor.proto b/include/google/protobuf/descriptor.proto
new file mode 100644
index 0000000..f8eb216
--- /dev/null
+++ b/include/google/protobuf/descriptor.proto
@@ -0,0 +1,921 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+syntax = "proto2";
+
+package google.protobuf;
+
+option go_package = "google.golang.org/protobuf/types/descriptorpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+  repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+  optional string name = 1;     // file name, relative to root of source tree
+  optional string package = 2;  // e.g. "foo", "foo.bar", etc.
+
+  // Names of files imported by this file.
+  repeated string dependency = 3;
+  // Indexes of the public imported files in the dependency list above.
+  repeated int32 public_dependency = 10;
+  // Indexes of the weak imported files in the dependency list.
+  // For Google-internal migration only. Do not use.
+  repeated int32 weak_dependency = 11;
+
+  // All top-level definitions in this file.
+  repeated DescriptorProto message_type = 4;
+  repeated EnumDescriptorProto enum_type = 5;
+  repeated ServiceDescriptorProto service = 6;
+  repeated FieldDescriptorProto extension = 7;
+
+  optional FileOptions options = 8;
+
+  // 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.
+  optional SourceCodeInfo source_code_info = 9;
+
+  // The syntax of the proto file.
+  // The supported values are "proto2" and "proto3".
+  optional string syntax = 12;
+}
+
+// Describes a message type.
+message DescriptorProto {
+  optional string name = 1;
+
+  repeated FieldDescriptorProto field = 2;
+  repeated FieldDescriptorProto extension = 6;
+
+  repeated DescriptorProto nested_type = 3;
+  repeated EnumDescriptorProto enum_type = 4;
+
+  message ExtensionRange {
+    optional int32 start = 1;  // Inclusive.
+    optional int32 end = 2;    // Exclusive.
+
+    optional ExtensionRangeOptions options = 3;
+  }
+  repeated ExtensionRange extension_range = 5;
+
+  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;
+}
+
+message ExtensionRangeOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+  enum Type {
+    // 0 is reserved for errors.
+    // Order is weird for historical reasons.
+    TYPE_DOUBLE = 1;
+    TYPE_FLOAT = 2;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+    // negative values are likely.
+    TYPE_INT64 = 3;
+    TYPE_UINT64 = 4;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+    // negative values are likely.
+    TYPE_INT32 = 5;
+    TYPE_FIXED64 = 6;
+    TYPE_FIXED32 = 7;
+    TYPE_BOOL = 8;
+    TYPE_STRING = 9;
+    // Tag-delimited aggregate.
+    // Group type is deprecated and not supported in proto3. However, Proto3
+    // implementations should still be able to parse the group wire format and
+    // treat group fields as unknown fields.
+    TYPE_GROUP = 10;
+    TYPE_MESSAGE = 11;  // Length-delimited aggregate.
+
+    // New in version 2.
+    TYPE_BYTES = 12;
+    TYPE_UINT32 = 13;
+    TYPE_ENUM = 14;
+    TYPE_SFIXED32 = 15;
+    TYPE_SFIXED64 = 16;
+    TYPE_SINT32 = 17;  // Uses ZigZag encoding.
+    TYPE_SINT64 = 18;  // Uses ZigZag encoding.
+  }
+
+  enum Label {
+    // 0 is reserved for errors
+    LABEL_OPTIONAL = 1;
+    LABEL_REQUIRED = 2;
+    LABEL_REPEATED = 3;
+  }
+
+  optional string name = 1;
+  optional int32 number = 3;
+  optional Label label = 4;
+
+  // 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.
+  optional Type type = 5;
+
+  // 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).
+  optional string type_name = 6;
+
+  // For extensions, this is the name of the type being extended.  It is
+  // resolved in the same manner as type_name.
+  optional string extendee = 2;
+
+  // 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.
+  optional string default_value = 7;
+
+  // If set, gives the index of a oneof in the containing type's oneof_decl
+  // list.  This field is a member of that oneof.
+  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;
+
+  // If true, this is a proto3 "optional". When a proto3 field is optional, it
+  // tracks presence regardless of field type.
+  //
+  // When proto3_optional is true, this field must be belong to a oneof to
+  // signal to old proto3 clients that presence is tracked for this field. This
+  // oneof is known as a "synthetic" oneof, and this field must be its sole
+  // member (each proto3 optional field gets its own synthetic oneof). Synthetic
+  // oneofs exist in the descriptor only, and do not generate any API. Synthetic
+  // oneofs must be ordered after all "real" oneofs.
+  //
+  // For message fields, proto3_optional doesn't create any semantic change,
+  // since non-repeated message fields always track presence. However it still
+  // indicates the semantic detail of whether the user wrote "optional" or not.
+  // This can be useful for round-tripping the .proto file. For consistency we
+  // give message fields a synthetic oneof also, even though it is not required
+  // to track presence. This is especially important because the parser can't
+  // tell if a field is a message or an enum, so it must always create a
+  // synthetic oneof.
+  //
+  // Proto2 optional fields do not set this flag, because they already indicate
+  // optional with `LABEL_OPTIONAL`.
+  optional bool proto3_optional = 17;
+}
+
+// Describes a oneof.
+message OneofDescriptorProto {
+  optional string name = 1;
+  optional OneofOptions options = 2;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+  optional string name = 1;
+
+  repeated EnumValueDescriptorProto value = 2;
+
+  optional EnumOptions options = 3;
+
+  // Range of reserved numeric values. Reserved values may not be used by
+  // entries in the same enum. Reserved ranges may not overlap.
+  //
+  // Note that this is distinct from DescriptorProto.ReservedRange in that it
+  // is inclusive such that it can appropriately represent the entire int32
+  // domain.
+  message EnumReservedRange {
+    optional int32 start = 1;  // Inclusive.
+    optional int32 end = 2;    // Inclusive.
+  }
+
+  // Range of reserved numeric values. Reserved numeric values may not be used
+  // by enum values in the same enum declaration. Reserved ranges may not
+  // overlap.
+  repeated EnumReservedRange reserved_range = 4;
+
+  // Reserved enum value names, which may not be reused. A given name may only
+  // be reserved once.
+  repeated string reserved_name = 5;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+  optional string name = 1;
+  optional int32 number = 2;
+
+  optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+  optional string name = 1;
+  repeated MethodDescriptorProto method = 2;
+
+  optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+  optional string name = 1;
+
+  // Input and output type names.  These are resolved in the same way as
+  // FieldDescriptorProto.type_name, but must refer to a message type.
+  optional string input_type = 2;
+  optional string output_type = 3;
+
+  optional MethodOptions options = 4;
+
+  // Identifies if client streams multiple client messages
+  optional bool client_streaming = 5 [default = false];
+  // Identifies if server streams multiple server messages
+  optional bool server_streaming = 6 [default = false];
+}
+
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached.  These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them.  Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+//   organization, or for experimental options, use field numbers 50000
+//   through 99999.  It is up to you to ensure that you do not use the
+//   same number for multiple options.
+// * 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.
+//   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.
+
+message FileOptions {
+
+  // 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.
+  optional string java_package = 1;
+
+
+  // Controls the name of the wrapper Java class generated for the .proto file.
+  // That class will always contain the .proto file's getDescriptor() method as
+  // well as any top-level extensions defined in the .proto file.
+  // If java_multiple_files is disabled, then all the other classes from the
+  // .proto file will be nested inside the single wrapper outer class.
+  optional string java_outer_classname = 8;
+
+  // If enabled, 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 wrapper class
+  // named by java_outer_classname.  However, the wrapper class will still be
+  // generated to contain the file's getDescriptor() method as well as any
+  // top-level extensions defined in the file.
+  optional bool java_multiple_files = 10 [default = false];
+
+  // This option does nothing.
+  optional bool java_generate_equals_and_hash = 20 [deprecated=true];
+
+  // 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.
+  optional bool java_string_check_utf8 = 27 [default = false];
+
+
+  // Generated classes can be optimized for speed or code size.
+  enum OptimizeMode {
+    SPEED = 1;         // Generate complete code for parsing, serialization,
+                       // etc.
+    CODE_SIZE = 2;     // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3;  // Generate code using MessageLite and the lite runtime.
+  }
+  optional OptimizeMode optimize_for = 9 [default = SPEED];
+
+  // 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.
+  optional string go_package = 11;
+
+
+
+
+  // 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.
+  optional bool cc_generic_services = 16 [default = false];
+  optional bool java_generic_services = 17 [default = false];
+  optional bool py_generic_services = 18 [default = false];
+  optional bool php_generic_services = 42 [default = false];
+
+  // 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.
+  optional bool deprecated = 23 [default = false];
+
+  // Enables the use of arenas for the proto messages in this file. This applies
+  // only to generated classes for C++.
+  optional bool cc_enable_arenas = 31 [default = true];
+
+
+  // Sets the objective c class prefix which is prepended to all objective c
+  // generated classes from this .proto. There is no default.
+  optional string objc_class_prefix = 36;
+
+  // Namespace for generated classes; defaults to the package.
+  optional string csharp_namespace = 37;
+
+  // By default Swift generators will take the proto package and CamelCase it
+  // replacing '.' with underscore and use that to prefix the types/symbols
+  // defined. When this options is provided, they will use this value instead
+  // to prefix the types/symbols defined.
+  optional string swift_prefix = 39;
+
+  // Sets the php class prefix which is prepended to all php generated classes
+  // from this .proto. Default is empty.
+  optional string php_class_prefix = 40;
+
+  // Use this option to change the namespace of php generated classes. Default
+  // is empty. When this option is empty, the package name will be used for
+  // determining the namespace.
+  optional string php_namespace = 41;
+
+  // Use this option to change the namespace of php generated metadata classes.
+  // Default is empty. When this option is empty, the proto file name will be
+  // used for determining the namespace.
+  optional string php_metadata_namespace = 44;
+
+  // Use this option to change the package of ruby generated classes. Default
+  // is empty. When this option is not set, the package name will be used for
+  // determining the ruby package.
+  optional string ruby_package = 45;
+
+
+  // The parser stores options it doesn't recognize here.
+  // See the documentation for the "Options" section above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message.
+  // See the documentation for the "Options" section above.
+  extensions 1000 to max;
+
+  reserved 38;
+}
+
+message MessageOptions {
+  // 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.
+  optional bool message_set_wire_format = 1 [default = false];
+
+  // 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".
+  optional bool no_standard_descriptor_accessor = 2 [default = false];
+
+  // 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.
+  optional bool deprecated = 3 [default = false];
+
+  reserved 4, 5, 6;
+
+  // 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 implementations still need to work as
+  // if the field is a repeated message field.
+  //
+  // NOTE: Do not set the option in .proto files. Always use the maps syntax
+  // instead. The option should only be implicitly set by the proto compiler
+  // parser.
+  optional bool map_entry = 7;
+
+  reserved 8;  // javalite_serializable
+  reserved 9;  // javanano_as_lite
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message FieldOptions {
+  // 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!
+  optional CType ctype = 1 [default = STRING];
+  enum CType {
+    // Default mode.
+    STRING = 0;
+
+    CORD = 1;
+
+    STRING_PIECE = 2;
+  }
+  // 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.
+  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).  A field with jstype JS_STRING
+  // is represented as JavaScript string, which avoids loss of precision that
+  // can happen when a large value is converted to a floating point JavaScript.
+  // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+  // use the JavaScript "number" type.  The behavior of the default option
+  // JS_NORMAL is implementation dependent.
+  //
+  // 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
+  // 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 outer 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.
+  //
+  // As of 2021, lazy does no correctness checks on the byte stream during
+  // parsing.  This may lead to crashes if and when an invalid byte stream is
+  // finally parsed upon access.
+  //
+  // TODO(b/211906113):  Enable validation on lazy fields.
+  optional bool lazy = 5 [default = false];
+
+  // unverified_lazy does no correctness checks on the byte stream. This should
+  // only be used where lazy with verification is prohibitive for performance
+  // reasons.
+  optional bool unverified_lazy = 15 [default = false];
+
+  // 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.
+  optional bool deprecated = 3 [default = false];
+
+  // For Google-internal migration only. Do not use.
+  optional bool weak = 10 [default = false];
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+
+  reserved 4;  // removed jtype
+}
+
+message OneofOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumOptions {
+
+  // Set this option to true to allow mapping different tag names to the same
+  // value.
+  optional bool allow_alias = 2;
+
+  // 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.
+  optional bool deprecated = 3 [default = false];
+
+  reserved 5;  // javanano_as_lite
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumValueOptions {
+  // 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.
+  optional bool deprecated = 1 [default = false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // 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.
+  optional bool deprecated = 33 [default = false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MethodOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // 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.
+  optional bool deprecated = 33 [default = false];
+
+  // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
+  // or neither? HTTP based RPC implementation may choose GET verb for safe
+  // methods, and PUT verb for idempotent methods instead of the default POST.
+  enum IdempotencyLevel {
+    IDEMPOTENCY_UNKNOWN = 0;
+    NO_SIDE_EFFECTS = 1;  // implies idempotent
+    IDEMPOTENT = 2;       // idempotent, but may have side effects
+  }
+  optional IdempotencyLevel idempotency_level = 34
+      [default = IDEMPOTENCY_UNKNOWN];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+
+// 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.
+message UninterpretedOption {
+  // 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], ["moo", false] } represents
+  // "foo.(bar.baz).moo".
+  message NamePart {
+    required string name_part = 1;
+    required bool is_extension = 2;
+  }
+  repeated NamePart name = 2;
+
+  // The value of the uninterpreted option, in whatever type the tokenizer
+  // identified it as during parsing. Exactly one of these should be set.
+  optional string identifier_value = 3;
+  optional uint64 positive_int_value = 4;
+  optional int64 negative_int_value = 5;
+  optional double double_value = 6;
+  optional bytes string_value = 7;
+  optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+  // 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 descendant.  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.
+  repeated Location location = 1;
+  message Location {
+    // 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 occurs.
+    // 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).
+    repeated int32 path = 1 [packed = true];
+
+    // 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.
+    repeated int32 span = 2 [packed = true];
+
+    // 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 moo.
+    //   //
+    //   // Another line attached to moo.
+    //   optional double moo = 4;
+    //
+    //   // Detached comment for corge. This is not leading or trailing comments
+    //   // to moo 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.
+    optional string leading_comments = 3;
+    optional string trailing_comments = 4;
+    repeated string leading_detached_comments = 6;
+  }
+}
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+  // An Annotation connects some span of text in generated code to an element
+  // of its generating .proto file.
+  repeated Annotation annotation = 1;
+  message Annotation {
+    // Identifies the element in the original source .proto file. This field
+    // is formatted the same as SourceCodeInfo.Location.path.
+    repeated int32 path = 1 [packed = true];
+
+    // Identifies the filesystem path to the original source .proto.
+    optional string source_file = 2;
+
+    // Identifies the starting offset in bytes in the generated code
+    // that relates to the identified object.
+    optional int32 begin = 3;
+
+    // Identifies the ending offset in bytes in the generated code that
+    // relates to the identified offset. The end offset should be one past
+    // the last relevant byte (so the length of the text = end - begin).
+    optional int32 end = 4;
+  }
+}
diff --git a/include/google/protobuf/duration.proto b/include/google/protobuf/duration.proto
new file mode 100644
index 0000000..81c3e36
--- /dev/null
+++ b/include/google/protobuf/duration.proto
@@ -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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/durationpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DurationProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// A Duration represents a signed, fixed-length span of time represented
+// as a count of seconds and fractions of seconds at nanosecond
+// resolution. It is independent of any calendar and concepts like "day"
+// or "month". It is related to Timestamp in that the difference between
+// two Timestamp values is a Duration and it can be added or subtracted
+// from a Timestamp. Range is approximately +-10,000 years.
+//
+// # Examples
+//
+// 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 (duration.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;
+//     }
+//
+// Example 3: Compute Duration from datetime.timedelta in Python.
+//
+//     td = datetime.timedelta(days=3, minutes=10)
+//     duration = Duration()
+//     duration.FromTimedelta(td)
+//
+// # JSON Mapping
+//
+// In JSON format, the Duration type is encoded as a string rather than an
+// object, where the string ends in the suffix "s" (indicating seconds) and
+// is preceded by the number of seconds, with nanoseconds expressed as
+// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
+// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
+// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
+// microsecond should be expressed in JSON format as "3.000001s".
+//
+//
+message Duration {
+  // Signed seconds of the span of time. Must be from -315,576,000,000
+  // to +315,576,000,000 inclusive. Note: these bounds are computed from:
+  // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
+  int64 seconds = 1;
+
+  // Signed fractions of a second at nanosecond resolution of the span
+  // of time. Durations less than one second are represented with a 0
+  // `seconds` field and a positive or negative `nanos` field. For durations
+  // of one second or more, a non-zero value for the `nanos` field must be
+  // of the same sign as the `seconds` field. Must be from -999,999,999
+  // to +999,999,999 inclusive.
+  int32 nanos = 2;
+}
diff --git a/include/google/protobuf/empty.proto b/include/google/protobuf/empty.proto
new file mode 100644
index 0000000..2227462
--- /dev/null
+++ b/include/google/protobuf/empty.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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "google.golang.org/protobuf/types/known/emptypb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = 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);
+//     }
+//
+message Empty {}
diff --git a/include/google/protobuf/field_mask.proto b/include/google/protobuf/field_mask.proto
new file mode 100644
index 0000000..6b5104f
--- /dev/null
+++ b/include/google/protobuf/field_mask.proto
@@ -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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldMaskProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb";
+option cc_enable_arenas = true;
+
+// `FieldMask` represents a set of symbolic field paths, for example:
+//
+//     paths: "f.a"
+//     paths: "f.b.d"
+//
+// Here `f` represents a field in some root message, `a` and `b`
+// fields in the message found in `f`, and `d` a field found in the
+// message in `f.b`.
+//
+// Field masks are used to specify a subset of fields that should be
+// returned by a get operation or modified by an update operation.
+// Field masks also have a custom JSON encoding (see below).
+//
+// # Field Masks in Projections
+//
+// When used in the context of a projection, a response message or
+// sub-message is filtered by the API to only contain those fields as
+// specified in the mask. For example, if the mask in the previous
+// example is applied to a response message as follows:
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//         x : 2
+//       }
+//       y : 13
+//     }
+//     z: 8
+//
+// The result will not contain specific values for fields x,y and z
+// (their value will be set to the default, and omitted in proto text
+// output):
+//
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//       }
+//     }
+//
+// A repeated field is not allowed except at the last position of a
+// paths string.
+//
+// If a FieldMask object is not present in a get operation, the
+// operation applies to all fields (as if a FieldMask of all fields
+// had been specified).
+//
+// Note that a field mask does not necessarily apply to the
+// top-level response message. In case of a REST get operation, the
+// field mask applies directly to the response, but in case of a REST
+// list operation, the mask instead applies to each individual message
+// in the returned resource list. In case of a REST custom method,
+// other definitions may be used. Where the mask applies will be
+// clearly documented together with its declaration in the API.  In
+// any case, the effect on the returned resource/resources is required
+// behavior for APIs.
+//
+// # Field Masks in Update Operations
+//
+// A field mask in update operations specifies which fields of the
+// targeted resource are going to be updated. The API is required
+// to only change the values of the fields as specified in the mask
+// and leave the others untouched. If a resource is passed in to
+// describe the updated values, the API ignores the values of all
+// fields not covered by the mask.
+//
+// If a repeated field is specified for an update operation, new values will
+// be appended to the existing repeated field in the target resource. Note that
+// a repeated field is only allowed in the last position of a `paths` string.
+//
+// If a sub-message is specified in the last position of the field mask for an
+// update operation, then new value will be merged into the existing sub-message
+// in the target resource.
+//
+// For example, given the target message:
+//
+//     f {
+//       b {
+//         d: 1
+//         x: 2
+//       }
+//       c: [1]
+//     }
+//
+// And an update message:
+//
+//     f {
+//       b {
+//         d: 10
+//       }
+//       c: [2]
+//     }
+//
+// then if the field mask is:
+//
+//  paths: ["f.b", "f.c"]
+//
+// then the result will be:
+//
+//     f {
+//       b {
+//         d: 10
+//         x: 2
+//       }
+//       c: [1, 2]
+//     }
+//
+// An implementation may provide options to override this default behavior for
+// repeated and message fields.
+//
+// In order to reset a field's value to the default, the field must
+// be in the mask and set to the default value in the provided resource.
+// Hence, in order to reset all fields of a resource, provide a default
+// instance of the resource and set all fields in the mask, or do
+// not provide a mask as described below.
+//
+// If a field mask is not present on update, the operation applies to
+// all fields (as if a field mask of all fields has been specified).
+// Note that in the presence of schema evolution, this may mean that
+// fields the client does not know and has therefore not filled into
+// the request will be reset to their default. If this is unwanted
+// behavior, a specific service may require a client to always specify
+// a field mask, producing an error if not.
+//
+// As with get operations, the location of the resource which
+// describes the updated values in the request message depends on the
+// operation kind. In any case, the effect of the field mask is
+// required to be honored by the API.
+//
+// ## Considerations for HTTP REST
+//
+// The HTTP kind of an update operation which uses a field mask must
+// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+// (PUT must only be used for full updates).
+//
+// # JSON Encoding of Field Masks
+//
+// In JSON, a field mask is encoded as a single string where paths are
+// separated by a comma. Fields name in each path are converted
+// to/from lower-camel naming conventions.
+//
+// As an example, consider the following message declarations:
+//
+//     message Profile {
+//       User user = 1;
+//       Photo photo = 2;
+//     }
+//     message User {
+//       string display_name = 1;
+//       string address = 2;
+//     }
+//
+// In proto a field mask for `Profile` may look as such:
+//
+//     mask {
+//       paths: "user.display_name"
+//       paths: "photo"
+//     }
+//
+// In JSON, the same mask is represented as below:
+//
+//     {
+//       mask: "user.displayName,photo"
+//     }
+//
+// # Field Masks and Oneof Fields
+//
+// Field masks treat fields in oneofs just as regular fields. Consider the
+// following message:
+//
+//     message SampleMessage {
+//       oneof test_oneof {
+//         string name = 4;
+//         SubMessage sub_message = 9;
+//       }
+//     }
+//
+// The field mask can be:
+//
+//     mask {
+//       paths: "name"
+//     }
+//
+// Or:
+//
+//     mask {
+//       paths: "sub_message"
+//     }
+//
+// Note that oneof type names ("test_oneof" in this case) cannot be used in
+// paths.
+//
+// ## Field Mask Verification
+//
+// The implementation of any API method which has a FieldMask type field in the
+// request should verify the included field paths, and return an
+// `INVALID_ARGUMENT` error if any path is unmappable.
+message FieldMask {
+  // The set of field mask paths.
+  repeated string paths = 1;
+}
diff --git a/include/google/protobuf/source_context.proto b/include/google/protobuf/source_context.proto
new file mode 100644
index 0000000..06bfc43
--- /dev/null
+++ b/include/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 objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb";
+
+// `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_context.proto"`.
+  string file_name = 1;
+}
diff --git a/include/google/protobuf/struct.proto b/include/google/protobuf/struct.proto
new file mode 100644
index 0000000..0ac843c
--- /dev/null
+++ b/include/google/protobuf/struct.proto
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/structpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "StructProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// `Struct` represents a structured data value, consisting of fields
+// which map to dynamically typed values. In some languages, `Struct`
+// might be supported by a native representation. For example, in
+// scripting languages like JS a struct is represented as an
+// object. The details of that representation are described together
+// with the proto support for the language.
+//
+// The JSON representation for `Struct` is JSON object.
+message Struct {
+  // Unordered map of dynamically typed values.
+  map<string, Value> fields = 1;
+}
+
+// `Value` represents a dynamically typed value which can be either
+// null, a number, a string, a boolean, a recursive struct value, or a
+// list of values. A producer of value is expected to set one of these
+// variants. Absence of any variant indicates an error.
+//
+// The JSON representation for `Value` is JSON value.
+message Value {
+  // The kind of value.
+  oneof kind {
+    // Represents a null value.
+    NullValue null_value = 1;
+    // Represents a double value.
+    double number_value = 2;
+    // Represents a string value.
+    string string_value = 3;
+    // Represents a boolean value.
+    bool bool_value = 4;
+    // Represents a structured value.
+    Struct struct_value = 5;
+    // Represents a repeated `Value`.
+    ListValue list_value = 6;
+  }
+}
+
+// `NullValue` is a singleton enumeration to represent the null value for the
+// `Value` type union.
+//
+//  The JSON representation for `NullValue` is JSON `null`.
+enum NullValue {
+  // Null value.
+  NULL_VALUE = 0;
+}
+
+// `ListValue` is a wrapper around a repeated field of values.
+//
+// The JSON representation for `ListValue` is JSON array.
+message ListValue {
+  // Repeated field of dynamically typed values.
+  repeated Value values = 1;
+}
diff --git a/include/google/protobuf/timestamp.proto b/include/google/protobuf/timestamp.proto
new file mode 100644
index 0000000..3b2df6d
--- /dev/null
+++ b/include/google/protobuf/timestamp.proto
@@ -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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/timestamppb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// A Timestamp represents a point in time independent of any time zone or local
+// calendar, encoded as a count of seconds and fractions of seconds at
+// nanosecond resolution. The count is relative to an epoch at UTC midnight on
+// January 1, 1970, in the proleptic Gregorian calendar which extends the
+// Gregorian calendar backwards to year one.
+//
+// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
+// second table is needed for interpretation, using a [24-hour linear
+// smear](https://developers.google.com/time/smear).
+//
+// The 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](https://www.ietf.org/rfc/rfc3339.txt) date strings.
+//
+// # Examples
+//
+// 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 Java `Instant.now()`.
+//
+//     Instant now = Instant.now();
+//
+//     Timestamp timestamp =
+//         Timestamp.newBuilder().setSeconds(now.getEpochSecond())
+//             .setNanos(now.getNano()).build();
+//
+//
+// Example 6: Compute Timestamp from current time in Python.
+//
+//     timestamp = Timestamp()
+//     timestamp.GetCurrentTime()
+//
+// # JSON Mapping
+//
+// In JSON format, the Timestamp type is encoded as a string in the
+// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+// where {year} is always expressed using four digits while {month}, {day},
+// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+// is required. A proto3 JSON serializer should always use UTC (as indicated by
+// "Z") when printing the Timestamp type and a proto3 JSON parser should be
+// able to accept both UTC and other timezones (as indicated by an offset).
+//
+// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+// 01:30 UTC on January 15, 2017.
+//
+// In JavaScript, one can convert a Date object to this format using the
+// standard
+// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+// method. In Python, a standard `datetime.datetime` object can be converted
+// to this format using
+// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+// the Joda Time's [`ISODateTimeFormat.dateTime()`](
+// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
+// ) to obtain a formatter capable of generating timestamps in this format.
+//
+//
+message Timestamp {
+  // Represents seconds of UTC time since Unix epoch
+  // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+  // 9999-12-31T23:59:59Z inclusive.
+  int64 seconds = 1;
+
+  // Non-negative fractions of a second at nanosecond resolution. Negative
+  // second values with fractions must still have non-negative nanos values
+  // that count forward in time. Must be from 0 to 999,999,999
+  // inclusive.
+  int32 nanos = 2;
+}
diff --git a/include/google/protobuf/type.proto b/include/google/protobuf/type.proto
new file mode 100644
index 0000000..d3f6a68
--- /dev/null
+++ b/include/google/protobuf/type.proto
@@ -0,0 +1,187 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/source_context.proto";
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TypeProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/typepb";
+
+// 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 protobuf built-in options (options defined in
+  // descriptor.proto), this is the short name. For example, `"map_entry"`.
+  // For custom options, it should be the fully-qualified name. For example,
+  // `"google.api.http"`.
+  string name = 1;
+  // The option's value packed in an Any message. If the value is a primitive,
+  // the corresponding wrapper type defined in google/protobuf/wrappers.proto
+  // should be used. If the value is an enum, it should be stored as an int32
+  // value using the google.protobuf.Int32Value type.
+  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/include/google/protobuf/wrappers.proto b/include/google/protobuf/wrappers.proto
new file mode 100644
index 0000000..d49dd53
--- /dev/null
+++ b/include/google/protobuf/wrappers.proto
@@ -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.
+
+// Wrappers for primitive (non-message) types. These types are useful
+// for embedding primitives in the `google.protobuf.Any` type and for places
+// where we need to distinguish between the absence of a primitive
+// typed field and its default value.
+//
+// These wrappers have no meaningful use within repeated fields as they lack
+// the ability to detect presence on individual elements.
+// These wrappers have no meaningful use within a map or a oneof since
+// individual entries of a map or fields of a oneof can already detect presence.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/wrapperspb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "WrappersProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// Wrapper message for `double`.
+//
+// The JSON representation for `DoubleValue` is JSON number.
+message DoubleValue {
+  // The double value.
+  double value = 1;
+}
+
+// Wrapper message for `float`.
+//
+// The JSON representation for `FloatValue` is JSON number.
+message FloatValue {
+  // The float value.
+  float value = 1;
+}
+
+// Wrapper message for `int64`.
+//
+// The JSON representation for `Int64Value` is JSON string.
+message Int64Value {
+  // The int64 value.
+  int64 value = 1;
+}
+
+// Wrapper message for `uint64`.
+//
+// The JSON representation for `UInt64Value` is JSON string.
+message UInt64Value {
+  // The uint64 value.
+  uint64 value = 1;
+}
+
+// Wrapper message for `int32`.
+//
+// The JSON representation for `Int32Value` is JSON number.
+message Int32Value {
+  // The int32 value.
+  int32 value = 1;
+}
+
+// Wrapper message for `uint32`.
+//
+// The JSON representation for `UInt32Value` is JSON number.
+message UInt32Value {
+  // The uint32 value.
+  uint32 value = 1;
+}
+
+// Wrapper message for `bool`.
+//
+// The JSON representation for `BoolValue` is JSON `true` and `false`.
+message BoolValue {
+  // The bool value.
+  bool value = 1;
+}
+
+// Wrapper message for `string`.
+//
+// The JSON representation for `StringValue` is JSON string.
+message StringValue {
+  // The string value.
+  string value = 1;
+}
+
+// Wrapper message for `bytes`.
+//
+// The JSON representation for `BytesValue` is JSON string.
+message BytesValue {
+  // The bytes value.
+  bytes value = 1;
+}
diff --git a/python/MANIFEST.in b/python/MANIFEST.in
new file mode 100644
index 0000000..a81760f
--- /dev/null
+++ b/python/MANIFEST.in
@@ -0,0 +1,19 @@
+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-include google *.cc
+recursive-include google *.h
+
+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
+
+include LICENSE
diff --git a/python/README.md b/python/README.md
new file mode 100644
index 0000000..27f22c8
--- /dev/null
+++ b/python/README.md
@@ -0,0 +1,130 @@
+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 pure python performance is slow. For better performance please
+use python c++ implementation.
+
+Installation
+============
+
+1) Make sure you have Python 3.7 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 be fixed.  We also do not know
+   how likely it is that this bug will affect users in practice.
+
+5) Install:
+
+       $ python setup.py install
+
+   or:
+
+       $ (cd .. && make install)
+       $ python setup.py install --cpp_implementation
+
+   This step may require superuser privileges.
+   NOTE: To use C++ implementation, you need to export an environment
+   variable before running your program.  See the "C++ Implementation"
+   section below for more details.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+  https://developers.google.com/protocol-buffers/
+
+C++ Implementation
+==================
+
+The C++ implementation for Python messages is built as a Python extension to
+improve the overall protobuf Python performance.
+
+To use the C++ implementation, you need to install the C++ protobuf runtime
+library, please see instructions in the parent directory.
diff --git a/python/google/__init__.py b/python/google/__init__.py
new file mode 100644
index 0000000..5585614
--- /dev/null
+++ b/python/google/__init__.py
@@ -0,0 +1,4 @@
+try:
+  __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+  __path__ = __import__('pkgutil').extend_path(__path__, __name__)
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
new file mode 100644
index 0000000..e7b197e
--- /dev/null
+++ b/python/google/protobuf/__init__.py
@@ -0,0 +1,33 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Copyright 2007 Google Inc. All Rights Reserved.
+
+__version__ = '4.21.9'
diff --git a/python/google/protobuf/any_pb2.py b/python/google/protobuf/any_pb2.py
new file mode 100644
index 0000000..e3b6ad8
--- /dev/null
+++ b/python/google/protobuf/any_pb2.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/any.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/any.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\010AnyProtoP\001Z,google.golang.org/protobuf/types/known/anypb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x19google/protobuf/any.proto\x12\x0fgoogle.protobuf\"&\n\x03\x41ny\x12\x10\n\x08type_url\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\x42v\n\x13\x63om.google.protobufB\x08\x41nyProtoP\x01Z,google.golang.org/protobuf/types/known/anypb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_ANY = _descriptor.Descriptor(
+  name='Any',
+  full_name='google.protobuf.Any',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='type_url', full_name='google.protobuf.Any.type_url', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.Any.value', index=1,
+      number=2, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=46,
+  serialized_end=84,
+)
+
+DESCRIPTOR.message_types_by_name['Any'] = _ANY
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Any = _reflection.GeneratedProtocolMessageType('Any', (_message.Message,), {
+  'DESCRIPTOR' : _ANY,
+  '__module__' : 'google.protobuf.any_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Any)
+  })
+_sym_db.RegisterMessage(Any)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/any_test_pb2.py b/python/google/protobuf/any_test_pb2.py
new file mode 100644
index 0000000..18e5383
--- /dev/null
+++ b/python/google/protobuf/any_test_pb2.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/any_test.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/any_test.proto',
+  package='protobuf_unittest',
+  syntax='proto3',
+  serialized_options=b'B\014TestAnyProto',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1egoogle/protobuf/any_test.proto\x12\x11protobuf_unittest\x1a\x19google/protobuf/any.proto\"\x87\x01\n\x07TestAny\x12\x13\n\x0bint32_value\x18\x01 \x01(\x05\x12\'\n\tany_value\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any\x12\x30\n\x12repeated_any_value\x18\x03 \x03(\x0b\x32\x14.google.protobuf.Any\x12\x0c\n\x04text\x18\x04 \x01(\tB\x0e\x42\x0cTestAnyProtob\x06proto3'
+  ,
+  dependencies=[google_dot_protobuf_dot_any__pb2.DESCRIPTOR,])
+
+
+
+
+_TESTANY = _descriptor.Descriptor(
+  name='TestAny',
+  full_name='protobuf_unittest.TestAny',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='int32_value', full_name='protobuf_unittest.TestAny.int32_value', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='any_value', full_name='protobuf_unittest.TestAny.any_value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='repeated_any_value', full_name='protobuf_unittest.TestAny.repeated_any_value', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='text', full_name='protobuf_unittest.TestAny.text', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=81,
+  serialized_end=216,
+)
+
+_TESTANY.fields_by_name['any_value'].message_type = google_dot_protobuf_dot_any__pb2._ANY
+_TESTANY.fields_by_name['repeated_any_value'].message_type = google_dot_protobuf_dot_any__pb2._ANY
+DESCRIPTOR.message_types_by_name['TestAny'] = _TESTANY
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TestAny = _reflection.GeneratedProtocolMessageType('TestAny', (_message.Message,), {
+  'DESCRIPTOR' : _TESTANY,
+  '__module__' : 'google.protobuf.any_test_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestAny)
+  })
+_sym_db.RegisterMessage(TestAny)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/api_pb2.py b/python/google/protobuf/api_pb2.py
new file mode 100644
index 0000000..5ecc064
--- /dev/null
+++ b/python/google/protobuf/api_pb2.py
@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/api.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import source_context_pb2 as google_dot_protobuf_dot_source__context__pb2
+from google.protobuf import type_pb2 as google_dot_protobuf_dot_type__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/api.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\010ApiProtoP\001Z,google.golang.org/protobuf/types/known/apipb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x19google/protobuf/api.proto\x12\x0fgoogle.protobuf\x1a$google/protobuf/source_context.proto\x1a\x1agoogle/protobuf/type.proto\"\x81\x02\n\x03\x41pi\x12\x0c\n\x04name\x18\x01 \x01(\t\x12(\n\x07methods\x18\x02 \x03(\x0b\x32\x17.google.protobuf.Method\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12&\n\x06mixins\x18\x06 \x03(\x0b\x32\x16.google.protobuf.Mixin\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\"\xd5\x01\n\x06Method\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10request_type_url\x18\x02 \x01(\t\x12\x19\n\x11request_streaming\x18\x03 \x01(\x08\x12\x19\n\x11response_type_url\x18\x04 \x01(\t\x12\x1a\n\x12response_streaming\x18\x05 \x01(\x08\x12(\n\x07options\x18\x06 \x03(\x0b\x32\x17.google.protobuf.Option\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\"#\n\x05Mixin\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\tBv\n\x13\x63om.google.protobufB\x08\x41piProtoP\x01Z,google.golang.org/protobuf/types/known/apipb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+  ,
+  dependencies=[google_dot_protobuf_dot_source__context__pb2.DESCRIPTOR,google_dot_protobuf_dot_type__pb2.DESCRIPTOR,])
+
+
+
+
+_API = _descriptor.Descriptor(
+  name='Api',
+  full_name='google.protobuf.Api',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Api.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='methods', full_name='google.protobuf.Api.methods', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.Api.options', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='version', full_name='google.protobuf.Api.version', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_context', full_name='google.protobuf.Api.source_context', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='mixins', full_name='google.protobuf.Api.mixins', index=5,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='syntax', full_name='google.protobuf.Api.syntax', index=6,
+      number=7, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=113,
+  serialized_end=370,
+)
+
+
+_METHOD = _descriptor.Descriptor(
+  name='Method',
+  full_name='google.protobuf.Method',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Method.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='request_type_url', full_name='google.protobuf.Method.request_type_url', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='request_streaming', full_name='google.protobuf.Method.request_streaming', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='response_type_url', full_name='google.protobuf.Method.response_type_url', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='response_streaming', full_name='google.protobuf.Method.response_streaming', index=4,
+      number=5, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.Method.options', index=5,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='syntax', full_name='google.protobuf.Method.syntax', index=6,
+      number=7, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=373,
+  serialized_end=586,
+)
+
+
+_MIXIN = _descriptor.Descriptor(
+  name='Mixin',
+  full_name='google.protobuf.Mixin',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Mixin.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='root', full_name='google.protobuf.Mixin.root', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=588,
+  serialized_end=623,
+)
+
+_API.fields_by_name['methods'].message_type = _METHOD
+_API.fields_by_name['options'].message_type = google_dot_protobuf_dot_type__pb2._OPTION
+_API.fields_by_name['source_context'].message_type = google_dot_protobuf_dot_source__context__pb2._SOURCECONTEXT
+_API.fields_by_name['mixins'].message_type = _MIXIN
+_API.fields_by_name['syntax'].enum_type = google_dot_protobuf_dot_type__pb2._SYNTAX
+_METHOD.fields_by_name['options'].message_type = google_dot_protobuf_dot_type__pb2._OPTION
+_METHOD.fields_by_name['syntax'].enum_type = google_dot_protobuf_dot_type__pb2._SYNTAX
+DESCRIPTOR.message_types_by_name['Api'] = _API
+DESCRIPTOR.message_types_by_name['Method'] = _METHOD
+DESCRIPTOR.message_types_by_name['Mixin'] = _MIXIN
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Api = _reflection.GeneratedProtocolMessageType('Api', (_message.Message,), {
+  'DESCRIPTOR' : _API,
+  '__module__' : 'google.protobuf.api_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Api)
+  })
+_sym_db.RegisterMessage(Api)
+
+Method = _reflection.GeneratedProtocolMessageType('Method', (_message.Message,), {
+  'DESCRIPTOR' : _METHOD,
+  '__module__' : 'google.protobuf.api_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Method)
+  })
+_sym_db.RegisterMessage(Method)
+
+Mixin = _reflection.GeneratedProtocolMessageType('Mixin', (_message.Message,), {
+  'DESCRIPTOR' : _MIXIN,
+  '__module__' : 'google.protobuf.api_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Mixin)
+  })
+_sym_db.RegisterMessage(Mixin)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/compiler/__init__.py b/python/google/protobuf/compiler/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/google/protobuf/compiler/__init__.py
diff --git a/python/google/protobuf/compiler/plugin_pb2.py b/python/google/protobuf/compiler/plugin_pb2.py
new file mode 100644
index 0000000..ff90d18
--- /dev/null
+++ b/python/google/protobuf/compiler/plugin_pb2.py
@@ -0,0 +1,301 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/compiler/plugin.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/compiler/plugin.proto',
+  package='google.protobuf.compiler',
+  syntax='proto2',
+  serialized_options=b'\n\034com.google.protobuf.compilerB\014PluginProtosZ)google.golang.org/protobuf/types/pluginpb',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n%google/protobuf/compiler/plugin.proto\x12\x18google.protobuf.compiler\x1a google/protobuf/descriptor.proto\"F\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x12\r\n\x05patch\x18\x03 \x01(\x05\x12\x0e\n\x06suffix\x18\x04 \x01(\t\"\xba\x01\n\x14\x43odeGeneratorRequest\x12\x18\n\x10\x66ile_to_generate\x18\x01 \x03(\t\x12\x11\n\tparameter\x18\x02 \x01(\t\x12\x38\n\nproto_file\x18\x0f \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\x12;\n\x10\x63ompiler_version\x18\x03 \x01(\x0b\x32!.google.protobuf.compiler.Version\"\xc1\x02\n\x15\x43odeGeneratorResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x12\x1a\n\x12supported_features\x18\x02 \x01(\x04\x12\x42\n\x04\x66ile\x18\x0f \x03(\x0b\x32\x34.google.protobuf.compiler.CodeGeneratorResponse.File\x1a\x7f\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\t\x12?\n\x13generated_code_info\x18\x10 \x01(\x0b\x32\".google.protobuf.GeneratedCodeInfo\"8\n\x07\x46\x65\x61ture\x12\x10\n\x0c\x46\x45\x41TURE_NONE\x10\x00\x12\x1b\n\x17\x46\x45\x41TURE_PROTO3_OPTIONAL\x10\x01\x42W\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtosZ)google.golang.org/protobuf/types/pluginpb'
+  ,
+  dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,])
+
+
+
+_CODEGENERATORRESPONSE_FEATURE = _descriptor.EnumDescriptor(
+  name='Feature',
+  full_name='google.protobuf.compiler.CodeGeneratorResponse.Feature',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='FEATURE_NONE', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='FEATURE_PROTO3_OPTIONAL', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=628,
+  serialized_end=684,
+)
+_sym_db.RegisterEnumDescriptor(_CODEGENERATORRESPONSE_FEATURE)
+
+
+_VERSION = _descriptor.Descriptor(
+  name='Version',
+  full_name='google.protobuf.compiler.Version',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='major', full_name='google.protobuf.compiler.Version.major', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='minor', full_name='google.protobuf.compiler.Version.minor', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='patch', full_name='google.protobuf.compiler.Version.patch', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='suffix', full_name='google.protobuf.compiler.Version.suffix', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=101,
+  serialized_end=171,
+)
+
+
+_CODEGENERATORREQUEST = _descriptor.Descriptor(
+  name='CodeGeneratorRequest',
+  full_name='google.protobuf.compiler.CodeGeneratorRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='file_to_generate', full_name='google.protobuf.compiler.CodeGeneratorRequest.file_to_generate', index=0,
+      number=1, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='parameter', full_name='google.protobuf.compiler.CodeGeneratorRequest.parameter', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='proto_file', full_name='google.protobuf.compiler.CodeGeneratorRequest.proto_file', index=2,
+      number=15, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='compiler_version', full_name='google.protobuf.compiler.CodeGeneratorRequest.compiler_version', index=3,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=174,
+  serialized_end=360,
+)
+
+
+_CODEGENERATORRESPONSE_FILE = _descriptor.Descriptor(
+  name='File',
+  full_name='google.protobuf.compiler.CodeGeneratorResponse.File',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='insertion_point', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='content', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.content', index=2,
+      number=15, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='generated_code_info', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info', index=3,
+      number=16, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=499,
+  serialized_end=626,
+)
+
+_CODEGENERATORRESPONSE = _descriptor.Descriptor(
+  name='CodeGeneratorResponse',
+  full_name='google.protobuf.compiler.CodeGeneratorResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='error', full_name='google.protobuf.compiler.CodeGeneratorResponse.error', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='supported_features', full_name='google.protobuf.compiler.CodeGeneratorResponse.supported_features', index=1,
+      number=2, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='file', full_name='google.protobuf.compiler.CodeGeneratorResponse.file', index=2,
+      number=15, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_CODEGENERATORRESPONSE_FILE, ],
+  enum_types=[
+    _CODEGENERATORRESPONSE_FEATURE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=363,
+  serialized_end=684,
+)
+
+_CODEGENERATORREQUEST.fields_by_name['proto_file'].message_type = google_dot_protobuf_dot_descriptor__pb2._FILEDESCRIPTORPROTO
+_CODEGENERATORREQUEST.fields_by_name['compiler_version'].message_type = _VERSION
+_CODEGENERATORRESPONSE_FILE.fields_by_name['generated_code_info'].message_type = google_dot_protobuf_dot_descriptor__pb2._GENERATEDCODEINFO
+_CODEGENERATORRESPONSE_FILE.containing_type = _CODEGENERATORRESPONSE
+_CODEGENERATORRESPONSE.fields_by_name['file'].message_type = _CODEGENERATORRESPONSE_FILE
+_CODEGENERATORRESPONSE_FEATURE.containing_type = _CODEGENERATORRESPONSE
+DESCRIPTOR.message_types_by_name['Version'] = _VERSION
+DESCRIPTOR.message_types_by_name['CodeGeneratorRequest'] = _CODEGENERATORREQUEST
+DESCRIPTOR.message_types_by_name['CodeGeneratorResponse'] = _CODEGENERATORRESPONSE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Version = _reflection.GeneratedProtocolMessageType('Version', (_message.Message,), {
+  'DESCRIPTOR' : _VERSION,
+  '__module__' : 'google.protobuf.compiler.plugin_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.compiler.Version)
+  })
+_sym_db.RegisterMessage(Version)
+
+CodeGeneratorRequest = _reflection.GeneratedProtocolMessageType('CodeGeneratorRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CODEGENERATORREQUEST,
+  '__module__' : 'google.protobuf.compiler.plugin_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
+  })
+_sym_db.RegisterMessage(CodeGeneratorRequest)
+
+CodeGeneratorResponse = _reflection.GeneratedProtocolMessageType('CodeGeneratorResponse', (_message.Message,), {
+
+  'File' : _reflection.GeneratedProtocolMessageType('File', (_message.Message,), {
+    'DESCRIPTOR' : _CODEGENERATORRESPONSE_FILE,
+    '__module__' : 'google.protobuf.compiler.plugin_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
+    })
+  ,
+  'DESCRIPTOR' : _CODEGENERATORRESPONSE,
+  '__module__' : 'google.protobuf.compiler.plugin_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
+  })
+_sym_db.RegisterMessage(CodeGeneratorResponse)
+_sym_db.RegisterMessage(CodeGeneratorResponse.File)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
new file mode 100644
index 0000000..f5a0caa
--- /dev/null
+++ b/python/google/protobuf/descriptor.py
@@ -0,0 +1,1228 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Descriptors essentially contain exactly the information found in a .proto
+file, in types that make this information accessible in Python.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import threading
+import warnings
+
+from google.protobuf.internal import api_implementation
+
+_USE_C_DESCRIPTORS = False
+if api_implementation.Type() != 'python':
+  # Used by MakeDescriptor in cpp mode
+  import binascii
+  import os
+  # pylint: disable=protected-access
+  _message = api_implementation._c_module
+  # TODO(jieluo): Remove this import after fix api_implementation
+  if _message is None:
+    from google.protobuf.pyext import _message
+  _USE_C_DESCRIPTORS = True
+
+
+class Error(Exception):
+  """Base error for this module."""
+
+
+class TypeTransformationError(Error):
+  """Error transforming between python proto type and corresponding C++ type."""
+
+
+if _USE_C_DESCRIPTORS:
+  # This metaclass allows to override the behavior of code like
+  #     isinstance(my_descriptor, FieldDescriptor)
+  # and make it return True when the descriptor is an instance of the extension
+  # type written in C++.
+  class DescriptorMetaclass(type):
+    def __instancecheck__(cls, obj):
+      if super(DescriptorMetaclass, cls).__instancecheck__(obj):
+        return True
+      if isinstance(obj, cls._C_DESCRIPTOR_CLASS):
+        return True
+      return False
+else:
+  # The standard metaclass; nothing changes.
+  DescriptorMetaclass = type
+
+
+class _Lock(object):
+  """Wrapper class of threading.Lock(), which is allowed by 'with'."""
+
+  def __new__(cls):
+    self = object.__new__(cls)
+    self._lock = threading.Lock()  # pylint: disable=protected-access
+    return self
+
+  def __enter__(self):
+    self._lock.acquire()
+
+  def __exit__(self, exc_type, exc_value, exc_tb):
+    self._lock.release()
+
+
+_lock = threading.Lock()
+
+
+def _Deprecated(name):
+  if _Deprecated.count > 0:
+    _Deprecated.count -= 1
+    warnings.warn(
+        'Call to deprecated create function %s(). Note: Create unlinked '
+        'descriptors is going to go away. Please use get/find descriptors from '
+        'generated code or query the descriptor_pool.'
+        % name,
+        category=DeprecationWarning, stacklevel=3)
+
+
+# Deprecated warnings will print 100 times at most which should be enough for
+# users to notice and do not cause timeout.
+_Deprecated.count = 100
+
+
+_internal_create_key = object()
+
+
+class DescriptorBase(metaclass=DescriptorMetaclass):
+
+  """Descriptors base class.
+
+  This class is the base of all descriptor classes. It provides common options
+  related functionality.
+
+  Attributes:
+    has_options:  True if the descriptor has non-default options.  Usually it
+        is not necessary to read this -- just call GetOptions() which will
+        happily return the default instance.  However, it's sometimes useful
+        for efficiency, and also useful inside the protobuf implementation to
+        avoid some bootstrapping issues.
+  """
+
+  if _USE_C_DESCRIPTORS:
+    # The class, or tuple of classes, that are considered as "virtual
+    # subclasses" of this descriptor class.
+    _C_DESCRIPTOR_CLASS = ()
+
+  def __init__(self, options, serialized_options, options_class_name):
+    """Initialize the descriptor given its options message and the name of the
+    class of the options message. The name of the class is required in case
+    the options message is None and has to be created.
+    """
+    self._options = options
+    self._options_class_name = options_class_name
+    self._serialized_options = serialized_options
+
+    # Does this descriptor have non-default options?
+    self.has_options = (options is not None) or (serialized_options is not None)
+
+  def _SetOptions(self, options, options_class_name):
+    """Sets the descriptor's options
+
+    This function is used in generated proto2 files to update descriptor
+    options. It must not be used outside proto2.
+    """
+    self._options = options
+    self._options_class_name = options_class_name
+
+    # Does this descriptor have non-default options?
+    self.has_options = options is not None
+
+  def GetOptions(self):
+    """Retrieves descriptor options.
+
+    This method returns the options set or creates the default options for the
+    descriptor.
+    """
+    if self._options:
+      return self._options
+
+    from google.protobuf import descriptor_pb2
+    try:
+      options_class = getattr(descriptor_pb2,
+                              self._options_class_name)
+    except AttributeError:
+      raise RuntimeError('Unknown options class name %s!' %
+                         (self._options_class_name))
+
+    with _lock:
+      if self._serialized_options is None:
+        self._options = options_class()
+      else:
+        self._options = _ParseOptions(options_class(),
+                                      self._serialized_options)
+
+      return self._options
+
+
+class _NestedDescriptorBase(DescriptorBase):
+  """Common class for descriptors that can be nested."""
+
+  def __init__(self, options, options_class_name, name, full_name,
+               file, containing_type, serialized_start=None,
+               serialized_end=None, serialized_options=None):
+    """Constructor.
+
+    Args:
+      options: Protocol message options or None
+        to use default message options.
+      options_class_name (str): The class name of the above options.
+      name (str): Name of this protocol message type.
+      full_name (str): Fully-qualified name of this protocol message type,
+        which will include protocol "package" name and the name of any
+        enclosing types.
+      file (FileDescriptor): Reference to file info.
+      containing_type: if provided, this is a nested descriptor, with this
+        descriptor as parent, otherwise None.
+      serialized_start: The start index (inclusive) in block in the
+        file.serialized_pb that describes this descriptor.
+      serialized_end: The end index (exclusive) in block in the
+        file.serialized_pb that describes this descriptor.
+      serialized_options: Protocol message serialized options or None.
+    """
+    super(_NestedDescriptorBase, self).__init__(
+        options, serialized_options, options_class_name)
+
+    self.name = name
+    # TODO(falk): Add function to calculate full_name instead of having it in
+    #             memory?
+    self.full_name = full_name
+    self.file = file
+    self.containing_type = containing_type
+
+    self._serialized_start = serialized_start
+    self._serialized_end = serialized_end
+
+  def CopyToProto(self, proto):
+    """Copies this to the matching proto in descriptor_pb2.
+
+    Args:
+      proto: An empty proto instance from descriptor_pb2.
+
+    Raises:
+      Error: If self couldn't be serialized, due to to few constructor
+        arguments.
+    """
+    if (self.file is not None and
+        self._serialized_start is not None and
+        self._serialized_end is not None):
+      proto.ParseFromString(self.file.serialized_pb[
+          self._serialized_start:self._serialized_end])
+    else:
+      raise Error('Descriptor does not contain serialization.')
+
+
+class Descriptor(_NestedDescriptorBase):
+
+  """Descriptor for a protocol message type.
+
+  Attributes:
+      name (str): Name of this protocol message type.
+      full_name (str): Fully-qualified name of this protocol message type,
+          which will include protocol "package" name and the name of any
+          enclosing types.
+      containing_type (Descriptor): Reference to the descriptor of the type
+          containing us, or None if this is top-level.
+      fields (list[FieldDescriptor]): Field descriptors for all fields in
+          this type.
+      fields_by_number (dict(int, FieldDescriptor)): Same
+          :class:`FieldDescriptor` objects as in :attr:`fields`, but indexed
+          by "number" attribute in each FieldDescriptor.
+      fields_by_name (dict(str, FieldDescriptor)): Same
+          :class:`FieldDescriptor` objects as in :attr:`fields`, but indexed by
+          "name" attribute in each :class:`FieldDescriptor`.
+      nested_types (list[Descriptor]): Descriptor references
+          for all protocol message types nested within this one.
+      nested_types_by_name (dict(str, Descriptor)): Same Descriptor
+          objects as in :attr:`nested_types`, but indexed by "name" attribute
+          in each Descriptor.
+      enum_types (list[EnumDescriptor]): :class:`EnumDescriptor` references
+          for all enums contained within this type.
+      enum_types_by_name (dict(str, EnumDescriptor)): Same
+          :class:`EnumDescriptor` objects as in :attr:`enum_types`, but
+          indexed by "name" attribute in each EnumDescriptor.
+      enum_values_by_name (dict(str, EnumValueDescriptor)): Dict mapping
+          from enum value name to :class:`EnumValueDescriptor` for that value.
+      extensions (list[FieldDescriptor]): All extensions defined directly
+          within this message type (NOT within a nested type).
+      extensions_by_name (dict(str, FieldDescriptor)): Same FieldDescriptor
+          objects as :attr:`extensions`, but indexed by "name" attribute of each
+          FieldDescriptor.
+      is_extendable (bool):  Does this type define any extension ranges?
+      oneofs (list[OneofDescriptor]): The list of descriptors for oneof fields
+          in this message.
+      oneofs_by_name (dict(str, OneofDescriptor)): Same objects as in
+          :attr:`oneofs`, but indexed by "name" attribute.
+      file (FileDescriptor): Reference to file descriptor.
+
+  """
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.Descriptor
+
+    def __new__(
+        cls,
+        name=None,
+        full_name=None,
+        filename=None,
+        containing_type=None,
+        fields=None,
+        nested_types=None,
+        enum_types=None,
+        extensions=None,
+        options=None,
+        serialized_options=None,
+        is_extendable=True,
+        extension_ranges=None,
+        oneofs=None,
+        file=None,  # pylint: disable=redefined-builtin
+        serialized_start=None,
+        serialized_end=None,
+        syntax=None,
+        create_key=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      return _message.default_pool.FindMessageTypeByName(full_name)
+
+  # NOTE(tmarek): The file argument redefining a builtin is nothing we can
+  # fix right now since we don't know how many clients already rely on the
+  # name of the argument.
+  def __init__(self, name, full_name, filename, containing_type, fields,
+               nested_types, enum_types, extensions, options=None,
+               serialized_options=None,
+               is_extendable=True, extension_ranges=None, oneofs=None,
+               file=None, serialized_start=None, serialized_end=None,  # pylint: disable=redefined-builtin
+               syntax=None, create_key=None):
+    """Arguments to __init__() are as described in the description
+    of Descriptor fields above.
+
+    Note that filename is an obsolete argument, that is not used anymore.
+    Please use file.name to access this as an attribute.
+    """
+    if create_key is not _internal_create_key:
+      _Deprecated('Descriptor')
+
+    super(Descriptor, self).__init__(
+        options, 'MessageOptions', name, full_name, file,
+        containing_type, serialized_start=serialized_start,
+        serialized_end=serialized_end, serialized_options=serialized_options)
+
+    # We have fields in addition to fields_by_name and fields_by_number,
+    # so that:
+    #   1. Clients can index fields by "order in which they're listed."
+    #   2. Clients can easily iterate over all fields with the terse
+    #      syntax: for f in descriptor.fields: ...
+    self.fields = fields
+    for field in self.fields:
+      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:
+      nested_type.containing_type = self
+    self.nested_types_by_name = dict((t.name, t) for t in nested_types)
+
+    self.enum_types = enum_types
+    for enum_type in self.enum_types:
+      enum_type.containing_type = self
+    self.enum_types_by_name = dict((t.name, t) for t in enum_types)
+    self.enum_values_by_name = dict(
+        (v.name, v) for t in enum_types for v in t.values)
+
+    self.extensions = extensions
+    for extension in self.extensions:
+      extension.extension_scope = self
+    self.extensions_by_name = dict((f.name, f) for f in extensions)
+    self.is_extendable = is_extendable
+    self.extension_ranges = extension_ranges
+    self.oneofs = oneofs if oneofs is not None else []
+    self.oneofs_by_name = dict((o.name, o) for o in self.oneofs)
+    for oneof in self.oneofs:
+      oneof.containing_type = self
+    self.syntax = syntax or "proto2"
+
+  @property
+  def fields_by_camelcase_name(self):
+    """Same FieldDescriptor objects as in :attr:`fields`, but indexed by
+    :attr:`FieldDescriptor.camelcase_name`.
+    """
+    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.
+
+    This is just a small helper method to simplify a common operation.
+
+    Args:
+      enum: string name of the Enum.
+      value: int, value of the enum.
+
+    Returns:
+      string name of the enum value.
+
+    Raises:
+      KeyError if either the Enum doesn't exist or the value is not a valid
+        value for the enum.
+    """
+    return self.enum_types_by_name[enum].values_by_number[value].name
+
+  def CopyToProto(self, proto):
+    """Copies this to a descriptor_pb2.DescriptorProto.
+
+    Args:
+      proto: An empty descriptor_pb2.DescriptorProto.
+    """
+    # This function is overridden to give a better doc comment.
+    super(Descriptor, self).CopyToProto(proto)
+
+
+# TODO(robinson): We should have aggressive checking here,
+# for example:
+#   * If you specify a repeated field, you should not be allowed
+#     to specify a default value.
+#   * [Other examples here as needed].
+#
+# TODO(robinson): for this and other *Descriptor classes, we
+# might also want to lock things down aggressively (e.g.,
+# prevent clients from setting the attributes).  Having
+# stronger invariants here in general will reduce the number
+# of runtime checks we must do in reflection.py...
+class FieldDescriptor(DescriptorBase):
+
+  """Descriptor for a single field in a .proto file.
+
+  Attributes:
+    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.
+    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.
+
+    type (int): (One of the TYPE_* constants below) Declared type.
+    cpp_type (int): (One of the CPPTYPE_* constants below) C++ type used to
+      represent this field.
+
+    label (int): (One of the LABEL_* constants below) Tells whether this
+      field is optional, required, or repeated.
+    has_default_value (bool): True if this field has a default value defined,
+      otherwise false.
+    default_value (Varies): Default value of this field.  Only
+      meaningful for non-repeated scalar fields.  Repeated fields
+      should always set this to [], and non-repeated composite
+      fields should always set this to None.
+
+    containing_type (Descriptor): Descriptor of the protocol message
+      type that contains this field.  Set by the Descriptor constructor
+      if we're passed into one.
+      Somewhat confusingly, for extension fields, this is the
+      descriptor of the EXTENDED message, not the descriptor
+      of the message containing this field.  (See is_extension and
+      extension_scope below).
+    message_type (Descriptor): If a composite field, a descriptor
+      of the message type contained in this field.  Otherwise, this is None.
+    enum_type (EnumDescriptor): If this field contains an enum, a
+      descriptor of that enum.  Otherwise, this is None.
+
+    is_extension: True iff this describes an extension field.
+    extension_scope (Descriptor): Only meaningful if is_extension is True.
+      Gives the message that immediately contains this extension field.
+      Will be None iff we're a top-level (file-level) extension field.
+
+    options (descriptor_pb2.FieldOptions): Protocol message field options or
+      None to use default field options.
+
+    containing_oneof (OneofDescriptor): If the field is a member of a oneof
+      union, contains its descriptor. Otherwise, None.
+
+    file (FileDescriptor): Reference to file descriptor.
+  """
+
+  # Must be consistent with C++ FieldDescriptor::Type enum in
+  # descriptor.h.
+  #
+  # TODO(robinson): Find a way to eliminate this repetition.
+  TYPE_DOUBLE         = 1
+  TYPE_FLOAT          = 2
+  TYPE_INT64          = 3
+  TYPE_UINT64         = 4
+  TYPE_INT32          = 5
+  TYPE_FIXED64        = 6
+  TYPE_FIXED32        = 7
+  TYPE_BOOL           = 8
+  TYPE_STRING         = 9
+  TYPE_GROUP          = 10
+  TYPE_MESSAGE        = 11
+  TYPE_BYTES          = 12
+  TYPE_UINT32         = 13
+  TYPE_ENUM           = 14
+  TYPE_SFIXED32       = 15
+  TYPE_SFIXED64       = 16
+  TYPE_SINT32         = 17
+  TYPE_SINT64         = 18
+  MAX_TYPE            = 18
+
+  # Must be consistent with C++ FieldDescriptor::CppType enum in
+  # descriptor.h.
+  #
+  # TODO(robinson): Find a way to eliminate this repetition.
+  CPPTYPE_INT32       = 1
+  CPPTYPE_INT64       = 2
+  CPPTYPE_UINT32      = 3
+  CPPTYPE_UINT64      = 4
+  CPPTYPE_DOUBLE      = 5
+  CPPTYPE_FLOAT       = 6
+  CPPTYPE_BOOL        = 7
+  CPPTYPE_ENUM        = 8
+  CPPTYPE_STRING      = 9
+  CPPTYPE_MESSAGE     = 10
+  MAX_CPPTYPE         = 10
+
+  _PYTHON_TO_CPP_PROTO_TYPE_MAP = {
+      TYPE_DOUBLE: CPPTYPE_DOUBLE,
+      TYPE_FLOAT: CPPTYPE_FLOAT,
+      TYPE_ENUM: CPPTYPE_ENUM,
+      TYPE_INT64: CPPTYPE_INT64,
+      TYPE_SINT64: CPPTYPE_INT64,
+      TYPE_SFIXED64: CPPTYPE_INT64,
+      TYPE_UINT64: CPPTYPE_UINT64,
+      TYPE_FIXED64: CPPTYPE_UINT64,
+      TYPE_INT32: CPPTYPE_INT32,
+      TYPE_SFIXED32: CPPTYPE_INT32,
+      TYPE_SINT32: CPPTYPE_INT32,
+      TYPE_UINT32: CPPTYPE_UINT32,
+      TYPE_FIXED32: CPPTYPE_UINT32,
+      TYPE_BYTES: CPPTYPE_STRING,
+      TYPE_STRING: CPPTYPE_STRING,
+      TYPE_BOOL: CPPTYPE_BOOL,
+      TYPE_MESSAGE: CPPTYPE_MESSAGE,
+      TYPE_GROUP: CPPTYPE_MESSAGE
+      }
+
+  # Must be consistent with C++ FieldDescriptor::Label enum in
+  # descriptor.h.
+  #
+  # TODO(robinson): Find a way to eliminate this repetition.
+  LABEL_OPTIONAL      = 1
+  LABEL_REQUIRED      = 2
+  LABEL_REPEATED      = 3
+  MAX_LABEL           = 3
+
+  # Must be consistent with C++ constants kMaxNumber, kFirstReservedNumber,
+  # and kLastReservedNumber in descriptor.h
+  MAX_FIELD_NUMBER = (1 << 29) - 1
+  FIRST_RESERVED_FIELD_NUMBER = 19000
+  LAST_RESERVED_FIELD_NUMBER = 19999
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.FieldDescriptor
+
+    def __new__(cls, name, full_name, index, number, type, cpp_type, label,
+                default_value, message_type, enum_type, containing_type,
+                is_extension, extension_scope, options=None,
+                serialized_options=None,
+                has_default_value=True, containing_oneof=None, json_name=None,
+                file=None, create_key=None):  # pylint: disable=redefined-builtin
+      _message.Message._CheckCalledFromGeneratedFile()
+      if is_extension:
+        return _message.default_pool.FindExtensionByName(full_name)
+      else:
+        return _message.default_pool.FindFieldByName(full_name)
+
+  def __init__(self, name, full_name, index, number, type, cpp_type, label,
+               default_value, message_type, enum_type, containing_type,
+               is_extension, extension_scope, options=None,
+               serialized_options=None,
+               has_default_value=True, containing_oneof=None, json_name=None,
+               file=None, create_key=None):  # pylint: disable=redefined-builtin
+    """The arguments are as described in the description of FieldDescriptor
+    attributes above.
+
+    Note that containing_type may be None, and may be set later if necessary
+    (to deal with circular references between message types, for example).
+    Likewise for extension_scope.
+    """
+    if create_key is not _internal_create_key:
+      _Deprecated('FieldDescriptor')
+
+    super(FieldDescriptor, self).__init__(
+        options, serialized_options, 'FieldOptions')
+    self.name = name
+    self.full_name = full_name
+    self.file = file
+    self._camelcase_name = None
+    if json_name is None:
+      self.json_name = _ToJsonName(name)
+    else:
+      self.json_name = json_name
+    self.index = index
+    self.number = number
+    self.type = type
+    self.cpp_type = cpp_type
+    self.label = label
+    self.has_default_value = has_default_value
+    self.default_value = default_value
+    self.containing_type = containing_type
+    self.message_type = message_type
+    self.enum_type = enum_type
+    self.is_extension = is_extension
+    self.extension_scope = extension_scope
+    self.containing_oneof = containing_oneof
+    if api_implementation.Type() == 'python':
+      self._cdescriptor = None
+    else:
+      if is_extension:
+        self._cdescriptor = _message.default_pool.FindExtensionByName(full_name)
+      else:
+        self._cdescriptor = _message.default_pool.FindFieldByName(full_name)
+
+  @property
+  def camelcase_name(self):
+    """Camelcase name of this field.
+
+    Returns:
+      str: the name in CamelCase.
+    """
+    if self._camelcase_name is None:
+      self._camelcase_name = _ToCamelCase(self.name)
+    return self._camelcase_name
+
+  @property
+  def has_presence(self):
+    """Whether the field distinguishes between unpopulated and default values.
+
+    Raises:
+      RuntimeError: singular field that is not linked with message nor file.
+    """
+    if self.label == FieldDescriptor.LABEL_REPEATED:
+      return False
+    if (self.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE or
+        self.containing_oneof):
+      return True
+    if hasattr(self.file, 'syntax'):
+      return self.file.syntax == 'proto2'
+    if hasattr(self.message_type, 'syntax'):
+      return self.message_type.syntax == 'proto2'
+    raise RuntimeError(
+        'has_presence is not ready to use because field %s is not'
+        ' linked with message type nor file' % self.full_name)
+
+  @staticmethod
+  def ProtoTypeToCppProtoType(proto_type):
+    """Converts from a Python proto type to a C++ Proto Type.
+
+    The Python ProtocolBuffer classes specify both the 'Python' datatype and the
+    'C++' datatype - and they're not the same. This helper method should
+    translate from one to another.
+
+    Args:
+      proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*)
+    Returns:
+      int: descriptor.FieldDescriptor.CPPTYPE_*, the C++ type.
+    Raises:
+      TypeTransformationError: when the Python proto type isn't known.
+    """
+    try:
+      return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type]
+    except KeyError:
+      raise TypeTransformationError('Unknown proto_type: %s' % proto_type)
+
+
+class EnumDescriptor(_NestedDescriptorBase):
+
+  """Descriptor for an enum defined in a .proto file.
+
+  Attributes:
+    name (str): Name of the enum type.
+    full_name (str): Full name of the type, including package name
+      and any enclosing type(s).
+
+    values (list[EnumValueDescriptor]): List of the values
+      in this enum.
+    values_by_name (dict(str, EnumValueDescriptor)): Same as :attr:`values`,
+      but indexed by the "name" field of each EnumValueDescriptor.
+    values_by_number (dict(int, EnumValueDescriptor)): Same as :attr:`values`,
+      but indexed by the "number" field of each EnumValueDescriptor.
+    containing_type (Descriptor): Descriptor of the immediate containing
+      type of this enum, or None if this is an enum defined at the
+      top level in a .proto file.  Set by Descriptor's constructor
+      if we're passed into one.
+    file (FileDescriptor): Reference to file descriptor.
+    options (descriptor_pb2.EnumOptions): Enum options message or
+      None to use default enum options.
+  """
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.EnumDescriptor
+
+    def __new__(cls, name, full_name, filename, values,
+                containing_type=None, options=None,
+                serialized_options=None, file=None,  # pylint: disable=redefined-builtin
+                serialized_start=None, serialized_end=None, create_key=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      return _message.default_pool.FindEnumTypeByName(full_name)
+
+  def __init__(self, name, full_name, filename, values,
+               containing_type=None, options=None,
+               serialized_options=None, file=None,  # pylint: disable=redefined-builtin
+               serialized_start=None, serialized_end=None, create_key=None):
+    """Arguments are as described in the attribute description above.
+
+    Note that filename is an obsolete argument, that is not used anymore.
+    Please use file.name to access this as an attribute.
+    """
+    if create_key is not _internal_create_key:
+      _Deprecated('EnumDescriptor')
+
+    super(EnumDescriptor, self).__init__(
+        options, 'EnumOptions', name, full_name, file,
+        containing_type, serialized_start=serialized_start,
+        serialized_end=serialized_end, serialized_options=serialized_options)
+
+    self.values = values
+    for value in self.values:
+      value.type = self
+    self.values_by_name = dict((v.name, v) for v in values)
+    # Values are reversed to ensure that the first alias is retained.
+    self.values_by_number = dict((v.number, v) for v in reversed(values))
+
+  def CopyToProto(self, proto):
+    """Copies this to a descriptor_pb2.EnumDescriptorProto.
+
+    Args:
+      proto (descriptor_pb2.EnumDescriptorProto): An empty descriptor proto.
+    """
+    # This function is overridden to give a better doc comment.
+    super(EnumDescriptor, self).CopyToProto(proto)
+
+
+class EnumValueDescriptor(DescriptorBase):
+
+  """Descriptor for a single value within an enum.
+
+  Attributes:
+    name (str): Name of this value.
+    index (int): Dense, 0-indexed index giving the order that this
+      value appears textually within its enum in the .proto file.
+    number (int): Actual number assigned to this enum value.
+    type (EnumDescriptor): :class:`EnumDescriptor` to which this value
+      belongs.  Set by :class:`EnumDescriptor`'s constructor if we're
+      passed into one.
+    options (descriptor_pb2.EnumValueOptions): Enum value options message or
+      None to use default enum value options options.
+  """
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor
+
+    def __new__(cls, name, index, number,
+                type=None,  # pylint: disable=redefined-builtin
+                options=None, serialized_options=None, create_key=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      # There is no way we can build a complete EnumValueDescriptor with the
+      # given parameters (the name of the Enum is not known, for example).
+      # Fortunately generated files just pass it to the EnumDescriptor()
+      # constructor, which will ignore it, so returning None is good enough.
+      return None
+
+  def __init__(self, name, index, number,
+               type=None,  # pylint: disable=redefined-builtin
+               options=None, serialized_options=None, create_key=None):
+    """Arguments are as described in the attribute description above."""
+    if create_key is not _internal_create_key:
+      _Deprecated('EnumValueDescriptor')
+
+    super(EnumValueDescriptor, self).__init__(
+        options, serialized_options, 'EnumValueOptions')
+    self.name = name
+    self.index = index
+    self.number = number
+    self.type = type
+
+
+class OneofDescriptor(DescriptorBase):
+  """Descriptor for a oneof field.
+
+  Attributes:
+    name (str): Name of the oneof field.
+    full_name (str): Full name of the oneof field, including package name.
+    index (int): 0-based index giving the order of the oneof field inside
+      its containing type.
+    containing_type (Descriptor): :class:`Descriptor` of the protocol message
+      type that contains this field.  Set by the :class:`Descriptor` constructor
+      if we're passed into one.
+    fields (list[FieldDescriptor]): The list of field descriptors this
+      oneof can contain.
+  """
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.OneofDescriptor
+
+    def __new__(
+        cls, name, full_name, index, containing_type, fields, options=None,
+        serialized_options=None, create_key=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      return _message.default_pool.FindOneofByName(full_name)
+
+  def __init__(
+      self, name, full_name, index, containing_type, fields, options=None,
+      serialized_options=None, create_key=None):
+    """Arguments are as described in the attribute description above."""
+    if create_key is not _internal_create_key:
+      _Deprecated('OneofDescriptor')
+
+    super(OneofDescriptor, self).__init__(
+        options, serialized_options, 'OneofOptions')
+    self.name = name
+    self.full_name = full_name
+    self.index = index
+    self.containing_type = containing_type
+    self.fields = fields
+
+
+class ServiceDescriptor(_NestedDescriptorBase):
+
+  """Descriptor for a service.
+
+  Attributes:
+    name (str): Name of the service.
+    full_name (str): Full name of the service, including package name.
+    index (int): 0-indexed index giving the order that this services
+      definition appears within the .proto file.
+    methods (list[MethodDescriptor]): List of methods provided by this
+      service.
+    methods_by_name (dict(str, MethodDescriptor)): Same
+      :class:`MethodDescriptor` objects as in :attr:`methods_by_name`, but
+      indexed by "name" attribute in each :class:`MethodDescriptor`.
+    options (descriptor_pb2.ServiceOptions): Service options message or
+      None to use default service options.
+    file (FileDescriptor): Reference to file info.
+  """
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor
+
+    def __new__(
+        cls,
+        name=None,
+        full_name=None,
+        index=None,
+        methods=None,
+        options=None,
+        serialized_options=None,
+        file=None,  # pylint: disable=redefined-builtin
+        serialized_start=None,
+        serialized_end=None,
+        create_key=None):
+      _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
+      return _message.default_pool.FindServiceByName(full_name)
+
+  def __init__(self, name, full_name, index, methods, options=None,
+               serialized_options=None, file=None,  # pylint: disable=redefined-builtin
+               serialized_start=None, serialized_end=None, create_key=None):
+    if create_key is not _internal_create_key:
+      _Deprecated('ServiceDescriptor')
+
+    super(ServiceDescriptor, self).__init__(
+        options, 'ServiceOptions', name, full_name, file,
+        None, serialized_start=serialized_start,
+        serialized_end=serialized_end, serialized_options=serialized_options)
+    self.index = index
+    self.methods = methods
+    self.methods_by_name = dict((m.name, m) for m in methods)
+    # Set the containing service for each method in this service.
+    for method in self.methods:
+      method.containing_service = self
+
+  def FindMethodByName(self, name):
+    """Searches for the specified method, and returns its descriptor.
+
+    Args:
+      name (str): Name of the method.
+    Returns:
+      MethodDescriptor or None: the descriptor for the requested method, if
+      found.
+    """
+    return self.methods_by_name.get(name, None)
+
+  def CopyToProto(self, proto):
+    """Copies this to a descriptor_pb2.ServiceDescriptorProto.
+
+    Args:
+      proto (descriptor_pb2.ServiceDescriptorProto): An empty descriptor proto.
+    """
+    # This function is overridden to give a better doc comment.
+    super(ServiceDescriptor, self).CopyToProto(proto)
+
+
+class MethodDescriptor(DescriptorBase):
+
+  """Descriptor for a method in a service.
+
+  Attributes:
+    name (str): Name of the method within the service.
+    full_name (str): Full name of method.
+    index (int): 0-indexed index of the method inside the service.
+    containing_service (ServiceDescriptor): The service that contains this
+      method.
+    input_type (Descriptor): The descriptor of the message that this method
+      accepts.
+    output_type (Descriptor): The descriptor of the message that this method
+      returns.
+    client_streaming (bool): Whether this method uses client streaming.
+    server_streaming (bool): Whether this method uses server streaming.
+    options (descriptor_pb2.MethodOptions or None): Method options message, or
+      None to use default method options.
+  """
+
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.MethodDescriptor
+
+    def __new__(cls,
+                name,
+                full_name,
+                index,
+                containing_service,
+                input_type,
+                output_type,
+                client_streaming=False,
+                server_streaming=False,
+                options=None,
+                serialized_options=None,
+                create_key=None):
+      _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
+      return _message.default_pool.FindMethodByName(full_name)
+
+  def __init__(self,
+               name,
+               full_name,
+               index,
+               containing_service,
+               input_type,
+               output_type,
+               client_streaming=False,
+               server_streaming=False,
+               options=None,
+               serialized_options=None,
+               create_key=None):
+    """The arguments are as described in the description of MethodDescriptor
+    attributes above.
+
+    Note that containing_service may be None, and may be set later if necessary.
+    """
+    if create_key is not _internal_create_key:
+      _Deprecated('MethodDescriptor')
+
+    super(MethodDescriptor, self).__init__(
+        options, serialized_options, 'MethodOptions')
+    self.name = name
+    self.full_name = full_name
+    self.index = index
+    self.containing_service = containing_service
+    self.input_type = input_type
+    self.output_type = output_type
+    self.client_streaming = client_streaming
+    self.server_streaming = server_streaming
+
+  def CopyToProto(self, proto):
+    """Copies this to a descriptor_pb2.MethodDescriptorProto.
+
+    Args:
+      proto (descriptor_pb2.MethodDescriptorProto): An empty descriptor proto.
+
+    Raises:
+      Error: If self couldn't be serialized, due to too few constructor
+        arguments.
+    """
+    if self.containing_service is not None:
+      from google.protobuf import descriptor_pb2
+      service_proto = descriptor_pb2.ServiceDescriptorProto()
+      self.containing_service.CopyToProto(service_proto)
+      proto.CopyFrom(service_proto.method[self.index])
+    else:
+      raise Error('Descriptor does not contain a service.')
+
+
+class FileDescriptor(DescriptorBase):
+  """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
+
+  Note that :attr:`enum_types_by_name`, :attr:`extensions_by_name`, and
+  :attr:`dependencies` fields are only set by the
+  :py:mod:`google.protobuf.message_factory` module, and not by the generated
+  proto code.
+
+  Attributes:
+    name (str): Name of file, relative to root of source tree.
+    package (str): Name of the package
+    syntax (str): string indicating syntax of the file (can be "proto2" or
+      "proto3")
+    serialized_pb (bytes): Byte string of serialized
+      :class:`descriptor_pb2.FileDescriptorProto`.
+    dependencies (list[FileDescriptor]): List of other :class:`FileDescriptor`
+      objects this :class:`FileDescriptor` depends on.
+    public_dependencies (list[FileDescriptor]): A subset of
+      :attr:`dependencies`, which were declared as "public".
+    message_types_by_name (dict(str, Descriptor)): Mapping from message names
+      to their :class:`Descriptor`.
+    enum_types_by_name (dict(str, EnumDescriptor)): Mapping from enum names to
+      their :class:`EnumDescriptor`.
+    extensions_by_name (dict(str, FieldDescriptor)): Mapping from extension
+      names declared at file scope to their :class:`FieldDescriptor`.
+    services_by_name (dict(str, ServiceDescriptor)): Mapping from services'
+      names to their :class:`ServiceDescriptor`.
+    pool (DescriptorPool): The pool 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_options=None, serialized_pb=None,
+                dependencies=None, public_dependencies=None,
+                syntax=None, pool=None, create_key=None):
+      # FileDescriptor() is called from various places, not only from generated
+      # files, to register dynamic proto files and messages.
+      # pylint: disable=g-explicit-bool-comparison
+      if serialized_pb == b'':
+        # Cpp generated code must be linked in if serialized_pb is ''
+        try:
+          return _message.default_pool.FindFileByName(name)
+        except KeyError:
+          raise RuntimeError('Please link in cpp generated lib for %s' % (name))
+      elif serialized_pb:
+        return _message.default_pool.AddSerializedFile(serialized_pb)
+      else:
+        return super(FileDescriptor, cls).__new__(cls)
+
+  def __init__(self, name, package, options=None,
+               serialized_options=None, serialized_pb=None,
+               dependencies=None, public_dependencies=None,
+               syntax=None, pool=None, create_key=None):
+    """Constructor."""
+    if create_key is not _internal_create_key:
+      _Deprecated('FileDescriptor')
+
+    super(FileDescriptor, self).__init__(
+        options, serialized_options, 'FileOptions')
+
+    if pool is None:
+      from google.protobuf import descriptor_pool
+      pool = descriptor_pool.Default()
+    self.pool = pool
+    self.message_types_by_name = {}
+    self.name = name
+    self.package = package
+    self.syntax = syntax or "proto2"
+    self.serialized_pb = serialized_pb
+
+    self.enum_types_by_name = {}
+    self.extensions_by_name = {}
+    self.services_by_name = {}
+    self.dependencies = (dependencies or [])
+    self.public_dependencies = (public_dependencies or [])
+
+  def CopyToProto(self, proto):
+    """Copies this to a descriptor_pb2.FileDescriptorProto.
+
+    Args:
+      proto: An empty descriptor_pb2.FileDescriptorProto.
+    """
+    proto.ParseFromString(self.serialized_pb)
+
+
+def _ParseOptions(message, string):
+  """Parses serialized options.
+
+  This helper function is used to parse serialized options in generated
+  proto2 files. It must not be used outside proto2.
+  """
+  message.ParseFromString(string)
+  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 _OptionsOrNone(descriptor_proto):
+  """Returns the value of the field `options`, or None if it is not set."""
+  if descriptor_proto.HasField('options'):
+    return descriptor_proto.options
+  else:
+    return None
+
+
+def _ToJsonName(name):
+  """Converts name to Json name and returns it."""
+  capitalize_next = False
+  result = []
+
+  for c in name:
+    if c == '_':
+      capitalize_next = True
+    elif capitalize_next:
+      result.append(c.upper())
+      capitalize_next = False
+    else:
+      result += c
+
+  return ''.join(result)
+
+
+def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
+                   syntax=None):
+  """Make a protobuf Descriptor given a DescriptorProto protobuf.
+
+  Handles nested descriptors. Note that this is limited to the scope of defining
+  a message inside of another message. Composite fields can currently only be
+  resolved if the message is defined in the same scope as the field.
+
+  Args:
+    desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
+    package: Optional package name for the new message Descriptor (string).
+    build_file_if_cpp: Update the C++ descriptor pool if api matches.
+                       Set to False on recursion, so no duplicates are created.
+    syntax: The syntax/semantics that should be used.  Set to "proto3" to get
+            proto3 field presence semantics.
+  Returns:
+    A Descriptor for protobuf messages.
+  """
+  if api_implementation.Type() != 'python' and build_file_if_cpp:
+    # The C++ implementation requires all descriptors to be backed by the same
+    # definition in the C++ descriptor pool. To do this, we build a
+    # FileDescriptorProto with the same definition as this descriptor and build
+    # it into the pool.
+    from google.protobuf import descriptor_pb2
+    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 the descriptor pool
+    # accepts our FileDescriptorProto, but it is not important what that file
+    # name is actually set to.
+    proto_name = binascii.hexlify(os.urandom(16)).decode('ascii')
+
+    if package:
+      file_descriptor_proto.name = os.path.join(package.replace('.', '/'),
+                                                proto_name + '.proto')
+      file_descriptor_proto.package = package
+    else:
+      file_descriptor_proto.name = proto_name + '.proto'
+
+    _message.default_pool.Add(file_descriptor_proto)
+    result = _message.default_pool.FindFileByName(file_descriptor_proto.name)
+
+    if _USE_C_DESCRIPTORS:
+      return result.message_types_by_name[desc_proto.name]
+
+  full_message_name = [desc_proto.name]
+  if package: full_message_name.insert(0, package)
+
+  # Create Descriptors for enum types
+  enum_types = {}
+  for enum_proto in desc_proto.enum_type:
+    full_name = '.'.join(full_message_name + [enum_proto.name])
+    enum_desc = EnumDescriptor(
+        enum_proto.name, full_name, None, [
+            EnumValueDescriptor(enum_val.name, ii, enum_val.number,
+                                create_key=_internal_create_key)
+            for ii, enum_val in enumerate(enum_proto.value)],
+        create_key=_internal_create_key)
+    enum_types[full_name] = enum_desc
+
+  # Create Descriptors for nested types
+  nested_types = {}
+  for nested_proto in desc_proto.nested_type:
+    full_name = '.'.join(full_message_name + [nested_proto.name])
+    # Nested types are just those defined inside of the message, not all types
+    # used by fields in the message, so no loops are possible here.
+    nested_desc = MakeDescriptor(nested_proto,
+                                 package='.'.join(full_message_name),
+                                 build_file_if_cpp=False,
+                                 syntax=syntax)
+    nested_types[full_name] = nested_desc
+
+  fields = []
+  for field_proto in desc_proto.field:
+    full_name = '.'.join(full_message_name + [field_proto.name])
+    enum_desc = None
+    nested_desc = None
+    if field_proto.json_name:
+      json_name = field_proto.json_name
+    else:
+      json_name = None
+    if field_proto.HasField('type_name'):
+      type_name = field_proto.type_name
+      full_type_name = '.'.join(full_message_name +
+                                [type_name[type_name.rfind('.')+1:]])
+      if full_type_name in nested_types:
+        nested_desc = nested_types[full_type_name]
+      elif full_type_name in enum_types:
+        enum_desc = enum_types[full_type_name]
+      # Else type_name references a non-local type, which isn't implemented
+    field = FieldDescriptor(
+        field_proto.name, full_name, field_proto.number - 1,
+        field_proto.number, field_proto.type,
+        FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
+        field_proto.label, None, nested_desc, enum_desc, None, False, None,
+        options=_OptionsOrNone(field_proto), has_default_value=False,
+        json_name=json_name, create_key=_internal_create_key)
+    fields.append(field)
+
+  desc_name = '.'.join(full_message_name)
+  return Descriptor(desc_proto.name, desc_name, None, None, fields,
+                    list(nested_types.values()), list(enum_types.values()), [],
+                    options=_OptionsOrNone(desc_proto),
+                    create_key=_internal_create_key)
diff --git a/python/google/protobuf/descriptor_database.py b/python/google/protobuf/descriptor_database.py
new file mode 100644
index 0000000..073eddc
--- /dev/null
+++ b/python/google/protobuf/descriptor_database.py
@@ -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.
+
+"""Provides a container for DescriptorProtos."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import warnings
+
+
+class Error(Exception):
+  pass
+
+
+class DescriptorDatabaseConflictingDefinitionError(Error):
+  """Raised when a proto is added with the same name & different descriptor."""
+
+
+class DescriptorDatabase(object):
+  """A container accepting FileDescriptorProtos and maps DescriptorProtos."""
+
+  def __init__(self):
+    self._file_desc_protos_by_file = {}
+    self._file_desc_protos_by_symbol = {}
+
+  def Add(self, file_desc_proto):
+    """Adds the FileDescriptorProto and its types to this database.
+
+    Args:
+      file_desc_proto: The FileDescriptorProto to add.
+    Raises:
+      DescriptorDatabaseConflictingDefinitionError: if an attempt is made to
+        add a proto with the same name but different definition than an
+        existing proto in the database.
+    """
+    proto_name = file_desc_proto.name
+    if proto_name not in self._file_desc_protos_by_file:
+      self._file_desc_protos_by_file[proto_name] = file_desc_proto
+    elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:
+      raise DescriptorDatabaseConflictingDefinitionError(
+          '%s already added, but with different descriptor.' % proto_name)
+    else:
+      return
+
+    # Add all the top-level descriptors to the index.
+    package = file_desc_proto.package
+    for message in file_desc_proto.message_type:
+      for name in _ExtractSymbols(message, package):
+        self._AddSymbol(name, file_desc_proto)
+    for enum in file_desc_proto.enum_type:
+      self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto)
+      for enum_value in enum.value:
+        self._file_desc_protos_by_symbol[
+            '.'.join((package, enum_value.name))] = file_desc_proto
+    for extension in file_desc_proto.extension:
+      self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto)
+    for service in file_desc_proto.service:
+      self._AddSymbol(('.'.join((package, service.name))), file_desc_proto)
+
+  def FindFileByName(self, name):
+    """Finds the file descriptor proto by file name.
+
+    Typically the file name is a relative path ending to a .proto file. The
+    proto with the given name will have to have been added to this database
+    using the Add method or else an error will be raised.
+
+    Args:
+      name: The file name to find.
+
+    Returns:
+      The file descriptor proto matching the name.
+
+    Raises:
+      KeyError if no file by the given name was added.
+    """
+
+    return self._file_desc_protos_by_file[name]
+
+  def FindFileContainingSymbol(self, symbol):
+    """Finds the file descriptor proto containing the specified symbol.
+
+    The symbol should be a fully qualified name including the file descriptor's
+    package and any containing messages. Some examples:
+
+    'some.package.name.Message'
+    'some.package.name.Message.NestedEnum'
+    'some.package.name.Message.some_field'
+
+    The file descriptor proto containing the specified symbol must be added to
+    this database using the Add method or else an error will be raised.
+
+    Args:
+      symbol: The fully qualified symbol name.
+
+    Returns:
+      The file descriptor proto containing the symbol.
+
+    Raises:
+      KeyError if no file contains the specified symbol.
+    """
+    try:
+      return self._file_desc_protos_by_symbol[symbol]
+    except KeyError:
+      # Fields, enum values, and nested extensions are not in
+      # _file_desc_protos_by_symbol. Try to find the top level
+      # descriptor. Non-existent nested symbol under a valid top level
+      # descriptor can also be found. The behavior is the same with
+      # protobuf C++.
+      top_level, _, _ = symbol.rpartition('.')
+      try:
+        return self._file_desc_protos_by_symbol[top_level]
+      except KeyError:
+        # Raise the original symbol as a KeyError for better diagnostics.
+        raise KeyError(symbol)
+
+  def FindFileContainingExtension(self, extendee_name, extension_number):
+    # TODO(jieluo): implement this API.
+    return None
+
+  def FindAllExtensionNumbers(self, extendee_name):
+    # TODO(jieluo): implement this API.
+    return []
+
+  def _AddSymbol(self, name, file_desc_proto):
+    if name in self._file_desc_protos_by_symbol:
+      warn_msg = ('Conflict register for file "' + file_desc_proto.name +
+                  '": ' + name +
+                  ' is already defined in file "' +
+                  self._file_desc_protos_by_symbol[name].name + '"')
+      warnings.warn(warn_msg, RuntimeWarning)
+    self._file_desc_protos_by_symbol[name] = file_desc_proto
+
+
+def _ExtractSymbols(desc_proto, package):
+  """Pulls out all the symbols from a descriptor proto.
+
+  Args:
+    desc_proto: The proto to extract symbols from.
+    package: The package containing the descriptor type.
+
+  Yields:
+    The fully qualified name found in the descriptor.
+  """
+  message_name = package + '.' + desc_proto.name if package else desc_proto.name
+  yield message_name
+  for nested_type in desc_proto.nested_type:
+    for symbol in _ExtractSymbols(nested_type, message_name):
+      yield symbol
+  for enum_type in desc_proto.enum_type:
+    yield '.'.join((message_name, enum_type.name))
diff --git a/python/google/protobuf/descriptor_pb2.py b/python/google/protobuf/descriptor_pb2.py
new file mode 100644
index 0000000..dbd05e7
--- /dev/null
+++ b/python/google/protobuf/descriptor_pb2.py
@@ -0,0 +1,2113 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/descriptor.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/descriptor.proto',
+  package='google.protobuf',
+  syntax='proto2',
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"G\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xdb\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\"\xa9\x05\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x12\x46\n\x0ereserved_range\x18\t \x03(\x0b\x32..google.protobuf.DescriptorProto.ReservedRange\x12\x15\n\rreserved_name\x18\n \x03(\t\x1a\x65\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\x12\x37\n\x07options\x18\x03 \x01(\x0b\x32&.google.protobuf.ExtensionRangeOptions\x1a+\n\rReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"g\n\x15\x45xtensionRangeOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xd5\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12\x11\n\tjson_name\x18\n \x01(\t\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\x12\x17\n\x0fproto3_optional\x18\x11 \x01(\x08\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"T\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\x07options\x18\x02 \x01(\x0b\x32\x1d.google.protobuf.OneofOptions\"\xa4\x02\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\x12N\n\x0ereserved_range\x18\x04 \x03(\x0b\x32\x36.google.protobuf.EnumDescriptorProto.EnumReservedRange\x12\x15\n\rreserved_name\x18\x05 \x03(\t\x1a/\n\x11\x45numReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xa5\x06\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12)\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08\x42\x02\x18\x01\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12#\n\x14php_generic_services\x18* \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x04true\x12\x19\n\x11objc_class_prefix\x18$ \x01(\t\x12\x18\n\x10\x63sharp_namespace\x18% \x01(\t\x12\x14\n\x0cswift_prefix\x18\' \x01(\t\x12\x18\n\x10php_class_prefix\x18( \x01(\t\x12\x15\n\rphp_namespace\x18) \x01(\t\x12\x1e\n\x16php_metadata_namespace\x18, \x01(\t\x12\x14\n\x0cruby_package\x18- \x01(\t\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08&\x10\'\"\x84\x02\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07J\x04\x08\x08\x10\tJ\x04\x08\t\x10\n\"\xbe\x03\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12?\n\x06jstype\x18\x06 \x01(\x0e\x32$.google.protobuf.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0funverified_lazy\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05\"^\n\x0cOneofOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x93\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x05\x10\x06\"}\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"{\n\x0eServiceOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xad\x02\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12_\n\x11idempotency_level\x18\" \x01(\x0e\x32/.google.protobuf.MethodOptions.IdempotencyLevel:\x13IDEMPOTENCY_UNKNOWN\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"P\n\x10IdempotencyLevel\x12\x17\n\x13IDEMPOTENCY_UNKNOWN\x10\x00\x12\x13\n\x0fNO_SIDE_EFFECTS\x10\x01\x12\x0e\n\nIDEMPOTENT\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xd5\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x86\x01\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\t\x12!\n\x19leading_detached_comments\x18\x06 \x03(\t\"\xa7\x01\n\x11GeneratedCodeInfo\x12\x41\n\nannotation\x18\x01 \x03(\x0b\x32-.google.protobuf.GeneratedCodeInfo.Annotation\x1aO\n\nAnnotation\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x13\n\x0bsource_file\x18\x02 \x01(\t\x12\r\n\x05\x62\x65gin\x18\x03 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x04 \x01(\x05\x42~\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01Z-google.golang.org/protobuf/types/descriptorpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1aGoogle.Protobuf.Reflection'
+)
+
+
+
+_FIELDDESCRIPTORPROTO_TYPE = _descriptor.EnumDescriptor(
+  name='Type',
+  full_name='google.protobuf.FieldDescriptorProto.Type',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_DOUBLE', index=0, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_FLOAT', index=1, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_INT64', index=2, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_UINT64', index=3, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_INT32', index=4, number=5,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_FIXED64', index=5, number=6,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_FIXED32', index=6, number=7,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_BOOL', index=7, number=8,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_STRING', index=8, number=9,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_GROUP', index=9, number=10,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_MESSAGE', index=10, number=11,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_BYTES', index=11, number=12,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_UINT32', index=12, number=13,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_ENUM', index=13, number=14,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SFIXED32', index=14, number=15,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SFIXED64', index=15, number=16,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SINT32', index=16, number=17,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SINT64', index=17, number=18,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1740,
+  serialized_end=2050,
+)
+_sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_TYPE)
+
+_FIELDDESCRIPTORPROTO_LABEL = _descriptor.EnumDescriptor(
+  name='Label',
+  full_name='google.protobuf.FieldDescriptorProto.Label',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='LABEL_OPTIONAL', index=0, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='LABEL_REQUIRED', index=1, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='LABEL_REPEATED', index=2, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=2052,
+  serialized_end=2119,
+)
+_sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_LABEL)
+
+_FILEOPTIONS_OPTIMIZEMODE = _descriptor.EnumDescriptor(
+  name='OptimizeMode',
+  full_name='google.protobuf.FileOptions.OptimizeMode',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='SPEED', index=0, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CODE_SIZE', index=1, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='LITE_RUNTIME', index=2, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=3686,
+  serialized_end=3744,
+)
+_sym_db.RegisterEnumDescriptor(_FILEOPTIONS_OPTIMIZEMODE)
+
+_FIELDOPTIONS_CTYPE = _descriptor.EnumDescriptor(
+  name='CType',
+  full_name='google.protobuf.FieldOptions.CType',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='STRING', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CORD', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='STRING_PIECE', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4354,
+  serialized_end=4401,
+)
+_sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_CTYPE)
+
+_FIELDOPTIONS_JSTYPE = _descriptor.EnumDescriptor(
+  name='JSType',
+  full_name='google.protobuf.FieldOptions.JSType',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='JS_NORMAL', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='JS_STRING', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='JS_NUMBER', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=4403,
+  serialized_end=4456,
+)
+_sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_JSTYPE)
+
+_METHODOPTIONS_IDEMPOTENCYLEVEL = _descriptor.EnumDescriptor(
+  name='IdempotencyLevel',
+  full_name='google.protobuf.MethodOptions.IdempotencyLevel',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='IDEMPOTENCY_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='NO_SIDE_EFFECTS', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='IDEMPOTENT', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=5184,
+  serialized_end=5264,
+)
+_sym_db.RegisterEnumDescriptor(_METHODOPTIONS_IDEMPOTENCYLEVEL)
+
+
+_FILEDESCRIPTORSET = _descriptor.Descriptor(
+  name='FileDescriptorSet',
+  full_name='google.protobuf.FileDescriptorSet',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='file', full_name='google.protobuf.FileDescriptorSet.file', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=53,
+  serialized_end=124,
+)
+
+
+_FILEDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='FileDescriptorProto',
+  full_name='google.protobuf.FileDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.FileDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='package', full_name='google.protobuf.FileDescriptorProto.package', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dependency', full_name='google.protobuf.FileDescriptorProto.dependency', index=2,
+      number=3, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='public_dependency', full_name='google.protobuf.FileDescriptorProto.public_dependency', index=3,
+      number=10, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='weak_dependency', full_name='google.protobuf.FileDescriptorProto.weak_dependency', index=4,
+      number=11, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='message_type', full_name='google.protobuf.FileDescriptorProto.message_type', index=5,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='enum_type', full_name='google.protobuf.FileDescriptorProto.enum_type', index=6,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='service', full_name='google.protobuf.FileDescriptorProto.service', index=7,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='extension', full_name='google.protobuf.FileDescriptorProto.extension', index=8,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.FileDescriptorProto.options', index=9,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_code_info', full_name='google.protobuf.FileDescriptorProto.source_code_info', index=10,
+      number=9, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='syntax', full_name='google.protobuf.FileDescriptorProto.syntax', index=11,
+      number=12, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=127,
+  serialized_end=602,
+)
+
+
+_DESCRIPTORPROTO_EXTENSIONRANGE = _descriptor.Descriptor(
+  name='ExtensionRange',
+  full_name='google.protobuf.DescriptorProto.ExtensionRange',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='start', full_name='google.protobuf.DescriptorProto.ExtensionRange.start', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='end', full_name='google.protobuf.DescriptorProto.ExtensionRange.end', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.DescriptorProto.ExtensionRange.options', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1140,
+  serialized_end=1241,
+)
+
+_DESCRIPTORPROTO_RESERVEDRANGE = _descriptor.Descriptor(
+  name='ReservedRange',
+  full_name='google.protobuf.DescriptorProto.ReservedRange',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='start', full_name='google.protobuf.DescriptorProto.ReservedRange.start', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='end', full_name='google.protobuf.DescriptorProto.ReservedRange.end', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1243,
+  serialized_end=1286,
+)
+
+_DESCRIPTORPROTO = _descriptor.Descriptor(
+  name='DescriptorProto',
+  full_name='google.protobuf.DescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.DescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='field', full_name='google.protobuf.DescriptorProto.field', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='extension', full_name='google.protobuf.DescriptorProto.extension', index=2,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='nested_type', full_name='google.protobuf.DescriptorProto.nested_type', index=3,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='enum_type', full_name='google.protobuf.DescriptorProto.enum_type', index=4,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='extension_range', full_name='google.protobuf.DescriptorProto.extension_range', index=5,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='oneof_decl', full_name='google.protobuf.DescriptorProto.oneof_decl', index=6,
+      number=8, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.DescriptorProto.options', index=7,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='reserved_range', full_name='google.protobuf.DescriptorProto.reserved_range', index=8,
+      number=9, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='reserved_name', full_name='google.protobuf.DescriptorProto.reserved_name', index=9,
+      number=10, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_DESCRIPTORPROTO_EXTENSIONRANGE, _DESCRIPTORPROTO_RESERVEDRANGE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=605,
+  serialized_end=1286,
+)
+
+
+_EXTENSIONRANGEOPTIONS = _descriptor.Descriptor(
+  name='ExtensionRangeOptions',
+  full_name='google.protobuf.ExtensionRangeOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.ExtensionRangeOptions.uninterpreted_option', index=0,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=1288,
+  serialized_end=1391,
+)
+
+
+_FIELDDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='FieldDescriptorProto',
+  full_name='google.protobuf.FieldDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.FieldDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='number', full_name='google.protobuf.FieldDescriptorProto.number', index=1,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='label', full_name='google.protobuf.FieldDescriptorProto.label', index=2,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=1,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='google.protobuf.FieldDescriptorProto.type', index=3,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=1,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='type_name', full_name='google.protobuf.FieldDescriptorProto.type_name', index=4,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='extendee', full_name='google.protobuf.FieldDescriptorProto.extendee', index=5,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='default_value', full_name='google.protobuf.FieldDescriptorProto.default_value', index=6,
+      number=7, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='oneof_index', full_name='google.protobuf.FieldDescriptorProto.oneof_index', index=7,
+      number=9, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='json_name', full_name='google.protobuf.FieldDescriptorProto.json_name', index=8,
+      number=10, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.FieldDescriptorProto.options', index=9,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='proto3_optional', full_name='google.protobuf.FieldDescriptorProto.proto3_optional', index=10,
+      number=17, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _FIELDDESCRIPTORPROTO_TYPE,
+    _FIELDDESCRIPTORPROTO_LABEL,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1394,
+  serialized_end=2119,
+)
+
+
+_ONEOFDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='OneofDescriptorProto',
+  full_name='google.protobuf.OneofDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.OneofDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.OneofDescriptorProto.options', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2121,
+  serialized_end=2205,
+)
+
+
+_ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE = _descriptor.Descriptor(
+  name='EnumReservedRange',
+  full_name='google.protobuf.EnumDescriptorProto.EnumReservedRange',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='start', full_name='google.protobuf.EnumDescriptorProto.EnumReservedRange.start', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='end', full_name='google.protobuf.EnumDescriptorProto.EnumReservedRange.end', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2453,
+  serialized_end=2500,
+)
+
+_ENUMDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='EnumDescriptorProto',
+  full_name='google.protobuf.EnumDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.EnumDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.EnumDescriptorProto.value', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.EnumDescriptorProto.options', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='reserved_range', full_name='google.protobuf.EnumDescriptorProto.reserved_range', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='reserved_name', full_name='google.protobuf.EnumDescriptorProto.reserved_name', index=4,
+      number=5, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2208,
+  serialized_end=2500,
+)
+
+
+_ENUMVALUEDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='EnumValueDescriptorProto',
+  full_name='google.protobuf.EnumValueDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.EnumValueDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='number', full_name='google.protobuf.EnumValueDescriptorProto.number', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.EnumValueDescriptorProto.options', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2502,
+  serialized_end=2610,
+)
+
+
+_SERVICEDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='ServiceDescriptorProto',
+  full_name='google.protobuf.ServiceDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.ServiceDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='method', full_name='google.protobuf.ServiceDescriptorProto.method', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.ServiceDescriptorProto.options', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2613,
+  serialized_end=2757,
+)
+
+
+_METHODDESCRIPTORPROTO = _descriptor.Descriptor(
+  name='MethodDescriptorProto',
+  full_name='google.protobuf.MethodDescriptorProto',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.MethodDescriptorProto.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='input_type', full_name='google.protobuf.MethodDescriptorProto.input_type', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='output_type', full_name='google.protobuf.MethodDescriptorProto.output_type', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.MethodDescriptorProto.options', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='client_streaming', full_name='google.protobuf.MethodDescriptorProto.client_streaming', index=4,
+      number=5, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='server_streaming', full_name='google.protobuf.MethodDescriptorProto.server_streaming', index=5,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2760,
+  serialized_end=2953,
+)
+
+
+_FILEOPTIONS = _descriptor.Descriptor(
+  name='FileOptions',
+  full_name='google.protobuf.FileOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='java_package', full_name='google.protobuf.FileOptions.java_package', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='java_outer_classname', full_name='google.protobuf.FileOptions.java_outer_classname', index=1,
+      number=8, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='java_multiple_files', full_name='google.protobuf.FileOptions.java_multiple_files', index=2,
+      number=10, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='java_generate_equals_and_hash', full_name='google.protobuf.FileOptions.java_generate_equals_and_hash', index=3,
+      number=20, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='java_string_check_utf8', full_name='google.protobuf.FileOptions.java_string_check_utf8', index=4,
+      number=27, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='optimize_for', full_name='google.protobuf.FileOptions.optimize_for', index=5,
+      number=9, type=14, cpp_type=8, label=1,
+      has_default_value=True, default_value=1,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='go_package', full_name='google.protobuf.FileOptions.go_package', index=6,
+      number=11, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cc_generic_services', full_name='google.protobuf.FileOptions.cc_generic_services', index=7,
+      number=16, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='java_generic_services', full_name='google.protobuf.FileOptions.java_generic_services', index=8,
+      number=17, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='py_generic_services', full_name='google.protobuf.FileOptions.py_generic_services', index=9,
+      number=18, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='php_generic_services', full_name='google.protobuf.FileOptions.php_generic_services', index=10,
+      number=42, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.FileOptions.deprecated', index=11,
+      number=23, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cc_enable_arenas', full_name='google.protobuf.FileOptions.cc_enable_arenas', index=12,
+      number=31, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=True,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='objc_class_prefix', full_name='google.protobuf.FileOptions.objc_class_prefix', index=13,
+      number=36, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='csharp_namespace', full_name='google.protobuf.FileOptions.csharp_namespace', index=14,
+      number=37, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='swift_prefix', full_name='google.protobuf.FileOptions.swift_prefix', index=15,
+      number=39, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='php_class_prefix', full_name='google.protobuf.FileOptions.php_class_prefix', index=16,
+      number=40, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='php_namespace', full_name='google.protobuf.FileOptions.php_namespace', index=17,
+      number=41, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='php_metadata_namespace', full_name='google.protobuf.FileOptions.php_metadata_namespace', index=18,
+      number=44, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='ruby_package', full_name='google.protobuf.FileOptions.ruby_package', index=19,
+      number=45, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.FileOptions.uninterpreted_option', index=20,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _FILEOPTIONS_OPTIMIZEMODE,
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=2956,
+  serialized_end=3761,
+)
+
+
+_MESSAGEOPTIONS = _descriptor.Descriptor(
+  name='MessageOptions',
+  full_name='google.protobuf.MessageOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='message_set_wire_format', full_name='google.protobuf.MessageOptions.message_set_wire_format', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='no_standard_descriptor_accessor', full_name='google.protobuf.MessageOptions.no_standard_descriptor_accessor', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.MessageOptions.deprecated', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='map_entry', full_name='google.protobuf.MessageOptions.map_entry', index=3,
+      number=7, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.MessageOptions.uninterpreted_option', index=4,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=3764,
+  serialized_end=4024,
+)
+
+
+_FIELDOPTIONS = _descriptor.Descriptor(
+  name='FieldOptions',
+  full_name='google.protobuf.FieldOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='ctype', full_name='google.protobuf.FieldOptions.ctype', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=True, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='packed', full_name='google.protobuf.FieldOptions.packed', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='jstype', full_name='google.protobuf.FieldOptions.jstype', index=2,
+      number=6, type=14, cpp_type=8, label=1,
+      has_default_value=True, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='lazy', full_name='google.protobuf.FieldOptions.lazy', index=3,
+      number=5, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='unverified_lazy', full_name='google.protobuf.FieldOptions.unverified_lazy', index=4,
+      number=15, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.FieldOptions.deprecated', index=5,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='weak', full_name='google.protobuf.FieldOptions.weak', index=6,
+      number=10, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.FieldOptions.uninterpreted_option', index=7,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _FIELDOPTIONS_CTYPE,
+    _FIELDOPTIONS_JSTYPE,
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=4027,
+  serialized_end=4473,
+)
+
+
+_ONEOFOPTIONS = _descriptor.Descriptor(
+  name='OneofOptions',
+  full_name='google.protobuf.OneofOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.OneofOptions.uninterpreted_option', index=0,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=4475,
+  serialized_end=4569,
+)
+
+
+_ENUMOPTIONS = _descriptor.Descriptor(
+  name='EnumOptions',
+  full_name='google.protobuf.EnumOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='allow_alias', full_name='google.protobuf.EnumOptions.allow_alias', index=0,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.EnumOptions.deprecated', index=1,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.EnumOptions.uninterpreted_option', index=2,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=4572,
+  serialized_end=4719,
+)
+
+
+_ENUMVALUEOPTIONS = _descriptor.Descriptor(
+  name='EnumValueOptions',
+  full_name='google.protobuf.EnumValueOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.EnumValueOptions.deprecated', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.EnumValueOptions.uninterpreted_option', index=1,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=4721,
+  serialized_end=4846,
+)
+
+
+_SERVICEOPTIONS = _descriptor.Descriptor(
+  name='ServiceOptions',
+  full_name='google.protobuf.ServiceOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.ServiceOptions.deprecated', index=0,
+      number=33, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.ServiceOptions.uninterpreted_option', index=1,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=4848,
+  serialized_end=4971,
+)
+
+
+_METHODOPTIONS = _descriptor.Descriptor(
+  name='MethodOptions',
+  full_name='google.protobuf.MethodOptions',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='deprecated', full_name='google.protobuf.MethodOptions.deprecated', index=0,
+      number=33, type=8, cpp_type=7, label=1,
+      has_default_value=True, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='idempotency_level', full_name='google.protobuf.MethodOptions.idempotency_level', index=1,
+      number=34, type=14, cpp_type=8, label=1,
+      has_default_value=True, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='uninterpreted_option', full_name='google.protobuf.MethodOptions.uninterpreted_option', index=2,
+      number=999, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _METHODOPTIONS_IDEMPOTENCYLEVEL,
+  ],
+  serialized_options=None,
+  is_extendable=True,
+  syntax='proto2',
+  extension_ranges=[(1000, 536870912), ],
+  oneofs=[
+  ],
+  serialized_start=4974,
+  serialized_end=5275,
+)
+
+
+_UNINTERPRETEDOPTION_NAMEPART = _descriptor.Descriptor(
+  name='NamePart',
+  full_name='google.protobuf.UninterpretedOption.NamePart',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name_part', full_name='google.protobuf.UninterpretedOption.NamePart.name_part', index=0,
+      number=1, type=9, cpp_type=9, label=2,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='is_extension', full_name='google.protobuf.UninterpretedOption.NamePart.is_extension', index=1,
+      number=2, type=8, cpp_type=7, label=2,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5513,
+  serialized_end=5564,
+)
+
+_UNINTERPRETEDOPTION = _descriptor.Descriptor(
+  name='UninterpretedOption',
+  full_name='google.protobuf.UninterpretedOption',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.UninterpretedOption.name', index=0,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='identifier_value', full_name='google.protobuf.UninterpretedOption.identifier_value', index=1,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='positive_int_value', full_name='google.protobuf.UninterpretedOption.positive_int_value', index=2,
+      number=4, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='negative_int_value', full_name='google.protobuf.UninterpretedOption.negative_int_value', index=3,
+      number=5, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='double_value', full_name='google.protobuf.UninterpretedOption.double_value', index=4,
+      number=6, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='string_value', full_name='google.protobuf.UninterpretedOption.string_value', index=5,
+      number=7, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='aggregate_value', full_name='google.protobuf.UninterpretedOption.aggregate_value', index=6,
+      number=8, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_UNINTERPRETEDOPTION_NAMEPART, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5278,
+  serialized_end=5564,
+)
+
+
+_SOURCECODEINFO_LOCATION = _descriptor.Descriptor(
+  name='Location',
+  full_name='google.protobuf.SourceCodeInfo.Location',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='google.protobuf.SourceCodeInfo.Location.path', index=0,
+      number=1, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='span', full_name='google.protobuf.SourceCodeInfo.Location.span', index=1,
+      number=2, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='leading_comments', full_name='google.protobuf.SourceCodeInfo.Location.leading_comments', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='trailing_comments', full_name='google.protobuf.SourceCodeInfo.Location.trailing_comments', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='leading_detached_comments', full_name='google.protobuf.SourceCodeInfo.Location.leading_detached_comments', index=4,
+      number=6, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5646,
+  serialized_end=5780,
+)
+
+_SOURCECODEINFO = _descriptor.Descriptor(
+  name='SourceCodeInfo',
+  full_name='google.protobuf.SourceCodeInfo',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='location', full_name='google.protobuf.SourceCodeInfo.location', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_SOURCECODEINFO_LOCATION, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5567,
+  serialized_end=5780,
+)
+
+
+_GENERATEDCODEINFO_ANNOTATION = _descriptor.Descriptor(
+  name='Annotation',
+  full_name='google.protobuf.GeneratedCodeInfo.Annotation',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='google.protobuf.GeneratedCodeInfo.Annotation.path', index=0,
+      number=1, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_file', full_name='google.protobuf.GeneratedCodeInfo.Annotation.source_file', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='begin', full_name='google.protobuf.GeneratedCodeInfo.Annotation.begin', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='end', full_name='google.protobuf.GeneratedCodeInfo.Annotation.end', index=3,
+      number=4, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5871,
+  serialized_end=5950,
+)
+
+_GENERATEDCODEINFO = _descriptor.Descriptor(
+  name='GeneratedCodeInfo',
+  full_name='google.protobuf.GeneratedCodeInfo',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='annotation', full_name='google.protobuf.GeneratedCodeInfo.annotation', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_GENERATEDCODEINFO_ANNOTATION, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=5783,
+  serialized_end=5950,
+)
+
+_FILEDESCRIPTORSET.fields_by_name['file'].message_type = _FILEDESCRIPTORPROTO
+_FILEDESCRIPTORPROTO.fields_by_name['message_type'].message_type = _DESCRIPTORPROTO
+_FILEDESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO
+_FILEDESCRIPTORPROTO.fields_by_name['service'].message_type = _SERVICEDESCRIPTORPROTO
+_FILEDESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO
+_FILEDESCRIPTORPROTO.fields_by_name['options'].message_type = _FILEOPTIONS
+_FILEDESCRIPTORPROTO.fields_by_name['source_code_info'].message_type = _SOURCECODEINFO
+_DESCRIPTORPROTO_EXTENSIONRANGE.fields_by_name['options'].message_type = _EXTENSIONRANGEOPTIONS
+_DESCRIPTORPROTO_EXTENSIONRANGE.containing_type = _DESCRIPTORPROTO
+_DESCRIPTORPROTO_RESERVEDRANGE.containing_type = _DESCRIPTORPROTO
+_DESCRIPTORPROTO.fields_by_name['field'].message_type = _FIELDDESCRIPTORPROTO
+_DESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO
+_DESCRIPTORPROTO.fields_by_name['nested_type'].message_type = _DESCRIPTORPROTO
+_DESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO
+_DESCRIPTORPROTO.fields_by_name['extension_range'].message_type = _DESCRIPTORPROTO_EXTENSIONRANGE
+_DESCRIPTORPROTO.fields_by_name['oneof_decl'].message_type = _ONEOFDESCRIPTORPROTO
+_DESCRIPTORPROTO.fields_by_name['options'].message_type = _MESSAGEOPTIONS
+_DESCRIPTORPROTO.fields_by_name['reserved_range'].message_type = _DESCRIPTORPROTO_RESERVEDRANGE
+_EXTENSIONRANGEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_FIELDDESCRIPTORPROTO.fields_by_name['label'].enum_type = _FIELDDESCRIPTORPROTO_LABEL
+_FIELDDESCRIPTORPROTO.fields_by_name['type'].enum_type = _FIELDDESCRIPTORPROTO_TYPE
+_FIELDDESCRIPTORPROTO.fields_by_name['options'].message_type = _FIELDOPTIONS
+_FIELDDESCRIPTORPROTO_TYPE.containing_type = _FIELDDESCRIPTORPROTO
+_FIELDDESCRIPTORPROTO_LABEL.containing_type = _FIELDDESCRIPTORPROTO
+_ONEOFDESCRIPTORPROTO.fields_by_name['options'].message_type = _ONEOFOPTIONS
+_ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE.containing_type = _ENUMDESCRIPTORPROTO
+_ENUMDESCRIPTORPROTO.fields_by_name['value'].message_type = _ENUMVALUEDESCRIPTORPROTO
+_ENUMDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMOPTIONS
+_ENUMDESCRIPTORPROTO.fields_by_name['reserved_range'].message_type = _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE
+_ENUMVALUEDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMVALUEOPTIONS
+_SERVICEDESCRIPTORPROTO.fields_by_name['method'].message_type = _METHODDESCRIPTORPROTO
+_SERVICEDESCRIPTORPROTO.fields_by_name['options'].message_type = _SERVICEOPTIONS
+_METHODDESCRIPTORPROTO.fields_by_name['options'].message_type = _METHODOPTIONS
+_FILEOPTIONS.fields_by_name['optimize_for'].enum_type = _FILEOPTIONS_OPTIMIZEMODE
+_FILEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_FILEOPTIONS_OPTIMIZEMODE.containing_type = _FILEOPTIONS
+_MESSAGEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_FIELDOPTIONS.fields_by_name['ctype'].enum_type = _FIELDOPTIONS_CTYPE
+_FIELDOPTIONS.fields_by_name['jstype'].enum_type = _FIELDOPTIONS_JSTYPE
+_FIELDOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_FIELDOPTIONS_CTYPE.containing_type = _FIELDOPTIONS
+_FIELDOPTIONS_JSTYPE.containing_type = _FIELDOPTIONS
+_ONEOFOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_ENUMOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_ENUMVALUEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_SERVICEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_METHODOPTIONS.fields_by_name['idempotency_level'].enum_type = _METHODOPTIONS_IDEMPOTENCYLEVEL
+_METHODOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+_METHODOPTIONS_IDEMPOTENCYLEVEL.containing_type = _METHODOPTIONS
+_UNINTERPRETEDOPTION_NAMEPART.containing_type = _UNINTERPRETEDOPTION
+_UNINTERPRETEDOPTION.fields_by_name['name'].message_type = _UNINTERPRETEDOPTION_NAMEPART
+_SOURCECODEINFO_LOCATION.containing_type = _SOURCECODEINFO
+_SOURCECODEINFO.fields_by_name['location'].message_type = _SOURCECODEINFO_LOCATION
+_GENERATEDCODEINFO_ANNOTATION.containing_type = _GENERATEDCODEINFO
+_GENERATEDCODEINFO.fields_by_name['annotation'].message_type = _GENERATEDCODEINFO_ANNOTATION
+DESCRIPTOR.message_types_by_name['FileDescriptorSet'] = _FILEDESCRIPTORSET
+DESCRIPTOR.message_types_by_name['FileDescriptorProto'] = _FILEDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['DescriptorProto'] = _DESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['ExtensionRangeOptions'] = _EXTENSIONRANGEOPTIONS
+DESCRIPTOR.message_types_by_name['FieldDescriptorProto'] = _FIELDDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['OneofDescriptorProto'] = _ONEOFDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['EnumDescriptorProto'] = _ENUMDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['EnumValueDescriptorProto'] = _ENUMVALUEDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['ServiceDescriptorProto'] = _SERVICEDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['MethodDescriptorProto'] = _METHODDESCRIPTORPROTO
+DESCRIPTOR.message_types_by_name['FileOptions'] = _FILEOPTIONS
+DESCRIPTOR.message_types_by_name['MessageOptions'] = _MESSAGEOPTIONS
+DESCRIPTOR.message_types_by_name['FieldOptions'] = _FIELDOPTIONS
+DESCRIPTOR.message_types_by_name['OneofOptions'] = _ONEOFOPTIONS
+DESCRIPTOR.message_types_by_name['EnumOptions'] = _ENUMOPTIONS
+DESCRIPTOR.message_types_by_name['EnumValueOptions'] = _ENUMVALUEOPTIONS
+DESCRIPTOR.message_types_by_name['ServiceOptions'] = _SERVICEOPTIONS
+DESCRIPTOR.message_types_by_name['MethodOptions'] = _METHODOPTIONS
+DESCRIPTOR.message_types_by_name['UninterpretedOption'] = _UNINTERPRETEDOPTION
+DESCRIPTOR.message_types_by_name['SourceCodeInfo'] = _SOURCECODEINFO
+DESCRIPTOR.message_types_by_name['GeneratedCodeInfo'] = _GENERATEDCODEINFO
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+FileDescriptorSet = _reflection.GeneratedProtocolMessageType('FileDescriptorSet', (_message.Message,), {
+  'DESCRIPTOR' : _FILEDESCRIPTORSET,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
+  })
+_sym_db.RegisterMessage(FileDescriptorSet)
+
+FileDescriptorProto = _reflection.GeneratedProtocolMessageType('FileDescriptorProto', (_message.Message,), {
+  'DESCRIPTOR' : _FILEDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
+  })
+_sym_db.RegisterMessage(FileDescriptorProto)
+
+DescriptorProto = _reflection.GeneratedProtocolMessageType('DescriptorProto', (_message.Message,), {
+
+  'ExtensionRange' : _reflection.GeneratedProtocolMessageType('ExtensionRange', (_message.Message,), {
+    'DESCRIPTOR' : _DESCRIPTORPROTO_EXTENSIONRANGE,
+    '__module__' : 'google.protobuf.descriptor_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
+    })
+  ,
+
+  'ReservedRange' : _reflection.GeneratedProtocolMessageType('ReservedRange', (_message.Message,), {
+    'DESCRIPTOR' : _DESCRIPTORPROTO_RESERVEDRANGE,
+    '__module__' : 'google.protobuf.descriptor_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ReservedRange)
+    })
+  ,
+  'DESCRIPTOR' : _DESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
+  })
+_sym_db.RegisterMessage(DescriptorProto)
+_sym_db.RegisterMessage(DescriptorProto.ExtensionRange)
+_sym_db.RegisterMessage(DescriptorProto.ReservedRange)
+
+ExtensionRangeOptions = _reflection.GeneratedProtocolMessageType('ExtensionRangeOptions', (_message.Message,), {
+  'DESCRIPTOR' : _EXTENSIONRANGEOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.ExtensionRangeOptions)
+  })
+_sym_db.RegisterMessage(ExtensionRangeOptions)
+
+FieldDescriptorProto = _reflection.GeneratedProtocolMessageType('FieldDescriptorProto', (_message.Message,), {
+  'DESCRIPTOR' : _FIELDDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
+  })
+_sym_db.RegisterMessage(FieldDescriptorProto)
+
+OneofDescriptorProto = _reflection.GeneratedProtocolMessageType('OneofDescriptorProto', (_message.Message,), {
+  'DESCRIPTOR' : _ONEOFDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
+  })
+_sym_db.RegisterMessage(OneofDescriptorProto)
+
+EnumDescriptorProto = _reflection.GeneratedProtocolMessageType('EnumDescriptorProto', (_message.Message,), {
+
+  'EnumReservedRange' : _reflection.GeneratedProtocolMessageType('EnumReservedRange', (_message.Message,), {
+    'DESCRIPTOR' : _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE,
+    '__module__' : 'google.protobuf.descriptor_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+    })
+  ,
+  'DESCRIPTOR' : _ENUMDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
+  })
+_sym_db.RegisterMessage(EnumDescriptorProto)
+_sym_db.RegisterMessage(EnumDescriptorProto.EnumReservedRange)
+
+EnumValueDescriptorProto = _reflection.GeneratedProtocolMessageType('EnumValueDescriptorProto', (_message.Message,), {
+  'DESCRIPTOR' : _ENUMVALUEDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
+  })
+_sym_db.RegisterMessage(EnumValueDescriptorProto)
+
+ServiceDescriptorProto = _reflection.GeneratedProtocolMessageType('ServiceDescriptorProto', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICEDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
+  })
+_sym_db.RegisterMessage(ServiceDescriptorProto)
+
+MethodDescriptorProto = _reflection.GeneratedProtocolMessageType('MethodDescriptorProto', (_message.Message,), {
+  'DESCRIPTOR' : _METHODDESCRIPTORPROTO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
+  })
+_sym_db.RegisterMessage(MethodDescriptorProto)
+
+FileOptions = _reflection.GeneratedProtocolMessageType('FileOptions', (_message.Message,), {
+  'DESCRIPTOR' : _FILEOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
+  })
+_sym_db.RegisterMessage(FileOptions)
+
+MessageOptions = _reflection.GeneratedProtocolMessageType('MessageOptions', (_message.Message,), {
+  'DESCRIPTOR' : _MESSAGEOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
+  })
+_sym_db.RegisterMessage(MessageOptions)
+
+FieldOptions = _reflection.GeneratedProtocolMessageType('FieldOptions', (_message.Message,), {
+  'DESCRIPTOR' : _FIELDOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
+  })
+_sym_db.RegisterMessage(FieldOptions)
+
+OneofOptions = _reflection.GeneratedProtocolMessageType('OneofOptions', (_message.Message,), {
+  'DESCRIPTOR' : _ONEOFOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.OneofOptions)
+  })
+_sym_db.RegisterMessage(OneofOptions)
+
+EnumOptions = _reflection.GeneratedProtocolMessageType('EnumOptions', (_message.Message,), {
+  'DESCRIPTOR' : _ENUMOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
+  })
+_sym_db.RegisterMessage(EnumOptions)
+
+EnumValueOptions = _reflection.GeneratedProtocolMessageType('EnumValueOptions', (_message.Message,), {
+  'DESCRIPTOR' : _ENUMVALUEOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
+  })
+_sym_db.RegisterMessage(EnumValueOptions)
+
+ServiceOptions = _reflection.GeneratedProtocolMessageType('ServiceOptions', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICEOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
+  })
+_sym_db.RegisterMessage(ServiceOptions)
+
+MethodOptions = _reflection.GeneratedProtocolMessageType('MethodOptions', (_message.Message,), {
+  'DESCRIPTOR' : _METHODOPTIONS,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
+  })
+_sym_db.RegisterMessage(MethodOptions)
+
+UninterpretedOption = _reflection.GeneratedProtocolMessageType('UninterpretedOption', (_message.Message,), {
+
+  'NamePart' : _reflection.GeneratedProtocolMessageType('NamePart', (_message.Message,), {
+    'DESCRIPTOR' : _UNINTERPRETEDOPTION_NAMEPART,
+    '__module__' : 'google.protobuf.descriptor_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
+    })
+  ,
+  'DESCRIPTOR' : _UNINTERPRETEDOPTION,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
+  })
+_sym_db.RegisterMessage(UninterpretedOption)
+_sym_db.RegisterMessage(UninterpretedOption.NamePart)
+
+SourceCodeInfo = _reflection.GeneratedProtocolMessageType('SourceCodeInfo', (_message.Message,), {
+
+  'Location' : _reflection.GeneratedProtocolMessageType('Location', (_message.Message,), {
+    'DESCRIPTOR' : _SOURCECODEINFO_LOCATION,
+    '__module__' : 'google.protobuf.descriptor_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
+    })
+  ,
+  'DESCRIPTOR' : _SOURCECODEINFO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
+  })
+_sym_db.RegisterMessage(SourceCodeInfo)
+_sym_db.RegisterMessage(SourceCodeInfo.Location)
+
+GeneratedCodeInfo = _reflection.GeneratedProtocolMessageType('GeneratedCodeInfo', (_message.Message,), {
+
+  'Annotation' : _reflection.GeneratedProtocolMessageType('Annotation', (_message.Message,), {
+    'DESCRIPTOR' : _GENERATEDCODEINFO_ANNOTATION,
+    '__module__' : 'google.protobuf.descriptor_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation)
+    })
+  ,
+  'DESCRIPTOR' : _GENERATEDCODEINFO,
+  '__module__' : 'google.protobuf.descriptor_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo)
+  })
+_sym_db.RegisterMessage(GeneratedCodeInfo)
+_sym_db.RegisterMessage(GeneratedCodeInfo.Annotation)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
new file mode 100644
index 0000000..911372a
--- /dev/null
+++ b/python/google/protobuf/descriptor_pool.py
@@ -0,0 +1,1295 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Provides DescriptorPool to use as a container for proto2 descriptors.
+
+The DescriptorPool is used in conjection with a DescriptorDatabase to maintain
+a collection of protocol buffer descriptors for use when dynamically creating
+message types at runtime.
+
+For most applications protocol buffers should be used via modules generated by
+the protocol buffer compiler tool. This should only be used when the type of
+protocol buffers used in an application or library cannot be predetermined.
+
+Below is a straightforward example on how to use this class::
+
+  pool = DescriptorPool()
+  file_descriptor_protos = [ ... ]
+  for file_descriptor_proto in file_descriptor_protos:
+    pool.Add(file_descriptor_proto)
+  my_message_descriptor = pool.FindMessageTypeByName('some.package.MessageType')
+
+The message descriptor can be used in conjunction with the message_factory
+module in order to create a protocol buffer class that can be encoded and
+decoded.
+
+If you want to get a Python class for the specified proto, use the
+helper functions inside google.protobuf.message_factory
+directly instead of this class.
+"""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import collections
+import warnings
+
+from google.protobuf import descriptor
+from google.protobuf import descriptor_database
+from google.protobuf import text_encoding
+
+
+_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS  # pylint: disable=protected-access
+
+
+def _Deprecated(func):
+  """Mark functions as deprecated."""
+
+  def NewFunc(*args, **kwargs):
+    warnings.warn(
+        'Call to deprecated function %s(). Note: Do add unlinked descriptors '
+        'to descriptor_pool is wrong. Use Add() or AddSerializedFile() '
+        'instead.' % func.__name__,
+        category=DeprecationWarning)
+    return func(*args, **kwargs)
+  NewFunc.__name__ = func.__name__
+  NewFunc.__doc__ = func.__doc__
+  NewFunc.__dict__.update(func.__dict__)
+  return NewFunc
+
+
+def _NormalizeFullyQualifiedName(name):
+  """Remove leading period from fully-qualified type name.
+
+  Due to b/13860351 in descriptor_database.py, types in the root namespace are
+  generated with a leading period. This function removes that prefix.
+
+  Args:
+    name (str): The fully-qualified symbol name.
+
+  Returns:
+    str: The normalized fully-qualified symbol name.
+  """
+  return name.lstrip('.')
+
+
+def _OptionsOrNone(descriptor_proto):
+  """Returns the value of the field `options`, or None if it is not set."""
+  if descriptor_proto.HasField('options'):
+    return descriptor_proto.options
+  else:
+    return None
+
+
+def _IsMessageSetExtension(field):
+  return (field.is_extension and
+          field.containing_type.has_options and
+          field.containing_type.GetOptions().message_set_wire_format and
+          field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL)
+
+
+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.
+
+    The descriptor_db argument to the constructor is provided to allow
+    specialized file descriptor proto lookup code to be triggered on demand. An
+    example would be an implementation which will read and compile a file
+    specified in a call to FindFileByName() and not require the call to Add()
+    at all. Results from this database will be cached internally here as well.
+
+    Args:
+      descriptor_db: A secondary source of file descriptors.
+    """
+
+    self._internal_db = descriptor_database.DescriptorDatabase()
+    self._descriptor_db = descriptor_db
+    self._descriptors = {}
+    self._enum_descriptors = {}
+    self._service_descriptors = {}
+    self._file_descriptors = {}
+    self._toplevel_extensions = {}
+    # TODO(jieluo): Remove _file_desc_by_toplevel_extension after
+    # maybe year 2020 for compatibility issue (with 3.4.1 only).
+    self._file_desc_by_toplevel_extension = {}
+    self._top_enum_values = {}
+    # We store extensions in two two-level mappings: The first key is the
+    # descriptor of the message being extended, the second key is the extension
+    # full name or its tag number.
+    self._extensions_by_name = collections.defaultdict(dict)
+    self._extensions_by_number = collections.defaultdict(dict)
+
+  def _CheckConflictRegister(self, desc, desc_name, file_name):
+    """Check if the descriptor name conflicts with another of the same name.
+
+    Args:
+      desc: Descriptor of a message, enum, service, extension or enum value.
+      desc_name (str): the full name of desc.
+      file_name (str): The file name of descriptor.
+    """
+    for register, descriptor_type in [
+        (self._descriptors, descriptor.Descriptor),
+        (self._enum_descriptors, descriptor.EnumDescriptor),
+        (self._service_descriptors, descriptor.ServiceDescriptor),
+        (self._toplevel_extensions, descriptor.FieldDescriptor),
+        (self._top_enum_values, descriptor.EnumValueDescriptor)]:
+      if desc_name in register:
+        old_desc = register[desc_name]
+        if isinstance(old_desc, descriptor.EnumValueDescriptor):
+          old_file = old_desc.type.file.name
+        else:
+          old_file = old_desc.file.name
+
+        if not isinstance(desc, descriptor_type) or (
+            old_file != file_name):
+          error_msg = ('Conflict register for file "' + file_name +
+                       '": ' + desc_name +
+                       ' is already defined in file "' +
+                       old_file + '". Please fix the conflict by adding '
+                       'package name on the proto file, or use different '
+                       'name for the duplication.')
+          if isinstance(desc, descriptor.EnumValueDescriptor):
+            error_msg += ('\nNote: enum values appear as '
+                          'siblings of the enum type instead of '
+                          'children of it.')
+
+          raise TypeError(error_msg)
+
+        return
+
+  def Add(self, file_desc_proto):
+    """Adds the FileDescriptorProto and its types to this pool.
+
+    Args:
+      file_desc_proto (FileDescriptorProto): The file descriptor to add.
+    """
+
+    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 (bytes): A bytes string, serialization of the
+        :class:`FileDescriptorProto` to add.
+
+    Returns:
+      FileDescriptor: Descriptor for the added file.
+    """
+
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf import descriptor_pb2
+    file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
+        serialized_file_desc_proto)
+    file_desc = self._ConvertFileProtoToFileDescriptor(file_desc_proto)
+    file_desc.serialized_pb = serialized_file_desc_proto
+    return file_desc
+
+  # Add Descriptor to descriptor pool is dreprecated. Please use Add()
+  # or AddSerializedFile() to add a FileDescriptorProto instead.
+  @_Deprecated
+  def AddDescriptor(self, desc):
+    self._AddDescriptor(desc)
+
+  # Never call this method. It is for internal usage only.
+  def _AddDescriptor(self, desc):
+    """Adds a Descriptor to the pool, non-recursively.
+
+    If the Descriptor contains nested messages or enums, the caller must
+    explicitly register them. This method also registers the FileDescriptor
+    associated with the message.
+
+    Args:
+      desc: A Descriptor.
+    """
+    if not isinstance(desc, descriptor.Descriptor):
+      raise TypeError('Expected instance of descriptor.Descriptor.')
+
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
+
+    self._descriptors[desc.full_name] = desc
+    self._AddFileDescriptor(desc.file)
+
+  # Add EnumDescriptor to descriptor pool is dreprecated. Please use Add()
+  # or AddSerializedFile() to add a FileDescriptorProto instead.
+  @_Deprecated
+  def AddEnumDescriptor(self, enum_desc):
+    self._AddEnumDescriptor(enum_desc)
+
+  # Never call this method. It is for internal usage only.
+  def _AddEnumDescriptor(self, enum_desc):
+    """Adds an EnumDescriptor to the pool.
+
+    This method also registers the FileDescriptor associated with the enum.
+
+    Args:
+      enum_desc: An EnumDescriptor.
+    """
+
+    if not isinstance(enum_desc, descriptor.EnumDescriptor):
+      raise TypeError('Expected instance of descriptor.EnumDescriptor.')
+
+    file_name = enum_desc.file.name
+    self._CheckConflictRegister(enum_desc, enum_desc.full_name, file_name)
+    self._enum_descriptors[enum_desc.full_name] = enum_desc
+
+    # Top enum values need to be indexed.
+    # Count the number of dots to see whether the enum is toplevel or nested
+    # in a message. We cannot use enum_desc.containing_type at this stage.
+    if enum_desc.file.package:
+      top_level = (enum_desc.full_name.count('.')
+                   - enum_desc.file.package.count('.') == 1)
+    else:
+      top_level = enum_desc.full_name.count('.') == 0
+    if top_level:
+      file_name = enum_desc.file.name
+      package = enum_desc.file.package
+      for enum_value in enum_desc.values:
+        full_name = _NormalizeFullyQualifiedName(
+            '.'.join((package, enum_value.name)))
+        self._CheckConflictRegister(enum_value, full_name, file_name)
+        self._top_enum_values[full_name] = enum_value
+    self._AddFileDescriptor(enum_desc.file)
+
+  # Add ServiceDescriptor to descriptor pool is dreprecated. Please use Add()
+  # or AddSerializedFile() to add a FileDescriptorProto instead.
+  @_Deprecated
+  def AddServiceDescriptor(self, service_desc):
+    self._AddServiceDescriptor(service_desc)
+
+  # Never call this method. It is for internal usage only.
+  def _AddServiceDescriptor(self, service_desc):
+    """Adds a ServiceDescriptor to the pool.
+
+    Args:
+      service_desc: A ServiceDescriptor.
+    """
+
+    if not isinstance(service_desc, descriptor.ServiceDescriptor):
+      raise TypeError('Expected instance of descriptor.ServiceDescriptor.')
+
+    self._CheckConflictRegister(service_desc, service_desc.full_name,
+                                service_desc.file.name)
+    self._service_descriptors[service_desc.full_name] = service_desc
+
+  # Add ExtensionDescriptor to descriptor pool is dreprecated. Please use Add()
+  # or AddSerializedFile() to add a FileDescriptorProto instead.
+  @_Deprecated
+  def AddExtensionDescriptor(self, extension):
+    self._AddExtensionDescriptor(extension)
+
+  # Never call this method. It is for internal usage only.
+  def _AddExtensionDescriptor(self, extension):
+    """Adds a FieldDescriptor describing an extension to the pool.
+
+    Args:
+      extension: A FieldDescriptor.
+
+    Raises:
+      AssertionError: when another extension with the same number extends the
+        same message.
+      TypeError: when the specified extension is not a
+        descriptor.FieldDescriptor.
+    """
+    if not (isinstance(extension, descriptor.FieldDescriptor) and
+            extension.is_extension):
+      raise TypeError('Expected an extension descriptor.')
+
+    if extension.extension_scope is None:
+      self._toplevel_extensions[extension.full_name] = extension
+
+    try:
+      existing_desc = self._extensions_by_number[
+          extension.containing_type][extension.number]
+    except KeyError:
+      pass
+    else:
+      if extension is not existing_desc:
+        raise AssertionError(
+            'Extensions "%s" and "%s" both try to extend message type "%s" '
+            'with field number %d.' %
+            (extension.full_name, existing_desc.full_name,
+             extension.containing_type.full_name, extension.number))
+
+    self._extensions_by_number[extension.containing_type][
+        extension.number] = extension
+    self._extensions_by_name[extension.containing_type][
+        extension.full_name] = extension
+
+    # Also register MessageSet extensions with the type name.
+    if _IsMessageSetExtension(extension):
+      self._extensions_by_name[extension.containing_type][
+          extension.message_type.full_name] = extension
+
+  @_Deprecated
+  def AddFileDescriptor(self, file_desc):
+    self._InternalAddFileDescriptor(file_desc)
+
+  # Never call this method. It is for internal usage only.
+  def _InternalAddFileDescriptor(self, file_desc):
+    """Adds a FileDescriptor to the pool, non-recursively.
+
+    If the FileDescriptor contains messages or enums, the caller must explicitly
+    register them.
+
+    Args:
+      file_desc: A FileDescriptor.
+    """
+
+    self._AddFileDescriptor(file_desc)
+    # TODO(jieluo): This is a temporary solution for FieldDescriptor.file.
+    # FieldDescriptor.file is added in code gen. Remove this solution after
+    # maybe 2020 for compatibility reason (with 3.4.1 only).
+    for extension in file_desc.extensions_by_name.values():
+      self._file_desc_by_toplevel_extension[
+          extension.full_name] = file_desc
+
+  def _AddFileDescriptor(self, file_desc):
+    """Adds a FileDescriptor to the pool, non-recursively.
+
+    If the FileDescriptor contains messages or enums, the caller must explicitly
+    register them.
+
+    Args:
+      file_desc: A FileDescriptor.
+    """
+
+    if not isinstance(file_desc, descriptor.FileDescriptor):
+      raise TypeError('Expected instance of descriptor.FileDescriptor.')
+    self._file_descriptors[file_desc.name] = file_desc
+
+  def FindFileByName(self, file_name):
+    """Gets a FileDescriptor by file name.
+
+    Args:
+      file_name (str): The path to the file to get a descriptor for.
+
+    Returns:
+      FileDescriptor: The descriptor for the named file.
+
+    Raises:
+      KeyError: if the file cannot be found in the pool.
+    """
+
+    try:
+      return self._file_descriptors[file_name]
+    except KeyError:
+      pass
+
+    try:
+      file_proto = self._internal_db.FindFileByName(file_name)
+    except KeyError as error:
+      if self._descriptor_db:
+        file_proto = self._descriptor_db.FindFileByName(file_name)
+      else:
+        raise error
+    if not file_proto:
+      raise KeyError('Cannot find a file named %s' % file_name)
+    return self._ConvertFileProtoToFileDescriptor(file_proto)
+
+  def FindFileContainingSymbol(self, symbol):
+    """Gets the FileDescriptor for the file containing the specified symbol.
+
+    Args:
+      symbol (str): The name of the symbol to search for.
+
+    Returns:
+      FileDescriptor: Descriptor for the file that contains the specified
+      symbol.
+
+    Raises:
+      KeyError: if the file cannot be found in the pool.
+    """
+
+    symbol = _NormalizeFullyQualifiedName(symbol)
+    try:
+      return self._InternalFindFileContainingSymbol(symbol)
+    except KeyError:
+      pass
+
+    try:
+      # Try fallback database. Build and find again if possible.
+      self._FindFileContainingSymbolInDb(symbol)
+      return self._InternalFindFileContainingSymbol(symbol)
+    except KeyError:
+      raise KeyError('Cannot find a file containing %s' % symbol)
+
+  def _InternalFindFileContainingSymbol(self, symbol):
+    """Gets the already built FileDescriptor containing the specified symbol.
+
+    Args:
+      symbol (str): The name of the symbol to search for.
+
+    Returns:
+      FileDescriptor: Descriptor for the file that contains the specified
+      symbol.
+
+    Raises:
+      KeyError: if the file cannot be found in the pool.
+    """
+    try:
+      return self._descriptors[symbol].file
+    except KeyError:
+      pass
+
+    try:
+      return self._enum_descriptors[symbol].file
+    except KeyError:
+      pass
+
+    try:
+      return self._service_descriptors[symbol].file
+    except KeyError:
+      pass
+
+    try:
+      return self._top_enum_values[symbol].type.file
+    except KeyError:
+      pass
+
+    try:
+      return self._file_desc_by_toplevel_extension[symbol]
+    except KeyError:
+      pass
+
+    # Try fields, enum values and nested extensions inside a message.
+    top_name, _, sub_name = symbol.rpartition('.')
+    try:
+      message = self.FindMessageTypeByName(top_name)
+      assert (sub_name in message.extensions_by_name or
+              sub_name in message.fields_by_name or
+              sub_name in message.enum_values_by_name)
+      return message.file
+    except (KeyError, AssertionError):
+      raise KeyError('Cannot find a file containing %s' % symbol)
+
+  def FindMessageTypeByName(self, full_name):
+    """Loads the named descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the descriptor to load.
+
+    Returns:
+      Descriptor: The descriptor for the named type.
+
+    Raises:
+      KeyError: if the message cannot be found in the pool.
+    """
+
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    if full_name not in self._descriptors:
+      self._FindFileContainingSymbolInDb(full_name)
+    return self._descriptors[full_name]
+
+  def FindEnumTypeByName(self, full_name):
+    """Loads the named enum descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the enum descriptor to load.
+
+    Returns:
+      EnumDescriptor: The enum descriptor for the named type.
+
+    Raises:
+      KeyError: if the enum cannot be found in the pool.
+    """
+
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    if full_name not in self._enum_descriptors:
+      self._FindFileContainingSymbolInDb(full_name)
+    return self._enum_descriptors[full_name]
+
+  def FindFieldByName(self, full_name):
+    """Loads the named field descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the field descriptor to load.
+
+    Returns:
+      FieldDescriptor: The field descriptor for the named field.
+
+    Raises:
+      KeyError: if the field cannot be found in the pool.
+    """
+    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 FindOneofByName(self, full_name):
+    """Loads the named oneof descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the oneof descriptor to load.
+
+    Returns:
+      OneofDescriptor: The oneof descriptor for the named oneof.
+
+    Raises:
+      KeyError: if the oneof cannot be found in the pool.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    message_name, _, oneof_name = full_name.rpartition('.')
+    message_descriptor = self.FindMessageTypeByName(message_name)
+    return message_descriptor.oneofs_by_name[oneof_name]
+
+  def FindExtensionByName(self, full_name):
+    """Loads the named extension descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the extension descriptor to load.
+
+    Returns:
+      FieldDescriptor: The field descriptor for the named extension.
+
+    Raises:
+      KeyError: if the extension cannot be found in the pool.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    try:
+      # The proto compiler does not give any link between the FileDescriptor
+      # and top-level extensions unless the FileDescriptorProto is added to
+      # the DescriptorDatabase, but this can impact memory usage.
+      # So we registered these extensions by name explicitly.
+      return self._toplevel_extensions[full_name]
+    except KeyError:
+      pass
+    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._FindFileContainingSymbolInDb(full_name)
+    return scope.extensions_by_name[extension_name]
+
+  def FindExtensionByNumber(self, message_descriptor, number):
+    """Gets the extension of the specified message with the specified number.
+
+    Extensions have to be registered to this pool by calling :func:`Add` or
+    :func:`AddExtensionDescriptor`.
+
+    Args:
+      message_descriptor (Descriptor): descriptor of the extended message.
+      number (int): Number of the extension field.
+
+    Returns:
+      FieldDescriptor: The descriptor for the extension.
+
+    Raises:
+      KeyError: when no extension with the given number is known for the
+        specified message.
+    """
+    try:
+      return self._extensions_by_number[message_descriptor][number]
+    except KeyError:
+      self._TryLoadExtensionFromDB(message_descriptor, number)
+      return self._extensions_by_number[message_descriptor][number]
+
+  def FindAllExtensions(self, message_descriptor):
+    """Gets all the known extensions of a given message.
+
+    Extensions have to be registered to this pool by build related
+    :func:`Add` or :func:`AddExtensionDescriptor`.
+
+    Args:
+      message_descriptor (Descriptor): Descriptor of the extended message.
+
+    Returns:
+      list[FieldDescriptor]: Field descriptors describing the extensions.
+    """
+    # Fallback to descriptor db if FindAllExtensionNumbers is provided.
+    if self._descriptor_db and hasattr(
+        self._descriptor_db, 'FindAllExtensionNumbers'):
+      full_name = message_descriptor.full_name
+      all_numbers = self._descriptor_db.FindAllExtensionNumbers(full_name)
+      for number in all_numbers:
+        if number in self._extensions_by_number[message_descriptor]:
+          continue
+        self._TryLoadExtensionFromDB(message_descriptor, number)
+
+    return list(self._extensions_by_number[message_descriptor].values())
+
+  def _TryLoadExtensionFromDB(self, message_descriptor, number):
+    """Try to Load extensions from descriptor db.
+
+    Args:
+      message_descriptor: descriptor of the extended message.
+      number: the extension number that needs to be loaded.
+    """
+    if not self._descriptor_db:
+      return
+    # Only supported when FindFileContainingExtension is provided.
+    if not hasattr(
+        self._descriptor_db, 'FindFileContainingExtension'):
+      return
+
+    full_name = message_descriptor.full_name
+    file_proto = self._descriptor_db.FindFileContainingExtension(
+        full_name, number)
+
+    if file_proto is None:
+      return
+
+    try:
+      self._ConvertFileProtoToFileDescriptor(file_proto)
+    except:
+      warn_msg = ('Unable to load proto file %s for extension number %d.' %
+                  (file_proto.name, number))
+      warnings.warn(warn_msg, RuntimeWarning)
+
+  def FindServiceByName(self, full_name):
+    """Loads the named service descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the service descriptor to load.
+
+    Returns:
+      ServiceDescriptor: The service descriptor for the named service.
+
+    Raises:
+      KeyError: if the service cannot be found in the pool.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    if full_name not in self._service_descriptors:
+      self._FindFileContainingSymbolInDb(full_name)
+    return self._service_descriptors[full_name]
+
+  def FindMethodByName(self, full_name):
+    """Loads the named service method descriptor from the pool.
+
+    Args:
+      full_name (str): The full name of the method descriptor to load.
+
+    Returns:
+      MethodDescriptor: The method descriptor for the service method.
+
+    Raises:
+      KeyError: if the method cannot be found in the pool.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    service_name, _, method_name = full_name.rpartition('.')
+    service_descriptor = self.FindServiceByName(service_name)
+    return service_descriptor.methods_by_name[method_name]
+
+  def _FindFileContainingSymbolInDb(self, symbol):
+    """Finds the file in descriptor DB containing the specified symbol.
+
+    Args:
+      symbol (str): The name of the symbol to search for.
+
+    Returns:
+      FileDescriptor: The file that contains the specified symbol.
+
+    Raises:
+      KeyError: if the file cannot be found in the descriptor database.
+    """
+    try:
+      file_proto = self._internal_db.FindFileContainingSymbol(symbol)
+    except KeyError as error:
+      if self._descriptor_db:
+        file_proto = self._descriptor_db.FindFileContainingSymbol(symbol)
+      else:
+        raise error
+    if not file_proto:
+      raise KeyError('Cannot find a file containing %s' % symbol)
+    return self._ConvertFileProtoToFileDescriptor(file_proto)
+
+  def _ConvertFileProtoToFileDescriptor(self, file_proto):
+    """Creates a FileDescriptor from a proto or returns a cached copy.
+
+    This method also has the side effect of loading all the symbols found in
+    the file into the appropriate dictionaries in the pool.
+
+    Args:
+      file_proto: The proto to convert.
+
+    Returns:
+      A FileDescriptor matching the passed in proto.
+    """
+    if file_proto.name not in self._file_descriptors:
+      built_deps = list(self._GetDeps(file_proto.dependency))
+      direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
+      public_deps = [direct_deps[i] for i in file_proto.public_dependency]
+
+      file_descriptor = descriptor.FileDescriptor(
+          pool=self,
+          name=file_proto.name,
+          package=file_proto.package,
+          syntax=file_proto.syntax,
+          options=_OptionsOrNone(file_proto),
+          serialized_pb=file_proto.SerializeToString(),
+          dependencies=direct_deps,
+          public_dependencies=public_deps,
+          # pylint: disable=protected-access
+          create_key=descriptor._internal_create_key)
+      scope = {}
+
+      # This loop extracts all the message and enum types from all the
+      # dependencies of the file_proto. This is necessary to create the
+      # scope of available message types when defining the passed in
+      # file proto.
+      for dependency in built_deps:
+        scope.update(self._ExtractSymbols(
+            dependency.message_types_by_name.values()))
+        scope.update((_PrefixWithDot(enum.full_name), enum)
+                     for enum in dependency.enum_types_by_name.values())
+
+      for message_type in file_proto.message_type:
+        message_desc = self._ConvertMessageDescriptor(
+            message_type, file_proto.package, file_descriptor, scope,
+            file_proto.syntax)
+        file_descriptor.message_types_by_name[message_desc.name] = (
+            message_desc)
+
+      for enum_type in file_proto.enum_type:
+        file_descriptor.enum_types_by_name[enum_type.name] = (
+            self._ConvertEnumDescriptor(enum_type, file_proto.package,
+                                        file_descriptor, None, scope, True))
+
+      for index, extension_proto in enumerate(file_proto.extension):
+        extension_desc = self._MakeFieldDescriptor(
+            extension_proto, file_proto.package, index, file_descriptor,
+            is_extension=True)
+        extension_desc.containing_type = self._GetTypeFromScope(
+            file_descriptor.package, extension_proto.extendee, scope)
+        self._SetFieldType(extension_proto, extension_desc,
+                           file_descriptor.package, scope)
+        file_descriptor.extensions_by_name[extension_desc.name] = (
+            extension_desc)
+        self._file_desc_by_toplevel_extension[extension_desc.full_name] = (
+            file_descriptor)
+
+      for desc_proto in file_proto.message_type:
+        self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
+
+      if file_proto.package:
+        desc_proto_prefix = _PrefixWithDot(file_proto.package)
+      else:
+        desc_proto_prefix = ''
+
+      for desc_proto in file_proto.message_type:
+        desc = self._GetTypeFromScope(
+            desc_proto_prefix, desc_proto.name, scope)
+        file_descriptor.message_types_by_name[desc_proto.name] = desc
+
+      for index, service_proto in enumerate(file_proto.service):
+        file_descriptor.services_by_name[service_proto.name] = (
+            self._MakeServiceDescriptor(service_proto, index, scope,
+                                        file_proto.package, file_descriptor))
+
+      self._file_descriptors[file_proto.name] = file_descriptor
+
+    # Add extensions to the pool
+    file_desc = self._file_descriptors[file_proto.name]
+    for extension in file_desc.extensions_by_name.values():
+      self._AddExtensionDescriptor(extension)
+    for message_type in file_desc.message_types_by_name.values():
+      for extension in message_type.extensions:
+        self._AddExtensionDescriptor(extension)
+
+    return file_desc
+
+  def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None,
+                                scope=None, syntax=None):
+    """Adds the proto to the pool in the specified package.
+
+    Args:
+      desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
+      package: The package the proto should be located in.
+      file_desc: The file containing this message.
+      scope: Dict mapping short and full symbols to message and enum types.
+      syntax: string indicating syntax of the file ("proto2" or "proto3")
+
+    Returns:
+      The added descriptor.
+    """
+
+    if package:
+      desc_name = '.'.join((package, desc_proto.name))
+    else:
+      desc_name = desc_proto.name
+
+    if file_desc is None:
+      file_name = None
+    else:
+      file_name = file_desc.name
+
+    if scope is None:
+      scope = {}
+
+    nested = [
+        self._ConvertMessageDescriptor(
+            nested, desc_name, file_desc, scope, syntax)
+        for nested in desc_proto.nested_type]
+    enums = [
+        self._ConvertEnumDescriptor(enum, desc_name, file_desc, None,
+                                    scope, False)
+        for enum in desc_proto.enum_type]
+    fields = [self._MakeFieldDescriptor(field, desc_name, index, file_desc)
+              for index, field in enumerate(desc_proto.field)]
+    extensions = [
+        self._MakeFieldDescriptor(extension, desc_name, index, file_desc,
+                                  is_extension=True)
+        for index, extension in enumerate(desc_proto.extension)]
+    oneofs = [
+        # pylint: disable=g-complex-comprehension
+        descriptor.OneofDescriptor(
+            desc.name,
+            '.'.join((desc_name, desc.name)),
+            index,
+            None,
+            [],
+            _OptionsOrNone(desc),
+            # pylint: disable=protected-access
+            create_key=descriptor._internal_create_key)
+        for index, desc in enumerate(desc_proto.oneof_decl)
+    ]
+    extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
+    if extension_ranges:
+      is_extendable = True
+    else:
+      is_extendable = False
+    desc = descriptor.Descriptor(
+        name=desc_proto.name,
+        full_name=desc_name,
+        filename=file_name,
+        containing_type=None,
+        fields=fields,
+        oneofs=oneofs,
+        nested_types=nested,
+        enum_types=enums,
+        extensions=extensions,
+        options=_OptionsOrNone(desc_proto),
+        is_extendable=is_extendable,
+        extension_ranges=extension_ranges,
+        file=file_desc,
+        serialized_start=None,
+        serialized_end=None,
+        syntax=syntax,
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    for nested in desc.nested_types:
+      nested.containing_type = desc
+    for enum in desc.enum_types:
+      enum.containing_type = desc
+    for field_index, field_desc in enumerate(desc_proto.field):
+      if field_desc.HasField('oneof_index'):
+        oneof_index = field_desc.oneof_index
+        oneofs[oneof_index].fields.append(fields[field_index])
+        fields[field_index].containing_oneof = oneofs[oneof_index]
+
+    scope[_PrefixWithDot(desc_name)] = desc
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
+    self._descriptors[desc_name] = desc
+    return desc
+
+  def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
+                             containing_type=None, scope=None, top_level=False):
+    """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
+
+    Args:
+      enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message.
+      package: Optional package name for the new message EnumDescriptor.
+      file_desc: The file containing the enum descriptor.
+      containing_type: The type containing this enum.
+      scope: Scope containing available types.
+      top_level: If True, the enum is a top level symbol. If False, the enum
+          is defined inside a message.
+
+    Returns:
+      The added descriptor
+    """
+
+    if package:
+      enum_name = '.'.join((package, enum_proto.name))
+    else:
+      enum_name = enum_proto.name
+
+    if file_desc is None:
+      file_name = None
+    else:
+      file_name = file_desc.name
+
+    values = [self._MakeEnumValueDescriptor(value, index)
+              for index, value in enumerate(enum_proto.value)]
+    desc = descriptor.EnumDescriptor(name=enum_proto.name,
+                                     full_name=enum_name,
+                                     filename=file_name,
+                                     file=file_desc,
+                                     values=values,
+                                     containing_type=containing_type,
+                                     options=_OptionsOrNone(enum_proto),
+                                     # pylint: disable=protected-access
+                                     create_key=descriptor._internal_create_key)
+    scope['.%s' % enum_name] = desc
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
+    self._enum_descriptors[enum_name] = desc
+
+    # Add top level enum values.
+    if top_level:
+      for value in values:
+        full_name = _NormalizeFullyQualifiedName(
+            '.'.join((package, value.name)))
+        self._CheckConflictRegister(value, full_name, file_name)
+        self._top_enum_values[full_name] = value
+
+    return desc
+
+  def _MakeFieldDescriptor(self, field_proto, message_name, index,
+                           file_desc, is_extension=False):
+    """Creates a field descriptor from a FieldDescriptorProto.
+
+    For message and enum type fields, this method will do a look up
+    in the pool for the appropriate descriptor for that type. If it
+    is unavailable, it will fall back to the _source function to
+    create it. If this type is still unavailable, construction will
+    fail.
+
+    Args:
+      field_proto: The proto describing the field.
+      message_name: The name of the containing message.
+      index: Index of the field
+      file_desc: The file containing the field descriptor.
+      is_extension: Indication that this field is for an extension.
+
+    Returns:
+      An initialized FieldDescriptor object
+    """
+
+    if message_name:
+      full_name = '.'.join((message_name, field_proto.name))
+    else:
+      full_name = field_proto.name
+
+    if field_proto.json_name:
+      json_name = field_proto.json_name
+    else:
+      json_name = None
+
+    return descriptor.FieldDescriptor(
+        name=field_proto.name,
+        full_name=full_name,
+        index=index,
+        number=field_proto.number,
+        type=field_proto.type,
+        cpp_type=None,
+        message_type=None,
+        enum_type=None,
+        containing_type=None,
+        label=field_proto.label,
+        has_default_value=False,
+        default_value=None,
+        is_extension=is_extension,
+        extension_scope=None,
+        options=_OptionsOrNone(field_proto),
+        json_name=json_name,
+        file=file_desc,
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+
+  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.
+
+    Args:
+      package: The current package of desc_proto.
+      desc_proto: The message descriptor to update.
+      scope: Enclosing scope of available types.
+    """
+
+    package = _PrefixWithDot(package)
+
+    main_desc = self._GetTypeFromScope(package, desc_proto.name, scope)
+
+    if package == '.':
+      nested_package = _PrefixWithDot(desc_proto.name)
+    else:
+      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)
+
+    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)
+
+    for nested_type in desc_proto.nested_type:
+      self._SetAllFieldTypes(nested_package, nested_type, scope)
+
+  def _SetFieldType(self, field_proto, field_desc, package, scope):
+    """Sets the field's type, cpp_type, message_type and enum_type.
+
+    Args:
+      field_proto: Data about the field in proto format.
+      field_desc: The descriptor to modify.
+      package: The package the field's container is in.
+      scope: Enclosing scope of available types.
+    """
+    if field_proto.type_name:
+      desc = self._GetTypeFromScope(package, field_proto.type_name, scope)
+    else:
+      desc = None
+
+    if not field_proto.HasField('type'):
+      if isinstance(desc, descriptor.Descriptor):
+        field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE
+      else:
+        field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM
+
+    field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType(
+        field_proto.type)
+
+    if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE
+        or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP):
+      field_desc.message_type = desc
+
+    if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
+      field_desc.enum_type = desc
+
+    if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+      field_desc.has_default_value = False
+      field_desc.default_value = []
+    elif field_proto.HasField('default_value'):
+      field_desc.has_default_value = True
+      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
+          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
+        field_desc.default_value = float(field_proto.default_value)
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
+        field_desc.default_value = field_proto.default_value
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
+        field_desc.default_value = field_proto.default_value.lower() == 'true'
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
+        field_desc.default_value = field_desc.enum_type.values_by_name[
+            field_proto.default_value].number
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
+        field_desc.default_value = text_encoding.CUnescape(
+            field_proto.default_value)
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE:
+        field_desc.default_value = None
+      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
+      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''
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE:
+        field_desc.default_value = None
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP:
+        field_desc.default_value = None
+      else:
+        # All other types are of the "int" type.
+        field_desc.default_value = 0
+
+    field_desc.type = field_proto.type
+
+  def _MakeEnumValueDescriptor(self, value_proto, index):
+    """Creates a enum value descriptor object from a enum value proto.
+
+    Args:
+      value_proto: The proto describing the enum value.
+      index: The index of the enum value.
+
+    Returns:
+      An initialized EnumValueDescriptor object.
+    """
+
+    return descriptor.EnumValueDescriptor(
+        name=value_proto.name,
+        index=index,
+        number=value_proto.number,
+        options=_OptionsOrNone(value_proto),
+        type=None,
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+
+  def _MakeServiceDescriptor(self, service_proto, service_index, scope,
+                             package, file_desc):
+    """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto.
+
+    Args:
+      service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message.
+      service_index: The index of the service in the File.
+      scope: Dict mapping short and full symbols to message and enum types.
+      package: Optional package name for the new message EnumDescriptor.
+      file_desc: The file containing the service descriptor.
+
+    Returns:
+      The added descriptor.
+    """
+
+    if package:
+      service_name = '.'.join((package, service_proto.name))
+    else:
+      service_name = service_proto.name
+
+    methods = [self._MakeMethodDescriptor(method_proto, service_name, package,
+                                          scope, index)
+               for index, method_proto in enumerate(service_proto.method)]
+    desc = descriptor.ServiceDescriptor(
+        name=service_proto.name,
+        full_name=service_name,
+        index=service_index,
+        methods=methods,
+        options=_OptionsOrNone(service_proto),
+        file=file_desc,
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
+    self._service_descriptors[service_name] = desc
+    return desc
+
+  def _MakeMethodDescriptor(self, method_proto, service_name, package, scope,
+                            index):
+    """Creates a method descriptor from a MethodDescriptorProto.
+
+    Args:
+      method_proto: The proto describing the method.
+      service_name: The name of the containing service.
+      package: Optional package name to look up for types.
+      scope: Scope containing available types.
+      index: Index of the method in the service.
+
+    Returns:
+      An initialized MethodDescriptor object.
+    """
+    full_name = '.'.join((service_name, method_proto.name))
+    input_type = self._GetTypeFromScope(
+        package, method_proto.input_type, scope)
+    output_type = self._GetTypeFromScope(
+        package, method_proto.output_type, scope)
+    return descriptor.MethodDescriptor(
+        name=method_proto.name,
+        full_name=full_name,
+        index=index,
+        containing_service=None,
+        input_type=input_type,
+        output_type=output_type,
+        client_streaming=method_proto.client_streaming,
+        server_streaming=method_proto.server_streaming,
+        options=_OptionsOrNone(method_proto),
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+
+  def _ExtractSymbols(self, descriptors):
+    """Pulls out all the symbols from descriptor protos.
+
+    Args:
+      descriptors: The messages to extract descriptors from.
+    Yields:
+      A two element tuple of the type name and descriptor object.
+    """
+
+    for desc in descriptors:
+      yield (_PrefixWithDot(desc.full_name), desc)
+      for symbol in self._ExtractSymbols(desc.nested_types):
+        yield symbol
+      for enum in desc.enum_types:
+        yield (_PrefixWithDot(enum.full_name), enum)
+
+  def _GetDeps(self, dependencies, visited=None):
+    """Recursively finds dependencies for file protos.
+
+    Args:
+      dependencies: The names of the files being depended on.
+      visited: The names of files already found.
+
+    Yields:
+      Each direct and indirect dependency.
+    """
+
+    visited = visited or set()
+    for dependency in dependencies:
+      if dependency not in visited:
+        visited.add(dependency)
+        dep_desc = self.FindFileByName(dependency)
+        yield dep_desc
+        public_files = [d.name for d in dep_desc.public_dependencies]
+        yield from self._GetDeps(public_files, visited)
+
+  def _GetTypeFromScope(self, package, type_name, scope):
+    """Finds a given type name in the current scope.
+
+    Args:
+      package: The package the proto should be located in.
+      type_name: The name of the type to be found in the scope.
+      scope: Dict mapping short and full symbols to message and enum types.
+
+    Returns:
+      The descriptor for the requested type.
+    """
+    if type_name not in scope:
+      components = _PrefixWithDot(package).split('.')
+      while components:
+        possible_match = '.'.join(components + [type_name])
+        if possible_match in scope:
+          type_name = possible_match
+          break
+        else:
+          components.pop(-1)
+    return scope[type_name]
+
+
+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/duration_pb2.py b/python/google/protobuf/duration_pb2.py
new file mode 100644
index 0000000..813a92d
--- /dev/null
+++ b/python/google/protobuf/duration_pb2.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/duration.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/duration.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\rDurationProtoP\001Z1google.golang.org/protobuf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1egoogle/protobuf/duration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_DURATION = _descriptor.Descriptor(
+  name='Duration',
+  full_name='google.protobuf.Duration',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='seconds', full_name='google.protobuf.Duration.seconds', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='nanos', full_name='google.protobuf.Duration.nanos', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=51,
+  serialized_end=93,
+)
+
+DESCRIPTOR.message_types_by_name['Duration'] = _DURATION
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Duration = _reflection.GeneratedProtocolMessageType('Duration', (_message.Message,), {
+  'DESCRIPTOR' : _DURATION,
+  '__module__' : 'google.protobuf.duration_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Duration)
+  })
+_sym_db.RegisterMessage(Duration)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/empty_pb2.py b/python/google/protobuf/empty_pb2.py
new file mode 100644
index 0000000..009d4d5
--- /dev/null
+++ b/python/google/protobuf/empty_pb2.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/empty.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/empty.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\nEmptyProtoP\001Z.google.golang.org/protobuf/types/known/emptypb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1bgoogle/protobuf/empty.proto\x12\x0fgoogle.protobuf\"\x07\n\x05\x45mptyB}\n\x13\x63om.google.protobufB\nEmptyProtoP\x01Z.google.golang.org/protobuf/types/known/emptypb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_EMPTY = _descriptor.Descriptor(
+  name='Empty',
+  full_name='google.protobuf.Empty',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=48,
+  serialized_end=55,
+)
+
+DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), {
+  'DESCRIPTOR' : _EMPTY,
+  '__module__' : 'google.protobuf.empty_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Empty)
+  })
+_sym_db.RegisterMessage(Empty)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/field_mask_pb2.py b/python/google/protobuf/field_mask_pb2.py
new file mode 100644
index 0000000..c749424
--- /dev/null
+++ b/python/google/protobuf/field_mask_pb2.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/field_mask.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/field_mask.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\016FieldMaskProtoP\001Z2google.golang.org/protobuf/types/known/fieldmaskpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n google/protobuf/field_mask.proto\x12\x0fgoogle.protobuf\"\x1a\n\tFieldMask\x12\r\n\x05paths\x18\x01 \x03(\tB\x85\x01\n\x13\x63om.google.protobufB\x0e\x46ieldMaskProtoP\x01Z2google.golang.org/protobuf/types/known/fieldmaskpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_FIELDMASK = _descriptor.Descriptor(
+  name='FieldMask',
+  full_name='google.protobuf.FieldMask',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='paths', full_name='google.protobuf.FieldMask.paths', index=0,
+      number=1, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=53,
+  serialized_end=79,
+)
+
+DESCRIPTOR.message_types_by_name['FieldMask'] = _FIELDMASK
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+FieldMask = _reflection.GeneratedProtocolMessageType('FieldMask', (_message.Message,), {
+  'DESCRIPTOR' : _FIELDMASK,
+  '__module__' : 'google.protobuf.field_mask_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FieldMask)
+  })
+_sym_db.RegisterMessage(FieldMask)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/internal/__init__.py b/python/google/protobuf/internal/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/google/protobuf/internal/__init__.py
diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py
new file mode 100755
index 0000000..afdbb78
--- /dev/null
+++ b/python/google/protobuf/internal/_parameterized.py
@@ -0,0 +1,443 @@
+#! /usr/bin/env python
+#
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Adds support for parameterized tests to Python's unittest TestCase class.
+
+A parameterized test is a method in a test case that is invoked with different
+argument tuples.
+
+A simple example:
+
+  class AdditionExample(parameterized.TestCase):
+    @parameterized.parameters(
+       (1, 2, 3),
+       (4, 5, 9),
+       (1, 1, 3))
+    def testAddition(self, op1, op2, result):
+      self.assertEqual(result, op1 + op2)
+
+
+Each invocation is a separate test case and properly isolated just
+like a normal test method, with its own setUp/tearDown cycle. In the
+example above, there are three separate testcases, one of which will
+fail due to an assertion error (1 + 1 != 3).
+
+Parameters for individual test cases can be tuples (with positional parameters)
+or dictionaries (with named parameters):
+
+  class AdditionExample(parameterized.TestCase):
+    @parameterized.parameters(
+       {'op1': 1, 'op2': 2, 'result': 3},
+       {'op1': 4, 'op2': 5, 'result': 9},
+    )
+    def testAddition(self, op1, op2, result):
+      self.assertEqual(result, op1 + op2)
+
+If a parameterized test fails, the error message will show the
+original test name (which is modified internally) and the arguments
+for the specific invocation, which are part of the string returned by
+the shortDescription() method on test cases.
+
+The id method of the test, used internally by the unittest framework,
+is also modified to show the arguments. To make sure that test names
+stay the same across several invocations, object representations like
+
+  >>> class Foo(object):
+  ...  pass
+  >>> repr(Foo())
+  '<__main__.Foo object at 0x23d8610>'
+
+are turned into '<__main__.Foo>'. For even more descriptive names,
+especially in test logs, you can use the named_parameters decorator. In
+this case, only tuples are supported, and the first parameters has to
+be a string (or an object that returns an apt name when converted via
+str()):
+
+  class NamedExample(parameterized.TestCase):
+    @parameterized.named_parameters(
+       ('Normal', 'aa', 'aaa', True),
+       ('EmptyPrefix', '', 'abc', True),
+       ('BothEmpty', '', '', True))
+    def testStartsWith(self, prefix, string, result):
+      self.assertEqual(result, strings.startswith(prefix))
+
+Named tests also have the benefit that they can be run individually
+from the command line:
+
+  $ testmodule.py NamedExample.testStartsWithNormal
+  .
+  --------------------------------------------------------------------
+  Ran 1 test in 0.000s
+
+  OK
+
+Parameterized Classes
+=====================
+If invocation arguments are shared across test methods in a single
+TestCase class, instead of decorating all test methods
+individually, the class itself can be decorated:
+
+  @parameterized.parameters(
+    (1, 2, 3)
+    (4, 5, 9))
+  class ArithmeticTest(parameterized.TestCase):
+    def testAdd(self, arg1, arg2, result):
+      self.assertEqual(arg1 + arg2, result)
+
+    def testSubtract(self, arg2, arg2, result):
+      self.assertEqual(result - arg1, arg2)
+
+Inputs from Iterables
+=====================
+If parameters should be shared across several test cases, or are dynamically
+created from other sources, a single non-tuple iterable can be passed into
+the decorator. This iterable will be used to obtain the test cases:
+
+  class AdditionExample(parameterized.TestCase):
+    @parameterized.parameters(
+      c.op1, c.op2, c.result for c in testcases
+    )
+    def testAddition(self, op1, op2, result):
+      self.assertEqual(result, op1 + op2)
+
+
+Single-Argument Test Methods
+============================
+If a test method takes only one argument, the single argument does not need to
+be wrapped into a tuple:
+
+  class NegativeNumberExample(parameterized.TestCase):
+    @parameterized.parameters(
+       -1, -3, -4, -5
+    )
+    def testIsNegative(self, arg):
+      self.assertTrue(IsNegative(arg))
+"""
+
+__author__ = 'tmarek@google.com (Torsten Marek)'
+
+import functools
+import re
+import types
+import unittest
+import uuid
+
+try:
+  # Since python 3
+  import collections.abc as collections_abc
+except ImportError:
+  # Won't work after python 3.8
+  import collections as collections_abc
+
+ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>')
+_SEPARATOR = uuid.uuid1().hex
+_FIRST_ARG = object()
+_ARGUMENT_REPR = object()
+
+
+def _CleanRepr(obj):
+  return ADDR_RE.sub(r'<\1>', repr(obj))
+
+
+# Helper function formerly from the unittest module, removed from it in
+# Python 2.7.
+def _StrClass(cls):
+  return '%s.%s' % (cls.__module__, cls.__name__)
+
+
+def _NonStringIterable(obj):
+  return (isinstance(obj, collections_abc.Iterable) and
+          not isinstance(obj, str))
+
+
+def _FormatParameterList(testcase_params):
+  if isinstance(testcase_params, collections_abc.Mapping):
+    return ', '.join('%s=%s' % (argname, _CleanRepr(value))
+                     for argname, value in testcase_params.items())
+  elif _NonStringIterable(testcase_params):
+    return ', '.join(map(_CleanRepr, testcase_params))
+  else:
+    return _FormatParameterList((testcase_params,))
+
+
+class _ParameterizedTestIter(object):
+  """Callable and iterable class for producing new test cases."""
+
+  def __init__(self, test_method, testcases, naming_type):
+    """Returns concrete test functions for a test and a list of parameters.
+
+    The naming_type is used to determine the name of the concrete
+    functions as reported by the unittest framework. If naming_type is
+    _FIRST_ARG, the testcases must be tuples, and the first element must
+    have a string representation that is a valid Python identifier.
+
+    Args:
+      test_method: The decorated test method.
+      testcases: (list of tuple/dict) A list of parameter
+                 tuples/dicts for individual test invocations.
+      naming_type: The test naming type, either _NAMED or _ARGUMENT_REPR.
+    """
+    self._test_method = test_method
+    self.testcases = testcases
+    self._naming_type = naming_type
+
+  def __call__(self, *args, **kwargs):
+    raise RuntimeError('You appear to be running a parameterized test case '
+                       'without having inherited from parameterized.'
+                       'TestCase. This is bad because none of '
+                       'your test cases are actually being run.')
+
+  def __iter__(self):
+    test_method = self._test_method
+    naming_type = self._naming_type
+
+    def MakeBoundParamTest(testcase_params):
+      @functools.wraps(test_method)
+      def BoundParamTest(self):
+        if isinstance(testcase_params, collections_abc.Mapping):
+          test_method(self, **testcase_params)
+        elif _NonStringIterable(testcase_params):
+          test_method(self, *testcase_params)
+        else:
+          test_method(self, testcase_params)
+
+      if naming_type is _FIRST_ARG:
+        # Signal the metaclass that the name of the test function is unique
+        # and descriptive.
+        BoundParamTest.__x_use_name__ = True
+        BoundParamTest.__name__ += str(testcase_params[0])
+        testcase_params = testcase_params[1:]
+      elif naming_type is _ARGUMENT_REPR:
+        # __x_extra_id__ is used to pass naming information to the __new__
+        # method of TestGeneratorMetaclass.
+        # The metaclass will make sure to create a unique, but nondescriptive
+        # name for this test.
+        BoundParamTest.__x_extra_id__ = '(%s)' % (
+            _FormatParameterList(testcase_params),)
+      else:
+        raise RuntimeError('%s is not a valid naming type.' % (naming_type,))
+
+      BoundParamTest.__doc__ = '%s(%s)' % (
+          BoundParamTest.__name__, _FormatParameterList(testcase_params))
+      if test_method.__doc__:
+        BoundParamTest.__doc__ += '\n%s' % (test_method.__doc__,)
+      return BoundParamTest
+    return (MakeBoundParamTest(c) for c in self.testcases)
+
+
+def _IsSingletonList(testcases):
+  """True iff testcases contains only a single non-tuple element."""
+  return len(testcases) == 1 and not isinstance(testcases[0], tuple)
+
+
+def _ModifyClass(class_object, testcases, naming_type):
+  assert not getattr(class_object, '_id_suffix', None), (
+      'Cannot add parameters to %s,'
+      ' which already has parameterized methods.' % (class_object,))
+  class_object._id_suffix = id_suffix = {}
+  # We change the size of __dict__ while we iterate over it,
+  # which Python 3.x will complain about, so use copy().
+  for name, obj in class_object.__dict__.copy().items():
+    if (name.startswith(unittest.TestLoader.testMethodPrefix)
+        and isinstance(obj, types.FunctionType)):
+      delattr(class_object, name)
+      methods = {}
+      _UpdateClassDictForParamTestCase(
+          methods, id_suffix, name,
+          _ParameterizedTestIter(obj, testcases, naming_type))
+      for name, meth in methods.items():
+        setattr(class_object, name, meth)
+
+
+def _ParameterDecorator(naming_type, testcases):
+  """Implementation of the parameterization decorators.
+
+  Args:
+    naming_type: The naming type.
+    testcases: Testcase parameters.
+
+  Returns:
+    A function for modifying the decorated object.
+  """
+  def _Apply(obj):
+    if isinstance(obj, type):
+      _ModifyClass(
+          obj,
+          list(testcases) if not isinstance(testcases, collections_abc.Sequence)
+          else testcases,
+          naming_type)
+      return obj
+    else:
+      return _ParameterizedTestIter(obj, testcases, naming_type)
+
+  if _IsSingletonList(testcases):
+    assert _NonStringIterable(testcases[0]), (
+        'Single parameter argument must be a non-string iterable')
+    testcases = testcases[0]
+
+  return _Apply
+
+
+def parameters(*testcases):  # pylint: disable=invalid-name
+  """A decorator for creating parameterized tests.
+
+  See the module docstring for a usage example.
+  Args:
+    *testcases: Parameters for the decorated method, either a single
+                iterable, or a list of tuples/dicts/objects (for tests
+                with only one argument).
+
+  Returns:
+     A test generator to be handled by TestGeneratorMetaclass.
+  """
+  return _ParameterDecorator(_ARGUMENT_REPR, testcases)
+
+
+def named_parameters(*testcases):  # pylint: disable=invalid-name
+  """A decorator for creating parameterized tests.
+
+  See the module docstring for a usage example. The first element of
+  each parameter tuple should be a string and will be appended to the
+  name of the test method.
+
+  Args:
+    *testcases: Parameters for the decorated method, either a single
+                iterable, or a list of tuples.
+
+  Returns:
+     A test generator to be handled by TestGeneratorMetaclass.
+  """
+  return _ParameterDecorator(_FIRST_ARG, testcases)
+
+
+class TestGeneratorMetaclass(type):
+  """Metaclass for test cases with test generators.
+
+  A test generator is an iterable in a testcase that produces callables. These
+  callables must be single-argument methods. These methods are injected into
+  the class namespace and the original iterable is removed. If the name of the
+  iterable conforms to the test pattern, the injected methods will be picked
+  up as tests by the unittest framework.
+
+  In general, it is supposed to be used in conjunction with the
+  parameters decorator.
+  """
+
+  def __new__(mcs, class_name, bases, dct):
+    dct['_id_suffix'] = id_suffix = {}
+    for name, obj in dct.copy().items():
+      if (name.startswith(unittest.TestLoader.testMethodPrefix) and
+          _NonStringIterable(obj)):
+        iterator = iter(obj)
+        dct.pop(name)
+        _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator)
+
+    return type.__new__(mcs, class_name, bases, dct)
+
+
+def _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator):
+  """Adds individual test cases to a dictionary.
+
+  Args:
+    dct: The target dictionary.
+    id_suffix: The dictionary for mapping names to test IDs.
+    name: The original name of the test case.
+    iterator: The iterator generating the individual test cases.
+  """
+  for idx, func in enumerate(iterator):
+    assert callable(func), 'Test generators must yield callables, got %r' % (
+        func,)
+    if getattr(func, '__x_use_name__', False):
+      new_name = func.__name__
+    else:
+      new_name = '%s%s%d' % (name, _SEPARATOR, idx)
+    assert new_name not in dct, (
+        'Name of parameterized test case "%s" not unique' % (new_name,))
+    dct[new_name] = func
+    id_suffix[new_name] = getattr(func, '__x_extra_id__', '')
+
+
+class TestCase(unittest.TestCase, metaclass=TestGeneratorMetaclass):
+  """Base class for test cases using the parameters decorator."""
+
+  def _OriginalName(self):
+    return self._testMethodName.split(_SEPARATOR)[0]
+
+  def __str__(self):
+    return '%s (%s)' % (self._OriginalName(), _StrClass(self.__class__))
+
+  def id(self):  # pylint: disable=invalid-name
+    """Returns the descriptive ID of the test.
+
+    This is used internally by the unittesting framework to get a name
+    for the test to be used in reports.
+
+    Returns:
+      The test id.
+    """
+    return '%s.%s%s' % (_StrClass(self.__class__),
+                        self._OriginalName(),
+                        self._id_suffix.get(self._testMethodName, ''))
+
+
+def CoopTestCase(other_base_class):
+  """Returns a new base class with a cooperative metaclass base.
+
+  This enables the TestCase to be used in combination
+  with other base classes that have custom metaclasses, such as
+  mox.MoxTestBase.
+
+  Only works with metaclasses that do not override type.__new__.
+
+  Example:
+
+    import google3
+    import mox
+
+    from google3.testing.pybase import parameterized
+
+    class ExampleTest(parameterized.CoopTestCase(mox.MoxTestBase)):
+      ...
+
+  Args:
+    other_base_class: (class) A test case base class.
+
+  Returns:
+    A new class object.
+  """
+  metaclass = type(
+      'CoopMetaclass',
+      (other_base_class.__metaclass__,
+       TestGeneratorMetaclass), {})
+  return metaclass(
+      'CoopTestCase',
+      (other_base_class, TestCase), {})
diff --git a/python/google/protobuf/internal/any_test.proto b/python/google/protobuf/internal/any_test.proto
new file mode 100644
index 0000000..1a563fd
--- /dev/null
+++ b/python/google/protobuf/internal/any_test.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: jieluo@google.com (Jie Luo)
+
+syntax = "proto2";
+
+package google.protobuf.internal;
+
+import "google/protobuf/any.proto";
+
+message TestAny {
+  optional google.protobuf.Any value = 1;
+  optional int32 int_value = 2;
+  map<string,int32> map_value = 3;
+  extensions 10 to max;
+}
+
+message TestAnyExtension1 {
+  extend TestAny {
+    optional TestAnyExtension1 extension1 = 98418603;
+  }
+  optional int32 i = 15;
+}
diff --git a/python/google/protobuf/internal/api_implementation.cc b/python/google/protobuf/internal/api_implementation.cc
new file mode 100644
index 0000000..33f5b04
--- /dev/null
+++ b/python/google/protobuf/internal/api_implementation.cc
@@ -0,0 +1,111 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Version constant.
+// This is either 0 for python, 1 for CPP V1, 2 for CPP V2.
+//
+// 0 is default and is equivalent to
+//   PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
+//
+// 1 is set with -DPYTHON_PROTO2_CPP_IMPL_V1 and is equivalent to
+//   PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+// and
+//   PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=1
+//
+// 2 is set with -DPYTHON_PROTO2_CPP_IMPL_V2 and is equivalent to
+//   PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+// and
+//   PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
+#ifdef PYTHON_PROTO2_CPP_IMPL_V1
+#error "PYTHON_PROTO2_CPP_IMPL_V1 is no longer supported."
+#else
+#ifdef PYTHON_PROTO2_CPP_IMPL_V2
+static int kImplVersion = 2;
+#else
+#ifdef PYTHON_PROTO2_PYTHON_IMPL
+static int kImplVersion = 0;
+#else
+
+static int kImplVersion = -1;  // -1 means "Unspecified by compiler flags".
+
+#endif  // PYTHON_PROTO2_PYTHON_IMPL
+#endif  // PYTHON_PROTO2_CPP_IMPL_V2
+#endif  // PYTHON_PROTO2_CPP_IMPL_V1
+
+static const char* kImplVersionName = "api_version";
+
+static const char* kModuleName = "_api_implementation";
+static const char kModuleDocstring[] =
+    "_api_implementation is a module that exposes compile-time constants that\n"
+    "determine the default API implementation to use for Python proto2.\n"
+    "\n"
+    "It complements api_implementation.py by setting defaults using "
+    "compile-time\n"
+    "constants defined in C, such that one can set defaults at compilation\n"
+    "(e.g. with blaze flag --copt=-DPYTHON_PROTO2_CPP_IMPL_V2).";
+
+static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
+                                     kModuleName,
+                                     kModuleDocstring,
+                                     -1,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr};
+
+extern "C" {
+PyMODINIT_FUNC PyInit__api_implementation() {
+  PyObject* module = PyModule_Create(&_module);
+  if (module == nullptr) {
+    return nullptr;
+  }
+
+  // Adds the module variable "api_version".
+  if (PyModule_AddIntConstant(module, const_cast<char*>(kImplVersionName),
+                              kImplVersion)) {
+    Py_DECREF(module);
+    return nullptr;
+  }
+
+  return module;
+}
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/internal/api_implementation.py b/python/google/protobuf/internal/api_implementation.py
new file mode 100644
index 0000000..7458648
--- /dev/null
+++ b/python/google/protobuf/internal/api_implementation.py
@@ -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.
+
+"""Determine which implementation of the protobuf API is used in this process.
+"""
+
+import importlib
+import os
+import sys
+import warnings
+
+
+def _ApiVersionToImplementationType(api_version):
+  if api_version == 2:
+    return 'cpp'
+  if api_version == 1:
+    raise ValueError('api_version=1 is no longer supported.')
+  if api_version == 0:
+    return 'python'
+  return None
+
+
+_implementation_type = None
+try:
+  # pylint: disable=g-import-not-at-top
+  from google.protobuf.internal import _api_implementation
+  # The compile-time constants in the _api_implementation module can be used to
+  # switch to a certain implementation of the Python API at build time.
+  _implementation_type = _ApiVersionToImplementationType(
+      _api_implementation.api_version)
+except ImportError:
+  pass  # Unspecified by compiler flags.
+
+
+def _CanImport(mod_name):
+  try:
+    mod = importlib.import_module(mod_name)
+    # Work around a known issue in the classic bootstrap .par import hook.
+    if not mod:
+      raise ImportError(mod_name + ' import succeeded but was None')
+    return True
+  except ImportError:
+    return False
+
+
+if _implementation_type is None:
+  if _CanImport('google._upb._message'):
+    _implementation_type = 'upb'
+  elif _CanImport('google.protobuf.pyext._message'):
+    _implementation_type = 'cpp'
+  else:
+    _implementation_type = 'python'
+
+
+# This environment variable can be used to switch to a certain implementation
+# of the Python API, overriding the compile-time constants in the
+# _api_implementation module. Right now only 'python', 'cpp' and 'upb' are
+# valid values. Any other value will raise error.
+_implementation_type = os.getenv('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION',
+                                 _implementation_type)
+
+if _implementation_type not in ('python', 'cpp', 'upb'):
+  raise ValueError('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION {0} is not '
+                   'supported. Please set to \'python\', \'cpp\' or '
+                   '\'upb\'.'.format(_implementation_type))
+
+if 'PyPy' in sys.version and _implementation_type == 'cpp':
+  warnings.warn('PyPy does not work yet with cpp protocol buffers. '
+                'Falling back to the python implementation.')
+  _implementation_type = 'python'
+
+_c_module = None
+
+if _implementation_type == 'cpp':
+  try:
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    _c_module = _message
+    del _message
+  except ImportError:
+    # TODO(jieluo): fail back to python
+    warnings.warn(
+        'Selected implementation cpp is not available.')
+    pass
+
+if _implementation_type == 'upb':
+  try:
+    # pylint: disable=g-import-not-at-top
+    from google._upb import _message
+    _c_module = _message
+    del _message
+  except ImportError:
+    warnings.warn('Selected implementation upb is not available. '
+                  'Falling back to the python implementation.')
+    _implementation_type = 'python'
+    pass
+
+# Detect if serialization should be deterministic by default
+try:
+  # The presence of this module in a build allows the proto implementation to
+  # be upgraded merely via build deps.
+  #
+  # NOTE: Merely importing this automatically enables deterministic proto
+  # serialization for C++ code, but we still need to export it as a boolean so
+  # that we can do the same for `_implementation_type == 'python'`.
+  #
+  # NOTE2: It is possible for C++ code to enable deterministic serialization by
+  # default _without_ affecting Python code, if the C++ implementation is not in
+  # use by this module.  That is intended behavior, so we don't actually expose
+  # this boolean outside of this module.
+  #
+  # pylint: disable=g-import-not-at-top,unused-import
+  from google.protobuf import enable_deterministic_proto_serialization
+  _python_deterministic_proto_serialization = True
+except ImportError:
+  _python_deterministic_proto_serialization = False
+
+
+# Usage of this function is discouraged. Clients shouldn't care which
+# implementation of the API is in use. Note that there is no guarantee
+# that differences between APIs will be maintained.
+# Please don't use this function if possible.
+def Type():
+  return _implementation_type
+
+
+def _SetType(implementation_type):
+  """Never use! Only for protobuf benchmark."""
+  global _implementation_type
+  _implementation_type = implementation_type
+
+
+# See comment on 'Type' above.
+# TODO(jieluo): Remove the API, it returns a constant. b/228102101
+def Version():
+  return 2
+
+
+# For internal use only
+def IsPythonDefaultSerializationDeterministic():
+  return _python_deterministic_proto_serialization
diff --git a/python/google/protobuf/internal/builder.py b/python/google/protobuf/internal/builder.py
new file mode 100644
index 0000000..64353ee
--- /dev/null
+++ b/python/google/protobuf/internal/builder.py
@@ -0,0 +1,130 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Builds descriptors, message classes and services for generated _pb2.py.
+
+This file is only called in python generated _pb2.py files. It builds
+descriptors, message classes and services that users can directly use
+in generated code.
+"""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+
+_sym_db = _symbol_database.Default()
+
+
+def BuildMessageAndEnumDescriptors(file_des, module):
+  """Builds message and enum descriptors.
+
+  Args:
+    file_des: FileDescriptor of the .proto file
+    module: Generated _pb2 module
+  """
+
+  def BuildNestedDescriptors(msg_des, prefix):
+    for (name, nested_msg) in msg_des.nested_types_by_name.items():
+      module_name = prefix + name.upper()
+      module[module_name] = nested_msg
+      BuildNestedDescriptors(nested_msg, module_name + '_')
+    for enum_des in msg_des.enum_types:
+      module[prefix + enum_des.name.upper()] = enum_des
+
+  for (name, msg_des) in file_des.message_types_by_name.items():
+    module_name = '_' + name.upper()
+    module[module_name] = msg_des
+    BuildNestedDescriptors(msg_des, module_name + '_')
+
+
+def BuildTopDescriptorsAndMessages(file_des, module_name, module):
+  """Builds top level descriptors and message classes.
+
+  Args:
+    file_des: FileDescriptor of the .proto file
+    module_name: str, the name of generated _pb2 module
+    module: Generated _pb2 module
+  """
+
+  def BuildMessage(msg_des):
+    create_dict = {}
+    for (name, nested_msg) in msg_des.nested_types_by_name.items():
+      create_dict[name] = BuildMessage(nested_msg)
+    create_dict['DESCRIPTOR'] = msg_des
+    create_dict['__module__'] = module_name
+    message_class = _reflection.GeneratedProtocolMessageType(
+        msg_des.name, (_message.Message,), create_dict)
+    _sym_db.RegisterMessage(message_class)
+    return message_class
+
+  # top level enums
+  for (name, enum_des) in file_des.enum_types_by_name.items():
+    module['_' + name.upper()] = enum_des
+    module[name] = enum_type_wrapper.EnumTypeWrapper(enum_des)
+    for enum_value in enum_des.values:
+      module[enum_value.name] = enum_value.number
+
+  # top level extensions
+  for (name, extension_des) in file_des.extensions_by_name.items():
+    module[name.upper() + '_FIELD_NUMBER'] = extension_des.number
+    module[name] = extension_des
+
+  # services
+  for (name, service) in file_des.services_by_name.items():
+    module['_' + name.upper()] = service
+
+  # Build messages.
+  for (name, msg_des) in file_des.message_types_by_name.items():
+    module[name] = BuildMessage(msg_des)
+
+
+def BuildServices(file_des, module_name, module):
+  """Builds services classes and services stub class.
+
+  Args:
+    file_des: FileDescriptor of the .proto file
+    module_name: str, the name of generated _pb2 module
+    module: Generated _pb2 module
+  """
+  # pylint: disable=g-import-not-at-top
+  from google.protobuf import service as _service
+  from google.protobuf import service_reflection
+  # pylint: enable=g-import-not-at-top
+  for (name, service) in file_des.services_by_name.items():
+    module[name] = service_reflection.GeneratedServiceType(
+        name, (_service.Service,),
+        dict(DESCRIPTOR=service, __module__=module_name))
+    stub_name = name + '_Stub'
+    module[stub_name] = service_reflection.GeneratedServiceStubType(
+        stub_name, (module[name],),
+        dict(DESCRIPTOR=service, __module__=module_name))
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
new file mode 100644
index 0000000..29fbb53
--- /dev/null
+++ b/python/google/protobuf/internal/containers.py
@@ -0,0 +1,710 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 container classes to represent different protocol buffer types.
+
+This file defines container classes which represent categories of protocol
+buffer field types which need extra maintenance. Currently these categories
+are:
+
+-   Repeated scalar fields - These are all repeated fields which aren't
+    composite (e.g. they are of simple types like int32, string, etc).
+-   Repeated composite fields - Repeated fields which are composite. This
+    includes groups and nested messages.
+"""
+
+import collections.abc
+import copy
+import pickle
+from typing import (
+    Any,
+    Iterable,
+    Iterator,
+    List,
+    MutableMapping,
+    MutableSequence,
+    NoReturn,
+    Optional,
+    Sequence,
+    TypeVar,
+    Union,
+    overload,
+)
+
+
+_T = TypeVar('_T')
+_K = TypeVar('_K')
+_V = TypeVar('_V')
+
+
+class BaseContainer(Sequence[_T]):
+  """Base container class."""
+
+  # Minimizes memory usage and disallows assignment to other attributes.
+  __slots__ = ['_message_listener', '_values']
+
+  def __init__(self, message_listener: Any) -> None:
+    """
+    Args:
+      message_listener: A MessageListener implementation.
+        The RepeatedScalarFieldContainer will call this object's
+        Modified() method when it is modified.
+    """
+    self._message_listener = message_listener
+    self._values = []
+
+  @overload
+  def __getitem__(self, key: int) -> _T:
+    ...
+
+  @overload
+  def __getitem__(self, key: slice) -> List[_T]:
+    ...
+
+  def __getitem__(self, key):
+    """Retrieves item by the specified key."""
+    return self._values[key]
+
+  def __len__(self) -> int:
+    """Returns the number of elements in the container."""
+    return len(self._values)
+
+  def __ne__(self, other: Any) -> bool:
+    """Checks if another instance isn't equal to this one."""
+    # The concrete classes should define __eq__.
+    return not self == other
+
+  __hash__ = None
+
+  def __repr__(self) -> str:
+    return repr(self._values)
+
+  def sort(self, *args, **kwargs) -> None:
+    # Continue to support the old sort_function keyword argument.
+    # This is expected to be a rare occurrence, so use LBYL to avoid
+    # the overhead of actually catching KeyError.
+    if 'sort_function' in kwargs:
+      kwargs['cmp'] = kwargs.pop('sort_function')
+    self._values.sort(*args, **kwargs)
+
+  def reverse(self) -> None:
+    self._values.reverse()
+
+
+# TODO(slebedev): Remove this. BaseContainer does *not* conform to
+# MutableSequence, only its subclasses do.
+collections.abc.MutableSequence.register(BaseContainer)
+
+
+class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]):
+  """Simple, type-checked, list-like container for holding repeated scalars."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_type_checker']
+
+  def __init__(
+      self,
+      message_listener: Any,
+      type_checker: Any,
+  ) -> None:
+    """Args:
+
+      message_listener: A MessageListener implementation. The
+      RepeatedScalarFieldContainer will call this object's Modified() method
+      when it is modified.
+      type_checker: A type_checkers.ValueChecker instance to run on elements
+      inserted into this container.
+    """
+    super().__init__(message_listener)
+    self._type_checker = type_checker
+
+  def append(self, value: _T) -> None:
+    """Appends an item to the list. Similar to list.append()."""
+    self._values.append(self._type_checker.CheckValue(value))
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+
+  def insert(self, key: int, value: _T) -> None:
+    """Inserts the item at the specified position. Similar to list.insert()."""
+    self._values.insert(key, self._type_checker.CheckValue(value))
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+
+  def extend(self, elem_seq: Iterable[_T]) -> None:
+    """Extends by appending the given iterable. Similar to list.extend()."""
+    if elem_seq is None:
+      return
+    try:
+      elem_seq_iter = iter(elem_seq)
+    except TypeError:
+      if not elem_seq:
+        # silently ignore falsy inputs :-/.
+        # TODO(ptucker): Deprecate this behavior. b/18413862
+        return
+      raise
+
+    new_values = [self._type_checker.CheckValue(elem) for elem in elem_seq_iter]
+    if new_values:
+      self._values.extend(new_values)
+    self._message_listener.Modified()
+
+  def MergeFrom(
+      self,
+      other: Union['RepeatedScalarFieldContainer[_T]', Iterable[_T]],
+  ) -> None:
+    """Appends the contents of another repeated field of the same type to this
+    one. We do not check the types of the individual fields.
+    """
+    self._values.extend(other)
+    self._message_listener.Modified()
+
+  def remove(self, elem: _T):
+    """Removes an item from the list. Similar to list.remove()."""
+    self._values.remove(elem)
+    self._message_listener.Modified()
+
+  def pop(self, key: Optional[int] = -1) -> _T:
+    """Removes and returns an item at a given index. Similar to list.pop()."""
+    value = self._values[key]
+    self.__delitem__(key)
+    return value
+
+  @overload
+  def __setitem__(self, key: int, value: _T) -> None:
+    ...
+
+  @overload
+  def __setitem__(self, key: slice, value: Iterable[_T]) -> None:
+    ...
+
+  def __setitem__(self, key, value) -> None:
+    """Sets the item on the specified position."""
+    if isinstance(key, slice):
+      if key.step is not None:
+        raise ValueError('Extended slices not supported')
+      self._values[key] = map(self._type_checker.CheckValue, value)
+      self._message_listener.Modified()
+    else:
+      self._values[key] = self._type_checker.CheckValue(value)
+      self._message_listener.Modified()
+
+  def __delitem__(self, key: Union[int, slice]) -> None:
+    """Deletes the item at the specified position."""
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __eq__(self, other: Any) -> bool:
+    """Compares the current instance with another one."""
+    if self is other:
+      return True
+    # Special case for the same type which should be common and fast.
+    if isinstance(other, self.__class__):
+      return other._values == self._values
+    # We are presumably comparing against some other sequence type.
+    return other == self._values
+
+  def __deepcopy__(
+      self,
+      unused_memo: Any = None,
+  ) -> 'RepeatedScalarFieldContainer[_T]':
+    clone = RepeatedScalarFieldContainer(
+        copy.deepcopy(self._message_listener), self._type_checker)
+    clone.MergeFrom(self)
+    return clone
+
+  def __reduce__(self, **kwargs) -> NoReturn:
+    raise pickle.PickleError(
+        "Can't pickle repeated scalar fields, convert to list first")
+
+
+# TODO(slebedev): Constrain T to be a subtype of Message.
+class RepeatedCompositeFieldContainer(BaseContainer[_T], MutableSequence[_T]):
+  """Simple, list-like container for holding repeated composite fields."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_message_descriptor']
+
+  def __init__(self, message_listener: Any, message_descriptor: Any) -> None:
+    """
+    Note that we pass in a descriptor instead of the generated directly,
+    since at the time we construct a _RepeatedCompositeFieldContainer we
+    haven't yet necessarily initialized the type that will be contained in the
+    container.
+
+    Args:
+      message_listener: A MessageListener implementation.
+        The RepeatedCompositeFieldContainer will call this object's
+        Modified() method when it is modified.
+      message_descriptor: A Descriptor instance describing the protocol type
+        that should be present in this container.  We'll use the
+        _concrete_class field of this descriptor when the client calls add().
+    """
+    super().__init__(message_listener)
+    self._message_descriptor = message_descriptor
+
+  def add(self, **kwargs: Any) -> _T:
+    """Adds a new element at the end of the list and returns it. Keyword
+    arguments may be used to initialize the element.
+    """
+    new_element = self._message_descriptor._concrete_class(**kwargs)
+    new_element._SetListener(self._message_listener)
+    self._values.append(new_element)
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+    return new_element
+
+  def append(self, value: _T) -> None:
+    """Appends one element by copying the message."""
+    new_element = self._message_descriptor._concrete_class()
+    new_element._SetListener(self._message_listener)
+    new_element.CopyFrom(value)
+    self._values.append(new_element)
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+
+  def insert(self, key: int, value: _T) -> None:
+    """Inserts the item at the specified position by copying."""
+    new_element = self._message_descriptor._concrete_class()
+    new_element._SetListener(self._message_listener)
+    new_element.CopyFrom(value)
+    self._values.insert(key, new_element)
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+
+  def extend(self, elem_seq: Iterable[_T]) -> None:
+    """Extends by appending the given sequence of elements of the same type
+
+    as this one, copying each individual message.
+    """
+    message_class = self._message_descriptor._concrete_class
+    listener = self._message_listener
+    values = self._values
+    for message in elem_seq:
+      new_element = message_class()
+      new_element._SetListener(listener)
+      new_element.MergeFrom(message)
+      values.append(new_element)
+    listener.Modified()
+
+  def MergeFrom(
+      self,
+      other: Union['RepeatedCompositeFieldContainer[_T]', Iterable[_T]],
+  ) -> None:
+    """Appends the contents of another repeated field of the same type to this
+    one, copying each individual message.
+    """
+    self.extend(other)
+
+  def remove(self, elem: _T) -> None:
+    """Removes an item from the list. Similar to list.remove()."""
+    self._values.remove(elem)
+    self._message_listener.Modified()
+
+  def pop(self, key: Optional[int] = -1) -> _T:
+    """Removes and returns an item at a given index. Similar to list.pop()."""
+    value = self._values[key]
+    self.__delitem__(key)
+    return value
+
+  @overload
+  def __setitem__(self, key: int, value: _T) -> None:
+    ...
+
+  @overload
+  def __setitem__(self, key: slice, value: Iterable[_T]) -> None:
+    ...
+
+  def __setitem__(self, key, value):
+    # This method is implemented to make RepeatedCompositeFieldContainer
+    # structurally compatible with typing.MutableSequence. It is
+    # otherwise unsupported and will always raise an error.
+    raise TypeError(
+        f'{self.__class__.__name__} object does not support item assignment')
+
+  def __delitem__(self, key: Union[int, slice]) -> None:
+    """Deletes the item at the specified position."""
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __eq__(self, other: Any) -> bool:
+    """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.')
+    return self._values == other._values
+
+
+class ScalarMap(MutableMapping[_K, _V]):
+  """Simple, type-checked, dict-like container for holding repeated scalars."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener',
+               '_entry_descriptor']
+
+  def __init__(
+      self,
+      message_listener: Any,
+      key_checker: Any,
+      value_checker: Any,
+      entry_descriptor: Any,
+  ) -> None:
+    """
+    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.
+      entry_descriptor: The MessageDescriptor of a map entry: key and value.
+    """
+    self._message_listener = message_listener
+    self._key_checker = key_checker
+    self._value_checker = value_checker
+    self._entry_descriptor = entry_descriptor
+    self._values = {}
+
+  def __getitem__(self, key: _K) -> _V:
+    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: _K) -> bool:
+    # 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
+
+  @overload
+  def get(self, key: _K) -> Optional[_V]:
+    ...
+
+  @overload
+  def get(self, key: _K, default: _T) -> Union[_V, _T]:
+    ...
+
+  # 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: _K, value: _V) -> _T:
+    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: _K) -> None:
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __len__(self) -> int:
+    return len(self._values)
+
+  def __iter__(self) -> Iterator[_K]:
+    return iter(self._values)
+
+  def __repr__(self) -> str:
+    return repr(self._values)
+
+  def MergeFrom(self, other: 'ScalarMap[_K, _V]') -> None:
+    self._values.update(other._values)
+    self._message_listener.Modified()
+
+  def InvalidateIterators(self) -> None:
+    # 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) -> None:
+    self._values.clear()
+    self._message_listener.Modified()
+
+  def GetEntryClass(self) -> Any:
+    return self._entry_descriptor._concrete_class
+
+
+class MessageMap(MutableMapping[_K, _V]):
+  """Simple, type-checked, dict-like container for with submessage values."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_key_checker', '_values', '_message_listener',
+               '_message_descriptor', '_entry_descriptor']
+
+  def __init__(
+      self,
+      message_listener: Any,
+      message_descriptor: Any,
+      key_checker: Any,
+      entry_descriptor: Any,
+  ) -> None:
+    """
+    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.
+      entry_descriptor: The MessageDescriptor of a map entry: key and value.
+    """
+    self._message_listener = message_listener
+    self._message_descriptor = message_descriptor
+    self._key_checker = key_checker
+    self._entry_descriptor = entry_descriptor
+    self._values = {}
+
+  def __getitem__(self, key: _K) -> _V:
+    key = self._key_checker.CheckValue(key)
+    try:
+      return self._values[key]
+    except KeyError:
+      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: _K) -> _V:
+    """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]
+
+  @overload
+  def get(self, key: _K) -> Optional[_V]:
+    ...
+
+  @overload
+  def get(self, key: _K, default: _T) -> Union[_V, _T]:
+    ...
+
+  # 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: _K) -> bool:
+    item = self._key_checker.CheckValue(item)
+    return item in self._values
+
+  def __setitem__(self, key: _K, value: _V) -> NoReturn:
+    raise ValueError('May not set values directly, call my_map[key].foo = 5')
+
+  def __delitem__(self, key: _K) -> None:
+    key = self._key_checker.CheckValue(key)
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __len__(self) -> int:
+    return len(self._values)
+
+  def __iter__(self) -> Iterator[_K]:
+    return iter(self._values)
+
+  def __repr__(self) -> str:
+    return repr(self._values)
+
+  def MergeFrom(self, other: 'MessageMap[_K, _V]') -> None:
+    # pylint: disable=protected-access
+    for key in other._values:
+      # According to documentation: "When parsing from the wire or when merging,
+      # if there are duplicate map keys the last key seen is used".
+      if key in self:
+        del self[key]
+      self[key].CopyFrom(other[key])
+    # self._message_listener.Modified() not required here, because
+    # mutations to submessages already propagate.
+
+  def InvalidateIterators(self) -> None:
+    # 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) -> None:
+    self._values.clear()
+    self._message_listener.Modified()
+
+  def GetEntryClass(self) -> Any:
+    return self._entry_descriptor._concrete_class
+
+
+class _UnknownField:
+  """A parsed unknown field."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_field_number', '_wire_type', '_data']
+
+  def __init__(self, field_number, wire_type, data):
+    self._field_number = field_number
+    self._wire_type = wire_type
+    self._data = data
+    return
+
+  def __lt__(self, other):
+    # pylint: disable=protected-access
+    return self._field_number < other._field_number
+
+  def __eq__(self, other):
+    if self is other:
+      return True
+    # pylint: disable=protected-access
+    return (self._field_number == other._field_number and
+            self._wire_type == other._wire_type and
+            self._data == other._data)
+
+
+class UnknownFieldRef:  # pylint: disable=missing-class-docstring
+
+  def __init__(self, parent, index):
+    self._parent = parent
+    self._index = index
+
+  def _check_valid(self):
+    if not self._parent:
+      raise ValueError('UnknownField does not exist. '
+                       'The parent message might be cleared.')
+    if self._index >= len(self._parent):
+      raise ValueError('UnknownField does not exist. '
+                       'The parent message might be cleared.')
+
+  @property
+  def field_number(self):
+    self._check_valid()
+    # pylint: disable=protected-access
+    return self._parent._internal_get(self._index)._field_number
+
+  @property
+  def wire_type(self):
+    self._check_valid()
+    # pylint: disable=protected-access
+    return self._parent._internal_get(self._index)._wire_type
+
+  @property
+  def data(self):
+    self._check_valid()
+    # pylint: disable=protected-access
+    return self._parent._internal_get(self._index)._data
+
+
+class UnknownFieldSet:
+  """UnknownField container"""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_values']
+
+  def __init__(self):
+    self._values = []
+
+  def __getitem__(self, index):
+    if self._values is None:
+      raise ValueError('UnknownFields does not exist. '
+                       'The parent message might be cleared.')
+    size = len(self._values)
+    if index < 0:
+      index += size
+    if index < 0 or index >= size:
+      raise IndexError('index %d out of range'.index)
+
+    return UnknownFieldRef(self, index)
+
+  def _internal_get(self, index):
+    return self._values[index]
+
+  def __len__(self):
+    if self._values is None:
+      raise ValueError('UnknownFields does not exist. '
+                       'The parent message might be cleared.')
+    return len(self._values)
+
+  def _add(self, field_number, wire_type, data):
+    unknown_field = _UnknownField(field_number, wire_type, data)
+    self._values.append(unknown_field)
+    return unknown_field
+
+  def __iter__(self):
+    for i in range(len(self)):
+      yield UnknownFieldRef(self, i)
+
+  def _extend(self, other):
+    if other is None:
+      return
+    # pylint: disable=protected-access
+    self._values.extend(other._values)
+
+  def __eq__(self, other):
+    if self is other:
+      return True
+    # Sort unknown fields because their order shouldn't
+    # affect equality test.
+    values = list(self._values)
+    if other is None:
+      return not values
+    values.sort()
+    # pylint: disable=protected-access
+    other_values = sorted(other._values)
+    return values == other_values
+
+  def _clear(self):
+    for value in self._values:
+      # pylint: disable=protected-access
+      if isinstance(value._data, UnknownFieldSet):
+        value._data._clear()  # pylint: disable=protected-access
+    self._values = None
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
new file mode 100644
index 0000000..a916276
--- /dev/null
+++ b/python/google/protobuf/internal/decoder.py
@@ -0,0 +1,1068 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Code for decoding protocol buffer primitives.
+
+This code is very similar to encoder.py -- read the docs for that module first.
+
+A "decoder" is a function with the signature:
+  Decode(buffer, pos, end, message, field_dict)
+The arguments are:
+  buffer:     The string containing the encoded message.
+  pos:        The current position in the string.
+  end:        The position in the string where the current message ends.  May be
+              less than len(buffer) if we're reading a sub-message.
+  message:    The message object into which we're parsing.
+  field_dict: message._fields (avoids a hashtable lookup).
+The decoder reads the field and stores it into field_dict, returning the new
+buffer position.  A decoder for a repeated field may proactively decode all of
+the elements of that field, if they appear consecutively.
+
+Note that decoders may throw any of the following:
+  IndexError:  Indicates a truncated message.
+  struct.error:  Unpacking of a fixed-width field failed.
+  message.DecodeError:  Other errors.
+
+Decoders are expected to raise an exception if they are called with pos > end.
+This allows callers to be lax about bounds checking:  it's fineto read past
+"end" as long as you are sure that someone else will notice and throw an
+exception later on.
+
+Something up the call stack is expected to catch IndexError and struct.error
+and convert them to message.DecodeError.
+
+Decoders are constructed using decoder constructors with the signature:
+  MakeDecoder(field_number, is_repeated, is_packed, key, new_default)
+The arguments are:
+  field_number:  The field number of the field we want to decode.
+  is_repeated:   Is the field a repeated field? (bool)
+  is_packed:     Is the field a packed field? (bool)
+  key:           The key to use when looking up the field within field_dict.
+                 (This is actually the FieldDescriptor but nothing in this
+                 file should depend on that.)
+  new_default:   A function which takes a message object as a parameter and
+                 returns a new instance of the default value for this field.
+                 (This is called for repeated fields and sub-messages, when an
+                 instance does not already exist.)
+
+As with encoders, we define a decoder constructor for every type of field.
+Then, for every field of every message class we construct an actual decoder.
+That decoder goes into a dict indexed by tag, so when we decode a message
+we repeatedly read a tag, look up the corresponding decoder, and invoke it.
+"""
+
+__author__ = 'kenton@google.com (Kenton Varda)'
+
+import math
+import struct
+
+from google.protobuf.internal import containers
+from google.protobuf.internal import encoder
+from google.protobuf.internal import wire_format
+from google.protobuf import message
+
+
+# This is not for optimization, but rather to avoid conflicts with local
+# variables named "message".
+_DecodeError = message.DecodeError
+
+
+def _VarintDecoder(mask, result_type):
+  """Return an encoder for a basic varint value (does not include tag).
+
+  Decoded values will be bitwise-anded with the given mask before being
+  returned, e.g. to limit them to 32 bits.  The returned decoder does not
+  take the usual "end" parameter -- the caller is expected to do bounds checking
+  after the fact (often the caller can defer such checking until later).  The
+  decoder returns a (value, new_pos) pair.
+  """
+
+  def DecodeVarint(buffer, pos):
+    result = 0
+    shift = 0
+    while 1:
+      b = buffer[pos]
+      result |= ((b & 0x7f) << shift)
+      pos += 1
+      if not (b & 0x80):
+        result &= mask
+        result = result_type(result)
+        return (result, pos)
+      shift += 7
+      if shift >= 64:
+        raise _DecodeError('Too many bytes when decoding varint.')
+  return DecodeVarint
+
+
+def _SignedVarintDecoder(bits, result_type):
+  """Like _VarintDecoder() but decodes signed values."""
+
+  signbit = 1 << (bits - 1)
+  mask = (1 << bits) - 1
+
+  def DecodeVarint(buffer, pos):
+    result = 0
+    shift = 0
+    while 1:
+      b = buffer[pos]
+      result |= ((b & 0x7f) << shift)
+      pos += 1
+      if not (b & 0x80):
+        result &= mask
+        result = (result ^ signbit) - signbit
+        result = result_type(result)
+        return (result, pos)
+      shift += 7
+      if shift >= 64:
+        raise _DecodeError('Too many bytes when decoding varint.')
+  return DecodeVarint
+
+# All 32-bit and 64-bit values are represented as int.
+_DecodeVarint = _VarintDecoder((1 << 64) - 1, int)
+_DecodeSignedVarint = _SignedVarintDecoder(64, int)
+
+# Use these versions for values which must be limited to 32 bits.
+_DecodeVarint32 = _VarintDecoder((1 << 32) - 1, int)
+_DecodeSignedVarint32 = _SignedVarintDecoder(32, int)
+
+
+def ReadTag(buffer, pos):
+  """Read a tag from the memoryview, and return a (tag_bytes, new_pos) tuple.
+
+  We return the raw bytes of the tag rather than decoding them.  The raw
+  bytes can then be used to look up the proper decoder.  This effectively allows
+  us to trade some work that would be done in pure-python (decoding a varint)
+  for work that is done in C (searching for a byte string in a hash table).
+  In a low-level language it would be much cheaper to decode the varint and
+  use that, but not in Python.
+
+  Args:
+    buffer: memoryview object of the encoded bytes
+    pos: int of the current position to start from
+
+  Returns:
+    Tuple[bytes, int] of the tag data and new position.
+  """
+  start = pos
+  while buffer[pos] & 0x80:
+    pos += 1
+  pos += 1
+
+  tag_bytes = buffer[start:pos].tobytes()
+  return tag_bytes, pos
+
+
+# --------------------------------------------------------------------
+
+
+def _SimpleDecoder(wire_type, decode_value):
+  """Return a constructor for a decoder for fields of a particular type.
+
+  Args:
+      wire_type:  The field's wire type.
+      decode_value:  A function which decodes an individual value, e.g.
+        _DecodeVarint()
+  """
+
+  def SpecificDecoder(field_number, is_repeated, is_packed, key, new_default,
+                      clear_if_default=False):
+    if is_packed:
+      local_DecodeVarint = _DecodeVarint
+      def DecodePackedField(buffer, pos, end, message, field_dict):
+        value = field_dict.get(key)
+        if value is None:
+          value = field_dict.setdefault(key, new_default(message))
+        (endpoint, pos) = local_DecodeVarint(buffer, pos)
+        endpoint += pos
+        if endpoint > end:
+          raise _DecodeError('Truncated message.')
+        while pos < endpoint:
+          (element, pos) = decode_value(buffer, pos)
+          value.append(element)
+        if pos > endpoint:
+          del value[-1]   # Discard corrupt value.
+          raise _DecodeError('Packed element was truncated.')
+        return pos
+      return DecodePackedField
+    elif is_repeated:
+      tag_bytes = encoder.TagBytes(field_number, wire_type)
+      tag_len = len(tag_bytes)
+      def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+        value = field_dict.get(key)
+        if value is None:
+          value = field_dict.setdefault(key, new_default(message))
+        while 1:
+          (element, new_pos) = decode_value(buffer, pos)
+          value.append(element)
+          # 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.
+            if new_pos > end:
+              raise _DecodeError('Truncated message.')
+            return new_pos
+      return DecodeRepeatedField
+    else:
+      def DecodeField(buffer, pos, end, message, field_dict):
+        (new_value, pos) = decode_value(buffer, pos)
+        if pos > end:
+          raise _DecodeError('Truncated message.')
+        if clear_if_default and not new_value:
+          field_dict.pop(key, None)
+        else:
+          field_dict[key] = new_value
+        return pos
+      return DecodeField
+
+  return SpecificDecoder
+
+
+def _ModifiedDecoder(wire_type, decode_value, modify_value):
+  """Like SimpleDecoder but additionally invokes modify_value on every value
+  before storing it.  Usually modify_value is ZigZagDecode.
+  """
+
+  # Reusing _SimpleDecoder is slightly slower than copying a bunch of code, but
+  # not enough to make a significant difference.
+
+  def InnerDecode(buffer, pos):
+    (result, new_pos) = decode_value(buffer, pos)
+    return (modify_value(result), new_pos)
+  return _SimpleDecoder(wire_type, InnerDecode)
+
+
+def _StructPackDecoder(wire_type, format):
+  """Return a constructor for a decoder for a fixed-width field.
+
+  Args:
+      wire_type:  The field's wire type.
+      format:  The format string to pass to struct.unpack().
+  """
+
+  value_size = struct.calcsize(format)
+  local_unpack = struct.unpack
+
+  # Reusing _SimpleDecoder is slightly slower than copying a bunch of code, but
+  # not enough to make a significant difference.
+
+  # Note that we expect someone up-stack to catch struct.error and convert
+  # it to _DecodeError -- this way we don't have to set up exception-
+  # handling blocks every time we parse one value.
+
+  def InnerDecode(buffer, pos):
+    new_pos = pos + value_size
+    result = local_unpack(format, buffer[pos:new_pos])[0]
+    return (result, new_pos)
+  return _SimpleDecoder(wire_type, InnerDecode)
+
+
+def _FloatDecoder():
+  """Returns a decoder for a float field.
+
+  This code works around a bug in struct.unpack for non-finite 32-bit
+  floating-point values.
+  """
+
+  local_unpack = struct.unpack
+
+  def InnerDecode(buffer, pos):
+    """Decode serialized float to a float and new position.
+
+    Args:
+      buffer: memoryview of the serialized bytes
+      pos: int, position in the memory view to start at.
+
+    Returns:
+      Tuple[float, int] of the deserialized float value and new position
+      in the serialized data.
+    """
+    # We expect a 32-bit value in little-endian byte order.  Bit 1 is the sign
+    # bit, bits 2-9 represent the exponent, and bits 10-32 are the significand.
+    new_pos = pos + 4
+    float_bytes = buffer[pos:new_pos].tobytes()
+
+    # 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' and float_bytes[2:3] >= b'\x80'):
+      # If at least one significand bit is set...
+      if float_bytes[0:3] != b'\x00\x00\x80':
+        return (math.nan, new_pos)
+      # If sign bit is set...
+      if float_bytes[3:4] == b'\xFF':
+        return (-math.inf, new_pos)
+      return (math.inf, new_pos)
+
+    # Note that we expect someone up-stack to catch struct.error and convert
+    # it to _DecodeError -- this way we don't have to set up exception-
+    # handling blocks every time we parse one value.
+    result = local_unpack('<f', float_bytes)[0]
+    return (result, new_pos)
+  return _SimpleDecoder(wire_format.WIRETYPE_FIXED32, InnerDecode)
+
+
+def _DoubleDecoder():
+  """Returns a decoder for a double field.
+
+  This code works around a bug in struct.unpack for not-a-number.
+  """
+
+  local_unpack = struct.unpack
+
+  def InnerDecode(buffer, pos):
+    """Decode serialized double to a double and new position.
+
+    Args:
+      buffer: memoryview of the serialized bytes.
+      pos: int, position in the memory view to start at.
+
+    Returns:
+      Tuple[float, int] of the decoded double value and new position
+      in the serialized data.
+    """
+    # We expect a 64-bit value in little-endian byte order.  Bit 1 is the sign
+    # bit, bits 2-12 represent the exponent, and bits 13-64 are the significand.
+    new_pos = pos + 8
+    double_bytes = buffer[pos:new_pos].tobytes()
+
+    # 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.
+    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 (math.nan, new_pos)
+
+    # Note that we expect someone up-stack to catch struct.error and convert
+    # it to _DecodeError -- this way we don't have to set up exception-
+    # handling blocks every time we parse one value.
+    result = local_unpack('<d', double_bytes)[0]
+    return (result, new_pos)
+  return _SimpleDecoder(wire_format.WIRETYPE_FIXED64, InnerDecode)
+
+
+def EnumDecoder(field_number, is_repeated, is_packed, key, new_default,
+                clear_if_default=False):
+  """Returns a decoder for enum field."""
+  enum_type = key.enum_type
+  if is_packed:
+    local_DecodeVarint = _DecodeVarint
+    def DecodePackedField(buffer, pos, end, message, field_dict):
+      """Decode serialized packed enum to its value and a new position.
+
+      Args:
+        buffer: memoryview of the serialized bytes.
+        pos: int, position in the memory view to start at.
+        end: int, end position of serialized data
+        message: Message object to store unknown fields in
+        field_dict: Map[Descriptor, Any] to store decoded values in.
+
+      Returns:
+        int, new position in serialized data.
+      """
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      (endpoint, pos) = local_DecodeVarint(buffer, pos)
+      endpoint += pos
+      if endpoint > end:
+        raise _DecodeError('Truncated message.')
+      while pos < endpoint:
+        value_start_pos = pos
+        (element, pos) = _DecodeSignedVarint32(buffer, pos)
+        # pylint: disable=protected-access
+        if element in enum_type.values_by_number:
+          value.append(element)
+        else:
+          if not message._unknown_fields:
+            message._unknown_fields = []
+          tag_bytes = encoder.TagBytes(field_number,
+                                       wire_format.WIRETYPE_VARINT)
+
+          message._unknown_fields.append(
+              (tag_bytes, buffer[value_start_pos:pos].tobytes()))
+          if message._unknown_field_set is None:
+            message._unknown_field_set = containers.UnknownFieldSet()
+          message._unknown_field_set._add(
+              field_number, wire_format.WIRETYPE_VARINT, element)
+          # pylint: enable=protected-access
+      if pos > endpoint:
+        if element in enum_type.values_by_number:
+          del value[-1]   # Discard corrupt value.
+        else:
+          del message._unknown_fields[-1]
+          # pylint: disable=protected-access
+          del message._unknown_field_set._values[-1]
+          # pylint: enable=protected-access
+        raise _DecodeError('Packed element was truncated.')
+      return pos
+    return DecodePackedField
+  elif is_repeated:
+    tag_bytes = encoder.TagBytes(field_number, wire_format.WIRETYPE_VARINT)
+    tag_len = len(tag_bytes)
+    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+      """Decode serialized repeated enum to its value and a new position.
+
+      Args:
+        buffer: memoryview of the serialized bytes.
+        pos: int, position in the memory view to start at.
+        end: int, end position of serialized data
+        message: Message object to store unknown fields in
+        field_dict: Map[Descriptor, Any] to store decoded values in.
+
+      Returns:
+        int, new position in serialized data.
+      """
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      while 1:
+        (element, new_pos) = _DecodeSignedVarint32(buffer, pos)
+        # pylint: disable=protected-access
+        if element in enum_type.values_by_number:
+          value.append(element)
+        else:
+          if not message._unknown_fields:
+            message._unknown_fields = []
+          message._unknown_fields.append(
+              (tag_bytes, buffer[pos:new_pos].tobytes()))
+          if message._unknown_field_set is None:
+            message._unknown_field_set = containers.UnknownFieldSet()
+          message._unknown_field_set._add(
+              field_number, wire_format.WIRETYPE_VARINT, element)
+        # pylint: enable=protected-access
+        # 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.
+          if new_pos > end:
+            raise _DecodeError('Truncated message.')
+          return new_pos
+    return DecodeRepeatedField
+  else:
+    def DecodeField(buffer, pos, end, message, field_dict):
+      """Decode serialized repeated enum to its value and a new position.
+
+      Args:
+        buffer: memoryview of the serialized bytes.
+        pos: int, position in the memory view to start at.
+        end: int, end position of serialized data
+        message: Message object to store unknown fields in
+        field_dict: Map[Descriptor, Any] to store decoded values in.
+
+      Returns:
+        int, new position in serialized data.
+      """
+      value_start_pos = pos
+      (enum_value, pos) = _DecodeSignedVarint32(buffer, pos)
+      if pos > end:
+        raise _DecodeError('Truncated message.')
+      if clear_if_default and not enum_value:
+        field_dict.pop(key, None)
+        return pos
+      # pylint: disable=protected-access
+      if enum_value in enum_type.values_by_number:
+        field_dict[key] = enum_value
+      else:
+        if not message._unknown_fields:
+          message._unknown_fields = []
+        tag_bytes = encoder.TagBytes(field_number,
+                                     wire_format.WIRETYPE_VARINT)
+        message._unknown_fields.append(
+            (tag_bytes, buffer[value_start_pos:pos].tobytes()))
+        if message._unknown_field_set is None:
+          message._unknown_field_set = containers.UnknownFieldSet()
+        message._unknown_field_set._add(
+            field_number, wire_format.WIRETYPE_VARINT, enum_value)
+        # pylint: enable=protected-access
+      return pos
+    return DecodeField
+
+
+# --------------------------------------------------------------------
+
+
+Int32Decoder = _SimpleDecoder(
+    wire_format.WIRETYPE_VARINT, _DecodeSignedVarint32)
+
+Int64Decoder = _SimpleDecoder(
+    wire_format.WIRETYPE_VARINT, _DecodeSignedVarint)
+
+UInt32Decoder = _SimpleDecoder(wire_format.WIRETYPE_VARINT, _DecodeVarint32)
+UInt64Decoder = _SimpleDecoder(wire_format.WIRETYPE_VARINT, _DecodeVarint)
+
+SInt32Decoder = _ModifiedDecoder(
+    wire_format.WIRETYPE_VARINT, _DecodeVarint32, wire_format.ZigZagDecode)
+SInt64Decoder = _ModifiedDecoder(
+    wire_format.WIRETYPE_VARINT, _DecodeVarint, wire_format.ZigZagDecode)
+
+# Note that Python conveniently guarantees that when using the '<' prefix on
+# formats, they will also have the same size across all platforms (as opposed
+# to without the prefix, where their sizes depend on the C compiler's basic
+# type sizes).
+Fixed32Decoder  = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, '<I')
+Fixed64Decoder  = _StructPackDecoder(wire_format.WIRETYPE_FIXED64, '<Q')
+SFixed32Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, '<i')
+SFixed64Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED64, '<q')
+FloatDecoder = _FloatDecoder()
+DoubleDecoder = _DoubleDecoder()
+
+BoolDecoder = _ModifiedDecoder(
+    wire_format.WIRETYPE_VARINT, _DecodeVarint, bool)
+
+
+def StringDecoder(field_number, is_repeated, is_packed, key, new_default,
+                  clear_if_default=False):
+  """Returns a decoder for a string field."""
+
+  local_DecodeVarint = _DecodeVarint
+
+  def _ConvertToUnicode(memview):
+    """Convert byte to unicode."""
+    byte_str = memview.tobytes()
+    try:
+      value = str(byte_str, 'utf-8')
+    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
+
+    return value
+
+  assert not is_packed
+  if is_repeated:
+    tag_bytes = encoder.TagBytes(field_number,
+                                 wire_format.WIRETYPE_LENGTH_DELIMITED)
+    tag_len = len(tag_bytes)
+    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      while 1:
+        (size, pos) = local_DecodeVarint(buffer, pos)
+        new_pos = pos + size
+        if new_pos > end:
+          raise _DecodeError('Truncated string.')
+        value.append(_ConvertToUnicode(buffer[pos:new_pos]))
+        # 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 DecodeRepeatedField
+  else:
+    def DecodeField(buffer, pos, end, message, field_dict):
+      (size, pos) = local_DecodeVarint(buffer, pos)
+      new_pos = pos + size
+      if new_pos > end:
+        raise _DecodeError('Truncated string.')
+      if clear_if_default and not size:
+        field_dict.pop(key, None)
+      else:
+        field_dict[key] = _ConvertToUnicode(buffer[pos:new_pos])
+      return new_pos
+    return DecodeField
+
+
+def BytesDecoder(field_number, is_repeated, is_packed, key, new_default,
+                 clear_if_default=False):
+  """Returns a decoder for a bytes field."""
+
+  local_DecodeVarint = _DecodeVarint
+
+  assert not is_packed
+  if is_repeated:
+    tag_bytes = encoder.TagBytes(field_number,
+                                 wire_format.WIRETYPE_LENGTH_DELIMITED)
+    tag_len = len(tag_bytes)
+    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      while 1:
+        (size, pos) = local_DecodeVarint(buffer, pos)
+        new_pos = pos + size
+        if new_pos > end:
+          raise _DecodeError('Truncated string.')
+        value.append(buffer[pos:new_pos].tobytes())
+        # 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 DecodeRepeatedField
+  else:
+    def DecodeField(buffer, pos, end, message, field_dict):
+      (size, pos) = local_DecodeVarint(buffer, pos)
+      new_pos = pos + size
+      if new_pos > end:
+        raise _DecodeError('Truncated string.')
+      if clear_if_default and not size:
+        field_dict.pop(key, None)
+      else:
+        field_dict[key] = buffer[pos:new_pos].tobytes()
+      return new_pos
+    return DecodeField
+
+
+def GroupDecoder(field_number, is_repeated, is_packed, key, new_default):
+  """Returns a decoder for a group field."""
+
+  end_tag_bytes = encoder.TagBytes(field_number,
+                                   wire_format.WIRETYPE_END_GROUP)
+  end_tag_len = len(end_tag_bytes)
+
+  assert not is_packed
+  if is_repeated:
+    tag_bytes = encoder.TagBytes(field_number,
+                                 wire_format.WIRETYPE_START_GROUP)
+    tag_len = len(tag_bytes)
+    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      while 1:
+        value = field_dict.get(key)
+        if value is None:
+          value = field_dict.setdefault(key, new_default(message))
+        # Read sub-message.
+        pos = value.add()._InternalParse(buffer, pos, end)
+        # Read end tag.
+        new_pos = pos+end_tag_len
+        if buffer[pos:new_pos] != end_tag_bytes or new_pos > end:
+          raise _DecodeError('Missing group end tag.')
+        # 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 DecodeRepeatedField
+  else:
+    def DecodeField(buffer, pos, end, message, field_dict):
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      # Read sub-message.
+      pos = value._InternalParse(buffer, pos, end)
+      # Read end tag.
+      new_pos = pos+end_tag_len
+      if buffer[pos:new_pos] != end_tag_bytes or new_pos > end:
+        raise _DecodeError('Missing group end tag.')
+      return new_pos
+    return DecodeField
+
+
+def MessageDecoder(field_number, is_repeated, is_packed, key, new_default):
+  """Returns a decoder for a message field."""
+
+  local_DecodeVarint = _DecodeVarint
+
+  assert not is_packed
+  if is_repeated:
+    tag_bytes = encoder.TagBytes(field_number,
+                                 wire_format.WIRETYPE_LENGTH_DELIMITED)
+    tag_len = len(tag_bytes)
+    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+      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.
+        if value.add()._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.')
+        # 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 DecodeRepeatedField
+  else:
+    def DecodeField(buffer, pos, end, message, field_dict):
+      value = field_dict.get(key)
+      if value is None:
+        value = field_dict.setdefault(key, new_default(message))
+      # Read length.
+      (size, pos) = local_DecodeVarint(buffer, pos)
+      new_pos = pos + size
+      if new_pos > end:
+        raise _DecodeError('Truncated message.')
+      # Read sub-message.
+      if value._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.')
+      return new_pos
+    return DecodeField
+
+
+# --------------------------------------------------------------------
+
+MESSAGE_SET_ITEM_TAG = encoder.TagBytes(1, wire_format.WIRETYPE_START_GROUP)
+
+def MessageSetItemDecoder(descriptor):
+  """Returns a decoder for a MessageSet item.
+
+  The parameter is the message Descriptor.
+
+  The message set message looks like this:
+    message MessageSet {
+      repeated group Item = 1 {
+        required int32 type_id = 2;
+        required string message = 3;
+      }
+    }
+  """
+
+  type_id_tag_bytes = encoder.TagBytes(2, wire_format.WIRETYPE_VARINT)
+  message_tag_bytes = encoder.TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED)
+  item_end_tag_bytes = encoder.TagBytes(1, wire_format.WIRETYPE_END_GROUP)
+
+  local_ReadTag = ReadTag
+  local_DecodeVarint = _DecodeVarint
+  local_SkipField = SkipField
+
+  def DecodeItem(buffer, pos, end, message, field_dict):
+    """Decode serialized message set to its value and new position.
+
+    Args:
+      buffer: memoryview of the serialized bytes.
+      pos: int, position in the memory view to start at.
+      end: int, end position of serialized data
+      message: Message object to store unknown fields in
+      field_dict: Map[Descriptor, Any] to store decoded values in.
+
+    Returns:
+      int, new position in serialized data.
+    """
+    message_set_item_start = pos
+    type_id = -1
+    message_start = -1
+    message_end = -1
+
+    # Technically, type_id and message can appear in any order, so we need
+    # a little loop here.
+    while 1:
+      (tag_bytes, pos) = local_ReadTag(buffer, pos)
+      if tag_bytes == type_id_tag_bytes:
+        (type_id, pos) = local_DecodeVarint(buffer, pos)
+      elif tag_bytes == message_tag_bytes:
+        (size, message_start) = local_DecodeVarint(buffer, pos)
+        pos = message_end = message_start + size
+      elif tag_bytes == item_end_tag_bytes:
+        break
+      else:
+        pos = SkipField(buffer, pos, end, tag_bytes)
+        if pos == -1:
+          raise _DecodeError('Missing group end tag.')
+
+    if pos > end:
+      raise _DecodeError('Truncated message.')
+
+    if type_id == -1:
+      raise _DecodeError('MessageSet item missing type_id.')
+    if message_start == -1:
+      raise _DecodeError('MessageSet item missing message.')
+
+    extension = message.Extensions._FindExtensionByNumber(type_id)
+    # pylint: disable=protected-access
+    if extension is not None:
+      value = field_dict.get(extension)
+      if value is None:
+        message_type = extension.message_type
+        if not hasattr(message_type, '_concrete_class'):
+          # pylint: disable=protected-access
+          message._FACTORY.GetPrototype(message_type)
+        value = field_dict.setdefault(
+            extension, message_type._concrete_class())
+      if value._InternalParse(buffer, message_start,message_end) != message_end:
+        # The only reason _InternalParse would return early is if it encountered
+        # an end-group tag.
+        raise _DecodeError('Unexpected end-group tag.')
+    else:
+      if not message._unknown_fields:
+        message._unknown_fields = []
+      message._unknown_fields.append(
+          (MESSAGE_SET_ITEM_TAG, buffer[message_set_item_start:pos].tobytes()))
+      if message._unknown_field_set is None:
+        message._unknown_field_set = containers.UnknownFieldSet()
+      message._unknown_field_set._add(
+          type_id,
+          wire_format.WIRETYPE_LENGTH_DELIMITED,
+          buffer[message_start:message_end].tobytes())
+      # pylint: enable=protected-access
+
+    return pos
+
+  return DecodeItem
+
+
+def UnknownMessageSetItemDecoder():
+  """Returns a decoder for a Unknown MessageSet item."""
+
+  type_id_tag_bytes = encoder.TagBytes(2, wire_format.WIRETYPE_VARINT)
+  message_tag_bytes = encoder.TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED)
+  item_end_tag_bytes = encoder.TagBytes(1, wire_format.WIRETYPE_END_GROUP)
+
+  def DecodeUnknownItem(buffer):
+    pos = 0
+    end = len(buffer)
+    message_start = -1
+    message_end = -1
+    while 1:
+      (tag_bytes, pos) = ReadTag(buffer, pos)
+      if tag_bytes == type_id_tag_bytes:
+        (type_id, pos) = _DecodeVarint(buffer, pos)
+      elif tag_bytes == message_tag_bytes:
+        (size, message_start) = _DecodeVarint(buffer, pos)
+        pos = message_end = message_start + size
+      elif tag_bytes == item_end_tag_bytes:
+        break
+      else:
+        pos = SkipField(buffer, pos, end, tag_bytes)
+        if pos == -1:
+          raise _DecodeError('Missing group end tag.')
+
+    if pos > end:
+      raise _DecodeError('Truncated message.')
+
+    if type_id == -1:
+      raise _DecodeError('MessageSet item missing type_id.')
+    if message_start == -1:
+      raise _DecodeError('MessageSet item missing message.')
+
+    return (type_id, buffer[message_start:message_end].tobytes())
+
+  return DecodeUnknownItem
+
+# --------------------------------------------------------------------
+
+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].CopyFrom(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.
+
+def _SkipVarint(buffer, pos, end):
+  """Skip a varint value.  Returns the new position."""
+  # Previously ord(buffer[pos]) raised IndexError when pos is out of range.
+  # With this code, ord(b'') raises TypeError.  Both are handled in
+  # python_message.py to generate a 'Truncated message' error.
+  while ord(buffer[pos:pos+1].tobytes()) & 0x80:
+    pos += 1
+  pos += 1
+  if pos > end:
+    raise _DecodeError('Truncated message.')
+  return pos
+
+def _SkipFixed64(buffer, pos, end):
+  """Skip a fixed64 value.  Returns the new position."""
+
+  pos += 8
+  if pos > end:
+    raise _DecodeError('Truncated message.')
+  return pos
+
+
+def _DecodeFixed64(buffer, pos):
+  """Decode a fixed64."""
+  new_pos = pos + 8
+  return (struct.unpack('<Q', buffer[pos:new_pos])[0], new_pos)
+
+
+def _SkipLengthDelimited(buffer, pos, end):
+  """Skip a length-delimited value.  Returns the new position."""
+
+  (size, pos) = _DecodeVarint(buffer, pos)
+  pos += size
+  if pos > end:
+    raise _DecodeError('Truncated message.')
+  return pos
+
+
+def _SkipGroup(buffer, pos, end):
+  """Skip sub-group.  Returns the new position."""
+
+  while 1:
+    (tag_bytes, pos) = ReadTag(buffer, pos)
+    new_pos = SkipField(buffer, pos, end, tag_bytes)
+    if new_pos == -1:
+      return pos
+    pos = new_pos
+
+
+def _DecodeUnknownFieldSet(buffer, pos, end_pos=None):
+  """Decode UnknownFieldSet.  Returns the UnknownFieldSet and new position."""
+
+  unknown_field_set = containers.UnknownFieldSet()
+  while end_pos is None or pos < end_pos:
+    (tag_bytes, pos) = ReadTag(buffer, pos)
+    (tag, _) = _DecodeVarint(tag_bytes, 0)
+    field_number, wire_type = wire_format.UnpackTag(tag)
+    if wire_type == wire_format.WIRETYPE_END_GROUP:
+      break
+    (data, pos) = _DecodeUnknownField(buffer, pos, wire_type)
+    # pylint: disable=protected-access
+    unknown_field_set._add(field_number, wire_type, data)
+
+  return (unknown_field_set, pos)
+
+
+def _DecodeUnknownField(buffer, pos, wire_type):
+  """Decode a unknown field.  Returns the UnknownField and new position."""
+
+  if wire_type == wire_format.WIRETYPE_VARINT:
+    (data, pos) = _DecodeVarint(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_FIXED64:
+    (data, pos) = _DecodeFixed64(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_FIXED32:
+    (data, pos) = _DecodeFixed32(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED:
+    (size, pos) = _DecodeVarint(buffer, pos)
+    data = buffer[pos:pos+size].tobytes()
+    pos += size
+  elif wire_type == wire_format.WIRETYPE_START_GROUP:
+    (data, pos) = _DecodeUnknownFieldSet(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_END_GROUP:
+    return (0, -1)
+  else:
+    raise _DecodeError('Wrong wire type in tag.')
+
+  return (data, pos)
+
+
+def _EndGroup(buffer, pos, end):
+  """Skipping an END_GROUP tag returns -1 to tell the parent loop to break."""
+
+  return -1
+
+
+def _SkipFixed32(buffer, pos, end):
+  """Skip a fixed32 value.  Returns the new position."""
+
+  pos += 4
+  if pos > end:
+    raise _DecodeError('Truncated message.')
+  return pos
+
+
+def _DecodeFixed32(buffer, pos):
+  """Decode a fixed32."""
+
+  new_pos = pos + 4
+  return (struct.unpack('<I', buffer[pos:new_pos])[0], new_pos)
+
+
+def _RaiseInvalidWireType(buffer, pos, end):
+  """Skip function for unknown wire types.  Raises an exception."""
+
+  raise _DecodeError('Tag had invalid wire type.')
+
+def _FieldSkipper():
+  """Constructs the SkipField function."""
+
+  WIRETYPE_TO_SKIPPER = [
+      _SkipVarint,
+      _SkipFixed64,
+      _SkipLengthDelimited,
+      _SkipGroup,
+      _EndGroup,
+      _SkipFixed32,
+      _RaiseInvalidWireType,
+      _RaiseInvalidWireType,
+      ]
+
+  wiretype_mask = wire_format.TAG_TYPE_MASK
+
+  def SkipField(buffer, pos, end, tag_bytes):
+    """Skips a field with the specified tag.
+
+    |pos| should point to the byte immediately after the tag.
+
+    Returns:
+        The new position (after the tag value), or -1 if the tag is an end-group
+        tag (in which case the calling loop should break).
+    """
+
+    # The wire type is always in the first byte since varints are little-endian.
+    wire_type = ord(tag_bytes[0:1]) & wiretype_mask
+    return WIRETYPE_TO_SKIPPER[wire_type](buffer, pos, end)
+
+  return SkipField
+
+SkipField = _FieldSkipper()
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
new file mode 100644
index 0000000..3c086b9
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -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.
+
+"""Tests for google.protobuf.descriptor_database."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import unittest
+import warnings
+
+from google.protobuf import unittest_pb2
+from google.protobuf import descriptor_pb2
+from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import no_package_pb2
+from google.protobuf.internal import testing_refleaks
+from google.protobuf import descriptor_database
+
+
+@testing_refleaks.TestCase
+class DescriptorDatabaseTest(unittest.TestCase):
+
+  def testAdd(self):
+    db = descriptor_database.DescriptorDatabase()
+    file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test2_pb2.DESCRIPTOR.serialized_pb)
+    file_desc_proto2 = descriptor_pb2.FileDescriptorProto.FromString(
+        no_package_pb2.DESCRIPTOR.serialized_pb)
+    db.Add(file_desc_proto)
+    db.Add(file_desc_proto2)
+
+    self.assertEqual(file_desc_proto, db.FindFileByName(
+        'google/protobuf/internal/factory_test2.proto'))
+    # Can find message type.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message'))
+    # Can find nested message type.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.NestedFactory2Message'))
+    # Can find enum type.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Enum'))
+    # Can find nested enum type.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum'))
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.MessageWithNestedEnumOnly.NestedEnum'))
+    # Can find field.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.list_field'))
+    # Can find enum value.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Enum.FACTORY_2_VALUE_0'))
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.FACTORY_2_VALUE_0'))
+    self.assertEqual(file_desc_proto2, db.FindFileContainingSymbol(
+        '.NO_PACKAGE_VALUE_0'))
+    # Can find top level extension.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.another_field'))
+    # Can find nested extension inside a message.
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.one_more_field'))
+
+    # Can find service.
+    file_desc_proto2 = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    db.Add(file_desc_proto2)
+    self.assertEqual(file_desc_proto2, db.FindFileContainingSymbol(
+        'protobuf_unittest.TestService'))
+
+    # Non-existent field under a valid top level symbol can also be
+    # found. The behavior is the same with protobuf C++.
+    self.assertEqual(file_desc_proto2, db.FindFileContainingSymbol(
+        'protobuf_unittest.TestAllTypes.none_field'))
+
+    with self.assertRaisesRegex(KeyError, r'\'protobuf_unittest\.NoneMessage\''):
+      db.FindFileContainingSymbol('protobuf_unittest.NoneMessage')
+
+  def testConflictRegister(self):
+    db = descriptor_database.DescriptorDatabase()
+    unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    db.Add(unittest_fd)
+    conflict_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    conflict_fd.name = 'other_file2'
+    with warnings.catch_warnings(record=True) as w:
+      # Cause all warnings to always be triggered.
+      warnings.simplefilter('always')
+      db.Add(conflict_fd)
+      self.assertTrue(len(w))
+      self.assertIs(w[0].category, RuntimeWarning)
+      self.assertIn('Conflict register for file "other_file2": ',
+                    str(w[0].message))
+      self.assertIn('already defined in file '
+                    '"google/protobuf/unittest.proto"',
+                    str(w[0].message))
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
new file mode 100644
index 0000000..9e451b4
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -0,0 +1,1149 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests for google.protobuf.descriptor_pool."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import copy
+import os
+import unittest
+import warnings
+
+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
+from google.protobuf.internal import descriptor_pool_test1_pb2
+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 file_options_test_pb2
+from google.protobuf.internal import more_messages_pb2
+from google.protobuf.internal import no_package_pb2
+from google.protobuf.internal import testing_refleaks
+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
+
+
+
+warnings.simplefilter('error', DeprecationWarning)
+
+
+class DescriptorPoolTestBase(object):
+
+  def testFindFileByName(self):
+    name1 = 'google/protobuf/internal/factory_test1.proto'
+    file_desc1 = self.pool.FindFileByName(name1)
+    self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
+    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.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):
+    with self.assertRaises(KeyError):
+      self.pool.FindFileByName('Does not exist')
+
+  def testFindFileContainingSymbol(self):
+    file_desc1 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory1Message')
+    self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
+    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.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)
+
+    # Tests top level extension.
+    file_desc3 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.another_field')
+    self.assertIsInstance(file_desc3, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/internal/factory_test2.proto',
+                     file_desc3.name)
+
+    # Tests nested extension inside a message.
+    file_desc4 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.one_more_field')
+    self.assertIsInstance(file_desc4, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/internal/factory_test2.proto',
+                     file_desc4.name)
+
+    file_desc5 = self.pool.FindFileContainingSymbol(
+        'protobuf_unittest.TestService')
+    self.assertIsInstance(file_desc5, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/unittest.proto',
+                     file_desc5.name)
+    # Tests the generated pool.
+    assert descriptor_pool.Default().FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.one_more_field')
+    assert descriptor_pool.Default().FindFileContainingSymbol(
+        'google.protobuf.python.internal.another_field')
+    assert descriptor_pool.Default().FindFileContainingSymbol(
+        'protobuf_unittest.TestService')
+
+    # Can find field.
+    file_desc6 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory1Message.list_value')
+    self.assertIsInstance(file_desc6, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/internal/factory_test1.proto',
+                     file_desc6.name)
+
+    # Can find top level Enum value.
+    file_desc7 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.FACTORY_1_VALUE_0')
+    self.assertIsInstance(file_desc7, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/internal/factory_test1.proto',
+                     file_desc7.name)
+
+    # Can find nested Enum value.
+    file_desc8 = self.pool.FindFileContainingSymbol(
+        'protobuf_unittest.TestAllTypes.FOO')
+    self.assertIsInstance(file_desc8, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/unittest.proto',
+                     file_desc8.name)
+
+    # TODO(jieluo): Add tests for no package when b/13860351 is fixed.
+
+    self.assertRaises(KeyError, self.pool.FindFileContainingSymbol,
+                      'google.protobuf.python.internal.Factory1Message.none_field')
+
+  def testFindFileContainingSymbolFailure(self):
+    with self.assertRaises(KeyError):
+      self.pool.FindFileContainingSymbol('Does not exist')
+
+  def testFindMessageTypeByName(self):
+    msg1 = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory1Message')
+    self.assertIsInstance(msg1, descriptor.Descriptor)
+    self.assertEqual('Factory1Message', msg1.name)
+    self.assertEqual('google.protobuf.python.internal.Factory1Message',
+                     msg1.full_name)
+    self.assertEqual(None, msg1.containing_type)
+    self.assertFalse(msg1.has_options)
+
+    nested_msg1 = msg1.nested_types[0]
+    self.assertEqual('NestedFactory1Message', nested_msg1.name)
+    self.assertEqual(msg1, nested_msg1.containing_type)
+
+    nested_enum1 = msg1.enum_types[0]
+    self.assertEqual('NestedFactory1Enum', nested_enum1.name)
+    self.assertEqual(msg1, nested_enum1.containing_type)
+
+    self.assertEqual(nested_msg1, msg1.fields_by_name[
+        'nested_factory_1_message'].message_type)
+    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.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.assertEqual('NestedFactory2Message', nested_msg2.name)
+    self.assertEqual(msg2, nested_msg2.containing_type)
+
+    nested_enum2 = msg2.enum_types[0]
+    self.assertEqual('NestedFactory2Enum', nested_enum2.name)
+    self.assertEqual(msg2, nested_enum2.containing_type)
+
+    self.assertEqual(nested_msg2, msg2.fields_by_name[
+        'nested_factory_2_message'].message_type)
+    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.assertEqual(
+        1776, msg2.fields_by_name['int_with_default'].default_value)
+
+    self.assertTrue(
+        msg2.fields_by_name['double_with_default'].has_default_value)
+    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.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.assertEqual(
+        1, msg2.fields_by_name['enum_with_default'].default_value)
+
+    msg3 = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message.NestedFactory2Message')
+    self.assertEqual(nested_msg2, msg3)
+
+    self.assertTrue(msg2.fields_by_name['bytes_with_default'].has_default_value)
+    self.assertEqual(
+        b'a\xfb\x00c',
+        msg2.fields_by_name['bytes_with_default'].default_value)
+
+    self.assertEqual(1, len(msg2.oneofs))
+    self.assertEqual(1, len(msg2.oneofs_by_name))
+    self.assertEqual(2, len(msg2.oneofs[0].fields))
+    for name in ['oneof_int', 'oneof_string']:
+      self.assertEqual(msg2.oneofs[0],
+                       msg2.fields_by_name[name].containing_oneof)
+      self.assertIn(msg2.fields_by_name[name], msg2.oneofs[0].fields)
+
+  def testFindTypeErrors(self):
+    self.assertRaises(TypeError, self.pool.FindExtensionByNumber, '')
+    self.assertRaises(KeyError, self.pool.FindMethodByName, '')
+
+    # TODO(jieluo): Fix python to raise correct errors.
+    if api_implementation.Type() == 'python':
+      error_type = AttributeError
+    else:
+      error_type = TypeError
+    self.assertRaises(error_type, self.pool.FindMessageTypeByName, 0)
+    self.assertRaises(error_type, self.pool.FindFieldByName, 0)
+    self.assertRaises(error_type, self.pool.FindExtensionByName, 0)
+    self.assertRaises(error_type, self.pool.FindEnumTypeByName, 0)
+    self.assertRaises(error_type, self.pool.FindOneofByName, 0)
+    self.assertRaises(error_type, self.pool.FindServiceByName, 0)
+    self.assertRaises(error_type, self.pool.FindMethodByName, 0)
+    self.assertRaises(error_type, self.pool.FindFileContainingSymbol, 0)
+    if api_implementation.Type() == 'python':
+      error_type = KeyError
+    self.assertRaises(error_type, self.pool.FindFileByName, 0)
+
+  def testFindMessageTypeByNameFailure(self):
+    with self.assertRaises(KeyError):
+      self.pool.FindMessageTypeByName('Does not exist')
+
+  def testFindEnumTypeByName(self):
+    enum1 = self.pool.FindEnumTypeByName(
+        'google.protobuf.python.internal.Factory1Enum')
+    self.assertIsInstance(enum1, descriptor.EnumDescriptor)
+    self.assertEqual(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
+    self.assertEqual(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
+    self.assertFalse(enum1.has_options)
+
+    nested_enum1 = self.pool.FindEnumTypeByName(
+        'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum')
+    self.assertIsInstance(nested_enum1, descriptor.EnumDescriptor)
+    self.assertEqual(
+        0, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_0'].number)
+    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.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.assertEqual(
+        0, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_0'].number)
+    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)
+    self.assertFalse(field.has_options)
+
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('Does not exist')
+
+  def testFindOneofByName(self):
+    oneof = self.pool.FindOneofByName(
+        'google.protobuf.python.internal.Factory2Message.oneof_field')
+    self.assertEqual(oneof.name, 'oneof_field')
+    with self.assertRaises(KeyError):
+      self.pool.FindOneofByName('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 testFindAllExtensions(self):
+    factory1_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory1Message')
+    factory2_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message')
+    # An extension defined in a message.
+    one_more_field = factory2_message.extensions_by_name['one_more_field']
+    # An extension defined at file scope.
+    factory_test2 = self.pool.FindFileByName(
+        'google/protobuf/internal/factory_test2.proto')
+    another_field = factory_test2.extensions_by_name['another_field']
+
+    extensions = self.pool.FindAllExtensions(factory1_message)
+    expected_extension_numbers = set([one_more_field, another_field])
+    self.assertEqual(expected_extension_numbers, set(extensions))
+    # Verify that mutating the returned list does not affect the pool.
+    extensions.append('unexpected_element')
+    # Get the extensions again, the returned value does not contain the
+    # 'unexpected_element'.
+    extensions = self.pool.FindAllExtensions(factory1_message)
+    self.assertEqual(expected_extension_numbers, set(extensions))
+
+  def testFindExtensionByNumber(self):
+    factory1_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory1Message')
+    # Build factory_test2.proto which will put extensions to the pool
+    self.pool.FindFileByName(
+        'google/protobuf/internal/factory_test2.proto')
+
+    # An extension defined in a message.
+    extension = self.pool.FindExtensionByNumber(factory1_message, 1001)
+    self.assertEqual(extension.name, 'one_more_field')
+    # An extension defined at file scope.
+    extension = self.pool.FindExtensionByNumber(factory1_message, 1002)
+    self.assertEqual(extension.name, 'another_field')
+    with self.assertRaises(KeyError):
+      extension = self.pool.FindExtensionByNumber(factory1_message, 1234567)
+
+  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 testFindService(self):
+    service = self.pool.FindServiceByName('protobuf_unittest.TestService')
+    self.assertEqual(service.full_name, 'protobuf_unittest.TestService')
+    with self.assertRaises(KeyError):
+      self.pool.FindServiceByName('Does not exist')
+
+    method = self.pool.FindMethodByName('protobuf_unittest.TestService.Foo')
+    self.assertIs(method.containing_service, service)
+    with self.assertRaises(KeyError):
+      self.pool.FindMethodByName('protobuf_unittest.TestService.Doesnotexist')
+
+  def testUserDefinedDB(self):
+    db = descriptor_database.DescriptorDatabase()
+    self.pool = descriptor_pool.DescriptorPool(db)
+    db.Add(self.factory_test1_fd)
+    db.Add(self.factory_test2_fd)
+    self.testFindMessageTypeByName()
+
+  def testAddSerializedFile(self):
+    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+      if api_implementation.Type() != 'python':
+        # Cpp extension cannot call Add on a DescriptorPool
+        # that uses a DescriptorDatabase.
+        # TODO(jieluo): Fix python and cpp extension diff.
+        return
+    self.pool = descriptor_pool.DescriptorPool()
+    file1 = self.pool.AddSerializedFile(
+        self.factory_test1_fd.SerializeToString())
+    file2 = self.pool.AddSerializedFile(
+        self.factory_test2_fd.SerializeToString())
+    self.assertEqual(file1.name,
+                     'google/protobuf/internal/factory_test1.proto')
+    self.assertEqual(file2.name,
+                     'google/protobuf/internal/factory_test2.proto')
+    self.testFindMessageTypeByName()
+    file_json = self.pool.AddSerializedFile(
+        more_messages_pb2.DESCRIPTOR.serialized_pb)
+    field = file_json.message_types_by_name['class'].fields_by_name['int_field']
+    self.assertEqual(field.json_name, 'json_int')
+
+
+  def testEnumDefaultValue(self):
+    """Test the default value of enums which don't start at zero."""
+    def _CheckDefaultValue(file_descriptor):
+      default_value = (file_descriptor
+                       .message_types_by_name['DescriptorPoolTest1']
+                       .fields_by_name['nested_enum']
+                       .default_value)
+      self.assertEqual(default_value,
+                       descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA)
+    # First check what the generated descriptor contains.
+    _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR)
+    # Then check the generated pool. Normally this is the same descriptor.
+    file_descriptor = symbol_database.Default().pool.FindFileByName(
+        'google/protobuf/internal/descriptor_pool_test1.proto')
+    self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR)
+    _CheckDefaultValue(file_descriptor)
+
+    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+      if api_implementation.Type() != 'python':
+        # Cpp extension cannot call Add on a DescriptorPool
+        # that uses a DescriptorDatabase.
+        # TODO(jieluo): Fix python and cpp extension diff.
+        return
+    # Then check the dynamic pool and its internal DescriptorDatabase.
+    descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString(
+        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
+    self.pool.Add(descriptor_proto)
+    # And do the same check as above
+    file_descriptor = self.pool.FindFileByName(
+        'google/protobuf/internal/descriptor_pool_test1.proto')
+    _CheckDefaultValue(file_descriptor)
+
+  def testDefaultValueForCustomMessages(self):
+    """Check the value returned by non-existent fields."""
+    def _CheckValueAndType(value, expected_value, expected_type):
+      self.assertEqual(value, expected_value)
+      self.assertIsInstance(value, expected_type)
+
+    def _CheckDefaultValues(msg):
+      try:
+        int64 = long
+      except NameError:  # Python3
+        int64 = int
+      try:
+        unicode_type = unicode
+      except NameError:  # Python3
+        unicode_type = str
+      _CheckValueAndType(msg.optional_int32, 0, int)
+      _CheckValueAndType(msg.optional_uint64, 0, (int64, int))
+      _CheckValueAndType(msg.optional_float, 0, (float, int))
+      _CheckValueAndType(msg.optional_double, 0, (float, int))
+      _CheckValueAndType(msg.optional_bool, False, bool)
+      _CheckValueAndType(msg.optional_string, u'', unicode_type)
+      _CheckValueAndType(msg.optional_bytes, b'', bytes)
+      _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int)
+    # First for the generated message
+    _CheckDefaultValues(unittest_pb2.TestAllTypes())
+    # Then for a message built with from the DescriptorPool.
+    pool = descriptor_pool.DescriptorPool()
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_pb2.DESCRIPTOR.serialized_pb))
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb))
+    message_class = message_factory.MessageFactory(pool).GetPrototype(
+        pool.FindMessageTypeByName(
+            unittest_pb2.TestAllTypes.DESCRIPTOR.full_name))
+    _CheckDefaultValues(message_class())
+
+  def testAddFileDescriptor(self):
+    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+      if api_implementation.Type() != 'python':
+        # Cpp extension cannot call Add on a DescriptorPool
+        # that uses a DescriptorDatabase.
+        # TODO(jieluo): Fix python and cpp extension diff.
+        return
+    file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
+    self.pool.Add(file_desc)
+    self.pool.AddSerializedFile(file_desc.SerializeToString())
+
+  def testComplexNesting(self):
+    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+      if api_implementation.Type() != 'python':
+        # Cpp extension cannot call Add on a DescriptorPool
+        # that uses a DescriptorDatabase.
+        # TODO(jieluo): Fix python and cpp extension diff.
+        return
+    more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString(
+        more_messages_pb2.DESCRIPTOR.serialized_pb)
+    test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
+        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
+    test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
+        descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
+    self.pool.Add(more_messages_desc)
+    self.pool.Add(test1_desc)
+    self.pool.Add(test2_desc)
+    TEST1_FILE.CheckFile(self, self.pool)
+    TEST2_FILE.CheckFile(self, self.pool)
+
+  def testConflictRegister(self):
+    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+      if api_implementation.Type() != 'python':
+        # Cpp extension cannot call Add on a DescriptorPool
+        # that uses a DescriptorDatabase.
+        # TODO(jieluo): Fix python and cpp extension diff.
+        return
+    unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    conflict_fd = copy.deepcopy(unittest_fd)
+    conflict_fd.name = 'other_file'
+    if api_implementation.Type() != 'python':
+        pass
+    else:
+      pool = copy.deepcopy(self.pool)
+      file_descriptor = unittest_pb2.DESCRIPTOR
+      pool._AddDescriptor(
+          file_descriptor.message_types_by_name['TestAllTypes'])
+      pool._AddEnumDescriptor(
+          file_descriptor.enum_types_by_name['ForeignEnum'])
+      pool._AddServiceDescriptor(
+          file_descriptor.services_by_name['TestService'])
+      pool._AddExtensionDescriptor(
+          file_descriptor.extensions_by_name['optional_int32_extension'])
+      pool.Add(unittest_fd)
+      with warnings.catch_warnings(record=True) as w:
+        warnings.simplefilter('always')
+        pool.Add(conflict_fd)
+        self.assertTrue(len(w))
+        self.assertIs(w[0].category, RuntimeWarning)
+        self.assertIn('Conflict register for file "other_file": ',
+                      str(w[0].message))
+      pool.FindFileByName(unittest_fd.name)
+      with self.assertRaises(TypeError):
+        pool.FindFileByName(conflict_fd.name)
+
+
+@testing_refleaks.TestCase
+class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
+
+  def setUp(self):
+    self.pool = descriptor_pool.Default()
+    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test1_pb2.DESCRIPTOR.serialized_pb)
+    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test2_pb2.DESCRIPTOR.serialized_pb)
+
+  def testFindMethods(self):
+    self.assertIs(
+        self.pool.FindFileByName('google/protobuf/unittest.proto'),
+        unittest_pb2.DESCRIPTOR)
+    self.assertIs(
+        self.pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertIs(
+        self.pool.FindFieldByName(
+            'protobuf_unittest.TestAllTypes.optional_int32'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
+    self.assertIs(
+        self.pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
+        unittest_pb2.ForeignEnum.DESCRIPTOR)
+    self.assertIs(
+        self.pool.FindExtensionByName(
+            'protobuf_unittest.optional_int32_extension'),
+        unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
+    self.assertIs(
+        self.pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
+    self.assertIs(
+        self.pool.FindServiceByName('protobuf_unittest.TestService'),
+        unittest_pb2.DESCRIPTOR.services_by_name['TestService'])
+
+
+@testing_refleaks.TestCase
+class CreateDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
+
+  def setUp(self):
+    self.pool = descriptor_pool.DescriptorPool()
+    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test1_pb2.DESCRIPTOR.serialized_pb)
+    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test2_pb2.DESCRIPTOR.serialized_pb)
+    self.pool.Add(self.factory_test1_fd)
+    self.pool.Add(self.factory_test2_fd)
+
+    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
+    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_pb2.DESCRIPTOR.serialized_pb))
+    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb))
+    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        no_package_pb2.DESCRIPTOR.serialized_pb))
+
+
+@testing_refleaks.TestCase
+class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
+                                          unittest.TestCase):
+
+  def setUp(self):
+    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test1_pb2.DESCRIPTOR.serialized_pb)
+    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test2_pb2.DESCRIPTOR.serialized_pb)
+    self.db = descriptor_database.DescriptorDatabase()
+    self.db.Add(self.factory_test1_fd)
+    self.db.Add(self.factory_test2_fd)
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_pb2.DESCRIPTOR.serialized_pb))
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb))
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        no_package_pb2.DESCRIPTOR.serialized_pb))
+    self.pool = descriptor_pool.DescriptorPool(descriptor_db=self.db)
+
+  def testErrorCollector(self):
+    file_proto = descriptor_pb2.FileDescriptorProto()
+    file_proto.package = 'collector'
+    file_proto.name = 'error_file'
+    message_type = file_proto.message_type.add()
+    message_type.name = 'ErrorMessage'
+    field = message_type.field.add()
+    field.number = 1
+    field.name = 'nested_message_field'
+    field.label = descriptor.FieldDescriptor.LABEL_OPTIONAL
+    field.type = descriptor.FieldDescriptor.TYPE_MESSAGE
+    field.type_name = 'SubMessage'
+    oneof = message_type.oneof_decl.add()
+    oneof.name = 'MyOneof'
+    enum_type = file_proto.enum_type.add()
+    enum_type.name = 'MyEnum'
+    enum_value = enum_type.value.add()
+    enum_value.name = 'MyEnumValue'
+    enum_value.number = 0
+    self.db.Add(file_proto)
+
+    self.assertRaisesRegex(KeyError, 'SubMessage',
+                           self.pool.FindMessageTypeByName,
+                           'collector.ErrorMessage')
+    self.assertRaisesRegex(KeyError, 'SubMessage', self.pool.FindFileByName,
+                           'error_file')
+    with self.assertRaises(KeyError) as exc:
+      self.pool.FindFileByName('none_file')
+    self.assertIn(str(exc.exception), ('\'none_file\'',
+                                       '\"Couldn\'t find file none_file\"'))
+
+    # Pure python _ConvertFileProtoToFileDescriptor() method has side effect
+    # that all the symbols found in the file will load into the pool even the
+    # file can not build. So when FindMessageTypeByName('ErrorMessage') was
+    # called the first time, a KeyError will be raised but call the find
+    # method later will return a descriptor which is not build.
+    # TODO(jieluo): fix pure python to revert the load if file can not be build
+    if api_implementation.Type() != 'python':
+      error_msg = ('Invalid proto descriptor for file "error_file":\\n  '
+                   'collector.ErrorMessage.nested_message_field: "SubMessage" '
+                   'is not defined.\\n  collector.ErrorMessage.MyOneof: Oneof '
+                   'must have at least one field.\\n\'')
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindMessageTypeByName('collector.ErrorMessage')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for '
+                       'message collector.ErrorMessage\\n' + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindFieldByName('collector.ErrorMessage.nested_message_field')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for field'
+                       ' collector.ErrorMessage.nested_message_field\\n'
+                       + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindEnumTypeByName('collector.MyEnum')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for enum'
+                       ' collector.MyEnum\\n' + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindFileContainingSymbol('collector.MyEnumValue')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for symbol'
+                       ' collector.MyEnumValue\\n' + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindOneofByName('collector.ErrorMessage.MyOneof')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for oneof'
+                       ' collector.ErrorMessage.MyOneof\\n' + error_msg)
+
+
+class ProtoFile(object):
+
+  def __init__(self, name, package, messages, dependencies=None,
+               public_dependencies=None):
+    self.name = name
+    self.package = package
+    self.messages = messages
+    self.dependencies = dependencies or []
+    self.public_dependencies = public_dependencies or []
+
+  def CheckFile(self, test, pool):
+    file_desc = pool.FindFileByName(self.name)
+    test.assertEqual(self.name, file_desc.name)
+    test.assertEqual(self.package, file_desc.package)
+    dependencies_names = [f.name for f in file_desc.dependencies]
+    test.assertEqual(self.dependencies, dependencies_names)
+    public_dependencies_names = [f.name for f in file_desc.public_dependencies]
+    test.assertEqual(self.public_dependencies, public_dependencies_names)
+    for name, msg_type in self.messages.items():
+      msg_type.CheckType(test, None, name, file_desc)
+
+
+class EnumType(object):
+
+  def __init__(self, values):
+    self.values = values
+
+  def CheckType(self, test, msg_desc, name, file_desc):
+    enum_desc = msg_desc.enum_types_by_name[name]
+    test.assertEqual(name, enum_desc.name)
+    expected_enum_full_name = '.'.join([msg_desc.full_name, name])
+    test.assertEqual(expected_enum_full_name, enum_desc.full_name)
+    test.assertEqual(msg_desc, enum_desc.containing_type)
+    test.assertEqual(file_desc, enum_desc.file)
+    for index, (value, number) in enumerate(self.values):
+      value_desc = enum_desc.values_by_name[value]
+      test.assertEqual(value, value_desc.name)
+      test.assertEqual(index, value_desc.index)
+      test.assertEqual(number, value_desc.number)
+      test.assertEqual(enum_desc, value_desc.type)
+      test.assertIn(value, msg_desc.enum_values_by_name)
+
+
+class MessageType(object):
+
+  def __init__(self, type_dict, field_list, is_extendable=False,
+               extensions=None):
+    self.type_dict = type_dict
+    self.field_list = field_list
+    self.is_extendable = is_extendable
+    self.extensions = extensions or []
+
+  def CheckType(self, test, containing_type_desc, name, file_desc):
+    if containing_type_desc is None:
+      desc = file_desc.message_types_by_name[name]
+      expected_full_name = '.'.join([file_desc.package, name])
+    else:
+      desc = containing_type_desc.nested_types_by_name[name]
+      expected_full_name = '.'.join([containing_type_desc.full_name, name])
+
+    test.assertEqual(name, desc.name)
+    test.assertEqual(expected_full_name, desc.full_name)
+    test.assertEqual(containing_type_desc, desc.containing_type)
+    test.assertEqual(desc.file, file_desc)
+    test.assertEqual(self.is_extendable, desc.is_extendable)
+    for name, subtype in self.type_dict.items():
+      subtype.CheckType(test, desc, name, file_desc)
+
+    for index, (name, field) in enumerate(self.field_list):
+      field.CheckField(test, desc, name, index, file_desc)
+
+    for index, (name, field) in enumerate(self.extensions):
+      field.CheckField(test, desc, name, index, file_desc)
+
+
+class EnumField(object):
+
+  def __init__(self, number, type_name, default_value):
+    self.number = number
+    self.type_name = type_name
+    self.default_value = default_value
+
+  def CheckField(self, test, msg_desc, name, index, file_desc):
+    field_desc = msg_desc.fields_by_name[name]
+    enum_desc = msg_desc.enum_types_by_name[self.type_name]
+    test.assertEqual(name, field_desc.name)
+    expected_field_full_name = '.'.join([msg_desc.full_name, name])
+    test.assertEqual(expected_field_full_name, field_desc.full_name)
+    test.assertEqual(index, field_desc.index)
+    test.assertEqual(self.number, field_desc.number)
+    test.assertEqual(descriptor.FieldDescriptor.TYPE_ENUM, field_desc.type)
+    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM,
+                     field_desc.cpp_type)
+    test.assertTrue(field_desc.has_default_value)
+    test.assertEqual(enum_desc.values_by_name[self.default_value].number,
+                     field_desc.default_value)
+    test.assertFalse(enum_desc.values_by_name[self.default_value].has_options)
+    test.assertEqual(msg_desc, field_desc.containing_type)
+    test.assertEqual(enum_desc, field_desc.enum_type)
+    test.assertEqual(file_desc, enum_desc.file)
+
+
+class MessageField(object):
+
+  def __init__(self, number, type_name):
+    self.number = number
+    self.type_name = type_name
+
+  def CheckField(self, test, msg_desc, name, index, file_desc):
+    field_desc = msg_desc.fields_by_name[name]
+    field_type_desc = msg_desc.nested_types_by_name[self.type_name]
+    test.assertEqual(name, field_desc.name)
+    expected_field_full_name = '.'.join([msg_desc.full_name, name])
+    test.assertEqual(expected_field_full_name, field_desc.full_name)
+    test.assertEqual(index, field_desc.index)
+    test.assertEqual(self.number, field_desc.number)
+    test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
+    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
+                     field_desc.cpp_type)
+    test.assertFalse(field_desc.has_default_value)
+    test.assertEqual(msg_desc, field_desc.containing_type)
+    test.assertEqual(field_type_desc, field_desc.message_type)
+    test.assertEqual(file_desc, field_desc.file)
+    test.assertEqual(field_desc.default_value, None)
+
+
+class StringField(object):
+
+  def __init__(self, number, default_value):
+    self.number = number
+    self.default_value = default_value
+
+  def CheckField(self, test, msg_desc, name, index, file_desc):
+    field_desc = msg_desc.fields_by_name[name]
+    test.assertEqual(name, field_desc.name)
+    expected_field_full_name = '.'.join([msg_desc.full_name, name])
+    test.assertEqual(expected_field_full_name, field_desc.full_name)
+    test.assertEqual(index, field_desc.index)
+    test.assertEqual(self.number, field_desc.number)
+    test.assertEqual(descriptor.FieldDescriptor.TYPE_STRING, field_desc.type)
+    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_STRING,
+                     field_desc.cpp_type)
+    test.assertTrue(field_desc.has_default_value)
+    test.assertEqual(self.default_value, field_desc.default_value)
+    test.assertEqual(file_desc, field_desc.file)
+
+
+class ExtensionField(object):
+
+  def __init__(self, number, extended_type):
+    self.number = number
+    self.extended_type = extended_type
+
+  def CheckField(self, test, msg_desc, name, index, file_desc):
+    field_desc = msg_desc.extensions_by_name[name]
+    test.assertEqual(name, field_desc.name)
+    expected_field_full_name = '.'.join([msg_desc.full_name, name])
+    test.assertEqual(expected_field_full_name, field_desc.full_name)
+    test.assertEqual(self.number, field_desc.number)
+    test.assertEqual(index, field_desc.index)
+    test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type)
+    test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE,
+                     field_desc.cpp_type)
+    test.assertFalse(field_desc.has_default_value)
+    test.assertTrue(field_desc.is_extension)
+    test.assertEqual(msg_desc, field_desc.extension_scope)
+    test.assertEqual(msg_desc, field_desc.message_type)
+    test.assertEqual(self.extended_type, field_desc.containing_type.name)
+    test.assertEqual(file_desc, field_desc.file)
+
+
+@testing_refleaks.TestCase
+class AddDescriptorTest(unittest.TestCase):
+
+  def _TestMessage(self, prefix):
+    pool = descriptor_pool.DescriptorPool()
+    pool._AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertEqual(
+        'protobuf_unittest.TestAllTypes',
+        pool.FindMessageTypeByName(
+            prefix + 'protobuf_unittest.TestAllTypes').full_name)
+
+    # AddDescriptor is not recursive.
+    with self.assertRaises(KeyError):
+      pool.FindMessageTypeByName(
+          prefix + 'protobuf_unittest.TestAllTypes.NestedMessage')
+
+    pool._AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR)
+    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.assertEqual(
+        'google/protobuf/unittest.proto',
+        pool.FindFileByName(
+            'google/protobuf/unittest.proto').name)
+
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        pool.FindFileContainingSymbol(
+            prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
+
+  @unittest.skipIf(api_implementation.Type() != 'python',
+                   'Only pure python allows _Add*()')
+  def testMessage(self):
+    self._TestMessage('')
+    self._TestMessage('.')
+
+  def _TestEnum(self, prefix):
+    pool = descriptor_pool.DescriptorPool()
+    if api_implementation.Type() == 'cpp':
+      pool.AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+    else:
+      pool._AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+    self.assertEqual(
+        'protobuf_unittest.ForeignEnum',
+        pool.FindEnumTypeByName(
+            prefix + 'protobuf_unittest.ForeignEnum').full_name)
+
+    # AddEnumDescriptor is not recursive.
+    with self.assertRaises(KeyError):
+      pool.FindEnumTypeByName(
+          prefix + 'protobuf_unittest.ForeignEnum.NestedEnum')
+
+    if api_implementation.Type() == 'cpp':
+      pool.AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+    else:
+      pool._AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+    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.assertEqual(
+        'google/protobuf/unittest.proto',
+        pool.FindFileByName(
+            'google/protobuf/unittest.proto').name)
+
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        pool.FindFileContainingSymbol(
+            prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
+
+  @unittest.skipIf(api_implementation.Type() != 'python',
+                   'Only pure python allows _Add*()')
+  def testEnum(self):
+    self._TestEnum('')
+    self._TestEnum('.')
+
+  @unittest.skipIf(api_implementation.Type() != 'python',
+                   'Only pure python allows _Add*()')
+  def testService(self):
+    pool = descriptor_pool.DescriptorPool()
+    with self.assertRaises(KeyError):
+      pool.FindServiceByName('protobuf_unittest.TestService')
+    pool._AddServiceDescriptor(unittest_pb2._TESTSERVICE)
+    self.assertEqual(
+        'protobuf_unittest.TestService',
+        pool.FindServiceByName('protobuf_unittest.TestService').full_name)
+
+  @unittest.skipIf(api_implementation.Type() != 'python',
+                   'Only pure python allows _Add*()')
+  def testFile(self):
+    pool = descriptor_pool.DescriptorPool()
+    pool._AddFileDescriptor(unittest_pb2.DESCRIPTOR)
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        pool.FindFileByName(
+            'google/protobuf/unittest.proto').name)
+
+    # AddFileDescriptor is not recursive; messages and enums within files must
+    # be explicitly registered.
+    with self.assertRaises(KeyError):
+      pool.FindFileContainingSymbol(
+          'protobuf_unittest.TestAllTypes')
+
+  def testEmptyDescriptorPool(self):
+    # Check that an empty DescriptorPool() contains no messages.
+    pool = descriptor_pool.DescriptorPool()
+    proto_file_name = descriptor_pb2.DESCRIPTOR.name
+    self.assertRaises(KeyError, pool.FindFileByName, proto_file_name)
+    # Add the above file to the pool
+    file_descriptor = descriptor_pb2.FileDescriptorProto()
+    descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor)
+    pool.Add(file_descriptor)
+    # Now it exists.
+    self.assertTrue(pool.FindFileByName(proto_file_name))
+
+  def testCustomDescriptorPool(self):
+    # Create a new pool, and add a file descriptor.
+    pool = descriptor_pool.DescriptorPool()
+    file_desc = descriptor_pb2.FileDescriptorProto(
+        name='some/file.proto', package='package')
+    file_desc.message_type.add(name='Message')
+    pool.Add(file_desc)
+    self.assertEqual(pool.FindFileByName('some/file.proto').name,
+                     'some/file.proto')
+    self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
+                     'Message')
+    # Test no package
+    file_proto = descriptor_pb2.FileDescriptorProto(
+        name='some/filename/container.proto')
+    message_proto = file_proto.message_type.add(
+        name='TopMessage')
+    message_proto.field.add(
+        name='bb',
+        number=1,
+        type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL)
+    enum_proto = file_proto.enum_type.add(name='TopEnum')
+    enum_proto.value.add(name='FOREIGN_FOO', number=4)
+    file_proto.service.add(name='TopService')
+    pool = descriptor_pool.DescriptorPool()
+    pool.Add(file_proto)
+    self.assertEqual('TopMessage',
+                     pool.FindMessageTypeByName('TopMessage').name)
+    self.assertEqual('TopEnum', pool.FindEnumTypeByName('TopEnum').name)
+    self.assertEqual('TopService', pool.FindServiceByName('TopService').name)
+
+  def testFileDescriptorOptionsWithCustomDescriptorPool(self):
+    # Create a descriptor pool, and add a new FileDescriptorProto to it.
+    pool = descriptor_pool.DescriptorPool()
+    file_name = 'file_descriptor_options_with_custom_descriptor_pool.proto'
+    file_descriptor_proto = descriptor_pb2.FileDescriptorProto(name=file_name)
+    extension_id = file_options_test_pb2.foo_options
+    file_descriptor_proto.options.Extensions[extension_id].foo_name = 'foo'
+    pool.Add(file_descriptor_proto)
+    # The options set on the FileDescriptorProto should be available in the
+    # descriptor even if they contain extensions that cannot be deserialized
+    # using the pool.
+    file_descriptor = pool.FindFileByName(file_name)
+    options = file_descriptor.GetOptions()
+    self.assertEqual('foo', options.Extensions[extension_id].foo_name)
+    # The object returned by GetOptions() is cached.
+    self.assertIs(options, file_descriptor.GetOptions())
+
+  def testAddTypeError(self):
+    pool = descriptor_pool.DescriptorPool()
+    if api_implementation.Type() != 'python':
+      with self.assertRaises(TypeError):
+        pool.AddDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool.AddEnumDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool.AddServiceDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool.AddExtensionDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool.AddFileDescriptor(0)
+    else:
+      with self.assertRaises(TypeError):
+        pool._AddDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool._AddEnumDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool._AddServiceDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool._AddExtensionDescriptor(0)
+      with self.assertRaises(TypeError):
+        pool._AddFileDescriptor(0)
+
+
+TEST1_FILE = ProtoFile(
+    'google/protobuf/internal/descriptor_pool_test1.proto',
+    'google.protobuf.python.internal',
+    {
+        'DescriptorPoolTest1': MessageType({
+            'NestedEnum': EnumType([('ALPHA', 1), ('BETA', 2)]),
+            'NestedMessage': MessageType({
+                'NestedEnum': EnumType([('EPSILON', 5), ('ZETA', 6)]),
+                'DeepNestedMessage': MessageType({
+                    'NestedEnum': EnumType([('ETA', 7), ('THETA', 8)]),
+                }, [
+                    ('nested_enum', EnumField(1, 'NestedEnum', 'ETA')),
+                    ('nested_field', StringField(2, 'theta')),
+                ]),
+            }, [
+                ('nested_enum', EnumField(1, 'NestedEnum', 'ZETA')),
+                ('nested_field', StringField(2, 'beta')),
+                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
+            ])
+        }, [
+            ('nested_enum', EnumField(1, 'NestedEnum', 'BETA')),
+            ('nested_message', MessageField(2, 'NestedMessage')),
+        ], is_extendable=True),
+
+        'DescriptorPoolTest2': MessageType({
+            'NestedEnum': EnumType([('GAMMA', 3), ('DELTA', 4)]),
+            'NestedMessage': MessageType({
+                'NestedEnum': EnumType([('IOTA', 9), ('KAPPA', 10)]),
+                'DeepNestedMessage': MessageType({
+                    'NestedEnum': EnumType([('LAMBDA', 11), ('MU', 12)]),
+                }, [
+                    ('nested_enum', EnumField(1, 'NestedEnum', 'MU')),
+                    ('nested_field', StringField(2, 'lambda')),
+                ]),
+            }, [
+                ('nested_enum', EnumField(1, 'NestedEnum', 'IOTA')),
+                ('nested_field', StringField(2, 'delta')),
+                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
+            ])
+        }, [
+            ('nested_enum', EnumField(1, 'NestedEnum', 'GAMMA')),
+            ('nested_message', MessageField(2, 'NestedMessage')),
+        ]),
+    })
+
+
+TEST2_FILE = ProtoFile(
+    'google/protobuf/internal/descriptor_pool_test2.proto',
+    'google.protobuf.python.internal',
+    {
+        'DescriptorPoolTest3': MessageType({
+            'NestedEnum': EnumType([('NU', 13), ('XI', 14)]),
+            'NestedMessage': MessageType({
+                'NestedEnum': EnumType([('OMICRON', 15), ('PI', 16)]),
+                'DeepNestedMessage': MessageType({
+                    'NestedEnum': EnumType([('RHO', 17), ('SIGMA', 18)]),
+                }, [
+                    ('nested_enum', EnumField(1, 'NestedEnum', 'RHO')),
+                    ('nested_field', StringField(2, 'sigma')),
+                ]),
+            }, [
+                ('nested_enum', EnumField(1, 'NestedEnum', 'PI')),
+                ('nested_field', StringField(2, 'nu')),
+                ('deep_nested_message', MessageField(3, 'DeepNestedMessage')),
+            ])
+        }, [
+            ('nested_enum', EnumField(1, 'NestedEnum', 'XI')),
+            ('nested_message', MessageField(2, 'NestedMessage')),
+        ], extensions=[
+            ('descriptor_pool_test',
+             ExtensionField(1001, 'DescriptorPoolTest1')),
+        ]),
+    },
+    dependencies=['google/protobuf/internal/descriptor_pool_test1.proto',
+                  'google/protobuf/internal/more_messages.proto'],
+    public_dependencies=['google/protobuf/internal/more_messages.proto'])
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/descriptor_pool_test1.proto b/python/google/protobuf/internal/descriptor_pool_test1.proto
new file mode 100644
index 0000000..00816b7
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_pool_test1.proto
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+
+message DescriptorPoolTest1 {
+  extensions 1000 to max;
+
+  enum NestedEnum {
+    ALPHA = 1;
+    BETA = 2;
+  }
+
+  optional NestedEnum nested_enum = 1 [default = BETA];
+
+  message NestedMessage {
+    enum NestedEnum {
+      EPSILON = 5;
+      ZETA = 6;
+    }
+    optional NestedEnum nested_enum = 1 [default = ZETA];
+    optional string nested_field = 2 [default = "beta"];
+    optional DeepNestedMessage deep_nested_message = 3;
+
+    message DeepNestedMessage {
+      enum NestedEnum {
+        ETA = 7;
+        THETA = 8;
+      }
+      optional NestedEnum nested_enum = 1 [default = ETA];
+      optional string nested_field = 2 [default = "theta"];
+    }
+  }
+
+  optional NestedMessage nested_message = 2;
+}
+
+message DescriptorPoolTest2 {
+  enum NestedEnum {
+    GAMMA = 3;
+    DELTA = 4;
+  }
+
+  optional NestedEnum nested_enum = 1 [default = GAMMA];
+
+  message NestedMessage {
+    enum NestedEnum {
+      IOTA = 9;
+      KAPPA = 10;
+    }
+    optional NestedEnum nested_enum = 1 [default = IOTA];
+    optional string nested_field = 2 [default = "delta"];
+    optional DeepNestedMessage deep_nested_message = 3;
+
+    message DeepNestedMessage {
+      enum NestedEnum {
+        LAMBDA = 11;
+        MU = 12;
+      }
+      optional NestedEnum nested_enum = 1 [default = MU];
+      optional string nested_field = 2 [default = "lambda"];
+    }
+  }
+
+  optional NestedMessage nested_message = 2;
+}
diff --git a/python/google/protobuf/internal/descriptor_pool_test2.proto b/python/google/protobuf/internal/descriptor_pool_test2.proto
new file mode 100644
index 0000000..a218ecc
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_pool_test2.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 = "proto2";
+
+package google.protobuf.python.internal;
+
+import "google/protobuf/internal/descriptor_pool_test1.proto";
+import public "google/protobuf/internal/more_messages.proto";
+
+
+message DescriptorPoolTest3 {
+
+  extend DescriptorPoolTest1 {
+    optional DescriptorPoolTest3 descriptor_pool_test = 1001;
+  }
+
+  enum NestedEnum {
+    NU = 13;
+    XI = 14;
+  }
+
+  optional NestedEnum nested_enum = 1 [default = XI];
+
+  message NestedMessage {
+    enum NestedEnum {
+      OMICRON = 15;
+      PI = 16;
+    }
+    optional NestedEnum nested_enum = 1 [default = PI];
+    optional string nested_field = 2 [default = "nu"];
+    optional DeepNestedMessage deep_nested_message = 3;
+
+    message DeepNestedMessage {
+      enum NestedEnum {
+        RHO = 17;
+        SIGMA = 18;
+      }
+      optional NestedEnum nested_enum = 1 [default = RHO];
+      optional string nested_field = 2 [default = "sigma"];
+    }
+  }
+
+  optional NestedMessage nested_message = 2;
+}
+
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
new file mode 100644
index 0000000..6a8532c
--- /dev/null
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -0,0 +1,1076 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 google.protobuf.internal.descriptor."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import unittest
+import warnings
+
+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
+
+
+TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """
+name: 'TestEmptyMessage'
+"""
+
+TEST_FILE_DESCRIPTOR_DEBUG = """syntax = "proto2";
+
+package protobuf_unittest;
+
+message NestedMessage {
+  enum ForeignEnum {
+    FOREIGN_FOO = 4;
+    FOREIGN_BAR = 5;
+    FOREIGN_BAZ = 6;
+  }
+  optional int32 bb = 1;
+}
+
+message ResponseMessage {
+}
+
+service Service {
+  rpc CallMethod(.protobuf_unittest.NestedMessage) returns (.protobuf_unittest.ResponseMessage);
+}
+
+"""
+
+
+warnings.simplefilter('error', DeprecationWarning)
+
+
+class DescriptorTest(unittest.TestCase):
+
+  def setUp(self):
+    file_proto = descriptor_pb2.FileDescriptorProto(
+        name='some/filename/some.proto',
+        package='protobuf_unittest')
+    message_proto = file_proto.message_type.add(
+        name='NestedMessage')
+    message_proto.field.add(
+        name='bb',
+        number=1,
+        type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL)
+    enum_proto = message_proto.enum_type.add(
+        name='ForeignEnum')
+    enum_proto.value.add(name='FOREIGN_FOO', number=4)
+    enum_proto.value.add(name='FOREIGN_BAR', number=5)
+    enum_proto.value.add(name='FOREIGN_BAZ', number=6)
+
+    file_proto.message_type.add(name='ResponseMessage')
+    service_proto = file_proto.service.add(
+        name='Service')
+    method_proto = service_proto.method.add(
+        name='CallMethod',
+        input_type='.protobuf_unittest.NestedMessage',
+        output_type='.protobuf_unittest.ResponseMessage')
+
+    # Note: Calling DescriptorPool.Add() multiple times with the same file only
+    # works if the input is canonical; in particular, all type names must be
+    # fully qualified.
+    self.pool = self.GetDescriptorPool()
+    self.pool.Add(file_proto)
+    self.my_file = self.pool.FindFileByName(file_proto.name)
+    self.my_message = self.my_file.message_types_by_name[message_proto.name]
+    self.my_enum = self.my_message.enum_types_by_name[enum_proto.name]
+    self.my_service = self.my_file.services_by_name[service_proto.name]
+    self.my_method = self.my_service.methods_by_name[method_proto.name]
+
+  def GetDescriptorPool(self):
+    return symbol_database.Default().pool
+
+  def testEnumValueName(self):
+    self.assertEqual(self.my_message.EnumValueName('ForeignEnum', 4),
+                     'FOREIGN_FOO')
+
+    self.assertEqual(
+        self.my_message.enum_types_by_name[
+            'ForeignEnum'].values_by_number[4].name,
+        self.my_message.EnumValueName('ForeignEnum', 4))
+    with self.assertRaises(KeyError):
+      self.my_message.EnumValueName('ForeignEnum', 999)
+    with self.assertRaises(KeyError):
+      self.my_message.EnumValueName('NoneEnum', 999)
+    with self.assertRaises(TypeError):
+      self.my_message.EnumValueName()
+
+  def testEnumFixups(self):
+    self.assertEqual(self.my_enum, self.my_enum.values[0].type)
+
+  def testContainingTypeFixups(self):
+    self.assertEqual(self.my_message, self.my_message.fields[0].containing_type)
+    self.assertEqual(self.my_message, self.my_enum.containing_type)
+
+  def testContainingServiceFixups(self):
+    self.assertEqual(self.my_service, self.my_method.containing_service)
+
+  @unittest.skipIf(
+      api_implementation.Type() == 'python',
+      'GetDebugString is only available with the cpp implementation',
+  )
+  def testGetDebugString(self):
+    self.assertEqual(self.my_file.GetDebugString(), TEST_FILE_DESCRIPTOR_DEBUG)
+
+  def testGetOptions(self):
+    self.assertEqual(self.my_enum.GetOptions(),
+                     descriptor_pb2.EnumOptions())
+    self.assertEqual(self.my_enum.values[0].GetOptions(),
+                     descriptor_pb2.EnumValueOptions())
+    self.assertEqual(self.my_message.GetOptions(),
+                     descriptor_pb2.MessageOptions())
+    self.assertEqual(self.my_message.fields[0].GetOptions(),
+                     descriptor_pb2.FieldOptions())
+    self.assertEqual(self.my_method.GetOptions(),
+                     descriptor_pb2.MethodOptions())
+    self.assertEqual(self.my_service.GetOptions(),
+                     descriptor_pb2.ServiceOptions())
+
+  def testSimpleCustomOptions(self):
+    file_descriptor = unittest_custom_options_pb2.DESCRIPTOR
+    message_descriptor = (unittest_custom_options_pb2.
+                          TestMessageWithCustomOptions.DESCRIPTOR)
+    field_descriptor = message_descriptor.fields_by_name['field1']
+    oneof_descriptor = message_descriptor.oneofs_by_name['AnOneof']
+    enum_descriptor = message_descriptor.enum_types_by_name['AnEnum']
+    enum_value_descriptor = (message_descriptor.
+                             enum_values_by_name['ANENUM_VAL2'])
+    other_enum_value_descriptor = (message_descriptor.
+                                   enum_values_by_name['ANENUM_VAL1'])
+    service_descriptor = (unittest_custom_options_pb2.
+                          TestServiceWithCustomOptions.DESCRIPTOR)
+    method_descriptor = service_descriptor.FindMethodByName('Foo')
+
+    file_options = file_descriptor.GetOptions()
+    file_opt1 = unittest_custom_options_pb2.file_opt1
+    self.assertEqual(9876543210, file_options.Extensions[file_opt1])
+    message_options = message_descriptor.GetOptions()
+    message_opt1 = unittest_custom_options_pb2.message_opt1
+    self.assertEqual(-56, message_options.Extensions[message_opt1])
+    field_options = field_descriptor.GetOptions()
+    field_opt1 = unittest_custom_options_pb2.field_opt1
+    self.assertEqual(8765432109, field_options.Extensions[field_opt1])
+    field_opt2 = unittest_custom_options_pb2.field_opt2
+    self.assertEqual(42, field_options.Extensions[field_opt2])
+    oneof_options = oneof_descriptor.GetOptions()
+    oneof_opt1 = unittest_custom_options_pb2.oneof_opt1
+    self.assertEqual(-99, oneof_options.Extensions[oneof_opt1])
+    enum_options = enum_descriptor.GetOptions()
+    enum_opt1 = unittest_custom_options_pb2.enum_opt1
+    self.assertEqual(-789, enum_options.Extensions[enum_opt1])
+    enum_value_options = enum_value_descriptor.GetOptions()
+    enum_value_opt1 = unittest_custom_options_pb2.enum_value_opt1
+    self.assertEqual(123, enum_value_options.Extensions[enum_value_opt1])
+
+    service_options = service_descriptor.GetOptions()
+    service_opt1 = unittest_custom_options_pb2.service_opt1
+    self.assertEqual(-9876543210, service_options.Extensions[service_opt1])
+    method_options = method_descriptor.GetOptions()
+    method_opt1 = unittest_custom_options_pb2.method_opt1
+    self.assertEqual(unittest_custom_options_pb2.METHODOPT1_VAL2,
+                     method_options.Extensions[method_opt1])
+
+    message_descriptor = (
+        unittest_custom_options_pb2.DummyMessageContainingEnum.DESCRIPTOR)
+    self.assertTrue(file_descriptor.has_options)
+    self.assertFalse(message_descriptor.has_options)
+    self.assertTrue(field_descriptor.has_options)
+    self.assertTrue(oneof_descriptor.has_options)
+    self.assertTrue(enum_descriptor.has_options)
+    self.assertTrue(enum_value_descriptor.has_options)
+    self.assertFalse(other_enum_value_descriptor.has_options)
+
+  def testCustomOptionsCopyTo(self):
+    message_descriptor = (unittest_custom_options_pb2.
+                          TestMessageWithCustomOptions.DESCRIPTOR)
+    message_proto = descriptor_pb2.DescriptorProto()
+    message_descriptor.CopyToProto(message_proto)
+    self.assertEqual(len(message_proto.options.ListFields()),
+                     2)
+
+  def testDifferentCustomOptionTypes(self):
+    kint32min = -2**31
+    kint64min = -2**63
+    kint32max = 2**31 - 1
+    kint64max = 2**63 - 1
+    kuint32max = 2**32 - 1
+    kuint64max = 2**64 - 1
+
+    message_descriptor =\
+        unittest_custom_options_pb2.CustomOptionMinIntegerValues.DESCRIPTOR
+    message_options = message_descriptor.GetOptions()
+    self.assertEqual(False, message_options.Extensions[
+        unittest_custom_options_pb2.bool_opt])
+    self.assertEqual(kint32min, message_options.Extensions[
+        unittest_custom_options_pb2.int32_opt])
+    self.assertEqual(kint64min, message_options.Extensions[
+        unittest_custom_options_pb2.int64_opt])
+    self.assertEqual(0, message_options.Extensions[
+        unittest_custom_options_pb2.uint32_opt])
+    self.assertEqual(0, message_options.Extensions[
+        unittest_custom_options_pb2.uint64_opt])
+    self.assertEqual(kint32min, message_options.Extensions[
+        unittest_custom_options_pb2.sint32_opt])
+    self.assertEqual(kint64min, message_options.Extensions[
+        unittest_custom_options_pb2.sint64_opt])
+    self.assertEqual(0, message_options.Extensions[
+        unittest_custom_options_pb2.fixed32_opt])
+    self.assertEqual(0, message_options.Extensions[
+        unittest_custom_options_pb2.fixed64_opt])
+    self.assertEqual(kint32min, message_options.Extensions[
+        unittest_custom_options_pb2.sfixed32_opt])
+    self.assertEqual(kint64min, message_options.Extensions[
+        unittest_custom_options_pb2.sfixed64_opt])
+
+    message_descriptor =\
+        unittest_custom_options_pb2.CustomOptionMaxIntegerValues.DESCRIPTOR
+    message_options = message_descriptor.GetOptions()
+    self.assertEqual(True, message_options.Extensions[
+        unittest_custom_options_pb2.bool_opt])
+    self.assertEqual(kint32max, message_options.Extensions[
+        unittest_custom_options_pb2.int32_opt])
+    self.assertEqual(kint64max, message_options.Extensions[
+        unittest_custom_options_pb2.int64_opt])
+    self.assertEqual(kuint32max, message_options.Extensions[
+        unittest_custom_options_pb2.uint32_opt])
+    self.assertEqual(kuint64max, message_options.Extensions[
+        unittest_custom_options_pb2.uint64_opt])
+    self.assertEqual(kint32max, message_options.Extensions[
+        unittest_custom_options_pb2.sint32_opt])
+    self.assertEqual(kint64max, message_options.Extensions[
+        unittest_custom_options_pb2.sint64_opt])
+    self.assertEqual(kuint32max, message_options.Extensions[
+        unittest_custom_options_pb2.fixed32_opt])
+    self.assertEqual(kuint64max, message_options.Extensions[
+        unittest_custom_options_pb2.fixed64_opt])
+    self.assertEqual(kint32max, message_options.Extensions[
+        unittest_custom_options_pb2.sfixed32_opt])
+    self.assertEqual(kint64max, message_options.Extensions[
+        unittest_custom_options_pb2.sfixed64_opt])
+
+    message_descriptor =\
+        unittest_custom_options_pb2.CustomOptionOtherValues.DESCRIPTOR
+    message_options = message_descriptor.GetOptions()
+    self.assertEqual(-100, message_options.Extensions[
+        unittest_custom_options_pb2.int32_opt])
+    self.assertAlmostEqual(12.3456789, message_options.Extensions[
+        unittest_custom_options_pb2.float_opt], 6)
+    self.assertAlmostEqual(1.234567890123456789, message_options.Extensions[
+        unittest_custom_options_pb2.double_opt])
+    self.assertEqual("Hello, \"World\"", message_options.Extensions[
+        unittest_custom_options_pb2.string_opt])
+    self.assertEqual(b"Hello\0World", message_options.Extensions[
+        unittest_custom_options_pb2.bytes_opt])
+    dummy_enum = unittest_custom_options_pb2.DummyMessageContainingEnum
+    self.assertEqual(
+        dummy_enum.TEST_OPTION_ENUM_TYPE2,
+        message_options.Extensions[unittest_custom_options_pb2.enum_opt])
+
+    message_descriptor =\
+        unittest_custom_options_pb2.SettingRealsFromPositiveInts.DESCRIPTOR
+    message_options = message_descriptor.GetOptions()
+    self.assertAlmostEqual(12, message_options.Extensions[
+        unittest_custom_options_pb2.float_opt], 6)
+    self.assertAlmostEqual(154, message_options.Extensions[
+        unittest_custom_options_pb2.double_opt])
+
+    message_descriptor =\
+        unittest_custom_options_pb2.SettingRealsFromNegativeInts.DESCRIPTOR
+    message_options = message_descriptor.GetOptions()
+    self.assertAlmostEqual(-12, message_options.Extensions[
+        unittest_custom_options_pb2.float_opt], 6)
+    self.assertAlmostEqual(-154, message_options.Extensions[
+        unittest_custom_options_pb2.double_opt])
+
+  def testComplexExtensionOptions(self):
+    descriptor =\
+        unittest_custom_options_pb2.VariousComplexOptions.DESCRIPTOR
+    options = descriptor.GetOptions()
+    self.assertEqual(42, options.Extensions[
+        unittest_custom_options_pb2.complex_opt1].foo)
+    self.assertEqual(324, options.Extensions[
+        unittest_custom_options_pb2.complex_opt1].Extensions[
+            unittest_custom_options_pb2.mooo])
+    self.assertEqual(876, options.Extensions[
+        unittest_custom_options_pb2.complex_opt1].Extensions[
+            unittest_custom_options_pb2.corge].moo)
+    self.assertEqual(987, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].baz)
+    self.assertEqual(654, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].Extensions[
+            unittest_custom_options_pb2.grault])
+    self.assertEqual(743, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].bar.foo)
+    self.assertEqual(1999, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].bar.Extensions[
+            unittest_custom_options_pb2.mooo])
+    self.assertEqual(2008, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].bar.Extensions[
+            unittest_custom_options_pb2.corge].moo)
+    self.assertEqual(741, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].Extensions[
+            unittest_custom_options_pb2.garply].foo)
+    self.assertEqual(1998, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].Extensions[
+            unittest_custom_options_pb2.garply].Extensions[
+                unittest_custom_options_pb2.mooo])
+    self.assertEqual(2121, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].Extensions[
+            unittest_custom_options_pb2.garply].Extensions[
+                unittest_custom_options_pb2.corge].moo)
+    self.assertEqual(1971, options.Extensions[
+        unittest_custom_options_pb2.ComplexOptionType2
+        .ComplexOptionType4.complex_opt4].waldo)
+    self.assertEqual(321, options.Extensions[
+        unittest_custom_options_pb2.complex_opt2].fred.waldo)
+    self.assertEqual(9, options.Extensions[
+        unittest_custom_options_pb2.complex_opt3].moo)
+    self.assertEqual(22, options.Extensions[
+        unittest_custom_options_pb2.complex_opt3].complexoptiontype5.plugh)
+    self.assertEqual(24, options.Extensions[
+        unittest_custom_options_pb2.complexopt6].xyzzy)
+
+  # Check that aggregate options were parsed and saved correctly in
+  # the appropriate descriptors.
+  def testAggregateOptions(self):
+    file_descriptor = unittest_custom_options_pb2.DESCRIPTOR
+    message_descriptor =\
+        unittest_custom_options_pb2.AggregateMessage.DESCRIPTOR
+    field_descriptor = message_descriptor.fields_by_name["fieldname"]
+    enum_descriptor = unittest_custom_options_pb2.AggregateEnum.DESCRIPTOR
+    enum_value_descriptor = enum_descriptor.values_by_name["VALUE"]
+    service_descriptor =\
+        unittest_custom_options_pb2.AggregateService.DESCRIPTOR
+    method_descriptor = service_descriptor.FindMethodByName("Method")
+
+    # Tests for the different types of data embedded in fileopt
+    file_options = file_descriptor.GetOptions().Extensions[
+        unittest_custom_options_pb2.fileopt]
+    self.assertEqual(100, file_options.i)
+    self.assertEqual("FileAnnotation", file_options.s)
+    self.assertEqual("NestedFileAnnotation", file_options.sub.s)
+    self.assertEqual("FileExtensionAnnotation", file_options.file.Extensions[
+        unittest_custom_options_pb2.fileopt].s)
+    self.assertEqual("EmbeddedMessageSetElement", file_options.mset.Extensions[
+        unittest_custom_options_pb2.AggregateMessageSetElement
+        .message_set_extension].s)
+
+    # Simple tests for all the other types of annotations
+    self.assertEqual(
+        "MessageAnnotation",
+        message_descriptor.GetOptions().Extensions[
+            unittest_custom_options_pb2.msgopt].s)
+    self.assertEqual(
+        "FieldAnnotation",
+        field_descriptor.GetOptions().Extensions[
+            unittest_custom_options_pb2.fieldopt].s)
+    self.assertEqual(
+        "EnumAnnotation",
+        enum_descriptor.GetOptions().Extensions[
+            unittest_custom_options_pb2.enumopt].s)
+    self.assertEqual(
+        "EnumValueAnnotation",
+        enum_value_descriptor.GetOptions().Extensions[
+            unittest_custom_options_pb2.enumvalopt].s)
+    self.assertEqual(
+        "ServiceAnnotation",
+        service_descriptor.GetOptions().Extensions[
+            unittest_custom_options_pb2.serviceopt].s)
+    self.assertEqual(
+        "MethodAnnotation",
+        method_descriptor.GetOptions().Extensions[
+            unittest_custom_options_pb2.methodopt].s)
+
+  def testNestedOptions(self):
+    nested_message =\
+        unittest_custom_options_pb2.NestedOptionType.NestedMessage.DESCRIPTOR
+    self.assertEqual(1001, nested_message.GetOptions().Extensions[
+        unittest_custom_options_pb2.message_opt1])
+    nested_field = nested_message.fields_by_name["nested_field"]
+    self.assertEqual(1002, nested_field.GetOptions().Extensions[
+        unittest_custom_options_pb2.field_opt1])
+    outer_message =\
+        unittest_custom_options_pb2.NestedOptionType.DESCRIPTOR
+    nested_enum = outer_message.enum_types_by_name["NestedEnum"]
+    self.assertEqual(1003, nested_enum.GetOptions().Extensions[
+        unittest_custom_options_pb2.enum_opt1])
+    nested_enum_value = outer_message.enum_values_by_name["NESTED_ENUM_VALUE"]
+    self.assertEqual(1004, nested_enum_value.GetOptions().Extensions[
+        unittest_custom_options_pb2.enum_value_opt1])
+    nested_extension = outer_message.extensions_by_name["nested_extension"]
+    self.assertEqual(1005, nested_extension.GetOptions().Extensions[
+        unittest_custom_options_pb2.field_opt2])
+
+  def testFileDescriptorReferences(self):
+    self.assertEqual(self.my_enum.file, self.my_file)
+    self.assertEqual(self.my_message.file, self.my_file)
+
+  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)
+    self.assertFalse(self.my_file.has_options)
+    self.assertEqual('proto2', self.my_file.syntax)
+    file_proto = descriptor_pb2.FileDescriptorProto()
+    self.my_file.CopyToProto(file_proto)
+    self.assertEqual(self.my_file.serialized_pb,
+                     file_proto.SerializeToString())
+    # Generated modules also belong to the default pool.
+    self.assertEqual(unittest_pb2.DESCRIPTOR.pool, descriptor_pool.Default())
+
+  @unittest.skipIf(
+      api_implementation.Type() == 'python',
+      'Immutability of descriptors is only enforced in v2 implementation')
+  def testImmutableCppDescriptor(self):
+    file_descriptor = unittest_pb2.DESCRIPTOR
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    field_descriptor = message_descriptor.fields_by_name['optional_int32']
+    enum_descriptor = message_descriptor.enum_types_by_name['NestedEnum']
+    oneof_descriptor = message_descriptor.oneofs_by_name['oneof_field']
+    with self.assertRaises(AttributeError):
+      message_descriptor.fields_by_name = None
+    with self.assertRaises(TypeError):
+      message_descriptor.fields_by_name['Another'] = None
+    with self.assertRaises(TypeError):
+      message_descriptor.fields.append(None)
+    with self.assertRaises(AttributeError):
+      field_descriptor.containing_type = message_descriptor
+    with self.assertRaises(AttributeError):
+      file_descriptor.has_options = False
+    with self.assertRaises(AttributeError):
+      field_descriptor.has_options = False
+    with self.assertRaises(AttributeError):
+      oneof_descriptor.has_options = False
+    with self.assertRaises(AttributeError):
+      enum_descriptor.has_options = False
+    with self.assertRaises(AttributeError) as e:
+      message_descriptor.has_options = True
+    self.assertEqual('attribute is not writable: has_options',
+                     str(e.exception))
+
+  def testDefault(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    field = message_descriptor.fields_by_name['repeated_int32']
+    self.assertEqual(field.default_value, [])
+    field = message_descriptor.fields_by_name['repeated_nested_message']
+    self.assertEqual(field.default_value, [])
+    field = message_descriptor.fields_by_name['optionalgroup']
+    self.assertEqual(field.default_value, None)
+    field = message_descriptor.fields_by_name['optional_nested_message']
+    self.assertEqual(field.default_value, None)
+
+
+class NewDescriptorTest(DescriptorTest):
+  """Redo the same tests as above, but with a separate DescriptorPool."""
+
+  def GetDescriptorPool(self):
+    return descriptor_pool.DescriptorPool()
+
+
+class GeneratedDescriptorTest(unittest.TestCase):
+  """Tests for the properties of descriptors in generated code."""
+
+  def CheckMessageDescriptor(self, message_descriptor):
+    # Basic properties
+    self.assertEqual(message_descriptor.name, 'TestAllTypes')
+    self.assertEqual(message_descriptor.full_name,
+                     'protobuf_unittest.TestAllTypes')
+    # Test equality and hashability
+    self.assertEqual(message_descriptor, message_descriptor)
+    self.assertEqual(message_descriptor.fields[0].containing_type,
+                     message_descriptor)
+    self.assertIn(message_descriptor, [message_descriptor])
+    self.assertIn(message_descriptor, {message_descriptor: None})
+    # Test field containers
+    self.CheckDescriptorSequence(message_descriptor.fields)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_name)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_number)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_camelcase_name)
+    self.CheckDescriptorMapping(message_descriptor.enum_types_by_name)
+    self.CheckDescriptorMapping(message_descriptor.enum_values_by_name)
+    self.CheckDescriptorMapping(message_descriptor.oneofs_by_name)
+    self.CheckDescriptorMapping(message_descriptor.enum_types[0].values_by_name)
+    # Test extension range
+    self.assertEqual(message_descriptor.extension_ranges, [])
+
+  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')
+    self.assertEqual(field_descriptor.file, unittest_pb2.DESCRIPTOR)
+    # Test equality and hashability
+    self.assertEqual(field_descriptor, field_descriptor)
+    self.assertEqual(
+        field_descriptor.containing_type.fields_by_name['optional_int32'],
+        field_descriptor)
+    self.assertEqual(
+        field_descriptor.containing_type.fields_by_camelcase_name[
+            'optionalInt32'],
+        field_descriptor)
+    self.assertIn(field_descriptor, [field_descriptor])
+    self.assertIn(field_descriptor, {field_descriptor: None})
+    self.assertEqual(None, field_descriptor.extension_scope)
+    self.assertEqual(None, field_descriptor.enum_type)
+    self.assertTrue(field_descriptor.has_presence)
+    if api_implementation.Type() == 'cpp':
+      # For test coverage only
+      self.assertEqual(field_descriptor.id, field_descriptor.id)
+
+  def CheckDescriptorSequence(self, sequence):
+    # Verifies that a property like 'messageDescriptor.fields' has all the
+    # properties of an immutable abc.Sequence.
+    self.assertNotEqual(sequence,
+                        unittest_pb2.TestAllExtensions.DESCRIPTOR.fields)
+    self.assertNotEqual(sequence, [])
+    self.assertNotEqual(sequence, 1)
+    self.assertFalse(sequence == 1)  # Only for cpp test coverage
+    self.assertEqual(sequence, sequence)
+    expected_list = list(sequence)
+    self.assertEqual(expected_list, sequence)
+    self.assertGreater(len(sequence), 0)  # Sized
+    self.assertEqual(len(sequence), len(expected_list))  # Iterable
+    self.assertEqual(sequence[len(sequence) -1], sequence[-1])
+    item = sequence[0]
+    self.assertEqual(item, sequence[0])
+    self.assertIn(item, sequence)  # Container
+    self.assertEqual(sequence.index(item), 0)
+    self.assertEqual(sequence.count(item), 1)
+    other_item = unittest_pb2.NestedTestAllTypes.DESCRIPTOR.fields[0]
+    self.assertNotIn(other_item, sequence)
+    self.assertEqual(sequence.count(other_item), 0)
+    self.assertRaises(ValueError, sequence.index, other_item)
+    self.assertRaises(ValueError, sequence.index, [])
+    reversed_iterator = reversed(sequence)
+    self.assertEqual(list(reversed_iterator), list(sequence)[::-1])
+    self.assertRaises(StopIteration, next, reversed_iterator)
+    expected_list[0] = 'change value'
+    self.assertNotEqual(expected_list, sequence)
+    # TODO(jieluo): Change __repr__ support for DescriptorSequence.
+    if api_implementation.Type() == 'python':
+      self.assertEqual(str(list(sequence)), str(sequence))
+    else:
+      self.assertEqual(str(sequence)[0], '<')
+
+  def CheckDescriptorMapping(self, mapping):
+    # Verifies that a property like 'messageDescriptor.fields' has all the
+    # properties of an immutable abc.Mapping.
+    self.assertNotEqual(
+        mapping, unittest_pb2.TestAllExtensions.DESCRIPTOR.fields_by_name)
+    self.assertNotEqual(mapping, {})
+    self.assertNotEqual(mapping, 1)
+    self.assertFalse(mapping == 1)  # Only for cpp test coverage
+    excepted_dict = dict(mapping.items())
+    self.assertEqual(mapping, excepted_dict)
+    self.assertEqual(mapping, mapping)
+    self.assertGreater(len(mapping), 0)  # Sized
+    self.assertEqual(len(mapping), len(excepted_dict))  # Iterable
+    key, item = next(iter(mapping.items()))
+    self.assertIn(key, mapping)  # Container
+    self.assertEqual(mapping.get(key), item)
+    with self.assertRaises(TypeError):
+      mapping.get()
+    # TODO(jieluo): Fix python and cpp extension diff.
+    if api_implementation.Type() == 'python':
+      self.assertRaises(TypeError, mapping.get, [])
+    else:
+      self.assertEqual(None, mapping.get([]))
+    # keys(), iterkeys() &co
+    item = (next(iter(mapping.keys())), next(iter(mapping.values())))
+    self.assertEqual(item, next(iter(mapping.items())))
+    excepted_dict[key] = 'change value'
+    self.assertNotEqual(mapping, excepted_dict)
+    del excepted_dict[key]
+    excepted_dict['new_key'] = 'new'
+    self.assertNotEqual(mapping, excepted_dict)
+    self.assertRaises(KeyError, mapping.__getitem__, 'key_error')
+    self.assertRaises(KeyError, mapping.__getitem__, len(mapping) + 1)
+    # TODO(jieluo): Add __repr__ support for DescriptorMapping.
+    if api_implementation.Type() == 'python':
+      self.assertEqual(len(str(dict(mapping.items()))), len(str(mapping)))
+    else:
+      self.assertEqual(str(mapping)[0], '<')
+
+  def testDescriptor(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    self.CheckMessageDescriptor(message_descriptor)
+    field_descriptor = message_descriptor.fields_by_name['optional_int32']
+    self.CheckFieldDescriptor(field_descriptor)
+    field_descriptor = message_descriptor.fields_by_camelcase_name[
+        'optionalInt32']
+    self.CheckFieldDescriptor(field_descriptor)
+    enum_descriptor = unittest_pb2.DESCRIPTOR.enum_types_by_name[
+        'ForeignEnum']
+    self.assertEqual(None, enum_descriptor.containing_type)
+    # Test extension range
+    self.assertEqual(
+        unittest_pb2.TestAllExtensions.DESCRIPTOR.extension_ranges,
+        [(1, 536870912)])
+    self.assertEqual(
+        unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR.extension_ranges,
+        [(42, 43), (4143, 4244), (65536, 536870912)])
+
+  def testCppDescriptorContainer(self):
+    containing_file = unittest_pb2.DESCRIPTOR
+    self.CheckDescriptorSequence(containing_file.dependencies)
+    self.CheckDescriptorMapping(containing_file.message_types_by_name)
+    self.CheckDescriptorMapping(containing_file.enum_types_by_name)
+    self.CheckDescriptorMapping(containing_file.services_by_name)
+    self.CheckDescriptorMapping(containing_file.extensions_by_name)
+    self.CheckDescriptorMapping(
+        unittest_pb2.TestNestedExtension.DESCRIPTOR.extensions_by_name)
+
+  def testCppDescriptorContainer_Iterator(self):
+    # Same test with the iterator
+    enum = unittest_pb2.TestAllTypes.DESCRIPTOR.enum_types_by_name['NestedEnum']
+    values_iter = iter(enum.values)
+    del enum
+    self.assertEqual('FOO', next(values_iter).name)
+
+  def testDescriptorNestedTypesContainer(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    nested_message_descriptor = unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR
+    self.assertEqual(len(message_descriptor.nested_types), 3)
+    self.assertFalse(None in message_descriptor.nested_types)
+    self.assertTrue(
+        nested_message_descriptor in message_descriptor.nested_types)
+
+  def testServiceDescriptor(self):
+    service_descriptor = unittest_pb2.DESCRIPTOR.services_by_name['TestService']
+    self.assertEqual(service_descriptor.name, 'TestService')
+    self.assertEqual(service_descriptor.methods[0].name, 'Foo')
+    self.assertIs(service_descriptor.file, unittest_pb2.DESCRIPTOR)
+    self.assertEqual(service_descriptor.index, 0)
+    self.CheckDescriptorMapping(service_descriptor.methods_by_name)
+
+  def testOneofDescriptor(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    oneof_descriptor = message_descriptor.oneofs_by_name['oneof_field']
+    self.assertFalse(oneof_descriptor.has_options)
+    self.assertEqual(message_descriptor, oneof_descriptor.containing_type)
+    self.assertEqual('oneof_field', oneof_descriptor.name)
+    self.assertEqual('protobuf_unittest.TestAllTypes.oneof_field',
+                     oneof_descriptor.full_name)
+    self.assertEqual(0, oneof_descriptor.index)
+
+
+class DescriptorCopyToProtoTest(unittest.TestCase):
+  """Tests for CopyTo functions of Descriptor."""
+
+  def _AssertProtoEqual(self, actual_proto, expected_class, expected_ascii):
+    expected_proto = expected_class()
+    text_format.Merge(expected_ascii, expected_proto)
+
+    self.assertEqual(
+        actual_proto, expected_proto,
+        'Not equal,\nActual:\n%s\nExpected:\n%s\n'
+        % (str(actual_proto), str(expected_proto)))
+
+  def _InternalTestCopyToProto(self, desc, expected_proto_class,
+                               expected_proto_ascii):
+    actual = expected_proto_class()
+    desc.CopyToProto(actual)
+    self._AssertProtoEqual(
+        actual, expected_proto_class, expected_proto_ascii)
+
+  def testCopyToProto_EmptyMessage(self):
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestEmptyMessage.DESCRIPTOR,
+        descriptor_pb2.DescriptorProto,
+        TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII)
+
+  def testCopyToProto_NestedMessage(self):
+    TEST_NESTED_MESSAGE_ASCII = """
+      name: 'NestedMessage'
+      field: <
+        name: 'bb'
+        number: 1
+        label: 1  # Optional
+        type: 5  # TYPE_INT32
+      >
+      """
+
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR,
+        descriptor_pb2.DescriptorProto,
+        TEST_NESTED_MESSAGE_ASCII)
+
+  def testCopyToProto_ForeignNestedMessage(self):
+    TEST_FOREIGN_NESTED_ASCII = """
+      name: 'TestForeignNested'
+      field: <
+        name: 'foreign_nested'
+        number: 1
+        label: 1  # Optional
+        type: 11  # TYPE_MESSAGE
+        type_name: '.protobuf_unittest.TestAllTypes.NestedMessage'
+      >
+      """
+
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestForeignNested.DESCRIPTOR,
+        descriptor_pb2.DescriptorProto,
+        TEST_FOREIGN_NESTED_ASCII)
+
+  def testCopyToProto_ForeignEnum(self):
+    TEST_FOREIGN_ENUM_ASCII = """
+      name: 'ForeignEnum'
+      value: <
+        name: 'FOREIGN_FOO'
+        number: 4
+      >
+      value: <
+        name: 'FOREIGN_BAR'
+        number: 5
+      >
+      value: <
+        name: 'FOREIGN_BAZ'
+        number: 6
+      >
+      """
+
+    self._InternalTestCopyToProto(
+        unittest_pb2.ForeignEnum.DESCRIPTOR,
+        descriptor_pb2.EnumDescriptorProto,
+        TEST_FOREIGN_ENUM_ASCII)
+
+  def testCopyToProto_Options(self):
+    TEST_DEPRECATED_FIELDS_ASCII = """
+      name: 'TestDeprecatedFields'
+      field: <
+        name: 'deprecated_int32'
+        number: 1
+        label: 1  # Optional
+        type: 5  # TYPE_INT32
+        options: <
+          deprecated: true
+        >
+      >
+      field {
+        name: "deprecated_int32_in_oneof"
+        number: 2
+        label: LABEL_OPTIONAL
+        type: TYPE_INT32
+        options {
+          deprecated: true
+        }
+        oneof_index: 0
+      }
+      oneof_decl {
+        name: "oneof_fields"
+      }
+      """
+
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestDeprecatedFields.DESCRIPTOR,
+        descriptor_pb2.DescriptorProto,
+        TEST_DEPRECATED_FIELDS_ASCII)
+
+  def testCopyToProto_AllExtensions(self):
+    TEST_EMPTY_MESSAGE_WITH_EXTENSIONS_ASCII = """
+      name: 'TestEmptyMessageWithExtensions'
+      extension_range: <
+        start: 1
+        end: 536870912
+      >
+      """
+
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestEmptyMessageWithExtensions.DESCRIPTOR,
+        descriptor_pb2.DescriptorProto,
+        TEST_EMPTY_MESSAGE_WITH_EXTENSIONS_ASCII)
+
+  def testCopyToProto_SeveralExtensions(self):
+    TEST_MESSAGE_WITH_SEVERAL_EXTENSIONS_ASCII = """
+      name: 'TestMultipleExtensionRanges'
+      extension_range: <
+        start: 42
+        end: 43
+      >
+      extension_range: <
+        start: 4143
+        end: 4244
+      >
+      extension_range: <
+        start: 65536
+        end: 536870912
+      >
+      """
+
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR,
+        descriptor_pb2.DescriptorProto,
+        TEST_MESSAGE_WITH_SEVERAL_EXTENSIONS_ASCII)
+
+  def testCopyToProto_FileDescriptor(self):
+    UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII = ("""
+      name: 'google/protobuf/unittest_import.proto'
+      package: 'protobuf_unittest_import'
+      dependency: 'google/protobuf/unittest_import_public.proto'
+      message_type: <
+        name: 'ImportMessage'
+        field: <
+          name: 'd'
+          number: 1
+          label: 1  # Optional
+          type: 5  # TYPE_INT32
+        >
+      >
+      """ +
+      """enum_type: <
+        name: 'ImportEnum'
+        value: <
+          name: 'IMPORT_FOO'
+          number: 7
+        >
+        value: <
+          name: 'IMPORT_BAR'
+          number: 8
+        >
+        value: <
+          name: 'IMPORT_BAZ'
+          number: 9
+        >
+      >
+      enum_type: <
+        name: 'ImportEnumForMap'
+        value: <
+          name: 'UNKNOWN'
+          number: 0
+        >
+        value: <
+          name: 'FOO'
+          number: 1
+        >
+        value: <
+          name: 'BAR'
+          number: 2
+        >
+      >
+      options: <
+        java_package: 'com.google.protobuf.test'
+        optimize_for: 1  # SPEED
+      """ +
+      """
+        cc_enable_arenas: true
+      >
+      public_dependency: 0
+    """)
+    self._InternalTestCopyToProto(
+        unittest_import_pb2.DESCRIPTOR,
+        descriptor_pb2.FileDescriptorProto,
+        UNITTEST_IMPORT_FILE_DESCRIPTOR_ASCII)
+
+  def testCopyToProto_ServiceDescriptor(self):
+    TEST_SERVICE_ASCII = """
+      name: 'TestService'
+      method: <
+        name: 'Foo'
+        input_type: '.protobuf_unittest.FooRequest'
+        output_type: '.protobuf_unittest.FooResponse'
+      >
+      method: <
+        name: 'Bar'
+        input_type: '.protobuf_unittest.BarRequest'
+        output_type: '.protobuf_unittest.BarResponse'
+      >
+      """
+    self._InternalTestCopyToProto(
+        unittest_pb2.TestService.DESCRIPTOR,
+        descriptor_pb2.ServiceDescriptorProto,
+        TEST_SERVICE_ASCII)
+
+  def testCopyToProto_MethodDescriptor(self):
+    expected_ascii = """
+      name: 'Foo'
+      input_type: '.protobuf_unittest.FooRequest'
+      output_type: '.protobuf_unittest.FooResponse'
+    """
+    method_descriptor = unittest_pb2.TestService.DESCRIPTOR.FindMethodByName(
+        'Foo')
+    self._InternalTestCopyToProto(
+        method_descriptor,
+        descriptor_pb2.MethodDescriptorProto,
+        expected_ascii)
+
+  @unittest.skipIf(
+      api_implementation.Type() == 'python',
+      'Pure python does not raise error.')
+  # TODO(jieluo): Fix pure python to check with the proto type.
+  def testCopyToProto_TypeError(self):
+    file_proto = descriptor_pb2.FileDescriptorProto()
+    self.assertRaises(TypeError,
+                      unittest_pb2.TestEmptyMessage.DESCRIPTOR.CopyToProto,
+                      file_proto)
+    self.assertRaises(TypeError,
+                      unittest_pb2.ForeignEnum.DESCRIPTOR.CopyToProto,
+                      file_proto)
+    self.assertRaises(TypeError,
+                      unittest_pb2.TestService.DESCRIPTOR.CopyToProto,
+                      file_proto)
+    proto = descriptor_pb2.DescriptorProto()
+    self.assertRaises(TypeError,
+                      unittest_import_pb2.DESCRIPTOR.CopyToProto,
+                      proto)
+
+
+class MakeDescriptorTest(unittest.TestCase):
+
+  def testMakeDescriptorWithNestedFields(self):
+    file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+    file_descriptor_proto.name = 'Foo2'
+    message_type = file_descriptor_proto.message_type.add()
+    message_type.name = file_descriptor_proto.name
+    nested_type = message_type.nested_type.add()
+    nested_type.name = 'Sub'
+    enum_type = nested_type.enum_type.add()
+    enum_type.name = 'FOO'
+    enum_type_val = enum_type.value.add()
+    enum_type_val.name = 'BAR'
+    enum_type_val.number = 3
+    field = message_type.field.add()
+    field.number = 1
+    field.name = 'uint64_field'
+    field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+    field.type = descriptor.FieldDescriptor.TYPE_UINT64
+    field = message_type.field.add()
+    field.number = 2
+    field.name = 'nested_message_field'
+    field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+    field.type = descriptor.FieldDescriptor.TYPE_MESSAGE
+    field.type_name = 'Sub'
+    enum_field = nested_type.field.add()
+    enum_field.number = 2
+    enum_field.name = 'bar_field'
+    enum_field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+    enum_field.type = descriptor.FieldDescriptor.TYPE_ENUM
+    enum_field.type_name = 'Foo2.Sub.FOO'
+
+    result = descriptor.MakeDescriptor(message_type)
+    self.assertEqual(result.fields[0].cpp_type,
+                     descriptor.FieldDescriptor.CPPTYPE_UINT64)
+    self.assertEqual(result.fields[1].cpp_type,
+                     descriptor.FieldDescriptor.CPPTYPE_MESSAGE)
+    self.assertEqual(result.fields[1].message_type.containing_type,
+                     result)
+    self.assertEqual(result.nested_types[0].fields[0].full_name,
+                     'Foo2.Sub.bar_field')
+    self.assertEqual(result.nested_types[0].fields[0].enum_type,
+                     result.nested_types[0].enum_types[0])
+    self.assertFalse(result.has_options)
+    self.assertFalse(result.fields[0].has_options)
+    if api_implementation.Type() == 'cpp':
+      with self.assertRaises(AttributeError):
+        result.fields[0].has_options = False
+
+  def testMakeDescriptorWithUnsignedIntField(self):
+    file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+    file_descriptor_proto.name = 'Foo'
+    message_type = file_descriptor_proto.message_type.add()
+    message_type.name = file_descriptor_proto.name
+    enum_type = message_type.enum_type.add()
+    enum_type.name = 'FOO'
+    enum_type_val = enum_type.value.add()
+    enum_type_val.name = 'BAR'
+    enum_type_val.number = 3
+    field = message_type.field.add()
+    field.number = 1
+    field.name = 'uint64_field'
+    field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+    field.type = descriptor.FieldDescriptor.TYPE_UINT64
+    enum_field = message_type.field.add()
+    enum_field.number = 2
+    enum_field.name = 'bar_field'
+    enum_field.label = descriptor.FieldDescriptor.LABEL_REQUIRED
+    enum_field.type = descriptor.FieldDescriptor.TYPE_ENUM
+    enum_field.type_name = 'Foo.FOO'
+
+    result = descriptor.MakeDescriptor(message_type)
+    self.assertEqual(result.fields[0].cpp_type,
+                     descriptor.FieldDescriptor.CPPTYPE_UINT64)
+
+
+  def testMakeDescriptorWithOptions(self):
+    descriptor_proto = descriptor_pb2.DescriptorProto()
+    aggregate_message = unittest_custom_options_pb2.AggregateMessage
+    aggregate_message.DESCRIPTOR.CopyToProto(descriptor_proto)
+    reformed_descriptor = descriptor.MakeDescriptor(descriptor_proto)
+
+    options = reformed_descriptor.GetOptions()
+    self.assertEqual(101,
+                      options.Extensions[unittest_custom_options_pb2.msgopt].i)
+
+  def testCamelcaseName(self):
+    descriptor_proto = descriptor_pb2.DescriptorProto()
+    descriptor_proto.name = 'Bar'
+    names = ['foo_foo', 'FooBar', 'fooBaz', 'fooFoo', 'foobar']
+    camelcase_names = ['fooFoo', 'fooBar', 'fooBaz', 'fooFoo', 'foobar']
+    for index in range(len(names)):
+      field = descriptor_proto.field.add()
+      field.number = index + 1
+      field.name = names[index]
+    result = descriptor.MakeDescriptor(descriptor_proto)
+    for index in range(len(camelcase_names)):
+      self.assertEqual(result.fields[index].camelcase_name,
+                       camelcase_names[index])
+
+  def testJsonName(self):
+    descriptor_proto = descriptor_pb2.DescriptorProto()
+    descriptor_proto.name = 'TestJsonName'
+    names = ['field_name', 'fieldName', 'FieldName',
+             '_field_name', 'FIELD_NAME', 'json_name']
+    json_names = ['fieldName', 'fieldName', 'FieldName',
+                  'FieldName', 'FIELDNAME', '@type']
+    for index in range(len(names)):
+      field = descriptor_proto.field.add()
+      field.number = index + 1
+      field.name = names[index]
+    field.json_name = '@type'
+    result = descriptor.MakeDescriptor(descriptor_proto)
+    for index in range(len(json_names)):
+      self.assertEqual(result.fields[index].json_name,
+                       json_names[index])
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
new file mode 100644
index 0000000..4b4f652
--- /dev/null
+++ b/python/google/protobuf/internal/encoder.py
@@ -0,0 +1,829 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Code for encoding protocol message primitives.
+
+Contains the logic for encoding every logical protocol field type
+into one of the 5 physical wire types.
+
+This code is designed to push the Python interpreter's performance to the
+limits.
+
+The basic idea is that at startup time, for every field (i.e. every
+FieldDescriptor) we construct two functions:  a "sizer" and an "encoder".  The
+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 BytesIO.
+
+We try to do as much work as possible when constructing the writer and the
+sizer rather than when calling them.  In particular:
+* We copy any needed global functions to local variables, so that we do not need
+  to do costly global table lookups at runtime.
+* Similarly, we try to do any attribute lookups at startup time if possible.
+* Every field's tag is encoded to bytes at startup, since it can't change at
+  runtime.
+* Whatever component of the field size we can compute at startup, we do.
+* We *avoid* sharing code if doing so would make the code slower and not sharing
+  does not burden us too much.  For example, encoders for repeated fields do
+  not just call the encoders for singular fields in a loop because this would
+  add an extra function call overhead for every loop iteration; instead, we
+  manually inline the single-value encoder into the loop.
+* If a Python function lacks a return statement, Python actually generates
+  instructions to pop the result of the last statement off the stack, push
+  None onto the stack, and then return that.  If we really don't care what
+  value is returned, then we can save two instructions by returning the
+  result of the last statement.  It looks funny but it helps.
+* We assume that type and bounds checking has happened at a higher level.
+"""
+
+__author__ = 'kenton@google.com (Kenton Varda)'
+
+import struct
+
+from google.protobuf.internal import wire_format
+
+
+# This will overflow and thus become IEEE-754 "infinity".  We would use
+# "float('inf')" but it doesn't work on Windows pre-Python-2.6.
+_POS_INF = 1e10000
+_NEG_INF = -_POS_INF
+
+
+def _VarintSize(value):
+  """Compute the size of a varint value."""
+  if value <= 0x7f: return 1
+  if value <= 0x3fff: return 2
+  if value <= 0x1fffff: return 3
+  if value <= 0xfffffff: return 4
+  if value <= 0x7ffffffff: return 5
+  if value <= 0x3ffffffffff: return 6
+  if value <= 0x1ffffffffffff: return 7
+  if value <= 0xffffffffffffff: return 8
+  if value <= 0x7fffffffffffffff: return 9
+  return 10
+
+
+def _SignedVarintSize(value):
+  """Compute the size of a signed varint value."""
+  if value < 0: return 10
+  if value <= 0x7f: return 1
+  if value <= 0x3fff: return 2
+  if value <= 0x1fffff: return 3
+  if value <= 0xfffffff: return 4
+  if value <= 0x7ffffffff: return 5
+  if value <= 0x3ffffffffff: return 6
+  if value <= 0x1ffffffffffff: return 7
+  if value <= 0xffffffffffffff: return 8
+  if value <= 0x7fffffffffffffff: return 9
+  return 10
+
+
+def _TagSize(field_number):
+  """Returns the number of bytes required to serialize a tag with this field
+  number."""
+  # Just pass in type 0, since the type won't affect the tag+type size.
+  return _VarintSize(wire_format.PackTag(field_number, 0))
+
+
+# --------------------------------------------------------------------
+# In this section we define some generic sizers.  Each of these functions
+# takes parameters specific to a particular field type, e.g. int32 or fixed64.
+# It returns another function which in turn takes parameters specific to a
+# particular field, e.g. the field number and whether it is repeated or packed.
+# Look at the next section to see how these are used.
+
+
+def _SimpleSizer(compute_value_size):
+  """A sizer which uses the function compute_value_size to compute the size of
+  each value.  Typically compute_value_size is _VarintSize."""
+
+  def SpecificSizer(field_number, is_repeated, is_packed):
+    tag_size = _TagSize(field_number)
+    if is_packed:
+      local_VarintSize = _VarintSize
+      def PackedFieldSize(value):
+        result = 0
+        for element in value:
+          result += compute_value_size(element)
+        return result + local_VarintSize(result) + tag_size
+      return PackedFieldSize
+    elif is_repeated:
+      def RepeatedFieldSize(value):
+        result = tag_size * len(value)
+        for element in value:
+          result += compute_value_size(element)
+        return result
+      return RepeatedFieldSize
+    else:
+      def FieldSize(value):
+        return tag_size + compute_value_size(value)
+      return FieldSize
+
+  return SpecificSizer
+
+
+def _ModifiedSizer(compute_value_size, modify_value):
+  """Like SimpleSizer, but modify_value is invoked on each value before it is
+  passed to compute_value_size.  modify_value is typically ZigZagEncode."""
+
+  def SpecificSizer(field_number, is_repeated, is_packed):
+    tag_size = _TagSize(field_number)
+    if is_packed:
+      local_VarintSize = _VarintSize
+      def PackedFieldSize(value):
+        result = 0
+        for element in value:
+          result += compute_value_size(modify_value(element))
+        return result + local_VarintSize(result) + tag_size
+      return PackedFieldSize
+    elif is_repeated:
+      def RepeatedFieldSize(value):
+        result = tag_size * len(value)
+        for element in value:
+          result += compute_value_size(modify_value(element))
+        return result
+      return RepeatedFieldSize
+    else:
+      def FieldSize(value):
+        return tag_size + compute_value_size(modify_value(value))
+      return FieldSize
+
+  return SpecificSizer
+
+
+def _FixedSizer(value_size):
+  """Like _SimpleSizer except for a fixed-size field.  The input is the size
+  of one value."""
+
+  def SpecificSizer(field_number, is_repeated, is_packed):
+    tag_size = _TagSize(field_number)
+    if is_packed:
+      local_VarintSize = _VarintSize
+      def PackedFieldSize(value):
+        result = len(value) * value_size
+        return result + local_VarintSize(result) + tag_size
+      return PackedFieldSize
+    elif is_repeated:
+      element_size = value_size + tag_size
+      def RepeatedFieldSize(value):
+        return len(value) * element_size
+      return RepeatedFieldSize
+    else:
+      field_size = value_size + tag_size
+      def FieldSize(value):
+        return field_size
+      return FieldSize
+
+  return SpecificSizer
+
+
+# ====================================================================
+# Here we declare a sizer constructor for each field type.  Each "sizer
+# constructor" is a function that takes (field_number, is_repeated, is_packed)
+# as parameters and returns a sizer, which in turn takes a field value as
+# a parameter and returns its encoded size.
+
+
+Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize)
+
+UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize)
+
+SInt32Sizer = SInt64Sizer = _ModifiedSizer(
+    _SignedVarintSize, wire_format.ZigZagEncode)
+
+Fixed32Sizer = SFixed32Sizer = FloatSizer  = _FixedSizer(4)
+Fixed64Sizer = SFixed64Sizer = DoubleSizer = _FixedSizer(8)
+
+BoolSizer = _FixedSizer(1)
+
+
+def StringSizer(field_number, is_repeated, is_packed):
+  """Returns a sizer for a string field."""
+
+  tag_size = _TagSize(field_number)
+  local_VarintSize = _VarintSize
+  local_len = len
+  assert not is_packed
+  if is_repeated:
+    def RepeatedFieldSize(value):
+      result = tag_size * len(value)
+      for element in value:
+        l = local_len(element.encode('utf-8'))
+        result += local_VarintSize(l) + l
+      return result
+    return RepeatedFieldSize
+  else:
+    def FieldSize(value):
+      l = local_len(value.encode('utf-8'))
+      return tag_size + local_VarintSize(l) + l
+    return FieldSize
+
+
+def BytesSizer(field_number, is_repeated, is_packed):
+  """Returns a sizer for a bytes field."""
+
+  tag_size = _TagSize(field_number)
+  local_VarintSize = _VarintSize
+  local_len = len
+  assert not is_packed
+  if is_repeated:
+    def RepeatedFieldSize(value):
+      result = tag_size * len(value)
+      for element in value:
+        l = local_len(element)
+        result += local_VarintSize(l) + l
+      return result
+    return RepeatedFieldSize
+  else:
+    def FieldSize(value):
+      l = local_len(value)
+      return tag_size + local_VarintSize(l) + l
+    return FieldSize
+
+
+def GroupSizer(field_number, is_repeated, is_packed):
+  """Returns a sizer for a group field."""
+
+  tag_size = _TagSize(field_number) * 2
+  assert not is_packed
+  if is_repeated:
+    def RepeatedFieldSize(value):
+      result = tag_size * len(value)
+      for element in value:
+        result += element.ByteSize()
+      return result
+    return RepeatedFieldSize
+  else:
+    def FieldSize(value):
+      return tag_size + value.ByteSize()
+    return FieldSize
+
+
+def MessageSizer(field_number, is_repeated, is_packed):
+  """Returns a sizer for a message field."""
+
+  tag_size = _TagSize(field_number)
+  local_VarintSize = _VarintSize
+  assert not is_packed
+  if is_repeated:
+    def RepeatedFieldSize(value):
+      result = tag_size * len(value)
+      for element in value:
+        l = element.ByteSize()
+        result += local_VarintSize(l) + l
+      return result
+    return RepeatedFieldSize
+  else:
+    def FieldSize(value):
+      l = value.ByteSize()
+      return tag_size + local_VarintSize(l) + l
+    return FieldSize
+
+
+# --------------------------------------------------------------------
+# MessageSet is special: it needs custom logic to compute its size properly.
+
+
+def MessageSetItemSizer(field_number):
+  """Returns a sizer for extensions of MessageSet.
+
+  The message set message looks like this:
+    message MessageSet {
+      repeated group Item = 1 {
+        required int32 type_id = 2;
+        required string message = 3;
+      }
+    }
+  """
+  static_size = (_TagSize(1) * 2 + _TagSize(2) + _VarintSize(field_number) +
+                 _TagSize(3))
+  local_VarintSize = _VarintSize
+
+  def FieldSize(value):
+    l = value.ByteSize()
+    return static_size + local_VarintSize(l) + l
+
+  return FieldSize
+
+
+# --------------------------------------------------------------------
+# Map is special: it needs custom logic to compute its size properly.
+
+
+def MapSizer(field_descriptor, is_message_map):
+  """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. For message map, value.ByteSize() should be called to
+      # update the status.
+      entry_msg = message_type._concrete_class(key=key, value=value)
+      total += message_sizer(entry_msg)
+      if is_message_map:
+        value.ByteSize()
+    return total
+
+  return FieldSize
+
+# ====================================================================
+# Encoders!
+
+
+def _VarintEncoder():
+  """Return an encoder for a basic varint value (does not include tag)."""
+
+  local_int2byte = struct.Struct('>B').pack
+
+  def EncodeVarint(write, value, unused_deterministic=None):
+    bits = value & 0x7f
+    value >>= 7
+    while value:
+      write(local_int2byte(0x80|bits))
+      bits = value & 0x7f
+      value >>= 7
+    return write(local_int2byte(bits))
+
+  return EncodeVarint
+
+
+def _SignedVarintEncoder():
+  """Return an encoder for a basic signed varint value (does not include
+  tag)."""
+
+  local_int2byte = struct.Struct('>B').pack
+
+  def EncodeSignedVarint(write, value, unused_deterministic=None):
+    if value < 0:
+      value += (1 << 64)
+    bits = value & 0x7f
+    value >>= 7
+    while value:
+      write(local_int2byte(0x80|bits))
+      bits = value & 0x7f
+      value >>= 7
+    return write(local_int2byte(bits))
+
+  return EncodeSignedVarint
+
+
+_EncodeVarint = _VarintEncoder()
+_EncodeSignedVarint = _SignedVarintEncoder()
+
+
+def _VarintBytes(value):
+  """Encode the given integer as a varint and return the bytes.  This is only
+  called at startup time so it doesn't need to be fast."""
+
+  pieces = []
+  _EncodeVarint(pieces.append, value, True)
+  return b"".join(pieces)
+
+
+def TagBytes(field_number, wire_type):
+  """Encode the given tag and return the bytes.  Only called at startup."""
+
+  return bytes(_VarintBytes(wire_format.PackTag(field_number, wire_type)))
+
+# --------------------------------------------------------------------
+# As with sizers (see above), we have a number of common encoder
+# implementations.
+
+
+def _SimpleEncoder(wire_type, encode_value, compute_value_size):
+  """Return a constructor for an encoder for fields of a particular type.
+
+  Args:
+      wire_type:  The field's wire type, for encoding tags.
+      encode_value:  A function which encodes an individual value, e.g.
+        _EncodeVarint().
+      compute_value_size:  A function which computes the size of an individual
+        value, e.g. _VarintSize().
+  """
+
+  def SpecificEncoder(field_number, is_repeated, is_packed):
+    if is_packed:
+      tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+      local_EncodeVarint = _EncodeVarint
+      def EncodePackedField(write, value, deterministic):
+        write(tag_bytes)
+        size = 0
+        for element in value:
+          size += compute_value_size(element)
+        local_EncodeVarint(write, size, deterministic)
+        for element in value:
+          encode_value(write, element, deterministic)
+      return EncodePackedField
+    elif is_repeated:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeRepeatedField(write, value, deterministic):
+        for element in value:
+          write(tag_bytes)
+          encode_value(write, element, deterministic)
+      return EncodeRepeatedField
+    else:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeField(write, value, deterministic):
+        write(tag_bytes)
+        return encode_value(write, value, deterministic)
+      return EncodeField
+
+  return SpecificEncoder
+
+
+def _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value):
+  """Like SimpleEncoder but additionally invokes modify_value on every value
+  before passing it to encode_value.  Usually modify_value is ZigZagEncode."""
+
+  def SpecificEncoder(field_number, is_repeated, is_packed):
+    if is_packed:
+      tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+      local_EncodeVarint = _EncodeVarint
+      def EncodePackedField(write, value, deterministic):
+        write(tag_bytes)
+        size = 0
+        for element in value:
+          size += compute_value_size(modify_value(element))
+        local_EncodeVarint(write, size, deterministic)
+        for element in value:
+          encode_value(write, modify_value(element), deterministic)
+      return EncodePackedField
+    elif is_repeated:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeRepeatedField(write, value, deterministic):
+        for element in value:
+          write(tag_bytes)
+          encode_value(write, modify_value(element), deterministic)
+      return EncodeRepeatedField
+    else:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeField(write, value, deterministic):
+        write(tag_bytes)
+        return encode_value(write, modify_value(value), deterministic)
+      return EncodeField
+
+  return SpecificEncoder
+
+
+def _StructPackEncoder(wire_type, format):
+  """Return a constructor for an encoder for a fixed-width field.
+
+  Args:
+      wire_type:  The field's wire type, for encoding tags.
+      format:  The format string to pass to struct.pack().
+  """
+
+  value_size = struct.calcsize(format)
+
+  def SpecificEncoder(field_number, is_repeated, is_packed):
+    local_struct_pack = struct.pack
+    if is_packed:
+      tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+      local_EncodeVarint = _EncodeVarint
+      def EncodePackedField(write, value, deterministic):
+        write(tag_bytes)
+        local_EncodeVarint(write, len(value) * value_size, deterministic)
+        for element in value:
+          write(local_struct_pack(format, element))
+      return EncodePackedField
+    elif is_repeated:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeRepeatedField(write, value, unused_deterministic=None):
+        for element in value:
+          write(tag_bytes)
+          write(local_struct_pack(format, element))
+      return EncodeRepeatedField
+    else:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeField(write, value, unused_deterministic=None):
+        write(tag_bytes)
+        return write(local_struct_pack(format, value))
+      return EncodeField
+
+  return SpecificEncoder
+
+
+def _FloatingPointEncoder(wire_type, format):
+  """Return a constructor for an encoder for float fields.
+
+  This is like StructPackEncoder, but catches errors that may be due to
+  passing non-finite floating-point values to struct.pack, and makes a
+  second attempt to encode those values.
+
+  Args:
+      wire_type:  The field's wire type, for encoding tags.
+      format:  The format string to pass to struct.pack().
+  """
+
+  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')
+      elif value == _NEG_INF:
+        write(b'\x00\x00\x80\xFF')
+      elif value != value:           # NaN
+        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')
+      elif value == _NEG_INF:
+        write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF')
+      elif value != value:                         # NaN
+        write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F')
+      else:
+        raise
+  else:
+    raise ValueError('Can\'t encode floating-point values that are '
+                     '%d bytes long (only 4 or 8)' % value_size)
+
+  def SpecificEncoder(field_number, is_repeated, is_packed):
+    local_struct_pack = struct.pack
+    if is_packed:
+      tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+      local_EncodeVarint = _EncodeVarint
+      def EncodePackedField(write, value, deterministic):
+        write(tag_bytes)
+        local_EncodeVarint(write, len(value) * value_size, deterministic)
+        for element in value:
+          # This try/except block is going to be faster than any code that
+          # we could write to check whether element is finite.
+          try:
+            write(local_struct_pack(format, element))
+          except SystemError:
+            EncodeNonFiniteOrRaise(write, element)
+      return EncodePackedField
+    elif is_repeated:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeRepeatedField(write, value, unused_deterministic=None):
+        for element in value:
+          write(tag_bytes)
+          try:
+            write(local_struct_pack(format, element))
+          except SystemError:
+            EncodeNonFiniteOrRaise(write, element)
+      return EncodeRepeatedField
+    else:
+      tag_bytes = TagBytes(field_number, wire_type)
+      def EncodeField(write, value, unused_deterministic=None):
+        write(tag_bytes)
+        try:
+          write(local_struct_pack(format, value))
+        except SystemError:
+          EncodeNonFiniteOrRaise(write, value)
+      return EncodeField
+
+  return SpecificEncoder
+
+
+# ====================================================================
+# Here we declare an encoder constructor for each field type.  These work
+# very similarly to sizer constructors, described earlier.
+
+
+Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder(
+    wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize)
+
+UInt32Encoder = UInt64Encoder = _SimpleEncoder(
+    wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize)
+
+SInt32Encoder = SInt64Encoder = _ModifiedEncoder(
+    wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize,
+    wire_format.ZigZagEncode)
+
+# Note that Python conveniently guarantees that when using the '<' prefix on
+# formats, they will also have the same size across all platforms (as opposed
+# to without the prefix, where their sizes depend on the C compiler's basic
+# type sizes).
+Fixed32Encoder  = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<I')
+Fixed64Encoder  = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<Q')
+SFixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<i')
+SFixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<q')
+FloatEncoder    = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED32, '<f')
+DoubleEncoder   = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d')
+
+
+def BoolEncoder(field_number, is_repeated, is_packed):
+  """Returns an encoder for a boolean field."""
+
+  false_byte = b'\x00'
+  true_byte = b'\x01'
+  if is_packed:
+    tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+    local_EncodeVarint = _EncodeVarint
+    def EncodePackedField(write, value, deterministic):
+      write(tag_bytes)
+      local_EncodeVarint(write, len(value), deterministic)
+      for element in value:
+        if element:
+          write(true_byte)
+        else:
+          write(false_byte)
+    return EncodePackedField
+  elif is_repeated:
+    tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
+    def EncodeRepeatedField(write, value, unused_deterministic=None):
+      for element in value:
+        write(tag_bytes)
+        if element:
+          write(true_byte)
+        else:
+          write(false_byte)
+    return EncodeRepeatedField
+  else:
+    tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
+    def EncodeField(write, value, unused_deterministic=None):
+      write(tag_bytes)
+      if value:
+        return write(true_byte)
+      return write(false_byte)
+    return EncodeField
+
+
+def StringEncoder(field_number, is_repeated, is_packed):
+  """Returns an encoder for a string field."""
+
+  tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+  local_EncodeVarint = _EncodeVarint
+  local_len = len
+  assert not is_packed
+  if is_repeated:
+    def EncodeRepeatedField(write, value, deterministic):
+      for element in value:
+        encoded = element.encode('utf-8')
+        write(tag)
+        local_EncodeVarint(write, local_len(encoded), deterministic)
+        write(encoded)
+    return EncodeRepeatedField
+  else:
+    def EncodeField(write, value, deterministic):
+      encoded = value.encode('utf-8')
+      write(tag)
+      local_EncodeVarint(write, local_len(encoded), deterministic)
+      return write(encoded)
+    return EncodeField
+
+
+def BytesEncoder(field_number, is_repeated, is_packed):
+  """Returns an encoder for a bytes field."""
+
+  tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+  local_EncodeVarint = _EncodeVarint
+  local_len = len
+  assert not is_packed
+  if is_repeated:
+    def EncodeRepeatedField(write, value, deterministic):
+      for element in value:
+        write(tag)
+        local_EncodeVarint(write, local_len(element), deterministic)
+        write(element)
+    return EncodeRepeatedField
+  else:
+    def EncodeField(write, value, deterministic):
+      write(tag)
+      local_EncodeVarint(write, local_len(value), deterministic)
+      return write(value)
+    return EncodeField
+
+
+def GroupEncoder(field_number, is_repeated, is_packed):
+  """Returns an encoder for a group field."""
+
+  start_tag = TagBytes(field_number, wire_format.WIRETYPE_START_GROUP)
+  end_tag = TagBytes(field_number, wire_format.WIRETYPE_END_GROUP)
+  assert not is_packed
+  if is_repeated:
+    def EncodeRepeatedField(write, value, deterministic):
+      for element in value:
+        write(start_tag)
+        element._InternalSerialize(write, deterministic)
+        write(end_tag)
+    return EncodeRepeatedField
+  else:
+    def EncodeField(write, value, deterministic):
+      write(start_tag)
+      value._InternalSerialize(write, deterministic)
+      return write(end_tag)
+    return EncodeField
+
+
+def MessageEncoder(field_number, is_repeated, is_packed):
+  """Returns an encoder for a message field."""
+
+  tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+  local_EncodeVarint = _EncodeVarint
+  assert not is_packed
+  if is_repeated:
+    def EncodeRepeatedField(write, value, deterministic):
+      for element in value:
+        write(tag)
+        local_EncodeVarint(write, element.ByteSize(), deterministic)
+        element._InternalSerialize(write, deterministic)
+    return EncodeRepeatedField
+  else:
+    def EncodeField(write, value, deterministic):
+      write(tag)
+      local_EncodeVarint(write, value.ByteSize(), deterministic)
+      return value._InternalSerialize(write, deterministic)
+    return EncodeField
+
+
+# --------------------------------------------------------------------
+# As before, MessageSet is special.
+
+
+def MessageSetItemEncoder(field_number):
+  """Encoder for extensions of MessageSet.
+
+  The message set message looks like this:
+    message MessageSet {
+      repeated group Item = 1 {
+        required int32 type_id = 2;
+        required string message = 3;
+      }
+    }
+  """
+  start_bytes = b"".join([
+      TagBytes(1, wire_format.WIRETYPE_START_GROUP),
+      TagBytes(2, wire_format.WIRETYPE_VARINT),
+      _VarintBytes(field_number),
+      TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED)])
+  end_bytes = TagBytes(1, wire_format.WIRETYPE_END_GROUP)
+  local_EncodeVarint = _EncodeVarint
+
+  def EncodeField(write, value, deterministic):
+    write(start_bytes)
+    local_EncodeVarint(write, value.ByteSize(), deterministic)
+    value._InternalSerialize(write, deterministic)
+    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, deterministic):
+    value_keys = sorted(value.keys()) if deterministic else value
+    for key in value_keys:
+      entry_msg = message_type._concrete_class(key=key, value=value[key])
+      encode_message(write, entry_msg, deterministic)
+
+  return EncodeField
diff --git a/python/google/protobuf/internal/enum_type_wrapper.py b/python/google/protobuf/internal/enum_type_wrapper.py
new file mode 100644
index 0000000..65d2c7a
--- /dev/null
+++ b/python/google/protobuf/internal/enum_type_wrapper.py
@@ -0,0 +1,124 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 simple wrapper around enum types to expose utility functions.
+
+Instances are created as properties with the same name as the enum they wrap
+on proto classes.  For usage, see:
+  reflection_test.py
+"""
+
+__author__ = 'rabsatt@google.com (Kevin Rabsatt)'
+
+
+class EnumTypeWrapper(object):
+  """A utility for finding the names of enum values."""
+
+  DESCRIPTOR = None
+
+  # This is a type alias, which mypy typing stubs can type as
+  # a genericized parameter constrained to an int, allowing subclasses
+  # to be typed with more constraint in .pyi stubs
+  # Eg.
+  # def MyGeneratedEnum(Message):
+  #   ValueType = NewType('ValueType', int)
+  #   def Name(self, number: MyGeneratedEnum.ValueType) -> str
+  ValueType = int
+
+  def __init__(self, enum_type):
+    """Inits EnumTypeWrapper with an EnumDescriptor."""
+    self._enum_type = enum_type
+    self.DESCRIPTOR = enum_type  # pylint: disable=invalid-name
+
+  def Name(self, number):  # pylint: disable=invalid-name
+    """Returns a string containing the name of an enum value."""
+    try:
+      return self._enum_type.values_by_number[number].name
+    except KeyError:
+      pass  # fall out to break exception chaining
+
+    if not isinstance(number, int):
+      raise TypeError(
+          'Enum value for {} must be an int, but got {} {!r}.'.format(
+              self._enum_type.name, type(number), number))
+    else:
+      # repr here to handle the odd case when you pass in a boolean.
+      raise ValueError('Enum {} has no name defined for value {!r}'.format(
+          self._enum_type.name, number))
+
+  def Value(self, name):  # pylint: disable=invalid-name
+    """Returns the value corresponding to the given enum name."""
+    try:
+      return self._enum_type.values_by_name[name].number
+    except KeyError:
+      pass  # fall out to break exception chaining
+    raise ValueError('Enum {} has no value defined for name {!r}'.format(
+        self._enum_type.name, name))
+
+  def keys(self):
+    """Return a list of the string names in the enum.
+
+    Returns:
+      A list of strs, in the order they were defined in the .proto file.
+    """
+
+    return [value_descriptor.name
+            for value_descriptor in self._enum_type.values]
+
+  def values(self):
+    """Return a list of the integer values in the enum.
+
+    Returns:
+      A list of ints, in the order they were defined in the .proto file.
+    """
+
+    return [value_descriptor.number
+            for value_descriptor in self._enum_type.values]
+
+  def items(self):
+    """Return a list of the (name, value) pairs of the enum.
+
+    Returns:
+      A list of (str, int) pairs, in the order they were defined
+      in the .proto file.
+    """
+    return [(value_descriptor.name, value_descriptor.number)
+            for value_descriptor in self._enum_type.values]
+
+  def __getattr__(self, name):
+    """Returns the value corresponding to the given enum name."""
+    try:
+      return super(
+          EnumTypeWrapper,
+          self).__getattribute__('_enum_type').values_by_name[name].number
+    except KeyError:
+      pass  # fall out to break exception chaining
+    raise AttributeError('Enum {} has no value defined for name {!r}'.format(
+        self._enum_type.name, name))
diff --git a/python/google/protobuf/internal/extension_dict.py b/python/google/protobuf/internal/extension_dict.py
new file mode 100644
index 0000000..b346cf2
--- /dev/null
+++ b/python/google/protobuf/internal/extension_dict.py
@@ -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.
+
+"""Contains _ExtensionDict class to represent extensions.
+"""
+
+from google.protobuf.internal import type_checkers
+from google.protobuf.descriptor import FieldDescriptor
+
+
+def _VerifyExtensionHandle(message, extension_handle):
+  """Verify that the given extension handle is valid."""
+
+  if not isinstance(extension_handle, FieldDescriptor):
+    raise KeyError('HasExtension() expects an extension handle, got: %s' %
+                   extension_handle)
+
+  if not extension_handle.is_extension:
+    raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
+
+  if not extension_handle.containing_type:
+    raise KeyError('"%s" is missing a containing_type.'
+                   % extension_handle.full_name)
+
+  if extension_handle.containing_type is not message.DESCRIPTOR:
+    raise KeyError('Extension "%s" extends message type "%s", but this '
+                   'message is of type "%s".' %
+                   (extension_handle.full_name,
+                    extension_handle.containing_type.full_name,
+                    message.DESCRIPTOR.full_name))
+
+
+# TODO(robinson): Unify error handling of "unknown extension" crap.
+# TODO(robinson): Support iteritems()-style iteration over all
+# extensions with the "has" bits turned on?
+class _ExtensionDict(object):
+
+  """Dict-like container for Extension fields on proto instances.
+
+  Note that in all cases we expect extension handles to be
+  FieldDescriptors.
+  """
+
+  def __init__(self, extended_message):
+    """
+    Args:
+      extended_message: Message instance for which we are the Extensions dict.
+    """
+    self._extended_message = extended_message
+
+  def __getitem__(self, extension_handle):
+    """Returns the current value of the given extension handle."""
+
+    _VerifyExtensionHandle(self._extended_message, extension_handle)
+
+    result = self._extended_message._fields.get(extension_handle)
+    if result is not None:
+      return result
+
+    if extension_handle.label == FieldDescriptor.LABEL_REPEATED:
+      result = extension_handle._default_constructor(self._extended_message)
+    elif extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+      message_type = extension_handle.message_type
+      if not hasattr(message_type, '_concrete_class'):
+        # pylint: disable=protected-access
+        self._extended_message._FACTORY.GetPrototype(message_type)
+      assert getattr(extension_handle.message_type, '_concrete_class', None), (
+          'Uninitialized concrete class found for field %r (message type %r)'
+          % (extension_handle.full_name,
+             extension_handle.message_type.full_name))
+      result = extension_handle.message_type._concrete_class()
+      try:
+        result._SetListener(self._extended_message._listener_for_children)
+      except ReferenceError:
+        pass
+    else:
+      # Singular scalar -- just return the default without inserting into the
+      # dict.
+      return extension_handle.default_value
+
+    # 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
+    # take that object and discard ours.
+    # WARNING:  We are relying on setdefault() being atomic.  This is true
+    #   in CPython but we haven't investigated others.  This warning appears
+    #   in several other locations in this file.
+    result = self._extended_message._fields.setdefault(
+        extension_handle, result)
+
+    return result
+
+  def __eq__(self, other):
+    if not isinstance(other, self.__class__):
+      return False
+
+    my_fields = self._extended_message.ListFields()
+    other_fields = other._extended_message.ListFields()
+
+    # Get rid of non-extension fields.
+    my_fields = [field for field in my_fields if field.is_extension]
+    other_fields = [field for field in other_fields if field.is_extension]
+
+    return my_fields == other_fields
+
+  def __ne__(self, other):
+    return not self == other
+
+  def __len__(self):
+    fields = self._extended_message.ListFields()
+    # Get rid of non-extension fields.
+    extension_fields = [field for field in fields if field[0].is_extension]
+    return len(extension_fields)
+
+  def __hash__(self):
+    raise TypeError('unhashable object')
+
+  # Note that this is only meaningful for non-repeated, scalar extension
+  # fields.  Note also that we may have to call _Modified() when we do
+  # successfully set a field this way, to set any necessary "has" bits in the
+  # ancestors of the extended message.
+  def __setitem__(self, extension_handle, value):
+    """If extension_handle specifies a non-repeated, scalar extension
+    field, sets the value of that field.
+    """
+
+    _VerifyExtensionHandle(self._extended_message, extension_handle)
+
+    if (extension_handle.label == FieldDescriptor.LABEL_REPEATED or
+        extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE):
+      raise TypeError(
+          'Cannot assign to extension "%s" because it is a repeated or '
+          'composite type.' % extension_handle.full_name)
+
+    # It's slightly wasteful to lookup the type checker each time,
+    # but we expect this to be a vanishingly uncommon case anyway.
+    type_checker = type_checkers.GetTypeChecker(extension_handle)
+    # pylint: disable=protected-access
+    self._extended_message._fields[extension_handle] = (
+        type_checker.CheckValue(value))
+    self._extended_message._Modified()
+
+  def __delitem__(self, extension_handle):
+    self._extended_message.ClearExtension(extension_handle)
+
+  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._extended_message._extensions_by_name.get(name, None)
+
+  def _FindExtensionByNumber(self, number):
+    """Tries to find a known extension with the field number.
+
+    Args:
+      number: Extension field number.
+
+    Returns:
+      Extension field descriptor.
+    """
+    return self._extended_message._extensions_by_number.get(number, None)
+
+  def __iter__(self):
+    # Return a generator over the populated extension fields
+    return (f[0] for f in self._extended_message.ListFields()
+            if f[0].is_extension)
+
+  def __contains__(self, extension_handle):
+    _VerifyExtensionHandle(self._extended_message, extension_handle)
+
+    if extension_handle not in self._extended_message._fields:
+      return False
+
+    if extension_handle.label == FieldDescriptor.LABEL_REPEATED:
+      return bool(self._extended_message._fields.get(extension_handle))
+
+    if extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+      value = self._extended_message._fields.get(extension_handle)
+      # pylint: disable=protected-access
+      return value is not None and value._is_present_in_parent
+
+    return True
diff --git a/python/google/protobuf/internal/factory_test1.proto b/python/google/protobuf/internal/factory_test1.proto
new file mode 100644
index 0000000..5e729f5
--- /dev/null
+++ b/python/google/protobuf/internal/factory_test1.proto
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: matthewtoia@google.com (Matt Toia)
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+enum Factory1Enum {
+  FACTORY_1_VALUE_0 = 0;
+  FACTORY_1_VALUE_1 = 1;
+}
+
+message Factory1Message {
+  optional Factory1Enum factory_1_enum = 1;
+  enum NestedFactory1Enum {
+    NESTED_FACTORY_1_VALUE_0 = 0;
+    NESTED_FACTORY_1_VALUE_1 = 1;
+  }
+  optional NestedFactory1Enum nested_factory_1_enum = 2;
+  message NestedFactory1Message {
+    optional string value = 1;
+  }
+  optional NestedFactory1Message nested_factory_1_message = 3;
+  optional int32 scalar_value = 4;
+  repeated string list_value = 5;
+
+  extensions 1000 to max;
+}
+
+message Factory1MethodRequest {
+  optional string argument = 1;
+}
+
+message Factory1MethodResponse {
+  optional string result = 1;
+}
+
+service Factory1Service {
+  // Dummy method for this dummy service.
+  rpc Factory1Method(Factory1MethodRequest) returns (Factory1MethodResponse) {}
+}
diff --git a/python/google/protobuf/internal/factory_test2.proto b/python/google/protobuf/internal/factory_test2.proto
new file mode 100644
index 0000000..5fcbc5a
--- /dev/null
+++ b/python/google/protobuf/internal/factory_test2.proto
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: matthewtoia@google.com (Matt Toia)
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+import "google/protobuf/internal/factory_test1.proto";
+
+
+enum Factory2Enum {
+  FACTORY_2_VALUE_0 = 0;
+  FACTORY_2_VALUE_1 = 1;
+}
+
+message Factory2Message {
+  required int32 mandatory = 1;
+  optional Factory2Enum factory_2_enum = 2;
+  enum NestedFactory2Enum {
+    NESTED_FACTORY_2_VALUE_0 = 0;
+    NESTED_FACTORY_2_VALUE_1 = 1;
+  }
+  optional NestedFactory2Enum nested_factory_2_enum = 3;
+  message NestedFactory2Message {
+    optional string value = 1;
+  }
+  optional NestedFactory2Message nested_factory_2_message = 4;
+  optional Factory1Message factory_1_message = 5;
+  optional Factory1Enum factory_1_enum = 6;
+  optional Factory1Message.NestedFactory1Enum nested_factory_1_enum = 7;
+  optional Factory1Message.NestedFactory1Message nested_factory_1_message = 8;
+  optional Factory2Message circular_message = 9;
+  optional string scalar_value = 10;
+  repeated string list_value = 11;
+  repeated group Grouped = 12 {
+    optional string part_1 = 13;
+    optional string part_2 = 14;
+  }
+  optional LoopMessage loop = 15;
+  optional int32 int_with_default = 16 [default = 1776];
+  optional double double_with_default = 17 [default = 9.99];
+  optional string string_with_default = 18 [default = "hello world"];
+  optional bool bool_with_default = 19 [default = false];
+  optional Factory2Enum enum_with_default = 20 [default = FACTORY_2_VALUE_1];
+  optional bytes bytes_with_default = 21 [default = "a\373\000c"];
+
+
+  extend Factory1Message {
+    optional string one_more_field = 1001;
+  }
+
+  oneof oneof_field {
+    int32 oneof_int = 22;
+    string oneof_string = 23;
+  }
+}
+
+message LoopMessage {
+  optional Factory2Message loop = 1;
+}
+
+message MessageWithNestedEnumOnly {
+  enum NestedEnum {
+    NESTED_MESSAGE_ENUM_0 = 0;
+  }
+}
+
+extend Factory1Message {
+  optional string another_field = 1002;
+}
+
+message MessageWithOption {
+  option no_standard_descriptor_accessor = true;
+  optional int32 field1 = 1;
+}
diff --git a/python/google/protobuf/internal/file_options_test.proto b/python/google/protobuf/internal/file_options_test.proto
new file mode 100644
index 0000000..4eceeb0
--- /dev/null
+++ b/python/google/protobuf/internal/file_options_test.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.
+
+syntax = "proto2";
+
+import "google/protobuf/descriptor.proto";
+
+package google.protobuf.python.internal;
+
+message FooOptions {
+  optional string foo_name = 1;
+}
+
+extend .google.protobuf.FileOptions {
+  optional FooOptions foo_options = 120436268;
+}
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
new file mode 100644
index 0000000..9883fce
--- /dev/null
+++ b/python/google/protobuf/internal/generator_test.py
@@ -0,0 +1,354 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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(robinson): Flesh this out considerably.  We focused on reflection_test.py
+# first, since it's testing the subtler code, and since it provides decent
+# indirect testing of the protocol compiler output.
+
+"""Unittest that directly tests the output of the pure-Python protocol
+compiler.  See //google/protobuf/internal/reflection_test.py for a test which
+further ensures that we can use Python protocol message objects as we expect.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+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
+from google.protobuf import symbol_database
+
+MAX_EXTENSION = 536870912
+
+
+class GeneratorTest(unittest.TestCase):
+
+  def testNestedMessageDescriptor(self):
+    field_name = 'optional_nested_message'
+    proto_type = unittest_pb2.TestAllTypes
+    self.assertEqual(
+        proto_type.NestedMessage.DESCRIPTOR,
+        proto_type.DESCRIPTOR.fields_by_name[field_name].message_type)
+
+  def testEnums(self):
+    # We test only module-level enums here.
+    # TODO(robinson): Examine descriptors directly to check
+    # enum descriptor output.
+    self.assertEqual(4, unittest_pb2.FOREIGN_FOO)
+    self.assertEqual(5, unittest_pb2.FOREIGN_BAR)
+    self.assertEqual(6, unittest_pb2.FOREIGN_BAZ)
+
+    proto = unittest_pb2.TestAllTypes()
+    self.assertEqual(1, proto.FOO)
+    self.assertEqual(1, unittest_pb2.TestAllTypes.FOO)
+    self.assertEqual(2, proto.BAR)
+    self.assertEqual(2, unittest_pb2.TestAllTypes.BAR)
+    self.assertEqual(3, proto.BAZ)
+    self.assertEqual(3, unittest_pb2.TestAllTypes.BAZ)
+
+  def testExtremeDefaultValues(self):
+    message = unittest_pb2.TestExtremeDefaultValues()
+
+    # Python pre-2.6 does not have isinf() or isnan() functions, so we have
+    # to provide our own.
+    def isnan(val):
+      # NaN is never equal to itself.
+      return val != val
+    def isinf(val):
+      # Infinity times zero equals NaN.
+      return not isnan(val) and isnan(val * 0)
+
+    self.assertTrue(isinf(message.inf_double))
+    self.assertTrue(message.inf_double > 0)
+    self.assertTrue(isinf(message.neg_inf_double))
+    self.assertTrue(message.neg_inf_double < 0)
+    self.assertTrue(isnan(message.nan_double))
+
+    self.assertTrue(isinf(message.inf_float))
+    self.assertTrue(message.inf_float > 0)
+    self.assertTrue(isinf(message.neg_inf_float))
+    self.assertTrue(message.neg_inf_float < 0)
+    self.assertTrue(isnan(message.nan_float))
+    self.assertEqual("? ? ?? ?? ??? ??/ ??-", message.cpp_trigraph)
+
+  def testHasDefaultValues(self):
+    desc = unittest_pb2.TestAllTypes.DESCRIPTOR
+
+    expected_has_default_by_name = {
+        'optional_int32': False,
+        'repeated_int32': False,
+        'optional_nested_message': False,
+        'default_int32': True,
+    }
+
+    has_default_by_name = dict(
+        [(f.name, f.has_default_value)
+         for f in desc.fields
+         if f.name in expected_has_default_by_name])
+    self.assertEqual(expected_has_default_by_name, has_default_by_name)
+
+  def testContainingTypeBehaviorForExtensions(self):
+    self.assertEqual(unittest_pb2.optional_int32_extension.containing_type,
+                     unittest_pb2.TestAllExtensions.DESCRIPTOR)
+    self.assertEqual(unittest_pb2.TestRequired.single.containing_type,
+                     unittest_pb2.TestAllExtensions.DESCRIPTOR)
+
+  def testExtensionScope(self):
+    self.assertEqual(unittest_pb2.optional_int32_extension.extension_scope,
+                     None)
+    self.assertEqual(unittest_pb2.TestRequired.single.extension_scope,
+                     unittest_pb2.TestRequired.DESCRIPTOR)
+
+  def testIsExtension(self):
+    self.assertTrue(unittest_pb2.optional_int32_extension.is_extension)
+    self.assertTrue(unittest_pb2.TestRequired.single.is_extension)
+
+    message_descriptor = unittest_pb2.TestRequired.DESCRIPTOR
+    non_extension_descriptor = message_descriptor.fields_by_name['a']
+    self.assertTrue(not non_extension_descriptor.is_extension)
+
+  def testOptions(self):
+    proto = unittest_mset_wire_format_pb2.TestMessageSet()
+    self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format)
+
+  def testMessageWithCustomOptions(self):
+    proto = unittest_custom_options_pb2.TestMessageWithCustomOptions()
+    enum_options = proto.DESCRIPTOR.enum_types_by_name['AnEnum'].GetOptions()
+    self.assertTrue(enum_options is not None)
+    # TODO(gps): We really should test for the presence of the enum_opt1
+    # extension and for its value to be set to -789.
+
+  def testNestedTypes(self):
+    self.assertEqual(
+        set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types),
+        set([
+            unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR,
+            unittest_pb2.TestAllTypes.OptionalGroup.DESCRIPTOR,
+            unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR,
+        ]))
+    self.assertEqual(unittest_pb2.TestEmptyMessage.DESCRIPTOR.nested_types, [])
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.nested_types, [])
+
+  def testContainingType(self):
+    self.assertTrue(
+        unittest_pb2.TestEmptyMessage.DESCRIPTOR.containing_type is None)
+    self.assertTrue(
+        unittest_pb2.TestAllTypes.DESCRIPTOR.containing_type is None)
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type,
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR.containing_type,
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.RepeatedGroup.DESCRIPTOR.containing_type,
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+
+  def testContainingTypeInEnumDescriptor(self):
+    self.assertTrue(unittest_pb2._FOREIGNENUM.containing_type is None)
+    self.assertEqual(unittest_pb2._TESTALLTYPES_NESTEDENUM.containing_type,
+                     unittest_pb2.TestAllTypes.DESCRIPTOR)
+
+  def testPackage(self):
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.DESCRIPTOR.file.package,
+        'protobuf_unittest')
+    desc = unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR
+    self.assertEqual(desc.file.package, 'protobuf_unittest')
+    self.assertEqual(
+        unittest_import_pb2.ImportMessage.DESCRIPTOR.file.package,
+        'protobuf_unittest_import')
+
+    self.assertEqual(
+        unittest_pb2._FOREIGNENUM.file.package, 'protobuf_unittest')
+    self.assertEqual(
+        unittest_pb2._TESTALLTYPES_NESTEDENUM.file.package,
+        'protobuf_unittest')
+    self.assertEqual(
+        unittest_import_pb2._IMPORTENUM.file.package,
+        'protobuf_unittest_import')
+
+  def testExtensionRange(self):
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.DESCRIPTOR.extension_ranges, [])
+    self.assertEqual(
+        unittest_pb2.TestAllExtensions.DESCRIPTOR.extension_ranges,
+        [(1, MAX_EXTENSION)])
+    self.assertEqual(
+        unittest_pb2.TestMultipleExtensionRanges.DESCRIPTOR.extension_ranges,
+        [(42, 43), (4143, 4244), (65536, MAX_EXTENSION)])
+
+  def testFileDescriptor(self):
+    self.assertEqual(unittest_pb2.DESCRIPTOR.name,
+                     'google/protobuf/unittest.proto')
+    self.assertEqual(unittest_pb2.DESCRIPTOR.package, 'protobuf_unittest')
+    self.assertFalse(unittest_pb2.DESCRIPTOR.serialized_pb is None)
+    self.assertEqual(unittest_pb2.DESCRIPTOR.dependencies,
+                     [unittest_import_pb2.DESCRIPTOR])
+    self.assertEqual(unittest_import_pb2.DESCRIPTOR.dependencies,
+                     [unittest_import_public_pb2.DESCRIPTOR])
+    self.assertEqual(unittest_import_pb2.DESCRIPTOR.public_dependencies,
+                     [unittest_import_public_pb2.DESCRIPTOR])
+  def testNoGenericServices(self):
+    self.assertTrue(hasattr(unittest_no_generic_services_pb2, "TestMessage"))
+    self.assertTrue(hasattr(unittest_no_generic_services_pb2, "FOO"))
+    self.assertTrue(hasattr(unittest_no_generic_services_pb2, "test_extension"))
+
+    # Make sure unittest_no_generic_services_pb2 has no services subclassing
+    # Proto2 Service class.
+    if hasattr(unittest_no_generic_services_pb2, "TestService"):
+      self.assertFalse(issubclass(unittest_no_generic_services_pb2.TestService,
+                                  service.Service))
+
+  def testMessageTypesByName(self):
+    file_type = unittest_pb2.DESCRIPTOR
+    self.assertEqual(
+        unittest_pb2._TESTALLTYPES,
+        file_type.message_types_by_name[unittest_pb2._TESTALLTYPES.name])
+
+    # Nested messages shouldn't be included in the message_types_by_name
+    # dictionary (like in the C++ API).
+    self.assertFalse(
+        unittest_pb2._TESTALLTYPES_NESTEDMESSAGE.name in
+        file_type.message_types_by_name)
+
+  def testEnumTypesByName(self):
+    file_type = unittest_pb2.DESCRIPTOR
+    self.assertEqual(
+        unittest_pb2._FOREIGNENUM,
+        file_type.enum_types_by_name[unittest_pb2._FOREIGNENUM.name])
+
+  def testExtensionsByName(self):
+    file_type = unittest_pb2.DESCRIPTOR
+    self.assertEqual(
+        unittest_pb2.my_extension_string,
+        file_type.extensions_by_name[unittest_pb2.my_extension_string.name])
+
+  def testPublicImports(self):
+    # Test public imports as embedded message.
+    all_type_proto = unittest_pb2.TestAllTypes()
+    self.assertEqual(0, all_type_proto.optional_public_import_message.e)
+
+    # PublicImportMessage is actually defined in unittest_import_public_pb2
+    # module, and is public imported by unittest_import_pb2 module.
+    public_import_proto = unittest_import_pb2.PublicImportMessage()
+    self.assertEqual(0, public_import_proto.e)
+    self.assertTrue(unittest_import_public_pb2.PublicImportMessage is
+                    unittest_import_pb2.PublicImportMessage)
+
+  def testBadIdentifiers(self):
+    # We're just testing that the code was imported without problems.
+    message = test_bad_identifiers_pb2.TestBadIdentifiers()
+    self.assertEqual(message.Extensions[test_bad_identifiers_pb2.message],
+                     "foo")
+    self.assertEqual(message.Extensions[test_bad_identifiers_pb2.descriptor],
+                     "bar")
+    self.assertEqual(message.Extensions[test_bad_identifiers_pb2.reflection],
+                     "baz")
+    self.assertEqual(message.Extensions[test_bad_identifiers_pb2.service],
+                     "qux")
+
+  def testOneof(self):
+    desc = unittest_pb2.TestAllTypes.DESCRIPTOR
+    self.assertEqual(1, len(desc.oneofs))
+    self.assertEqual('oneof_field', desc.oneofs[0].name)
+    self.assertEqual(0, desc.oneofs[0].index)
+    self.assertIs(desc, desc.oneofs[0].containing_type)
+    self.assertIs(desc.oneofs[0], desc.oneofs_by_name['oneof_field'])
+    nested_names = set(['oneof_uint32', 'oneof_nested_message',
+                        'oneof_string', 'oneof_bytes'])
+    self.assertEqual(
+        nested_names,
+        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)
+
+  def testEnumWithDupValue(self):
+    self.assertEqual('FOO1',
+                     unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.FOO1))
+    self.assertEqual('FOO1',
+                     unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.FOO2))
+    self.assertEqual('BAR1',
+                     unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.BAR1))
+    self.assertEqual('BAR1',
+                     unittest_pb2.TestEnumWithDupValue.Name(unittest_pb2.BAR2))
+
+
+class SymbolDatabaseRegistrationTest(unittest.TestCase):
+  """Checks that messages, enums and files are correctly registered."""
+
+  def testGetSymbol(self):
+    self.assertEqual(
+        unittest_pb2.TestAllTypes, symbol_database.Default().GetSymbol(
+            'protobuf_unittest.TestAllTypes'))
+    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.assertEqual(
+        unittest_pb2.TestAllTypes.OptionalGroup,
+        symbol_database.Default().GetSymbol(
+            'protobuf_unittest.TestAllTypes.OptionalGroup'))
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.RepeatedGroup,
+        symbol_database.Default().GetSymbol(
+            'protobuf_unittest.TestAllTypes.RepeatedGroup'))
+
+  def testEnums(self):
+    self.assertEqual(
+        'protobuf_unittest.ForeignEnum',
+        symbol_database.Default().pool.FindEnumTypeByName(
+            'protobuf_unittest.ForeignEnum').full_name)
+    self.assertEqual(
+        'protobuf_unittest.TestAllTypes.NestedEnum',
+        symbol_database.Default().pool.FindEnumTypeByName(
+            'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
+
+  def testFindFileByName(self):
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        symbol_database.Default().pool.FindFileByName(
+            'google/protobuf/unittest.proto').name)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/import_test.py b/python/google/protobuf/internal/import_test.py
new file mode 100644
index 0000000..b5c572c
--- /dev/null
+++ b/python/google/protobuf/internal/import_test.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unittest for nested public imports."""
+
+import unittest
+
+from google.protobuf.internal.import_test_package import outer_pb2
+
+
+class ImportTest(unittest.TestCase):
+
+  def testPackageInitializationImport(self):
+    """Test that we can import nested import public messages."""
+
+    msg = outer_pb2.Outer()
+    self.assertEqual(58, msg.import_public_nested.value)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/import_test_package/__init__.py b/python/google/protobuf/internal/import_test_package/__init__.py
new file mode 100644
index 0000000..5121dd0
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/__init__.py
@@ -0,0 +1,33 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Sample module importing a nested proto from itself."""
+
+from google.protobuf.internal.import_test_package import outer_pb2 as myproto
diff --git a/python/google/protobuf/internal/import_test_package/import_public.proto b/python/google/protobuf/internal/import_test_package/import_public.proto
new file mode 100644
index 0000000..8774702
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/import_public.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A proto file which is imported by inner.proto to test public importing.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+option optimize_for = SPEED;
+
+// Test nested public import
+import public "google/protobuf/internal/import_test_package/import_public_nested.proto";
diff --git a/python/google/protobuf/internal/import_test_package/import_public_nested.proto b/python/google/protobuf/internal/import_test_package/import_public_nested.proto
new file mode 100644
index 0000000..fcf4d68
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/import_public_nested.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A proto file which is imported by import_public.proto to test nested public
+// importing.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+message ImportPublicNestedMessage {
+  optional int32 value = 1 [default = 58];
+}
diff --git a/python/google/protobuf/internal/import_test_package/inner.proto b/python/google/protobuf/internal/import_test_package/inner.proto
new file mode 100644
index 0000000..f20c22e
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/inner.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+// Test public import
+import public "google/protobuf/internal/import_test_package/import_public.proto";
+
+message Inner {
+  optional int32 value = 1 [default = 57];
+}
diff --git a/python/google/protobuf/internal/import_test_package/outer.proto b/python/google/protobuf/internal/import_test_package/outer.proto
new file mode 100644
index 0000000..7810aec
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/outer.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+import "google/protobuf/internal/import_test_package/inner.proto";
+
+message Outer {
+  optional Inner inner = 1;
+  optional ImportPublicNestedMessage import_public_nested = 2;
+}
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..d018c3f
--- /dev/null
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -0,0 +1,1285 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 struct
+
+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 import any_test_pb2
+from google.protobuf import unittest_mset_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf.internal import test_proto3_optional_pb2
+from google.protobuf import descriptor_pool
+from google.protobuf import json_format
+from google.protobuf.util import json_format_pb2
+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.assertRaisesRegex(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 testUnknownEnumToJsonAndBack(self):
+    text = '{\n  "enumValue": 999\n}'
+    message = json_format_proto3_pb2.TestMessage()
+    message.enum_value = 999
+    self.assertEqual(json_format.MessageToJson(message),
+                     text)
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testExtensionToJsonAndBack(self):
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    message_text = json_format.MessageToJson(
+        message
+    )
+    parsed_message = unittest_mset_pb2.TestMessageSetContainer()
+    json_format.Parse(message_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testExtensionErrors(self):
+    self.CheckError('{"[extensionField]": {}}',
+                    'Message type proto3.TestMessage does not have extensions')
+
+  def testExtensionToDictAndBack(self):
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    message_dict = json_format.MessageToDict(
+        message
+    )
+    parsed_message = unittest_mset_pb2.TestMessageSetContainer()
+    json_format.ParseDict(message_dict, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testExtensionToDictAndBackWithScalar(self):
+    message = unittest_pb2.TestAllExtensions()
+    ext1 = unittest_pb2.TestNestedExtension.test
+    message.Extensions[ext1] = 'data'
+    message_dict = json_format.MessageToDict(
+        message
+    )
+    parsed_message = unittest_pb2.TestAllExtensions()
+    json_format.ParseDict(message_dict, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testJsonParseDictToAnyDoesNotAlterInput(self):
+    orig_dict = {
+        'int32Value': 20,
+        '@type': 'type.googleapis.com/proto3.TestMessage'
+    }
+    copied_dict = json.loads(json.dumps(orig_dict))
+    parsed_message = any_pb2.Any()
+    json_format.ParseDict(copied_dict, parsed_message)
+    self.assertEqual(copied_dict, orig_dict)
+
+  def testExtensionSerializationDictMatchesProto3Spec(self):
+    """See go/proto3-json-spec for spec.
+    """
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    message_dict = json_format.MessageToDict(
+        message
+    )
+    golden_dict = {
+        'messageSet': {
+            '[protobuf_unittest.'
+            'TestMessageSetExtension1.message_set_extension]': {
+                'i': 23,
+            },
+            '[protobuf_unittest.'
+            'TestMessageSetExtension2.message_set_extension]': {
+                'str': u'foo',
+            },
+        },
+    }
+    self.assertEqual(golden_dict, message_dict)
+    parsed_msg = unittest_mset_pb2.TestMessageSetContainer()
+    json_format.ParseDict(golden_dict, parsed_msg)
+    self.assertEqual(message, parsed_msg)
+
+  def testExtensionSerializationDictMatchesProto3SpecMore(self):
+    """See go/proto3-json-spec for spec.
+    """
+    message = json_format_pb2.TestMessageWithExtension()
+    ext = json_format_pb2.TestExtension.ext
+    message.Extensions[ext].value = 'stuff'
+    message_dict = json_format.MessageToDict(
+        message
+    )
+    expected_dict = {
+        '[protobuf_unittest.TestExtension.ext]': {
+            'value': u'stuff',
+        },
+    }
+    self.assertEqual(expected_dict, message_dict)
+
+  def testExtensionSerializationJsonMatchesProto3Spec(self):
+    """See go/proto3-json-spec for spec.
+    """
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    message_text = json_format.MessageToJson(
+        message
+    )
+    ext1_text = ('protobuf_unittest.TestMessageSetExtension1.'
+                 'message_set_extension')
+    ext2_text = ('protobuf_unittest.TestMessageSetExtension2.'
+                 'message_set_extension')
+    golden_text = ('{"messageSet": {'
+                   '    "[%s]": {'
+                   '        "i": 23'
+                   '    },'
+                   '    "[%s]": {'
+                   '        "str": "foo"'
+                   '    }'
+                   '}}') % (ext1_text, ext2_text)
+    self.assertEqual(json.loads(golden_text), json.loads(message_text))
+
+  def testJsonEscapeString(self):
+    message = json_format_proto3_pb2.TestMessage()
+    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 testProto3Optional(self):
+    message = test_proto3_optional_pb2.TestProto3Optional()
+    self.assertEqual(
+        json.loads(
+            json_format.MessageToJson(
+                message, including_default_value_fields=True)),
+        json.loads('{}'))
+    message.optional_int32 = 0
+    self.assertEqual(
+        json.loads(
+            json_format.MessageToJson(
+                message, including_default_value_fields=True)),
+        json.loads('{"optionalInt32": 0}'))
+
+  def testIntegersRepresentedAsFloat(self):
+    message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse('{"int32Value": -2.147483648e9}', message)
+    self.assertEqual(message.int32_value, -2147483648)
+    json_format.Parse('{"int32Value": 1e5}', message)
+    self.assertEqual(message.int32_value, 100000)
+    json_format.Parse('{"int32Value": 1.0}', message)
+    self.assertEqual(message.int32_value, 1)
+
+  def testMapFields(self):
+    message = json_format_proto3_pb2.TestNestedMap()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"boolMap": {},'
+                   '"int32Map": {},'
+                   '"int64Map": {},'
+                   '"uint32Map": {},'
+                   '"uint64Map": {},'
+                   '"stringMap": {},'
+                   '"mapMap": {}'
+                   '}'))
+    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
+    message.map_map['1'].bool_map[True] = 3
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        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},'
+                   '"mapMap": {"1": {"boolMap": {"true": 3}}}'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestNestedMap()
+    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 testSurrogates(self):
+    # Test correct surrogate handling.
+    message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse('{"stringValue": "\\uD83D\\uDE01"}', message)
+    self.assertEqual(message.string_value,
+                     b'\xF0\x9F\x98\x81'.decode('utf-8', 'strict'))
+
+    # Error case: unpaired high surrogate.
+    self.CheckError(
+        '{"stringValue": "\\uD83D"}',
+        r'Invalid \\uXXXX escape|Unpaired.*surrogate')
+
+    # Unpaired low surrogate.
+    self.CheckError(
+        '{"stringValue": "\\uDE01"}',
+        r'Invalid \\uXXXX escape|Unpaired.*surrogate')
+
+  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)
+
+    message.value.Clear()
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{\n'
+        '  "value": ""\n'
+        '}')
+    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
+    message.value.get_or_create_struct('empty_struct')
+    message.value.get_or_create_list('empty_list')
+    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'
+            '    }, '
+            '    "empty_struct": {}, '
+            '    "empty_list": [], '
+            '    "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)
+    # check for regression; this used to raise
+    parsed_message.value['empty_struct']
+    parsed_message.value['empty_list']
+
+  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]'
+            '}'))
+    message.Clear()
+    json_format.Parse('{"value": null}', message)
+    self.assertEqual(message.value.WhichOneof('kind'), 'null_value')
+
+  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 testNullValue(self):
+    message = json_format_proto3_pb2.TestOneof()
+    message.oneof_null_value = 0
+    self.assertEqual(json_format.MessageToJson(message),
+                     '{\n  "oneofNullValue": null\n}')
+    parsed_message = json_format_proto3_pb2.TestOneof()
+    self.CheckParseBack(message, parsed_message)
+    # Check old format is also accepted
+    new_message = json_format_proto3_pb2.TestOneof()
+    json_format.Parse('{\n  "oneofNullValue": "NULL_VALUE"\n}',
+                      new_message)
+    self.assertEqual(json_format.MessageToJson(new_message),
+                     '{\n  "oneofNullValue": null\n}')
+
+  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)
+    # Must print @type first
+    test_message = json_format_proto3_pb2.TestMessage(
+        bool_value=True,
+        int32_value=20,
+        int64_value=-20,
+        uint32_value=20,
+        uint64_value=20,
+        double_value=3.14,
+        string_value='foo')
+    message.Clear()
+    message.value.Pack(test_message)
+    self.assertEqual(
+        json_format.MessageToJson(message, False)[0:68],
+        '{\n'
+        '  "value": {\n'
+        '    "@type": "type.googleapis.com/proto3.TestMessage"')
+
+  def testAnyMessageDescriptorPoolMissingType(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    empty_pool = descriptor_pool.DescriptorPool()
+    with self.assertRaises(TypeError) as cm:
+      json_format.MessageToJson(message, True, descriptor_pool=empty_pool)
+    self.assertEqual(
+        'Can not find message descriptor by type_url:'
+        ' type.googleapis.com/protobuf_unittest.OneString', str(cm.exception))
+
+  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)
+    # Null and {} should have different behavior for sub message.
+    self.assertFalse(parsed_message.HasField('message_value'))
+    json_format.Parse('{"messageValue": {}}', parsed_message)
+    self.assertTrue(parsed_message.HasField('message_value'))
+    # Null is not allowed to be used as an element in repeated field.
+    self.assertRaisesRegex(
+        json_format.ParseError, r'Failed to parse repeatedInt32Value field: '
+        r'null is not allowed to be used as an element in a repeated field '
+        r'at TestMessage.repeatedInt32Value\[1\].', json_format.Parse,
+        '{"repeatedInt32Value":[1, null]}', parsed_message)
+    self.CheckError(
+        '{"repeatedMessageValue":[null]}',
+        r'Failed to parse repeatedMessageValue field: null is not'
+        r' allowed to be used as an element in a repeated field '
+        r'at TestMessage.repeatedMessageValue\[0\].')
+
+  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 testParseDoubleToFloat(self):
+    message = json_format_proto3_pb2.TestMessage()
+    text = ('{"repeatedDoubleValue": [3.4028235e+39, 1.4028235e-39]\n}')
+    json_format.Parse(text, message)
+    self.assertEqual(message.repeated_double_value[0], 3.4028235e+39)
+    self.assertEqual(message.repeated_double_value[1], 1.4028235e-39)
+    text = ('{"repeatedFloatValue": [3.4028235e+39, 1.4028235e-39]\n}')
+    self.CheckError(
+        text, r'Failed to parse repeatedFloatValue field: '
+        r'Float value too large at TestMessage.repeatedFloatValue\[0\].')
+
+  def testFloatPrecision(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.float_value = 1.123456789
+    # Set to 8 valid digits.
+    text = '{\n  "floatValue": 1.1234568\n}'
+    self.assertEqual(
+        json_format.MessageToJson(message, float_precision=8), text)
+    # Set to 7 valid digits.
+    text = '{\n  "floatValue": 1.123457\n}'
+    self.assertEqual(
+        json_format.MessageToJson(message, float_precision=7), text)
+
+    # Default float_precision will automatic print shortest float.
+    message.float_value = 1.1000000011
+    text = '{\n  "floatValue": 1.1\n}'
+    self.assertEqual(
+        json_format.MessageToJson(message), text)
+    message.float_value = 1.00000075e-36
+    text = '{\n  "floatValue": 1.00000075e-36\n}'
+    self.assertEqual(
+        json_format.MessageToJson(message), text)
+    message.float_value = 12345678912345e+11
+    text = '{\n  "floatValue": 1.234568e+24\n}'
+    self.assertEqual(
+        json_format.MessageToJson(message), text)
+
+    # Test a bunch of data and check json encode/decode do not
+    # lose precision
+    value_list = [0x00, 0xD8, 0x6E, 0x00]
+    msg2 = json_format_proto3_pb2.TestMessage()
+    for a in range(0, 256):
+      value_list[3] = a
+      for b in range(0, 256):
+        value_list[0] = b
+        byte_array = bytearray(value_list)
+        message.float_value = struct.unpack('<f', byte_array)[0]
+        self.CheckParseBack(message, msg2)
+
+  def testParseEmptyText(self):
+    self.CheckError('',
+                    r'Failed to load JSON: (Expecting value)|(No JSON).')
+
+  def testParseEnumValue(self):
+    message = json_format_proto3_pb2.TestMessage()
+    text = '{"enumValue": 0}'
+    json_format.Parse(text, message)
+    text = '{"enumValue": 1}'
+    json_format.Parse(text, message)
+    self.CheckError(
+        '{"enumValue": "baz"}',
+        'Failed to parse enumValue field: Invalid enum value baz '
+        'for enum type proto3.EnumType at TestMessage.enumValue.')
+    # Proto3 accepts numeric unknown enums.
+    text = '{"enumValue": 12345}'
+    json_format.Parse(text, message)
+    # Proto2 does not accept unknown enums.
+    message = unittest_pb2.TestAllTypes()
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        'Failed to parse optionalNestedEnum field: Invalid enum value 12345 '
+        'for enum type protobuf_unittest.TestAllTypes.NestedEnum at '
+        'TestAllTypes.optionalNestedEnum.', json_format.Parse,
+        '{"optionalNestedEnum": 12345}', message)
+
+  def testBytes(self):
+    message = json_format_proto3_pb2.TestMessage()
+    # Test url base64
+    text = '{"bytesValue": "-_"}'
+    json_format.Parse(text, message)
+    self.assertEqual(message.bytes_value, b'\xfb')
+    # Test padding
+    text = '{"bytesValue": "AQI="}'
+    json_format.Parse(text, message)
+    self.assertEqual(message.bytes_value, b'\x01\x02')
+    text = '{"bytesValue": "AQI"}'
+    json_format.Parse(text, message)
+    self.assertEqual(message.bytes_value, b'\x01\x02')
+    text = '{"bytesValue": "AQI*"}'
+    json_format.Parse(text, message)
+    self.assertEqual(message.bytes_value, b'\x01\x02')
+
+  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" at "TestMessage".')
+
+  def testIgnoreUnknownField(self):
+    text = '{"unknownName": 1}'
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
+    text = ('{\n'
+            '  "repeatedValue": [ {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "unknownName": 1\n'
+            '  }]\n'
+            '}\n')
+    parsed_message = json_format_proto3_pb2.TestAny()
+    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
+
+  def testDuplicateField(self):
+    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 at TestMessage.boolValue.')
+    self.CheckError(
+        '{"boolValue": "true"}', 'Failed to parse boolValue field: '
+        'Expected true or false without quotes at TestMessage.boolValue.')
+
+  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": 1.5}', 'Failed to parse int32Value field: '
+        'Couldn\'t parse integer: 1.5 at TestMessage.int32Value.')
+    self.CheckError('{"int32Value": 012345}',
+                    (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
+                     r'line 1.'))
+    self.CheckError(
+        '{"int32Value": " 1 "}', 'Failed to parse int32Value field: '
+        'Couldn\'t parse integer: " 1 " at TestMessage.int32Value.')
+    self.CheckError(
+        '{"int32Value": "1 "}', 'Failed to parse int32Value field: '
+        'Couldn\'t parse integer: "1 " at TestMessage.int32Value.')
+    self.CheckError(
+        '{"int32Value": false}',
+        'Failed to parse int32Value field: Bool value False '
+        'is not acceptable for integer field at TestMessage.int32Value.')
+    self.CheckError('{"int32Value": 12345678901234567890}',
+                    'Failed to parse int32Value field: Value out of range: '
+                    '12345678901234567890.')
+    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 at TestMessage.floatValue.')
+    self.CheckError('{"floatValue": NaN}',
+                    'Failed to parse floatValue field: Couldn\'t '
+                    'parse NaN, use quoted "NaN" instead.')
+    self.CheckError('{"floatValue": Infinity}',
+                    'Failed to parse floatValue field: Couldn\'t parse Infinity'
+                    ' or value too large, use quoted "Infinity" instead.')
+    self.CheckError('{"floatValue": -Infinity}',
+                    'Failed to parse floatValue field: Couldn\'t parse '
+                    '-Infinity or value too small, '
+                    'use quoted "-Infinity" instead.')
+    self.CheckError('{"doubleValue": -1.89769e+308}',
+                    'Failed to parse doubleValue field: Couldn\'t parse '
+                    '-Infinity or value too small, '
+                    'use quoted "-Infinity" instead.')
+    self.CheckError('{"floatValue": 3.4028235e+39}',
+                    'Failed to parse floatValue field: Float value too large.')
+    self.CheckError('{"floatValue": -3.502823e+38}',
+                    'Failed to parse floatValue field: Float value too small.')
+
+  def testInvalidRepeated(self):
+    self.CheckError(
+        '{"repeatedInt32Value": 12345}',
+        (r'Failed to parse repeatedInt32Value field: repeated field'
+         r' repeatedInt32Value must be in \[\] which is 12345 at TestMessage.'))
+
+  def testInvalidMap(self):
+    message = json_format_proto3_pb2.TestMap()
+    text = '{"int32Map": {"null": 2, "2": 3}}'
+    self.assertRaisesRegex(json_format.ParseError,
+                           'Failed to parse int32Map field: invalid literal',
+                           json_format.Parse, text, message)
+    text = '{"int32Map": {1: 2, "2": 3}}'
+    self.assertRaisesRegex(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.assertRaisesRegex(
+        json_format.ParseError,
+        'Failed to parse boolMap field: Expected "true" or "false", not null at '
+        'TestMap.boolMap.key', json_format.Parse, text, message)
+    text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
+    self.assertRaisesRegex(json_format.ParseError,
+                           'Failed to load JSON: duplicate key a',
+                           json_format.Parse, text, message)
+    text = r'{"stringMap": 0}'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        'Failed to parse stringMap field: Map field string_map must be '
+        'in a dict which is 0 at TestMap.stringMap.', 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, 'Failed to parse value field: '
+        'time data \'10000-01-01T00:00:00\' does not match'
+        ' format \'%Y-%m-%dT%H:%M:%S\' at TestTimestamp.value.',
+        json_format.Parse, text, message)
+    text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        'nanos 0123456789012 more than 9 fractional digits.', json_format.Parse,
+        text, message)
+    text = '{"value": "1972-01-01T01:00:00.01+08"}'
+    self.assertRaisesRegex(json_format.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.assertRaisesRegex(
+        json_format.ParseError,
+        'Failed to parse value field: year (0 )?is out of range.',
+        json_format.Parse, text, message)
+    # Time bigger than maximum time.
+    message.value.seconds = 253402300800
+    self.assertRaisesRegex(OverflowError, 'date value out of range',
+                           json_format.MessageToJson, message)
+    # Lower case t does not accept.
+    text = '{"value": "0001-01-01t00:00:00Z"}'
+    with self.assertRaises(json_format.ParseError) as e:
+      json_format.Parse(text, message)
+    self.assertEqual(
+        'Failed to parse value field: '
+        'time data \'0001-01-01t00:00:00\' does not match format '
+        '\'%Y-%m-%dT%H:%M:%S\', lowercase \'t\' is not accepted '
+        'at TestTimestamp.value.', str(e.exception))
+
+  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 at "TestOneof".',
+        json_format.Parse, text, message)
+
+  def testInvalidListValue(self):
+    message = json_format_proto3_pb2.TestListValue()
+    text = '{"value": 1234}'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        r'Failed to parse value field: ListValue must be in \[\] which is '
+        '1234 at TestListValue.value.', json_format.Parse, text, message)
+
+    class UnknownClass(object):
+
+      def __str__(self):
+        return 'v'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        r' at TestListValue.value\[1\].fake.',
+        json_format.ParseDict,
+        {'value': ['hello', {'fake': UnknownClass()}]}, message)
+
+  def testInvalidStruct(self):
+    message = json_format_proto3_pb2.TestStruct()
+    text = '{"value": 1234}'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        'Failed to parse value field: Struct must be in a dict which is '
+        '1234 at TestStruct.value', json_format.Parse, text, message)
+
+  def testTimestampInvalidStringValue(self):
+    message = json_format_proto3_pb2.TestTimestamp()
+    text = '{"value": {"foo": 123}}'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        r"Timestamp JSON value not a string: {u?'foo': 123}", json_format.Parse,
+        text, message)
+
+  def testDurationInvalidStringValue(self):
+    message = json_format_proto3_pb2.TestDuration()
+    text = '{"value": {"foo": 123}}'
+    self.assertRaisesRegex(json_format.ParseError,
+                           r"Duration JSON value not a string: {u?'foo': 123}",
+                           json_format.Parse, text, message)
+
+  def testFieldMaskInvalidStringValue(self):
+    message = json_format_proto3_pb2.TestFieldMask()
+    text = '{"value": {"foo": 123}}'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        r"FieldMask JSON value not a string: {u?'foo': 123}", json_format.Parse,
+        text, message)
+
+  def testInvalidAny(self):
+    message = any_pb2.Any()
+    text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
+    self.assertRaisesRegex(KeyError, 'value', json_format.Parse, text, message)
+    text = '{"value": 1234}'
+    self.assertRaisesRegex(json_format.ParseError,
+                           '@type is missing when parsing any message at Any',
+                           json_format.Parse, text, message)
+    text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
+    self.assertRaisesRegex(
+        json_format.ParseError, 'Can not find message descriptor by type_url: '
+        'type.googleapis.com/MessageNotExist at Any', json_format.Parse, text,
+        message)
+    # Only last part is to be used: b/25630112
+    text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
+            r'"value": 1234}')
+    json_format.Parse(text, message)
+
+  def testPreservingProtoFieldNames(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.int32_value = 12345
+    self.assertEqual('{\n  "int32Value": 12345\n}',
+                     json_format.MessageToJson(message))
+    self.assertEqual('{\n  "int32_value": 12345\n}',
+                     json_format.MessageToJson(message, False, True))
+    # When including_default_value_fields is True.
+    message = json_format_proto3_pb2.TestTimestamp()
+    self.assertEqual('{\n  "repeatedValue": []\n}',
+                     json_format.MessageToJson(message, True, False))
+    self.assertEqual('{\n  "repeated_value": []\n}',
+                     json_format.MessageToJson(message, True, True))
+
+    # Parsers accept both original proto field names and lowerCamelCase names.
+    message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse('{"int32Value": 54321}', message)
+    self.assertEqual(54321, message.int32_value)
+    json_format.Parse('{"int32_value": 12345}', message)
+    self.assertEqual(12345, message.int32_value)
+
+  def testIndent(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.int32_value = 12345
+    self.assertEqual('{\n"int32Value": 12345\n}',
+                     json_format.MessageToJson(message, indent=0))
+
+  def testFormatEnumsAsInts(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.enum_value = json_format_proto3_pb2.BAR
+    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
+    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
+    self.assertEqual(json.loads('{\n'
+                                '  "enumValue": 1,\n'
+                                '  "repeatedEnumValue": [0, 1]\n'
+                                '}\n'),
+                     json.loads(json_format.MessageToJson(
+                         message, use_integers_for_enums=True)))
+
+  def testParseDict(self):
+    expected = 12345
+    js_dict = {'int32Value': expected}
+    message = json_format_proto3_pb2.TestMessage()
+    json_format.ParseDict(js_dict, message)
+    self.assertEqual(expected, message.int32_value)
+
+  def testParseDictAnyDescriptorPoolMissingType(self):
+    # Confirm that ParseDict does not raise ParseError with default pool
+    js_dict = {
+        'any_value': {
+            '@type': 'type.googleapis.com/proto3.MessageType',
+            'value': 1234
+        }
+    }
+    json_format.ParseDict(js_dict, any_test_pb2.TestAny())
+    # Check ParseDict raises ParseError with empty pool
+    js_dict = {
+        'any_value': {
+            '@type': 'type.googleapis.com/proto3.MessageType',
+            'value': 1234
+        }
+    }
+    with self.assertRaises(json_format.ParseError) as cm:
+      empty_pool = descriptor_pool.DescriptorPool()
+      json_format.ParseDict(js_dict,
+                            any_test_pb2.TestAny(),
+                            descriptor_pool=empty_pool)
+    self.assertEqual(
+        str(cm.exception),
+        'Failed to parse any_value field: Can not find message descriptor by'
+        ' type_url: type.googleapis.com/proto3.MessageType at '
+        'TestAny.any_value.'
+    )
+
+  def testParseDictUnknownValueType(self):
+    class UnknownClass(object):
+
+      def __repr__(self):
+        return 'v'
+    message = json_format_proto3_pb2.TestValue()
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        r"Value v has unexpected type <class '.*\.UnknownClass'>.",
+        json_format.ParseDict, {'value': UnknownClass()}, message)
+
+  def testMessageToDict(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.int32_value = 12345
+    expected = {'int32Value': 12345}
+    self.assertEqual(expected,
+                     json_format.MessageToDict(message))
+
+  def testJsonName(self):
+    message = json_format_proto3_pb2.TestCustomJsonName()
+    message.value = 12345
+    self.assertEqual('{\n  "@value": 12345\n}',
+                     json_format.MessageToJson(message))
+    parsed_message = json_format_proto3_pb2.TestCustomJsonName()
+    self.CheckParseBack(message, parsed_message)
+
+  def testSortKeys(self):
+    # Testing sort_keys is not perfectly working, as by random luck we could
+    # get the output sorted. We just use a selection of names.
+    message = json_format_proto3_pb2.TestMessage(bool_value=True,
+                                                 int32_value=1,
+                                                 int64_value=3,
+                                                 uint32_value=4,
+                                                 string_value='bla')
+    self.assertEqual(
+        json_format.MessageToJson(message, sort_keys=True),
+        # We use json.dumps() instead of a hardcoded string due to differences
+        # between Python 2 and Python 3.
+        json.dumps({'boolValue': True, 'int32Value': 1, 'int64Value': '3',
+                    'uint32Value': 4, 'stringValue': 'bla'},
+                   indent=2, sort_keys=True))
+
+  def testNestedRecursiveLimit(self):
+    message = unittest_pb2.NestedTestAllTypes()
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        'Message too deep. Max recursion depth is 3',
+        json_format.Parse,
+        '{"child": {"child": {"child" : {}}}}',
+        message,
+        max_recursion_depth=3)
+    # The following one can pass
+    json_format.Parse('{"payload": {}, "child": {"child":{}}}',
+                      message, max_recursion_depth=3)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/keywords_test.py b/python/google/protobuf/internal/keywords_test.py
new file mode 100644
index 0000000..4182cf6
--- /dev/null
+++ b/python/google/protobuf/internal/keywords_test.py
@@ -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.
+
+"""Tests for google.protobuf.internal.keywords."""
+
+import unittest
+
+
+from google.protobuf.internal import more_messages_pb2
+from google.protobuf import descriptor_pool
+
+
+class KeywordsConflictTest(unittest.TestCase):
+
+  def setUp(self):
+    super(KeywordsConflictTest, self).setUp()
+    self.pool = descriptor_pool.Default()
+
+  def testMessage(self):
+    message = getattr(more_messages_pb2, 'class')()
+    message.int_field = 123
+    self.assertEqual(message.int_field, 123)
+    des = self.pool.FindMessageTypeByName('google.protobuf.internal.class')
+    self.assertEqual(des.name, 'class')
+
+  def testNestedMessage(self):
+    message = getattr(more_messages_pb2, 'class')()
+    message.nested_message.field = 234
+    self.assertEqual(message.nested_message.field, 234)
+    des = self.pool.FindMessageTypeByName('google.protobuf.internal.class.try')
+    self.assertEqual(des.name, 'try')
+
+  def testField(self):
+    message = getattr(more_messages_pb2, 'class')()
+    setattr(message, 'if', 123)
+    setattr(message, 'as', 1)
+    self.assertEqual(getattr(message, 'if'), 123)
+    self.assertEqual(getattr(message, 'as'), 1)
+
+  def testEnum(self):
+    class_ = getattr(more_messages_pb2, 'class')
+    message = class_()
+    # Normal enum value.
+    message.enum_field = more_messages_pb2.default
+    self.assertEqual(message.enum_field, more_messages_pb2.default)
+    # Top level enum value.
+    message.enum_field = getattr(more_messages_pb2, 'else')
+    self.assertEqual(message.enum_field, 1)
+    # Nested enum value
+    message.nested_enum_field = getattr(class_, 'True')
+    self.assertEqual(message.nested_enum_field, 1)
+
+  def testExtension(self):
+    message = getattr(more_messages_pb2, 'class')()
+    # Top level extension
+    extension1 = getattr(more_messages_pb2, 'continue')
+    message.Extensions[extension1] = 456
+    self.assertEqual(message.Extensions[extension1], 456)
+    # None top level extension
+    extension2 = getattr(more_messages_pb2.ExtendClass, 'return')
+    message.Extensions[extension2] = 789
+    self.assertEqual(message.Extensions[extension2], 789)
+
+  def testExtensionForNestedMessage(self):
+    message = getattr(more_messages_pb2, 'class')()
+    extension = getattr(more_messages_pb2, 'with')
+    message.nested_message.Extensions[extension] = 999
+    self.assertEqual(message.nested_message.Extensions[extension], 999)
+
+  def TestFullKeywordUsed(self):
+    message = more_messages_pb2.TestFullKeyword()
+    message.field2.int_field = 123
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
new file mode 100644
index 0000000..efba619
--- /dev/null
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -0,0 +1,299 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests for google.protobuf.message_factory."""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+import unittest
+
+from google.protobuf import descriptor_pb2
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import factory_test1_pb2
+from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import testing_refleaks
+from google.protobuf import descriptor_database
+from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
+
+
+@testing_refleaks.TestCase
+class MessageFactoryTest(unittest.TestCase):
+
+  def setUp(self):
+    self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test1_pb2.DESCRIPTOR.serialized_pb)
+    self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        factory_test2_pb2.DESCRIPTOR.serialized_pb)
+
+  def _ExerciseDynamicClass(self, cls):
+    msg = cls()
+    msg.mandatory = 42
+    msg.nested_factory_2_enum = 0
+    msg.nested_factory_2_message.value = 'nested message value'
+    msg.factory_1_message.factory_1_enum = 1
+    msg.factory_1_message.nested_factory_1_enum = 0
+    msg.factory_1_message.nested_factory_1_message.value = (
+        'nested message value')
+    msg.factory_1_message.scalar_value = 22
+    msg.factory_1_message.list_value.extend([u'one', u'two', u'three'])
+    msg.factory_1_message.list_value.append(u'four')
+    msg.factory_1_enum = 1
+    msg.nested_factory_1_enum = 0
+    msg.nested_factory_1_message.value = 'nested message value'
+    msg.circular_message.mandatory = 1
+    msg.circular_message.circular_message.mandatory = 2
+    msg.circular_message.scalar_value = 'one deep'
+    msg.scalar_value = 'zero deep'
+    msg.list_value.extend([u'four', u'three', u'two'])
+    msg.list_value.append(u'one')
+    msg.grouped.add()
+    msg.grouped[0].part_1 = 'hello'
+    msg.grouped[0].part_2 = 'world'
+    msg.grouped.add(part_1='testing', part_2='123')
+    msg.loop.loop.mandatory = 2
+    msg.loop.loop.loop.loop.mandatory = 4
+    serialized = msg.SerializeToString()
+    converted = factory_test2_pb2.Factory2Message.FromString(serialized)
+    reserialized = converted.SerializeToString()
+    self.assertEqual(serialized, reserialized)
+    result = cls.FromString(reserialized)
+    self.assertEqual(msg, result)
+
+  def testGetPrototype(self):
+    db = descriptor_database.DescriptorDatabase()
+    pool = descriptor_pool.DescriptorPool(db)
+    db.Add(self.factory_test1_fd)
+    db.Add(self.factory_test2_fd)
+    factory = message_factory.MessageFactory()
+    cls = factory.GetPrototype(pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message'))
+    self.assertFalse(cls is factory_test2_pb2.Factory2Message)
+    self._ExerciseDynamicClass(cls)
+    cls2 = factory.GetPrototype(pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message'))
+    self.assertTrue(cls is cls2)
+
+  def testCreatePrototypeOverride(self):
+    class MyMessageFactory(message_factory.MessageFactory):
+
+      def CreatePrototype(self, descriptor):
+        cls = super(MyMessageFactory, self).CreatePrototype(descriptor)
+        cls.additional_field = 'Some value'
+        return cls
+
+    db = descriptor_database.DescriptorDatabase()
+    pool = descriptor_pool.DescriptorPool(db)
+    db.Add(self.factory_test1_fd)
+    db.Add(self.factory_test2_fd)
+    factory = MyMessageFactory()
+    cls = factory.GetPrototype(pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message'))
+    self.assertTrue(hasattr(cls, 'additional_field'))
+
+  def testGetMessages(self):
+    # performed twice because multiple calls with the same input must be allowed
+    for _ in range(2):
+      # GetMessage should work regardless of the order the FileDescriptorProto
+      # are provided. In particular, the function should succeed when the files
+      # are not in the topological order of dependencies.
+
+      # Assuming factory_test2_fd depends on factory_test1_fd.
+      self.assertIn(self.factory_test1_fd.name,
+                    self.factory_test2_fd.dependency)
+      # Get messages should work when a file comes before its dependencies:
+      # factory_test2_fd comes before factory_test1_fd.
+      messages = message_factory.GetMessages([self.factory_test2_fd,
+                                              self.factory_test1_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'])
+      factory_msg1 = messages['google.protobuf.python.internal.Factory1Message']
+      self.assertTrue(set(
+          ['google.protobuf.python.internal.Factory2Message.one_more_field',
+           'google.protobuf.python.internal.another_field'],).issubset(set(
+               ext.full_name
+               for ext in factory_msg1.DESCRIPTOR.file.pool.FindAllExtensions(
+                   factory_msg1.DESCRIPTOR))))
+      msg1 = messages['google.protobuf.python.internal.Factory1Message']()
+      ext1 = msg1.Extensions._FindExtensionByName(
+          'google.protobuf.python.internal.Factory2Message.one_more_field')
+      ext2 = msg1.Extensions._FindExtensionByName(
+          'google.protobuf.python.internal.another_field')
+      self.assertEqual(0, len(msg1.Extensions))
+      msg1.Extensions[ext1] = 'test1'
+      msg1.Extensions[ext2] = 'test2'
+      self.assertEqual('test1', msg1.Extensions[ext1])
+      self.assertEqual('test2', msg1.Extensions[ext2])
+      self.assertEqual(None,
+                       msg1.Extensions._FindExtensionByNumber(12321))
+      self.assertEqual(2, len(msg1.Extensions))
+      if api_implementation.Type() == 'cpp':
+        self.assertRaises(TypeError,
+                          msg1.Extensions._FindExtensionByName, 0)
+        self.assertRaises(TypeError,
+                          msg1.Extensions._FindExtensionByNumber, '')
+      else:
+        self.assertEqual(None,
+                         msg1.Extensions._FindExtensionByName(0))
+        self.assertEqual(None,
+                         msg1.Extensions._FindExtensionByNumber(''))
+
+  def testDuplicateExtensionNumber(self):
+    pool = descriptor_pool.DescriptorPool()
+    factory = message_factory.MessageFactory(pool=pool)
+
+    # Add Container message.
+    f = descriptor_pb2.FileDescriptorProto(
+        name='google/protobuf/internal/container.proto',
+        package='google.protobuf.python.internal')
+    f.message_type.add(name='Container').extension_range.add(start=1, end=10)
+    pool.Add(f)
+    msgs = factory.GetMessages([f.name])
+    self.assertIn('google.protobuf.python.internal.Container', msgs)
+
+    # Extend container.
+    f = descriptor_pb2.FileDescriptorProto(
+        name='google/protobuf/internal/extension.proto',
+        package='google.protobuf.python.internal',
+        dependency=['google/protobuf/internal/container.proto'])
+    msg = f.message_type.add(name='Extension')
+    msg.extension.add(
+        name='extension_field',
+        number=2,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,
+        type_name='Extension',
+        extendee='Container')
+    pool.Add(f)
+    msgs = factory.GetMessages([f.name])
+    self.assertIn('google.protobuf.python.internal.Extension', msgs)
+
+    # Add Duplicate extending the same field number.
+    f = descriptor_pb2.FileDescriptorProto(
+        name='google/protobuf/internal/duplicate.proto',
+        package='google.protobuf.python.internal',
+        dependency=['google/protobuf/internal/container.proto'])
+    msg = f.message_type.add(name='Duplicate')
+    msg.extension.add(
+        name='extension_field',
+        number=2,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,
+        type_name='Duplicate',
+        extendee='Container')
+    pool.Add(f)
+
+    with self.assertRaises(Exception) as cm:
+      factory.GetMessages([f.name])
+
+    self.assertIn(str(cm.exception),
+                  ['Extensions '
+                   '"google.protobuf.python.internal.Duplicate.extension_field" and'
+                   ' "google.protobuf.python.internal.Extension.extension_field"'
+                   ' both try to extend message type'
+                   ' "google.protobuf.python.internal.Container"'
+                   ' with field number 2.',
+                   'Double registration of Extensions'])
+
+  def testExtensionValueInDifferentFile(self):
+    # Add Container message.
+    f1 = descriptor_pb2.FileDescriptorProto(
+        name='google/protobuf/internal/container.proto',
+        package='google.protobuf.python.internal')
+    f1.message_type.add(name='Container').extension_range.add(start=1, end=10)
+
+    # Add ValueType message.
+    f2 = descriptor_pb2.FileDescriptorProto(
+        name='google/protobuf/internal/value_type.proto',
+        package='google.protobuf.python.internal')
+    f2.message_type.add(name='ValueType').field.add(
+        name='setting',
+        number=1,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,
+        type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,
+        default_value='123')
+
+    # Extend container with field of ValueType.
+    f3 = descriptor_pb2.FileDescriptorProto(
+        name='google/protobuf/internal/extension.proto',
+        package='google.protobuf.python.internal',
+        dependency=[f1.name, f2.name])
+    f3.extension.add(
+        name='top_level_extension_field',
+        number=2,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,
+        type_name='ValueType',
+        extendee='Container')
+    f3.message_type.add(name='Extension').extension.add(
+        name='nested_extension_field',
+        number=3,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL,
+        type_name='ValueType',
+        extendee='Container')
+
+    class SimpleDescriptorDB:
+
+      def __init__(self, files):
+        self._files = files
+
+      def FindFileByName(self, name):
+        return self._files[name]
+
+    db = SimpleDescriptorDB({f1.name: f1, f2.name: f2, f3.name: f3})
+
+    pool = descriptor_pool.DescriptorPool(db)
+    factory = message_factory.MessageFactory(pool=pool)
+    msgs = factory.GetMessages([f1.name, f3.name])  # Deliberately not f2.
+    msg = msgs['google.protobuf.python.internal.Container']
+    desc = msgs['google.protobuf.python.internal.Extension'].DESCRIPTOR
+    ext1 = desc.file.extensions_by_name['top_level_extension_field']
+    ext2 = desc.extensions_by_name['nested_extension_field']
+    m = msg()
+    m.Extensions[ext1].setting = 234
+    m.Extensions[ext2].setting = 345
+    serialized = m.SerializeToString()
+
+    pool = descriptor_pool.DescriptorPool(db)
+    factory = message_factory.MessageFactory(pool=pool)
+    msgs = factory.GetMessages([f1.name, f3.name])  # Deliberately not f2.
+    msg = msgs['google.protobuf.python.internal.Container']
+    desc = msgs['google.protobuf.python.internal.Extension'].DESCRIPTOR
+    ext1 = desc.file.extensions_by_name['top_level_extension_field']
+    ext2 = desc.extensions_by_name['nested_extension_field']
+    m = msg.FromString(serialized)
+    self.assertEqual(2, len(m.ListFields()))
+    self.assertEqual(234, m.Extensions[ext1].setting)
+    self.assertEqual(345, m.Extensions[ext2].setting)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/message_listener.py b/python/google/protobuf/internal/message_listener.py
new file mode 100644
index 0000000..0fc255a
--- /dev/null
+++ b/python/google/protobuf/internal/message_listener.py
@@ -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.
+
+"""Defines a listener interface for observing certain
+state transitions on Message objects.
+
+Also defines a null implementation of this interface.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+
+class MessageListener(object):
+
+  """Listens for modifications made to a message.  Meant to be registered via
+  Message._SetListener().
+
+  Attributes:
+    dirty:  If True, then calling Modified() would be a no-op.  This can be
+            used to avoid these calls entirely in the common case.
+  """
+
+  def Modified(self):
+    """Called every time the message is modified in such a way that the parent
+    message may need to be updated.  This currently means either:
+    (a) The message was modified for the first time, so the parent message
+        should henceforth mark the message as present.
+    (b) The message's cached byte size became dirty -- i.e. the message was
+        modified for the first time after a previous call to ByteSize().
+        Therefore the parent should also mark its byte size as dirty.
+    Note that (a) implies (b), since new objects start out with a client cached
+    size (zero).  However, we document (a) explicitly because it is important.
+
+    Modified() will *only* be called in response to one of these two events --
+    not every time the sub-message is modified.
+
+    Note that if the listener's |dirty| attribute is true, then calling
+    Modified at the moment would be a no-op, so it can be skipped.  Performance-
+    sensitive callers should check this attribute directly before calling since
+    it will be true most of the time.
+    """
+
+    raise NotImplementedError
+
+
+class NullMessageListener(object):
+
+  """No-op MessageListener implementation."""
+
+  def Modified(self):
+    pass
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
new file mode 100644
index 0000000..40abfe4
--- /dev/null
+++ b/python/google/protobuf/internal/message_test.py
@@ -0,0 +1,2572 @@
+# -*- coding: utf-8 -*-
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests python protocol buffers against the golden message.
+
+Note that the golden messages exercise every known field type, thus this
+test ends up exercising and verifying nearly all of the parsing and
+serialization code in the whole library.
+
+TODO(kenton):  Merge with wire_format_test?  It doesn't make a whole lot of
+sense to call this a test of the "message" module, which only declares an
+abstract interface.
+"""
+
+__author__ = 'gps@google.com (Gregory P. Smith)'
+
+import collections
+import copy
+import math
+import operator
+import pickle
+import pydoc
+import sys
+import unittest
+import warnings
+
+cmp = lambda x, y: (x > y) - (x < y)
+
+from google.protobuf import map_proto2_unittest_pb2
+from google.protobuf import map_unittest_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf import descriptor
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import encoder
+from google.protobuf.internal import more_extensions_pb2
+from google.protobuf.internal import packed_field_test_pb2
+from google.protobuf.internal import test_util
+from google.protobuf.internal import test_proto3_optional_pb2
+from google.protobuf.internal import testing_refleaks
+from google.protobuf import message
+from google.protobuf.internal import _parameterized
+
+UCS2_MAXUNICODE = 65535
+
+warnings.simplefilter('error', DeprecationWarning)
+
+
+@_parameterized.named_parameters(('_proto2', unittest_pb2),
+                                ('_proto3', unittest_proto3_arena_pb2))
+@testing_refleaks.TestCase
+class MessageTest(unittest.TestCase):
+
+  def testBadUtf8String(self, message_module):
+    if api_implementation.Type() != 'python':
+      self.skipTest('Skipping testBadUtf8String, currently only the python '
+                    'api implementation raises UnicodeDecodeError when a '
+                    'string field contains bad utf-8.')
+    bad_utf8_data = test_util.GoldenFileData('bad_utf8_string')
+    with self.assertRaises(UnicodeDecodeError) as context:
+      message_module.TestAllTypes.FromString(bad_utf8_data)
+    self.assertIn('TestAllTypes.optional_string', str(context.exception))
+
+  def testGoldenMessage(self, message_module):
+    # Proto3 doesn't have the "default_foo" members or foreign enums,
+    # and doesn't preserve unknown fields, so for proto3 we use a golden
+    # message that doesn't have these fields set.
+    if message_module is unittest_pb2:
+      golden_data = test_util.GoldenFileData('golden_message_oneof_implemented')
+    else:
+      golden_data = test_util.GoldenFileData('golden_message_proto3')
+
+    golden_message = message_module.TestAllTypes()
+    golden_message.ParseFromString(golden_data)
+    if message_module is unittest_pb2:
+      test_util.ExpectAllFieldsSet(self, golden_message)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+    golden_copy = copy.deepcopy(golden_message)
+    self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+  def testGoldenPackedMessage(self, message_module):
+    golden_data = test_util.GoldenFileData('golden_packed_fields_message')
+    golden_message = message_module.TestPackedTypes()
+    parsed_bytes = golden_message.ParseFromString(golden_data)
+    all_set = message_module.TestPackedTypes()
+    test_util.SetAllPackedFields(all_set)
+    self.assertEqual(parsed_bytes, len(golden_data))
+    self.assertEqual(all_set, golden_message)
+    self.assertEqual(golden_data, all_set.SerializeToString())
+    golden_copy = copy.deepcopy(golden_message)
+    self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+  def testParseErrors(self, message_module):
+    msg = message_module.TestAllTypes()
+    self.assertRaises(TypeError, msg.FromString, 0)
+    self.assertRaises(Exception, msg.FromString, '0')
+    # TODO(jieluo): Fix cpp extension to raise error instead of warning.
+    # b/27494216
+    end_tag = encoder.TagBytes(1, 4)
+    if (api_implementation.Type() == 'python' or
+        api_implementation.Type() == 'upb'):
+      with self.assertRaises(message.DecodeError) as context:
+        msg.FromString(end_tag)
+      if api_implementation.Type() == 'python':
+        # Only pure-Python has an error message this specific.
+        self.assertEqual('Unexpected end-group tag.', str(context.exception))
+
+    # Field number 0 is illegal.
+    self.assertRaises(message.DecodeError, msg.FromString, b'\3\4')
+
+  def testDeterminismParameters(self, message_module):
+    # This message is always deterministically serialized, even if determinism
+    # is disabled, so we can use it to verify that all the determinism
+    # parameters work correctly.
+    golden_data = (b'\xe2\x02\nOne string'
+                   b'\xe2\x02\nTwo string'
+                   b'\xe2\x02\nRed string'
+                   b'\xe2\x02\x0bBlue string')
+    golden_message = message_module.TestAllTypes()
+    golden_message.repeated_string.extend([
+        'One string',
+        'Two string',
+        'Red string',
+        'Blue string',
+    ])
+    self.assertEqual(golden_data,
+                     golden_message.SerializeToString(deterministic=None))
+    self.assertEqual(golden_data,
+                     golden_message.SerializeToString(deterministic=False))
+    self.assertEqual(golden_data,
+                     golden_message.SerializeToString(deterministic=True))
+
+    class BadArgError(Exception):
+      pass
+
+    class BadArg(object):
+
+      def __nonzero__(self):
+        raise BadArgError()
+
+      def __bool__(self):
+        raise BadArgError()
+
+    with self.assertRaises(BadArgError):
+      golden_message.SerializeToString(deterministic=BadArg())
+
+  def testPickleSupport(self, message_module):
+    golden_data = test_util.GoldenFileData('golden_message')
+    golden_message = message_module.TestAllTypes()
+    golden_message.ParseFromString(golden_data)
+    pickled_message = pickle.dumps(golden_message)
+
+    unpickled_message = pickle.loads(pickled_message)
+    self.assertEqual(unpickled_message, golden_message)
+
+  def testPickleNestedMessage(self, message_module):
+    golden_message = message_module.TestPickleNestedMessage.NestedMessage(bb=1)
+    pickled_message = pickle.dumps(golden_message)
+    unpickled_message = pickle.loads(pickled_message)
+    self.assertEqual(unpickled_message, golden_message)
+
+  def testPickleNestedNestedMessage(self, message_module):
+    cls = message_module.TestPickleNestedMessage.NestedMessage
+    golden_message = cls.NestedNestedMessage(cc=1)
+    pickled_message = pickle.dumps(golden_message)
+    unpickled_message = pickle.loads(pickled_message)
+    self.assertEqual(unpickled_message, golden_message)
+
+  def testPositiveInfinity(self, message_module):
+    if message_module is unittest_pb2:
+      golden_data = (b'\x5D\x00\x00\x80\x7F'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+                     b'\xCD\x02\x00\x00\x80\x7F'
+                     b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
+    else:
+      golden_data = (b'\x5D\x00\x00\x80\x7F'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+                     b'\xCA\x02\x04\x00\x00\x80\x7F'
+                     b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
+
+    golden_message = message_module.TestAllTypes()
+    golden_message.ParseFromString(golden_data)
+    self.assertEqual(golden_message.optional_float, math.inf)
+    self.assertEqual(golden_message.optional_double, math.inf)
+    self.assertEqual(golden_message.repeated_float[0], math.inf)
+    self.assertEqual(golden_message.repeated_double[0], math.inf)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+
+  def testNegativeInfinity(self, message_module):
+    if message_module is unittest_pb2:
+      golden_data = (b'\x5D\x00\x00\x80\xFF'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+                     b'\xCD\x02\x00\x00\x80\xFF'
+                     b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
+    else:
+      golden_data = (b'\x5D\x00\x00\x80\xFF'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+                     b'\xCA\x02\x04\x00\x00\x80\xFF'
+                     b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
+
+    golden_message = message_module.TestAllTypes()
+    golden_message.ParseFromString(golden_data)
+    self.assertEqual(golden_message.optional_float, -math.inf)
+    self.assertEqual(golden_message.optional_double, -math.inf)
+    self.assertEqual(golden_message.repeated_float[0], -math.inf)
+    self.assertEqual(golden_message.repeated_double[0], -math.inf)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+
+  def testNotANumber(self, message_module):
+    golden_data = (b'\x5D\x00\x00\xC0\x7F'
+                   b'\x61\x00\x00\x00\x00\x00\x00\xF8\x7F'
+                   b'\xCD\x02\x00\x00\xC0\x7F'
+                   b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF8\x7F')
+    golden_message = message_module.TestAllTypes()
+    golden_message.ParseFromString(golden_data)
+    self.assertTrue(math.isnan(golden_message.optional_float))
+    self.assertTrue(math.isnan(golden_message.optional_double))
+    self.assertTrue(math.isnan(golden_message.repeated_float[0]))
+    self.assertTrue(math.isnan(golden_message.repeated_double[0]))
+
+    # The protocol buffer may serialize to any one of multiple different
+    # representations of a NaN.  Rather than verify a specific representation,
+    # verify the serialized string can be converted into a correctly
+    # behaving protocol buffer.
+    serialized = golden_message.SerializeToString()
+    message = message_module.TestAllTypes()
+    message.ParseFromString(serialized)
+    self.assertTrue(math.isnan(message.optional_float))
+    self.assertTrue(math.isnan(message.optional_double))
+    self.assertTrue(math.isnan(message.repeated_float[0]))
+    self.assertTrue(math.isnan(message.repeated_double[0]))
+
+  def testPositiveInfinityPacked(self, message_module):
+    golden_data = (b'\xA2\x06\x04\x00\x00\x80\x7F'
+                   b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
+    golden_message = message_module.TestPackedTypes()
+    golden_message.ParseFromString(golden_data)
+    self.assertEqual(golden_message.packed_float[0], math.inf)
+    self.assertEqual(golden_message.packed_double[0], math.inf)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+
+  def testNegativeInfinityPacked(self, message_module):
+    golden_data = (b'\xA2\x06\x04\x00\x00\x80\xFF'
+                   b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
+    golden_message = message_module.TestPackedTypes()
+    golden_message.ParseFromString(golden_data)
+    self.assertEqual(golden_message.packed_float[0], -math.inf)
+    self.assertEqual(golden_message.packed_double[0], -math.inf)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+
+  def testNotANumberPacked(self, message_module):
+    golden_data = (b'\xA2\x06\x04\x00\x00\xC0\x7F'
+                   b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF8\x7F')
+    golden_message = message_module.TestPackedTypes()
+    golden_message.ParseFromString(golden_data)
+    self.assertTrue(math.isnan(golden_message.packed_float[0]))
+    self.assertTrue(math.isnan(golden_message.packed_double[0]))
+
+    serialized = golden_message.SerializeToString()
+    message = message_module.TestPackedTypes()
+    message.ParseFromString(serialized)
+    self.assertTrue(math.isnan(message.packed_float[0]))
+    self.assertTrue(math.isnan(message.packed_double[0]))
+
+  def testExtremeFloatValues(self, message_module):
+    message = message_module.TestAllTypes()
+
+    # Most positive exponent, no significand bits set.
+    kMostPosExponentNoSigBits = math.pow(2, 127)
+    message.optional_float = kMostPosExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == kMostPosExponentNoSigBits)
+
+    # Most positive exponent, one significand bit set.
+    kMostPosExponentOneSigBit = 1.5 * math.pow(2, 127)
+    message.optional_float = kMostPosExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == kMostPosExponentOneSigBit)
+
+    # Repeat last two cases with values of same magnitude, but negative.
+    message.optional_float = -kMostPosExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == -kMostPosExponentNoSigBits)
+
+    message.optional_float = -kMostPosExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == -kMostPosExponentOneSigBit)
+
+    # Most negative exponent, no significand bits set.
+    kMostNegExponentNoSigBits = math.pow(2, -127)
+    message.optional_float = kMostNegExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == kMostNegExponentNoSigBits)
+
+    # Most negative exponent, one significand bit set.
+    kMostNegExponentOneSigBit = 1.5 * math.pow(2, -127)
+    message.optional_float = kMostNegExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == kMostNegExponentOneSigBit)
+
+    # Repeat last two cases with values of the same magnitude, but negative.
+    message.optional_float = -kMostNegExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == -kMostNegExponentNoSigBits)
+
+    message.optional_float = -kMostNegExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_float == -kMostNegExponentOneSigBit)
+
+    # Max 4 bytes float value
+    max_float = float.fromhex('0x1.fffffep+127')
+    message.optional_float = max_float
+    self.assertAlmostEqual(message.optional_float, max_float)
+    serialized_data = message.SerializeToString()
+    message.ParseFromString(serialized_data)
+    self.assertAlmostEqual(message.optional_float, max_float)
+
+    # Test set double to float field.
+    message.optional_float = 3.4028235e+39
+    self.assertEqual(message.optional_float, float('inf'))
+    serialized_data = message.SerializeToString()
+    message.ParseFromString(serialized_data)
+    self.assertEqual(message.optional_float, float('inf'))
+
+    message.optional_float = -3.4028235e+39
+    self.assertEqual(message.optional_float, float('-inf'))
+
+    message.optional_float = 1.4028235e-39
+    self.assertAlmostEqual(message.optional_float, 1.4028235e-39)
+
+  def testExtremeDoubleValues(self, message_module):
+    message = message_module.TestAllTypes()
+
+    # Most positive exponent, no significand bits set.
+    kMostPosExponentNoSigBits = math.pow(2, 1023)
+    message.optional_double = kMostPosExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == kMostPosExponentNoSigBits)
+
+    # Most positive exponent, one significand bit set.
+    kMostPosExponentOneSigBit = 1.5 * math.pow(2, 1023)
+    message.optional_double = kMostPosExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == kMostPosExponentOneSigBit)
+
+    # Repeat last two cases with values of same magnitude, but negative.
+    message.optional_double = -kMostPosExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == -kMostPosExponentNoSigBits)
+
+    message.optional_double = -kMostPosExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == -kMostPosExponentOneSigBit)
+
+    # Most negative exponent, no significand bits set.
+    kMostNegExponentNoSigBits = math.pow(2, -1023)
+    message.optional_double = kMostNegExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == kMostNegExponentNoSigBits)
+
+    # Most negative exponent, one significand bit set.
+    kMostNegExponentOneSigBit = 1.5 * math.pow(2, -1023)
+    message.optional_double = kMostNegExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == kMostNegExponentOneSigBit)
+
+    # Repeat last two cases with values of the same magnitude, but negative.
+    message.optional_double = -kMostNegExponentNoSigBits
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == -kMostNegExponentNoSigBits)
+
+    message.optional_double = -kMostNegExponentOneSigBit
+    message.ParseFromString(message.SerializeToString())
+    self.assertTrue(message.optional_double == -kMostNegExponentOneSigBit)
+
+  def testFloatPrinting(self, message_module):
+    message = message_module.TestAllTypes()
+    message.optional_float = 2.0
+    self.assertEqual(str(message), 'optional_float: 2.0\n')
+
+  def testHighPrecisionFloatPrinting(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.optional_float = 0.12345678912345678
+    old_float = msg.optional_float
+    msg.ParseFromString(msg.SerializeToString())
+    self.assertEqual(old_float, msg.optional_float)
+
+  def testHighPrecisionDoublePrinting(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.optional_double = 0.12345678912345678
+    self.assertEqual(str(msg), 'optional_double: 0.12345678912345678\n')
+
+  def testUnknownFieldPrinting(self, message_module):
+    populated = message_module.TestAllTypes()
+    test_util.SetAllNonLazyFields(populated)
+    empty = message_module.TestEmptyMessage()
+    empty.ParseFromString(populated.SerializeToString())
+    self.assertEqual(str(empty), '')
+
+  def testAppendRepeatedCompositeField(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_nested_message.append(
+        message_module.TestAllTypes.NestedMessage(bb=1))
+    nested = message_module.TestAllTypes.NestedMessage(bb=2)
+    msg.repeated_nested_message.append(nested)
+    try:
+      msg.repeated_nested_message.append(1)
+    except TypeError:
+      pass
+    self.assertEqual(2, len(msg.repeated_nested_message))
+    self.assertEqual([1, 2], [m.bb for m in msg.repeated_nested_message])
+
+  def testInsertRepeatedCompositeField(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_nested_message.insert(
+        -1, message_module.TestAllTypes.NestedMessage(bb=1))
+    sub_msg = msg.repeated_nested_message[0]
+    msg.repeated_nested_message.insert(
+        0, message_module.TestAllTypes.NestedMessage(bb=2))
+    msg.repeated_nested_message.insert(
+        99, message_module.TestAllTypes.NestedMessage(bb=3))
+    msg.repeated_nested_message.insert(
+        -2, message_module.TestAllTypes.NestedMessage(bb=-1))
+    msg.repeated_nested_message.insert(
+        -1000, message_module.TestAllTypes.NestedMessage(bb=-1000))
+    try:
+      msg.repeated_nested_message.insert(1, 999)
+    except TypeError:
+      pass
+    self.assertEqual(5, len(msg.repeated_nested_message))
+    self.assertEqual([-1000, 2, -1, 1, 3],
+                     [m.bb for m in msg.repeated_nested_message])
+    self.assertEqual(
+        str(msg), 'repeated_nested_message {\n'
+        '  bb: -1000\n'
+        '}\n'
+        'repeated_nested_message {\n'
+        '  bb: 2\n'
+        '}\n'
+        'repeated_nested_message {\n'
+        '  bb: -1\n'
+        '}\n'
+        'repeated_nested_message {\n'
+        '  bb: 1\n'
+        '}\n'
+        'repeated_nested_message {\n'
+        '  bb: 3\n'
+        '}\n')
+    self.assertEqual(sub_msg.bb, 1)
+
+  def testMergeFromRepeatedField(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.append(1)
+    msg.repeated_int32.append(3)
+    msg.repeated_nested_message.add(bb=1)
+    msg.repeated_nested_message.add(bb=2)
+    other_msg = message_module.TestAllTypes()
+    other_msg.repeated_nested_message.add(bb=3)
+    other_msg.repeated_nested_message.add(bb=4)
+    other_msg.repeated_int32.append(5)
+    other_msg.repeated_int32.append(7)
+
+    msg.repeated_int32.MergeFrom(other_msg.repeated_int32)
+    self.assertEqual(4, len(msg.repeated_int32))
+
+    msg.repeated_nested_message.MergeFrom(other_msg.repeated_nested_message)
+    self.assertEqual([1, 2, 3, 4], [m.bb for m in msg.repeated_nested_message])
+
+  def testAddWrongRepeatedNestedField(self, message_module):
+    msg = message_module.TestAllTypes()
+    try:
+      msg.repeated_nested_message.add('wrong')
+    except TypeError:
+      pass
+    try:
+      msg.repeated_nested_message.add(value_field='wrong')
+    except ValueError:
+      pass
+    self.assertEqual(len(msg.repeated_nested_message), 0)
+
+  def testRepeatedContains(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertIn(2, msg.repeated_int32)
+    self.assertNotIn(0, msg.repeated_int32)
+
+    msg.repeated_nested_message.add(bb=1)
+    sub_msg1 = msg.repeated_nested_message[0]
+    sub_msg2 = message_module.TestAllTypes.NestedMessage(bb=2)
+    sub_msg3 = message_module.TestAllTypes.NestedMessage(bb=3)
+    msg.repeated_nested_message.append(sub_msg2)
+    msg.repeated_nested_message.insert(0, sub_msg3)
+    self.assertIn(sub_msg1, msg.repeated_nested_message)
+    self.assertIn(sub_msg2, msg.repeated_nested_message)
+    self.assertIn(sub_msg3, msg.repeated_nested_message)
+
+  def testRepeatedScalarIterable(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    add = 0
+    for item in msg.repeated_int32:
+      add += item
+    self.assertEqual(add, 6)
+
+  def testRepeatedNestedFieldIteration(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_nested_message.add(bb=1)
+    msg.repeated_nested_message.add(bb=2)
+    msg.repeated_nested_message.add(bb=3)
+    msg.repeated_nested_message.add(bb=4)
+
+    self.assertEqual([1, 2, 3, 4], [m.bb for m in msg.repeated_nested_message])
+    self.assertEqual([4, 3, 2, 1],
+                     [m.bb for m in reversed(msg.repeated_nested_message)])
+    self.assertEqual([4, 3, 2, 1],
+                     [m.bb for m in msg.repeated_nested_message[::-1]])
+
+  def testSortingRepeatedScalarFieldsDefaultComparator(self, message_module):
+    """Check some different types with the default comparator."""
+    message = message_module.TestAllTypes()
+
+    # TODO(mattp): would testing more scalar types strengthen test?
+    message.repeated_int32.append(1)
+    message.repeated_int32.append(3)
+    message.repeated_int32.append(2)
+    message.repeated_int32.sort()
+    self.assertEqual(message.repeated_int32[0], 1)
+    self.assertEqual(message.repeated_int32[1], 2)
+    self.assertEqual(message.repeated_int32[2], 3)
+    self.assertEqual(str(message.repeated_int32), str([1, 2, 3]))
+
+    message.repeated_float.append(1.1)
+    message.repeated_float.append(1.3)
+    message.repeated_float.append(1.2)
+    message.repeated_float.sort()
+    self.assertAlmostEqual(message.repeated_float[0], 1.1)
+    self.assertAlmostEqual(message.repeated_float[1], 1.2)
+    self.assertAlmostEqual(message.repeated_float[2], 1.3)
+
+    message.repeated_string.append('a')
+    message.repeated_string.append('c')
+    message.repeated_string.append('b')
+    message.repeated_string.sort()
+    self.assertEqual(message.repeated_string[0], 'a')
+    self.assertEqual(message.repeated_string[1], 'b')
+    self.assertEqual(message.repeated_string[2], 'c')
+    self.assertEqual(str(message.repeated_string), str([u'a', u'b', u'c']))
+
+    message.repeated_bytes.append(b'a')
+    message.repeated_bytes.append(b'c')
+    message.repeated_bytes.append(b'b')
+    message.repeated_bytes.sort()
+    self.assertEqual(message.repeated_bytes[0], b'a')
+    self.assertEqual(message.repeated_bytes[1], b'b')
+    self.assertEqual(message.repeated_bytes[2], b'c')
+    self.assertEqual(str(message.repeated_bytes), str([b'a', b'b', b'c']))
+
+  def testSortingRepeatedScalarFieldsCustomComparator(self, message_module):
+    """Check some different types with custom comparator."""
+    message = message_module.TestAllTypes()
+
+    message.repeated_int32.append(-3)
+    message.repeated_int32.append(-2)
+    message.repeated_int32.append(-1)
+    message.repeated_int32.sort(key=abs)
+    self.assertEqual(message.repeated_int32[0], -1)
+    self.assertEqual(message.repeated_int32[1], -2)
+    self.assertEqual(message.repeated_int32[2], -3)
+
+    message.repeated_string.append('aaa')
+    message.repeated_string.append('bb')
+    message.repeated_string.append('c')
+    message.repeated_string.sort(key=len)
+    self.assertEqual(message.repeated_string[0], 'c')
+    self.assertEqual(message.repeated_string[1], 'bb')
+    self.assertEqual(message.repeated_string[2], 'aaa')
+
+  def testSortingRepeatedCompositeFieldsCustomComparator(self, message_module):
+    """Check passing a custom comparator to sort a repeated composite field."""
+    message = message_module.TestAllTypes()
+
+    message.repeated_nested_message.add().bb = 1
+    message.repeated_nested_message.add().bb = 3
+    message.repeated_nested_message.add().bb = 2
+    message.repeated_nested_message.add().bb = 6
+    message.repeated_nested_message.add().bb = 5
+    message.repeated_nested_message.add().bb = 4
+    message.repeated_nested_message.sort(key=operator.attrgetter('bb'))
+    self.assertEqual(message.repeated_nested_message[0].bb, 1)
+    self.assertEqual(message.repeated_nested_message[1].bb, 2)
+    self.assertEqual(message.repeated_nested_message[2].bb, 3)
+    self.assertEqual(message.repeated_nested_message[3].bb, 4)
+    self.assertEqual(message.repeated_nested_message[4].bb, 5)
+    self.assertEqual(message.repeated_nested_message[5].bb, 6)
+    self.assertEqual(
+        str(message.repeated_nested_message),
+        '[bb: 1\n, bb: 2\n, bb: 3\n, bb: 4\n, bb: 5\n, bb: 6\n]')
+
+  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()
+
+    get_bb = operator.attrgetter('bb')
+    message.repeated_nested_message.add().bb = 1
+    message.repeated_nested_message.add().bb = 3
+    message.repeated_nested_message.add().bb = 2
+    message.repeated_nested_message.add().bb = 6
+    message.repeated_nested_message.add().bb = 5
+    message.repeated_nested_message.add().bb = 4
+    message.repeated_nested_message.sort(key=get_bb)
+    self.assertEqual([k.bb for k in message.repeated_nested_message],
+                     [1, 2, 3, 4, 5, 6])
+    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])
+
+  def testRepeatedScalarFieldSortArguments(self, message_module):
+    """Check sorting a scalar field using list.sort() arguments."""
+    message = message_module.TestAllTypes()
+
+    message.repeated_int32.append(-3)
+    message.repeated_int32.append(-2)
+    message.repeated_int32.append(-1)
+    message.repeated_int32.sort(key=abs)
+    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])
+
+    message.repeated_string.append('aaa')
+    message.repeated_string.append('bb')
+    message.repeated_string.append('c')
+    message.repeated_string.sort(key=len)
+    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'])
+
+  def testRepeatedFieldsComparable(self, message_module):
+    m1 = message_module.TestAllTypes()
+    m2 = message_module.TestAllTypes()
+    m1.repeated_int32.append(0)
+    m1.repeated_int32.append(1)
+    m1.repeated_int32.append(2)
+    m2.repeated_int32.append(0)
+    m2.repeated_int32.append(1)
+    m2.repeated_int32.append(2)
+    m1.repeated_nested_message.add().bb = 1
+    m1.repeated_nested_message.add().bb = 2
+    m1.repeated_nested_message.add().bb = 3
+    m2.repeated_nested_message.add().bb = 1
+    m2.repeated_nested_message.add().bb = 2
+    m2.repeated_nested_message.add().bb = 3
+
+  def testRepeatedFieldsAreSequences(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIsInstance(m.repeated_int32, collections.abc.MutableSequence)
+    self.assertIsInstance(m.repeated_nested_message,
+                          collections.abc.MutableSequence)
+
+  def testRepeatedFieldsNotHashable(self, message_module):
+    m = message_module.TestAllTypes()
+    with self.assertRaises(TypeError):
+      hash(m.repeated_int32)
+    with self.assertRaises(TypeError):
+      hash(m.repeated_nested_message)
+
+  def testRepeatedFieldInsideNestedMessage(self, message_module):
+    m = message_module.NestedTestAllTypes()
+    m.payload.repeated_int32.extend([])
+    self.assertTrue(m.HasField('payload'))
+
+  def testMergeFrom(self, message_module):
+    m1 = message_module.TestAllTypes()
+    m2 = message_module.TestAllTypes()
+    # Cpp extension will lazily create a sub message which is immutable.
+    nested = m1.optional_nested_message
+    self.assertEqual(0, nested.bb)
+    m2.optional_nested_message.bb = 1
+    # Make sure cmessage pointing to a mutable message after merge instead of
+    # the lazily created message.
+    m1.MergeFrom(m2)
+    self.assertEqual(1, nested.bb)
+
+    # Test more nested sub message.
+    msg1 = message_module.NestedTestAllTypes()
+    msg2 = message_module.NestedTestAllTypes()
+    nested = msg1.child.payload.optional_nested_message
+    self.assertEqual(0, nested.bb)
+    msg2.child.payload.optional_nested_message.bb = 1
+    msg1.MergeFrom(msg2)
+    self.assertEqual(1, nested.bb)
+
+    # Test repeated field.
+    self.assertEqual(msg1.payload.repeated_nested_message,
+                     msg1.payload.repeated_nested_message)
+    nested = msg2.payload.repeated_nested_message.add()
+    nested.bb = 1
+    msg1.MergeFrom(msg2)
+    self.assertEqual(1, len(msg1.payload.repeated_nested_message))
+    self.assertEqual(1, nested.bb)
+
+  def testMergeFromString(self, message_module):
+    m1 = message_module.TestAllTypes()
+    m2 = message_module.TestAllTypes()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(0, m1.optional_nested_message.bb)
+    m2.optional_nested_message.bb = 1
+    # Make sure cmessage pointing to a mutable message after merge instead of
+    # the lazily created message.
+    m1.MergeFromString(m2.SerializeToString())
+    self.assertEqual(1, m1.optional_nested_message.bb)
+
+  def testMergeFromStringUsingMemoryView(self, message_module):
+    m2 = message_module.TestAllTypes()
+    m2.optional_string = 'scalar string'
+    m2.repeated_string.append('repeated string')
+    m2.optional_bytes = b'scalar bytes'
+    m2.repeated_bytes.append(b'repeated bytes')
+
+    serialized = m2.SerializeToString()
+    memview = memoryview(serialized)
+    m1 = message_module.TestAllTypes.FromString(memview)
+
+    self.assertEqual(m1.optional_bytes, b'scalar bytes')
+    self.assertEqual(m1.repeated_bytes, [b'repeated bytes'])
+    self.assertEqual(m1.optional_string, 'scalar string')
+    self.assertEqual(m1.repeated_string, ['repeated string'])
+    # Make sure that the memoryview was correctly converted to bytes, and
+    # that a sub-sliced memoryview is not being used.
+    self.assertIsInstance(m1.optional_bytes, bytes)
+    self.assertIsInstance(m1.repeated_bytes[0], bytes)
+    self.assertIsInstance(m1.optional_string, str)
+    self.assertIsInstance(m1.repeated_string[0], str)
+
+  def testMergeFromEmpty(self, message_module):
+    m1 = message_module.TestAllTypes()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(0, m1.optional_nested_message.bb)
+    self.assertFalse(m1.HasField('optional_nested_message'))
+    # Make sure the sub message is still immutable after merge from empty.
+    m1.MergeFromString(b'')  # field state should not change
+    self.assertFalse(m1.HasField('optional_nested_message'))
+
+  def ensureNestedMessageExists(self, msg, attribute):
+    """Make sure that a nested message object exists.
+
+    As soon as a nested message attribute is accessed, it will be present in the
+    _fields dict, without being marked as actually being set.
+    """
+    getattr(msg, attribute)
+    self.assertFalse(msg.HasField(attribute))
+
+  def testOneofGetCaseNonexistingField(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertRaises(ValueError, m.WhichOneof, 'no_such_oneof_field')
+    self.assertRaises(Exception, m.WhichOneof, 0)
+
+  def testOneofDefaultValues(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+
+    # Oneof is set even when setting it to a default value.
+    m.oneof_uint32 = 0
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_field'))
+    self.assertTrue(m.HasField('oneof_uint32'))
+    self.assertFalse(m.HasField('oneof_string'))
+
+    m.oneof_string = ''
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_string'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+
+  def testOneofSemantics(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+
+    m.oneof_uint32 = 11
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_uint32'))
+
+    m.oneof_string = u'foo'
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+    self.assertTrue(m.HasField('oneof_string'))
+
+    # Read nested message accessor without accessing submessage.
+    m.oneof_nested_message
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_string'))
+    self.assertFalse(m.HasField('oneof_nested_message'))
+
+    # Read accessor of nested message without accessing submessage.
+    m.oneof_nested_message.bb
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_string'))
+    self.assertFalse(m.HasField('oneof_nested_message'))
+
+    m.oneof_nested_message.bb = 11
+    self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_string'))
+    self.assertTrue(m.HasField('oneof_nested_message'))
+
+    m.oneof_bytes = b'bb'
+    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_nested_message'))
+    self.assertTrue(m.HasField('oneof_bytes'))
+
+  def testOneofCompositeFieldReadAccess(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+
+    self.ensureNestedMessageExists(m, 'oneof_nested_message')
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    self.assertEqual(11, m.oneof_uint32)
+
+  def testOneofWhichOneof(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+
+    m.oneof_uint32 = 11
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    if message_module is unittest_pb2:
+      self.assertTrue(m.HasField('oneof_field'))
+
+    m.oneof_bytes = b'bb'
+    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+
+    m.ClearField('oneof_bytes')
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+
+  def testOneofClearField(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m.ClearField('oneof_field')
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+
+  def testOneofClearSetField(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m.ClearField('oneof_uint32')
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+
+  def testOneofClearUnsetField(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    self.ensureNestedMessageExists(m, 'oneof_nested_message')
+    m.ClearField('oneof_nested_message')
+    self.assertEqual(11, m.oneof_uint32)
+    if message_module is unittest_pb2:
+      self.assertTrue(m.HasField('oneof_field'))
+    self.assertTrue(m.HasField('oneof_uint32'))
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+
+  def testOneofDeserialize(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    m2.ParseFromString(m.SerializeToString())
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testOneofCopyFrom(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    m2.CopyFrom(m)
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testOneofNestedMergeFrom(self, message_module):
+    m = message_module.NestedTestAllTypes()
+    m.payload.oneof_uint32 = 11
+    m2 = message_module.NestedTestAllTypes()
+    m2.payload.oneof_bytes = b'bb'
+    m2.child.payload.oneof_bytes = b'bb'
+    m2.MergeFrom(m)
+    self.assertEqual('oneof_uint32', m2.payload.WhichOneof('oneof_field'))
+    self.assertEqual('oneof_bytes', m2.child.payload.WhichOneof('oneof_field'))
+
+  def testOneofMessageMergeFrom(self, message_module):
+    m = message_module.NestedTestAllTypes()
+    m.payload.oneof_nested_message.bb = 11
+    m.child.payload.oneof_nested_message.bb = 12
+    m2 = message_module.NestedTestAllTypes()
+    m2.payload.oneof_uint32 = 13
+    m2.MergeFrom(m)
+    self.assertEqual('oneof_nested_message',
+                     m2.payload.WhichOneof('oneof_field'))
+    self.assertEqual('oneof_nested_message',
+                     m2.child.payload.WhichOneof('oneof_field'))
+
+  def testOneofNestedMessageInit(self, message_module):
+    m = message_module.TestAllTypes(
+        oneof_nested_message=message_module.TestAllTypes.NestedMessage())
+    self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
+
+  def testOneofClear(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m.Clear()
+    self.assertIsNone(m.WhichOneof('oneof_field'))
+    m.oneof_bytes = b'bb'
+    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+
+  def testAssignByteStringToUnicodeField(self, message_module):
+    """Assigning a byte string to a string field should result
+
+    in the value being converted to a Unicode string.
+    """
+    m = message_module.TestAllTypes()
+    m.optional_string = str('')
+    self.assertIsInstance(m.optional_string, str)
+
+  def testLongValuedSlice(self, message_module):
+    """It should be possible to use int-valued indices in slices.
+
+    This didn't used to work in the v2 C++ implementation.
+    """
+    m = message_module.TestAllTypes()
+
+    # Repeated scalar
+    m.repeated_int32.append(1)
+    sl = m.repeated_int32[int(0):int(len(m.repeated_int32))]
+    self.assertEqual(len(m.repeated_int32), len(sl))
+
+    # Repeated composite
+    m.repeated_nested_message.add().bb = 3
+    sl = m.repeated_nested_message[int(0):int(len(m.repeated_nested_message))]
+    self.assertEqual(len(m.repeated_nested_message), len(sl))
+
+  def testExtendShouldNotSwallowExceptions(self, message_module):
+    """This didn't use to work in the v2 C++ implementation."""
+    m = message_module.TestAllTypes()
+    with self.assertRaises(NameError) as _:
+      m.repeated_int32.extend(a for i in range(10))  # pylint: disable=undefined-variable
+    with self.assertRaises(NameError) as _:
+      m.repeated_nested_enum.extend(a for i in range(10))  # pylint: disable=undefined-variable
+
+  FALSY_VALUES = [None, False, 0, 0.0, b'', u'', bytearray(), [], {}, set()]
+
+  def testExtendInt32WithNothing(self, message_module):
+    """Test no-ops extending repeated int32 fields."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_int32)
+
+    # TODO(ptucker): Deprecate this behavior. b/18413862
+    for falsy_value in MessageTest.FALSY_VALUES:
+      m.repeated_int32.extend(falsy_value)
+      self.assertSequenceEqual([], m.repeated_int32)
+
+    m.repeated_int32.extend([])
+    self.assertSequenceEqual([], m.repeated_int32)
+
+  def testExtendFloatWithNothing(self, message_module):
+    """Test no-ops extending repeated float fields."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_float)
+
+    # TODO(ptucker): Deprecate this behavior. b/18413862
+    for falsy_value in MessageTest.FALSY_VALUES:
+      m.repeated_float.extend(falsy_value)
+      self.assertSequenceEqual([], m.repeated_float)
+
+    m.repeated_float.extend([])
+    self.assertSequenceEqual([], m.repeated_float)
+
+  def testExtendStringWithNothing(self, message_module):
+    """Test no-ops extending repeated string fields."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+
+    # TODO(ptucker): Deprecate this behavior. b/18413862
+    for falsy_value in MessageTest.FALSY_VALUES:
+      m.repeated_string.extend(falsy_value)
+      self.assertSequenceEqual([], m.repeated_string)
+
+    m.repeated_string.extend([])
+    self.assertSequenceEqual([], m.repeated_string)
+
+  def testExtendInt32WithPythonList(self, message_module):
+    """Test extending repeated int32 fields with python lists."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_int32)
+    m.repeated_int32.extend([0])
+    self.assertSequenceEqual([0], m.repeated_int32)
+    m.repeated_int32.extend([1, 2])
+    self.assertSequenceEqual([0, 1, 2], m.repeated_int32)
+    m.repeated_int32.extend([3, 4])
+    self.assertSequenceEqual([0, 1, 2, 3, 4], m.repeated_int32)
+
+  def testExtendFloatWithPythonList(self, message_module):
+    """Test extending repeated float fields with python lists."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_float)
+    m.repeated_float.extend([0.0])
+    self.assertSequenceEqual([0.0], m.repeated_float)
+    m.repeated_float.extend([1.0, 2.0])
+    self.assertSequenceEqual([0.0, 1.0, 2.0], m.repeated_float)
+    m.repeated_float.extend([3.0, 4.0])
+    self.assertSequenceEqual([0.0, 1.0, 2.0, 3.0, 4.0], m.repeated_float)
+
+  def testExtendStringWithPythonList(self, message_module):
+    """Test extending repeated string fields with python lists."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend([''])
+    self.assertSequenceEqual([''], m.repeated_string)
+    m.repeated_string.extend(['11', '22'])
+    self.assertSequenceEqual(['', '11', '22'], m.repeated_string)
+    m.repeated_string.extend(['33', '44'])
+    self.assertSequenceEqual(['', '11', '22', '33', '44'], m.repeated_string)
+
+  def testExtendStringWithString(self, message_module):
+    """Test extending repeated string fields with characters from a string."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend('abc')
+    self.assertSequenceEqual(['a', 'b', 'c'], m.repeated_string)
+
+  class TestIterable(object):
+    """This iterable object mimics the behavior of numpy.array.
+
+    __nonzero__ fails for length > 1, and returns bool(item[0]) for length == 1.
+
+    """
+
+    def __init__(self, values=None):
+      self._list = values or []
+
+    def __nonzero__(self):
+      size = len(self._list)
+      if size == 0:
+        return False
+      if size == 1:
+        return bool(self._list[0])
+      raise ValueError('Truth value is ambiguous.')
+
+    def __len__(self):
+      return len(self._list)
+
+    def __iter__(self):
+      return self._list.__iter__()
+
+  def testExtendInt32WithIterable(self, message_module):
+    """Test extending repeated int32 fields with iterable."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([]))
+    self.assertSequenceEqual([], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([0]))
+    self.assertSequenceEqual([0], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([1, 2]))
+    self.assertSequenceEqual([0, 1, 2], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([3, 4]))
+    self.assertSequenceEqual([0, 1, 2, 3, 4], m.repeated_int32)
+
+  def testExtendFloatWithIterable(self, message_module):
+    """Test extending repeated float fields with iterable."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([]))
+    self.assertSequenceEqual([], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([0.0]))
+    self.assertSequenceEqual([0.0], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([1.0, 2.0]))
+    self.assertSequenceEqual([0.0, 1.0, 2.0], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([3.0, 4.0]))
+    self.assertSequenceEqual([0.0, 1.0, 2.0, 3.0, 4.0], m.repeated_float)
+
+  def testExtendStringWithIterable(self, message_module):
+    """Test extending repeated string fields with iterable."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable([]))
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable(['']))
+    self.assertSequenceEqual([''], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable(['1', '2']))
+    self.assertSequenceEqual(['', '1', '2'], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable(['3', '4']))
+    self.assertSequenceEqual(['', '1', '2', '3', '4'], m.repeated_string)
+
+  class TestIndex(object):
+    """This index object mimics the behavior of numpy.int64 and other types."""
+
+    def __init__(self, value=None):
+      self.value = value
+
+    def __index__(self):
+      return self.value
+
+  def testRepeatedIndexingWithIntIndex(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertEqual(1, msg.repeated_int32[MessageTest.TestIndex(0)])
+
+  def testRepeatedIndexingWithNegative1IntIndex(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertEqual(3, msg.repeated_int32[MessageTest.TestIndex(-1)])
+
+  def testRepeatedIndexingWithNegative1Int(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertEqual(3, msg.repeated_int32[-1])
+
+  def testPickleRepeatedScalarContainer(self, message_module):
+    # Pickle repeated scalar container is not supported.
+    m = message_module.TestAllTypes()
+    with self.assertRaises(pickle.PickleError) as _:
+      pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
+
+  def testSortEmptyRepeatedCompositeContainer(self, message_module):
+    """Exercise a scenario that has led to segfaults in the past."""
+    m = message_module.TestAllTypes()
+    m.repeated_nested_message.sort()
+
+  def testHasFieldOnRepeatedField(self, message_module):
+    """Using HasField on a repeated field should raise an exception."""
+    m = message_module.TestAllTypes()
+    with self.assertRaises(ValueError) as _:
+      m.HasField('repeated_int32')
+
+  def testRepeatedScalarFieldPop(self, message_module):
+    m = message_module.TestAllTypes()
+    with self.assertRaises(IndexError) as _:
+      m.repeated_int32.pop()
+    m.repeated_int32.extend(range(5))
+    self.assertEqual(4, m.repeated_int32.pop())
+    self.assertEqual(0, m.repeated_int32.pop(0))
+    self.assertEqual(2, m.repeated_int32.pop(1))
+    self.assertEqual([1, 3], m.repeated_int32)
+
+  def testRepeatedCompositeFieldPop(self, message_module):
+    m = message_module.TestAllTypes()
+    with self.assertRaises(IndexError) as _:
+      m.repeated_nested_message.pop()
+    with self.assertRaises(TypeError) as _:
+      m.repeated_nested_message.pop('0')
+    for i in range(5):
+      n = m.repeated_nested_message.add()
+      n.bb = i
+    self.assertEqual(4, m.repeated_nested_message.pop().bb)
+    self.assertEqual(0, m.repeated_nested_message.pop(0).bb)
+    self.assertEqual(2, m.repeated_nested_message.pop(1).bb)
+    self.assertEqual([1, 3], [n.bb for n in m.repeated_nested_message])
+
+  def testRepeatedCompareWithSelf(self, message_module):
+    m = message_module.TestAllTypes()
+    for i in range(5):
+      m.repeated_int32.insert(i, i)
+      n = m.repeated_nested_message.add()
+      n.bb = i
+    self.assertSequenceEqual(m.repeated_int32, m.repeated_int32)
+    self.assertEqual(m.repeated_nested_message, m.repeated_nested_message)
+
+  def testReleasedNestedMessages(self, message_module):
+    """A case that lead to a segfault when a message detached from its parent
+
+    container has itself a child container.
+    """
+    m = message_module.NestedTestAllTypes()
+    m = m.repeated_child.add()
+    m = m.child
+    m = m.repeated_child.add()
+    self.assertEqual(m.payload.optional_int32, 0)
+
+  def testSetRepeatedComposite(self, message_module):
+    m = message_module.TestAllTypes()
+    with self.assertRaises(AttributeError):
+      m.repeated_int32 = []
+    m.repeated_int32.append(1)
+    with self.assertRaises(AttributeError):
+      m.repeated_int32 = []
+
+  def testReturningType(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertEqual(float, type(m.optional_float))
+    self.assertEqual(float, type(m.optional_double))
+    self.assertEqual(bool, type(m.optional_bool))
+    m.optional_float = 1
+    m.optional_double = 1
+    m.optional_bool = 1
+    m.repeated_float.append(1)
+    m.repeated_double.append(1)
+    m.repeated_bool.append(1)
+    m.ParseFromString(m.SerializeToString())
+    self.assertEqual(float, type(m.optional_float))
+    self.assertEqual(float, type(m.optional_double))
+    self.assertEqual('1.0', str(m.optional_double))
+    self.assertEqual(bool, type(m.optional_bool))
+    self.assertEqual(float, type(m.repeated_float[0]))
+    self.assertEqual(float, type(m.repeated_double[0]))
+    self.assertEqual(bool, type(m.repeated_bool[0]))
+    self.assertEqual(True, m.repeated_bool[0])
+
+
+# Class to test proto2-only features (required, extensions, etc.)
+@testing_refleaks.TestCase
+class Proto2Test(unittest.TestCase):
+
+  def testFieldPresence(self):
+    message = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(message.HasField('optional_int32'))
+    self.assertFalse(message.HasField('optional_bool'))
+    self.assertFalse(message.HasField('optional_nested_message'))
+
+    with self.assertRaises(ValueError):
+      message.HasField('field_doesnt_exist')
+
+    with self.assertRaises(ValueError):
+      message.HasField('repeated_int32')
+    with self.assertRaises(ValueError):
+      message.HasField('repeated_nested_message')
+
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+    # Fields are set even when setting the values to default values.
+    message.optional_int32 = 0
+    message.optional_bool = False
+    message.optional_nested_message.bb = 0
+    self.assertTrue(message.HasField('optional_int32'))
+    self.assertTrue(message.HasField('optional_bool'))
+    self.assertTrue(message.HasField('optional_nested_message'))
+
+    # Set the fields to non-default values.
+    message.optional_int32 = 5
+    message.optional_bool = True
+    message.optional_nested_message.bb = 15
+
+    self.assertTrue(message.HasField(u'optional_int32'))
+    self.assertTrue(message.HasField('optional_bool'))
+    self.assertTrue(message.HasField('optional_nested_message'))
+
+    # Clearing the fields unsets them and resets their value to default.
+    message.ClearField('optional_int32')
+    message.ClearField(u'optional_bool')
+    message.ClearField('optional_nested_message')
+
+    self.assertFalse(message.HasField('optional_int32'))
+    self.assertFalse(message.HasField('optional_bool'))
+    self.assertFalse(message.HasField('optional_nested_message'))
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+  def testAssignInvalidEnum(self):
+    """Assigning an invalid enum number is not allowed in proto2."""
+    m = unittest_pb2.TestAllTypes()
+
+    # Proto2 can not assign unknown enum.
+    with self.assertRaises(ValueError) as _:
+      m.optional_nested_enum = 1234567
+    self.assertRaises(ValueError, m.repeated_nested_enum.append, 1234567)
+    # Assignment is a different code path than append for the C++ impl.
+    m.repeated_nested_enum.append(2)
+    m.repeated_nested_enum[0] = 2
+    with self.assertRaises(ValueError):
+      m.repeated_nested_enum[0] = 123456
+
+    # Unknown enum value can be parsed but is ignored.
+    m2 = unittest_proto3_arena_pb2.TestAllTypes()
+    m2.optional_nested_enum = 1234567
+    m2.repeated_nested_enum.append(7654321)
+    serialized = m2.SerializeToString()
+
+    m3 = unittest_pb2.TestAllTypes()
+    m3.ParseFromString(serialized)
+    self.assertFalse(m3.HasField('optional_nested_enum'))
+    # 1 is the default value for optional_nested_enum.
+    self.assertEqual(1, m3.optional_nested_enum)
+    self.assertEqual(0, len(m3.repeated_nested_enum))
+    m2.Clear()
+    m2.ParseFromString(m3.SerializeToString())
+    self.assertEqual(1234567, m2.optional_nested_enum)
+    self.assertEqual(7654321, m2.repeated_nested_enum[0])
+
+  def testUnknownEnumMap(self):
+    m = map_proto2_unittest_pb2.TestEnumMap()
+    m.known_map_field[123] = 0
+    with self.assertRaises(ValueError):
+      m.unknown_map_field[1] = 123
+
+  def testExtensionsErrors(self):
+    msg = unittest_pb2.TestAllTypes()
+    self.assertRaises(AttributeError, getattr, msg, 'Extensions')
+
+  def testMergeFromExtensions(self):
+    msg1 = more_extensions_pb2.TopLevelMessage()
+    msg2 = more_extensions_pb2.TopLevelMessage()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(
+        0,
+        msg1.submessage.Extensions[more_extensions_pb2.optional_int_extension])
+    self.assertFalse(msg1.HasField('submessage'))
+    msg2.submessage.Extensions[more_extensions_pb2.optional_int_extension] = 123
+    # Make sure cmessage and extensions pointing to a mutable message
+    # after merge instead of the lazily created message.
+    msg1.MergeFrom(msg2)
+    self.assertEqual(
+        123,
+        msg1.submessage.Extensions[more_extensions_pb2.optional_int_extension])
+
+  def testGoldenExtensions(self):
+    golden_data = test_util.GoldenFileData('golden_message')
+    golden_message = unittest_pb2.TestAllExtensions()
+    golden_message.ParseFromString(golden_data)
+    all_set = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(all_set)
+    self.assertEqual(all_set, golden_message)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+    golden_copy = copy.deepcopy(golden_message)
+    self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+  def testGoldenPackedExtensions(self):
+    golden_data = test_util.GoldenFileData('golden_packed_fields_message')
+    golden_message = unittest_pb2.TestPackedExtensions()
+    golden_message.ParseFromString(golden_data)
+    all_set = unittest_pb2.TestPackedExtensions()
+    test_util.SetAllPackedExtensions(all_set)
+    self.assertEqual(all_set, golden_message)
+    self.assertEqual(golden_data, all_set.SerializeToString())
+    golden_copy = copy.deepcopy(golden_message)
+    self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+  def testPickleIncompleteProto(self):
+    golden_message = unittest_pb2.TestRequired(a=1)
+    pickled_message = pickle.dumps(golden_message)
+
+    unpickled_message = pickle.loads(pickled_message)
+    self.assertEqual(unpickled_message, golden_message)
+    self.assertEqual(unpickled_message.a, 1)
+    # This is still an incomplete proto - so serializing should fail
+    self.assertRaises(message.EncodeError, unpickled_message.SerializeToString)
+
+  # TODO(haberman): this isn't really a proto2-specific test except that this
+  # message has a required field in it.  Should probably be factored out so
+  # that we can test the other parts with proto3.
+  def testParsingMerge(self):
+    """Check the merge behavior when a required or optional field appears
+
+    multiple times in the input.
+    """
+    messages = [
+        unittest_pb2.TestAllTypes(),
+        unittest_pb2.TestAllTypes(),
+        unittest_pb2.TestAllTypes()
+    ]
+    messages[0].optional_int32 = 1
+    messages[1].optional_int64 = 2
+    messages[2].optional_int32 = 3
+    messages[2].optional_string = 'hello'
+
+    merged_message = unittest_pb2.TestAllTypes()
+    merged_message.optional_int32 = 3
+    merged_message.optional_int64 = 2
+    merged_message.optional_string = 'hello'
+
+    generator = unittest_pb2.TestParsingMerge.RepeatedFieldsGenerator()
+    generator.field1.extend(messages)
+    generator.field2.extend(messages)
+    generator.field3.extend(messages)
+    generator.ext1.extend(messages)
+    generator.ext2.extend(messages)
+    generator.group1.add().field1.MergeFrom(messages[0])
+    generator.group1.add().field1.MergeFrom(messages[1])
+    generator.group1.add().field1.MergeFrom(messages[2])
+    generator.group2.add().field1.MergeFrom(messages[0])
+    generator.group2.add().field1.MergeFrom(messages[1])
+    generator.group2.add().field1.MergeFrom(messages[2])
+
+    data = generator.SerializeToString()
+    parsing_merge = unittest_pb2.TestParsingMerge()
+    parsing_merge.ParseFromString(data)
+
+    # Required and optional fields should be merged.
+    self.assertEqual(parsing_merge.required_all_types, merged_message)
+    self.assertEqual(parsing_merge.optional_all_types, merged_message)
+    self.assertEqual(parsing_merge.optionalgroup.optional_group_all_types,
+                     merged_message)
+    self.assertEqual(
+        parsing_merge.Extensions[unittest_pb2.TestParsingMerge.optional_ext],
+        merged_message)
+
+    # Repeated fields should not be merged.
+    self.assertEqual(len(parsing_merge.repeated_all_types), 3)
+    self.assertEqual(len(parsing_merge.repeatedgroup), 3)
+    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_foreign_message={},
+        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.assertTrue(message.HasField('optional_foreign_message'))
+    self.assertEqual(message.optional_foreign_message,
+                     unittest_pb2.ForeignMessage())
+    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')
+
+  def testPythonicInitWithDict(self):
+    # Both string/unicode field name keys should work.
+    kwargs = {
+        'optional_int32': 100,
+        u'optional_fixed32': 200,
+    }
+    msg = unittest_pb2.TestAllTypes(**kwargs)
+    self.assertEqual(100, msg.optional_int32)
+    self.assertEqual(200, msg.optional_fixed32)
+
+
+  def test_documentation(self):
+    # Also used by the interactive help() function.
+    doc = pydoc.html.document(unittest_pb2.TestAllTypes, 'message')
+    self.assertIn('class TestAllTypes', doc)
+    self.assertIn('SerializePartialToString', doc)
+    self.assertIn('repeated_float', doc)
+    base = unittest_pb2.TestAllTypes.__bases__[0]
+    self.assertRaises(AttributeError, getattr, base, '_extensions_by_name')
+
+
+# Class to test proto3-only features/behavior (updated field presence & enums)
+@testing_refleaks.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')
+    with self.assertRaises(ValueError):
+      message.HasField('optional_float')
+    with self.assertRaises(ValueError):
+      message.HasField('optional_string')
+    with self.assertRaises(ValueError):
+      message.HasField('optional_bool')
+
+    # But we can still test presence of submessage fields.
+    self.assertFalse(message.HasField('optional_nested_message'))
+
+    # As with proto2, we can't test presence of fields that don't exist, or
+    # repeated fields.
+    with self.assertRaises(ValueError):
+      message.HasField('field_doesnt_exist')
+
+    with self.assertRaises(ValueError):
+      message.HasField('repeated_int32')
+    with self.assertRaises(ValueError):
+      message.HasField('repeated_nested_message')
+
+    # Fields should default to their type-specific default.
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(0, message.optional_float)
+    self.assertEqual('', message.optional_string)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+    # Setting a submessage should still return proper presence information.
+    message.optional_nested_message.bb = 0
+    self.assertTrue(message.HasField('optional_nested_message'))
+
+    # Set the fields to non-default values.
+    message.optional_int32 = 5
+    message.optional_float = 1.1
+    message.optional_string = 'abc'
+    message.optional_bool = True
+    message.optional_nested_message.bb = 15
+
+    # Clearing the fields unsets them and resets their value to default.
+    message.ClearField('optional_int32')
+    message.ClearField('optional_float')
+    message.ClearField('optional_string')
+    message.ClearField('optional_bool')
+    message.ClearField('optional_nested_message')
+
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(0, message.optional_float)
+    self.assertEqual('', message.optional_string)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+  def testProto3ParserDropDefaultScalar(self):
+    message_proto2 = unittest_pb2.TestAllTypes()
+    message_proto2.optional_int32 = 0
+    message_proto2.optional_string = ''
+    message_proto2.optional_bytes = b''
+    self.assertEqual(len(message_proto2.ListFields()), 3)
+
+    message_proto3 = unittest_proto3_arena_pb2.TestAllTypes()
+    message_proto3.ParseFromString(message_proto2.SerializeToString())
+    self.assertEqual(len(message_proto3.ListFields()), 0)
+
+  def testProto3Optional(self):
+    msg = test_proto3_optional_pb2.TestProto3Optional()
+    self.assertFalse(msg.HasField('optional_int32'))
+    self.assertFalse(msg.HasField('optional_float'))
+    self.assertFalse(msg.HasField('optional_string'))
+    self.assertFalse(msg.HasField('optional_nested_message'))
+    self.assertFalse(msg.optional_nested_message.HasField('bb'))
+
+    # Set fields.
+    msg.optional_int32 = 1
+    msg.optional_float = 1.0
+    msg.optional_string = '123'
+    msg.optional_nested_message.bb = 1
+    self.assertTrue(msg.HasField('optional_int32'))
+    self.assertTrue(msg.HasField('optional_float'))
+    self.assertTrue(msg.HasField('optional_string'))
+    self.assertTrue(msg.HasField('optional_nested_message'))
+    self.assertTrue(msg.optional_nested_message.HasField('bb'))
+    # Set to default value does not clear the fields
+    msg.optional_int32 = 0
+    msg.optional_float = 0.0
+    msg.optional_string = ''
+    msg.optional_nested_message.bb = 0
+    self.assertTrue(msg.HasField('optional_int32'))
+    self.assertTrue(msg.HasField('optional_float'))
+    self.assertTrue(msg.HasField('optional_string'))
+    self.assertTrue(msg.HasField('optional_nested_message'))
+    self.assertTrue(msg.optional_nested_message.HasField('bb'))
+
+    # Test serialize
+    msg2 = test_proto3_optional_pb2.TestProto3Optional()
+    msg2.ParseFromString(msg.SerializeToString())
+    self.assertTrue(msg2.HasField('optional_int32'))
+    self.assertTrue(msg2.HasField('optional_float'))
+    self.assertTrue(msg2.HasField('optional_string'))
+    self.assertTrue(msg2.HasField('optional_nested_message'))
+    self.assertTrue(msg2.optional_nested_message.HasField('bb'))
+
+    self.assertEqual(msg.WhichOneof('_optional_int32'), 'optional_int32')
+
+    # Clear these fields.
+    msg.ClearField('optional_int32')
+    msg.ClearField('optional_float')
+    msg.ClearField('optional_string')
+    msg.ClearField('optional_nested_message')
+    self.assertFalse(msg.HasField('optional_int32'))
+    self.assertFalse(msg.HasField('optional_float'))
+    self.assertFalse(msg.HasField('optional_string'))
+    self.assertFalse(msg.HasField('optional_nested_message'))
+    self.assertFalse(msg.optional_nested_message.HasField('bb'))
+
+    self.assertEqual(msg.WhichOneof('_optional_int32'), None)
+
+    # Test has presence:
+    for field in test_proto3_optional_pb2.TestProto3Optional.DESCRIPTOR.fields:
+      self.assertTrue(field.has_presence)
+    for field in unittest_pb2.TestAllTypes.DESCRIPTOR.fields:
+      if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        self.assertFalse(field.has_presence)
+      else:
+        self.assertTrue(field.has_presence)
+    proto3_descriptor = unittest_proto3_arena_pb2.TestAllTypes.DESCRIPTOR
+    repeated_field = proto3_descriptor.fields_by_name['repeated_int32']
+    self.assertFalse(repeated_field.has_presence)
+    singular_field = proto3_descriptor.fields_by_name['optional_int32']
+    self.assertFalse(singular_field.has_presence)
+    optional_field = proto3_descriptor.fields_by_name['proto3_optional_int32']
+    self.assertTrue(optional_field.has_presence)
+    message_field = proto3_descriptor.fields_by_name['optional_nested_message']
+    self.assertTrue(message_field.has_presence)
+    oneof_field = proto3_descriptor.fields_by_name['oneof_uint32']
+    self.assertTrue(oneof_field.has_presence)
+
+  def testAssignUnknownEnum(self):
+    """Assigning an unknown enum value is allowed and preserves the value."""
+    m = unittest_proto3_arena_pb2.TestAllTypes()
+
+    # Proto3 can assign unknown enums.
+    m.optional_nested_enum = 1234567
+    self.assertEqual(1234567, m.optional_nested_enum)
+    m.repeated_nested_enum.append(22334455)
+    self.assertEqual(22334455, m.repeated_nested_enum[0])
+    # Assignment is a different code path than append for the C++ impl.
+    m.repeated_nested_enum[0] = 7654321
+    self.assertEqual(7654321, m.repeated_nested_enum[0])
+    serialized = m.SerializeToString()
+
+    m2 = unittest_proto3_arena_pb2.TestAllTypes()
+    m2.ParseFromString(serialized)
+    self.assertEqual(1234567, m2.optional_nested_enum)
+    self.assertEqual(7654321, m2.repeated_nested_enum[0])
+
+  # Map isn't really a proto3-only feature. But there is no proto2 equivalent
+  # of google/protobuf/map_unittest.proto right now, so it's not easy to
+  # test both with the same test like we do for the other proto2/proto3 tests.
+  # (google/protobuf/map_proto2_unittest.proto is very different in the set
+  # of messages and fields it contains).
+  def testScalarMapDefaults(self):
+    msg = map_unittest_pb2.TestMap()
+
+    # Scalars start out unset.
+    self.assertFalse(-123 in msg.map_int32_int32)
+    self.assertFalse(-2**33 in msg.map_int64_int64)
+    self.assertFalse(123 in msg.map_uint32_uint32)
+    self.assertFalse(2**33 in msg.map_uint64_uint64)
+    self.assertFalse(123 in msg.map_int32_double)
+    self.assertFalse(False in msg.map_bool_bool)
+    self.assertFalse('abc' in msg.map_string_string)
+    self.assertFalse(111 in msg.map_int32_bytes)
+    self.assertFalse(888 in msg.map_int32_enum)
+
+    # Accessing an unset key returns the default.
+    self.assertEqual(0, msg.map_int32_int32[-123])
+    self.assertEqual(0, msg.map_int64_int64[-2**33])
+    self.assertEqual(0, msg.map_uint32_uint32[123])
+    self.assertEqual(0, msg.map_uint64_uint64[2**33])
+    self.assertEqual(0.0, msg.map_int32_double[123])
+    self.assertTrue(isinstance(msg.map_int32_double[123], float))
+    self.assertEqual(False, msg.map_bool_bool[False])
+    self.assertTrue(isinstance(msg.map_bool_bool[False], bool))
+    self.assertEqual('', msg.map_string_string['abc'])
+    self.assertEqual(b'', msg.map_int32_bytes[111])
+    self.assertEqual(0, msg.map_int32_enum[888])
+
+    # It also sets the value in the map
+    self.assertTrue(-123 in msg.map_int32_int32)
+    self.assertTrue(-2**33 in msg.map_int64_int64)
+    self.assertTrue(123 in msg.map_uint32_uint32)
+    self.assertTrue(2**33 in msg.map_uint64_uint64)
+    self.assertTrue(123 in msg.map_int32_double)
+    self.assertTrue(False in msg.map_bool_bool)
+    self.assertTrue('abc' in msg.map_string_string)
+    self.assertTrue(111 in msg.map_int32_bytes)
+    self.assertTrue(888 in msg.map_int32_enum)
+
+    self.assertIsInstance(msg.map_string_string['abc'], str)
+
+    # 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.assertEqual(10, msg.map_int32_int32.get(key=5, default=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.assertEqual(15, msg.map_int32_int32.get(5))
+    with self.assertRaises(TypeError):
+      msg.map_int32_int32.get('')
+
+    self.assertIsNone(msg.map_int32_foreign_message.get(5))
+    self.assertEqual(10, msg.map_int32_foreign_message.get(5, 10))
+    self.assertEqual(10, msg.map_int32_foreign_message.get(key=5, default=10))
+
+    submsg = msg.map_int32_foreign_message[5]
+    self.assertIs(submsg, msg.map_int32_foreign_message.get(5))
+    with self.assertRaises(TypeError):
+      msg.map_int32_foreign_message.get('')
+
+  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_int32_float[2] = 1.2
+    msg.map_int32_double[1] = 3.3
+    msg.map_string_string['abc'] = '123'
+    msg.map_bool_bool[True] = True
+    msg.map_int32_enum[888] = 2
+    # Unknown numeric enum is supported in proto3.
+    msg.map_int32_enum[123] = 456
+
+    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.assertAlmostEqual(1.2, msg.map_int32_float[2])
+    self.assertEqual(3.3, msg.map_int32_double[1])
+    self.assertEqual('123', msg2.map_string_string['abc'])
+    self.assertEqual(True, msg2.map_bool_bool[True])
+    self.assertEqual(2, msg2.map_int32_enum[888])
+    self.assertEqual(456, msg2.map_int32_enum[123])
+    self.assertEqual('{-123: -456}', str(msg2.map_int32_int32))
+
+  def testMapEntryAlwaysSerialized(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[0] = 0
+    msg.map_string_string[''] = ''
+    self.assertEqual(msg.ByteSize(), 12)
+    self.assertEqual(b'\n\x04\x08\x00\x10\x00r\x04\n\x00\x12\x00',
+                     msg.SerializeToString())
+
+  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, str)
+    self.assertIsInstance(value, str)
+
+  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))
+    msg2.map_int32_foreign_message[123].c = 1
+    # TODO(jieluo): Fix text format for message map.
+    self.assertIn(
+        str(msg2.map_int32_foreign_message),
+        ('{-456: , 123: c: 1\n}', '{123: c: 1\n, -456: }'))
+
+  def testNestedMessageMapItemDelete(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_all_types[1].optional_nested_message.bb = 1
+    del msg.map_int32_all_types[1]
+    msg.map_int32_all_types[2].optional_nested_message.bb = 2
+    self.assertEqual(1, len(msg.map_int32_all_types))
+    msg.map_int32_all_types[1].optional_nested_message.bb = 1
+    self.assertEqual(2, len(msg.map_int32_all_types))
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+    keys = [1, 2]
+    # The loop triggers PyErr_Occurred() in c extension.
+    for key in keys:
+      del msg2.map_int32_all_types[key]
+
+  def testMapByteSize(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[1] = 1
+    size = msg.ByteSize()
+    msg.map_int32_int32[1] = 128
+    self.assertEqual(msg.ByteSize(), size + 1)
+
+    msg.map_int32_foreign_message[19].c = 1
+    size = msg.ByteSize()
+    msg.map_int32_foreign_message[19].c = 128
+    self.assertEqual(msg.ByteSize(), size + 1)
+
+  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.map_int32_foreign_message[222].d = 20
+    old_map_value = msg2.map_int32_foreign_message[222]
+
+    msg2.MergeFrom(msg)
+    # Compare with expected message instead of call
+    # msg2.map_int32_foreign_message[222] to make sure MergeFrom does not
+    # sync with repeated field and there is no duplicated keys.
+    expected_msg = map_unittest_pb2.TestMap()
+    expected_msg.CopyFrom(msg)
+    expected_msg.map_int64_int64[88] = 99
+    self.assertEqual(msg2, expected_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)
+    self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
+    if api_implementation.Type() != 'cpp':
+      # During the call to MergeFrom(), the C++ implementation will have
+      # deallocated the underlying message, but this is very difficult to detect
+      # properly. The line below is likely to cause a segmentation fault.
+      # With the Python implementation, old_map_value is just 'detached' from
+      # the main message. Using it will not crash of course, but since it still
+      # have a reference to the parent message I'm sure we can find interesting
+      # ways to cause inconsistencies.
+      self.assertEqual(15, old_map_value.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)
+    with self.assertRaises(TypeError):
+      del msg2.map_int32_foreign_message['']
+
+  def testMapMergeFrom(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.map_int32_foreign_message[222].d = 20
+
+    msg2.map_int32_int32.MergeFrom(msg.map_int32_int32)
+    self.assertEqual(34, msg2.map_int32_int32[12])
+    self.assertEqual(78, msg2.map_int32_int32[56])
+
+    msg2.map_int64_int64.MergeFrom(msg.map_int64_int64)
+    self.assertEqual(33, msg2.map_int64_int64[22])
+    self.assertEqual(99, msg2.map_int64_int64[88])
+
+    msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message)
+    # Compare with expected message instead of call
+    # msg.map_int32_foreign_message[222] to make sure MergeFrom does not
+    # sync with repeated field and no duplicated keys.
+    expected_msg = map_unittest_pb2.TestMap()
+    expected_msg.CopyFrom(msg)
+    expected_msg.map_int64_int64[88] = 99
+    self.assertEqual(msg2, expected_msg)
+
+    # Test when cpp extension cache a map.
+    m1 = map_unittest_pb2.TestMap()
+    m2 = map_unittest_pb2.TestMap()
+    self.assertEqual(m1.map_int32_foreign_message, m1.map_int32_foreign_message)
+    m2.map_int32_foreign_message[123].c = 10
+    m1.MergeFrom(m2)
+    self.assertEqual(10, m2.map_int32_foreign_message[123].c)
+
+    # Test merge maps within different message types.
+    m1 = map_unittest_pb2.TestMap()
+    m2 = map_unittest_pb2.TestMessageMap()
+    m2.map_int32_message[123].optional_int32 = 10
+    m1.map_int32_all_types.MergeFrom(m2.map_int32_message)
+    self.assertEqual(10, m1.map_int32_all_types[123].optional_int32)
+
+    # Test overwrite message value map
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_foreign_message[222].c = 123
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.map_int32_foreign_message[222].d = 20
+    msg.MergeFromString(msg2.SerializeToString())
+    self.assertEqual(msg.map_int32_foreign_message[222].d, 20)
+    self.assertNotEqual(msg.map_int32_foreign_message[222].c, 123)
+
+    # Merge a dict to map field is not accepted
+    with self.assertRaises(AttributeError):
+      m1.map_int32_all_types.MergeFrom(
+          {1: unittest_proto3_arena_pb2.TestAllTypes()})
+
+  def testMergeFromBadType(self):
+    msg = map_unittest_pb2.TestMap()
+    with self.assertRaisesRegex(
+        TypeError,
+        r'Parameter to MergeFrom\(\) must be instance of same class: expected '
+        r'.+TestMap got int\.'):
+      msg.MergeFrom(1)
+
+  def testCopyFromBadType(self):
+    msg = map_unittest_pb2.TestMap()
+    with self.assertRaisesRegex(
+        TypeError,
+        r'Parameter to [A-Za-z]*From\(\) must be instance of same class: '
+        r'expected .+TestMap got int\.'):
+      msg.CopyFrom(1)
+
+  def testIntegerMapWithLongs(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[int(-123)] = int(-456)
+    msg.map_int64_int64[int(-2**33)] = int(-2**34)
+    msg.map_uint32_uint32[int(123)] = int(456)
+    msg.map_uint64_uint64[int(2**33)] = int(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 testModifyMapEntryWhileIterating(self):
+    msg = map_unittest_pb2.TestMap()
+
+    msg.map_string_string['abc'] = '123'
+    msg.map_string_string['def'] = '456'
+    msg.map_string_string['ghi'] = '789'
+
+    msg.map_int32_foreign_message[5].c = 5
+    msg.map_int32_foreign_message[6].c = 6
+    msg.map_int32_foreign_message[7].c = 7
+
+    string_string_keys = list(msg.map_string_string.keys())
+    int32_foreign_keys = list(msg.map_int32_foreign_message.keys())
+
+    keys = []
+    for key in msg.map_string_string:
+      keys.append(key)
+      msg.map_string_string[key] = '000'
+    self.assertEqual(keys, string_string_keys)
+    self.assertEqual(keys, list(msg.map_string_string.keys()))
+
+    keys = []
+    for key in msg.map_int32_foreign_message:
+      keys.append(key)
+      msg.map_int32_foreign_message[key].c = 0
+    self.assertEqual(keys, int32_foreign_keys)
+    self.assertEqual(keys, list(msg.map_int32_foreign_message.keys()))
+
+  def testSubmessageMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    submsg = msg.map_int32_foreign_message[111]
+    self.assertIs(submsg, msg.map_int32_foreign_message[111])
+    self.assertIsInstance(submsg, unittest_pb2.ForeignMessage)
+
+    submsg.c = 5
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
+
+    # Doesn't allow direct submessage assignment.
+    with self.assertRaises(ValueError):
+      msg.map_int32_foreign_message[88] = unittest_pb2.ForeignMessage()
+
+  def testMapIteration(self):
+    msg = map_unittest_pb2.TestMap()
+
+    for k, v in msg.map_int32_int32.items():
+      # Should not be reached.
+      self.assertTrue(False)
+
+    msg.map_int32_int32[2] = 4
+    msg.map_int32_int32[3] = 6
+    msg.map_int32_int32[4] = 8
+    self.assertEqual(3, len(msg.map_int32_int32))
+
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(msg.map_int32_int32.items(), matching_dict)
+
+  def testMapItems(self):
+    # Map items used to have strange behaviors when use c extension. Because
+    # [] may reorder the map and invalidate any existing iterators.
+    # TODO(jieluo): Check if [] reordering the map is a bug or intended
+    # behavior.
+    msg = map_unittest_pb2.TestMap()
+    msg.map_string_string['local_init_op'] = ''
+    msg.map_string_string['trainable_variables'] = ''
+    msg.map_string_string['variables'] = ''
+    msg.map_string_string['init_op'] = ''
+    msg.map_string_string['summaries'] = ''
+    items1 = msg.map_string_string.items()
+    items2 = msg.map_string_string.items()
+    self.assertEqual(items1, items2)
+
+  def testMapDeterministicSerialization(self):
+    golden_data = (b'r\x0c\n\x07init_op\x12\x01d'
+                   b'r\n\n\x05item1\x12\x01e'
+                   b'r\n\n\x05item2\x12\x01f'
+                   b'r\n\n\x05item3\x12\x01g'
+                   b'r\x0b\n\x05item4\x12\x02QQ'
+                   b'r\x12\n\rlocal_init_op\x12\x01a'
+                   b'r\x0e\n\tsummaries\x12\x01e'
+                   b'r\x18\n\x13trainable_variables\x12\x01b'
+                   b'r\x0e\n\tvariables\x12\x01c')
+    msg = map_unittest_pb2.TestMap()
+    msg.map_string_string['local_init_op'] = 'a'
+    msg.map_string_string['trainable_variables'] = 'b'
+    msg.map_string_string['variables'] = 'c'
+    msg.map_string_string['init_op'] = 'd'
+    msg.map_string_string['summaries'] = 'e'
+    msg.map_string_string['item1'] = 'e'
+    msg.map_string_string['item2'] = 'f'
+    msg.map_string_string['item3'] = 'g'
+    msg.map_string_string['item4'] = 'QQ'
+
+    # If deterministic serialization is not working correctly, this will be
+    # "flaky" depending on the exact python dict hash seed.
+    #
+    # Fortunately, there are enough items in this map that it is extremely
+    # unlikely to ever hit the "right" in-order combination, so the test
+    # itself should fail reliably.
+    self.assertEqual(golden_data, msg.SerializeToString(deterministic=True))
+
+  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 testMapScalarFieldConstruction(self):
+    msg1 = map_unittest_pb2.TestMap()
+    msg1.map_int32_int32[1] = 42
+    msg2 = map_unittest_pb2.TestMap(map_int32_int32=msg1.map_int32_int32)
+    self.assertEqual(42, msg2.map_int32_int32[1])
+
+  def testMapMessageFieldConstruction(self):
+    msg1 = map_unittest_pb2.TestMap()
+    msg1.map_string_foreign_message['test'].c = 42
+    msg2 = map_unittest_pb2.TestMap(
+        map_string_foreign_message=msg1.map_string_foreign_message)
+    self.assertEqual(42, msg2.map_string_foreign_message['test'].c)
+
+  def testMapFieldRaisesCorrectError(self):
+    # Should raise a TypeError when given a non-iterable.
+    with self.assertRaises(TypeError):
+      map_unittest_pb2.TestMap(map_string_foreign_message=1)
+
+  def testMapValidAfterFieldCleared(self):
+    # Map needs to work even if field is cleared.
+    # For the C++ implementation this tests the correctness of
+    # MapContainer::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
+    # MapContainer::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 testMessageMapItemValidAfterTopMessageCleared(self):
+    # Message map item needs to work even if it is cleared.
+    # For the C++ implementation this tests the correctness of
+    # MapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_all_types[2].optional_string = 'bar'
+
+    if api_implementation.Type() == 'cpp':
+      # Need to keep the map reference because of b/27942626.
+      # TODO(jieluo): Remove it.
+      unused_map = msg.map_int32_all_types  # pylint: disable=unused-variable
+    msg_value = msg.map_int32_all_types[2]
+    msg.Clear()
+
+    # Reset to trigger sync between repeated field and map in c++.
+    msg.map_int32_all_types[3].optional_string = 'foo'
+    self.assertEqual(msg_value.optional_string, 'bar')
+
+  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))
+
+    with self.assertRaises(KeyError):
+      del msg.map_int32_all_types[32]
+
+  def testMapsAreMapping(self):
+    msg = map_unittest_pb2.TestMap()
+    self.assertIsInstance(msg.map_int32_int32, collections.abc.Mapping)
+    self.assertIsInstance(msg.map_int32_int32, collections.abc.MutableMapping)
+    self.assertIsInstance(msg.map_int32_foreign_message,
+                          collections.abc.Mapping)
+    self.assertIsInstance(msg.map_int32_foreign_message,
+                          collections.abc.MutableMapping)
+
+  def testMapsCompare(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[-123] = -456
+    self.assertEqual(msg.map_int32_int32, msg.map_int32_int32)
+    self.assertEqual(msg.map_int32_foreign_message,
+                     msg.map_int32_foreign_message)
+    self.assertNotEqual(msg.map_int32_int32, 0)
+
+  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()))
+
+  @unittest.skipIf(sys.maxunicode == UCS2_MAXUNICODE, 'Skip for ucs2')
+  def testStrictUtf8Check(self):
+    # Test u'\ud801' is rejected at parser in both python2 and python3.
+    serialized = (b'r\x03\xed\xa0\x81')
+    msg = unittest_proto3_arena_pb2.TestAllTypes()
+    with self.assertRaises(Exception) as context:
+      msg.MergeFromString(serialized)
+    if api_implementation.Type() == 'python':
+      self.assertIn('optional_string', str(context.exception))
+    else:
+      self.assertIn('Error parsing message', str(context.exception))
+
+    # Test optional_string=u'😍' is accepted.
+    serialized = unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=u'😍').SerializeToString()
+    msg2 = unittest_proto3_arena_pb2.TestAllTypes()
+    msg2.MergeFromString(serialized)
+    self.assertEqual(msg2.optional_string, u'😍')
+
+    msg = unittest_proto3_arena_pb2.TestAllTypes(optional_string=u'\ud001')
+    self.assertEqual(msg.optional_string, u'\ud001')
+
+  def testSurrogatesInPython3(self):
+    # Surrogates are rejected at setters in Python3.
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(optional_string=u'\ud801\udc01')
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(optional_string=b'\xed\xa0\x81')
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(optional_string=u'\ud801')
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(optional_string=u'\ud801\ud801')
+
+
+
+
+@testing_refleaks.TestCase
+class ValidTypeNamesTest(unittest.TestCase):
+
+  def assertImportFromName(self, msg, base_name):
+    # Parse <type 'module.class_name'> to extra 'some.name' as a string.
+    tp_name = str(type(msg)).split("'")[1]
+    valid_names = ('Repeated%sContainer' % base_name,
+                   'Repeated%sFieldContainer' % base_name)
+    self.assertTrue(
+        any(tp_name.endswith(v) for v in valid_names),
+        '%r does end with any of %r' % (tp_name, valid_names))
+
+    parts = tp_name.split('.')
+    class_name = parts[-1]
+    module_name = '.'.join(parts[:-1])
+    __import__(module_name, fromlist=[class_name])
+
+  def testTypeNamesCanBeImported(self):
+    # If import doesn't work, pickling won't work either.
+    pb = unittest_pb2.TestAllTypes()
+    self.assertImportFromName(pb.repeated_int32, 'Scalar')
+    self.assertImportFromName(pb.repeated_nested_message, 'Composite')
+
+
+@testing_refleaks.TestCase
+class PackedFieldTest(unittest.TestCase):
+
+  def setMessage(self, message):
+    message.repeated_int32.append(1)
+    message.repeated_int64.append(1)
+    message.repeated_uint32.append(1)
+    message.repeated_uint64.append(1)
+    message.repeated_sint32.append(1)
+    message.repeated_sint64.append(1)
+    message.repeated_fixed32.append(1)
+    message.repeated_fixed64.append(1)
+    message.repeated_sfixed32.append(1)
+    message.repeated_sfixed64.append(1)
+    message.repeated_float.append(1.0)
+    message.repeated_double.append(1.0)
+    message.repeated_bool.append(True)
+    message.repeated_nested_enum.append(1)
+
+  def testPackedFields(self):
+    message = packed_field_test_pb2.TestPackedTypes()
+    self.setMessage(message)
+    golden_data = (b'\x0A\x01\x01'
+                   b'\x12\x01\x01'
+                   b'\x1A\x01\x01'
+                   b'\x22\x01\x01'
+                   b'\x2A\x01\x02'
+                   b'\x32\x01\x02'
+                   b'\x3A\x04\x01\x00\x00\x00'
+                   b'\x42\x08\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x4A\x04\x01\x00\x00\x00'
+                   b'\x52\x08\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x5A\x04\x00\x00\x80\x3f'
+                   b'\x62\x08\x00\x00\x00\x00\x00\x00\xf0\x3f'
+                   b'\x6A\x01\x01'
+                   b'\x72\x01\x01')
+    self.assertEqual(golden_data, message.SerializeToString())
+
+  def testUnpackedFields(self):
+    message = packed_field_test_pb2.TestUnpackedTypes()
+    self.setMessage(message)
+    golden_data = (b'\x08\x01'
+                   b'\x10\x01'
+                   b'\x18\x01'
+                   b'\x20\x01'
+                   b'\x28\x02'
+                   b'\x30\x02'
+                   b'\x3D\x01\x00\x00\x00'
+                   b'\x41\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x4D\x01\x00\x00\x00'
+                   b'\x51\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x5D\x00\x00\x80\x3f'
+                   b'\x61\x00\x00\x00\x00\x00\x00\xf0\x3f'
+                   b'\x68\x01'
+                   b'\x70\x01')
+    self.assertEqual(golden_data, message.SerializeToString())
+
+
+@unittest.skipIf(api_implementation.Type() == 'python',
+                 'explicit tests of the C++ implementation')
+@testing_refleaks.TestCase
+class OversizeProtosTest(unittest.TestCase):
+
+  def GenerateNestedProto(self, n):
+    msg = unittest_pb2.TestRecursiveMessage()
+    sub = msg
+    for _ in range(n):
+      sub = sub.a
+    sub.i = 0
+    return msg.SerializeToString()
+
+  def testSucceedOkSizedProto(self):
+    msg = unittest_pb2.TestRecursiveMessage()
+    msg.ParseFromString(self.GenerateNestedProto(100))
+
+  def testAssertOversizeProto(self):
+    api_implementation._c_module.SetAllowOversizeProtos(False)
+    msg = unittest_pb2.TestRecursiveMessage()
+    with self.assertRaises(message.DecodeError) as context:
+      msg.ParseFromString(self.GenerateNestedProto(101))
+    self.assertIn('Error parsing message', str(context.exception))
+
+  def testSucceedOversizeProto(self):
+    api_implementation._c_module.SetAllowOversizeProtos(True)
+    msg = unittest_pb2.TestRecursiveMessage()
+    msg.ParseFromString(self.GenerateNestedProto(101))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto
new file mode 100644
index 0000000..37baca7
--- /dev/null
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -0,0 +1,56 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+
+package google.protobuf.python.internal;
+
+message TestEnumValues {
+  enum NestedEnum {
+    ZERO = 0;
+    ONE = 1;
+  }
+  optional NestedEnum optional_nested_enum = 1;
+  repeated NestedEnum repeated_nested_enum = 2;
+  repeated NestedEnum packed_nested_enum = 3 [packed = true];
+}
+
+message TestMissingEnumValues {
+  enum NestedEnum { TWO = 2; }
+  optional NestedEnum optional_nested_enum = 1;
+  repeated NestedEnum repeated_nested_enum = 2;
+  repeated NestedEnum packed_nested_enum = 3 [packed = true];
+}
+
+message JustString {
+  required string dummy = 1;
+}
+
diff --git a/python/google/protobuf/internal/more_extensions.proto b/python/google/protobuf/internal/more_extensions.proto
new file mode 100644
index 0000000..5340a70
--- /dev/null
+++ b/python/google/protobuf/internal/more_extensions.proto
@@ -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.
+
+// Author: robinson@google.com (Will Robinson)
+
+syntax = "proto2";
+
+package google.protobuf.internal;
+
+message TopLevelMessage {
+  optional ExtendedMessage submessage = 1 [lazy = true];
+  optional NestedMessage nested_message = 2 [lazy = true];
+}
+
+message NestedMessage {
+  optional ExtendedMessage submessage = 1 [lazy = true];
+}
+
+message ExtendedMessage {
+  optional int32 optional_int32 = 1001;
+  repeated string repeated_string = 1002;
+  extensions 1 to 999;
+}
+
+message ForeignMessage {
+  optional int32 foreign_message_int = 1;
+}
+
+extend ExtendedMessage {
+  optional int32 optional_int_extension = 1;
+  optional ForeignMessage optional_message_extension = 2;
+
+  repeated int32 repeated_int_extension = 3;
+  repeated ForeignMessage repeated_message_extension = 4;
+}
diff --git a/python/google/protobuf/internal/more_extensions_dynamic.proto b/python/google/protobuf/internal/more_extensions_dynamic.proto
new file mode 100644
index 0000000..98fcbcb
--- /dev/null
+++ b/python/google/protobuf/internal/more_extensions_dynamic.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: jasonh@google.com (Jason Hsueh)
+//
+// This file is used to test a corner case in the CPP implementation where the
+// generated C++ type is available for the extendee, but the extension is
+// defined in a file whose C++ type is not in the binary.
+
+syntax = "proto2";
+
+import "google/protobuf/internal/more_extensions.proto";
+
+package google.protobuf.internal;
+
+message DynamicMessageType {
+  optional int32 a = 1;
+}
+
+extend ExtendedMessage {
+  optional int32 dynamic_int32_extension = 100;
+  optional DynamicMessageType dynamic_message_extension = 101;
+  repeated DynamicMessageType repeated_dynamic_message_extension = 102;
+}
diff --git a/python/google/protobuf/internal/more_messages.proto b/python/google/protobuf/internal/more_messages.proto
new file mode 100644
index 0000000..524dc70
--- /dev/null
+++ b/python/google/protobuf/internal/more_messages.proto
@@ -0,0 +1,360 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: robinson@google.com (Will Robinson)
+
+// LINT: LEGACY_NAMES
+
+syntax = "proto2";
+
+package google.protobuf.internal;
+
+// A message where tag numbers are listed out of order, to allow us to test our
+// canonicalization of serialized output, which should always be in tag order.
+// We also mix in some extensions for extra fun.
+message OutOfOrderFields {
+  optional sint32 optional_sint32 = 5;
+  extensions 4 to 4;
+  optional uint32 optional_uint32 = 3;
+  extensions 2 to 2;
+  optional int32 optional_int32 = 1;
+}
+
+extend OutOfOrderFields {
+  optional uint64 optional_uint64 = 4;
+  optional int64 optional_int64 = 2;
+}
+
+enum is {  // top level enum keyword
+  default = 0;
+  else = 1;  // top level enum value keyword
+}
+
+message class {  // message keyword
+  optional int32 int_field = 1 [json_name = "json_int"];
+  optional int32 if = 2;  // field keyword
+  optional is as = 3;     // enum field keyword
+  optional is enum_field = 4;
+  enum for {                            // nested enum keyword
+    default = 0;
+    True = 1;  // nested enum value keyword
+  }
+  optional for nested_enum_field = 5;
+  message try {
+    optional int32 field = 1;
+    extensions 999 to 9999;
+  }
+  optional try
+    nested_message = 6;
+  extensions 999 to 9999;
+}
+
+extend class {
+  optional int32 continue = 1001;  // top level extension keyword
+}
+
+extend class.try {
+  optional int32 with = 1001;
+}
+
+message ExtendClass {
+  extend class {
+    optional int32 return = 1002;  // nested extension keyword
+  }
+}
+
+message TestFullKeyword {
+  optional google.protobuf.internal.OutOfOrderFields field1 = 1;
+  optional google.protobuf.internal.class field2 = 2;
+}
+
+// TODO(jieluo): Add keyword support for service.
+// service False {
+//   rpc Bar(class) returns (class);
+// }
+
+message LotsNestedMessage {
+  message B0 {}
+  message B1 {}
+  message B2 {}
+  message B3 {}
+  message B4 {}
+  message B5 {}
+  message B6 {}
+  message B7 {}
+  message B8 {}
+  message B9 {}
+  message B10 {}
+  message B11 {}
+  message B12 {}
+  message B13 {}
+  message B14 {}
+  message B15 {}
+  message B16 {}
+  message B17 {}
+  message B18 {}
+  message B19 {}
+  message B20 {}
+  message B21 {}
+  message B22 {}
+  message B23 {}
+  message B24 {}
+  message B25 {}
+  message B26 {}
+  message B27 {}
+  message B28 {}
+  message B29 {}
+  message B30 {}
+  message B31 {}
+  message B32 {}
+  message B33 {}
+  message B34 {}
+  message B35 {}
+  message B36 {}
+  message B37 {}
+  message B38 {}
+  message B39 {}
+  message B40 {}
+  message B41 {}
+  message B42 {}
+  message B43 {}
+  message B44 {}
+  message B45 {}
+  message B46 {}
+  message B47 {}
+  message B48 {}
+  message B49 {}
+  message B50 {}
+  message B51 {}
+  message B52 {}
+  message B53 {}
+  message B54 {}
+  message B55 {}
+  message B56 {}
+  message B57 {}
+  message B58 {}
+  message B59 {}
+  message B60 {}
+  message B61 {}
+  message B62 {}
+  message B63 {}
+  message B64 {}
+  message B65 {}
+  message B66 {}
+  message B67 {}
+  message B68 {}
+  message B69 {}
+  message B70 {}
+  message B71 {}
+  message B72 {}
+  message B73 {}
+  message B74 {}
+  message B75 {}
+  message B76 {}
+  message B77 {}
+  message B78 {}
+  message B79 {}
+  message B80 {}
+  message B81 {}
+  message B82 {}
+  message B83 {}
+  message B84 {}
+  message B85 {}
+  message B86 {}
+  message B87 {}
+  message B88 {}
+  message B89 {}
+  message B90 {}
+  message B91 {}
+  message B92 {}
+  message B93 {}
+  message B94 {}
+  message B95 {}
+  message B96 {}
+  message B97 {}
+  message B98 {}
+  message B99 {}
+  message B100 {}
+  message B101 {}
+  message B102 {}
+  message B103 {}
+  message B104 {}
+  message B105 {}
+  message B106 {}
+  message B107 {}
+  message B108 {}
+  message B109 {}
+  message B110 {}
+  message B111 {}
+  message B112 {}
+  message B113 {}
+  message B114 {}
+  message B115 {}
+  message B116 {}
+  message B117 {}
+  message B118 {}
+  message B119 {}
+  message B120 {}
+  message B121 {}
+  message B122 {}
+  message B123 {}
+  message B124 {}
+  message B125 {}
+  message B126 {}
+  message B127 {}
+  message B128 {}
+  message B129 {}
+  message B130 {}
+  message B131 {}
+  message B132 {}
+  message B133 {}
+  message B134 {}
+  message B135 {}
+  message B136 {}
+  message B137 {}
+  message B138 {}
+  message B139 {}
+  message B140 {}
+  message B141 {}
+  message B142 {}
+  message B143 {}
+  message B144 {}
+  message B145 {}
+  message B146 {}
+  message B147 {}
+  message B148 {}
+  message B149 {}
+  message B150 {}
+  message B151 {}
+  message B152 {}
+  message B153 {}
+  message B154 {}
+  message B155 {}
+  message B156 {}
+  message B157 {}
+  message B158 {}
+  message B159 {}
+  message B160 {}
+  message B161 {}
+  message B162 {}
+  message B163 {}
+  message B164 {}
+  message B165 {}
+  message B166 {}
+  message B167 {}
+  message B168 {}
+  message B169 {}
+  message B170 {}
+  message B171 {}
+  message B172 {}
+  message B173 {}
+  message B174 {}
+  message B175 {}
+  message B176 {}
+  message B177 {}
+  message B178 {}
+  message B179 {}
+  message B180 {}
+  message B181 {}
+  message B182 {}
+  message B183 {}
+  message B184 {}
+  message B185 {}
+  message B186 {}
+  message B187 {}
+  message B188 {}
+  message B189 {}
+  message B190 {}
+  message B191 {}
+  message B192 {}
+  message B193 {}
+  message B194 {}
+  message B195 {}
+  message B196 {}
+  message B197 {}
+  message B198 {}
+  message B199 {}
+  message B200 {}
+  message B201 {}
+  message B202 {}
+  message B203 {}
+  message B204 {}
+  message B205 {}
+  message B206 {}
+  message B207 {}
+  message B208 {}
+  message B209 {}
+  message B210 {}
+  message B211 {}
+  message B212 {}
+  message B213 {}
+  message B214 {}
+  message B215 {}
+  message B216 {}
+  message B217 {}
+  message B218 {}
+  message B219 {}
+  message B220 {}
+  message B221 {}
+  message B222 {}
+  message B223 {}
+  message B224 {}
+  message B225 {}
+  message B226 {}
+  message B227 {}
+  message B228 {}
+  message B229 {}
+  message B230 {}
+  message B231 {}
+  message B232 {}
+  message B233 {}
+  message B234 {}
+  message B235 {}
+  message B236 {}
+  message B237 {}
+  message B238 {}
+  message B239 {}
+  message B240 {}
+  message B241 {}
+  message B242 {}
+  message B243 {}
+  message B244 {}
+  message B245 {}
+  message B246 {}
+  message B247 {}
+  message B248 {}
+  message B249 {}
+  message B250 {}
+  message B251 {}
+  message B252 {}
+  message B253 {}
+  message B254 {}
+  message B255 {}
+}
diff --git a/python/google/protobuf/internal/no_package.proto b/python/google/protobuf/internal/no_package.proto
new file mode 100644
index 0000000..49eda95
--- /dev/null
+++ b/python/google/protobuf/internal/no_package.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+enum NoPackageEnum {
+  NO_PACKAGE_VALUE_0 = 0;
+  NO_PACKAGE_VALUE_1 = 1;
+}
+
+message NoPackageMessage {
+  optional NoPackageEnum no_package_enum = 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
new file mode 100644
index 0000000..48077b0
--- /dev/null
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -0,0 +1,106 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests for google.protobuf.proto_builder."""
+
+import collections
+import unittest
+
+from google.protobuf import descriptor_pb2  # pylint: disable=g-import-not-at-top
+from google.protobuf import descriptor
+from google.protobuf import descriptor_pool
+from google.protobuf import proto_builder
+from google.protobuf import text_format
+
+
+class ProtoBuilderTest(unittest.TestCase):
+
+  def setUp(self):
+    self.ordered_fields = collections.OrderedDict([
+        ('foo', descriptor_pb2.FieldDescriptorProto.TYPE_INT64),
+        ('bar', descriptor_pb2.FieldDescriptorProto.TYPE_STRING),
+        ])
+    self._fields = dict(self.ordered_fields)
+
+  def testMakeSimpleProtoClass(self):
+    """Test that we can create a proto class."""
+    proto_cls = proto_builder.MakeSimpleProtoClass(
+        self._fields,
+        full_name='net.proto2.python.public.proto_builder_test.Test')
+    proto = proto_cls()
+    proto.foo = 12345
+    proto.bar = 'asdf'
+    self.assertMultiLineEqual(
+        'bar: "asdf"\nfoo: 12345\n', text_format.MessageToString(proto))
+
+  def testOrderedFields(self):
+    """Test that the field order is maintained when given an OrderedDict."""
+    proto_cls = proto_builder.MakeSimpleProtoClass(
+        self.ordered_fields,
+        full_name='net.proto2.python.public.proto_builder_test.OrderedTest')
+    proto = proto_cls()
+    proto.foo = 12345
+    proto.bar = 'asdf'
+    self.assertMultiLineEqual(
+        'foo: 12345\nbar: "asdf"\n', text_format.MessageToString(proto))
+
+  def testMakeSameProtoClassTwice(self):
+    """Test that the DescriptorPool is used."""
+    pool = descriptor_pool.DescriptorPool()
+    proto_cls1 = proto_builder.MakeSimpleProtoClass(
+        self._fields,
+        full_name='net.proto2.python.public.proto_builder_test.Test',
+        pool=pool)
+    proto_cls2 = proto_builder.MakeSimpleProtoClass(
+        self._fields,
+        full_name='net.proto2.python.public.proto_builder_test.Test',
+        pool=pool)
+    self.assertIs(proto_cls1.DESCRIPTOR, proto_cls2.DESCRIPTOR)
+
+  def testMakeLargeProtoClass(self):
+    """Test that large created protos don't use reserved field numbers."""
+    num_fields = 123456
+    fields = {
+        'foo%d' % i: descriptor_pb2.FieldDescriptorProto.TYPE_INT64
+        for i in range(num_fields)
+    }
+    proto_cls = proto_builder.MakeSimpleProtoClass(
+        fields,
+        full_name='net.proto2.python.public.proto_builder_test.LargeProtoTest')
+
+    reserved_field_numbers = set(
+        range(descriptor.FieldDescriptor.FIRST_RESERVED_FIELD_NUMBER,
+              descriptor.FieldDescriptor.LAST_RESERVED_FIELD_NUMBER + 1))
+    proto_field_numbers = set(proto_cls.DESCRIPTOR.fields_by_number)
+    self.assertFalse(reserved_field_numbers.intersection(proto_field_numbers))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
new file mode 100644
index 0000000..5550b42
--- /dev/null
+++ b/python/google/protobuf/internal/python_message.py
@@ -0,0 +1,1539 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 code is meant to work on Python 2.4 and above only.
+#
+# TODO(robinson): Helpers for verbose, common checks like seeing if a
+# descriptor's cpp_type is CPPTYPE_MESSAGE.
+
+"""Contains a metaclass and helper functions used to create
+protocol message classes from Descriptor objects at runtime.
+
+Recall that a metaclass is the "type" of a class.
+(A class is to a metaclass what an instance is to a class.)
+
+In this case, we use the GeneratedProtocolMessageType metaclass
+to inject all the useful functionality into the classes
+output by the protocol compiler at compile-time.
+
+The upshot of all this is that the real implementation
+details for ALL pure-Python protocol buffers are *here in
+this file*.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+from io import BytesIO
+import struct
+import sys
+import weakref
+
+# We use "as" to avoid name collisions with variables.
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import containers
+from google.protobuf.internal import decoder
+from google.protobuf.internal import encoder
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf.internal import extension_dict
+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 text_format
+
+_FieldDescriptor = descriptor_mod.FieldDescriptor
+_AnyFullTypeName = 'google.protobuf.Any'
+_ExtensionDict = extension_dict._ExtensionDict
+
+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(.....)
+  factory = symbol_database.Default()
+  factory.pool.AddDescriptor(mydescriptor)
+  MyProtoClass = factory.GetPrototype(mydescriptor)
+  myproto_instance = MyProtoClass()
+  myproto.foo_field = 23
+  ...
+  """
+
+  # 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.
+
+    Raises:
+      RuntimeError: Generated code only work with python cpp extension.
+    """
+    descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+
+    if isinstance(descriptor, str):
+      raise RuntimeError('The generated code only work with python cpp '
+                         'extension, but it is using pure python runtime.')
+
+    # If a concrete class already exists for this descriptor, don't try to
+    # create another.  Doing so will break any messages that already exist with
+    # the existing class.
+    #
+    # The C++ implementation appears to have its own internal `PyMessageFactory`
+    # to achieve similar results.
+    #
+    # This most commonly happens in `text_format.py` when using descriptors from
+    # a custom pool; it calls symbol_database.Global().getPrototype() on a
+    # descriptor which already has an existing concrete class.
+    new_class = getattr(descriptor, '_concrete_class', None)
+    if new_class:
+      return new_class
+
+    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]
+
+    # If this is an _existing_ class looked up via `_concrete_class` in the
+    # __new__ method above, then we don't need to re-initialize anything.
+    existing_class = getattr(descriptor, '_concrete_class', None)
+    if existing_class:
+      assert existing_class is cls, (
+          'Duplicate `GeneratedProtocolMessageType` created for descriptor %r'
+          % (descriptor.full_name))
+      return
+
+    cls._decoders_by_tag = {}
+    if (descriptor.has_options and
+        descriptor.GetOptions().message_set_wire_format):
+      cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = (
+          decoder.MessageSetItemDecoder(descriptor), 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)
+
+    superclass = super(GeneratedProtocolMessageType, cls)
+    superclass.__init__(name, bases, dictionary)
+
+
+# Stateless helpers for GeneratedProtocolMessageType below.
+# Outside clients should not access these directly.
+#
+# I opted not to make any of these methods on the metaclass, to make it more
+# clear that I'm not really using any state there and to keep clients from
+# thinking that they have direct access to these construction helpers.
+
+
+def _PropertyName(proto_field_name):
+  """Returns the name of the public property attribute which
+  clients can use to get and (in some cases) set the value
+  of a protocol message field.
+
+  Args:
+    proto_field_name: The protocol message field name, exactly
+      as it appears (or would appear) in a .proto file.
+  """
+  # TODO(robinson): Escape Python keywords (e.g., yield), and test this support.
+  # nnorwitz makes my day by writing:
+  # """
+  # FYI.  See the keyword module in the stdlib. This could be as simple as:
+  #
+  # if keyword.iskeyword(proto_field_name):
+  #   return proto_field_name + "_"
+  # return proto_field_name
+  # """
+  # Kenton says:  The above is a BAD IDEA.  People rely on being able to use
+  #   getattr() and setattr() to reflectively manipulate field values.  If we
+  #   rename the properties, then every such user has to also make sure to apply
+  #   the same transformation.  Note that currently if you name a field "yield",
+  #   you can still access it just fine using getattr/setattr -- it's not even
+  #   that cumbersome to do so.
+  # TODO(kenton):  Remove this method entirely if/when everyone agrees with my
+  #   position.
+  return proto_field_name
+
+
+def _AddSlots(message_descriptor, dictionary):
+  """Adds a __slots__ entry to dictionary, containing the names of all valid
+  attributes for this message type.
+
+  Args:
+    message_descriptor: A Descriptor instance describing this message type.
+    dictionary: Class dictionary to which we'll add a '__slots__' entry.
+  """
+  dictionary['__slots__'] = ['_cached_byte_size',
+                             '_cached_byte_size_dirty',
+                             '_fields',
+                             '_unknown_fields',
+                             '_unknown_field_set',
+                             '_is_present_in_parent',
+                             '_listener',
+                             '_listener_for_children',
+                             '__weakref__',
+                             '_oneofs']
+
+
+def _IsMessageSetExtension(field):
+  return (field.is_extension and
+          field.containing_type.has_options and
+          field.containing_type.GetOptions().message_set_wire_format and
+          field.type == _FieldDescriptor.TYPE_MESSAGE 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_packable = (is_repeated and
+                 wire_format.IsTypePackable(field_descriptor.type))
+  is_proto3 = field_descriptor.containing_type.syntax == 'proto3'
+  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 is_map_entry:
+    field_encoder = encoder.MapEncoder(field_descriptor)
+    sizer = encoder.MapSizer(field_descriptor,
+                             _IsMessageMapField(field_descriptor))
+  elif _IsMessageSetExtension(field_descriptor):
+    field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number)
+    sizer = encoder.MessageSetItemSizer(field_descriptor.number)
+  else:
+    field_encoder = type_checkers.TYPE_TO_ENCODER[field_descriptor.type](
+        field_descriptor.number, is_repeated, is_packed)
+    sizer = type_checkers.TYPE_TO_SIZER[field_descriptor.type](
+        field_descriptor.number, is_repeated, is_packed)
+
+  field_descriptor._encoder = field_encoder
+  field_descriptor._sizer = sizer
+  field_descriptor._default_constructor = _DefaultValueConstructorForField(
+      field_descriptor)
+
+  def AddDecoder(wiretype, is_packed):
+    tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype)
+    decode_type = field_descriptor.type
+    if (decode_type == _FieldDescriptor.TYPE_ENUM and
+        type_checkers.SupportsOpenEnums(field_descriptor)):
+      decode_type = _FieldDescriptor.TYPE_INT32
+
+    oneof_descriptor = None
+    clear_if_default = False
+    if field_descriptor.containing_oneof is not None:
+      oneof_descriptor = field_descriptor
+    elif (is_proto3 and not is_repeated and
+          field_descriptor.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE):
+      clear_if_default = True
+
+    if is_map_entry:
+      is_message_map = _IsMessageMapField(field_descriptor)
+
+      field_decoder = decoder.MapDecoder(
+          field_descriptor, _GetInitializeDefaultForMap(field_descriptor),
+          is_message_map)
+    elif decode_type == _FieldDescriptor.TYPE_STRING:
+      field_decoder = decoder.StringDecoder(
+          field_descriptor.number, is_repeated, is_packed,
+          field_descriptor, field_descriptor._default_constructor,
+          clear_if_default)
+    elif field_descriptor.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+      field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
+          field_descriptor.number, is_repeated, is_packed,
+          field_descriptor, field_descriptor._default_constructor)
+    else:
+      field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
+          field_descriptor.number, is_repeated, is_packed,
+          # pylint: disable=protected-access
+          field_descriptor, field_descriptor._default_constructor,
+          clear_if_default)
+
+    cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor)
+
+  AddDecoder(type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type],
+             False)
+
+  if is_repeated and wire_format.IsTypePackable(field_descriptor.type):
+    # To support wire compatibility of adding packed = true, add a decoder for
+    # packed values regardless of the field's options.
+    AddDecoder(wire_format.WIRETYPE_LENGTH_DELIMITED, True)
+
+
+def _AddClassAttributesForNestedExtensions(descriptor, dictionary):
+  extensions = descriptor.extensions_by_name
+  for extension_name, extension_field in extensions.items():
+    assert extension_name not in dictionary
+    dictionary[extension_name] = extension_field
+
+
+def _AddEnumValues(descriptor, cls):
+  """Sets class-level attributes for all enum fields defined in this message.
+
+  Also exporting a class-level object that can name enum values.
+
+  Args:
+    descriptor: Descriptor object for this message type.
+    cls: Class we're constructing for this message type.
+  """
+  for enum_type in descriptor.enum_types:
+    setattr(cls, enum_type.name, enum_type_wrapper.EnumTypeWrapper(enum_type))
+    for enum_value in enum_type.values:
+      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,
+          field.message_type)
+    return MakeMessageMapDefault
+  else:
+    value_checker = type_checkers.GetTypeChecker(value_field)
+    def MakePrimitiveMapDefault(message):
+      return containers.ScalarMap(
+          message._listener_for_children, key_checker, value_checker,
+          field.message_type)
+    return MakePrimitiveMapDefault
+
+def _DefaultValueConstructorForField(field):
+  """Returns a function which returns a default value for a field.
+
+  Args:
+    field: FieldDescriptor object for this field.
+
+  The returned function has one argument:
+    message: Message instance containing this field, or a weakref proxy
+      of same.
+
+  That function in turn returns a default value for this field.  The default
+    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' % (
+          field.default_value))
+    if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+      # We can't look at _concrete_class yet since it might not have
+      # been set.  (Depends on order in which we initialize the classes).
+      message_type = field.message_type
+      def MakeRepeatedMessageDefault(message):
+        return containers.RepeatedCompositeFieldContainer(
+            message._listener_for_children, field.message_type)
+      return MakeRepeatedMessageDefault
+    else:
+      type_checker = type_checkers.GetTypeChecker(field)
+      def MakeRepeatedScalarDefault(message):
+        return containers.RepeatedScalarFieldContainer(
+            message._listener_for_children, type_checker)
+      return MakeRepeatedScalarDefault
+
+  if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+    # _concrete_class may not yet be initialized.
+    message_type = field.message_type
+    def MakeSubMessageDefault(message):
+      assert getattr(message_type, '_concrete_class', None), (
+          'Uninitialized concrete class found for field %r (message type %r)'
+          % (field.full_name, message_type.full_name))
+      result = message_type._concrete_class()
+      result._SetListener(
+          _OneofListener(message, field)
+          if field.containing_oneof is not None
+          else message._listener_for_children)
+      return result
+    return MakeSubMessageDefault
+
+  def MakeScalarDefault(message):
+    # TODO(protobuf-team): This may be broken since there may not be
+    # default_value.  Combine with has_default_value somehow.
+    return field.default_value
+  return MakeScalarDefault
+
+
+def _ReraiseTypeErrorWithFieldName(message_name, field_name):
+  """Re-raise the currently-handled TypeError with the field name added."""
+  exc = sys.exc_info()[1]
+  if len(exc.args) == 1 and type(exc) is TypeError:
+    # simple TypeError; add field name to exception message
+    exc = TypeError('%s for field %s.%s' % (str(exc), message_name, field_name))
+
+  # re-raise possibly-amended exception with original traceback:
+  raise exc.with_traceback(sys.exc_info()[2])
+
+
+def _AddInitMethod(message_descriptor, cls):
+  """Adds an __init__ method to cls."""
+
+  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, str):
+      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
+    self._fields = {}
+    # Contains a mapping from oneof field descriptors to the descriptor
+    # of the currently set field in that oneof field.
+    self._oneofs = {}
+
+    # _unknown_fields is () when empty for efficiency, and will be turned into
+    # a list if fields are added.
+    self._unknown_fields = ()
+    # _unknown_field_set is None when empty for efficiency, and will be
+    # turned into UnknownFieldSet struct if fields are added.
+    self._unknown_field_set = None      # pylint: disable=protected-access
+    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.items():
+      field = _GetFieldByName(message_descriptor, field_name)
+      if field is None:
+        raise TypeError('%s() got an unexpected keyword argument "%s"' %
+                        (message_descriptor.name, field_name))
+      if field_value is None:
+        # field=None is the same as no field at all.
+        continue
+      if field.label == _FieldDescriptor.LABEL_REPEATED:
+        copy = field._default_constructor(self)
+        if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:  # Composite
+          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(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:
+          _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
+
+  init.__module__ = None
+  init.__doc__ = None
+  cls.__init__ = init
+
+
+def _GetFieldByName(message_descriptor, field_name):
+  """Returns a field descriptor by field name.
+
+  Args:
+    message_descriptor: A Descriptor describing all fields in message.
+    field_name: The name of the field to retrieve.
+  Returns:
+    The field descriptor associated with the field name.
+  """
+  try:
+    return message_descriptor.fields_by_name[field_name]
+  except KeyError:
+    raise ValueError('Protocol message %s has no "%s" field.' %
+                     (message_descriptor.name, field_name))
+
+
+def _AddPropertiesForFields(descriptor, cls):
+  """Adds properties for all fields in this protocol message type."""
+  for field in descriptor.fields:
+    _AddPropertiesForField(field, cls)
+
+  if descriptor.is_extendable:
+    # _ExtensionDict is just an adaptor with no state so we allocate a new one
+    # every time it is accessed.
+    cls.Extensions = property(lambda self: _ExtensionDict(self))
+
+
+def _AddPropertiesForField(field, cls):
+  """Adds a public property for a protocol message field.
+  Clients can use this property to get and (in the case
+  of non-repeated scalar fields) directly set the value
+  of a protocol message field.
+
+  Args:
+    field: A FieldDescriptor for this field.
+    cls: The class we're constructing.
+  """
+  # Catch it if we add other types that we should
+  # handle specially here.
+  assert _FieldDescriptor.MAX_CPPTYPE == 10
+
+  constant_name = field.name.upper() + '_FIELD_NUMBER'
+  setattr(cls, constant_name, field.number)
+
+  if field.label == _FieldDescriptor.LABEL_REPEATED:
+    _AddPropertiesForRepeatedField(field, cls)
+  elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+    _AddPropertiesForNonRepeatedCompositeField(field, cls)
+  else:
+    _AddPropertiesForNonRepeatedScalarField(field, cls)
+
+
+class _FieldProperty(property):
+  __slots__ = ('DESCRIPTOR',)
+
+  def __init__(self, descriptor, getter, setter, doc):
+    property.__init__(self, getter, setter, doc=doc)
+    self.DESCRIPTOR = descriptor
+
+
+def _AddPropertiesForRepeatedField(field, cls):
+  """Adds a public property for a "repeated" protocol message field.  Clients
+  can use this property to get the value of the field, which will be either a
+  RepeatedScalarFieldContainer or RepeatedCompositeFieldContainer (see
+  below).
+
+  Note that when clients add values to these containers, we perform
+  type-checking in the case of repeated scalar fields, and we also set any
+  necessary "has" bits as a side-effect.
+
+  Args:
+    field: A FieldDescriptor for this field.
+    cls: The class we're constructing.
+  """
+  proto_field_name = field.name
+  property_name = _PropertyName(proto_field_name)
+
+  def getter(self):
+    field_value = self._fields.get(field)
+    if field_value is None:
+      # Construct a new object to represent this field.
+      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
+      # take that object and discard ours.
+      # WARNING:  We are relying on setdefault() being atomic.  This is true
+      #   in CPython but we haven't investigated others.  This warning appears
+      #   in several other locations in this file.
+      field_value = self._fields.setdefault(field, field_value)
+    return field_value
+  getter.__module__ = None
+  getter.__doc__ = 'Getter for %s.' % proto_field_name
+
+  # We define a setter just so we can throw an exception with a more
+  # helpful error message.
+  def setter(self, new_value):
+    raise AttributeError('Assignment not allowed to repeated field '
+                         '"%s" in protocol message object.' % proto_field_name)
+
+  doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
+  setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc))
+
+
+def _AddPropertiesForNonRepeatedScalarField(field, cls):
+  """Adds a public property for a nonrepeated, scalar protocol message field.
+  Clients can use this property to get and directly set the value of the field.
+  Note that when the client sets the value of a field by using this property,
+  all necessary "has" bits are set as a side-effect, and we also perform
+  type-checking.
+
+  Args:
+    field: A FieldDescriptor for this field.
+    cls: The class we're constructing.
+  """
+  proto_field_name = field.name
+  property_name = _PropertyName(proto_field_name)
+  type_checker = type_checkers.GetTypeChecker(field)
+  default_value = field.default_value
+  is_proto3 = field.containing_type.syntax == 'proto3'
+
+  def getter(self):
+    # TODO(protobuf-team): This may be broken since there may not be
+    # default_value.  Combine with has_default_value somehow.
+    return self._fields.get(field, default_value)
+  getter.__module__ = None
+  getter.__doc__ = 'Getter for %s.' % proto_field_name
+
+  clear_when_set_to_default = is_proto3 and not field.containing_oneof
+
+  def field_setter(self, new_value):
+    # pylint: disable=protected-access
+    # Testing the value for truthiness captures all of the proto3 defaults
+    # (0, 0.0, enum 0, and False).
+    try:
+      new_value = type_checker.CheckValue(new_value)
+    except TypeError as e:
+      raise TypeError(
+          'Cannot set %s to %.1024r: %s' % (field.full_name, new_value, e))
+    if clear_when_set_to_default and not new_value:
+      self._fields.pop(field, None)
+    else:
+      self._fields[field] = new_value
+    # Check _cached_byte_size_dirty inline to improve performance, since scalar
+    # setters are called frequently.
+    if not self._cached_byte_size_dirty:
+      self._Modified()
+
+  if field.containing_oneof:
+    def setter(self, new_value):
+      field_setter(self, new_value)
+      self._UpdateOneofState(field)
+  else:
+    setter = field_setter
+
+  setter.__module__ = None
+  setter.__doc__ = 'Setter for %s.' % proto_field_name
+
+  # Add a property to encapsulate the getter/setter.
+  doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
+  setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc))
+
+
+def _AddPropertiesForNonRepeatedCompositeField(field, cls):
+  """Adds a public property for a nonrepeated, composite protocol message field.
+  A composite field is a "group" or "message" field.
+
+  Clients can use this property to get the value of the field, but cannot
+  assign to the property directly.
+
+  Args:
+    field: A FieldDescriptor for this field.
+    cls: The class we're constructing.
+  """
+  # TODO(robinson): Remove duplication with similar method
+  # for non-repeated scalars.
+  proto_field_name = field.name
+  property_name = _PropertyName(proto_field_name)
+
+  def getter(self):
+    field_value = self._fields.get(field)
+    if field_value is None:
+      # Construct a new object to represent this field.
+      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
+      # take that object and discard ours.
+      # WARNING:  We are relying on setdefault() being atomic.  This is true
+      #   in CPython but we haven't investigated others.  This warning appears
+      #   in several other locations in this file.
+      field_value = self._fields.setdefault(field, field_value)
+    return field_value
+  getter.__module__ = None
+  getter.__doc__ = 'Getter for %s.' % proto_field_name
+
+  # We define a setter just so we can throw an exception with a more
+  # helpful error message.
+  def setter(self, new_value):
+    raise AttributeError('Assignment not allowed to composite field '
+                         '"%s" in protocol message object.' % proto_field_name)
+
+  # Add a property to encapsulate the getter.
+  doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
+  setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc))
+
+
+def _AddPropertiesForExtensions(descriptor, cls):
+  """Adds properties for all fields in this protocol message type."""
+  extensions = descriptor.extensions_by_name
+  for extension_name, extension_field in extensions.items():
+    constant_name = extension_name.upper() + '_FIELD_NUMBER'
+    setattr(cls, constant_name, extension_field.number)
+
+  # TODO(amauryfa): Migrate all users of these attributes to functions like
+  #   pool.FindExtensionByNumber(descriptor).
+  if descriptor.file is not None:
+    # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
+    pool = descriptor.file.pool
+    cls._extensions_by_number = pool._extensions_by_number[descriptor]
+    cls._extensions_by_name = pool._extensions_by_name[descriptor]
+
+def _AddStaticMethods(cls):
+  # TODO(robinson): This probably needs to be thread-safe(?)
+  def RegisterExtension(extension_handle):
+    extension_handle.containing_type = cls.DESCRIPTOR
+    # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
+    # pylint: disable=protected-access
+    cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
+    _AttachFieldHelpers(cls, extension_handle)
+  cls.RegisterExtension = staticmethod(RegisterExtension)
+
+  def FromString(s):
+    message = cls()
+    message.MergeFromString(s)
+    return message
+  cls.FromString = staticmethod(FromString)
+
+
+def _IsPresent(item):
+  """Given a (FieldDescriptor, value) tuple from _fields, return true if the
+  value should be included in the list returned by ListFields()."""
+
+  if item[0].label == _FieldDescriptor.LABEL_REPEATED:
+    return bool(item[1])
+  elif item[0].cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+    return item[1]._is_present_in_parent
+  else:
+    return True
+
+
+def _AddListFieldsMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+
+  def ListFields(self):
+    all_fields = [item for item in self._fields.items() if _IsPresent(item)]
+    all_fields.sort(key = lambda item: item[0].number)
+    return all_fields
+
+  cls.ListFields = ListFields
+
+_PROTO3_ERROR_TEMPLATE = \
+  ('Protocol message %s has no non-repeated submessage field "%s" '
+   'nor marked as optional')
+_PROTO2_ERROR_TEMPLATE = 'Protocol message %s has no non-repeated field "%s"'
+
+def _AddHasFieldMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+
+  is_proto3 = (message_descriptor.syntax == "proto3")
+  error_msg = _PROTO3_ERROR_TEMPLATE if is_proto3 else _PROTO2_ERROR_TEMPLATE
+
+  hassable_fields = {}
+  for field in message_descriptor.fields:
+    if field.label == _FieldDescriptor.LABEL_REPEATED:
+      continue
+    # For proto3, only submessages and fields inside a oneof have presence.
+    if (is_proto3 and field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE and
+        not field.containing_oneof):
+      continue
+    hassable_fields[field.name] = field
+
+  # Has methods are supported for oneof descriptors.
+  for oneof in message_descriptor.oneofs:
+    hassable_fields[oneof.name] = oneof
+
+  def HasField(self, field_name):
+    try:
+      field = hassable_fields[field_name]
+    except KeyError:
+      raise ValueError(error_msg % (message_descriptor.full_name, field_name))
+
+    if isinstance(field, descriptor_mod.OneofDescriptor):
+      try:
+        return HasField(self, self._oneofs[field].name)
+      except KeyError:
+        return False
+    else:
+      if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+        value = self._fields.get(field)
+        return value is not None and value._is_present_in_parent
+      else:
+        return field in self._fields
+
+  cls.HasField = HasField
+
+
+def _AddClearFieldMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def ClearField(self, field_name):
+    try:
+      field = message_descriptor.fields_by_name[field_name]
+    except KeyError:
+      try:
+        field = message_descriptor.oneofs_by_name[field_name]
+        if field in self._oneofs:
+          field = self._oneofs[field]
+        else:
+          return
+      except KeyError:
+        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.
+      del self._fields[field]
+
+      if self._oneofs.get(field.containing_oneof, None) is field:
+        del self._oneofs[field.containing_oneof]
+
+    # Always call _Modified() -- even if nothing was changed, this is
+    # a mutating method, and thus calling it should cause the field to become
+    # present in the parent message.
+    self._Modified()
+
+  cls.ClearField = ClearField
+
+
+def _AddClearExtensionMethod(cls):
+  """Helper for _AddMessageMethods()."""
+  def ClearExtension(self, extension_handle):
+    extension_dict._VerifyExtensionHandle(self, extension_handle)
+
+    # Similar to ClearField(), above.
+    if extension_handle in self._fields:
+      del self._fields[extension_handle]
+    self._Modified()
+  cls.ClearExtension = ClearExtension
+
+
+def _AddHasExtensionMethod(cls):
+  """Helper for _AddMessageMethods()."""
+  def HasExtension(self, extension_handle):
+    extension_dict._VerifyExtensionHandle(self, extension_handle)
+    if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
+      raise KeyError('"%s" is repeated.' % extension_handle.full_name)
+
+    if extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+      value = self._fields.get(extension_handle)
+      return value is not None and value._is_present_in_parent
+    else:
+      return extension_handle in self._fields
+  cls.HasExtension = HasExtension
+
+def _InternalUnpackAny(msg):
+  """Unpacks Any message and returns the unpacked message.
+
+  This internal method is different 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.
+  """
+  # TODO(amauryfa): Don't use the factory of generated messages.
+  # To make Any work with custom factories, use the message factory of the
+  # parent message.
+  # pylint: disable=g-import-not-at-top
+  from google.protobuf import symbol_database
+  factory = symbol_database.Default()
+
+  type_url = msg.type_url
+
+  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 = factory.pool.FindMessageTypeByName(type_name)
+
+  if descriptor is None:
+    return None
+
+  message_class = factory.GetPrototype(descriptor)
+  message = message_class()
+
+  message.ParseFromString(msg.value)
+  return message
+
+
+def _AddEqualsMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def __eq__(self, other):
+    if (not isinstance(other, message_mod.Message) or
+        other.DESCRIPTOR != self.DESCRIPTOR):
+      return False
+
+    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
+
+    # TODO(jieluo): Fix UnknownFieldSet to consider MessageSet extensions,
+    # then use it for the comparison.
+    unknown_fields = list(self._unknown_fields)
+    unknown_fields.sort()
+    other_unknown_fields = list(other._unknown_fields)
+    other_unknown_fields.sort()
+    return unknown_fields == other_unknown_fields
+
+  cls.__eq__ = __eq__
+
+
+def _AddStrMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def __str__(self):
+    return text_format.MessageToString(self)
+  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()."""
+
+  def __unicode__(self):
+    return text_format.MessageToString(self, as_utf8=True).decode('utf-8')
+  cls.__unicode__ = __unicode__
+
+
+def _BytesForNonRepeatedElement(value, field_number, field_type):
+  """Returns the number of bytes needed to serialize a non-repeated element.
+  The returned byte count includes space for tag information and any
+  other additional space associated with serializing value.
+
+  Args:
+    value: Value we're serializing.
+    field_number: Field number of this value.  (Since the field number
+      is stored as part of a varint-encoded tag, this has an impact
+      on the total bytes required to serialize the value).
+    field_type: The type of the field.  One of the TYPE_* constants
+      within FieldDescriptor.
+  """
+  try:
+    fn = type_checkers.TYPE_TO_BYTE_SIZE_FN[field_type]
+    return fn(field_number, value)
+  except KeyError:
+    raise message_mod.EncodeError('Unrecognized field type: %d' % field_type)
+
+
+def _AddByteSizeMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+
+  def ByteSize(self):
+    if not self._cached_byte_size_dirty:
+      return self._cached_byte_size
+
+    size = 0
+    descriptor = self.DESCRIPTOR
+    if descriptor.GetOptions().map_entry:
+      # Fields of map entry should always be serialized.
+      size = descriptor.fields_by_name['key']._sizer(self.key)
+      size += descriptor.fields_by_name['value']._sizer(self.value)
+    else:
+      for field_descriptor, field_value in self.ListFields():
+        size += field_descriptor._sizer(field_value)
+      for tag_bytes, value_bytes in self._unknown_fields:
+        size += len(tag_bytes) + len(value_bytes)
+
+    self._cached_byte_size = size
+    self._cached_byte_size_dirty = False
+    self._listener_for_children.dirty = False
+    return size
+
+  cls.ByteSize = ByteSize
+
+
+def _AddSerializeToStringMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+
+  def SerializeToString(self, **kwargs):
+    # Check if the message has all of its required fields set.
+    if not self.IsInitialized():
+      raise message_mod.EncodeError(
+          'Message %s is missing required fields: %s' % (
+          self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
+    return self.SerializePartialToString(**kwargs)
+  cls.SerializeToString = SerializeToString
+
+
+def _AddSerializePartialToStringMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+
+  def SerializePartialToString(self, **kwargs):
+    out = BytesIO()
+    self._InternalSerialize(out.write, **kwargs)
+    return out.getvalue()
+  cls.SerializePartialToString = SerializePartialToString
+
+  def InternalSerialize(self, write_bytes, deterministic=None):
+    if deterministic is None:
+      deterministic = (
+          api_implementation.IsPythonDefaultSerializationDeterministic())
+    else:
+      deterministic = bool(deterministic)
+
+    descriptor = self.DESCRIPTOR
+    if descriptor.GetOptions().map_entry:
+      # Fields of map entry should always be serialized.
+      descriptor.fields_by_name['key']._encoder(
+          write_bytes, self.key, deterministic)
+      descriptor.fields_by_name['value']._encoder(
+          write_bytes, self.value, deterministic)
+    else:
+      for field_descriptor, field_value in self.ListFields():
+        field_descriptor._encoder(write_bytes, field_value, deterministic)
+      for tag_bytes, value_bytes in self._unknown_fields:
+        write_bytes(tag_bytes)
+        write_bytes(value_bytes)
+  cls._InternalSerialize = InternalSerialize
+
+
+def _AddMergeFromStringMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def MergeFromString(self, serialized):
+    serialized = memoryview(serialized)
+    length = len(serialized)
+    try:
+      if self._InternalParse(serialized, 0, length) != length:
+        # The only reason _InternalParse would return early is if it
+        # encountered an end-group tag.
+        raise message_mod.DecodeError('Unexpected end-group tag.')
+    except (IndexError, TypeError):
+      # Now ord(buf[p:p+1]) == ord('') gets TypeError.
+      raise message_mod.DecodeError('Truncated message.')
+    except struct.error as e:
+      raise message_mod.DecodeError(e)
+    return length   # Return this for legacy reasons.
+  cls.MergeFromString = MergeFromString
+
+  local_ReadTag = decoder.ReadTag
+  local_SkipField = decoder.SkipField
+  decoders_by_tag = cls._decoders_by_tag
+
+  def InternalParse(self, buffer, pos, end):
+    """Create a message from serialized bytes.
+
+    Args:
+      self: Message, instance of the proto message object.
+      buffer: memoryview of the serialized data.
+      pos: int, position to start in the serialized data.
+      end: int, end position of the serialized data.
+
+    Returns:
+      Message object.
+    """
+    # Guard against internal misuse, since this function is called internally
+    # quite extensively, and its easy to accidentally pass bytes.
+    assert isinstance(buffer, memoryview)
+    self._Modified()
+    field_dict = self._fields
+    # pylint: disable=protected-access
+    unknown_field_set = self._unknown_field_set
+    while pos != end:
+      (tag_bytes, new_pos) = local_ReadTag(buffer, pos)
+      field_decoder, field_desc = decoders_by_tag.get(tag_bytes, (None, None))
+      if field_decoder is None:
+        if not self._unknown_fields:   # pylint: disable=protected-access
+          self._unknown_fields = []    # pylint: disable=protected-access
+        if unknown_field_set is None:
+          # pylint: disable=protected-access
+          self._unknown_field_set = containers.UnknownFieldSet()
+          # pylint: disable=protected-access
+          unknown_field_set = self._unknown_field_set
+        # pylint: disable=protected-access
+        (tag, _) = decoder._DecodeVarint(tag_bytes, 0)
+        field_number, wire_type = wire_format.UnpackTag(tag)
+        if field_number == 0:
+          raise message_mod.DecodeError('Field number 0 is illegal.')
+        # TODO(jieluo): remove old_pos.
+        old_pos = new_pos
+        (data, new_pos) = decoder._DecodeUnknownField(
+            buffer, new_pos, wire_type)  # pylint: disable=protected-access
+        if new_pos == -1:
+          return pos
+        # pylint: disable=protected-access
+        unknown_field_set._add(field_number, wire_type, data)
+        # TODO(jieluo): remove _unknown_fields.
+        new_pos = local_SkipField(buffer, old_pos, end, tag_bytes)
+        if new_pos == -1:
+          return pos
+        self._unknown_fields.append(
+            (tag_bytes, buffer[old_pos:new_pos].tobytes()))
+        pos = new_pos
+      else:
+        pos = field_decoder(buffer, new_pos, end, self, field_dict)
+        if field_desc:
+          self._UpdateOneofState(field_desc)
+    return pos
+  cls._InternalParse = InternalParse
+
+
+def _AddIsInitializedMethod(message_descriptor, cls):
+  """Adds the IsInitialized and FindInitializationError methods to the
+  protocol message class."""
+
+  required_fields = [field for field in message_descriptor.fields
+                           if field.label == _FieldDescriptor.LABEL_REQUIRED]
+
+  def IsInitialized(self, errors=None):
+    """Checks if all required fields of a message are set.
+
+    Args:
+      errors:  A list which, if provided, will be populated with the field
+               paths of all missing required fields.
+
+    Returns:
+      True iff the specified message has all required fields set.
+    """
+
+    # Performance is critical so we avoid HasField() and ListFields().
+
+    for field in required_fields:
+      if (field not in self._fields or
+          (field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
+           not self._fields[field]._is_present_in_parent)):
+        if errors is not None:
+          errors.extend(self.FindInitializationErrors())
+        return False
+
+    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:
+                errors.extend(self.FindInitializationErrors())
+              return False
+        elif value._is_present_in_parent and not value.IsInitialized():
+          if errors is not None:
+            errors.extend(self.FindInitializationErrors())
+          return False
+
+    return True
+
+  cls.IsInitialized = IsInitialized
+
+  def FindInitializationErrors(self):
+    """Finds required fields which are not initialized.
+
+    Returns:
+      A list of strings.  Each string is a path to an uninitialized field from
+      the top-level message, e.g. "foo.bar[5].baz".
+    """
+
+    errors = []  # simplify things
+
+    for field in required_fields:
+      if not self.HasField(field.name):
+        errors.append(field.name)
+
+    for field, value in self.ListFields():
+      if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+        if field.is_extension:
+          name = '(%s)' % field.full_name
+        else:
+          name = field.name
+
+        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]
+        else:
+          prefix = name + '.'
+          sub_errors = value.FindInitializationErrors()
+          errors += [prefix + error for error in sub_errors]
+
+    return errors
+
+  cls.FindInitializationErrors = FindInitializationErrors
+
+
+def _FullyQualifiedClassName(klass):
+  module = klass.__module__
+  name = getattr(klass, '__qualname__', klass.__name__)
+  if module in (None, 'builtins', '__builtin__'):
+    return name
+  return module + '.' + name
+
+
+def _AddMergeFromMethod(cls):
+  LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED
+  CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE
+
+  def MergeFrom(self, msg):
+    if not isinstance(msg, cls):
+      raise TypeError(
+          'Parameter to MergeFrom() must be instance of same class: '
+          'expected %s got %s.' % (_FullyQualifiedClassName(cls),
+                                   _FullyQualifiedClassName(msg.__class__)))
+
+    assert msg is not self
+    self._Modified()
+
+    fields = self._fields
+
+    for field, value in msg._fields.items():
+      if field.label == LABEL_REPEATED:
+        field_value = fields.get(field)
+        if field_value is None:
+          # Construct a new object to represent this field.
+          field_value = field._default_constructor(self)
+          fields[field] = field_value
+        field_value.MergeFrom(value)
+      elif field.cpp_type == CPPTYPE_MESSAGE:
+        if value._is_present_in_parent:
+          field_value = fields.get(field)
+          if field_value is None:
+            # Construct a new object to represent this field.
+            field_value = field._default_constructor(self)
+            fields[field] = field_value
+          field_value.MergeFrom(value)
+      else:
+        self._fields[field] = value
+        if field.containing_oneof:
+          self._UpdateOneofState(field)
+
+    if msg._unknown_fields:
+      if not self._unknown_fields:
+        self._unknown_fields = []
+      self._unknown_fields.extend(msg._unknown_fields)
+      # pylint: disable=protected-access
+      if self._unknown_field_set is None:
+        self._unknown_field_set = containers.UnknownFieldSet()
+      self._unknown_field_set._extend(msg._unknown_field_set)
+
+  cls.MergeFrom = MergeFrom
+
+
+def _AddWhichOneofMethod(message_descriptor, cls):
+  def WhichOneof(self, oneof_name):
+    """Returns the name of the currently set field inside a oneof, or None."""
+    try:
+      field = message_descriptor.oneofs_by_name[oneof_name]
+    except KeyError:
+      raise ValueError(
+          'Protocol message has no oneof "%s" field.' % oneof_name)
+
+    nested_field = self._oneofs.get(field, None)
+    if nested_field is not None and self.HasField(nested_field.name):
+      return nested_field.name
+    else:
+      return None
+
+  cls.WhichOneof = WhichOneof
+
+
+def _Clear(self):
+  # Clear fields.
+  self._fields = {}
+  self._unknown_fields = ()
+  # pylint: disable=protected-access
+  if self._unknown_field_set is not None:
+    self._unknown_field_set._clear()
+    self._unknown_field_set = None
+
+  self._oneofs = {}
+  self._Modified()
+
+
+def _UnknownFields(self):
+  if self._unknown_field_set is None:  # pylint: disable=protected-access
+    # pylint: disable=protected-access
+    self._unknown_field_set = containers.UnknownFieldSet()
+  return self._unknown_field_set    # pylint: disable=protected-access
+
+
+def _DiscardUnknownFields(self):
+  self._unknown_fields = []
+  self._unknown_field_set = None      # pylint: disable=protected-access
+  for field, value in self.ListFields():
+    if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+      if _IsMapField(field):
+        if _IsMessageMapField(field):
+          for key in value:
+            value[key].DiscardUnknownFields()
+      elif field.label == _FieldDescriptor.LABEL_REPEATED:
+        for sub_message in value:
+          sub_message.DiscardUnknownFields()
+      else:
+        value.DiscardUnknownFields()
+
+
+def _SetListener(self, listener):
+  if listener is None:
+    self._listener = message_listener_mod.NullMessageListener()
+  else:
+    self._listener = listener
+
+
+def _AddMessageMethods(message_descriptor, cls):
+  """Adds implementations of all Message methods to cls."""
+  _AddListFieldsMethod(message_descriptor, cls)
+  _AddHasFieldMethod(message_descriptor, cls)
+  _AddClearFieldMethod(message_descriptor, cls)
+  if message_descriptor.is_extendable:
+    _AddClearExtensionMethod(cls)
+    _AddHasExtensionMethod(cls)
+  _AddEqualsMethod(message_descriptor, cls)
+  _AddStrMethod(message_descriptor, cls)
+  _AddReprMethod(message_descriptor, cls)
+  _AddUnicodeMethod(message_descriptor, cls)
+  _AddByteSizeMethod(message_descriptor, cls)
+  _AddSerializeToStringMethod(message_descriptor, cls)
+  _AddSerializePartialToStringMethod(message_descriptor, cls)
+  _AddMergeFromStringMethod(message_descriptor, cls)
+  _AddIsInitializedMethod(message_descriptor, cls)
+  _AddMergeFromMethod(cls)
+  _AddWhichOneofMethod(message_descriptor, cls)
+  # Adds methods which do not depend on cls.
+  cls.Clear = _Clear
+  cls.UnknownFields = _UnknownFields
+  cls.DiscardUnknownFields = _DiscardUnknownFields
+  cls._SetListener = _SetListener
+
+
+def _AddPrivateHelperMethods(message_descriptor, cls):
+  """Adds implementation of private helper methods to cls."""
+
+  def Modified(self):
+    """Sets the _cached_byte_size_dirty bit to true,
+    and propagates this to our listener iff this was a state change.
+    """
+
+    # Note:  Some callers check _cached_byte_size_dirty before calling
+    #   _Modified() as an extra optimization.  So, if this method is ever
+    #   changed such that it does stuff even when _cached_byte_size_dirty is
+    #   already true, the callers need to be updated.
+    if not self._cached_byte_size_dirty:
+      self._cached_byte_size_dirty = True
+      self._listener_for_children.dirty = True
+      self._is_present_in_parent = True
+      self._listener.Modified()
+
+  def _UpdateOneofState(self, field):
+    """Sets field as the active field in its containing oneof.
+
+    Will also delete currently active field in the oneof, if it is different
+    from the argument. Does not mark the message as modified.
+    """
+    other_field = self._oneofs.setdefault(field.containing_oneof, field)
+    if other_field is not field:
+      del self._fields[other_field]
+      self._oneofs[field.containing_oneof] = field
+
+  cls._Modified = Modified
+  cls.SetInParent = Modified
+  cls._UpdateOneofState = _UpdateOneofState
+
+
+class _Listener(object):
+
+  """MessageListener implementation that a parent message registers with its
+  child message.
+
+  In order to support semantics like:
+
+    foo.bar.baz.moo = 23
+    assert foo.HasField('bar')
+
+  ...child objects must have back references to their parents.
+  This helper class is at the heart of this support.
+  """
+
+  def __init__(self, parent_message):
+    """Args:
+      parent_message: The message whose _Modified() method we should call when
+        we receive Modified() messages.
+    """
+    # This listener establishes a back reference from a child (contained) object
+    # to its parent (containing) object.  We make this a weak reference to avoid
+    # creating cyclic garbage when the client finishes with the 'parent' object
+    # in the tree.
+    if isinstance(parent_message, weakref.ProxyType):
+      self._parent_message_weakref = parent_message
+    else:
+      self._parent_message_weakref = weakref.proxy(parent_message)
+
+    # As an optimization, we also indicate directly on the listener whether
+    # or not the parent message is dirty.  This way we can avoid traversing
+    # up the tree in the common case.
+    self.dirty = False
+
+  def Modified(self):
+    if self.dirty:
+      return
+    try:
+      # Propagate the signal to our parents iff this is the first field set.
+      self._parent_message_weakref._Modified()
+    except ReferenceError:
+      # We can get here if a client has kept a reference to a child object,
+      # and is now setting a field on it, but the child's parent has been
+      # garbage-collected.  This is not an error.
+      pass
+
+
+class _OneofListener(_Listener):
+  """Special listener implementation for setting composite oneof fields."""
+
+  def __init__(self, parent_message, field):
+    """Args:
+      parent_message: The message whose _Modified() method we should call when
+        we receive Modified() messages.
+      field: The descriptor of the field being set in the parent message.
+    """
+    super(_OneofListener, self).__init__(parent_message)
+    self._field = field
+
+  def Modified(self):
+    """Also updates the state of the containing oneof in the parent message."""
+    try:
+      self._parent_message_weakref._UpdateOneofState(self._field)
+      super(_OneofListener, self).Modified()
+    except ReferenceError:
+      pass
diff --git a/python/google/protobuf/internal/python_protobuf.cc b/python/google/protobuf/internal/python_protobuf.cc
new file mode 100644
index 0000000..26e3a8b
--- /dev/null
+++ b/python/google/protobuf/internal/python_protobuf.cc
@@ -0,0 +1,63 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: qrczak@google.com (Marcin Kowalczyk)
+
+#include <google/protobuf/python/python_protobuf.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+static const Message* GetCProtoInsidePyProtoStub(PyObject* msg) {
+  return nullptr;
+}
+static Message* MutableCProtoInsidePyProtoStub(PyObject* msg) {
+  return nullptr;
+}
+
+// This is initialized with a default, stub implementation.
+// If python-google.protobuf.cc is loaded, the function pointer is overridden
+// with a full implementation.
+const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg) =
+    GetCProtoInsidePyProtoStub;
+Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg) =
+    MutableCProtoInsidePyProtoStub;
+
+const Message* GetCProtoInsidePyProto(PyObject* msg) {
+  return GetCProtoInsidePyProtoPtr(msg);
+}
+Message* MutableCProtoInsidePyProto(PyObject* msg) {
+  return MutableCProtoInsidePyProtoPtr(msg);
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
new file mode 100644
index 0000000..62957d3
--- /dev/null
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -0,0 +1,3381 @@
+# -*- coding: utf-8 -*-
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unittest for reflection.py, which also indirectly tests the output of the
+pure-Python protocol compiler.
+"""
+
+import copy
+import gc
+import operator
+import struct
+import sys
+import warnings
+import unittest
+
+from google.protobuf import unittest_import_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 import descriptor_pb2
+from google.protobuf import descriptor
+from google.protobuf import message
+from google.protobuf import reflection
+from google.protobuf import text_format
+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 testing_refleaks
+from google.protobuf.internal import decoder
+from google.protobuf.internal import _parameterized
+
+
+warnings.simplefilter('error', DeprecationWarning)
+
+
+class _MiniDecoder(object):
+  """Decodes a stream of values from a string.
+
+  Once upon a time we actually had a class called decoder.Decoder.  Then we
+  got rid of it during a redesign that made decoding much, much faster overall.
+  But a couple tests in this file used it to check that the serialized form of
+  a message was correct.  So, this class implements just the methods that were
+  used by said tests, so that we don't have to rewrite the tests.
+  """
+
+  def __init__(self, bytes):
+    self._bytes = bytes
+    self._pos = 0
+
+  def ReadVarint(self):
+    result, self._pos = decoder._DecodeVarint(self._bytes, self._pos)
+    return result
+
+  ReadInt32 = ReadVarint
+  ReadInt64 = ReadVarint
+  ReadUInt32 = ReadVarint
+  ReadUInt64 = ReadVarint
+
+  def ReadSInt64(self):
+    return wire_format.ZigZagDecode(self.ReadVarint())
+
+  ReadSInt32 = ReadSInt64
+
+  def ReadFieldNumberAndWireType(self):
+    return wire_format.UnpackTag(self.ReadVarint())
+
+  def ReadFloat(self):
+    result = struct.unpack('<f', self._bytes[self._pos:self._pos+4])[0]
+    self._pos += 4
+    return result
+
+  def ReadDouble(self):
+    result = struct.unpack('<d', self._bytes[self._pos:self._pos+8])[0]
+    self._pos += 8
+    return result
+
+  def EndOfStream(self):
+    return self._pos == len(self._bytes)
+
+
+@_parameterized.named_parameters(
+    ('_proto2', unittest_pb2),
+    ('_proto3', unittest_proto3_arena_pb2))
+@testing_refleaks.TestCase
+class ReflectionTest(unittest.TestCase):
+
+  def assertListsEqual(self, values, others):
+    self.assertEqual(len(values), len(others))
+    for i in range(len(values)):
+      self.assertEqual(values[i], others[i])
+
+  def testScalarConstructor(self, message_module):
+    # Constructor with only scalar types should succeed.
+    proto = message_module.TestAllTypes(
+        optional_int32=24,
+        optional_double=54.321,
+        optional_string='optional_string',
+        optional_float=None)
+
+    self.assertEqual(24, proto.optional_int32)
+    self.assertEqual(54.321, proto.optional_double)
+    self.assertEqual('optional_string', proto.optional_string)
+    if message_module is unittest_pb2:
+      self.assertFalse(proto.HasField("optional_float"))
+
+  def testRepeatedScalarConstructor(self, message_module):
+    # Constructor with only repeated scalar types should succeed.
+    proto = message_module.TestAllTypes(
+        repeated_int32=[1, 2, 3, 4],
+        repeated_double=[1.23, 54.321],
+        repeated_bool=[True, False, False],
+        repeated_string=["optional_string"],
+        repeated_float=None)
+
+    self.assertEqual([1, 2, 3, 4], list(proto.repeated_int32))
+    self.assertEqual([1.23, 54.321], list(proto.repeated_double))
+    self.assertEqual([True, False, False], list(proto.repeated_bool))
+    self.assertEqual(["optional_string"], list(proto.repeated_string))
+    self.assertEqual([], list(proto.repeated_float))
+
+  def testMixedConstructor(self, message_module):
+    # Constructor with only mixed types should succeed.
+    proto = message_module.TestAllTypes(
+        optional_int32=24,
+        optional_string='optional_string',
+        repeated_double=[1.23, 54.321],
+        repeated_bool=[True, False, False],
+        repeated_nested_message=[
+            message_module.TestAllTypes.NestedMessage(
+                bb=message_module.TestAllTypes.FOO),
+            message_module.TestAllTypes.NestedMessage(
+                bb=message_module.TestAllTypes.BAR)],
+        repeated_foreign_message=[
+            message_module.ForeignMessage(c=-43),
+            message_module.ForeignMessage(c=45324),
+            message_module.ForeignMessage(c=12)],
+        optional_nested_message=None)
+
+    self.assertEqual(24, proto.optional_int32)
+    self.assertEqual('optional_string', proto.optional_string)
+    self.assertEqual([1.23, 54.321], list(proto.repeated_double))
+    self.assertEqual([True, False, False], list(proto.repeated_bool))
+    self.assertEqual(
+        [message_module.TestAllTypes.NestedMessage(
+            bb=message_module.TestAllTypes.FOO),
+         message_module.TestAllTypes.NestedMessage(
+             bb=message_module.TestAllTypes.BAR)],
+        list(proto.repeated_nested_message))
+    self.assertEqual(
+        [message_module.ForeignMessage(c=-43),
+         message_module.ForeignMessage(c=45324),
+         message_module.ForeignMessage(c=12)],
+        list(proto.repeated_foreign_message))
+    self.assertFalse(proto.HasField("optional_nested_message"))
+
+  def testConstructorTypeError(self, message_module):
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, optional_int32='foo')
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, optional_string=1234)
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, optional_nested_message=1234)
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, repeated_int32=1234)
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, repeated_int32=['foo'])
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, repeated_string=1234)
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, repeated_string=[1234])
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, repeated_nested_message=1234)
+    self.assertRaises(
+        TypeError, message_module.TestAllTypes, repeated_nested_message=[1234])
+
+  def testConstructorInvalidatesCachedByteSize(self, message_module):
+    message = message_module.TestAllTypes(optional_int32=12)
+    self.assertEqual(2, message.ByteSize())
+
+    message = message_module.TestAllTypes(
+        optional_nested_message=message_module.TestAllTypes.NestedMessage())
+    self.assertEqual(3, message.ByteSize())
+
+    message = message_module.TestAllTypes(repeated_int32=[12])
+    # TODO(jieluo): Add this test back for proto3
+    if message_module is unittest_pb2:
+      self.assertEqual(3, message.ByteSize())
+
+    message = message_module.TestAllTypes(
+        repeated_nested_message=[message_module.TestAllTypes.NestedMessage()])
+    self.assertEqual(3, message.ByteSize())
+
+  def testReferencesToNestedMessage(self, message_module):
+    proto = message_module.TestAllTypes()
+    nested = proto.optional_nested_message
+    del proto
+    # A previous version had a bug where this would raise an exception when
+    # hitting a now-dead weak reference.
+    nested.bb = 23
+
+  def testOneOf(self, message_module):
+    proto = message_module.TestAllTypes()
+    proto.oneof_uint32 = 10
+    proto.oneof_nested_message.bb = 11
+    self.assertEqual(11, proto.oneof_nested_message.bb)
+    self.assertFalse(proto.HasField('oneof_uint32'))
+    nested = proto.oneof_nested_message
+    proto.oneof_string = 'abc'
+    self.assertEqual('abc', proto.oneof_string)
+    self.assertEqual(11, nested.bb)
+    self.assertFalse(proto.HasField('oneof_nested_message'))
+
+  def testGetDefaultMessageAfterDisconnectingDefaultMessage(
+      self, message_module):
+    proto = message_module.TestAllTypes()
+    nested = proto.optional_nested_message
+    proto.ClearField('optional_nested_message')
+    del proto
+    del nested
+    # Force a garbage collect so that the underlying CMessages are freed along
+    # with the Messages they point to. This is to make sure we're not deleting
+    # default message instances.
+    gc.collect()
+    proto = message_module.TestAllTypes()
+    nested = proto.optional_nested_message
+
+  def testDisconnectingNestedMessageAfterSettingField(self, message_module):
+    proto = message_module.TestAllTypes()
+    nested = proto.optional_nested_message
+    nested.bb = 5
+    self.assertTrue(proto.HasField('optional_nested_message'))
+    proto.ClearField('optional_nested_message')  # Should disconnect from parent
+    self.assertEqual(5, nested.bb)
+    self.assertEqual(0, proto.optional_nested_message.bb)
+    self.assertIsNot(nested, proto.optional_nested_message)
+    nested.bb = 23
+    self.assertFalse(proto.HasField('optional_nested_message'))
+    self.assertEqual(0, proto.optional_nested_message.bb)
+
+  def testDisconnectingNestedMessageBeforeGettingField(self, message_module):
+    proto = message_module.TestAllTypes()
+    self.assertFalse(proto.HasField('optional_nested_message'))
+    proto.ClearField('optional_nested_message')
+    self.assertFalse(proto.HasField('optional_nested_message'))
+
+  def testDisconnectingNestedMessageAfterMerge(self, message_module):
+    # This test exercises the code path that does not use ReleaseMessage().
+    # The underlying fear is that if we use ReleaseMessage() incorrectly,
+    # we will have memory leaks.  It's hard to check that that doesn't happen,
+    # but at least we can exercise that code path to make sure it works.
+    proto1 = message_module.TestAllTypes()
+    proto2 = message_module.TestAllTypes()
+    proto2.optional_nested_message.bb = 5
+    proto1.MergeFrom(proto2)
+    self.assertTrue(proto1.HasField('optional_nested_message'))
+    proto1.ClearField('optional_nested_message')
+    self.assertFalse(proto1.HasField('optional_nested_message'))
+
+  def testDisconnectingLazyNestedMessage(self, message_module):
+    # This test exercises releasing a nested message that is lazy. This test
+    # only exercises real code in the C++ implementation as Python does not
+    # support lazy parsing, but the current C++ implementation results in
+    # memory corruption and a crash.
+    if api_implementation.Type() != 'python':
+      return
+    proto = message_module.TestAllTypes()
+    proto.optional_lazy_message.bb = 5
+    proto.ClearField('optional_lazy_message')
+    del proto
+    gc.collect()
+
+  def testSingularListFields(self, message_module):
+    proto = message_module.TestAllTypes()
+    proto.optional_fixed32 = 1
+    proto.optional_int32 = 5
+    proto.optional_string = 'foo'
+    # Access sub-message but don't set it yet.
+    nested_message = proto.optional_nested_message
+    self.assertEqual(
+      [ (proto.DESCRIPTOR.fields_by_name['optional_int32'  ], 5),
+        (proto.DESCRIPTOR.fields_by_name['optional_fixed32'], 1),
+        (proto.DESCRIPTOR.fields_by_name['optional_string' ], 'foo') ],
+      proto.ListFields())
+
+    proto.optional_nested_message.bb = 123
+    self.assertEqual(
+      [ (proto.DESCRIPTOR.fields_by_name['optional_int32'  ], 5),
+        (proto.DESCRIPTOR.fields_by_name['optional_fixed32'], 1),
+        (proto.DESCRIPTOR.fields_by_name['optional_string' ], 'foo'),
+        (proto.DESCRIPTOR.fields_by_name['optional_nested_message' ],
+             nested_message) ],
+      proto.ListFields())
+
+  def testRepeatedListFields(self, message_module):
+    proto = message_module.TestAllTypes()
+    proto.repeated_fixed32.append(1)
+    proto.repeated_int32.append(5)
+    proto.repeated_int32.append(11)
+    proto.repeated_string.extend(['foo', 'bar'])
+    proto.repeated_string.extend([])
+    proto.repeated_string.append('baz')
+    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(
+      [ (proto.DESCRIPTOR.fields_by_name['optional_int32'  ], 21),
+        (proto.DESCRIPTOR.fields_by_name['repeated_int32'  ], [5, 11]),
+        (proto.DESCRIPTOR.fields_by_name['repeated_fixed32'], [1]),
+        (proto.DESCRIPTOR.fields_by_name['repeated_string' ],
+          ['foo', 'bar', 'baz', '0', '1']) ],
+      proto.ListFields())
+
+  def testClearFieldWithUnknownFieldName(self, message_module):
+    proto = message_module.TestAllTypes()
+    self.assertRaises(ValueError, proto.ClearField, 'nonexistent_field')
+    self.assertRaises(ValueError, proto.ClearField, b'nonexistent_field')
+
+  def testDisallowedAssignments(self, message_module):
+    # It's illegal to assign values directly to repeated fields
+    # or to nonrepeated composite fields.  Ensure that this fails.
+    proto = message_module.TestAllTypes()
+    # Repeated fields.
+    self.assertRaises(AttributeError, setattr, proto, 'repeated_int32', 10)
+    # Lists shouldn't work, either.
+    self.assertRaises(AttributeError, setattr, proto, 'repeated_int32', [10])
+    # Composite fields.
+    self.assertRaises(AttributeError, setattr, proto,
+                      'optional_nested_message', 23)
+    # Assignment to a repeated nested message field without specifying
+    # the index in the array of nested messages.
+    self.assertRaises(AttributeError, setattr, proto.repeated_nested_message,
+                      'bb', 34)
+    # Assignment to an attribute of a repeated field.
+    self.assertRaises(AttributeError, setattr, proto.repeated_float,
+                      'some_attribute', 34)
+    # proto.nonexistent_field = 23 should fail as well.
+    self.assertRaises(AttributeError, setattr, proto, 'nonexistent_field', 23)
+
+  def testSingleScalarTypeSafety(self, message_module):
+    proto = message_module.TestAllTypes()
+    self.assertRaises(TypeError, setattr, proto, 'optional_int32', 1.1)
+    self.assertRaises(TypeError, setattr, proto, 'optional_int32', 'foo')
+    self.assertRaises(TypeError, setattr, proto, 'optional_string', 10)
+    self.assertRaises(TypeError, setattr, proto, 'optional_bytes', 10)
+    self.assertRaises(TypeError, setattr, proto, 'optional_bool', 'foo')
+    self.assertRaises(TypeError, setattr, proto, 'optional_float', 'foo')
+    self.assertRaises(TypeError, setattr, proto, 'optional_double', 'foo')
+    # TODO(jieluo): Fix type checking difference for python and c extension
+    if (api_implementation.Type() == 'python' or
+        (sys.version_info.major, sys.version_info.minor) >= (3, 10)):
+      self.assertRaises(TypeError, setattr, proto, 'optional_bool', 1.1)
+    else:
+      proto.optional_bool = 1.1
+
+  def assertIntegerTypes(self, integer_fn, message_module):
+    """Verifies setting of scalar integers.
+
+    Args:
+      integer_fn: A function to wrap the integers that will be assigned.
+      message_module: unittest_pb2 or unittest_proto3_arena_pb2
+    """
+    def TestGetAndDeserialize(field_name, value, expected_type):
+      proto = message_module.TestAllTypes()
+      value = integer_fn(value)
+      setattr(proto, field_name, value)
+      self.assertIsInstance(getattr(proto, field_name), expected_type)
+      proto2 = message_module.TestAllTypes()
+      proto2.ParseFromString(proto.SerializeToString())
+      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)
+    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.
+      TestGetAndDeserialize('optional_uint32', 1 << 31, integer_64)
+    else:
+      # 64-bit python can fit uint32 inside an int
+      TestGetAndDeserialize('optional_uint32', 1 << 31, int)
+    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 testIntegerTypes(self, message_module):
+    self.assertIntegerTypes(lambda x: x, message_module)
+
+  def testNonStandardIntegerTypes(self, message_module):
+    self.assertIntegerTypes(test_util.NonStandardInteger, message_module)
+
+  def testIllegalValuesForIntegers(self, message_module):
+    pb = message_module.TestAllTypes()
+
+    # Strings are illegal, even when the represent an integer.
+    with self.assertRaises(TypeError):
+      pb.optional_uint64 = '2'
+
+    # The exact error should propagate with a poorly written custom integer.
+    with self.assertRaisesRegex(RuntimeError, 'my_error'):
+      pb.optional_uint64 = test_util.NonStandardInteger(5, 'my_error')
+
+  def assetIntegerBoundsChecking(self, integer_fn, message_module):
+    """Verifies bounds checking for scalar integer fields.
+
+    Args:
+      integer_fn: A function to wrap the integers that will be assigned.
+      message_module: unittest_pb2 or unittest_proto3_arena_pb2
+    """
+    def TestMinAndMaxIntegers(field_name, expected_min, expected_max):
+      pb = message_module.TestAllTypes()
+      expected_min = integer_fn(expected_min)
+      expected_max = integer_fn(expected_max)
+      setattr(pb, field_name, expected_min)
+      self.assertEqual(expected_min, getattr(pb, field_name))
+      setattr(pb, field_name, expected_max)
+      self.assertEqual(expected_max, getattr(pb, field_name))
+      self.assertRaises((ValueError, TypeError), setattr, pb, field_name,
+                        expected_min - 1)
+      self.assertRaises((ValueError, TypeError), setattr, pb, field_name,
+                        expected_max + 1)
+
+    TestMinAndMaxIntegers('optional_int32', -(1 << 31), (1 << 31) - 1)
+    TestMinAndMaxIntegers('optional_uint32', 0, 0xffffffff)
+    TestMinAndMaxIntegers('optional_int64', -(1 << 63), (1 << 63) - 1)
+    TestMinAndMaxIntegers('optional_uint64', 0, 0xffffffffffffffff)
+    # A bit of white-box testing since -1 is an int and not a long in C++ and
+    # so goes down a different path.
+    pb = message_module.TestAllTypes()
+    with self.assertRaises((ValueError, TypeError)):
+      pb.optional_uint64 = integer_fn(-(1 << 63))
+
+    pb = message_module.TestAllTypes()
+    pb.optional_nested_enum = integer_fn(1)
+    self.assertEqual(1, pb.optional_nested_enum)
+
+  def testSingleScalarBoundsChecking(self, message_module):
+    self.assetIntegerBoundsChecking(lambda x: x, message_module)
+
+  def testNonStandardSingleScalarBoundsChecking(self, message_module):
+    self.assetIntegerBoundsChecking(
+        test_util.NonStandardInteger, message_module)
+
+  def testRepeatedScalarTypeSafety(self, message_module):
+    proto = message_module.TestAllTypes()
+    self.assertRaises(TypeError, proto.repeated_int32.append, 1.1)
+    self.assertRaises(TypeError, proto.repeated_int32.append, 'foo')
+    self.assertRaises(TypeError, proto.repeated_string, 10)
+    self.assertRaises(TypeError, proto.repeated_bytes, 10)
+
+    proto.repeated_int32.append(10)
+    proto.repeated_int32[0] = 23
+    self.assertRaises(IndexError, proto.repeated_int32.__setitem__, 500, 23)
+    self.assertRaises(TypeError, proto.repeated_int32.__setitem__, 0, 'abc')
+    self.assertRaises(TypeError, proto.repeated_int32.__setitem__, 0, [])
+    self.assertRaises(TypeError, proto.repeated_int32.__setitem__,
+                      'index', 23)
+
+    proto.repeated_string.append('2')
+    self.assertRaises(TypeError, proto.repeated_string.__setitem__, 0, 10)
+
+    # Repeated enums tests.
+    #proto.repeated_nested_enum.append(0)
+
+  def testSingleScalarGettersAndSetters(self, message_module):
+    proto = message_module.TestAllTypes()
+    self.assertEqual(0, proto.optional_int32)
+    proto.optional_int32 = 1
+    self.assertEqual(1, proto.optional_int32)
+
+    proto.optional_uint64 = 0xffffffffffff
+    self.assertEqual(0xffffffffffff, proto.optional_uint64)
+    proto.optional_uint64 = 0xffffffffffffffff
+    self.assertEqual(0xffffffffffffffff, proto.optional_uint64)
+    # TODO(robinson): Test all other scalar field types.
+
+  def testEnums(self, message_module):
+    proto = message_module.TestAllTypes()
+    self.assertEqual(1, proto.FOO)
+    self.assertEqual(1, message_module.TestAllTypes.FOO)
+    self.assertEqual(2, proto.BAR)
+    self.assertEqual(2, message_module.TestAllTypes.BAR)
+    self.assertEqual(3, proto.BAZ)
+    self.assertEqual(3, message_module.TestAllTypes.BAZ)
+
+  def testEnum_Name(self, message_module):
+    self.assertEqual(
+        'FOREIGN_FOO',
+        message_module.ForeignEnum.Name(message_module.FOREIGN_FOO))
+    self.assertEqual(
+        'FOREIGN_BAR',
+        message_module.ForeignEnum.Name(message_module.FOREIGN_BAR))
+    self.assertEqual(
+        'FOREIGN_BAZ',
+        message_module.ForeignEnum.Name(message_module.FOREIGN_BAZ))
+    self.assertRaises(ValueError,
+                      message_module.ForeignEnum.Name, 11312)
+
+    proto = message_module.TestAllTypes()
+    self.assertEqual('FOO',
+                     proto.NestedEnum.Name(proto.FOO))
+    self.assertEqual('FOO',
+                     message_module.TestAllTypes.NestedEnum.Name(proto.FOO))
+    self.assertEqual('BAR',
+                     proto.NestedEnum.Name(proto.BAR))
+    self.assertEqual('BAR',
+                     message_module.TestAllTypes.NestedEnum.Name(proto.BAR))
+    self.assertEqual('BAZ',
+                     proto.NestedEnum.Name(proto.BAZ))
+    self.assertEqual('BAZ',
+                     message_module.TestAllTypes.NestedEnum.Name(proto.BAZ))
+    self.assertRaises(ValueError,
+                      proto.NestedEnum.Name, 11312)
+    self.assertRaises(ValueError,
+                      message_module.TestAllTypes.NestedEnum.Name, 11312)
+
+    # Check some coercion cases.
+    self.assertRaises(TypeError, message_module.TestAllTypes.NestedEnum.Name,
+                      11312.0)
+    self.assertRaises(TypeError, message_module.TestAllTypes.NestedEnum.Name,
+                      None)
+    self.assertEqual('FOO', message_module.TestAllTypes.NestedEnum.Name(True))
+
+  def testEnum_Value(self, message_module):
+    self.assertEqual(message_module.FOREIGN_FOO,
+                     message_module.ForeignEnum.Value('FOREIGN_FOO'))
+    self.assertEqual(message_module.FOREIGN_FOO,
+                     message_module.ForeignEnum.FOREIGN_FOO)
+
+    self.assertEqual(message_module.FOREIGN_BAR,
+                     message_module.ForeignEnum.Value('FOREIGN_BAR'))
+    self.assertEqual(message_module.FOREIGN_BAR,
+                     message_module.ForeignEnum.FOREIGN_BAR)
+
+    self.assertEqual(message_module.FOREIGN_BAZ,
+                     message_module.ForeignEnum.Value('FOREIGN_BAZ'))
+    self.assertEqual(message_module.FOREIGN_BAZ,
+                     message_module.ForeignEnum.FOREIGN_BAZ)
+
+    self.assertRaises(ValueError,
+                      message_module.ForeignEnum.Value, 'FO')
+    with self.assertRaises(AttributeError):
+      message_module.ForeignEnum.FO
+
+    proto = message_module.TestAllTypes()
+    self.assertEqual(proto.FOO,
+                     proto.NestedEnum.Value('FOO'))
+    self.assertEqual(proto.FOO,
+                     proto.NestedEnum.FOO)
+
+    self.assertEqual(proto.FOO,
+                     message_module.TestAllTypes.NestedEnum.Value('FOO'))
+    self.assertEqual(proto.FOO,
+                     message_module.TestAllTypes.NestedEnum.FOO)
+
+    self.assertEqual(proto.BAR,
+                     proto.NestedEnum.Value('BAR'))
+    self.assertEqual(proto.BAR,
+                     proto.NestedEnum.BAR)
+
+    self.assertEqual(proto.BAR,
+                     message_module.TestAllTypes.NestedEnum.Value('BAR'))
+    self.assertEqual(proto.BAR,
+                     message_module.TestAllTypes.NestedEnum.BAR)
+
+    self.assertEqual(proto.BAZ,
+                     proto.NestedEnum.Value('BAZ'))
+    self.assertEqual(proto.BAZ,
+                     proto.NestedEnum.BAZ)
+
+    self.assertEqual(proto.BAZ,
+                     message_module.TestAllTypes.NestedEnum.Value('BAZ'))
+    self.assertEqual(proto.BAZ,
+                     message_module.TestAllTypes.NestedEnum.BAZ)
+
+    self.assertRaises(ValueError,
+                      proto.NestedEnum.Value, 'Foo')
+    with self.assertRaises(AttributeError):
+      proto.NestedEnum.Value.Foo
+
+    self.assertRaises(ValueError,
+                      message_module.TestAllTypes.NestedEnum.Value, 'Foo')
+    with self.assertRaises(AttributeError):
+      message_module.TestAllTypes.NestedEnum.Value.Foo
+
+  def testEnum_KeysAndValues(self, message_module):
+    if message_module == unittest_pb2:
+      keys = ['FOREIGN_FOO', 'FOREIGN_BAR', 'FOREIGN_BAZ']
+      values = [4, 5, 6]
+      items = [('FOREIGN_FOO', 4), ('FOREIGN_BAR', 5), ('FOREIGN_BAZ', 6)]
+    else:
+      keys = ['FOREIGN_ZERO', 'FOREIGN_FOO', 'FOREIGN_BAR', 'FOREIGN_BAZ']
+      values = [0, 4, 5, 6]
+      items = [('FOREIGN_ZERO', 0), ('FOREIGN_FOO', 4),
+               ('FOREIGN_BAR', 5), ('FOREIGN_BAZ', 6)]
+    self.assertEqual(keys,
+                     list(message_module.ForeignEnum.keys()))
+    self.assertEqual(values,
+                     list(message_module.ForeignEnum.values()))
+    self.assertEqual(items,
+                     list(message_module.ForeignEnum.items()))
+
+    proto = message_module.TestAllTypes()
+    if message_module == unittest_pb2:
+      keys = ['FOO', 'BAR', 'BAZ', 'NEG']
+      values = [1, 2, 3, -1]
+      items = [('FOO', 1), ('BAR', 2), ('BAZ', 3), ('NEG', -1)]
+    else:
+      keys = ['ZERO', 'FOO', 'BAR', 'BAZ', 'NEG']
+      values = [0, 1, 2, 3, -1]
+      items = [('ZERO', 0), ('FOO', 1), ('BAR', 2), ('BAZ', 3), ('NEG', -1)]
+    self.assertEqual(keys, list(proto.NestedEnum.keys()))
+    self.assertEqual(values, list(proto.NestedEnum.values()))
+    self.assertEqual(items,
+                     list(proto.NestedEnum.items()))
+
+  def testStaticParseFrom(self, message_module):
+    proto1 = message_module.TestAllTypes()
+    test_util.SetAllFields(proto1)
+
+    string1 = proto1.SerializeToString()
+    proto2 = message_module.TestAllTypes.FromString(string1)
+
+    # Messages should be equal.
+    self.assertEqual(proto2, proto1)
+
+  def testMergeFromSingularField(self, message_module):
+    # Test merge with just a singular field.
+    proto1 = message_module.TestAllTypes()
+    proto1.optional_int32 = 1
+
+    proto2 = message_module.TestAllTypes()
+    # This shouldn't get overwritten.
+    proto2.optional_string = 'value'
+
+    proto2.MergeFrom(proto1)
+    self.assertEqual(1, proto2.optional_int32)
+    self.assertEqual('value', proto2.optional_string)
+
+  def testMergeFromRepeatedField(self, message_module):
+    # Test merge with just a repeated field.
+    proto1 = message_module.TestAllTypes()
+    proto1.repeated_int32.append(1)
+    proto1.repeated_int32.append(2)
+
+    proto2 = message_module.TestAllTypes()
+    proto2.repeated_int32.append(0)
+    proto2.MergeFrom(proto1)
+
+    self.assertEqual(0, proto2.repeated_int32[0])
+    self.assertEqual(1, proto2.repeated_int32[1])
+    self.assertEqual(2, proto2.repeated_int32[2])
+
+  def testMergeFromRepeatedNestedMessage(self, message_module):
+    # Test merge with a repeated nested message.
+    proto1 = message_module.TestAllTypes()
+    m = proto1.repeated_nested_message.add()
+    m.bb = 123
+    m = proto1.repeated_nested_message.add()
+    m.bb = 321
+
+    proto2 = message_module.TestAllTypes()
+    m = proto2.repeated_nested_message.add()
+    m.bb = 999
+    proto2.MergeFrom(proto1)
+    self.assertEqual(999, proto2.repeated_nested_message[0].bb)
+    self.assertEqual(123, proto2.repeated_nested_message[1].bb)
+    self.assertEqual(321, proto2.repeated_nested_message[2].bb)
+
+    proto3 = message_module.TestAllTypes()
+    proto3.repeated_nested_message.MergeFrom(proto2.repeated_nested_message)
+    self.assertEqual(999, proto3.repeated_nested_message[0].bb)
+    self.assertEqual(123, proto3.repeated_nested_message[1].bb)
+    self.assertEqual(321, proto3.repeated_nested_message[2].bb)
+
+  def testMergeFromAllFields(self, message_module):
+    # With all fields set.
+    proto1 = message_module.TestAllTypes()
+    test_util.SetAllFields(proto1)
+    proto2 = message_module.TestAllTypes()
+    proto2.MergeFrom(proto1)
+
+    # Messages should be equal.
+    self.assertEqual(proto2, proto1)
+
+    # Serialized string should be equal too.
+    string1 = proto1.SerializeToString()
+    string2 = proto2.SerializeToString()
+    self.assertEqual(string1, string2)
+
+  def testMergeFromBug(self, message_module):
+    message1 = message_module.TestAllTypes()
+    message2 = message_module.TestAllTypes()
+
+    # Cause optional_nested_message to be instantiated within message1, even
+    # though it is not considered to be "present".
+    message1.optional_nested_message
+    self.assertFalse(message1.HasField('optional_nested_message'))
+
+    # Merge into message2.  This should not instantiate the field is message2.
+    message2.MergeFrom(message1)
+    self.assertFalse(message2.HasField('optional_nested_message'))
+
+  def testCopyFromSingularField(self, message_module):
+    # Test copy with just a singular field.
+    proto1 = message_module.TestAllTypes()
+    proto1.optional_int32 = 1
+    proto1.optional_string = 'important-text'
+
+    proto2 = message_module.TestAllTypes()
+    proto2.optional_string = 'value'
+
+    proto2.CopyFrom(proto1)
+    self.assertEqual(1, proto2.optional_int32)
+    self.assertEqual('important-text', proto2.optional_string)
+
+  def testCopyFromRepeatedField(self, message_module):
+    # Test copy with a repeated field.
+    proto1 = message_module.TestAllTypes()
+    proto1.repeated_int32.append(1)
+    proto1.repeated_int32.append(2)
+
+    proto2 = message_module.TestAllTypes()
+    proto2.repeated_int32.append(0)
+    proto2.CopyFrom(proto1)
+
+    self.assertEqual(1, proto2.repeated_int32[0])
+    self.assertEqual(2, proto2.repeated_int32[1])
+
+  def testCopyFromAllFields(self, message_module):
+    # With all fields set.
+    proto1 = message_module.TestAllTypes()
+    test_util.SetAllFields(proto1)
+    proto2 = message_module.TestAllTypes()
+    proto2.CopyFrom(proto1)
+
+    # Messages should be equal.
+    self.assertEqual(proto2, proto1)
+
+    # Serialized string should be equal too.
+    string1 = proto1.SerializeToString()
+    string2 = proto2.SerializeToString()
+    self.assertEqual(string1, string2)
+
+  def testCopyFromSelf(self, message_module):
+    proto1 = message_module.TestAllTypes()
+    proto1.repeated_int32.append(1)
+    proto1.optional_int32 = 2
+    proto1.optional_string = 'important-text'
+
+    proto1.CopyFrom(proto1)
+    self.assertEqual(1, proto1.repeated_int32[0])
+    self.assertEqual(2, proto1.optional_int32)
+    self.assertEqual('important-text', proto1.optional_string)
+
+  def testDeepCopy(self, message_module):
+    proto1 = message_module.TestAllTypes()
+    proto1.optional_int32 = 1
+    proto2 = copy.deepcopy(proto1)
+    self.assertEqual(1, proto2.optional_int32)
+
+    proto1.repeated_int32.append(2)
+    proto1.repeated_int32.append(3)
+    container = copy.deepcopy(proto1.repeated_int32)
+    self.assertEqual([2, 3], container)
+    container.remove(container[0])
+    self.assertEqual([3], container)
+
+    message1 = proto1.repeated_nested_message.add()
+    message1.bb = 1
+    messages = copy.deepcopy(proto1.repeated_nested_message)
+    self.assertEqual(proto1.repeated_nested_message, messages)
+    message1.bb = 2
+    self.assertNotEqual(proto1.repeated_nested_message, messages)
+    messages.remove(messages[0])
+    self.assertEqual(len(messages), 0)
+
+    # TODO(anuraag): Implement deepcopy for extension dict
+
+  def testDisconnectingBeforeClear(self, message_module):
+    proto = message_module.TestAllTypes()
+    nested = proto.optional_nested_message
+    proto.Clear()
+    self.assertIsNot(nested, proto.optional_nested_message)
+    nested.bb = 23
+    self.assertFalse(proto.HasField('optional_nested_message'))
+    self.assertEqual(0, proto.optional_nested_message.bb)
+
+    proto = message_module.TestAllTypes()
+    nested = proto.optional_nested_message
+    nested.bb = 5
+    foreign = proto.optional_foreign_message
+    foreign.c = 6
+    proto.Clear()
+    self.assertIsNot(nested, proto.optional_nested_message)
+    self.assertIsNot(foreign, proto.optional_foreign_message)
+    self.assertEqual(5, nested.bb)
+    self.assertEqual(6, foreign.c)
+    nested.bb = 15
+    foreign.c = 16
+    self.assertFalse(proto.HasField('optional_nested_message'))
+    self.assertEqual(0, proto.optional_nested_message.bb)
+    self.assertFalse(proto.HasField('optional_foreign_message'))
+    self.assertEqual(0, proto.optional_foreign_message.c)
+
+  def testStringUTF8Encoding(self, message_module):
+    proto = message_module.TestAllTypes()
+
+    # Assignment of a unicode object to a field of type 'bytes' is not allowed.
+    self.assertRaises(TypeError,
+                      setattr, proto, 'optional_bytes', u'unicode object')
+
+    # Check that the default value is of python's 'unicode' type.
+    self.assertEqual(type(proto.optional_string), str)
+
+    proto.optional_string = str('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, str('Testing'))
+
+    # Try to assign a 'bytes' object which contains non-UTF-8.
+    self.assertRaises(ValueError,
+                      setattr, proto, 'optional_string', b'a\x80a')
+    # No exception: Assign already encoded UTF-8 bytes to a string field.
+    utf8_bytes = u'Тест'.encode('utf-8')
+    proto.optional_string = utf8_bytes
+    # No exception: Assign the a non-ascii unicode object.
+    proto.optional_string = u'Тест'
+    # No exception thrown (normal str assignment containing ASCII).
+    proto.optional_string = 'abc'
+
+  def testBytesInTextFormat(self, message_module):
+    proto = message_module.TestAllTypes(optional_bytes=b'\x00\x7f\x80\xff')
+    self.assertEqual(u'optional_bytes: "\\000\\177\\200\\377"\n', str(proto))
+
+  def testEmptyNestedMessage(self, message_module):
+    proto = message_module.TestAllTypes()
+    proto.optional_nested_message.MergeFrom(
+        message_module.TestAllTypes.NestedMessage())
+    self.assertTrue(proto.HasField('optional_nested_message'))
+
+    proto = message_module.TestAllTypes()
+    proto.optional_nested_message.CopyFrom(
+        message_module.TestAllTypes.NestedMessage())
+    self.assertTrue(proto.HasField('optional_nested_message'))
+
+    proto = message_module.TestAllTypes()
+    bytes_read = proto.optional_nested_message.MergeFromString(b'')
+    self.assertEqual(0, bytes_read)
+    self.assertTrue(proto.HasField('optional_nested_message'))
+
+    proto = message_module.TestAllTypes()
+    proto.optional_nested_message.ParseFromString(b'')
+    self.assertTrue(proto.HasField('optional_nested_message'))
+
+    serialized = proto.SerializeToString()
+    proto2 = message_module.TestAllTypes()
+    self.assertEqual(
+        len(serialized),
+        proto2.MergeFromString(serialized))
+    self.assertTrue(proto2.HasField('optional_nested_message'))
+
+
+# Class to test proto2-only features (required, extensions, etc.)
+@testing_refleaks.TestCase
+class Proto2ReflectionTest(unittest.TestCase):
+
+  def testRepeatedCompositeConstructor(self):
+    # Constructor with only repeated composite types should succeed.
+    proto = unittest_pb2.TestAllTypes(
+        repeated_nested_message=[
+            unittest_pb2.TestAllTypes.NestedMessage(
+                bb=unittest_pb2.TestAllTypes.FOO),
+            unittest_pb2.TestAllTypes.NestedMessage(
+                bb=unittest_pb2.TestAllTypes.BAR)],
+        repeated_foreign_message=[
+            unittest_pb2.ForeignMessage(c=-43),
+            unittest_pb2.ForeignMessage(c=45324),
+            unittest_pb2.ForeignMessage(c=12)],
+        repeatedgroup=[
+            unittest_pb2.TestAllTypes.RepeatedGroup(),
+            unittest_pb2.TestAllTypes.RepeatedGroup(a=1),
+            unittest_pb2.TestAllTypes.RepeatedGroup(a=2)])
+
+    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.assertEqual(
+        [unittest_pb2.ForeignMessage(c=-43),
+         unittest_pb2.ForeignMessage(c=45324),
+         unittest_pb2.ForeignMessage(c=12)],
+        list(proto.repeated_foreign_message))
+    self.assertEqual(
+        [unittest_pb2.TestAllTypes.RepeatedGroup(),
+         unittest_pb2.TestAllTypes.RepeatedGroup(a=1),
+         unittest_pb2.TestAllTypes.RepeatedGroup(a=2)],
+        list(proto.repeatedgroup))
+
+  def assertListsEqual(self, values, others):
+    self.assertEqual(len(values), len(others))
+    for i in range(len(values)):
+      self.assertEqual(values[i], others[i])
+
+  def testSimpleHasBits(self):
+    # Test a scalar.
+    proto = unittest_pb2.TestAllTypes()
+    self.assertFalse(proto.HasField('optional_int32'))
+    self.assertEqual(0, proto.optional_int32)
+    # HasField() shouldn't be true if all we've done is
+    # read the default value.
+    self.assertFalse(proto.HasField('optional_int32'))
+    proto.optional_int32 = 1
+    # Setting a value however *should* set the "has" bit.
+    self.assertTrue(proto.HasField('optional_int32'))
+    proto.ClearField('optional_int32')
+    # And clearing that value should unset the "has" bit.
+    self.assertFalse(proto.HasField('optional_int32'))
+
+  def testHasBitsWithSinglyNestedScalar(self):
+    # Helper used to test foreign messages and groups.
+    #
+    # composite_field_name should be the name of a non-repeated
+    # composite (i.e., foreign or group) field in TestAllTypes,
+    # and scalar_field_name should be the name of an integer-valued
+    # scalar field within that composite.
+    #
+    # I never thought I'd miss C++ macros and templates so much. :(
+    # This helper is semantically just:
+    #
+    #   assert proto.composite_field.scalar_field == 0
+    #   assert not proto.composite_field.HasField('scalar_field')
+    #   assert not proto.HasField('composite_field')
+    #
+    #   proto.composite_field.scalar_field = 10
+    #   old_composite_field = proto.composite_field
+    #
+    #   assert proto.composite_field.scalar_field == 10
+    #   assert proto.composite_field.HasField('scalar_field')
+    #   assert proto.HasField('composite_field')
+    #
+    #   proto.ClearField('composite_field')
+    #
+    #   assert not proto.composite_field.HasField('scalar_field')
+    #   assert not proto.HasField('composite_field')
+    #   assert proto.composite_field.scalar_field == 0
+    #
+    #   # Now ensure that ClearField('composite_field') disconnected
+    #   # the old field object from the object tree...
+    #   assert old_composite_field is not proto.composite_field
+    #   old_composite_field.scalar_field = 20
+    #   assert not proto.composite_field.HasField('scalar_field')
+    #   assert not proto.HasField('composite_field')
+    def TestCompositeHasBits(composite_field_name, scalar_field_name):
+      proto = unittest_pb2.TestAllTypes()
+      # First, check that we can get the scalar value, and see that it's the
+      # default (0), but that proto.HasField('omposite') and
+      # proto.composite.HasField('scalar') will still return False.
+      composite_field = getattr(proto, composite_field_name)
+      original_scalar_value = getattr(composite_field, scalar_field_name)
+      self.assertEqual(0, original_scalar_value)
+      # Assert that the composite object does not "have" the scalar.
+      self.assertFalse(composite_field.HasField(scalar_field_name))
+      # Assert that proto does not "have" the composite field.
+      self.assertFalse(proto.HasField(composite_field_name))
+
+      # Now set the scalar within the composite field.  Ensure that the setting
+      # is reflected, and that proto.HasField('composite') and
+      # proto.composite.HasField('scalar') now both return True.
+      new_val = 20
+      setattr(composite_field, scalar_field_name, new_val)
+      self.assertEqual(new_val, getattr(composite_field, scalar_field_name))
+      # Hold on to a reference to the current composite_field object.
+      old_composite_field = composite_field
+      # Assert that the has methods now return true.
+      self.assertTrue(composite_field.HasField(scalar_field_name))
+      self.assertTrue(proto.HasField(composite_field_name))
+
+      # Now call the clear method...
+      proto.ClearField(composite_field_name)
+
+      # ...and ensure that the "has" bits are all back to False...
+      composite_field = getattr(proto, composite_field_name)
+      self.assertFalse(composite_field.HasField(scalar_field_name))
+      self.assertFalse(proto.HasField(composite_field_name))
+      # ...and ensure that the scalar field has returned to its default.
+      self.assertEqual(0, getattr(composite_field, scalar_field_name))
+
+      self.assertIsNot(old_composite_field, composite_field)
+      setattr(old_composite_field, scalar_field_name, new_val)
+      self.assertFalse(composite_field.HasField(scalar_field_name))
+      self.assertFalse(proto.HasField(composite_field_name))
+      self.assertEqual(0, getattr(composite_field, scalar_field_name))
+
+    # Test simple, single-level nesting when we set a scalar.
+    TestCompositeHasBits('optionalgroup', 'a')
+    TestCompositeHasBits('optional_nested_message', 'bb')
+    TestCompositeHasBits('optional_foreign_message', 'c')
+    TestCompositeHasBits('optional_import_message', 'd')
+
+  def testHasBitsWhenModifyingRepeatedFields(self):
+    # Test nesting when we add an element to a repeated field in a submessage.
+    proto = unittest_pb2.TestNestedMessageHasBits()
+    proto.optional_nested_message.nestedmessage_repeated_int32.append(5)
+    self.assertEqual(
+        [5], proto.optional_nested_message.nestedmessage_repeated_int32)
+    self.assertTrue(proto.HasField('optional_nested_message'))
+
+    # Do the same test, but with a repeated composite field within the
+    # submessage.
+    proto.ClearField('optional_nested_message')
+    self.assertFalse(proto.HasField('optional_nested_message'))
+    proto.optional_nested_message.nestedmessage_repeated_foreignmessage.add()
+    self.assertTrue(proto.HasField('optional_nested_message'))
+
+  def testHasBitsForManyLevelsOfNesting(self):
+    # Test nesting many levels deep.
+    recursive_proto = unittest_pb2.TestMutualRecursionA()
+    self.assertFalse(recursive_proto.HasField('bb'))
+    self.assertEqual(0, recursive_proto.bb.a.bb.a.bb.optional_int32)
+    self.assertFalse(recursive_proto.HasField('bb'))
+    recursive_proto.bb.a.bb.a.bb.optional_int32 = 5
+    self.assertEqual(5, recursive_proto.bb.a.bb.a.bb.optional_int32)
+    self.assertTrue(recursive_proto.HasField('bb'))
+    self.assertTrue(recursive_proto.bb.HasField('a'))
+    self.assertTrue(recursive_proto.bb.a.HasField('bb'))
+    self.assertTrue(recursive_proto.bb.a.bb.HasField('a'))
+    self.assertTrue(recursive_proto.bb.a.bb.a.HasField('bb'))
+    self.assertFalse(recursive_proto.bb.a.bb.a.bb.HasField('a'))
+    self.assertTrue(recursive_proto.bb.a.bb.a.bb.HasField('optional_int32'))
+
+  def testSingularListExtensions(self):
+    proto = unittest_pb2.TestAllExtensions()
+    proto.Extensions[unittest_pb2.optional_fixed32_extension] = 1
+    proto.Extensions[unittest_pb2.optional_int32_extension  ] = 5
+    proto.Extensions[unittest_pb2.optional_string_extension ] = 'foo'
+    self.assertEqual(
+      [ (unittest_pb2.optional_int32_extension  , 5),
+        (unittest_pb2.optional_fixed32_extension, 1),
+        (unittest_pb2.optional_string_extension , 'foo') ],
+      proto.ListFields())
+    del proto.Extensions[unittest_pb2.optional_fixed32_extension]
+    self.assertEqual(
+        [(unittest_pb2.optional_int32_extension, 5),
+         (unittest_pb2.optional_string_extension, 'foo')],
+        proto.ListFields())
+
+  def testRepeatedListExtensions(self):
+    proto = unittest_pb2.TestAllExtensions()
+    proto.Extensions[unittest_pb2.repeated_fixed32_extension].append(1)
+    proto.Extensions[unittest_pb2.repeated_int32_extension  ].append(5)
+    proto.Extensions[unittest_pb2.repeated_int32_extension  ].append(11)
+    proto.Extensions[unittest_pb2.repeated_string_extension ].append('foo')
+    proto.Extensions[unittest_pb2.repeated_string_extension ].append('bar')
+    proto.Extensions[unittest_pb2.repeated_string_extension ].append('baz')
+    proto.Extensions[unittest_pb2.optional_int32_extension  ] = 21
+    self.assertEqual(
+      [ (unittest_pb2.optional_int32_extension  , 21),
+        (unittest_pb2.repeated_int32_extension  , [5, 11]),
+        (unittest_pb2.repeated_fixed32_extension, [1]),
+        (unittest_pb2.repeated_string_extension , ['foo', 'bar', 'baz']) ],
+      proto.ListFields())
+    del proto.Extensions[unittest_pb2.repeated_int32_extension]
+    del proto.Extensions[unittest_pb2.repeated_string_extension]
+    self.assertEqual(
+        [(unittest_pb2.optional_int32_extension, 21),
+         (unittest_pb2.repeated_fixed32_extension, [1])],
+        proto.ListFields())
+
+  def testListFieldsAndExtensions(self):
+    proto = unittest_pb2.TestFieldOrderings()
+    test_util.SetAllFieldsAndExtensions(proto)
+    unittest_pb2.my_extension_int
+    self.assertEqual(
+      [ (proto.DESCRIPTOR.fields_by_name['my_int'   ], 1),
+        (unittest_pb2.my_extension_int               , 23),
+        (proto.DESCRIPTOR.fields_by_name['my_string'], 'foo'),
+        (unittest_pb2.my_extension_string            , 'bar'),
+        (proto.DESCRIPTOR.fields_by_name['my_float' ], 1.0) ],
+      proto.ListFields())
+
+  def testDefaultValues(self):
+    proto = unittest_pb2.TestAllTypes()
+    self.assertEqual(0, proto.optional_int32)
+    self.assertEqual(0, proto.optional_int64)
+    self.assertEqual(0, proto.optional_uint32)
+    self.assertEqual(0, proto.optional_uint64)
+    self.assertEqual(0, proto.optional_sint32)
+    self.assertEqual(0, proto.optional_sint64)
+    self.assertEqual(0, proto.optional_fixed32)
+    self.assertEqual(0, proto.optional_fixed64)
+    self.assertEqual(0, proto.optional_sfixed32)
+    self.assertEqual(0, proto.optional_sfixed64)
+    self.assertEqual(0.0, proto.optional_float)
+    self.assertEqual(0.0, proto.optional_double)
+    self.assertEqual(False, proto.optional_bool)
+    self.assertEqual('', proto.optional_string)
+    self.assertEqual(b'', proto.optional_bytes)
+
+    self.assertEqual(41, proto.default_int32)
+    self.assertEqual(42, proto.default_int64)
+    self.assertEqual(43, proto.default_uint32)
+    self.assertEqual(44, proto.default_uint64)
+    self.assertEqual(-45, proto.default_sint32)
+    self.assertEqual(46, proto.default_sint64)
+    self.assertEqual(47, proto.default_fixed32)
+    self.assertEqual(48, proto.default_fixed64)
+    self.assertEqual(49, proto.default_sfixed32)
+    self.assertEqual(-50, proto.default_sfixed64)
+    self.assertEqual(51.5, proto.default_float)
+    self.assertEqual(52e3, proto.default_double)
+    self.assertEqual(True, proto.default_bool)
+    self.assertEqual('hello', proto.default_string)
+    self.assertEqual(b'world', proto.default_bytes)
+    self.assertEqual(unittest_pb2.TestAllTypes.BAR, proto.default_nested_enum)
+    self.assertEqual(unittest_pb2.FOREIGN_BAR, proto.default_foreign_enum)
+    self.assertEqual(unittest_import_pb2.IMPORT_BAR,
+                     proto.default_import_enum)
+
+    proto = unittest_pb2.TestExtremeDefaultValues()
+    self.assertEqual(u'\u1234', proto.utf8_string)
+
+  def testHasFieldWithUnknownFieldName(self):
+    proto = unittest_pb2.TestAllTypes()
+    self.assertRaises(ValueError, proto.HasField, 'nonexistent_field')
+
+  def testClearRemovesChildren(self):
+    # Make sure there aren't any implementation bugs that are only partially
+    # clearing the message (which can happen in the more complex C++
+    # implementation which has parallel message lists).
+    proto = unittest_pb2.TestRequiredForeign()
+    for i in range(10):
+      proto.repeated_message.add()
+    proto2 = unittest_pb2.TestRequiredForeign()
+    proto.CopyFrom(proto2)
+    self.assertRaises(IndexError, lambda: proto.repeated_message[5])
+
+  def testSingleScalarClearField(self):
+    proto = unittest_pb2.TestAllTypes()
+    # Should be allowed to clear something that's not there (a no-op).
+    proto.ClearField('optional_int32')
+    proto.optional_int32 = 1
+    self.assertTrue(proto.HasField('optional_int32'))
+    proto.ClearField('optional_int32')
+    self.assertEqual(0, proto.optional_int32)
+    self.assertFalse(proto.HasField('optional_int32'))
+    # TODO(robinson): Test all other scalar field types.
+
+  def testRepeatedScalars(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(proto.repeated_int32)
+    self.assertEqual(0, len(proto.repeated_int32))
+    proto.repeated_int32.append(5)
+    proto.repeated_int32.append(10)
+    proto.repeated_int32.append(15)
+    self.assertTrue(proto.repeated_int32)
+    self.assertEqual(3, len(proto.repeated_int32))
+
+    self.assertEqual([5, 10, 15], proto.repeated_int32)
+
+    # Test single retrieval.
+    self.assertEqual(5, proto.repeated_int32[0])
+    self.assertEqual(15, proto.repeated_int32[-1])
+    # Test out-of-bounds indices.
+    self.assertRaises(IndexError, proto.repeated_int32.__getitem__, 1234)
+    self.assertRaises(IndexError, proto.repeated_int32.__getitem__, -1234)
+    # Test incorrect types passed to __getitem__.
+    self.assertRaises(TypeError, proto.repeated_int32.__getitem__, 'foo')
+    self.assertRaises(TypeError, proto.repeated_int32.__getitem__, None)
+
+    # Test single assignment.
+    proto.repeated_int32[1] = 20
+    self.assertEqual([5, 20, 15], proto.repeated_int32)
+
+    # Test insertion.
+    proto.repeated_int32.insert(1, 25)
+    self.assertEqual([5, 25, 20, 15], proto.repeated_int32)
+
+    # Test slice retrieval.
+    proto.repeated_int32.append(30)
+    self.assertEqual([25, 20, 15], proto.repeated_int32[1:4])
+    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 range(3))
+    self.assertEqual([5, 0, 1, 2, 30], proto.repeated_int32)
+
+    # Test slice assignment.
+    proto.repeated_int32[1:4] = [35, 40, 45]
+    self.assertEqual([5, 35, 40, 45, 30], proto.repeated_int32)
+
+    # Test that we can use the field as an iterator.
+    result = []
+    for i in proto.repeated_int32:
+      result.append(i)
+    self.assertEqual([5, 35, 40, 45, 30], result)
+
+    # Test single deletion.
+    del proto.repeated_int32[2]
+    self.assertEqual([5, 35, 45, 30], proto.repeated_int32)
+
+    # Test slice deletion.
+    del proto.repeated_int32[2:]
+    self.assertEqual([5, 35], proto.repeated_int32)
+
+    # Test extending.
+    proto.repeated_int32.extend([3, 13])
+    self.assertEqual([5, 35, 3, 13], proto.repeated_int32)
+
+    # Test clearing.
+    proto.ClearField('repeated_int32')
+    self.assertFalse(proto.repeated_int32)
+    self.assertEqual(0, len(proto.repeated_int32))
+
+    proto.repeated_int32.append(1)
+    self.assertEqual(1, proto.repeated_int32[-1])
+    # Test assignment to a negative index.
+    proto.repeated_int32[-1] = 2
+    self.assertEqual(2, proto.repeated_int32[-1])
+
+    # Test deletion at negative indices.
+    proto.repeated_int32[:] = [0, 1, 2, 3]
+    del proto.repeated_int32[-1]
+    self.assertEqual([0, 1, 2], proto.repeated_int32)
+
+    del proto.repeated_int32[-2]
+    self.assertEqual([0, 2], proto.repeated_int32)
+
+    self.assertRaises(IndexError, proto.repeated_int32.__delitem__, -3)
+    self.assertRaises(IndexError, proto.repeated_int32.__delitem__, 300)
+
+    del proto.repeated_int32[-2:-1]
+    self.assertEqual([2], proto.repeated_int32)
+
+    del proto.repeated_int32[100:10000]
+    self.assertEqual([2], proto.repeated_int32)
+
+  def testRepeatedScalarsRemove(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(proto.repeated_int32)
+    self.assertEqual(0, len(proto.repeated_int32))
+    proto.repeated_int32.append(5)
+    proto.repeated_int32.append(10)
+    proto.repeated_int32.append(5)
+    proto.repeated_int32.append(5)
+
+    self.assertEqual(4, len(proto.repeated_int32))
+    proto.repeated_int32.remove(5)
+    self.assertEqual(3, len(proto.repeated_int32))
+    self.assertEqual(10, proto.repeated_int32[0])
+    self.assertEqual(5, proto.repeated_int32[1])
+    self.assertEqual(5, proto.repeated_int32[2])
+
+    proto.repeated_int32.remove(5)
+    self.assertEqual(2, len(proto.repeated_int32))
+    self.assertEqual(10, proto.repeated_int32[0])
+    self.assertEqual(5, proto.repeated_int32[1])
+
+    proto.repeated_int32.remove(10)
+    self.assertEqual(1, len(proto.repeated_int32))
+    self.assertEqual(5, proto.repeated_int32[0])
+
+    # Remove a non-existent element.
+    self.assertRaises(ValueError, proto.repeated_int32.remove, 123)
+
+  def testRepeatedScalarsReverse_Empty(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(proto.repeated_int32)
+    self.assertEqual(0, len(proto.repeated_int32))
+
+    self.assertIsNone(proto.repeated_int32.reverse())
+
+    self.assertFalse(proto.repeated_int32)
+    self.assertEqual(0, len(proto.repeated_int32))
+
+  def testRepeatedScalarsReverse_NonEmpty(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(proto.repeated_int32)
+    self.assertEqual(0, len(proto.repeated_int32))
+
+    proto.repeated_int32.append(1)
+    proto.repeated_int32.append(2)
+    proto.repeated_int32.append(3)
+    proto.repeated_int32.append(4)
+
+    self.assertEqual(4, len(proto.repeated_int32))
+
+    self.assertIsNone(proto.repeated_int32.reverse())
+
+    self.assertEqual(4, len(proto.repeated_int32))
+    self.assertEqual(4, proto.repeated_int32[0])
+    self.assertEqual(3, proto.repeated_int32[1])
+    self.assertEqual(2, proto.repeated_int32[2])
+    self.assertEqual(1, proto.repeated_int32[3])
+
+  def testRepeatedComposites(self):
+    proto = unittest_pb2.TestAllTypes()
+    self.assertFalse(proto.repeated_nested_message)
+    self.assertEqual(0, len(proto.repeated_nested_message))
+    m0 = proto.repeated_nested_message.add()
+    m1 = proto.repeated_nested_message.add()
+    self.assertTrue(proto.repeated_nested_message)
+    self.assertEqual(2, len(proto.repeated_nested_message))
+    self.assertListsEqual([m0, m1], proto.repeated_nested_message)
+    self.assertIsInstance(m0, unittest_pb2.TestAllTypes.NestedMessage)
+
+    # Test out-of-bounds indices.
+    self.assertRaises(IndexError, proto.repeated_nested_message.__getitem__,
+                      1234)
+    self.assertRaises(IndexError, proto.repeated_nested_message.__getitem__,
+                      -1234)
+
+    # Test incorrect types passed to __getitem__.
+    self.assertRaises(TypeError, proto.repeated_nested_message.__getitem__,
+                      'foo')
+    self.assertRaises(TypeError, proto.repeated_nested_message.__getitem__,
+                      None)
+
+    # Test slice retrieval.
+    m2 = proto.repeated_nested_message.add()
+    m3 = proto.repeated_nested_message.add()
+    m4 = proto.repeated_nested_message.add()
+    self.assertListsEqual(
+        [m1, m2, m3], proto.repeated_nested_message[1:4])
+    self.assertListsEqual(
+        [m0, m1, m2, m3, m4], proto.repeated_nested_message[:])
+    self.assertListsEqual(
+        [m0, m1], proto.repeated_nested_message[:2])
+    self.assertListsEqual(
+        [m2, m3, m4], proto.repeated_nested_message[2:])
+    self.assertEqual(
+        m0, proto.repeated_nested_message[0])
+    self.assertListsEqual(
+        [m0], proto.repeated_nested_message[:1])
+
+    # Test that we can use the field as an iterator.
+    result = []
+    for i in proto.repeated_nested_message:
+      result.append(i)
+    self.assertListsEqual([m0, m1, m2, m3, m4], result)
+
+    # Test single deletion.
+    del proto.repeated_nested_message[2]
+    self.assertListsEqual([m0, m1, m3, m4], proto.repeated_nested_message)
+
+    # Test slice deletion.
+    del proto.repeated_nested_message[2:]
+    self.assertListsEqual([m0, m1], proto.repeated_nested_message)
+
+    # Test extending.
+    n1 = unittest_pb2.TestAllTypes.NestedMessage(bb=1)
+    n2 = unittest_pb2.TestAllTypes.NestedMessage(bb=2)
+    proto.repeated_nested_message.extend([n1,n2])
+    self.assertEqual(4, len(proto.repeated_nested_message))
+    self.assertEqual(n1, proto.repeated_nested_message[2])
+    self.assertEqual(n2, proto.repeated_nested_message[3])
+    self.assertRaises(TypeError,
+                      proto.repeated_nested_message.extend, n1)
+    self.assertRaises(TypeError,
+                      proto.repeated_nested_message.extend, [0])
+    wrong_message_type = unittest_pb2.TestAllTypes()
+    self.assertRaises(TypeError,
+                      proto.repeated_nested_message.extend,
+                      [wrong_message_type])
+
+    # Test clearing.
+    proto.ClearField('repeated_nested_message')
+    self.assertFalse(proto.repeated_nested_message)
+    self.assertEqual(0, len(proto.repeated_nested_message))
+
+    # Test constructing an element while adding it.
+    proto.repeated_nested_message.add(bb=23)
+    self.assertEqual(1, len(proto.repeated_nested_message))
+    self.assertEqual(23, proto.repeated_nested_message[0].bb)
+    self.assertRaises(TypeError, proto.repeated_nested_message.add, 23)
+    with self.assertRaises(Exception):
+      proto.repeated_nested_message[0] = 23
+
+  def testRepeatedCompositeRemove(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertEqual(0, len(proto.repeated_nested_message))
+    m0 = proto.repeated_nested_message.add()
+    # Need to set some differentiating variable so m0 != m1 != m2:
+    m0.bb = len(proto.repeated_nested_message)
+    m1 = proto.repeated_nested_message.add()
+    m1.bb = len(proto.repeated_nested_message)
+    self.assertTrue(m0 != m1)
+    m2 = proto.repeated_nested_message.add()
+    m2.bb = len(proto.repeated_nested_message)
+    self.assertListsEqual([m0, m1, m2], proto.repeated_nested_message)
+
+    self.assertEqual(3, len(proto.repeated_nested_message))
+    proto.repeated_nested_message.remove(m0)
+    self.assertEqual(2, len(proto.repeated_nested_message))
+    self.assertEqual(m1, proto.repeated_nested_message[0])
+    self.assertEqual(m2, proto.repeated_nested_message[1])
+
+    # Removing m0 again or removing None should raise error
+    self.assertRaises(ValueError, proto.repeated_nested_message.remove, m0)
+    self.assertRaises(ValueError, proto.repeated_nested_message.remove, None)
+    self.assertEqual(2, len(proto.repeated_nested_message))
+
+    proto.repeated_nested_message.remove(m2)
+    self.assertEqual(1, len(proto.repeated_nested_message))
+    self.assertEqual(m1, proto.repeated_nested_message[0])
+
+  def testRepeatedCompositeReverse_Empty(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(proto.repeated_nested_message)
+    self.assertEqual(0, len(proto.repeated_nested_message))
+
+    self.assertIsNone(proto.repeated_nested_message.reverse())
+
+    self.assertFalse(proto.repeated_nested_message)
+    self.assertEqual(0, len(proto.repeated_nested_message))
+
+  def testRepeatedCompositeReverse_NonEmpty(self):
+    proto = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(proto.repeated_nested_message)
+    self.assertEqual(0, len(proto.repeated_nested_message))
+
+    m0 = proto.repeated_nested_message.add()
+    m0.bb = len(proto.repeated_nested_message)
+    m1 = proto.repeated_nested_message.add()
+    m1.bb = len(proto.repeated_nested_message)
+    m2 = proto.repeated_nested_message.add()
+    m2.bb = len(proto.repeated_nested_message)
+    self.assertListsEqual([m0, m1, m2], proto.repeated_nested_message)
+
+    self.assertIsNone(proto.repeated_nested_message.reverse())
+
+    self.assertListsEqual([m2, m1, m0], proto.repeated_nested_message)
+
+  def testHandWrittenReflection(self):
+    # Hand written extensions are only supported by the pure-Python
+    # implementation of the API.
+    if api_implementation.Type() != 'python':
+      return
+
+    FieldDescriptor = descriptor.FieldDescriptor
+    foo_field_descriptor = FieldDescriptor(
+        name='foo_field', full_name='MyProto.foo_field',
+        index=0, number=1, type=FieldDescriptor.TYPE_INT64,
+        cpp_type=FieldDescriptor.CPPTYPE_INT64,
+        label=FieldDescriptor.LABEL_OPTIONAL, default_value=0,
+        containing_type=None, message_type=None, enum_type=None,
+        is_extension=False, extension_scope=None,
+        options=descriptor_pb2.FieldOptions(),
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    mydescriptor = descriptor.Descriptor(
+        name='MyProto', full_name='MyProto', filename='ignored',
+        containing_type=None, nested_types=[], enum_types=[],
+        fields=[foo_field_descriptor], extensions=[],
+        options=descriptor_pb2.MessageOptions(),
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+
+    class MyProtoClass(
+        message.Message, metaclass=reflection.GeneratedProtocolMessageType):
+      DESCRIPTOR = mydescriptor
+    myproto_instance = MyProtoClass()
+    self.assertEqual(0, myproto_instance.foo_field)
+    self.assertFalse(myproto_instance.HasField('foo_field'))
+    myproto_instance.foo_field = 23
+    self.assertEqual(23, myproto_instance.foo_field)
+    self.assertTrue(myproto_instance.HasField('foo_field'))
+
+  @testing_refleaks.SkipReferenceLeakChecker('MakeDescriptor is not repeatable')
+  def testDescriptorProtoSupport(self):
+    # Hand written descriptors/reflection are only supported by the pure-Python
+    # implementation of the API.
+    if api_implementation.Type() != 'python':
+      return
+
+    def AddDescriptorField(proto, field_name, field_type):
+      AddDescriptorField.field_index += 1
+      new_field = proto.field.add()
+      new_field.name = field_name
+      new_field.type = field_type
+      new_field.number = AddDescriptorField.field_index
+      new_field.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
+
+    AddDescriptorField.field_index = 0
+
+    desc_proto = descriptor_pb2.DescriptorProto()
+    desc_proto.name = 'Car'
+    fdp = descriptor_pb2.FieldDescriptorProto
+    AddDescriptorField(desc_proto, 'name', fdp.TYPE_STRING)
+    AddDescriptorField(desc_proto, 'year', fdp.TYPE_INT64)
+    AddDescriptorField(desc_proto, 'automatic', fdp.TYPE_BOOL)
+    AddDescriptorField(desc_proto, 'price', fdp.TYPE_DOUBLE)
+    # Add a repeated field
+    AddDescriptorField.field_index += 1
+    new_field = desc_proto.field.add()
+    new_field.name = 'owners'
+    new_field.type = fdp.TYPE_STRING
+    new_field.number = AddDescriptorField.field_index
+    new_field.label = descriptor_pb2.FieldDescriptorProto.LABEL_REPEATED
+
+    desc = descriptor.MakeDescriptor(desc_proto)
+    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):
+      DESCRIPTOR = desc
+
+    prius = CarMessage()
+    prius.name = 'prius'
+    prius.year = 2010
+    prius.automatic = True
+    prius.price = 25134.75
+    prius.owners.extend(['bob', 'susan'])
+
+    serialized_prius = prius.SerializeToString()
+    new_prius = reflection.ParseMessage(desc, serialized_prius)
+    self.assertIsNot(new_prius, prius)
+    self.assertEqual(prius, new_prius)
+
+    # these are unnecessary assuming message equality works as advertised but
+    # explicitly check to be safe since we're mucking about in metaclass foo
+    self.assertEqual(prius.name, new_prius.name)
+    self.assertEqual(prius.year, new_prius.year)
+    self.assertEqual(prius.automatic, new_prius.automatic)
+    self.assertEqual(prius.price, new_prius.price)
+    self.assertEqual(prius.owners, new_prius.owners)
+
+  def testExtensionDelete(self):
+    extendee_proto = more_extensions_pb2.ExtendedMessage()
+
+    extension_int32 = more_extensions_pb2.optional_int_extension
+    extendee_proto.Extensions[extension_int32] = 23
+
+    extension_repeated = more_extensions_pb2.repeated_int_extension
+    extendee_proto.Extensions[extension_repeated].append(11)
+
+    extension_msg = more_extensions_pb2.optional_message_extension
+    extendee_proto.Extensions[extension_msg].foreign_message_int = 56
+
+    self.assertEqual(len(extendee_proto.Extensions), 3)
+    del extendee_proto.Extensions[extension_msg]
+    self.assertEqual(len(extendee_proto.Extensions), 2)
+    del extendee_proto.Extensions[extension_repeated]
+    self.assertEqual(len(extendee_proto.Extensions), 1)
+    # Delete a none exist extension. It is OK to "del m.Extensions[ext]"
+    # even if the extension is not present in the message; we don't
+    # raise KeyError. This is consistent with "m.Extensions[ext]"
+    # returning a default value even if we did not set anything.
+    del extendee_proto.Extensions[extension_repeated]
+    self.assertEqual(len(extendee_proto.Extensions), 1)
+    del extendee_proto.Extensions[extension_int32]
+    self.assertEqual(len(extendee_proto.Extensions), 0)
+
+  def testExtensionIter(self):
+    extendee_proto = more_extensions_pb2.ExtendedMessage()
+
+    extension_int32 = more_extensions_pb2.optional_int_extension
+    extendee_proto.Extensions[extension_int32] = 23
+
+    extension_repeated = more_extensions_pb2.repeated_int_extension
+    extendee_proto.Extensions[extension_repeated].append(11)
+
+    extension_msg = more_extensions_pb2.optional_message_extension
+    extendee_proto.Extensions[extension_msg].foreign_message_int = 56
+
+    # Set some normal fields.
+    extendee_proto.optional_int32 = 1
+    extendee_proto.repeated_string.append('hi')
+
+    expected = (extension_int32, extension_msg, extension_repeated)
+    count = 0
+    for item in extendee_proto.Extensions:
+      self.assertEqual(item.name, expected[count].name)
+      self.assertIn(item, extendee_proto.Extensions)
+      count += 1
+    self.assertEqual(count, 3)
+
+  def testExtensionContainsError(self):
+    extendee_proto = more_extensions_pb2.ExtendedMessage()
+    self.assertRaises(KeyError, extendee_proto.Extensions.__contains__, 0)
+
+    field = more_extensions_pb2.ExtendedMessage.DESCRIPTOR.fields_by_name[
+        'optional_int32']
+    self.assertRaises(KeyError, extendee_proto.Extensions.__contains__, field)
+
+  def testTopLevelExtensionsForOptionalScalar(self):
+    extendee_proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.optional_int32_extension
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    self.assertEqual(0, extendee_proto.Extensions[extension])
+    # As with normal scalar fields, just doing a read doesn't actually set the
+    # "has" bit.
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    # Actually set the thing.
+    extendee_proto.Extensions[extension] = 23
+    self.assertEqual(23, extendee_proto.Extensions[extension])
+    self.assertTrue(extendee_proto.HasExtension(extension))
+    self.assertIn(extension, extendee_proto.Extensions)
+    # Ensure that clearing works as well.
+    extendee_proto.ClearExtension(extension)
+    self.assertEqual(0, extendee_proto.Extensions[extension])
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+
+  def testTopLevelExtensionsForRepeatedScalar(self):
+    extendee_proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.repeated_string_extension
+    self.assertEqual(0, len(extendee_proto.Extensions[extension]))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    extendee_proto.Extensions[extension].append('foo')
+    self.assertEqual(['foo'], extendee_proto.Extensions[extension])
+    self.assertIn(extension, extendee_proto.Extensions)
+    string_list = extendee_proto.Extensions[extension]
+    extendee_proto.ClearExtension(extension)
+    self.assertEqual(0, len(extendee_proto.Extensions[extension]))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    self.assertIsNot(string_list, extendee_proto.Extensions[extension])
+    # Shouldn't be allowed to do Extensions[extension] = 'a'
+    self.assertRaises(TypeError, operator.setitem, extendee_proto.Extensions,
+                      extension, 'a')
+
+  def testTopLevelExtensionsForOptionalMessage(self):
+    extendee_proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.optional_foreign_message_extension
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    self.assertEqual(0, extendee_proto.Extensions[extension].c)
+    # As with normal (non-extension) fields, merely reading from the
+    # thing shouldn't set the "has" bit.
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    extendee_proto.Extensions[extension].c = 23
+    self.assertEqual(23, extendee_proto.Extensions[extension].c)
+    self.assertTrue(extendee_proto.HasExtension(extension))
+    self.assertIn(extension, extendee_proto.Extensions)
+    # Save a reference here.
+    foreign_message = extendee_proto.Extensions[extension]
+    extendee_proto.ClearExtension(extension)
+    self.assertIsNot(foreign_message, extendee_proto.Extensions[extension])
+    # Setting a field on foreign_message now shouldn't set
+    # any "has" bits on extendee_proto.
+    foreign_message.c = 42
+    self.assertEqual(42, foreign_message.c)
+    self.assertTrue(foreign_message.HasField('c'))
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    # Shouldn't be allowed to do Extensions[extension] = 'a'
+    self.assertRaises(TypeError, operator.setitem, extendee_proto.Extensions,
+                      extension, 'a')
+
+  def testTopLevelExtensionsForRepeatedMessage(self):
+    extendee_proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.repeatedgroup_extension
+    self.assertEqual(0, len(extendee_proto.Extensions[extension]))
+    group = extendee_proto.Extensions[extension].add()
+    group.a = 23
+    self.assertEqual(23, extendee_proto.Extensions[extension][0].a)
+    group.a = 42
+    self.assertEqual(42, extendee_proto.Extensions[extension][0].a)
+    group_list = extendee_proto.Extensions[extension]
+    extendee_proto.ClearExtension(extension)
+    self.assertEqual(0, len(extendee_proto.Extensions[extension]))
+    self.assertIsNot(group_list, extendee_proto.Extensions[extension])
+    # Shouldn't be allowed to do Extensions[extension] = 'a'
+    self.assertRaises(TypeError, operator.setitem, extendee_proto.Extensions,
+                      extension, 'a')
+
+  def testNestedExtensions(self):
+    extendee_proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.TestRequired.single
+
+    # We just test the non-repeated case.
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    required = extendee_proto.Extensions[extension]
+    self.assertEqual(0, required.a)
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+    required.a = 23
+    self.assertEqual(23, extendee_proto.Extensions[extension].a)
+    self.assertTrue(extendee_proto.HasExtension(extension))
+    self.assertIn(extension, extendee_proto.Extensions)
+    extendee_proto.ClearExtension(extension)
+    self.assertIsNot(required, extendee_proto.Extensions[extension])
+    self.assertFalse(extendee_proto.HasExtension(extension))
+    self.assertNotIn(extension, extendee_proto.Extensions)
+
+  def testRegisteredExtensions(self):
+    pool = unittest_pb2.DESCRIPTOR.pool
+    self.assertTrue(
+        pool.FindExtensionByNumber(
+            unittest_pb2.TestAllExtensions.DESCRIPTOR, 1))
+    self.assertIs(
+        pool.FindExtensionByName(
+            'protobuf_unittest.optional_int32_extension').containing_type,
+        unittest_pb2.TestAllExtensions.DESCRIPTOR)
+    # Make sure extensions haven't been registered into types that shouldn't
+    # have any.
+    self.assertEqual(0, len(
+        pool.FindAllExtensions(unittest_pb2.TestAllTypes.DESCRIPTOR)))
+
+  # If message A directly contains message B, and
+  # a.HasField('b') is currently False, then mutating any
+  # extension in B should change a.HasField('b') to True
+  # (and so on up the object tree).
+  def testHasBitsForAncestorsOfExtendedMessage(self):
+    # Optional scalar extension.
+    toplevel = more_extensions_pb2.TopLevelMessage()
+    self.assertFalse(toplevel.HasField('submessage'))
+    self.assertEqual(0, toplevel.submessage.Extensions[
+        more_extensions_pb2.optional_int_extension])
+    self.assertFalse(toplevel.HasField('submessage'))
+    toplevel.submessage.Extensions[
+        more_extensions_pb2.optional_int_extension] = 23
+    self.assertEqual(23, toplevel.submessage.Extensions[
+        more_extensions_pb2.optional_int_extension])
+    self.assertTrue(toplevel.HasField('submessage'))
+
+    # Repeated scalar extension.
+    toplevel = more_extensions_pb2.TopLevelMessage()
+    self.assertFalse(toplevel.HasField('submessage'))
+    self.assertEqual([], toplevel.submessage.Extensions[
+        more_extensions_pb2.repeated_int_extension])
+    self.assertFalse(toplevel.HasField('submessage'))
+    toplevel.submessage.Extensions[
+        more_extensions_pb2.repeated_int_extension].append(23)
+    self.assertEqual([23], toplevel.submessage.Extensions[
+        more_extensions_pb2.repeated_int_extension])
+    self.assertTrue(toplevel.HasField('submessage'))
+
+    # Optional message extension.
+    toplevel = more_extensions_pb2.TopLevelMessage()
+    self.assertFalse(toplevel.HasField('submessage'))
+    self.assertEqual(0, toplevel.submessage.Extensions[
+        more_extensions_pb2.optional_message_extension].foreign_message_int)
+    self.assertFalse(toplevel.HasField('submessage'))
+    toplevel.submessage.Extensions[
+        more_extensions_pb2.optional_message_extension].foreign_message_int = 23
+    self.assertEqual(23, toplevel.submessage.Extensions[
+        more_extensions_pb2.optional_message_extension].foreign_message_int)
+    self.assertTrue(toplevel.HasField('submessage'))
+
+    # Repeated message extension.
+    toplevel = more_extensions_pb2.TopLevelMessage()
+    self.assertFalse(toplevel.HasField('submessage'))
+    self.assertEqual(0, len(toplevel.submessage.Extensions[
+        more_extensions_pb2.repeated_message_extension]))
+    self.assertFalse(toplevel.HasField('submessage'))
+    foreign = toplevel.submessage.Extensions[
+        more_extensions_pb2.repeated_message_extension].add()
+    self.assertEqual(foreign, toplevel.submessage.Extensions[
+        more_extensions_pb2.repeated_message_extension][0])
+    self.assertTrue(toplevel.HasField('submessage'))
+
+  def testDisconnectionAfterClearingEmptyMessage(self):
+    toplevel = more_extensions_pb2.TopLevelMessage()
+    extendee_proto = toplevel.submessage
+    extension = more_extensions_pb2.optional_message_extension
+    extension_proto = extendee_proto.Extensions[extension]
+    extendee_proto.ClearExtension(extension)
+    extension_proto.foreign_message_int = 23
+
+    self.assertIsNot(extension_proto, extendee_proto.Extensions[extension])
+
+  def testExtensionFailureModes(self):
+    extendee_proto = unittest_pb2.TestAllExtensions()
+
+    # Try non-extension-handle arguments to HasExtension,
+    # ClearExtension(), and Extensions[]...
+    self.assertRaises(KeyError, extendee_proto.HasExtension, 1234)
+    self.assertRaises(KeyError, extendee_proto.ClearExtension, 1234)
+    self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__, 1234)
+    self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__, 1234, 5)
+
+    # Try something that *is* an extension handle, just not for
+    # this message...
+    for unknown_handle in (more_extensions_pb2.optional_int_extension,
+                           more_extensions_pb2.optional_message_extension,
+                           more_extensions_pb2.repeated_int_extension,
+                           more_extensions_pb2.repeated_message_extension):
+      self.assertRaises(KeyError, extendee_proto.HasExtension,
+                        unknown_handle)
+      self.assertRaises(KeyError, extendee_proto.ClearExtension,
+                        unknown_handle)
+      self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__,
+                        unknown_handle)
+      self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__,
+                        unknown_handle, 5)
+
+    # Try call HasExtension() with a valid handle, but for a
+    # *repeated* field.  (Just as with non-extension repeated
+    # fields, Has*() isn't supported for extension repeated fields).
+    self.assertRaises(KeyError, extendee_proto.HasExtension,
+                      unittest_pb2.repeated_string_extension)
+
+  def testMergeFromOptionalGroup(self):
+    # Test merge with an optional group.
+    proto1 = unittest_pb2.TestAllTypes()
+    proto1.optionalgroup.a = 12
+    proto2 = unittest_pb2.TestAllTypes()
+    proto2.MergeFrom(proto1)
+    self.assertEqual(12, proto2.optionalgroup.a)
+
+  def testMergeFromExtensionsSingular(self):
+    proto1 = unittest_pb2.TestAllExtensions()
+    proto1.Extensions[unittest_pb2.optional_int32_extension] = 1
+
+    proto2 = unittest_pb2.TestAllExtensions()
+    proto2.MergeFrom(proto1)
+    self.assertEqual(
+        1, proto2.Extensions[unittest_pb2.optional_int32_extension])
+
+  def testMergeFromExtensionsRepeated(self):
+    proto1 = unittest_pb2.TestAllExtensions()
+    proto1.Extensions[unittest_pb2.repeated_int32_extension].append(1)
+    proto1.Extensions[unittest_pb2.repeated_int32_extension].append(2)
+
+    proto2 = unittest_pb2.TestAllExtensions()
+    proto2.Extensions[unittest_pb2.repeated_int32_extension].append(0)
+    proto2.MergeFrom(proto1)
+    self.assertEqual(
+        3, len(proto2.Extensions[unittest_pb2.repeated_int32_extension]))
+    self.assertEqual(
+        0, proto2.Extensions[unittest_pb2.repeated_int32_extension][0])
+    self.assertEqual(
+        1, proto2.Extensions[unittest_pb2.repeated_int32_extension][1])
+    self.assertEqual(
+        2, proto2.Extensions[unittest_pb2.repeated_int32_extension][2])
+
+  def testMergeFromExtensionsNestedMessage(self):
+    proto1 = unittest_pb2.TestAllExtensions()
+    ext1 = proto1.Extensions[
+        unittest_pb2.repeated_nested_message_extension]
+    m = ext1.add()
+    m.bb = 222
+    m = ext1.add()
+    m.bb = 333
+
+    proto2 = unittest_pb2.TestAllExtensions()
+    ext2 = proto2.Extensions[
+        unittest_pb2.repeated_nested_message_extension]
+    m = ext2.add()
+    m.bb = 111
+
+    proto2.MergeFrom(proto1)
+    ext2 = proto2.Extensions[
+        unittest_pb2.repeated_nested_message_extension]
+    self.assertEqual(3, len(ext2))
+    self.assertEqual(111, ext2[0].bb)
+    self.assertEqual(222, ext2[1].bb)
+    self.assertEqual(333, ext2[2].bb)
+
+  def testCopyFromBadType(self):
+    # The python implementation doesn't raise an exception in this
+    # case. In theory it should.
+    if api_implementation.Type() == 'python':
+      return
+    proto1 = unittest_pb2.TestAllTypes()
+    proto2 = unittest_pb2.TestAllExtensions()
+    self.assertRaises(TypeError, proto1.CopyFrom, proto2)
+
+  def testClear(self):
+    proto = unittest_pb2.TestAllTypes()
+    # C++ implementation does not support lazy fields right now so leave it
+    # out for now.
+    if api_implementation.Type() == 'python':
+      test_util.SetAllFields(proto)
+    else:
+      test_util.SetAllNonLazyFields(proto)
+    # Clear the message.
+    proto.Clear()
+    self.assertEqual(proto.ByteSize(), 0)
+    empty_proto = unittest_pb2.TestAllTypes()
+    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.assertEqual(proto.ByteSize(), 0)
+    empty_proto = unittest_pb2.TestAllExtensions()
+    self.assertEqual(proto, empty_proto)
+
+  def testDisconnectingInOneof(self):
+    m = unittest_pb2.TestOneof2()  # This message has two messages in a oneof.
+    m.foo_message.moo_int = 5
+    sub_message = m.foo_message
+    # Accessing another message's field does not clear the first one
+    self.assertEqual(m.foo_lazy_message.moo_int, 0)
+    self.assertEqual(m.foo_message.moo_int, 5)
+    # But mutating another message in the oneof detaches the first one.
+    m.foo_lazy_message.moo_int = 6
+    self.assertEqual(m.foo_message.moo_int, 0)
+    # The reference we got above was detached and is still valid.
+    self.assertEqual(sub_message.moo_int, 5)
+    sub_message.moo_int = 7
+
+  def assertInitialized(self, proto):
+    self.assertTrue(proto.IsInitialized())
+    # Neither method should raise an exception.
+    proto.SerializeToString()
+    proto.SerializePartialToString()
+
+  def assertNotInitialized(self, proto, error_size=None):
+    errors = []
+    self.assertFalse(proto.IsInitialized())
+    self.assertFalse(proto.IsInitialized(errors))
+    self.assertEqual(error_size, len(errors))
+    self.assertRaises(message.EncodeError, proto.SerializeToString)
+    # "Partial" serialization doesn't care if message is uninitialized.
+    proto.SerializePartialToString()
+
+  def testIsInitialized(self):
+    # Trivial cases - all optional fields and extensions.
+    proto = unittest_pb2.TestAllTypes()
+    self.assertInitialized(proto)
+    proto = unittest_pb2.TestAllExtensions()
+    self.assertInitialized(proto)
+
+    # The case of uninitialized required fields.
+    proto = unittest_pb2.TestRequired()
+    self.assertNotInitialized(proto, 3)
+    proto.a = proto.b = proto.c = 2
+    self.assertInitialized(proto)
+
+    # The case of uninitialized submessage.
+    proto = unittest_pb2.TestRequiredForeign()
+    self.assertInitialized(proto)
+    proto.optional_message.a = 1
+    self.assertNotInitialized(proto, 2)
+    proto.optional_message.b = 0
+    proto.optional_message.c = 0
+    self.assertInitialized(proto)
+
+    # Uninitialized repeated submessage.
+    message1 = proto.repeated_message.add()
+    self.assertNotInitialized(proto, 3)
+    message1.a = message1.b = message1.c = 0
+    self.assertInitialized(proto)
+
+    # Uninitialized repeated group in an extension.
+    proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.TestRequired.multi
+    message1 = proto.Extensions[extension].add()
+    message2 = proto.Extensions[extension].add()
+    self.assertNotInitialized(proto, 6)
+    message1.a = 1
+    message1.b = 1
+    message1.c = 1
+    self.assertNotInitialized(proto, 3)
+    message2.a = 2
+    message2.b = 2
+    message2.c = 2
+    self.assertInitialized(proto)
+
+    # Uninitialized nonrepeated message in an extension.
+    proto = unittest_pb2.TestAllExtensions()
+    extension = unittest_pb2.TestRequired.single
+    proto.Extensions[extension].a = 1
+    self.assertNotInitialized(proto, 2)
+    proto.Extensions[extension].b = 2
+    proto.Extensions[extension].c = 3
+    self.assertInitialized(proto)
+
+    # Try passing an errors list.
+    errors = []
+    proto = unittest_pb2.TestRequired()
+    self.assertFalse(proto.IsInitialized(errors))
+    self.assertEqual(errors, ['a', 'b', 'c'])
+    self.assertRaises(TypeError, proto.IsInitialized, 1, 2, 3)
+
+  @unittest.skipIf(
+      api_implementation.Type() == 'python',
+      'Errors are only available from the most recent C++ implementation.')
+  def testFileDescriptorErrors(self):
+    file_name = 'test_file_descriptor_errors.proto'
+    package_name = 'test_file_descriptor_errors.proto'
+    file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
+    file_descriptor_proto.name = file_name
+    file_descriptor_proto.package = package_name
+    m1 = file_descriptor_proto.message_type.add()
+    m1.name = 'msg1'
+    # Compiles the proto into the C++ descriptor pool
+    descriptor.FileDescriptor(
+        file_name,
+        package_name,
+        serialized_pb=file_descriptor_proto.SerializeToString())
+    # Add a FileDescriptorProto that has duplicate symbols
+    another_file_name = 'another_test_file_descriptor_errors.proto'
+    file_descriptor_proto.name = another_file_name
+    m2 = file_descriptor_proto.message_type.add()
+    m2.name = 'msg2'
+    with self.assertRaises(TypeError) as cm:
+      descriptor.FileDescriptor(
+          another_file_name,
+          package_name,
+          serialized_pb=file_descriptor_proto.SerializeToString())
+      self.assertTrue(hasattr(cm, 'exception'), '%s not raised' %
+                      getattr(cm.expected, '__name__', cm.expected))
+      self.assertIn('test_file_descriptor_errors.proto', str(cm.exception))
+      # Error message will say something about this definition being a
+      # duplicate, though we don't check the message exactly to avoid a
+      # dependency on the C++ logging code.
+      self.assertIn('test_file_descriptor_errors.msg1', str(cm.exception))
+
+  def testStringUTF8Serialization(self):
+    proto = message_set_extensions_pb2.TestMessageSet()
+    extension_message = message_set_extensions_pb2.TestMessageSetExtension2
+    extension = extension_message.message_set_extension
+
+    test_utf8 = u'Тест'
+    test_utf8_bytes = test_utf8.encode('utf-8')
+
+    # 'Test' in another language, using UTF-8 charset.
+    proto.Extensions[extension].str = test_utf8
+
+    # Serialize using the MessageSet wire format (this is specified in the
+    # .proto file).
+    serialized = proto.SerializeToString()
+
+    # Check byte size.
+    self.assertEqual(proto.ByteSize(), len(serialized))
+
+    raw = unittest_mset_pb2.RawMessageSet()
+    bytes_read = raw.MergeFromString(serialized)
+    self.assertEqual(len(serialized), bytes_read)
+
+    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, 98418634)
+
+    # Check the actual bytes on the wire.
+    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), str)
+    self.assertEqual(message2.str, test_utf8)
+
+    # The pure Python API throws an exception on MergeFromString(),
+    # if any of the string fields of the message can't be UTF-8 decoded.
+    # The C++ implementation of the API has no way to check that on
+    # MergeFromString and thus has no way to throw the exception.
+    #
+    # The pure Python API always returns objects of type 'unicode' (UTF-8
+    # encoded), or 'bytes' (in 7 bit ASCII).
+    badbytes = raw.item[0].message.replace(
+        test_utf8_bytes, len(test_utf8_bytes) * b'\xff')
+
+    unicode_decode_failed = False
+    try:
+      message2.MergeFromString(badbytes)
+    except UnicodeDecodeError:
+      unicode_decode_failed = True
+    string_field = message2.str
+    self.assertTrue(unicode_decode_failed or type(string_field) is bytes)
+
+  def testSetInParent(self):
+    proto = unittest_pb2.TestAllTypes()
+    self.assertFalse(proto.HasField('optionalgroup'))
+    proto.optionalgroup.SetInParent()
+    self.assertTrue(proto.HasField('optionalgroup'))
+
+  def testPackageInitializationImport(self):
+    """Test that we can import nested messages from their __init__.py.
+
+    Such setup is not trivial since at the time of processing of __init__.py one
+    can't refer to its submodules by name in code, so expressions like
+    google.protobuf.internal.import_test_package.inner_pb2
+    don't work. They do work in imports, so we have assign an alias at import
+    and then use that alias in generated code.
+    """
+    # We import here since it's the import that used to fail, and we want
+    # the failure to have the right context.
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.internal import import_test_package
+    # pylint: enable=g-import-not-at-top
+    msg = import_test_package.myproto.Outer()
+    # Just check the default value.
+    self.assertEqual(57, msg.inner.value)
+
+#  Since we had so many tests for protocol buffer equality, we broke these out
+#  into separate TestCase classes.
+
+
+@testing_refleaks.TestCase
+class TestAllTypesEqualityTest(unittest.TestCase):
+
+  def setUp(self):
+    self.first_proto = unittest_pb2.TestAllTypes()
+    self.second_proto = unittest_pb2.TestAllTypes()
+
+  def testNotHashable(self):
+    self.assertRaises(TypeError, hash, self.first_proto)
+
+  def testSelfEquality(self):
+    self.assertEqual(self.first_proto, self.first_proto)
+
+  def testEmptyProtosEqual(self):
+    self.assertEqual(self.first_proto, self.second_proto)
+
+
+@testing_refleaks.TestCase
+class FullProtosEqualityTest(unittest.TestCase):
+
+  """Equality tests using completely-full protos as a starting point."""
+
+  def setUp(self):
+    self.first_proto = unittest_pb2.TestAllTypes()
+    self.second_proto = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(self.first_proto)
+    test_util.SetAllFields(self.second_proto)
+
+  def testNotHashable(self):
+    self.assertRaises(TypeError, hash, self.first_proto)
+
+  def testNoneNotEqual(self):
+    self.assertNotEqual(self.first_proto, None)
+    self.assertNotEqual(None, self.second_proto)
+
+  def testNotEqualToOtherMessage(self):
+    third_proto = unittest_pb2.TestRequired()
+    self.assertNotEqual(self.first_proto, third_proto)
+    self.assertNotEqual(third_proto, self.second_proto)
+
+  def testAllFieldsFilledEquality(self):
+    self.assertEqual(self.first_proto, self.second_proto)
+
+  def testNonRepeatedScalar(self):
+    # Nonrepeated scalar field change should cause inequality.
+    self.first_proto.optional_int32 += 1
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    # ...as should clearing a field.
+    self.first_proto.ClearField('optional_int32')
+    self.assertNotEqual(self.first_proto, self.second_proto)
+
+  def testNonRepeatedComposite(self):
+    # Change a nonrepeated composite field.
+    self.first_proto.optional_nested_message.bb += 1
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    self.first_proto.optional_nested_message.bb -= 1
+    self.assertEqual(self.first_proto, self.second_proto)
+    # Clear a field in the nested message.
+    self.first_proto.optional_nested_message.ClearField('bb')
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    self.first_proto.optional_nested_message.bb = (
+        self.second_proto.optional_nested_message.bb)
+    self.assertEqual(self.first_proto, self.second_proto)
+    # Remove the nested message entirely.
+    self.first_proto.ClearField('optional_nested_message')
+    self.assertNotEqual(self.first_proto, self.second_proto)
+
+  def testRepeatedScalar(self):
+    # Change a repeated scalar field.
+    self.first_proto.repeated_int32.append(5)
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    self.first_proto.ClearField('repeated_int32')
+    self.assertNotEqual(self.first_proto, self.second_proto)
+
+  def testRepeatedComposite(self):
+    # Change value within a repeated composite field.
+    self.first_proto.repeated_nested_message[0].bb += 1
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    self.first_proto.repeated_nested_message[0].bb -= 1
+    self.assertEqual(self.first_proto, self.second_proto)
+    # Add a value to a repeated composite field.
+    self.first_proto.repeated_nested_message.add()
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    self.second_proto.repeated_nested_message.add()
+    self.assertEqual(self.first_proto, self.second_proto)
+
+  def testNonRepeatedScalarHasBits(self):
+    # Ensure that we test "has" bits as well as value for
+    # nonrepeated scalar field.
+    self.first_proto.ClearField('optional_int32')
+    self.second_proto.optional_int32 = 0
+    self.assertNotEqual(self.first_proto, self.second_proto)
+
+  def testNonRepeatedCompositeHasBits(self):
+    # Ensure that we test "has" bits as well as value for
+    # nonrepeated composite field.
+    self.first_proto.ClearField('optional_nested_message')
+    self.second_proto.optional_nested_message.ClearField('bb')
+    self.assertNotEqual(self.first_proto, self.second_proto)
+    self.first_proto.optional_nested_message.bb = 0
+    self.first_proto.optional_nested_message.ClearField('bb')
+    self.assertEqual(self.first_proto, self.second_proto)
+
+
+@testing_refleaks.TestCase
+class ExtensionEqualityTest(unittest.TestCase):
+
+  def testExtensionEquality(self):
+    first_proto = unittest_pb2.TestAllExtensions()
+    second_proto = unittest_pb2.TestAllExtensions()
+    self.assertEqual(first_proto, second_proto)
+    test_util.SetAllExtensions(first_proto)
+    self.assertNotEqual(first_proto, second_proto)
+    test_util.SetAllExtensions(second_proto)
+    self.assertEqual(first_proto, second_proto)
+
+    # Ensure that we check value equality.
+    first_proto.Extensions[unittest_pb2.optional_int32_extension] += 1
+    self.assertNotEqual(first_proto, second_proto)
+    first_proto.Extensions[unittest_pb2.optional_int32_extension] -= 1
+    self.assertEqual(first_proto, second_proto)
+
+    # Ensure that we also look at "has" bits.
+    first_proto.ClearExtension(unittest_pb2.optional_int32_extension)
+    second_proto.Extensions[unittest_pb2.optional_int32_extension] = 0
+    self.assertNotEqual(first_proto, second_proto)
+    first_proto.Extensions[unittest_pb2.optional_int32_extension] = 0
+    self.assertEqual(first_proto, second_proto)
+
+    # Ensure that differences in cached values
+    # don't matter if "has" bits are both false.
+    first_proto = unittest_pb2.TestAllExtensions()
+    second_proto = unittest_pb2.TestAllExtensions()
+    self.assertEqual(
+        0, first_proto.Extensions[unittest_pb2.optional_int32_extension])
+    self.assertEqual(first_proto, second_proto)
+
+
+@testing_refleaks.TestCase
+class MutualRecursionEqualityTest(unittest.TestCase):
+
+  def testEqualityWithMutualRecursion(self):
+    first_proto = unittest_pb2.TestMutualRecursionA()
+    second_proto = unittest_pb2.TestMutualRecursionA()
+    self.assertEqual(first_proto, second_proto)
+    first_proto.bb.a.bb.optional_int32 = 23
+    self.assertNotEqual(first_proto, second_proto)
+    second_proto.bb.a.bb.optional_int32 = 23
+    self.assertEqual(first_proto, second_proto)
+
+
+@testing_refleaks.TestCase
+class ByteSizeTest(unittest.TestCase):
+
+  def setUp(self):
+    self.proto = unittest_pb2.TestAllTypes()
+    self.extended_proto = more_extensions_pb2.ExtendedMessage()
+    self.packed_proto = unittest_pb2.TestPackedTypes()
+    self.packed_extended_proto = unittest_pb2.TestPackedExtensions()
+
+  def Size(self):
+    return self.proto.ByteSize()
+
+  def testEmptyMessage(self):
+    self.assertEqual(0, self.proto.ByteSize())
+
+  def testSizedOnKwargs(self):
+    # Use a separate message to ensure testing right after creation.
+    proto = unittest_pb2.TestAllTypes()
+    self.assertEqual(0, proto.ByteSize())
+    proto_kwargs = unittest_pb2.TestAllTypes(optional_int64 = 1)
+    # One byte for the tag, one to encode varint 1.
+    self.assertEqual(2, proto_kwargs.ByteSize())
+
+  def testVarints(self):
+    def Test(i, expected_varint_size):
+      self.proto.Clear()
+      self.proto.optional_int64 = i
+      # Add one to the varint size for the tag info
+      # for tag 1.
+      self.assertEqual(expected_varint_size + 1, self.Size())
+    Test(0, 1)
+    Test(1, 1)
+    for i, num_bytes in zip(range(7, 63, 7), range(1, 10000)):
+      Test((1 << i) - 1, num_bytes)
+    Test(-1, 10)
+    Test(-2, 10)
+    Test(-(1 << 63), 10)
+
+  def testStrings(self):
+    self.proto.optional_string = ''
+    # Need one byte for tag info (tag #14), and one byte for length.
+    self.assertEqual(2, self.Size())
+
+    self.proto.optional_string = 'abc'
+    # Need one byte for tag info (tag #14), and one byte for length.
+    self.assertEqual(2 + len(self.proto.optional_string), self.Size())
+
+    self.proto.optional_string = 'x' * 128
+    # Need one byte for tag info (tag #14), and TWO bytes for length.
+    self.assertEqual(3 + len(self.proto.optional_string), self.Size())
+
+  def testOtherNumerics(self):
+    self.proto.optional_fixed32 = 1234
+    # One byte for tag and 4 bytes for fixed32.
+    self.assertEqual(5, self.Size())
+    self.proto = unittest_pb2.TestAllTypes()
+
+    self.proto.optional_fixed64 = 1234
+    # One byte for tag and 8 bytes for fixed64.
+    self.assertEqual(9, self.Size())
+    self.proto = unittest_pb2.TestAllTypes()
+
+    self.proto.optional_float = 1.234
+    # One byte for tag and 4 bytes for float.
+    self.assertEqual(5, self.Size())
+    self.proto = unittest_pb2.TestAllTypes()
+
+    self.proto.optional_double = 1.234
+    # One byte for tag and 8 bytes for float.
+    self.assertEqual(9, self.Size())
+    self.proto = unittest_pb2.TestAllTypes()
+
+    self.proto.optional_sint32 = 64
+    # One byte for tag and 2 bytes for zig-zag-encoded 64.
+    self.assertEqual(3, self.Size())
+    self.proto = unittest_pb2.TestAllTypes()
+
+  def testComposites(self):
+    # 3 bytes.
+    self.proto.optional_nested_message.bb = (1 << 14)
+    # Plus one byte for bb tag.
+    # Plus 1 byte for optional_nested_message serialized size.
+    # Plus two bytes for optional_nested_message tag.
+    self.assertEqual(3 + 1 + 1 + 2, self.Size())
+
+  def testGroups(self):
+    # 4 bytes.
+    self.proto.optionalgroup.a = (1 << 21)
+    # Plus two bytes for |a| tag.
+    # Plus 2 * two bytes for START_GROUP and END_GROUP tags.
+    self.assertEqual(4 + 2 + 2*2, self.Size())
+
+  def testRepeatedScalars(self):
+    self.proto.repeated_int32.append(10)  # 1 byte.
+    self.proto.repeated_int32.append(128)  # 2 bytes.
+    # Also need 2 bytes for each entry for tag.
+    self.assertEqual(1 + 2 + 2*2, self.Size())
+
+  def testRepeatedScalarsExtend(self):
+    self.proto.repeated_int32.extend([10, 128])  # 3 bytes.
+    # Also need 2 bytes for each entry for tag.
+    self.assertEqual(1 + 2 + 2*2, self.Size())
+
+  def testRepeatedScalarsRemove(self):
+    self.proto.repeated_int32.append(10)  # 1 byte.
+    self.proto.repeated_int32.append(128)  # 2 bytes.
+    # Also need 2 bytes for each entry for tag.
+    self.assertEqual(1 + 2 + 2*2, self.Size())
+    self.proto.repeated_int32.remove(128)
+    self.assertEqual(1 + 2, self.Size())
+
+  def testRepeatedComposites(self):
+    # Empty message.  2 bytes tag plus 1 byte length.
+    foreign_message_0 = self.proto.repeated_nested_message.add()
+    # 2 bytes tag plus 1 byte length plus 1 byte bb tag 1 byte int.
+    foreign_message_1 = self.proto.repeated_nested_message.add()
+    foreign_message_1.bb = 7
+    self.assertEqual(2 + 1 + 2 + 1 + 1 + 1, self.Size())
+
+  def testRepeatedCompositesDelete(self):
+    # Empty message.  2 bytes tag plus 1 byte length.
+    foreign_message_0 = self.proto.repeated_nested_message.add()
+    # 2 bytes tag plus 1 byte length plus 1 byte bb tag 1 byte int.
+    foreign_message_1 = self.proto.repeated_nested_message.add()
+    foreign_message_1.bb = 9
+    self.assertEqual(2 + 1 + 2 + 1 + 1 + 1, self.Size())
+    repeated_nested_message = copy.deepcopy(
+        self.proto.repeated_nested_message)
+
+    # 2 bytes tag plus 1 byte length plus 1 byte bb tag 1 byte int.
+    del self.proto.repeated_nested_message[0]
+    self.assertEqual(2 + 1 + 1 + 1, self.Size())
+
+    # Now add a new message.
+    foreign_message_2 = self.proto.repeated_nested_message.add()
+    foreign_message_2.bb = 12
+
+    # 2 bytes tag plus 1 byte length plus 1 byte bb tag 1 byte int.
+    # 2 bytes tag plus 1 byte length plus 1 byte bb tag 1 byte int.
+    self.assertEqual(2 + 1 + 1 + 1 + 2 + 1 + 1 + 1, self.Size())
+
+    # 2 bytes tag plus 1 byte length plus 1 byte bb tag 1 byte int.
+    del self.proto.repeated_nested_message[1]
+    self.assertEqual(2 + 1 + 1 + 1, self.Size())
+
+    del self.proto.repeated_nested_message[0]
+    self.assertEqual(0, self.Size())
+
+    self.assertEqual(2, len(repeated_nested_message))
+    del repeated_nested_message[0:1]
+    # TODO(jieluo): Fix cpp extension bug when delete repeated message.
+    if api_implementation.Type() == 'python':
+      self.assertEqual(1, len(repeated_nested_message))
+    del repeated_nested_message[-1]
+    # TODO(jieluo): Fix cpp extension bug when delete repeated message.
+    if api_implementation.Type() == 'python':
+      self.assertEqual(0, len(repeated_nested_message))
+
+  def testRepeatedGroups(self):
+    # 2-byte START_GROUP plus 2-byte END_GROUP.
+    group_0 = self.proto.repeatedgroup.add()
+    # 2-byte START_GROUP plus 2-byte |a| tag + 1-byte |a|
+    # plus 2-byte END_GROUP.
+    group_1 = self.proto.repeatedgroup.add()
+    group_1.a =  7
+    self.assertEqual(2 + 2 + 2 + 2 + 1 + 2, self.Size())
+
+  def testExtensions(self):
+    proto = unittest_pb2.TestAllExtensions()
+    self.assertEqual(0, proto.ByteSize())
+    extension = unittest_pb2.optional_int32_extension  # Field #1, 1 byte.
+    proto.Extensions[extension] = 23
+    # 1 byte for tag, 1 byte for value.
+    self.assertEqual(2, proto.ByteSize())
+    field = unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name[
+        'optional_int32']
+    with self.assertRaises(KeyError):
+      proto.Extensions[field] = 23
+
+  def testCacheInvalidationForNonrepeatedScalar(self):
+    # Test non-extension.
+    self.proto.optional_int32 = 1
+    self.assertEqual(2, self.proto.ByteSize())
+    self.proto.optional_int32 = 128
+    self.assertEqual(3, self.proto.ByteSize())
+    self.proto.ClearField('optional_int32')
+    self.assertEqual(0, self.proto.ByteSize())
+
+    # Test within extension.
+    extension = more_extensions_pb2.optional_int_extension
+    self.extended_proto.Extensions[extension] = 1
+    self.assertEqual(2, self.extended_proto.ByteSize())
+    self.extended_proto.Extensions[extension] = 128
+    self.assertEqual(3, self.extended_proto.ByteSize())
+    self.extended_proto.ClearExtension(extension)
+    self.assertEqual(0, self.extended_proto.ByteSize())
+
+  def testCacheInvalidationForRepeatedScalar(self):
+    # Test non-extension.
+    self.proto.repeated_int32.append(1)
+    self.assertEqual(3, self.proto.ByteSize())
+    self.proto.repeated_int32.append(1)
+    self.assertEqual(6, self.proto.ByteSize())
+    self.proto.repeated_int32[1] = 128
+    self.assertEqual(7, self.proto.ByteSize())
+    self.proto.ClearField('repeated_int32')
+    self.assertEqual(0, self.proto.ByteSize())
+
+    # Test within extension.
+    extension = more_extensions_pb2.repeated_int_extension
+    repeated = self.extended_proto.Extensions[extension]
+    repeated.append(1)
+    self.assertEqual(2, self.extended_proto.ByteSize())
+    repeated.append(1)
+    self.assertEqual(4, self.extended_proto.ByteSize())
+    repeated[1] = 128
+    self.assertEqual(5, self.extended_proto.ByteSize())
+    self.extended_proto.ClearExtension(extension)
+    self.assertEqual(0, self.extended_proto.ByteSize())
+
+  def testCacheInvalidationForNonrepeatedMessage(self):
+    # Test non-extension.
+    self.proto.optional_foreign_message.c = 1
+    self.assertEqual(5, self.proto.ByteSize())
+    self.proto.optional_foreign_message.c = 128
+    self.assertEqual(6, self.proto.ByteSize())
+    self.proto.optional_foreign_message.ClearField('c')
+    self.assertEqual(3, self.proto.ByteSize())
+    self.proto.ClearField('optional_foreign_message')
+    self.assertEqual(0, self.proto.ByteSize())
+
+    if api_implementation.Type() == 'python':
+      # This is only possible in pure-Python implementation of the API.
+      child = self.proto.optional_foreign_message
+      self.proto.ClearField('optional_foreign_message')
+      child.c = 128
+      self.assertEqual(0, self.proto.ByteSize())
+
+    # Test within extension.
+    extension = more_extensions_pb2.optional_message_extension
+    child = self.extended_proto.Extensions[extension]
+    self.assertEqual(0, self.extended_proto.ByteSize())
+    child.foreign_message_int = 1
+    self.assertEqual(4, self.extended_proto.ByteSize())
+    child.foreign_message_int = 128
+    self.assertEqual(5, self.extended_proto.ByteSize())
+    self.extended_proto.ClearExtension(extension)
+    self.assertEqual(0, self.extended_proto.ByteSize())
+
+  def testCacheInvalidationForRepeatedMessage(self):
+    # Test non-extension.
+    child0 = self.proto.repeated_foreign_message.add()
+    self.assertEqual(3, self.proto.ByteSize())
+    self.proto.repeated_foreign_message.add()
+    self.assertEqual(6, self.proto.ByteSize())
+    child0.c = 1
+    self.assertEqual(8, self.proto.ByteSize())
+    self.proto.ClearField('repeated_foreign_message')
+    self.assertEqual(0, self.proto.ByteSize())
+
+    # Test within extension.
+    extension = more_extensions_pb2.repeated_message_extension
+    child_list = self.extended_proto.Extensions[extension]
+    child0 = child_list.add()
+    self.assertEqual(2, self.extended_proto.ByteSize())
+    child_list.add()
+    self.assertEqual(4, self.extended_proto.ByteSize())
+    child0.foreign_message_int = 1
+    self.assertEqual(6, self.extended_proto.ByteSize())
+    child0.ClearField('foreign_message_int')
+    self.assertEqual(4, self.extended_proto.ByteSize())
+    self.extended_proto.ClearExtension(extension)
+    self.assertEqual(0, self.extended_proto.ByteSize())
+
+  def testPackedRepeatedScalars(self):
+    self.assertEqual(0, self.packed_proto.ByteSize())
+
+    self.packed_proto.packed_int32.append(10)   # 1 byte.
+    self.packed_proto.packed_int32.append(128)  # 2 bytes.
+    # The tag is 2 bytes (the field number is 90), and the varint
+    # storing the length is 1 byte.
+    int_size = 1 + 2 + 3
+    self.assertEqual(int_size, self.packed_proto.ByteSize())
+
+    self.packed_proto.packed_double.append(4.2)   # 8 bytes
+    self.packed_proto.packed_double.append(3.25)  # 8 bytes
+    # 2 more tag bytes, 1 more length byte.
+    double_size = 8 + 8 + 3
+    self.assertEqual(int_size+double_size, self.packed_proto.ByteSize())
+
+    self.packed_proto.ClearField('packed_int32')
+    self.assertEqual(double_size, self.packed_proto.ByteSize())
+
+  def testPackedExtensions(self):
+    self.assertEqual(0, self.packed_extended_proto.ByteSize())
+    extension = self.packed_extended_proto.Extensions[
+        unittest_pb2.packed_fixed32_extension]
+    extension.extend([1, 2, 3, 4])   # 16 bytes
+    # Tag is 3 bytes.
+    self.assertEqual(19, self.packed_extended_proto.ByteSize())
+
+
+# Issues to be sure to cover include:
+#   * Handling of unrecognized tags ("uninterpreted_bytes").
+#   * Handling of MessageSets.
+#   * Consistent ordering of tags in the wire format,
+#     including ordering between extensions and non-extension
+#     fields.
+#   * Consistent serialization of negative numbers, especially
+#     negative int32s.
+#   * Handling of empty submessages (with and without "has"
+#     bits set).
+
+@testing_refleaks.TestCase
+class SerializationTest(unittest.TestCase):
+
+  def testSerializeEmtpyMessage(self):
+    first_proto = unittest_pb2.TestAllTypes()
+    second_proto = unittest_pb2.TestAllTypes()
+    serialized = first_proto.SerializeToString()
+    self.assertEqual(first_proto.ByteSize(), len(serialized))
+    self.assertEqual(
+        len(serialized),
+        second_proto.MergeFromString(serialized))
+    self.assertEqual(first_proto, second_proto)
+
+  def testSerializeAllFields(self):
+    first_proto = unittest_pb2.TestAllTypes()
+    second_proto = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(first_proto)
+    serialized = first_proto.SerializeToString()
+    self.assertEqual(first_proto.ByteSize(), len(serialized))
+    self.assertEqual(
+        len(serialized),
+        second_proto.MergeFromString(serialized))
+    self.assertEqual(first_proto, second_proto)
+
+  def testSerializeAllExtensions(self):
+    first_proto = unittest_pb2.TestAllExtensions()
+    second_proto = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(first_proto)
+    serialized = first_proto.SerializeToString()
+    self.assertEqual(
+        len(serialized),
+        second_proto.MergeFromString(serialized))
+    self.assertEqual(first_proto, second_proto)
+
+  def testSerializeWithOptionalGroup(self):
+    first_proto = unittest_pb2.TestAllTypes()
+    second_proto = unittest_pb2.TestAllTypes()
+    first_proto.optionalgroup.a = 242
+    serialized = first_proto.SerializeToString()
+    self.assertEqual(
+        len(serialized),
+        second_proto.MergeFromString(serialized))
+    self.assertEqual(first_proto, second_proto)
+
+  def testSerializeNegativeValues(self):
+    first_proto = unittest_pb2.TestAllTypes()
+
+    first_proto.optional_int32 = -1
+    first_proto.optional_int64 = -(2 << 40)
+    first_proto.optional_sint32 = -3
+    first_proto.optional_sint64 = -(4 << 40)
+    first_proto.optional_sfixed32 = -5
+    first_proto.optional_sfixed64 = -(6 << 40)
+
+    second_proto = unittest_pb2.TestAllTypes.FromString(
+        first_proto.SerializeToString())
+
+    self.assertEqual(first_proto, second_proto)
+
+  def testParseTruncated(self):
+    # This test is only applicable for the Python implementation of the API.
+    if api_implementation.Type() != 'python':
+      return
+
+    first_proto = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(first_proto)
+    serialized = memoryview(first_proto.SerializeToString())
+
+    for truncation_point in range(len(serialized) + 1):
+      try:
+        second_proto = unittest_pb2.TestAllTypes()
+        unknown_fields = unittest_pb2.TestEmptyMessage()
+        pos = second_proto._InternalParse(serialized, 0, truncation_point)
+        # If we didn't raise an error then we read exactly the amount expected.
+        self.assertEqual(truncation_point, pos)
+
+        # Parsing to unknown fields should not throw if parsing to known fields
+        # did not.
+        try:
+          pos2 = unknown_fields._InternalParse(serialized, 0, truncation_point)
+          self.assertEqual(truncation_point, pos2)
+        except message.DecodeError:
+          self.fail('Parsing unknown fields failed when parsing known fields '
+                    'did not.')
+      except message.DecodeError:
+        # Parsing unknown fields should also fail.
+        self.assertRaises(message.DecodeError, unknown_fields._InternalParse,
+                          serialized, 0, truncation_point)
+
+  def testCanonicalSerializationOrder(self):
+    proto = more_messages_pb2.OutOfOrderFields()
+    # These are also their tag numbers.  Even though we're setting these in
+    # reverse-tag order AND they're listed in reverse tag-order in the .proto
+    # file, they should nonetheless be serialized in tag order.
+    proto.optional_sint32 = 5
+    proto.Extensions[more_messages_pb2.optional_uint64] = 4
+    proto.optional_uint32 = 3
+    proto.Extensions[more_messages_pb2.optional_int64] = 2
+    proto.optional_int32 = 1
+    serialized = proto.SerializeToString()
+    self.assertEqual(proto.ByteSize(), len(serialized))
+    d = _MiniDecoder(serialized)
+    ReadTag = d.ReadFieldNumberAndWireType
+    self.assertEqual((1, wire_format.WIRETYPE_VARINT), ReadTag())
+    self.assertEqual(1, d.ReadInt32())
+    self.assertEqual((2, wire_format.WIRETYPE_VARINT), ReadTag())
+    self.assertEqual(2, d.ReadInt64())
+    self.assertEqual((3, wire_format.WIRETYPE_VARINT), ReadTag())
+    self.assertEqual(3, d.ReadUInt32())
+    self.assertEqual((4, wire_format.WIRETYPE_VARINT), ReadTag())
+    self.assertEqual(4, d.ReadUInt64())
+    self.assertEqual((5, wire_format.WIRETYPE_VARINT), ReadTag())
+    self.assertEqual(5, d.ReadSInt32())
+
+  def testCanonicalSerializationOrderSameAsCpp(self):
+    # Copy of the same test we use for C++.
+    proto = unittest_pb2.TestFieldOrderings()
+    test_util.SetAllFieldsAndExtensions(proto)
+    serialized = proto.SerializeToString()
+    test_util.ExpectAllFieldsAndExtensionsInOrder(serialized)
+
+  def testMergeFromStringWhenFieldsAlreadySet(self):
+    first_proto = unittest_pb2.TestAllTypes()
+    first_proto.repeated_string.append('foobar')
+    first_proto.optional_int32 = 23
+    first_proto.optional_nested_message.bb = 42
+    serialized = first_proto.SerializeToString()
+
+    second_proto = unittest_pb2.TestAllTypes()
+    second_proto.repeated_string.append('baz')
+    second_proto.optional_int32 = 100
+    second_proto.optional_nested_message.bb = 999
+
+    bytes_parsed = second_proto.MergeFromString(serialized)
+    self.assertEqual(len(serialized), bytes_parsed)
+
+    # Ensure that we append to repeated fields.
+    self.assertEqual(['baz', 'foobar'], list(second_proto.repeated_string))
+    # Ensure that we overwrite nonrepeatd scalars.
+    self.assertEqual(23, second_proto.optional_int32)
+    # Ensure that we recursively call MergeFromString() on
+    # submessages.
+    self.assertEqual(42, second_proto.optional_nested_message.bb)
+
+  def testMessageSetWireFormat(self):
+    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).
+    serialized = proto.SerializeToString()
+
+    raw = unittest_mset_pb2.RawMessageSet()
+    self.assertEqual(False,
+                     raw.DESCRIPTOR.GetOptions().message_set_wire_format)
+    self.assertEqual(
+        len(serialized),
+        raw.MergeFromString(serialized))
+    self.assertEqual(3, len(raw.item))
+
+    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 = 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 = 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))
+    self.assertEqual(proto.ByteSize(), len(serialized))
+
+  def testMessageSetWireFormatUnknownExtension(self):
+    # Create a message using the message set wire format with an unknown
+    # message.
+    raw = unittest_mset_pb2.RawMessageSet()
+
+    # Add an item.
+    item = raw.item.add()
+    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 = 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 = 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 = message_set_extensions_pb2.TestMessageSet()
+    self.assertEqual(
+        len(serialized),
+        proto.MergeFromString(serialized))
+
+    # Check that the message parsed well.
+    extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1
+    extension1 = extension_message1.message_set_extension
+    self.assertEqual(12345, proto.Extensions[extension1].i)
+
+  def testUnknownFields(self):
+    proto = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(proto)
+
+    serialized = proto.SerializeToString()
+
+    # The empty message should be parsable with all of the fields
+    # unknown.
+    proto2 = unittest_pb2.TestEmptyMessage()
+
+    # Parsing this message should succeed.
+    self.assertEqual(
+        len(serialized),
+        proto2.MergeFromString(serialized))
+
+    # Now test with a int64 field set.
+    proto = unittest_pb2.TestAllTypes()
+    proto.optional_int64 = 0x0fffffffffffffff
+    serialized = proto.SerializeToString()
+    # The empty message should be parsable with all of the fields
+    # unknown.
+    proto2 = unittest_pb2.TestEmptyMessage()
+    # Parsing this message should succeed.
+    self.assertEqual(
+        len(serialized),
+        proto2.MergeFromString(serialized))
+
+  def _CheckRaises(self, exc_class, callable_obj, exception):
+    """This method checks if the exception type and message are as expected."""
+    try:
+      callable_obj()
+    except exc_class as ex:
+      # Check if the exception message is the right one.
+      self.assertEqual(exception, str(ex))
+      return
+    else:
+      raise self.failureException('%s not raised' % str(exc_class))
+
+  def testSerializeUninitialized(self):
+    proto = unittest_pb2.TestRequired()
+    self._CheckRaises(
+        message.EncodeError,
+        proto.SerializeToString,
+        'Message protobuf_unittest.TestRequired is missing required fields: '
+        'a,b,c')
+    # Shouldn't raise exceptions.
+    partial = proto.SerializePartialToString()
+
+    proto2 = unittest_pb2.TestRequired()
+    self.assertFalse(proto2.HasField('a'))
+    # proto2 ParseFromString does not check that required fields are set.
+    proto2.ParseFromString(partial)
+    self.assertFalse(proto2.HasField('a'))
+
+    proto.a = 1
+    self._CheckRaises(
+        message.EncodeError,
+        proto.SerializeToString,
+        'Message protobuf_unittest.TestRequired is missing required fields: b,c')
+    # Shouldn't raise exceptions.
+    partial = proto.SerializePartialToString()
+
+    proto.b = 2
+    self._CheckRaises(
+        message.EncodeError,
+        proto.SerializeToString,
+        'Message protobuf_unittest.TestRequired is missing required fields: c')
+    # Shouldn't raise exceptions.
+    partial = proto.SerializePartialToString()
+
+    proto.c = 3
+    serialized = proto.SerializeToString()
+    # Shouldn't raise exceptions.
+    partial = proto.SerializePartialToString()
+
+    proto2 = unittest_pb2.TestRequired()
+    self.assertEqual(
+        len(serialized),
+        proto2.MergeFromString(serialized))
+    self.assertEqual(1, proto2.a)
+    self.assertEqual(2, proto2.b)
+    self.assertEqual(3, proto2.c)
+    self.assertEqual(
+        len(partial),
+        proto2.MergeFromString(partial))
+    self.assertEqual(1, proto2.a)
+    self.assertEqual(2, proto2.b)
+    self.assertEqual(3, proto2.c)
+
+  def testSerializeUninitializedSubMessage(self):
+    proto = unittest_pb2.TestRequiredForeign()
+
+    # Sub-message doesn't exist yet, so this succeeds.
+    proto.SerializeToString()
+
+    proto.optional_message.a = 1
+    self._CheckRaises(
+        message.EncodeError,
+        proto.SerializeToString,
+        'Message protobuf_unittest.TestRequiredForeign '
+        'is missing required fields: '
+        'optional_message.b,optional_message.c')
+
+    proto.optional_message.b = 2
+    proto.optional_message.c = 3
+    proto.SerializeToString()
+
+    proto.repeated_message.add().a = 1
+    proto.repeated_message.add().b = 2
+    self._CheckRaises(
+        message.EncodeError,
+        proto.SerializeToString,
+        'Message protobuf_unittest.TestRequiredForeign is missing required fields: '
+        'repeated_message[0].b,repeated_message[0].c,'
+        'repeated_message[1].a,repeated_message[1].c')
+
+    proto.repeated_message[0].b = 2
+    proto.repeated_message[0].c = 3
+    proto.repeated_message[1].a = 1
+    proto.repeated_message[1].c = 3
+    proto.SerializeToString()
+
+  def testSerializeAllPackedFields(self):
+    first_proto = unittest_pb2.TestPackedTypes()
+    second_proto = unittest_pb2.TestPackedTypes()
+    test_util.SetAllPackedFields(first_proto)
+    serialized = first_proto.SerializeToString()
+    self.assertEqual(first_proto.ByteSize(), len(serialized))
+    bytes_read = second_proto.MergeFromString(serialized)
+    self.assertEqual(second_proto.ByteSize(), bytes_read)
+    self.assertEqual(first_proto, second_proto)
+
+  def testSerializeAllPackedExtensions(self):
+    first_proto = unittest_pb2.TestPackedExtensions()
+    second_proto = unittest_pb2.TestPackedExtensions()
+    test_util.SetAllPackedExtensions(first_proto)
+    serialized = first_proto.SerializeToString()
+    bytes_read = second_proto.MergeFromString(serialized)
+    self.assertEqual(second_proto.ByteSize(), bytes_read)
+    self.assertEqual(first_proto, second_proto)
+
+  def testMergePackedFromStringWhenSomeFieldsAlreadySet(self):
+    first_proto = unittest_pb2.TestPackedTypes()
+    first_proto.packed_int32.extend([1, 2])
+    first_proto.packed_double.append(3.0)
+    serialized = first_proto.SerializeToString()
+
+    second_proto = unittest_pb2.TestPackedTypes()
+    second_proto.packed_int32.append(3)
+    second_proto.packed_double.extend([1.0, 2.0])
+    second_proto.packed_sint32.append(4)
+
+    self.assertEqual(
+        len(serialized),
+        second_proto.MergeFromString(serialized))
+    self.assertEqual([3, 1, 2], second_proto.packed_int32)
+    self.assertEqual([1.0, 2.0, 3.0], second_proto.packed_double)
+    self.assertEqual([4], second_proto.packed_sint32)
+
+  def testPackedFieldsWireFormat(self):
+    proto = unittest_pb2.TestPackedTypes()
+    proto.packed_int32.extend([1, 2, 150, 3])  # 1 + 1 + 2 + 1 bytes
+    proto.packed_double.extend([1.0, 1000.0])  # 8 + 8 bytes
+    proto.packed_float.append(2.0)             # 4 bytes, will be before double
+    serialized = proto.SerializeToString()
+    self.assertEqual(proto.ByteSize(), len(serialized))
+    d = _MiniDecoder(serialized)
+    ReadTag = d.ReadFieldNumberAndWireType
+    self.assertEqual((90, wire_format.WIRETYPE_LENGTH_DELIMITED), ReadTag())
+    self.assertEqual(1+1+1+2, d.ReadInt32())
+    self.assertEqual(1, d.ReadInt32())
+    self.assertEqual(2, d.ReadInt32())
+    self.assertEqual(150, d.ReadInt32())
+    self.assertEqual(3, d.ReadInt32())
+    self.assertEqual((100, wire_format.WIRETYPE_LENGTH_DELIMITED), ReadTag())
+    self.assertEqual(4, d.ReadInt32())
+    self.assertEqual(2.0, d.ReadFloat())
+    self.assertEqual((101, wire_format.WIRETYPE_LENGTH_DELIMITED), ReadTag())
+    self.assertEqual(8+8, d.ReadInt32())
+    self.assertEqual(1.0, d.ReadDouble())
+    self.assertEqual(1000.0, d.ReadDouble())
+    self.assertTrue(d.EndOfStream())
+
+  def testParsePackedFromUnpacked(self):
+    unpacked = unittest_pb2.TestUnpackedTypes()
+    test_util.SetAllUnpackedFields(unpacked)
+    packed = unittest_pb2.TestPackedTypes()
+    serialized = unpacked.SerializeToString()
+    self.assertEqual(
+        len(serialized),
+        packed.MergeFromString(serialized))
+    expected = unittest_pb2.TestPackedTypes()
+    test_util.SetAllPackedFields(expected)
+    self.assertEqual(expected, packed)
+
+  def testParseUnpackedFromPacked(self):
+    packed = unittest_pb2.TestPackedTypes()
+    test_util.SetAllPackedFields(packed)
+    unpacked = unittest_pb2.TestUnpackedTypes()
+    serialized = packed.SerializeToString()
+    self.assertEqual(
+        len(serialized),
+        unpacked.MergeFromString(serialized))
+    expected = unittest_pb2.TestUnpackedTypes()
+    test_util.SetAllUnpackedFields(expected)
+    self.assertEqual(expected, unpacked)
+
+  def testFieldNumbers(self):
+    proto = unittest_pb2.TestAllTypes()
+    self.assertEqual(unittest_pb2.TestAllTypes.NestedMessage.BB_FIELD_NUMBER, 1)
+    self.assertEqual(unittest_pb2.TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER, 1)
+    self.assertEqual(unittest_pb2.TestAllTypes.OPTIONALGROUP_FIELD_NUMBER, 16)
+    self.assertEqual(
+      unittest_pb2.TestAllTypes.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER, 18)
+    self.assertEqual(
+      unittest_pb2.TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, 21)
+    self.assertEqual(unittest_pb2.TestAllTypes.REPEATED_INT32_FIELD_NUMBER, 31)
+    self.assertEqual(unittest_pb2.TestAllTypes.REPEATEDGROUP_FIELD_NUMBER, 46)
+    self.assertEqual(
+      unittest_pb2.TestAllTypes.REPEATED_NESTED_MESSAGE_FIELD_NUMBER, 48)
+    self.assertEqual(
+      unittest_pb2.TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 51)
+
+  def testExtensionFieldNumbers(self):
+    self.assertEqual(unittest_pb2.TestRequired.single.number, 1000)
+    self.assertEqual(unittest_pb2.TestRequired.SINGLE_FIELD_NUMBER, 1000)
+    self.assertEqual(unittest_pb2.TestRequired.multi.number, 1001)
+    self.assertEqual(unittest_pb2.TestRequired.MULTI_FIELD_NUMBER, 1001)
+    self.assertEqual(unittest_pb2.optional_int32_extension.number, 1)
+    self.assertEqual(unittest_pb2.OPTIONAL_INT32_EXTENSION_FIELD_NUMBER, 1)
+    self.assertEqual(unittest_pb2.optionalgroup_extension.number, 16)
+    self.assertEqual(unittest_pb2.OPTIONALGROUP_EXTENSION_FIELD_NUMBER, 16)
+    self.assertEqual(unittest_pb2.optional_nested_message_extension.number, 18)
+    self.assertEqual(
+      unittest_pb2.OPTIONAL_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 18)
+    self.assertEqual(unittest_pb2.optional_nested_enum_extension.number, 21)
+    self.assertEqual(unittest_pb2.OPTIONAL_NESTED_ENUM_EXTENSION_FIELD_NUMBER,
+      21)
+    self.assertEqual(unittest_pb2.repeated_int32_extension.number, 31)
+    self.assertEqual(unittest_pb2.REPEATED_INT32_EXTENSION_FIELD_NUMBER, 31)
+    self.assertEqual(unittest_pb2.repeatedgroup_extension.number, 46)
+    self.assertEqual(unittest_pb2.REPEATEDGROUP_EXTENSION_FIELD_NUMBER, 46)
+    self.assertEqual(unittest_pb2.repeated_nested_message_extension.number, 48)
+    self.assertEqual(
+      unittest_pb2.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 48)
+    self.assertEqual(unittest_pb2.repeated_nested_enum_extension.number, 51)
+    self.assertEqual(unittest_pb2.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER,
+      51)
+
+  def testFieldProperties(self):
+    cls = unittest_pb2.TestAllTypes
+    self.assertIs(cls.optional_int32.DESCRIPTOR,
+                  cls.DESCRIPTOR.fields_by_name['optional_int32'])
+    self.assertEqual(cls.OPTIONAL_INT32_FIELD_NUMBER,
+                     cls.optional_int32.DESCRIPTOR.number)
+    self.assertIs(cls.optional_nested_message.DESCRIPTOR,
+                  cls.DESCRIPTOR.fields_by_name['optional_nested_message'])
+    self.assertEqual(cls.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER,
+                     cls.optional_nested_message.DESCRIPTOR.number)
+    self.assertIs(cls.repeated_int32.DESCRIPTOR,
+                  cls.DESCRIPTOR.fields_by_name['repeated_int32'])
+    self.assertEqual(cls.REPEATED_INT32_FIELD_NUMBER,
+                     cls.repeated_int32.DESCRIPTOR.number)
+
+  def testFieldDataDescriptor(self):
+    msg = unittest_pb2.TestAllTypes()
+    msg.optional_int32 = 42
+    self.assertEqual(unittest_pb2.TestAllTypes.optional_int32.__get__(msg), 42)
+    unittest_pb2.TestAllTypes.optional_int32.__set__(msg, 25)
+    self.assertEqual(msg.optional_int32, 25)
+    with self.assertRaises(AttributeError):
+      del msg.optional_int32
+    try:
+      unittest_pb2.ForeignMessage.c.__get__(msg)
+    except TypeError:
+      pass  # The cpp implementation cannot mix fields from other messages.
+      # This test exercises a specific check that avoids a crash.
+    else:
+      pass  # The python implementation allows fields from other messages.
+      # This is useless, but works.
+
+  def testInitKwargs(self):
+    proto = unittest_pb2.TestAllTypes(
+        optional_int32=1,
+        optional_string='foo',
+        optional_bool=True,
+        optional_bytes=b'bar',
+        optional_nested_message=unittest_pb2.TestAllTypes.NestedMessage(bb=1),
+        optional_foreign_message=unittest_pb2.ForeignMessage(c=1),
+        optional_nested_enum=unittest_pb2.TestAllTypes.FOO,
+        optional_foreign_enum=unittest_pb2.FOREIGN_FOO,
+        repeated_int32=[1, 2, 3])
+    self.assertTrue(proto.IsInitialized())
+    self.assertTrue(proto.HasField('optional_int32'))
+    self.assertTrue(proto.HasField('optional_string'))
+    self.assertTrue(proto.HasField('optional_bool'))
+    self.assertTrue(proto.HasField('optional_bytes'))
+    self.assertTrue(proto.HasField('optional_nested_message'))
+    self.assertTrue(proto.HasField('optional_foreign_message'))
+    self.assertTrue(proto.HasField('optional_nested_enum'))
+    self.assertTrue(proto.HasField('optional_foreign_enum'))
+    self.assertEqual(1, proto.optional_int32)
+    self.assertEqual('foo', proto.optional_string)
+    self.assertEqual(True, proto.optional_bool)
+    self.assertEqual(b'bar', proto.optional_bytes)
+    self.assertEqual(1, proto.optional_nested_message.bb)
+    self.assertEqual(1, proto.optional_foreign_message.c)
+    self.assertEqual(unittest_pb2.TestAllTypes.FOO,
+                     proto.optional_nested_enum)
+    self.assertEqual(unittest_pb2.FOREIGN_FOO, proto.optional_foreign_enum)
+    self.assertEqual([1, 2, 3], proto.repeated_int32)
+
+  def testInitArgsUnknownFieldName(self):
+    def InitalizeEmptyMessageWithExtraKeywordArg():
+      unused_proto = unittest_pb2.TestEmptyMessage(unknown='unknown')
+    self._CheckRaises(
+        ValueError,
+        InitalizeEmptyMessageWithExtraKeywordArg,
+        'Protocol message TestEmptyMessage has no "unknown" field.')
+
+  def testInitRequiredKwargs(self):
+    proto = unittest_pb2.TestRequired(a=1, b=1, c=1)
+    self.assertTrue(proto.IsInitialized())
+    self.assertTrue(proto.HasField('a'))
+    self.assertTrue(proto.HasField('b'))
+    self.assertTrue(proto.HasField('c'))
+    self.assertFalse(proto.HasField('dummy2'))
+    self.assertEqual(1, proto.a)
+    self.assertEqual(1, proto.b)
+    self.assertEqual(1, proto.c)
+
+  def testInitRequiredForeignKwargs(self):
+    proto = unittest_pb2.TestRequiredForeign(
+        optional_message=unittest_pb2.TestRequired(a=1, b=1, c=1))
+    self.assertTrue(proto.IsInitialized())
+    self.assertTrue(proto.HasField('optional_message'))
+    self.assertTrue(proto.optional_message.IsInitialized())
+    self.assertTrue(proto.optional_message.HasField('a'))
+    self.assertTrue(proto.optional_message.HasField('b'))
+    self.assertTrue(proto.optional_message.HasField('c'))
+    self.assertFalse(proto.optional_message.HasField('dummy2'))
+    self.assertEqual(unittest_pb2.TestRequired(a=1, b=1, c=1),
+                     proto.optional_message)
+    self.assertEqual(1, proto.optional_message.a)
+    self.assertEqual(1, proto.optional_message.b)
+    self.assertEqual(1, proto.optional_message.c)
+
+  def testInitRepeatedKwargs(self):
+    proto = unittest_pb2.TestAllTypes(repeated_int32=[1, 2, 3])
+    self.assertTrue(proto.IsInitialized())
+    self.assertEqual(1, proto.repeated_int32[0])
+    self.assertEqual(2, proto.repeated_int32[1])
+    self.assertEqual(3, proto.repeated_int32[2])
+
+
+@testing_refleaks.TestCase
+class OptionsTest(unittest.TestCase):
+
+  def testMessageOptions(self):
+    proto = message_set_extensions_pb2.TestMessageSet()
+    self.assertEqual(True,
+                     proto.DESCRIPTOR.GetOptions().message_set_wire_format)
+    proto = unittest_pb2.TestAllTypes()
+    self.assertEqual(False,
+                     proto.DESCRIPTOR.GetOptions().message_set_wire_format)
+
+  def testPackedOptions(self):
+    proto = unittest_pb2.TestAllTypes()
+    proto.optional_int32 = 1
+    proto.optional_double = 3.0
+    for field_descriptor, _ in proto.ListFields():
+      self.assertEqual(False, field_descriptor.GetOptions().packed)
+
+    proto = unittest_pb2.TestPackedTypes()
+    proto.packed_int32.append(1)
+    proto.packed_double.append(3.0)
+    for field_descriptor, _ in proto.ListFields():
+      self.assertEqual(True, field_descriptor.GetOptions().packed)
+      self.assertEqual(descriptor.FieldDescriptor.LABEL_REPEATED,
+                       field_descriptor.label)
+
+
+
+@testing_refleaks.TestCase
+class ClassAPITest(unittest.TestCase):
+
+  @unittest.skipIf(
+      api_implementation.Type() != 'python',
+      'C++ implementation requires a call to MakeDescriptor()')
+  @testing_refleaks.SkipReferenceLeakChecker('MakeClass is not repeatable')
+  def testMakeClassWithNestedDescriptor(self):
+    leaf_desc = descriptor.Descriptor(
+        'leaf', 'package.parent.child.leaf', '',
+        containing_type=None, fields=[],
+        nested_types=[], enum_types=[],
+        extensions=[],
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    child_desc = descriptor.Descriptor(
+        'child', 'package.parent.child', '',
+        containing_type=None, fields=[],
+        nested_types=[leaf_desc], enum_types=[],
+        extensions=[],
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    sibling_desc = descriptor.Descriptor(
+        'sibling', 'package.parent.sibling',
+        '', containing_type=None, fields=[],
+        nested_types=[], enum_types=[],
+        extensions=[],
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    parent_desc = descriptor.Descriptor(
+        'parent', 'package.parent', '',
+        containing_type=None, fields=[],
+        nested_types=[child_desc, sibling_desc],
+        enum_types=[], extensions=[],
+        # pylint: disable=protected-access
+        create_key=descriptor._internal_create_key)
+    reflection.MakeClass(parent_desc)
+
+  def _GetSerializedFileDescriptor(self, name):
+    """Get a serialized representation of a test FileDescriptorProto.
+
+    Args:
+      name: All calls to this must use a unique message name, to avoid
+          collisions in the cpp descriptor pool.
+    Returns:
+      A string containing the serialized form of a test FileDescriptorProto.
+    """
+    file_descriptor_str = (
+        'message_type {'
+        '  name: "' + name + '"'
+        '  field {'
+        '    name: "flat"'
+        '    number: 1'
+        '    label: LABEL_REPEATED'
+        '    type: TYPE_UINT32'
+        '  }'
+        '  field {'
+        '    name: "bar"'
+        '    number: 2'
+        '    label: LABEL_OPTIONAL'
+        '    type: TYPE_MESSAGE'
+        '    type_name: "Bar"'
+        '  }'
+        '  nested_type {'
+        '    name: "Bar"'
+        '    field {'
+        '      name: "baz"'
+        '      number: 3'
+        '      label: LABEL_OPTIONAL'
+        '      type: TYPE_MESSAGE'
+        '      type_name: "Baz"'
+        '    }'
+        '    nested_type {'
+        '      name: "Baz"'
+        '      enum_type {'
+        '        name: "deep_enum"'
+        '        value {'
+        '          name: "VALUE_A"'
+        '          number: 0'
+        '        }'
+        '      }'
+        '      field {'
+        '        name: "deep"'
+        '        number: 4'
+        '        label: LABEL_OPTIONAL'
+        '        type: TYPE_UINT32'
+        '      }'
+        '    }'
+        '  }'
+        '}')
+    file_descriptor = descriptor_pb2.FileDescriptorProto()
+    text_format.Merge(file_descriptor_str, file_descriptor)
+    return file_descriptor.SerializeToString()
+
+  @testing_refleaks.SkipReferenceLeakChecker('MakeDescriptor is not repeatable')
+  # This test can only run once; the second time, it raises errors about
+  # conflicting message descriptors.
+  def testParsingFlatClassWithExplicitClassDeclaration(self):
+    """Test that the generated class can parse a flat message."""
+    # TODO(xiaofeng): This test fails with cpp implementation 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):
+      DESCRIPTOR = msg_descriptor
+    msg = MessageClass()
+    msg_str = (
+        'flat: 0 '
+        'flat: 1 '
+        'flat: 2 ')
+    text_format.Merge(msg_str, msg)
+    self.assertEqual(msg.flat, [0, 1, 2])
+
+  @testing_refleaks.SkipReferenceLeakChecker('MakeDescriptor is not repeatable')
+  def testParsingFlatClass(self):
+    """Test that the generated class can parse a flat message."""
+    file_descriptor = descriptor_pb2.FileDescriptorProto()
+    file_descriptor.ParseFromString(self._GetSerializedFileDescriptor('B'))
+    msg_descriptor = descriptor.MakeDescriptor(
+        file_descriptor.message_type[0])
+    msg_class = reflection.MakeClass(msg_descriptor)
+    msg = msg_class()
+    msg_str = (
+        'flat: 0 '
+        'flat: 1 '
+        'flat: 2 ')
+    text_format.Merge(msg_str, msg)
+    self.assertEqual(msg.flat, [0, 1, 2])
+
+  @testing_refleaks.SkipReferenceLeakChecker('MakeDescriptor is not repeatable')
+  def testParsingNestedClass(self):
+    """Test that the generated class can parse a nested message."""
+    file_descriptor = descriptor_pb2.FileDescriptorProto()
+    file_descriptor.ParseFromString(self._GetSerializedFileDescriptor('C'))
+    msg_descriptor = descriptor.MakeDescriptor(
+        file_descriptor.message_type[0])
+    msg_class = reflection.MakeClass(msg_descriptor)
+    msg = msg_class()
+    msg_str = (
+        'bar {'
+        '  baz {'
+        '    deep: 4'
+        '  }'
+        '}')
+    text_format.Merge(msg_str, msg)
+    self.assertEqual(msg.bar.baz.deep, 4)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py
new file mode 100644
index 0000000..8e72213
--- /dev/null
+++ b/python/google/protobuf/internal/service_reflection_test.py
@@ -0,0 +1,139 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests for google.protobuf.internal.service_reflection."""
+
+__author__ = 'petar@google.com (Petar Petrov)'
+
+
+import unittest
+
+from google.protobuf import unittest_pb2
+from google.protobuf import service_reflection
+from google.protobuf import service
+
+
+class FooUnitTest(unittest.TestCase):
+
+  def testService(self):
+    class MockRpcChannel(service.RpcChannel):
+      def CallMethod(self, method, controller, request, response, callback):
+        self.method = method
+        self.controller = controller
+        self.request = request
+        callback(response)
+
+    class MockRpcController(service.RpcController):
+      def SetFailed(self, msg):
+        self.failure_message = msg
+
+    self.callback_response = None
+
+    class MyService(unittest_pb2.TestService):
+      pass
+
+    self.callback_response = None
+
+    def MyCallback(response):
+      self.callback_response = response
+
+    rpc_controller = MockRpcController()
+    channel = MockRpcChannel()
+    srvc = MyService()
+    srvc.Foo(rpc_controller, unittest_pb2.FooRequest(), MyCallback)
+    self.assertEqual('Method Foo not implemented.',
+                     rpc_controller.failure_message)
+    self.assertEqual(None, self.callback_response)
+
+    rpc_controller.failure_message = None
+
+    service_descriptor = unittest_pb2.TestService.GetDescriptor()
+    srvc.CallMethod(service_descriptor.methods[1], rpc_controller,
+                    unittest_pb2.BarRequest(), MyCallback)
+    self.assertTrue(srvc.GetRequestClass(service_descriptor.methods[1]) is
+                    unittest_pb2.BarRequest)
+    self.assertTrue(srvc.GetResponseClass(service_descriptor.methods[1]) is
+                    unittest_pb2.BarResponse)
+    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
+      def Bar(self, rpc_controller, request, done):
+        self.bar_called = True
+
+    srvc = MyServiceImpl()
+    rpc_controller.failure_message = None
+    srvc.Foo(rpc_controller, unittest_pb2.FooRequest(), MyCallback)
+    self.assertEqual(None, rpc_controller.failure_message)
+    self.assertEqual(True, srvc.foo_called)
+
+    rpc_controller.failure_message = None
+    srvc.CallMethod(service_descriptor.methods[1], rpc_controller,
+                    unittest_pb2.BarRequest(), MyCallback)
+    self.assertEqual(None, rpc_controller.failure_message)
+    self.assertEqual(True, srvc.bar_called)
+
+  def testServiceStub(self):
+    class MockRpcChannel(service.RpcChannel):
+      def CallMethod(self, method, controller, request,
+                     response_class, callback):
+        self.method = method
+        self.controller = controller
+        self.request = request
+        callback(response_class())
+
+    self.callback_response = None
+
+    def MyCallback(response):
+      self.callback_response = response
+
+    channel = MockRpcChannel()
+    stub = unittest_pb2.TestService_Stub(channel)
+    rpc_controller = 'controller'
+    request = 'request'
+
+    # GetDescriptor now static, still works as instance method for compatibility
+    self.assertEqual(unittest_pb2.TestService_Stub.GetDescriptor(),
+                     stub.GetDescriptor())
+
+    # Invoke method.
+    stub.Foo(rpc_controller, request, MyCallback)
+
+    self.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__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
new file mode 100644
index 0000000..4fdc4ee
--- /dev/null
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -0,0 +1,133 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests for google.protobuf.symbol_database."""
+
+import unittest
+
+from google.protobuf import unittest_pb2
+from google.protobuf import descriptor
+from google.protobuf import descriptor_pool
+from google.protobuf import symbol_database
+
+
+class SymbolDatabaseTest(unittest.TestCase):
+
+  def _Database(self):
+    if descriptor._USE_C_DESCRIPTORS:
+      # The C++ implementation does not allow mixing descriptors from
+      # different pools.
+      db = symbol_database.SymbolDatabase(pool=descriptor_pool.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)
+    db.RegisterServiceDescriptor(unittest_pb2._TESTSERVICE)
+    return db
+
+  def testGetPrototype(self):
+    instance = self._Database().GetPrototype(
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertTrue(instance is unittest_pb2.TestAllTypes)
+
+  def testGetMessages(self):
+    messages = self._Database().GetMessages(
+        ['google/protobuf/unittest.proto'])
+    self.assertTrue(
+        unittest_pb2.TestAllTypes is
+        messages['protobuf_unittest.TestAllTypes'])
+
+  def testGetSymbol(self):
+    self.assertEqual(
+        unittest_pb2.TestAllTypes, self._Database().GetSymbol(
+            'protobuf_unittest.TestAllTypes'))
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.NestedMessage, self._Database().GetSymbol(
+            'protobuf_unittest.TestAllTypes.NestedMessage'))
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.OptionalGroup, self._Database().GetSymbol(
+            'protobuf_unittest.TestAllTypes.OptionalGroup'))
+    self.assertEqual(
+        unittest_pb2.TestAllTypes.RepeatedGroup, self._Database().GetSymbol(
+            'protobuf_unittest.TestAllTypes.RepeatedGroup'))
+
+  def testEnums(self):
+    # Check registration of types in the pool.
+    self.assertEqual(
+        'protobuf_unittest.ForeignEnum',
+        self._Database().pool.FindEnumTypeByName(
+            'protobuf_unittest.ForeignEnum').full_name)
+    self.assertEqual(
+        'protobuf_unittest.TestAllTypes.NestedEnum',
+        self._Database().pool.FindEnumTypeByName(
+            'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
+
+  def testFindMessageTypeByName(self):
+    self.assertEqual(
+        'protobuf_unittest.TestAllTypes',
+        self._Database().pool.FindMessageTypeByName(
+            'protobuf_unittest.TestAllTypes').full_name)
+    self.assertEqual(
+        'protobuf_unittest.TestAllTypes.NestedMessage',
+        self._Database().pool.FindMessageTypeByName(
+            'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
+
+  def testFindServiceByName(self):
+    self.assertEqual(
+        'protobuf_unittest.TestService',
+        self._Database().pool.FindServiceByName(
+            'protobuf_unittest.TestService').full_name)
+
+  def testFindFileContainingSymbol(self):
+    # Lookup based on either enum or message.
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        self._Database().pool.FindFileContainingSymbol(
+            'protobuf_unittest.TestAllTypes.NestedEnum').name)
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        self._Database().pool.FindFileContainingSymbol(
+            'protobuf_unittest.TestAllTypes').name)
+
+  def testFindFileByName(self):
+    self.assertEqual(
+        'google/protobuf/unittest.proto',
+        self._Database().pool.FindFileByName(
+            'google/protobuf/unittest.proto').name)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/test_bad_identifiers.proto b/python/google/protobuf/internal/test_bad_identifiers.proto
new file mode 100644
index 0000000..caf86b5
--- /dev/null
+++ b/python/google/protobuf/internal/test_bad_identifiers.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option py_generic_services = true;
+
+message TestBadIdentifiers {
+  extensions 100 to max;
+}
+
+// Make sure these reasonable extension names don't conflict with internal
+// variables.
+extend TestBadIdentifiers {
+  optional string message = 100 [default = "foo"];
+  optional string descriptor = 101 [default = "bar"];
+  optional string reflection = 102 [default = "baz"];
+  optional string service = 103 [default = "qux"];
+}
+
+message AnotherMessage {}
+service AnotherService {}
diff --git a/python/google/protobuf/internal/test_proto3_optional.proto b/python/google/protobuf/internal/test_proto3_optional.proto
new file mode 100644
index 0000000..f3e0a2e
--- /dev/null
+++ b/python/google/protobuf/internal/test_proto3_optional.proto
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf.python.internal;
+
+message TestProto3Optional {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    UNSPECIFIED = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  optional int32 optional_int32 = 1;
+  optional int64 optional_int64 = 2;
+  optional uint32 optional_uint32 = 3;
+  optional uint64 optional_uint64 = 4;
+  optional sint32 optional_sint32 = 5;
+  optional sint64 optional_sint64 = 6;
+  optional fixed32 optional_fixed32 = 7;
+  optional fixed64 optional_fixed64 = 8;
+  optional sfixed32 optional_sfixed32 = 9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional float optional_float = 11;
+  optional double optional_double = 12;
+  optional bool optional_bool = 13;
+  optional string optional_string = 14;
+  optional bytes optional_bytes = 15;
+
+  optional NestedMessage optional_nested_message = 18;
+  optional NestedEnum optional_nested_enum = 21;
+}
diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py
new file mode 100644
index 0000000..32fb8fd
--- /dev/null
+++ b/python/google/protobuf/internal/test_util.py
@@ -0,0 +1,878 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Utilities for Python proto2 tests.
+
+This is intentionally modeled on C++ code in
+//google/protobuf/test_util.*.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import numbers
+import operator
+import os.path
+
+from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_pb2
+
+try:
+  long        # Python 2
+except NameError:
+  long = int  # Python 3
+
+
+# Tests whether the given TestAllTypes message is proto2 or not.
+# This is used to gate several fields/features that only exist
+# for the proto2 version of the message.
+def IsProto2(message):
+  return message.DESCRIPTOR.syntax == "proto2"
+
+
+def SetAllNonLazyFields(message):
+  """Sets every non-lazy field in the message to a unique value.
+
+  Args:
+    message: A TestAllTypes instance.
+  """
+
+  #
+  # Optional fields.
+  #
+
+  message.optional_int32    = 101
+  message.optional_int64    = 102
+  message.optional_uint32   = 103
+  message.optional_uint64   = 104
+  message.optional_sint32   = 105
+  message.optional_sint64   = 106
+  message.optional_fixed32  = 107
+  message.optional_fixed64  = 108
+  message.optional_sfixed32 = 109
+  message.optional_sfixed64 = 110
+  message.optional_float    = 111
+  message.optional_double   = 112
+  message.optional_bool     = True
+  message.optional_string   = u'115'
+  message.optional_bytes    = b'116'
+
+  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
+  message.optional_public_import_message.e = 126
+
+  message.optional_nested_enum = unittest_pb2.TestAllTypes.BAZ
+  message.optional_foreign_enum = unittest_pb2.FOREIGN_BAZ
+  if IsProto2(message):
+    message.optional_import_enum = unittest_import_pb2.IMPORT_BAZ
+
+  message.optional_string_piece = u'124'
+  message.optional_cord = u'125'
+
+  #
+  # Repeated fields.
+  #
+
+  message.repeated_int32.append(201)
+  message.repeated_int64.append(202)
+  message.repeated_uint32.append(203)
+  message.repeated_uint64.append(204)
+  message.repeated_sint32.append(205)
+  message.repeated_sint64.append(206)
+  message.repeated_fixed32.append(207)
+  message.repeated_fixed64.append(208)
+  message.repeated_sfixed32.append(209)
+  message.repeated_sfixed64.append(210)
+  message.repeated_float.append(211)
+  message.repeated_double.append(212)
+  message.repeated_bool.append(True)
+  message.repeated_string.append(u'215')
+  message.repeated_bytes.append(b'216')
+
+  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
+  message.repeated_lazy_message.add().bb = 227
+
+  message.repeated_nested_enum.append(unittest_pb2.TestAllTypes.BAR)
+  message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR)
+  if IsProto2(message):
+    message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAR)
+
+  message.repeated_string_piece.append(u'224')
+  message.repeated_cord.append(u'225')
+
+  # Add a second one of each field and set value by index.
+  message.repeated_int32.append(0)
+  message.repeated_int64.append(0)
+  message.repeated_uint32.append(0)
+  message.repeated_uint64.append(0)
+  message.repeated_sint32.append(0)
+  message.repeated_sint64.append(0)
+  message.repeated_fixed32.append(0)
+  message.repeated_fixed64.append(0)
+  message.repeated_sfixed32.append(0)
+  message.repeated_sfixed64.append(0)
+  message.repeated_float.append(0)
+  message.repeated_double.append(0)
+  message.repeated_bool.append(True)
+  message.repeated_string.append(u'0')
+  message.repeated_bytes.append(b'0')
+  message.repeated_int32[1] = 301
+  message.repeated_int64[1] = 302
+  message.repeated_uint32[1] = 303
+  message.repeated_uint64[1] = 304
+  message.repeated_sint32[1] = 305
+  message.repeated_sint64[1] = 306
+  message.repeated_fixed32[1] = 307
+  message.repeated_fixed64[1] = 308
+  message.repeated_sfixed32[1] = 309
+  message.repeated_sfixed64[1] = 310
+  message.repeated_float[1] = 311
+  message.repeated_double[1] = 312
+  message.repeated_bool[1] = False
+  message.repeated_string[1] = u'315'
+  message.repeated_bytes[1] = b'316'
+
+  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
+  message.repeated_lazy_message.add().bb = 327
+
+  message.repeated_nested_enum.append(unittest_pb2.TestAllTypes.BAR)
+  message.repeated_nested_enum[1] = unittest_pb2.TestAllTypes.BAZ
+  message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ)
+  if IsProto2(message):
+    message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAZ)
+
+  message.repeated_string_piece.append(u'324')
+  message.repeated_cord.append(u'325')
+
+  #
+  # Fields that have defaults.
+  #
+
+  if IsProto2(message):
+    message.default_int32 = 401
+    message.default_int64 = 402
+    message.default_uint32 = 403
+    message.default_uint64 = 404
+    message.default_sint32 = 405
+    message.default_sint64 = 406
+    message.default_fixed32 = 407
+    message.default_fixed64 = 408
+    message.default_sfixed32 = 409
+    message.default_sfixed64 = 410
+    message.default_float = 411
+    message.default_double = 412
+    message.default_bool = False
+    message.default_string = '415'
+    message.default_bytes = b'416'
+
+    message.default_nested_enum = unittest_pb2.TestAllTypes.FOO
+    message.default_foreign_enum = unittest_pb2.FOREIGN_FOO
+    message.default_import_enum = unittest_import_pb2.IMPORT_FOO
+
+    message.default_string_piece = '424'
+    message.default_cord = '425'
+
+  message.oneof_uint32 = 601
+  message.oneof_nested_message.bb = 602
+  message.oneof_string = '603'
+  message.oneof_bytes = b'604'
+
+
+def SetAllFields(message):
+  SetAllNonLazyFields(message)
+  message.optional_lazy_message.bb = 127
+  message.optional_unverified_lazy_message.bb = 128
+
+
+def SetAllExtensions(message):
+  """Sets every extension in the message to a unique value.
+
+  Args:
+    message: A unittest_pb2.TestAllExtensions instance.
+  """
+
+  extensions = message.Extensions
+  pb2 = unittest_pb2
+  import_pb2 = unittest_import_pb2
+
+  #
+  # Optional fields.
+  #
+
+  extensions[pb2.optional_int32_extension] = 101
+  extensions[pb2.optional_int64_extension] = 102
+  extensions[pb2.optional_uint32_extension] = 103
+  extensions[pb2.optional_uint64_extension] = 104
+  extensions[pb2.optional_sint32_extension] = 105
+  extensions[pb2.optional_sint64_extension] = 106
+  extensions[pb2.optional_fixed32_extension] = 107
+  extensions[pb2.optional_fixed64_extension] = 108
+  extensions[pb2.optional_sfixed32_extension] = 109
+  extensions[pb2.optional_sfixed64_extension] = 110
+  extensions[pb2.optional_float_extension] = 111
+  extensions[pb2.optional_double_extension] = 112
+  extensions[pb2.optional_bool_extension] = True
+  extensions[pb2.optional_string_extension] = u'115'
+  extensions[pb2.optional_bytes_extension] = b'116'
+
+  extensions[pb2.optionalgroup_extension].a = 117
+  extensions[pb2.optional_nested_message_extension].bb = 118
+  extensions[pb2.optional_foreign_message_extension].c = 119
+  extensions[pb2.optional_import_message_extension].d = 120
+  extensions[pb2.optional_public_import_message_extension].e = 126
+  extensions[pb2.optional_lazy_message_extension].bb = 127
+  extensions[pb2.optional_unverified_lazy_message_extension].bb = 128
+
+  extensions[pb2.optional_nested_enum_extension] = pb2.TestAllTypes.BAZ
+  extensions[pb2.optional_nested_enum_extension] = pb2.TestAllTypes.BAZ
+  extensions[pb2.optional_foreign_enum_extension] = pb2.FOREIGN_BAZ
+  extensions[pb2.optional_import_enum_extension] = import_pb2.IMPORT_BAZ
+
+  extensions[pb2.optional_string_piece_extension] = u'124'
+  extensions[pb2.optional_cord_extension] = u'125'
+
+  #
+  # Repeated fields.
+  #
+
+  extensions[pb2.repeated_int32_extension].append(201)
+  extensions[pb2.repeated_int64_extension].append(202)
+  extensions[pb2.repeated_uint32_extension].append(203)
+  extensions[pb2.repeated_uint64_extension].append(204)
+  extensions[pb2.repeated_sint32_extension].append(205)
+  extensions[pb2.repeated_sint64_extension].append(206)
+  extensions[pb2.repeated_fixed32_extension].append(207)
+  extensions[pb2.repeated_fixed64_extension].append(208)
+  extensions[pb2.repeated_sfixed32_extension].append(209)
+  extensions[pb2.repeated_sfixed64_extension].append(210)
+  extensions[pb2.repeated_float_extension].append(211)
+  extensions[pb2.repeated_double_extension].append(212)
+  extensions[pb2.repeated_bool_extension].append(True)
+  extensions[pb2.repeated_string_extension].append(u'215')
+  extensions[pb2.repeated_bytes_extension].append(b'216')
+
+  extensions[pb2.repeatedgroup_extension].add().a = 217
+  extensions[pb2.repeated_nested_message_extension].add().bb = 218
+  extensions[pb2.repeated_foreign_message_extension].add().c = 219
+  extensions[pb2.repeated_import_message_extension].add().d = 220
+  extensions[pb2.repeated_lazy_message_extension].add().bb = 227
+
+  extensions[pb2.repeated_nested_enum_extension].append(pb2.TestAllTypes.BAR)
+  extensions[pb2.repeated_foreign_enum_extension].append(pb2.FOREIGN_BAR)
+  extensions[pb2.repeated_import_enum_extension].append(import_pb2.IMPORT_BAR)
+
+  extensions[pb2.repeated_string_piece_extension].append(u'224')
+  extensions[pb2.repeated_cord_extension].append(u'225')
+
+  # Append a second one of each field.
+  extensions[pb2.repeated_int32_extension].append(301)
+  extensions[pb2.repeated_int64_extension].append(302)
+  extensions[pb2.repeated_uint32_extension].append(303)
+  extensions[pb2.repeated_uint64_extension].append(304)
+  extensions[pb2.repeated_sint32_extension].append(305)
+  extensions[pb2.repeated_sint64_extension].append(306)
+  extensions[pb2.repeated_fixed32_extension].append(307)
+  extensions[pb2.repeated_fixed64_extension].append(308)
+  extensions[pb2.repeated_sfixed32_extension].append(309)
+  extensions[pb2.repeated_sfixed64_extension].append(310)
+  extensions[pb2.repeated_float_extension].append(311)
+  extensions[pb2.repeated_double_extension].append(312)
+  extensions[pb2.repeated_bool_extension].append(False)
+  extensions[pb2.repeated_string_extension].append(u'315')
+  extensions[pb2.repeated_bytes_extension].append(b'316')
+
+  extensions[pb2.repeatedgroup_extension].add().a = 317
+  extensions[pb2.repeated_nested_message_extension].add().bb = 318
+  extensions[pb2.repeated_foreign_message_extension].add().c = 319
+  extensions[pb2.repeated_import_message_extension].add().d = 320
+  extensions[pb2.repeated_lazy_message_extension].add().bb = 327
+
+  extensions[pb2.repeated_nested_enum_extension].append(pb2.TestAllTypes.BAZ)
+  extensions[pb2.repeated_foreign_enum_extension].append(pb2.FOREIGN_BAZ)
+  extensions[pb2.repeated_import_enum_extension].append(import_pb2.IMPORT_BAZ)
+
+  extensions[pb2.repeated_string_piece_extension].append(u'324')
+  extensions[pb2.repeated_cord_extension].append(u'325')
+
+  #
+  # Fields with defaults.
+  #
+
+  extensions[pb2.default_int32_extension] = 401
+  extensions[pb2.default_int64_extension] = 402
+  extensions[pb2.default_uint32_extension] = 403
+  extensions[pb2.default_uint64_extension] = 404
+  extensions[pb2.default_sint32_extension] = 405
+  extensions[pb2.default_sint64_extension] = 406
+  extensions[pb2.default_fixed32_extension] = 407
+  extensions[pb2.default_fixed64_extension] = 408
+  extensions[pb2.default_sfixed32_extension] = 409
+  extensions[pb2.default_sfixed64_extension] = 410
+  extensions[pb2.default_float_extension] = 411
+  extensions[pb2.default_double_extension] = 412
+  extensions[pb2.default_bool_extension] = False
+  extensions[pb2.default_string_extension] = u'415'
+  extensions[pb2.default_bytes_extension] = b'416'
+
+  extensions[pb2.default_nested_enum_extension] = pb2.TestAllTypes.FOO
+  extensions[pb2.default_foreign_enum_extension] = pb2.FOREIGN_FOO
+  extensions[pb2.default_import_enum_extension] = import_pb2.IMPORT_FOO
+
+  extensions[pb2.default_string_piece_extension] = u'424'
+  extensions[pb2.default_cord_extension] = '425'
+
+  extensions[pb2.oneof_uint32_extension] = 601
+  extensions[pb2.oneof_nested_message_extension].bb = 602
+  extensions[pb2.oneof_string_extension] = u'603'
+  extensions[pb2.oneof_bytes_extension] = b'604'
+
+
+def SetAllFieldsAndExtensions(message):
+  """Sets every field and extension in the message to a unique value.
+
+  Args:
+    message: A unittest_pb2.TestAllExtensions message.
+  """
+  message.my_int = 1
+  message.my_string = 'foo'
+  message.my_float = 1.0
+  message.Extensions[unittest_pb2.my_extension_int] = 23
+  message.Extensions[unittest_pb2.my_extension_string] = 'bar'
+
+
+def ExpectAllFieldsAndExtensionsInOrder(serialized):
+  """Ensures that serialized is the serialization we expect for a message
+  filled with SetAllFieldsAndExtensions().  (Specifically, ensures that the
+  serialization is in canonical, tag-number order).
+  """
+  my_extension_int = unittest_pb2.my_extension_int
+  my_extension_string = unittest_pb2.my_extension_string
+  expected_strings = []
+  message = unittest_pb2.TestFieldOrderings()
+  message.my_int = 1  # Field 1.
+  expected_strings.append(message.SerializeToString())
+  message.Clear()
+  message.Extensions[my_extension_int] = 23  # Field 5.
+  expected_strings.append(message.SerializeToString())
+  message.Clear()
+  message.my_string = 'foo'  # Field 11.
+  expected_strings.append(message.SerializeToString())
+  message.Clear()
+  message.Extensions[my_extension_string] = 'bar'  # Field 50.
+  expected_strings.append(message.SerializeToString())
+  message.Clear()
+  message.my_float = 1.0
+  expected_strings.append(message.SerializeToString())
+  message.Clear()
+  expected = b''.join(expected_strings)
+
+  if expected != serialized:
+    raise ValueError('Expected %r, found %r' % (expected, serialized))
+
+
+def ExpectAllFieldsSet(test_case, message):
+  """Check all fields for correct values have after Set*Fields() is called."""
+  test_case.assertTrue(message.HasField('optional_int32'))
+  test_case.assertTrue(message.HasField('optional_int64'))
+  test_case.assertTrue(message.HasField('optional_uint32'))
+  test_case.assertTrue(message.HasField('optional_uint64'))
+  test_case.assertTrue(message.HasField('optional_sint32'))
+  test_case.assertTrue(message.HasField('optional_sint64'))
+  test_case.assertTrue(message.HasField('optional_fixed32'))
+  test_case.assertTrue(message.HasField('optional_fixed64'))
+  test_case.assertTrue(message.HasField('optional_sfixed32'))
+  test_case.assertTrue(message.HasField('optional_sfixed64'))
+  test_case.assertTrue(message.HasField('optional_float'))
+  test_case.assertTrue(message.HasField('optional_double'))
+  test_case.assertTrue(message.HasField('optional_bool'))
+  test_case.assertTrue(message.HasField('optional_string'))
+  test_case.assertTrue(message.HasField('optional_bytes'))
+
+  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'))
+
+  test_case.assertTrue(message.optionalgroup.HasField('a'))
+  test_case.assertTrue(message.optional_nested_message.HasField('bb'))
+  test_case.assertTrue(message.optional_foreign_message.HasField('c'))
+  test_case.assertTrue(message.optional_import_message.HasField('d'))
+
+  test_case.assertTrue(message.HasField('optional_nested_enum'))
+  test_case.assertTrue(message.HasField('optional_foreign_enum'))
+  if IsProto2(message):
+    test_case.assertTrue(message.HasField('optional_import_enum'))
+
+  test_case.assertTrue(message.HasField('optional_string_piece'))
+  test_case.assertTrue(message.HasField('optional_cord'))
+
+  test_case.assertEqual(101, message.optional_int32)
+  test_case.assertEqual(102, message.optional_int64)
+  test_case.assertEqual(103, message.optional_uint32)
+  test_case.assertEqual(104, message.optional_uint64)
+  test_case.assertEqual(105, message.optional_sint32)
+  test_case.assertEqual(106, message.optional_sint64)
+  test_case.assertEqual(107, message.optional_fixed32)
+  test_case.assertEqual(108, message.optional_fixed64)
+  test_case.assertEqual(109, message.optional_sfixed32)
+  test_case.assertEqual(110, message.optional_sfixed64)
+  test_case.assertEqual(111, message.optional_float)
+  test_case.assertEqual(112, message.optional_double)
+  test_case.assertEqual(True, message.optional_bool)
+  test_case.assertEqual('115', message.optional_string)
+  test_case.assertEqual(b'116', message.optional_bytes)
+
+  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)
+  test_case.assertEqual(126, message.optional_public_import_message.e)
+  test_case.assertEqual(127, message.optional_lazy_message.bb)
+  test_case.assertEqual(128, message.optional_unverified_lazy_message.bb)
+
+  test_case.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                        message.optional_nested_enum)
+  test_case.assertEqual(unittest_pb2.FOREIGN_BAZ,
+                        message.optional_foreign_enum)
+  if IsProto2(message):
+    test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+                          message.optional_import_enum)
+
+  # -----------------------------------------------------------------
+
+  test_case.assertEqual(2, len(message.repeated_int32))
+  test_case.assertEqual(2, len(message.repeated_int64))
+  test_case.assertEqual(2, len(message.repeated_uint32))
+  test_case.assertEqual(2, len(message.repeated_uint64))
+  test_case.assertEqual(2, len(message.repeated_sint32))
+  test_case.assertEqual(2, len(message.repeated_sint64))
+  test_case.assertEqual(2, len(message.repeated_fixed32))
+  test_case.assertEqual(2, len(message.repeated_fixed64))
+  test_case.assertEqual(2, len(message.repeated_sfixed32))
+  test_case.assertEqual(2, len(message.repeated_sfixed64))
+  test_case.assertEqual(2, len(message.repeated_float))
+  test_case.assertEqual(2, len(message.repeated_double))
+  test_case.assertEqual(2, len(message.repeated_bool))
+  test_case.assertEqual(2, len(message.repeated_string))
+  test_case.assertEqual(2, len(message.repeated_bytes))
+
+  if IsProto2(message):
+    test_case.assertEqual(2, len(message.repeatedgroup))
+  test_case.assertEqual(2, len(message.repeated_nested_message))
+  test_case.assertEqual(2, len(message.repeated_foreign_message))
+  test_case.assertEqual(2, len(message.repeated_import_message))
+  test_case.assertEqual(2, len(message.repeated_nested_enum))
+  test_case.assertEqual(2, len(message.repeated_foreign_enum))
+  if IsProto2(message):
+    test_case.assertEqual(2, len(message.repeated_import_enum))
+
+  test_case.assertEqual(2, len(message.repeated_string_piece))
+  test_case.assertEqual(2, len(message.repeated_cord))
+
+  test_case.assertEqual(201, message.repeated_int32[0])
+  test_case.assertEqual(202, message.repeated_int64[0])
+  test_case.assertEqual(203, message.repeated_uint32[0])
+  test_case.assertEqual(204, message.repeated_uint64[0])
+  test_case.assertEqual(205, message.repeated_sint32[0])
+  test_case.assertEqual(206, message.repeated_sint64[0])
+  test_case.assertEqual(207, message.repeated_fixed32[0])
+  test_case.assertEqual(208, message.repeated_fixed64[0])
+  test_case.assertEqual(209, message.repeated_sfixed32[0])
+  test_case.assertEqual(210, message.repeated_sfixed64[0])
+  test_case.assertEqual(211, message.repeated_float[0])
+  test_case.assertEqual(212, message.repeated_double[0])
+  test_case.assertEqual(True, message.repeated_bool[0])
+  test_case.assertEqual('215', message.repeated_string[0])
+  test_case.assertEqual(b'216', message.repeated_bytes[0])
+
+  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)
+  test_case.assertEqual(227, message.repeated_lazy_message[0].bb)
+
+  test_case.assertEqual(unittest_pb2.TestAllTypes.BAR,
+                        message.repeated_nested_enum[0])
+  test_case.assertEqual(unittest_pb2.FOREIGN_BAR,
+                        message.repeated_foreign_enum[0])
+  if IsProto2(message):
+    test_case.assertEqual(unittest_import_pb2.IMPORT_BAR,
+                          message.repeated_import_enum[0])
+
+  test_case.assertEqual(301, message.repeated_int32[1])
+  test_case.assertEqual(302, message.repeated_int64[1])
+  test_case.assertEqual(303, message.repeated_uint32[1])
+  test_case.assertEqual(304, message.repeated_uint64[1])
+  test_case.assertEqual(305, message.repeated_sint32[1])
+  test_case.assertEqual(306, message.repeated_sint64[1])
+  test_case.assertEqual(307, message.repeated_fixed32[1])
+  test_case.assertEqual(308, message.repeated_fixed64[1])
+  test_case.assertEqual(309, message.repeated_sfixed32[1])
+  test_case.assertEqual(310, message.repeated_sfixed64[1])
+  test_case.assertEqual(311, message.repeated_float[1])
+  test_case.assertEqual(312, message.repeated_double[1])
+  test_case.assertEqual(False, message.repeated_bool[1])
+  test_case.assertEqual('315', message.repeated_string[1])
+  test_case.assertEqual(b'316', message.repeated_bytes[1])
+
+  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)
+  test_case.assertEqual(327, message.repeated_lazy_message[1].bb)
+
+  test_case.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                        message.repeated_nested_enum[1])
+  test_case.assertEqual(unittest_pb2.FOREIGN_BAZ,
+                        message.repeated_foreign_enum[1])
+  if IsProto2(message):
+    test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+                          message.repeated_import_enum[1])
+
+  # -----------------------------------------------------------------
+
+  if IsProto2(message):
+    test_case.assertTrue(message.HasField('default_int32'))
+    test_case.assertTrue(message.HasField('default_int64'))
+    test_case.assertTrue(message.HasField('default_uint32'))
+    test_case.assertTrue(message.HasField('default_uint64'))
+    test_case.assertTrue(message.HasField('default_sint32'))
+    test_case.assertTrue(message.HasField('default_sint64'))
+    test_case.assertTrue(message.HasField('default_fixed32'))
+    test_case.assertTrue(message.HasField('default_fixed64'))
+    test_case.assertTrue(message.HasField('default_sfixed32'))
+    test_case.assertTrue(message.HasField('default_sfixed64'))
+    test_case.assertTrue(message.HasField('default_float'))
+    test_case.assertTrue(message.HasField('default_double'))
+    test_case.assertTrue(message.HasField('default_bool'))
+    test_case.assertTrue(message.HasField('default_string'))
+    test_case.assertTrue(message.HasField('default_bytes'))
+
+    test_case.assertTrue(message.HasField('default_nested_enum'))
+    test_case.assertTrue(message.HasField('default_foreign_enum'))
+    test_case.assertTrue(message.HasField('default_import_enum'))
+
+    test_case.assertEqual(401, message.default_int32)
+    test_case.assertEqual(402, message.default_int64)
+    test_case.assertEqual(403, message.default_uint32)
+    test_case.assertEqual(404, message.default_uint64)
+    test_case.assertEqual(405, message.default_sint32)
+    test_case.assertEqual(406, message.default_sint64)
+    test_case.assertEqual(407, message.default_fixed32)
+    test_case.assertEqual(408, message.default_fixed64)
+    test_case.assertEqual(409, message.default_sfixed32)
+    test_case.assertEqual(410, message.default_sfixed64)
+    test_case.assertEqual(411, message.default_float)
+    test_case.assertEqual(412, message.default_double)
+    test_case.assertEqual(False, message.default_bool)
+    test_case.assertEqual('415', message.default_string)
+    test_case.assertEqual(b'416', message.default_bytes)
+
+    test_case.assertEqual(unittest_pb2.TestAllTypes.FOO,
+                          message.default_nested_enum)
+    test_case.assertEqual(unittest_pb2.FOREIGN_FOO,
+                          message.default_foreign_enum)
+    test_case.assertEqual(unittest_import_pb2.IMPORT_FOO,
+                          message.default_import_enum)
+
+
+def GoldenFile(filename):
+  """Finds the given golden file and returns a file object representing it."""
+
+  # Search up the directory tree looking for the C++ protobuf source code.
+  path = '.'
+  while os.path.exists(path):
+    if os.path.exists(os.path.join(path, 'src/google/protobuf')):
+      # Found it.  Load the golden file from the testdata directory.
+      full_path = os.path.join(path, 'src/google/protobuf/testdata', filename)
+      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')
+
+  # Search for cross-repo path.
+  full_path = os.path.join('external/com_google_protobuf/src/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 '
+      'C++ source tree.')
+
+
+def GoldenFileData(filename):
+  """Finds the given golden file and returns its contents."""
+  with GoldenFile(filename) as f:
+    return f.read()
+
+
+def SetAllPackedFields(message):
+  """Sets every field in the message to a unique value.
+
+  Args:
+    message: A TestPackedTypes instance.
+  """
+  message.packed_int32.extend([601, 701])
+  message.packed_int64.extend([602, 702])
+  message.packed_uint32.extend([603, 703])
+  message.packed_uint64.extend([604, 704])
+  message.packed_sint32.extend([605, 705])
+  message.packed_sint64.extend([606, 706])
+  message.packed_fixed32.extend([607, 707])
+  message.packed_fixed64.extend([608, 708])
+  message.packed_sfixed32.extend([609, 709])
+  message.packed_sfixed64.extend([610, 710])
+  message.packed_float.extend([611.0, 711.0])
+  message.packed_double.extend([612.0, 712.0])
+  message.packed_bool.extend([True, False])
+  message.packed_enum.extend([unittest_pb2.FOREIGN_BAR,
+                              unittest_pb2.FOREIGN_BAZ])
+
+
+def SetAllPackedExtensions(message):
+  """Sets every extension in the message to a unique value.
+
+  Args:
+    message: A unittest_pb2.TestPackedExtensions instance.
+  """
+  extensions = message.Extensions
+  pb2 = unittest_pb2
+
+  extensions[pb2.packed_int32_extension].extend([601, 701])
+  extensions[pb2.packed_int64_extension].extend([602, 702])
+  extensions[pb2.packed_uint32_extension].extend([603, 703])
+  extensions[pb2.packed_uint64_extension].extend([604, 704])
+  extensions[pb2.packed_sint32_extension].extend([605, 705])
+  extensions[pb2.packed_sint64_extension].extend([606, 706])
+  extensions[pb2.packed_fixed32_extension].extend([607, 707])
+  extensions[pb2.packed_fixed64_extension].extend([608, 708])
+  extensions[pb2.packed_sfixed32_extension].extend([609, 709])
+  extensions[pb2.packed_sfixed64_extension].extend([610, 710])
+  extensions[pb2.packed_float_extension].extend([611.0, 711.0])
+  extensions[pb2.packed_double_extension].extend([612.0, 712.0])
+  extensions[pb2.packed_bool_extension].extend([True, False])
+  extensions[pb2.packed_enum_extension].extend([unittest_pb2.FOREIGN_BAR,
+                                                unittest_pb2.FOREIGN_BAZ])
+
+
+def SetAllUnpackedFields(message):
+  """Sets every field in the message to a unique value.
+
+  Args:
+    message: A unittest_pb2.TestUnpackedTypes instance.
+  """
+  message.unpacked_int32.extend([601, 701])
+  message.unpacked_int64.extend([602, 702])
+  message.unpacked_uint32.extend([603, 703])
+  message.unpacked_uint64.extend([604, 704])
+  message.unpacked_sint32.extend([605, 705])
+  message.unpacked_sint64.extend([606, 706])
+  message.unpacked_fixed32.extend([607, 707])
+  message.unpacked_fixed64.extend([608, 708])
+  message.unpacked_sfixed32.extend([609, 709])
+  message.unpacked_sfixed64.extend([610, 710])
+  message.unpacked_float.extend([611.0, 711.0])
+  message.unpacked_double.extend([612.0, 712.0])
+  message.unpacked_bool.extend([True, False])
+  message.unpacked_enum.extend([unittest_pb2.FOREIGN_BAR,
+                                unittest_pb2.FOREIGN_BAZ])
+
+
+class NonStandardInteger(numbers.Integral):
+  """An integer object that does not subclass int.
+
+  This is used to verify that both C++ and regular proto systems can handle
+  integer others than int and long and that they handle them in predictable
+  ways.
+
+  NonStandardInteger is the minimal legal specification for a custom Integral.
+  As such, it does not support 0 < x < 5 and it is not hashable.
+
+  Note: This is added here instead of relying on numpy or a similar library
+  with custom integers to limit dependencies.
+  """
+
+  def __init__(self, val, error_string_on_conversion=None):
+    assert isinstance(val, numbers.Integral)
+    if isinstance(val, NonStandardInteger):
+      val = val.val
+    self.val = val
+    self.error_string_on_conversion = error_string_on_conversion
+
+  def __long__(self):
+    if self.error_string_on_conversion:
+      raise RuntimeError(self.error_string_on_conversion)
+    return long(self.val)
+
+  def __abs__(self):
+    return NonStandardInteger(operator.abs(self.val))
+
+  def __add__(self, y):
+    return NonStandardInteger(operator.add(self.val, y))
+
+  def __div__(self, y):
+    return NonStandardInteger(operator.div(self.val, y))
+
+  def __eq__(self, y):
+    return operator.eq(self.val, y)
+
+  def __floordiv__(self, y):
+    return NonStandardInteger(operator.floordiv(self.val, y))
+
+  def __truediv__(self, y):
+    return NonStandardInteger(operator.truediv(self.val, y))
+
+  def __invert__(self):
+    return NonStandardInteger(operator.invert(self.val))
+
+  def __mod__(self, y):
+    return NonStandardInteger(operator.mod(self.val, y))
+
+  def __mul__(self, y):
+    return NonStandardInteger(operator.mul(self.val, y))
+
+  def __neg__(self):
+    return NonStandardInteger(operator.neg(self.val))
+
+  def __pos__(self):
+    return NonStandardInteger(operator.pos(self.val))
+
+  def __pow__(self, y):
+    return NonStandardInteger(operator.pow(self.val, y))
+
+  def __trunc__(self):
+    return int(self.val)
+
+  def __radd__(self, y):
+    return NonStandardInteger(operator.add(y, self.val))
+
+  def __rdiv__(self, y):
+    return NonStandardInteger(operator.div(y, self.val))
+
+  def __rmod__(self, y):
+    return NonStandardInteger(operator.mod(y, self.val))
+
+  def __rmul__(self, y):
+    return NonStandardInteger(operator.mul(y, self.val))
+
+  def __rpow__(self, y):
+    return NonStandardInteger(operator.pow(y, self.val))
+
+  def __rfloordiv__(self, y):
+    return NonStandardInteger(operator.floordiv(y, self.val))
+
+  def __rtruediv__(self, y):
+    return NonStandardInteger(operator.truediv(y, self.val))
+
+  def __lshift__(self, y):
+    return NonStandardInteger(operator.lshift(self.val, y))
+
+  def __rshift__(self, y):
+    return NonStandardInteger(operator.rshift(self.val, y))
+
+  def __rlshift__(self, y):
+    return NonStandardInteger(operator.lshift(y, self.val))
+
+  def __rrshift__(self, y):
+    return NonStandardInteger(operator.rshift(y, self.val))
+
+  def __le__(self, y):
+    if isinstance(y, NonStandardInteger):
+      y = y.val
+    return operator.le(self.val, y)
+
+  def __lt__(self, y):
+    if isinstance(y, NonStandardInteger):
+      y = y.val
+    return operator.lt(self.val, y)
+
+  def __and__(self, y):
+    return NonStandardInteger(operator.and_(self.val, y))
+
+  def __or__(self, y):
+    return NonStandardInteger(operator.or_(self.val, y))
+
+  def __xor__(self, y):
+    return NonStandardInteger(operator.xor(self.val, y))
+
+  def __rand__(self, y):
+    return NonStandardInteger(operator.and_(y, self.val))
+
+  def __ror__(self, y):
+    return NonStandardInteger(operator.or_(y, self.val))
+
+  def __rxor__(self, y):
+    return NonStandardInteger(operator.xor(y, self.val))
+
+  def __bool__(self):
+    return self.val
+
+  def __nonzero__(self):
+    return self.val
+
+  def __ceil__(self):
+    return self
+
+  def __floor__(self):
+    return self
+
+  def __int__(self):
+    if self.error_string_on_conversion:
+      raise RuntimeError(self.error_string_on_conversion)
+    return int(self.val)
+
+  def __round__(self):
+    return self
+
+  def __repr__(self):
+    return 'NonStandardInteger(%s)' % self.val
diff --git a/python/google/protobuf/internal/testing_refleaks.py b/python/google/protobuf/internal/testing_refleaks.py
new file mode 100644
index 0000000..5f19c46
--- /dev/null
+++ b/python/google/protobuf/internal/testing_refleaks.py
@@ -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.
+
+"""A subclass of unittest.TestCase which checks for reference leaks.
+
+To use:
+- Use testing_refleak.BaseTestCase instead of unittest.TestCase
+- Configure and compile Python with --with-pydebug
+
+If sys.gettotalrefcount() is not available (because Python was built without
+the Py_DEBUG option), then this module is a no-op and tests will run normally.
+"""
+
+import copyreg
+import gc
+import sys
+import unittest
+
+
+class LocalTestResult(unittest.TestResult):
+  """A TestResult which forwards events to a parent object, except for Skips."""
+
+  def __init__(self, parent_result):
+    unittest.TestResult.__init__(self)
+    self.parent_result = parent_result
+
+  def addError(self, test, error):
+    self.parent_result.addError(test, error)
+
+  def addFailure(self, test, error):
+    self.parent_result.addFailure(test, error)
+
+  def addSkip(self, test, reason):
+    pass
+
+
+class ReferenceLeakCheckerMixin(object):
+  """A mixin class for TestCase, which checks reference counts."""
+
+  NB_RUNS = 3
+
+  def run(self, result=None):
+    testMethod = getattr(self, self._testMethodName)
+    expecting_failure_method = getattr(testMethod, "__unittest_expecting_failure__", False)
+    expecting_failure_class = getattr(self, "__unittest_expecting_failure__", False)
+    if expecting_failure_class or expecting_failure_method:
+      return
+
+    # python_message.py registers all Message classes to some pickle global
+    # registry, which makes the classes immortal.
+    # We save a copy of this registry, and reset it before we could references.
+    self._saved_pickle_registry = copyreg.dispatch_table.copy()
+
+    # Run the test twice, to warm up the instance attributes.
+    super(ReferenceLeakCheckerMixin, self).run(result=result)
+    super(ReferenceLeakCheckerMixin, self).run(result=result)
+
+    oldrefcount = 0
+    local_result = LocalTestResult(result)
+    num_flakes = 0
+
+    refcount_deltas = []
+    while len(refcount_deltas) < self.NB_RUNS:
+      oldrefcount = self._getRefcounts()
+      super(ReferenceLeakCheckerMixin, self).run(result=local_result)
+      newrefcount = self._getRefcounts()
+      # If the GC was able to collect some objects after the call to run() that
+      # it could not collect before the call, then the counts won't match.
+      if newrefcount < oldrefcount and num_flakes < 2:
+        # This result is (probably) a flake -- garbage collectors aren't very
+        # predictable, but a lower ending refcount is the opposite of the
+        # failure we are testing for. If the result is repeatable, then we will
+        # eventually report it, but not after trying to eliminate it.
+        num_flakes += 1
+        continue
+      num_flakes = 0
+      refcount_deltas.append(newrefcount - oldrefcount)
+    print(refcount_deltas, self)
+
+    try:
+      self.assertEqual(refcount_deltas, [0] * self.NB_RUNS)
+    except Exception:  # pylint: disable=broad-except
+      result.addError(self, sys.exc_info())
+
+  def _getRefcounts(self):
+    copyreg.dispatch_table.clear()
+    copyreg.dispatch_table.update(self._saved_pickle_registry)
+    # It is sometimes necessary to gc.collect() multiple times, to ensure
+    # that all objects can be collected.
+    gc.collect()
+    gc.collect()
+    gc.collect()
+    return sys.gettotalrefcount()
+
+
+if hasattr(sys, 'gettotalrefcount'):
+
+  def TestCase(test_class):
+    new_bases = (ReferenceLeakCheckerMixin,) + test_class.__bases__
+    new_class = type(test_class)(
+        test_class.__name__, new_bases, dict(test_class.__dict__))
+    return new_class
+  SkipReferenceLeakChecker = unittest.skip
+
+else:
+  # When PyDEBUG is not enabled, run the tests normally.
+
+  def TestCase(test_class):
+    return test_class
+
+  def SkipReferenceLeakChecker(reason):
+    del reason  # Don't skip, so don't need a reason.
+    def Same(func):
+      return func
+    return Same
diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py
new file mode 100644
index 0000000..f36a2cc
--- /dev/null
+++ b/python/google/protobuf/internal/text_encoding_test.py
@@ -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.
+
+"""Tests for google.protobuf.text_encoding."""
+
+import unittest
+
+from google.protobuf import text_encoding
+
+TEST_VALUES = [
+    ("foo\\rbar\\nbaz\\t",
+     "foo\\rbar\\nbaz\\t",
+     b"foo\rbar\nbaz\t"),
+    ("\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
+     "\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
+     b"'full of \"sound\" and \"fury\"'"),
+    ("signi\\\\fying\\\\ nothing\\\\",
+     "signi\\\\fying\\\\ nothing\\\\",
+     b"signi\\fying\\ nothing\\"),
+    ("\\010\\t\\n\\013\\014\\r",
+     "\x08\\t\\n\x0b\x0c\\r",
+     b"\010\011\012\013\014\015")]
+
+
+class TextEncodingTestCase(unittest.TestCase):
+  def testCEscape(self):
+    for escaped, escaped_utf8, unescaped in TEST_VALUES:
+      self.assertEqual(escaped,
+                        text_encoding.CEscape(unescaped, as_utf8=False))
+      self.assertEqual(escaped_utf8,
+                        text_encoding.CEscape(unescaped, as_utf8=True))
+
+  def testCUnescape(self):
+    for escaped, escaped_utf8, unescaped in TEST_VALUES:
+      self.assertEqual(unescaped, text_encoding.CUnescape(escaped))
+      self.assertEqual(unescaped, text_encoding.CUnescape(escaped_utf8))
+
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
new file mode 100644
index 0000000..18b784e
--- /dev/null
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -0,0 +1,2447 @@
+# -*- coding: utf-8 -*-
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Test for google.protobuf.text_format."""
+
+import io
+import math
+import re
+import string
+import textwrap
+
+import unittest
+
+from google.protobuf import any_pb2
+from google.protobuf import struct_pb2
+from google.protobuf import any_test_pb2
+from google.protobuf import map_unittest_pb2
+from google.protobuf import unittest_custom_options_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 import descriptor_pb2
+from google.protobuf.internal import any_test_pb2 as test_extend_any
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import message_set_extensions_pb2
+from google.protobuf.internal import test_proto3_optional_pb2
+from google.protobuf.internal import test_util
+from google.protobuf import descriptor_pool
+from google.protobuf import text_format
+from google.protobuf.internal import _parameterized
+# pylint: enable=g-import-not-at-top
+
+
+# Low-level nuts-n-bolts tests.
+class SimpleTextFormatTests(unittest.TestCase):
+
+  # The members of _QUOTES are formatted into a regexp template that
+  # expects single characters.  Therefore it's an error (in addition to being
+  # non-sensical in the first place) to try to specify a "quote mark" that is
+  # more than one character.
+  def testQuoteMarksAreSingleChars(self):
+    for quote in text_format._QUOTES:
+      self.assertEqual(1, len(quote))
+
+
+# Base class with some common functionality.
+class TextFormatBase(unittest.TestCase):
+
+  def ReadGolden(self, golden_filename):
+    with test_util.GoldenFile(golden_filename) as f:
+      return (f.readlines() if str is bytes else  # PY3
+              [golden_line.decode('utf-8') for golden_line in f])
+
+  def CompareToGoldenFile(self, text, golden_filename):
+    golden_lines = self.ReadGolden(golden_filename)
+    self.assertMultiLineEqual(text, ''.join(golden_lines))
+
+  def CompareToGoldenText(self, 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
+    # these zeros in order to match the golden file.
+    text = text.replace('e+0','e+').replace('e+0','e+') \
+               .replace('e-0','e-').replace('e-0','e-')
+    # Floating point fields are printed with .0 suffix even if they are
+    # actually integer numbers.
+    text = re.compile(r'\.0$', re.MULTILINE).sub('', text)
+    return text
+
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatMessageToStringTests(TextFormatBase):
+
+  def testPrintExotic(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_int64.append(-9223372036854775808)
+    message.repeated_uint64.append(18446744073709551615)
+    message.repeated_double.append(123.456)
+    message.repeated_double.append(1.23e22)
+    message.repeated_double.append(1.23e-18)
+    message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
+    message.repeated_string.append(u'\u00fc\ua71f')
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'repeated_int64: -9223372036854775808\n'
+        'repeated_uint64: 18446744073709551615\n'
+        'repeated_double: 123.456\n'
+        'repeated_double: 1.23e+22\n'
+        'repeated_double: 1.23e-18\n'
+        'repeated_string:'
+        ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
+        'repeated_string: "\\303\\274\\352\\234\\237"\n')
+
+  def testPrintFloatPrecision(self, message_module):
+    message = message_module.TestAllTypes()
+
+    message.repeated_float.append(0.0)
+    message.repeated_float.append(0.8)
+    message.repeated_float.append(1.0)
+    message.repeated_float.append(1.2)
+    message.repeated_float.append(1.23)
+    message.repeated_float.append(1.234)
+    message.repeated_float.append(1.2345)
+    message.repeated_float.append(1.23456)
+    message.repeated_float.append(1.2e10)
+    message.repeated_float.append(1.23e10)
+    message.repeated_float.append(1.234e10)
+    message.repeated_float.append(1.2345e10)
+    message.repeated_float.append(1.23456e10)
+    message.repeated_float.append(float('NaN'))
+    message.repeated_float.append(float('inf'))
+    message.repeated_double.append(0.0)
+    message.repeated_double.append(0.8)
+    message.repeated_double.append(1.0)
+    message.repeated_double.append(1.2)
+    message.repeated_double.append(1.23)
+    message.repeated_double.append(1.234)
+    message.repeated_double.append(1.2345)
+    message.repeated_double.append(1.23456)
+    message.repeated_double.append(1.234567)
+    message.repeated_double.append(1.2345678)
+    message.repeated_double.append(1.23456789)
+    message.repeated_double.append(1.234567898)
+    message.repeated_double.append(1.2345678987)
+    message.repeated_double.append(1.23456789876)
+    message.repeated_double.append(1.234567898765)
+    message.repeated_double.append(1.2345678987654)
+    message.repeated_double.append(1.23456789876543)
+    message.repeated_double.append(1.2e100)
+    message.repeated_double.append(1.23e100)
+    message.repeated_double.append(1.234e100)
+    message.repeated_double.append(1.2345e100)
+    message.repeated_double.append(1.23456e100)
+    message.repeated_double.append(1.234567e100)
+    message.repeated_double.append(1.2345678e100)
+    message.repeated_double.append(1.23456789e100)
+    message.repeated_double.append(1.234567898e100)
+    message.repeated_double.append(1.2345678987e100)
+    message.repeated_double.append(1.23456789876e100)
+    message.repeated_double.append(1.234567898765e100)
+    message.repeated_double.append(1.2345678987654e100)
+    message.repeated_double.append(1.23456789876543e100)
+    # pylint: disable=g-long-ternary
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'repeated_float: 0\n'
+        'repeated_float: 0.8\n'
+        'repeated_float: 1\n'
+        'repeated_float: 1.2\n'
+        'repeated_float: 1.23\n'
+        'repeated_float: 1.234\n'
+        'repeated_float: 1.2345\n'
+        'repeated_float: 1.23456\n'
+        # Note that these don't use scientific notation.
+        'repeated_float: 12000000000\n'
+        'repeated_float: 12300000000\n'
+        'repeated_float: 12340000000\n'
+        'repeated_float: 12345000000\n'
+        'repeated_float: 12345600000\n'
+        'repeated_float: nan\n'
+        'repeated_float: inf\n'
+        'repeated_double: 0\n'
+        'repeated_double: 0.8\n'
+        'repeated_double: 1\n'
+        'repeated_double: 1.2\n'
+        'repeated_double: 1.23\n'
+        'repeated_double: 1.234\n'
+        'repeated_double: 1.2345\n'
+        'repeated_double: 1.23456\n'
+        'repeated_double: 1.234567\n'
+        'repeated_double: 1.2345678\n'
+        'repeated_double: 1.23456789\n'
+        'repeated_double: 1.234567898\n'
+        'repeated_double: 1.2345678987\n'
+        'repeated_double: 1.23456789876\n'
+        'repeated_double: 1.234567898765\n'
+        'repeated_double: 1.2345678987654\n'
+        'repeated_double: 1.23456789876543\n'
+        'repeated_double: 1.2e+100\n'
+        'repeated_double: 1.23e+100\n'
+        'repeated_double: 1.234e+100\n'
+        'repeated_double: 1.2345e+100\n'
+        'repeated_double: 1.23456e+100\n'
+        'repeated_double: 1.234567e+100\n'
+        'repeated_double: 1.2345678e+100\n'
+        'repeated_double: 1.23456789e+100\n'
+        'repeated_double: 1.234567898e+100\n'
+        'repeated_double: 1.2345678987e+100\n'
+        'repeated_double: 1.23456789876e+100\n'
+        'repeated_double: 1.234567898765e+100\n'
+        'repeated_double: 1.2345678987654e+100\n'
+        'repeated_double: 1.23456789876543e+100\n')
+
+  def testPrintExoticUnicodeSubclass(self, message_module):
+
+    class UnicodeSub(str):
+      pass
+
+    message = message_module.TestAllTypes()
+    message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        'repeated_string: "\\303\\274\\352\\234\\237"\n')
+
+  def testPrintNestedMessageAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
+    msg = message.repeated_nested_message.add()
+    msg.bb = 42
+    self.CompareToGoldenText(
+        text_format.MessageToString(message, as_one_line=True),
+        'repeated_nested_message { bb: 42 }')
+
+  def testPrintRepeatedFieldsAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_int32.append(1)
+    message.repeated_int32.append(1)
+    message.repeated_int32.append(3)
+    message.repeated_string.append('Google')
+    message.repeated_string.append('Zurich')
+    self.CompareToGoldenText(
+        text_format.MessageToString(message, as_one_line=True),
+        'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 '
+        'repeated_string: "Google" repeated_string: "Zurich"')
+
+  def VerifyPrintShortFormatRepeatedFields(self, message_module, as_one_line):
+    message = message_module.TestAllTypes()
+    message.repeated_int32.append(1)
+    message.repeated_string.append('Google')
+    message.repeated_string.append('Hello,World')
+    message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_FOO)
+    message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR)
+    message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ)
+    message.optional_nested_message.bb = 3
+    for i in (21, 32):
+      msg = message.repeated_nested_message.add()
+      msg.bb = i
+    expected_ascii = (
+        'optional_nested_message {\n  bb: 3\n}\n'
+        'repeated_int32: [1]\n'
+        'repeated_string: "Google"\n'
+        'repeated_string: "Hello,World"\n'
+        'repeated_nested_message {\n  bb: 21\n}\n'
+        'repeated_nested_message {\n  bb: 32\n}\n'
+        'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n')
+    if as_one_line:
+      expected_ascii = expected_ascii.replace('\n', ' ')
+      expected_ascii = re.sub(r'\s+', ' ', expected_ascii)
+      expected_ascii = re.sub(r'\s$', '', expected_ascii)
+
+    actual_ascii = text_format.MessageToString(
+        message, use_short_repeated_primitives=True,
+        as_one_line=as_one_line)
+    self.CompareToGoldenText(actual_ascii, expected_ascii)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(actual_ascii, parsed_message)
+    self.assertEqual(parsed_message, message)
+
+  def testPrintShortFormatRepeatedFields(self, message_module):
+    self.VerifyPrintShortFormatRepeatedFields(message_module, False)
+    self.VerifyPrintShortFormatRepeatedFields(message_module, True)
+
+  def testPrintNestedNewLineInStringAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
+    message.optional_string = 'a\nnew\nline'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message, as_one_line=True),
+        'optional_string: "a\\nnew\\nline"')
+
+  def testPrintExoticAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_int64.append(-9223372036854775808)
+    message.repeated_uint64.append(18446744073709551615)
+    message.repeated_double.append(123.456)
+    message.repeated_double.append(1.23e22)
+    message.repeated_double.append(1.23e-18)
+    message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
+    message.repeated_string.append(u'\u00fc\ua71f')
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message, as_one_line=True)),
+        'repeated_int64: -9223372036854775808'
+        ' repeated_uint64: 18446744073709551615'
+        ' repeated_double: 123.456'
+        ' repeated_double: 1.23e+22'
+        ' repeated_double: 1.23e-18'
+        ' repeated_string: '
+        '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""'
+        ' repeated_string: "\\303\\274\\352\\234\\237"')
+
+  def testRoundTripExoticAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_int64.append(-9223372036854775808)
+    message.repeated_uint64.append(18446744073709551615)
+    message.repeated_double.append(123.456)
+    message.repeated_double.append(1.23e22)
+    message.repeated_double.append(1.23e-18)
+    message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
+    message.repeated_string.append(u'\u00fc\ua71f')
+
+    # Test as_utf8 = False.
+    wire_text = text_format.MessageToString(message,
+                                            as_one_line=True,
+                                            as_utf8=False)
+    parsed_message = message_module.TestAllTypes()
+    r = text_format.Parse(wire_text, parsed_message)
+    self.assertIs(r, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+    # Test as_utf8 = True.
+    wire_text = text_format.MessageToString(message,
+                                            as_one_line=True,
+                                            as_utf8=True)
+    parsed_message = message_module.TestAllTypes()
+    r = text_format.Parse(wire_text, parsed_message)
+    self.assertIs(r, parsed_message)
+    self.assertEqual(message, parsed_message,
+                     '\n%s != %s' % (message, parsed_message))
+
+  def testPrintRawUtf8String(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_string.append(u'\u00fc\t\ua71f')
+    text = text_format.MessageToString(message, as_utf8=True)
+    golden_unicode = u'repeated_string: "\u00fc\\t\ua71f"\n'
+    golden_text = golden_unicode
+    # MessageToString always returns a native str.
+    self.CompareToGoldenText(text, golden_text)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(text, parsed_message)
+    self.assertEqual(
+        message, parsed_message, '\n%s != %s  (%s != %s)' %
+        (message, parsed_message, message.repeated_string[0],
+         parsed_message.repeated_string[0]))
+
+  def testPrintFloatFormat(self, message_module):
+    # Check that float_format argument is passed to sub-message formatting.
+    message = message_module.NestedTestAllTypes()
+    message.payload.optional_float = 1.25
+    # Check rounding at 15 significant digits
+    message.payload.optional_double = -.000003456789012345678
+    # Check no decimal point.
+    message.payload.repeated_float.append(-5642)
+    # Check no trailing zeros.
+    message.payload.repeated_double.append(.000078900)
+    formatted_fields = ['optional_float: 1.25',
+                        'optional_double: -3.45678901234568e-6',
+                        'repeated_float: -5642', 'repeated_double: 7.89e-5']
+    text_message = text_format.MessageToString(message, float_format='.15g')
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_message),
+        '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 {{ {0} {1} {2} {3} }}'.format(*formatted_fields))
+
+    # 32-bit 1.2 is noisy when extended to 64-bit:
+    #  >>> struct.unpack('f', struct.pack('f', 1.2))[0]
+    #  1.2000000476837158
+    message.payload.optional_float = 1.2
+    formatted_fields = ['optional_float: 1.2',
+                        'optional_double: -3.45678901234568e-6',
+                        'repeated_float: -5642', 'repeated_double: 7.89e-5']
+    text_message = text_format.MessageToString(message, float_format='.7g',
+                                               double_format='.15g')
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_message),
+        'payload {{\n  {0}\n  {1}\n  {2}\n  {3}\n}}\n'.format(
+            *formatted_fields))
+
+    # Test only set float_format affect both float and double fields.
+    formatted_fields = ['optional_float: 1.2',
+                        'optional_double: -3.456789e-6',
+                        'repeated_float: -5642', 'repeated_double: 7.89e-5']
+    text_message = text_format.MessageToString(message, float_format='.7g')
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_message),
+        'payload {{\n  {0}\n  {1}\n  {2}\n  {3}\n}}\n'.format(
+            *formatted_fields))
+
+    # Test default float_format will automatic print shortest float.
+    message.payload.optional_float = 1.2345678912
+    message.payload.optional_double = 1.2345678912
+    formatted_fields = ['optional_float: 1.2345679',
+                        'optional_double: 1.2345678912',
+                        'repeated_float: -5642', 'repeated_double: 7.89e-5']
+    text_message = text_format.MessageToString(message)
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_message),
+        'payload {{\n  {0}\n  {1}\n  {2}\n  {3}\n}}\n'.format(
+            *formatted_fields))
+
+    message.Clear()
+    message.payload.optional_float = 1.1000000000011
+    self.assertEqual(text_format.MessageToString(message),
+                     'payload {\n  optional_float: 1.1\n}\n')
+    message.payload.optional_float = 1.00000075e-36
+    self.assertEqual(text_format.MessageToString(message),
+                     'payload {\n  optional_float: 1.00000075e-36\n}\n')
+    message.payload.optional_float = 12345678912345e+11
+    self.assertEqual(text_format.MessageToString(message),
+                     'payload {\n  optional_float: 1.234568e+24\n}\n')
+
+  def testMessageToString(self, message_module):
+    message = message_module.ForeignMessage()
+    message.c = 123
+    self.assertEqual('c: 123\n', str(message))
+
+  def testMessageToStringUnicode(self, message_module):
+    golden_unicode = u'Á short desçription and a 🍌.'
+    golden_bytes = golden_unicode.encode('utf-8')
+    message = message_module.TestAllTypes()
+    message.optional_string = golden_unicode
+    message.optional_bytes = golden_bytes
+    text = text_format.MessageToString(message, as_utf8=True)
+    golden_message = textwrap.dedent(
+        'optional_string: "Á short desçription and a 🍌."\n'
+        'optional_bytes: '
+        r'"\303\201 short des\303\247ription and a \360\237\215\214."'
+        '\n')
+    self.CompareToGoldenText(text, golden_message)
+
+  def testMessageToStringASCII(self, message_module):
+    golden_unicode = u'Á short desçription and a 🍌.'
+    golden_bytes = golden_unicode.encode('utf-8')
+    message = message_module.TestAllTypes()
+    message.optional_string = golden_unicode
+    message.optional_bytes = golden_bytes
+    text = text_format.MessageToString(message, as_utf8=False)  # ASCII
+    golden_message = (
+        'optional_string: '
+        r'"\303\201 short des\303\247ription and a \360\237\215\214."'
+        '\n'
+        'optional_bytes: '
+        r'"\303\201 short des\303\247ription and a \360\237\215\214."'
+        '\n')
+    self.CompareToGoldenText(text, golden_message)
+
+  def testPrintField(self, message_module):
+    message = message_module.TestAllTypes()
+    field = message.DESCRIPTOR.fields_by_name['optional_float']
+    value = message.optional_float
+    out = text_format.TextWriter(False)
+    text_format.PrintField(field, value, out)
+    self.assertEqual('optional_float: 0.0\n', out.getvalue())
+    out.close()
+    # Test Printer
+    out = text_format.TextWriter(False)
+    printer = text_format._Printer(out)
+    printer.PrintField(field, value)
+    self.assertEqual('optional_float: 0.0\n', out.getvalue())
+    out.close()
+
+  def testPrintFieldValue(self, message_module):
+    message = message_module.TestAllTypes()
+    field = message.DESCRIPTOR.fields_by_name['optional_float']
+    value = message.optional_float
+    out = text_format.TextWriter(False)
+    text_format.PrintFieldValue(field, value, out)
+    self.assertEqual('0.0', out.getvalue())
+    out.close()
+    # Test Printer
+    out = text_format.TextWriter(False)
+    printer = text_format._Printer(out)
+    printer.PrintFieldValue(field, value)
+    self.assertEqual('0.0', out.getvalue())
+    out.close()
+
+  def testCustomOptions(self, message_module):
+    message_descriptor = (unittest_custom_options_pb2.
+                          TestMessageWithCustomOptions.DESCRIPTOR)
+    message_proto = descriptor_pb2.DescriptorProto()
+    message_descriptor.CopyToProto(message_proto)
+    expected_text = (
+        'name: "TestMessageWithCustomOptions"\n'
+        'field {\n'
+        '  name: "field1"\n'
+        '  number: 1\n'
+        '  label: LABEL_OPTIONAL\n'
+        '  type: TYPE_STRING\n'
+        '  options {\n'
+        '    ctype: CORD\n'
+        '    [protobuf_unittest.field_opt1]: 8765432109\n'
+        '  }\n'
+        '}\n'
+        'field {\n'
+        '  name: "oneof_field"\n'
+        '  number: 2\n'
+        '  label: LABEL_OPTIONAL\n'
+        '  type: TYPE_INT32\n'
+        '  oneof_index: 0\n'
+        '}\n'
+        'field {\n'
+        '  name: "map_field"\n'
+        '  number: 3\n'
+        '  label: LABEL_REPEATED\n'
+        '  type: TYPE_MESSAGE\n'
+        '  type_name: ".protobuf_unittest.TestMessageWithCustomOptions.'
+        'MapFieldEntry"\n'
+        '  options {\n'
+        '    [protobuf_unittest.field_opt1]: 12345\n'
+        '  }\n'
+        '}\n'
+        'nested_type {\n'
+        '  name: "MapFieldEntry"\n'
+        '  field {\n'
+        '    name: "key"\n'
+        '    number: 1\n'
+        '    label: LABEL_OPTIONAL\n'
+        '    type: TYPE_STRING\n'
+        '  }\n'
+        '  field {\n'
+        '    name: "value"\n'
+        '    number: 2\n'
+        '    label: LABEL_OPTIONAL\n'
+        '    type: TYPE_STRING\n'
+        '  }\n'
+        '  options {\n'
+        '    map_entry: true\n'
+        '  }\n'
+        '}\n'
+        'enum_type {\n'
+        '  name: "AnEnum"\n'
+        '  value {\n'
+        '    name: "ANENUM_VAL1"\n'
+        '    number: 1\n'
+        '  }\n'
+        '  value {\n'
+        '    name: "ANENUM_VAL2"\n'
+        '    number: 2\n'
+        '    options {\n'
+        '      [protobuf_unittest.enum_value_opt1]: 123\n'
+        '    }\n'
+        '  }\n'
+        '  options {\n'
+        '    [protobuf_unittest.enum_opt1]: -789\n'
+        '  }\n'
+        '}\n'
+        'options {\n'
+        '  message_set_wire_format: false\n'
+        '  [protobuf_unittest.message_opt1]: -56\n'
+        '}\n'
+        'oneof_decl {\n'
+        '  name: "AnOneof"\n'
+        '  options {\n'
+        '    [protobuf_unittest.oneof_opt1]: -99\n'
+        '  }\n'
+        '}\n')
+    self.assertEqual(expected_text,
+                     text_format.MessageToString(message_proto))
+    parsed_proto = descriptor_pb2.DescriptorProto()
+    text_format.Parse(expected_text, parsed_proto)
+    self.assertEqual(message_proto, parsed_proto)
+
+  @unittest.skipIf(
+      api_implementation.Type() == 'upb',
+      "upb API doesn't support old UnknownField API. The TextFormat library "
+      "needs to convert to the new API.")
+  def testPrintUnknownFieldsEmbeddedMessageInBytes(self, message_module):
+    inner_msg = message_module.TestAllTypes()
+    inner_msg.optional_int32 = 101
+    inner_msg.optional_double = 102.0
+    inner_msg.optional_string = u'hello'
+    inner_msg.optional_bytes = b'103'
+    inner_msg.optional_nested_message.bb = 105
+    inner_data = inner_msg.SerializeToString()
+    outer_message = message_module.TestAllTypes()
+    outer_message.optional_int32 = 101
+    outer_message.optional_bytes = inner_data
+    all_data = outer_message.SerializeToString()
+    empty_message = message_module.TestEmptyMessage()
+    empty_message.ParseFromString(all_data)
+
+    self.assertEqual('  1: 101\n'
+                     '  15 {\n'
+                     '    1: 101\n'
+                     '    12: 4636878028842991616\n'
+                     '    14: "hello"\n'
+                     '    15: "103"\n'
+                     '    18 {\n'
+                     '      1: 105\n'
+                     '    }\n'
+                     '  }\n',
+                     text_format.MessageToString(empty_message,
+                                                 indent=2,
+                                                 print_unknown_fields=True))
+    self.assertEqual('1: 101 '
+                     '15 { '
+                     '1: 101 '
+                     '12: 4636878028842991616 '
+                     '14: "hello" '
+                     '15: "103" '
+                     '18 { 1: 105 } '
+                     '}',
+                     text_format.MessageToString(empty_message,
+                                                 print_unknown_fields=True,
+                                                 as_one_line=True))
+
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatMessageToTextBytesTests(TextFormatBase):
+
+  def testMessageToBytes(self, message_module):
+    message = message_module.ForeignMessage()
+    message.c = 123
+    self.assertEqual(b'c: 123\n', text_format.MessageToBytes(message))
+
+  def testRawUtf8RoundTrip(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_string.append(u'\u00fc\t\ua71f')
+    utf8_text = text_format.MessageToBytes(message, as_utf8=True)
+    golden_bytes = b'repeated_string: "\xc3\xbc\\t\xea\x9c\x9f"\n'
+    self.CompareToGoldenText(utf8_text, golden_bytes)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(utf8_text, parsed_message)
+    self.assertEqual(
+        message, parsed_message, '\n%s != %s  (%s != %s)' %
+        (message, parsed_message, message.repeated_string[0],
+         parsed_message.repeated_string[0]))
+
+  def testEscapedUtf8ASCIIRoundTrip(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_string.append(u'\u00fc\t\ua71f')
+    ascii_text = text_format.MessageToBytes(message)  # as_utf8=False default
+    golden_bytes = b'repeated_string: "\\303\\274\\t\\352\\234\\237"\n'
+    self.CompareToGoldenText(ascii_text, golden_bytes)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(ascii_text, parsed_message)
+    self.assertEqual(
+        message, parsed_message, '\n%s != %s  (%s != %s)' %
+        (message, parsed_message, message.repeated_string[0],
+         parsed_message.repeated_string[0]))
+
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatParserTests(TextFormatBase):
+
+  def testParseAllFields(self, message_module):
+    message = message_module.TestAllTypes()
+    test_util.SetAllFields(message)
+    ascii_text = text_format.MessageToString(message)
+
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+    if message_module is unittest_pb2:
+      test_util.ExpectAllFieldsSet(self, message)
+
+  def testParseAndMergeUtf8(self, message_module):
+    message = message_module.TestAllTypes()
+    test_util.SetAllFields(message)
+    ascii_text = text_format.MessageToString(message)
+    ascii_text = ascii_text.encode('utf-8')
+
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+    if message_module is unittest_pb2:
+      test_util.ExpectAllFieldsSet(self, message)
+
+    parsed_message.Clear()
+    text_format.Merge(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+    if message_module is unittest_pb2:
+      test_util.ExpectAllFieldsSet(self, message)
+
+    msg2 = message_module.TestAllTypes()
+    text = (u'optional_string: "café"')
+    text_format.Merge(text, msg2)
+    self.assertEqual(msg2.optional_string, u'café')
+    msg2.Clear()
+    self.assertEqual(msg2.optional_string, u'')
+    text_format.Parse(text, msg2)
+    self.assertEqual(msg2.optional_string, u'café')
+
+  def testParseDoubleToFloat(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_float: 3.4028235e+39\n'
+            'repeated_float: 1.4028235e-39\n')
+    text_format.Parse(text, message)
+    self.assertEqual(message.repeated_float[0], float('inf'))
+    self.assertAlmostEqual(message.repeated_float[1], 1.4028235e-39)
+
+  def testParseExotic(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_int64: -9223372036854775808\n'
+            'repeated_uint64: 18446744073709551615\n'
+            'repeated_double: 123.456\n'
+            'repeated_double: 1.23e+22\n'
+            'repeated_double: 1.23e-18\n'
+            'repeated_string: \n'
+            '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
+            'repeated_string: "foo" \'corge\' "grault"\n'
+            'repeated_string: "\\303\\274\\352\\234\\237"\n'
+            'repeated_string: "\\xc3\\xbc"\n'
+            'repeated_string: "\xc3\xbc"\n')
+    text_format.Parse(text, message)
+
+    self.assertEqual(-9223372036854775808, message.repeated_int64[0])
+    self.assertEqual(18446744073709551615, message.repeated_uint64[0])
+    self.assertEqual(123.456, message.repeated_double[0])
+    self.assertEqual(1.23e22, message.repeated_double[1])
+    self.assertEqual(1.23e-18, message.repeated_double[2])
+    self.assertEqual('\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
+    self.assertEqual('foocorgegrault', message.repeated_string[1])
+    self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
+    self.assertEqual(u'\u00fc', message.repeated_string[3])
+
+  def testParseTrailingCommas(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_int64: 100;\n'
+            'repeated_int64: 200;\n'
+            'repeated_int64: 300,\n'
+            'repeated_string: "one",\n'
+            'repeated_string: "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 testParseRepeatedScalarShortFormat(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_int64: [100, 200];\n'
+            'repeated_int64: []\n'
+            'repeated_int64: 300,\n'
+            'repeated_string: ["one", "two"];\n')
+    text_format.Parse(text, message)
+
+    self.assertEqual(100, message.repeated_int64[0])
+    self.assertEqual(200, message.repeated_int64[1])
+    self.assertEqual(300, message.repeated_int64[2])
+    self.assertEqual(u'one', message.repeated_string[0])
+    self.assertEqual(u'two', message.repeated_string[1])
+
+  def testParseRepeatedMessageShortFormat(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_nested_message: [{bb: 100}, {bb: 200}],\n'
+            'repeated_nested_message: {bb: 300}\n'
+            'repeated_nested_message [{bb: 400}];\n')
+    text_format.Parse(text, message)
+
+    self.assertEqual(100, message.repeated_nested_message[0].bb)
+    self.assertEqual(200, message.repeated_nested_message[1].bb)
+    self.assertEqual(300, message.repeated_nested_message[2].bb)
+    self.assertEqual(400, message.repeated_nested_message[3].bb)
+
+  def testParseEmptyText(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ''
+    text_format.Parse(text, message)
+    self.assertEqual(message_module.TestAllTypes(), message)
+
+  def testParseInvalidUtf8(self, message_module):
+    message = message_module.TestAllTypes()
+    text = 'repeated_string: "\\xc3\\xc3"'
+    with self.assertRaises(text_format.ParseError) as e:
+      text_format.Parse(text, message)
+    self.assertEqual(e.exception.GetLine(), 1)
+    self.assertEqual(e.exception.GetColumn(), 28)
+
+  def testParseSingleWord(self, message_module):
+    message = message_module.TestAllTypes()
+    text = 'foo'
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"foo".'), text_format.Parse, text, message)
+
+  def testParseUnknownField(self, message_module):
+    message = message_module.TestAllTypes()
+    text = 'unknown_field: 8\n'
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"unknown_field".'), text_format.Parse, text, message)
+    text = ('optional_int32: 123\n'
+            'unknown_field: 8\n'
+            'optional_nested_message { bb: 45 }')
+    text_format.Parse(text, message, allow_unknown_field=True)
+    self.assertEqual(message.optional_nested_message.bb, 45)
+    self.assertEqual(message.optional_int32, 123)
+
+  def testParseBadEnumValue(self, message_module):
+    message = message_module.TestAllTypes()
+    text = 'optional_nested_enum: BARR'
+    self.assertRaisesRegex(text_format.ParseError,
+                           (r'1:23 : \'optional_nested_enum: BARR\': '
+                            r'Enum type "\w+.TestAllTypes.NestedEnum" '
+                            r'has no value named BARR.'), text_format.Parse,
+                           text, message)
+
+  def testParseBadIntValue(self, message_module):
+    message = message_module.TestAllTypes()
+    text = 'optional_int32: bork'
+    self.assertRaisesRegex(text_format.ParseError,
+                           ('1:17 : \'optional_int32: bork\': '
+                            'Couldn\'t parse integer: bork'), text_format.Parse,
+                           text, message)
+
+  def testParseStringFieldUnescape(self, message_module):
+    message = message_module.TestAllTypes()
+    text = r'''repeated_string: "\xf\x62"
+               repeated_string: "\\xf\\x62"
+               repeated_string: "\\\xf\\\x62"
+               repeated_string: "\\\\xf\\\\x62"
+               repeated_string: "\\\\\xf\\\\\x62"
+               repeated_string: "\x5cx20"'''
+
+    text_format.Parse(text, message)
+
+    SLASH = '\\'
+    self.assertEqual('\x0fb', message.repeated_string[0])
+    self.assertEqual(SLASH + 'xf' + SLASH + 'x62', message.repeated_string[1])
+    self.assertEqual(SLASH + '\x0f' + SLASH + 'b', message.repeated_string[2])
+    self.assertEqual(SLASH + SLASH + 'xf' + SLASH + SLASH + 'x62',
+                     message.repeated_string[3])
+    self.assertEqual(SLASH + SLASH + '\x0f' + SLASH + SLASH + 'b',
+                     message.repeated_string[4])
+    self.assertEqual(SLASH + 'x20', message.repeated_string[5])
+
+  def testParseOneof(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    text_format.Parse(text_format.MessageToString(m), m2)
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testParseMultipleOneof(self, message_module):
+    m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
+    m2 = message_module.TestAllTypes()
+    with self.assertRaisesRegex(text_format.ParseError,
+                                ' is specified along with field '):
+      text_format.Parse(m_string, m2)
+
+  # This example contains non-ASCII codepoint unicode data as literals
+  # which should come through as utf-8 for bytes, and as the unicode
+  # itself for string fields.  It also demonstrates escaped binary data.
+  # The ur"" string prefix is unfortunately missing from Python 3
+  # so we resort to double escaping our \s so that they come through.
+  _UNICODE_SAMPLE = u"""
+      optional_bytes: 'Á short desçription'
+      optional_string: 'Á short desçription'
+      repeated_bytes: '\\303\\201 short des\\303\\247ription'
+      repeated_bytes: '\\x12\\x34\\x56\\x78\\x90\\xab\\xcd\\xef'
+      repeated_string: '\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82'
+      """
+  _BYTES_SAMPLE = _UNICODE_SAMPLE.encode('utf-8')
+  _GOLDEN_UNICODE = u'Á short desçription'
+  _GOLDEN_BYTES = _GOLDEN_UNICODE.encode('utf-8')
+  _GOLDEN_BYTES_1 = b'\x12\x34\x56\x78\x90\xab\xcd\xef'
+  _GOLDEN_STR_0 = u'Привет'
+
+  def testParseUnicode(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.Parse(self._UNICODE_SAMPLE, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+    # repeated_bytes[1] contained simple \ escaped non-UTF-8 raw binary data.
+    self.assertEqual(m.repeated_bytes[1], self._GOLDEN_BYTES_1)
+    # repeated_string[0] contained \ escaped data representing the UTF-8
+    # representation of _GOLDEN_STR_0 - it needs to decode as such.
+    self.assertEqual(m.repeated_string[0], self._GOLDEN_STR_0)
+
+  def testParseBytes(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.Parse(self._BYTES_SAMPLE, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+    # repeated_bytes[1] contained simple \ escaped non-UTF-8 raw binary data.
+    self.assertEqual(m.repeated_bytes[1], self._GOLDEN_BYTES_1)
+    # repeated_string[0] contained \ escaped data representing the UTF-8
+    # representation of _GOLDEN_STR_0 - it needs to decode as such.
+    self.assertEqual(m.repeated_string[0], self._GOLDEN_STR_0)
+
+  def testFromBytesFile(self, message_module):
+    m = message_module.TestAllTypes()
+    f = io.BytesIO(self._BYTES_SAMPLE)
+    text_format.ParseLines(f, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testFromUnicodeFile(self, message_module):
+    m = message_module.TestAllTypes()
+    f = io.StringIO(self._UNICODE_SAMPLE)
+    text_format.ParseLines(f, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testFromBytesLines(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.ParseLines(self._BYTES_SAMPLE.split(b'\n'), m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testFromUnicodeLines(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.ParseLines(self._UNICODE_SAMPLE.split(u'\n'), m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testParseDuplicateMessages(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('optional_nested_message { bb: 1 } '
+            'optional_nested_message { bb: 2 }')
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        (r'1:59 : Message type "\w+.TestAllTypes" '
+         r'should not have multiple "optional_nested_message" fields.'),
+        text_format.Parse, text, message)
+
+  def testParseDuplicateScalars(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('optional_int32: 42 ' 'optional_int32: 67')
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        (r'1:36 : Message type "\w+.TestAllTypes" should not '
+         r'have multiple "optional_int32" fields.'), text_format.Parse, text,
+        message)
+
+  def testParseExistingScalarInMessage(self, message_module):
+    message = message_module.TestAllTypes(optional_int32=42)
+    text = 'optional_int32: 67'
+    self.assertRaisesRegex(text_format.ParseError,
+                           (r'Message type "\w+.TestAllTypes" should not '
+                            r'have multiple "optional_int32" fields.'),
+                           text_format.Parse, text, message)
+
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatMergeTests(TextFormatBase):
+
+  def testMergeDuplicateScalarsInText(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('optional_int32: 42 ' 'optional_int32: 67')
+    r = text_format.Merge(text, message)
+    self.assertIs(r, message)
+    self.assertEqual(67, message.optional_int32)
+
+  def testMergeDuplicateNestedMessageScalars(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('optional_nested_message { bb: 1 } '
+            'optional_nested_message { bb: 2 }')
+    r = text_format.Merge(text, message)
+    self.assertTrue(r is message)
+    self.assertEqual(2, message.optional_nested_message.bb)
+
+  def testReplaceScalarInMessage(self, message_module):
+    message = message_module.TestAllTypes(optional_int32=42)
+    text = 'optional_int32: 67'
+    r = text_format.Merge(text, message)
+    self.assertIs(r, message)
+    self.assertEqual(67, message.optional_int32)
+
+  def testReplaceMessageInMessage(self, message_module):
+    message = message_module.TestAllTypes(
+        optional_int32=42, optional_nested_message=dict())
+    self.assertTrue(message.HasField('optional_nested_message'))
+    text = 'optional_nested_message{ bb: 3 }'
+    r = text_format.Merge(text, message)
+    self.assertIs(r, message)
+    self.assertEqual(3, message.optional_nested_message.bb)
+
+  def testMergeMultipleOneof(self, message_module):
+    m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
+    m2 = message_module.TestAllTypes()
+    text_format.Merge(m_string, m2)
+    self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
+
+
+# These are tests that aren't fundamentally specific to proto2, but are at
+# the moment because of differences between the proto2 and proto3 test schemas.
+# Ideally the schemas would be made more similar so these tests could pass.
+class OnlyWorksWithProto2RightNowTests(TextFormatBase):
+
+  def testPrintAllFieldsPointy(self):
+    message = unittest_pb2.TestAllTypes()
+    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_oneof_implemented.txt'))
+    parsed_message = unittest_pb2.TestAllTypes()
+    r = text_format.Parse(golden_text, parsed_message)
+    self.assertIs(r, parsed_message)
+
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.assertEqual(message, parsed_message)
+
+  def testPrintAllFields(self):
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'text_format_unittest_data_oneof_implemented.txt')
+
+  def testPrintUnknownFields(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optional_int32 = 101
+    message.optional_double = 102.0
+    message.optional_string = u'hello'
+    message.optional_bytes = b'103'
+    message.optionalgroup.a = 104
+    message.optional_nested_message.bb = 105
+    all_data = message.SerializeToString()
+    empty_message = unittest_pb2.TestEmptyMessage()
+    empty_message.ParseFromString(all_data)
+    self.assertEqual('  1: 101\n'
+                     '  12: 4636878028842991616\n'
+                     '  14: "hello"\n'
+                     '  15: "103"\n'
+                     '  16 {\n'
+                     '    17: 104\n'
+                     '  }\n'
+                     '  18 {\n'
+                     '    1: 105\n'
+                     '  }\n',
+                     text_format.MessageToString(empty_message,
+                                                 indent=2,
+                                                 print_unknown_fields=True))
+    self.assertEqual('1: 101 '
+                     '12: 4636878028842991616 '
+                     '14: "hello" '
+                     '15: "103" '
+                     '16 { 17: 104 } '
+                     '18 { 1: 105 }',
+                     text_format.MessageToString(empty_message,
+                                                 print_unknown_fields=True,
+                                                 as_one_line=True))
+
+  def testPrintInIndexOrder(self):
+    message = unittest_pb2.TestFieldOrderings()
+    # Fields are listed in index order instead of field number.
+    message.my_string = 'str'
+    message.my_int = 101
+    message.my_float = 111
+    message.optional_nested_message.oo = 0
+    message.optional_nested_message.bb = 1
+    message.Extensions[unittest_pb2.my_extension_string] = 'ext_str0'
+    # Extensions are listed based on the order of extension number.
+    # Extension number 12.
+    message.Extensions[unittest_pb2.TestExtensionOrderings2.
+                       test_ext_orderings2].my_string = 'ext_str2'
+    # Extension number 13.
+    message.Extensions[unittest_pb2.TestExtensionOrderings1.
+                       test_ext_orderings1].my_string = 'ext_str1'
+    # Extension number 14.
+    message.Extensions[
+        unittest_pb2.TestExtensionOrderings2.TestExtensionOrderings3.
+        test_ext_orderings3].my_string = 'ext_str3'
+
+    # Print in index order.
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(
+            text_format.MessageToString(message, use_index_order=True)),
+        'my_string: "str"\n'
+        'my_int: 101\n'
+        'my_float: 111\n'
+        'optional_nested_message {\n'
+        '  oo: 0\n'
+        '  bb: 1\n'
+        '}\n'
+        '[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n'
+        '  my_string: "ext_str2"\n'
+        '}\n'
+        '[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n'
+        '  my_string: "ext_str1"\n'
+        '}\n'
+        '[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3'
+        '.test_ext_orderings3] {\n'
+        '  my_string: "ext_str3"\n'
+        '}\n'
+        '[protobuf_unittest.my_extension_string]: "ext_str0"\n')
+    # By default, print in field number order.
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'my_int: 101\n'
+        'my_string: "str"\n'
+        '[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n'
+        '  my_string: "ext_str2"\n'
+        '}\n'
+        '[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n'
+        '  my_string: "ext_str1"\n'
+        '}\n'
+        '[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3'
+        '.test_ext_orderings3] {\n'
+        '  my_string: "ext_str3"\n'
+        '}\n'
+        '[protobuf_unittest.my_extension_string]: "ext_str0"\n'
+        'my_float: 111\n'
+        'optional_nested_message {\n'
+        '  bb: 1\n'
+        '  oo: 0\n'
+        '}\n')
+
+  def testMergeLinesGolden(self):
+    opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
+    parsed_message = unittest_pb2.TestAllTypes()
+    r = text_format.MergeLines(opened, parsed_message)
+    self.assertIs(r, parsed_message)
+
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.assertEqual(message, parsed_message)
+
+  def testParseLinesGolden(self):
+    opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
+    parsed_message = unittest_pb2.TestAllTypes()
+    r = text_format.ParseLines(opened, parsed_message)
+    self.assertIs(r, parsed_message)
+
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.assertEqual(message, parsed_message)
+
+  def testPrintMap(self):
+    message = map_unittest_pb2.TestMap()
+
+    message.map_int32_int32[-123] = -456
+    message.map_int64_int64[-2**33] = -2**34
+    message.map_uint32_uint32[123] = 456
+    message.map_uint64_uint64[2**33] = 2**34
+    message.map_string_string['abc'] = '123'
+    message.map_int32_foreign_message[111].c = 5
+
+    # Maps are serialized to text format using their underlying repeated
+    # representation.
+    self.CompareToGoldenText(
+        text_format.MessageToString(message), 'map_int32_int32 {\n'
+        '  key: -123\n'
+        '  value: -456\n'
+        '}\n'
+        'map_int64_int64 {\n'
+        '  key: -8589934592\n'
+        '  value: -17179869184\n'
+        '}\n'
+        'map_uint32_uint32 {\n'
+        '  key: 123\n'
+        '  value: 456\n'
+        '}\n'
+        'map_uint64_uint64 {\n'
+        '  key: 8589934592\n'
+        '  value: 17179869184\n'
+        '}\n'
+        'map_string_string {\n'
+        '  key: "abc"\n'
+        '  value: "123"\n'
+        '}\n'
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    c: 5\n'
+        '  }\n'
+        '}\n')
+
+  def testDuplicateMapKey(self):
+    message = map_unittest_pb2.TestMap()
+    text = (
+        'map_uint64_uint64 {\n'
+        '  key: 123\n'
+        '  value: 17179869184\n'
+        '}\n'
+        'map_string_string {\n'
+        '  key: "abc"\n'
+        '  value: "first"\n'
+        '}\n'
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    c: 5\n'
+        '  }\n'
+        '}\n'
+        'map_uint64_uint64 {\n'
+        '  key: 123\n'
+        '  value: 321\n'
+        '}\n'
+        'map_string_string {\n'
+        '  key: "abc"\n'
+        '  value: "second"\n'
+        '}\n'
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    d: 5\n'
+        '  }\n'
+        '}\n')
+    text_format.Parse(text, message)
+    self.CompareToGoldenText(
+        text_format.MessageToString(message), 'map_uint64_uint64 {\n'
+        '  key: 123\n'
+        '  value: 321\n'
+        '}\n'
+        'map_string_string {\n'
+        '  key: "abc"\n'
+        '  value: "second"\n'
+        '}\n'
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    d: 5\n'
+        '  }\n'
+        '}\n')
+
+  # In cpp implementation, __str__ calls the cpp implementation of text format.
+  def testPrintMapUsingCppImplementation(self):
+    message = map_unittest_pb2.TestMap()
+    inner_msg = message.map_int32_foreign_message[111]
+    inner_msg.c = 1
+    self.assertEqual(
+        str(message),
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    c: 1\n'
+        '  }\n'
+        '}\n')
+    inner_msg.c = 2
+    self.assertEqual(
+        str(message),
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    c: 2\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)
+
+  # TODO(teboring): In c/137553523, not serializing default value for map entry
+  # message has been fixed. This test needs to be disabled in order to submit
+  # that cl. Add this back when c/137553523 has been submitted.
+  # def testMapOrderSemantics(self):
+  #   golden_lines = self.ReadGolden('map_test_data.txt')
+
+  #   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)
+  #   candidate = candidate.replace('0.0', '0', 2)
+  #   self.assertMultiLineEqual(candidate, ''.join(golden_lines))
+
+
+# Tests of proto2-only features (MessageSet, extensions, etc.).
+class Proto2Tests(TextFormatBase):
+
+  def testPrintMessageSet(self):
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message), 'message_set {\n'
+        '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+        '    i: 23\n'
+        '  }\n'
+        '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+        '    str: \"foo\"\n'
+        '  }\n'
+        '}\n')
+
+    message = message_set_extensions_pb2.TestMessageSet()
+    ext = message_set_extensions_pb2.message_set_extension3
+    message.Extensions[ext].text = 'bar'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        '[google.protobuf.internal.TestMessageSetExtension3] {\n'
+        '  text: \"bar\"\n'
+        '}\n')
+
+  def testPrintMessageSetByFieldNumber(self):
+    out = text_format.TextWriter(False)
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    text_format.PrintMessage(message, out, use_field_number=True)
+    self.CompareToGoldenText(out.getvalue(), '1 {\n'
+                             '  1545008 {\n'
+                             '    15: 23\n'
+                             '  }\n'
+                             '  1547769 {\n'
+                             '    25: \"foo\"\n'
+                             '  }\n'
+                             '}\n')
+    out.close()
+
+  def testPrintMessageSetAsOneLine(self):
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message, as_one_line=True),
+        'message_set {'
+        ' [protobuf_unittest.TestMessageSetExtension1] {'
+        ' i: 23'
+        ' }'
+        ' [protobuf_unittest.TestMessageSetExtension2] {'
+        ' str: \"foo\"'
+        ' }'
+        ' }')
+
+  def testParseMessageSet(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('repeated_uint64: 1\n' 'repeated_uint64: 2\n')
+    text_format.Parse(text, message)
+    self.assertEqual(1, message.repeated_uint64[0])
+    self.assertEqual(2, message.repeated_uint64[1])
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+            '    i: 23\n'
+            '  }\n'
+            '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+            '    str: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Parse(text, message)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
+
+  def testExtensionInsideAnyMessage(self):
+    message = test_extend_any.TestAny()
+    text = ('value {\n'
+            '  [type.googleapis.com/google.protobuf.internal.TestAny] {\n'
+            '    [google.protobuf.internal.TestAnyExtension1.extension1] {\n'
+            '      i: 10\n'
+            '    }\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, descriptor_pool=descriptor_pool.Default()),
+        text)
+
+  def testParseMessageByFieldNumber(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('34: 1\n' 'repeated_uint64: 2\n')
+    text_format.Parse(text, message, allow_field_number=True)
+    self.assertEqual(1, message.repeated_uint64[0])
+    self.assertEqual(2, message.repeated_uint64[1])
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('1 {\n'
+            '  1545008 {\n'
+            '    15: 23\n'
+            '  }\n'
+            '  1547769 {\n'
+            '    25: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Parse(text, message, allow_field_number=True)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
+
+    # Can't parse field number without set allow_field_number=True.
+    message = unittest_pb2.TestAllTypes()
+    text = '34:1\n'
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"34".'), text_format.Parse, text, message)
+
+    # Can't parse if field number is not found.
+    text = '1234:1\n'
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"1234".'),
+        text_format.Parse,
+        text,
+        message,
+        allow_field_number=True)
+
+  def testPrintAllExtensions(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'text_format_unittest_extensions_data.txt')
+
+  def testPrintAllExtensionsPointy(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message, pointy_brackets=True)),
+        'text_format_unittest_extensions_data_pointy.txt')
+
+  def testParseGoldenExtensions(self):
+    golden_text = '\n'.join(self.ReadGolden(
+        'text_format_unittest_extensions_data.txt'))
+    parsed_message = unittest_pb2.TestAllExtensions()
+    text_format.Parse(golden_text, parsed_message)
+
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.assertEqual(message, parsed_message)
+
+  def testParseAllExtensions(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    ascii_text = text_format.MessageToString(message)
+
+    parsed_message = unittest_pb2.TestAllExtensions()
+    text_format.Parse(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testParseAllowedUnknownExtension(self):
+    # Skip over unknown extension correctly.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [unknown_extension] {\n'
+            '    i: 23\n'
+            '    repeated_i: []\n'
+            '    bin: "\xe0"\n'
+            '    [nested_unknown_ext]: {\n'
+            '      i: 23\n'
+            '      repeated_i: [1, 2]\n'
+            '      x: x\n'
+            '      test: "test_string"\n'
+            '      floaty_float: -0.315\n'
+            '      num: -inf\n'
+            '      multiline_str: "abc"\n'
+            '          "def"\n'
+            '          "xyz."\n'
+            '      [nested_unknown_ext.ext]: <\n'
+            '        i: 23\n'
+            '        i: 24\n'
+            '        pointfloat: .3\n'
+            '        test: "test_string"\n'
+            '        repeated_test: ["test_string1", "test_string2"]\n'
+            '        floaty_float: -0.315\n'
+            '        num: -inf\n'
+            '        long_string: "test" "test2" \n'
+            '      >\n'
+            '    }\n'
+            '  }\n'
+            '  [unknown_extension]: 5\n'
+            '  [unknown_extension_with_number_field] {\n'
+            '    1: "some_field"\n'
+            '    2: -0.451\n'
+            '  }\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')
+    self.assertRaisesRegex(
+        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')
+    self.assertRaisesRegex(
+        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')
+    self.assertRaisesRegex(
+        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')
+    self.assertRaisesRegex(
+        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')
+    self.assertRaisesRegex(
+        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 correctly.
+    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 testParseBadIdentifier(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('optional_nested_message { "bb": 1 }')
+    with self.assertRaises(text_format.ParseError) as e:
+      text_format.Parse(text, message)
+    self.assertEqual(str(e.exception),
+                     '1:27 : \'optional_nested_message { "bb": 1 }\': '
+                     'Expected identifier or number, got "bb".')
+
+  def testParseBadExtension(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = '[unknown_extension]: 8\n'
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        '1:2 : Extension "unknown_extension" not registered.',
+        text_format.Parse, text, message)
+    message = unittest_pb2.TestAllTypes()
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
+         'extensions.'), text_format.Parse, text, message)
+
+  def testParseNumericUnknownEnum(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'optional_nested_enum: 100'
+    self.assertRaisesRegex(text_format.ParseError,
+                           (r'1:23 : \'optional_nested_enum: 100\': '
+                            r'Enum type "\w+.TestAllTypes.NestedEnum" '
+                            r'has no value with number 100.'),
+                           text_format.Parse, text, message)
+
+  def testMergeDuplicateExtensionScalars(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = ('[protobuf_unittest.optional_int32_extension]: 42 '
+            '[protobuf_unittest.optional_int32_extension]: 67')
+    text_format.Merge(text, message)
+    self.assertEqual(67,
+                     message.Extensions[unittest_pb2.optional_int32_extension])
+
+  def testParseDuplicateExtensionScalars(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = ('[protobuf_unittest.optional_int32_extension]: 42 '
+            '[protobuf_unittest.optional_int32_extension]: 67')
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
+         'should not have multiple '
+         '"protobuf_unittest.optional_int32_extension" extensions.'),
+        text_format.Parse, text, message)
+
+  def testParseDuplicateExtensionMessages(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = ('[protobuf_unittest.optional_nested_message_extension]: {} '
+            '[protobuf_unittest.optional_nested_message_extension]: {}')
+    self.assertRaisesRegex(
+        text_format.ParseError,
+        ('1:114 : Message type "protobuf_unittest.TestAllExtensions" '
+         'should not have multiple '
+         '"protobuf_unittest.optional_nested_message_extension" extensions.'),
+        text_format.Parse, text, message)
+
+  def testParseGroupNotClosed(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'RepeatedGroup: <'
+    self.assertRaisesRegex(text_format.ParseError, '1:16 : Expected ">".',
+                           text_format.Parse, text, message)
+    text = 'RepeatedGroup: {'
+    self.assertRaisesRegex(text_format.ParseError, '1:16 : Expected "}".',
+                           text_format.Parse, text, message)
+
+  def testParseEmptyGroup(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'OptionalGroup: {}'
+    text_format.Parse(text, message)
+    self.assertTrue(message.HasField('optionalgroup'))
+
+    message.Clear()
+
+    message = unittest_pb2.TestAllTypes()
+    text = 'OptionalGroup: <>'
+    text_format.Parse(text, message)
+    self.assertTrue(message.HasField('optionalgroup'))
+
+  # Maps aren't really proto2-only, but our test schema only has maps for
+  # proto2.
+  def testParseMap(self):
+    text = ('map_int32_int32 {\n'
+            '  key: -123\n'
+            '  value: -456\n'
+            '}\n'
+            'map_int64_int64 {\n'
+            '  key: -8589934592\n'
+            '  value: -17179869184\n'
+            '}\n'
+            'map_uint32_uint32 {\n'
+            '  key: 123\n'
+            '  value: 456\n'
+            '}\n'
+            'map_uint64_uint64 {\n'
+            '  key: 8589934592\n'
+            '  value: 17179869184\n'
+            '}\n'
+            'map_string_string {\n'
+            '  key: "abc"\n'
+            '  value: "123"\n'
+            '}\n'
+            'map_int32_foreign_message {\n'
+            '  key: 111\n'
+            '  value {\n'
+            '    c: 5\n'
+            '  }\n'
+            '}\n')
+    message = map_unittest_pb2.TestMap()
+    text_format.Parse(text, message)
+
+    self.assertEqual(-456, message.map_int32_int32[-123])
+    self.assertEqual(-2**34, message.map_int64_int64[-2**33])
+    self.assertEqual(456, message.map_uint32_uint32[123])
+    self.assertEqual(2**34, message.map_uint64_uint64[2**33])
+    self.assertEqual('123', message.map_string_string['abc'])
+    self.assertEqual(5, message.map_int32_foreign_message[111].c)
+
+
+class Proto3Tests(unittest.TestCase):
+
+  def testPrintMessageExpandAny(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'any_value {\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+        '    data: "string"\n'
+        '  }\n'
+        '}\n')
+
+  def testTopAnyMessage(self):
+    packed_msg = unittest_pb2.OneString()
+    msg = any_pb2.Any()
+    msg.Pack(packed_msg)
+    text = text_format.MessageToString(msg)
+    other_msg = text_format.Parse(text, any_pb2.Any())
+    self.assertEqual(msg, other_msg)
+
+  def testPrintMessageExpandAnyRepeated(self):
+    packed_message = unittest_pb2.OneString()
+    message = any_test_pb2.TestAny()
+    packed_message.data = 'string0'
+    message.repeated_any_value.add().Pack(packed_message)
+    packed_message.data = 'string1'
+    message.repeated_any_value.add().Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message),
+        'repeated_any_value {\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+        '    data: "string0"\n'
+        '  }\n'
+        '}\n'
+        'repeated_any_value {\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+        '    data: "string1"\n'
+        '  }\n'
+        '}\n')
+
+  def testPrintMessageExpandAnyDescriptorPoolMissingType(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    empty_pool = descriptor_pool.DescriptorPool()
+    self.assertEqual(
+        text_format.MessageToString(message, descriptor_pool=empty_pool),
+        'any_value {\n'
+        '  type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+        '  value: "\\n\\006string"\n'
+        '}\n')
+
+  def testPrintMessageExpandAnyPointyBrackets(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    pointy_brackets=True),
+        'any_value <\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] <\n'
+        '    data: "string"\n'
+        '  >\n'
+        '>\n')
+
+  def testPrintMessageExpandAnyAsOneLine(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    as_one_line=True),
+        'any_value {'
+        ' [type.googleapis.com/protobuf_unittest.OneString]'
+        ' { data: "string" } '
+        '}')
+
+  def testPrintMessageExpandAnyAsOneLinePointyBrackets(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    as_one_line=True,
+                                    pointy_brackets=True,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'any_value <'
+        ' [type.googleapis.com/protobuf_unittest.OneString]'
+        ' < data: "string" > '
+        '>')
+
+  def testPrintAndParseMessageInvalidAny(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    # Only include string after last '/' in type_url.
+    message.any_value.type_url = message.any_value.TypeName()
+    text = text_format.MessageToString(message)
+    self.assertEqual(
+        text, 'any_value {\n'
+        '  type_url: "protobuf_unittest.OneString"\n'
+        '  value: "\\n\\006string"\n'
+        '}\n')
+
+    parsed_message = any_test_pb2.TestAny()
+    text_format.Parse(text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testUnknownEnums(self):
+    message = unittest_proto3_arena_pb2.TestAllTypes()
+    message2 = unittest_proto3_arena_pb2.TestAllTypes()
+    message.optional_nested_enum = 999
+    text_string = text_format.MessageToString(message)
+    text_format.Parse(text_string, message2)
+    self.assertEqual(999, message2.optional_nested_enum)
+
+  def testMergeExpandedAny(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message)
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+    message.Clear()
+    text_format.Parse(text, message)
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+
+  def testMergeExpandedAnyRepeated(self):
+    message = any_test_pb2.TestAny()
+    text = ('repeated_any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string0"\n'
+            '  }\n'
+            '}\n'
+            'repeated_any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string1"\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message)
+    packed_message = unittest_pb2.OneString()
+    message.repeated_any_value[0].Unpack(packed_message)
+    self.assertEqual('string0', packed_message.data)
+    message.repeated_any_value[1].Unpack(packed_message)
+    self.assertEqual('string1', packed_message.data)
+
+  def testMergeExpandedAnyPointyBrackets(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] <\n'
+            '    data: "string"\n'
+            '  >\n'
+            '}\n')
+    text_format.Merge(text, message)
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+
+  def testMergeAlternativeUrl(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.otherapi.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message)
+    packed_message = unittest_pb2.OneString()
+    self.assertEqual('type.otherapi.com/protobuf_unittest.OneString',
+                     message.any_value.type_url)
+
+  def testMergeExpandedAnyDescriptorPoolMissingType(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n'
+            '  }\n'
+            '}\n')
+    with self.assertRaises(text_format.ParseError) as e:
+      empty_pool = descriptor_pool.DescriptorPool()
+      text_format.Merge(text, message, descriptor_pool=empty_pool)
+    self.assertEqual(
+        str(e.exception),
+        'Type protobuf_unittest.OneString not found in descriptor pool')
+
+  def testMergeUnexpandedAny(self):
+    text = ('any_value {\n'
+            '  type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+            '  value: "\\n\\006string"\n'
+            '}\n')
+    message = any_test_pb2.TestAny()
+    text_format.Merge(text, message)
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+
+  def testMergeMissingAnyEndToken(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n')
+    with self.assertRaises(text_format.ParseError) as e:
+      text_format.Merge(text, message)
+    self.assertEqual(str(e.exception), '3:11 : Expected "}".')
+
+  def testParseExpandedAnyListValue(self):
+    any_msg = any_pb2.Any()
+    any_msg.Pack(struct_pb2.ListValue())
+    msg = any_test_pb2.TestAny(any_value=any_msg)
+    text = ('any_value {\n'
+            '  [type.googleapis.com/google.protobuf.ListValue] {}\n'
+            '}\n')
+    parsed_msg = text_format.Parse(text, any_test_pb2.TestAny())
+    self.assertEqual(msg, parsed_msg)
+
+  def testProto3Optional(self):
+    msg = test_proto3_optional_pb2.TestProto3Optional()
+    self.assertEqual(text_format.MessageToString(msg), '')
+    msg.optional_int32 = 0
+    msg.optional_float = 0.0
+    msg.optional_string = ''
+    msg.optional_nested_message.bb = 0
+    text = ('optional_int32: 0\n'
+            'optional_float: 0.0\n'
+            'optional_string: ""\n'
+            'optional_nested_message {\n'
+            '  bb: 0\n'
+            '}\n')
+    self.assertEqual(text_format.MessageToString(msg), text)
+    msg2 = test_proto3_optional_pb2.TestProto3Optional()
+    text_format.Parse(text, msg2)
+    self.assertEqual(text_format.MessageToString(msg2), text)
+
+
+class TokenizerTest(unittest.TestCase):
+
+  def testSimpleTokenCases(self):
+    text = ('identifier1:"string1"\n     \n\n'
+            'identifier2 : \n \n123  \n  identifier3 :\'string\'\n'
+            'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n'
+            'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n'
+            'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
+            'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f '
+            'false_bool:  0 true_BOOL:t \n true_bool1:  1 false_BOOL1:f '
+            'False_bool: False True_bool: True X:iNf Y:-inF Z:nAN')
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), ':',
+               (tokenizer.ConsumeString, 'string1'),
+               (tokenizer.ConsumeIdentifier, 'identifier2'), ':',
+               (tokenizer.ConsumeInteger, 123),
+               (tokenizer.ConsumeIdentifier, 'identifier3'), ':',
+               (tokenizer.ConsumeString, 'string'),
+               (tokenizer.ConsumeIdentifier, 'identifiER_4'), ':',
+               (tokenizer.ConsumeFloat, 1.1e+2),
+               (tokenizer.ConsumeIdentifier, 'ID5'), ':',
+               (tokenizer.ConsumeFloat, -0.23),
+               (tokenizer.ConsumeIdentifier, 'ID6'), ':',
+               (tokenizer.ConsumeString, 'aaaa\'bbbb'),
+               (tokenizer.ConsumeIdentifier, 'ID7'), ':',
+               (tokenizer.ConsumeString, 'aa\"bb'),
+               (tokenizer.ConsumeIdentifier, 'ID8'), ':', '{',
+               (tokenizer.ConsumeIdentifier, 'A'), ':',
+               (tokenizer.ConsumeFloat, float('inf')),
+               (tokenizer.ConsumeIdentifier, 'B'), ':',
+               (tokenizer.ConsumeFloat, -float('inf')),
+               (tokenizer.ConsumeIdentifier, 'C'), ':',
+               (tokenizer.ConsumeBool, True),
+               (tokenizer.ConsumeIdentifier, 'D'), ':',
+               (tokenizer.ConsumeBool, False), '}',
+               (tokenizer.ConsumeIdentifier, 'ID9'), ':',
+               (tokenizer.ConsumeInteger, 22),
+               (tokenizer.ConsumeIdentifier, 'ID10'), ':',
+               (tokenizer.ConsumeInteger, -111111111111111111),
+               (tokenizer.ConsumeIdentifier, 'ID11'), ':',
+               (tokenizer.ConsumeInteger, -22),
+               (tokenizer.ConsumeIdentifier, 'ID12'), ':',
+               (tokenizer.ConsumeInteger, 2222222222222222222),
+               (tokenizer.ConsumeIdentifier, 'ID13'), ':',
+               (tokenizer.ConsumeFloat, 1.23456),
+               (tokenizer.ConsumeIdentifier, 'ID14'), ':',
+               (tokenizer.ConsumeFloat, 1.2e+2),
+               (tokenizer.ConsumeIdentifier, 'false_bool'), ':',
+               (tokenizer.ConsumeBool, False),
+               (tokenizer.ConsumeIdentifier, 'true_BOOL'), ':',
+               (tokenizer.ConsumeBool, True),
+               (tokenizer.ConsumeIdentifier, 'true_bool1'), ':',
+               (tokenizer.ConsumeBool, True),
+               (tokenizer.ConsumeIdentifier, 'false_BOOL1'), ':',
+               (tokenizer.ConsumeBool, False),
+               (tokenizer.ConsumeIdentifier, 'False_bool'), ':',
+               (tokenizer.ConsumeBool, False),
+               (tokenizer.ConsumeIdentifier, 'True_bool'), ':',
+               (tokenizer.ConsumeBool, True),
+               (tokenizer.ConsumeIdentifier, 'X'), ':',
+               (tokenizer.ConsumeFloat, float('inf')),
+               (tokenizer.ConsumeIdentifier, 'Y'), ':',
+               (tokenizer.ConsumeFloat, float('-inf')),
+               (tokenizer.ConsumeIdentifier, 'Z'), ':',
+               (tokenizer.ConsumeFloat, float('nan'))]
+
+    i = 0
+    while not tokenizer.AtEnd():
+      m = methods[i]
+      if isinstance(m, str):
+        token = tokenizer.token
+        self.assertEqual(token, m)
+        tokenizer.NextToken()
+      elif isinstance(m[1], float) and math.isnan(m[1]):
+        self.assertTrue(math.isnan(m[0]()))
+      else:
+        self.assertEqual(m[1], m[0]())
+      i += 1
+
+  def testConsumeAbstractIntegers(self):
+    # This test only tests the failures in the integer parsing methods as well
+    # as the '0' special cases.
+    int64_max = (1 << 63) - 1
+    uint32_max = (1 << 32) - 1
+    text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(-1, tokenizer.ConsumeInteger())
+
+    self.assertEqual(uint32_max + 1, tokenizer.ConsumeInteger())
+
+    self.assertEqual(int64_max + 1, tokenizer.ConsumeInteger())
+    self.assertTrue(tokenizer.AtEnd())
+
+    text = '-0 0 0 1.2'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(True, tokenizer.TryConsumeInteger())
+    self.assertEqual(False, tokenizer.TryConsumeInteger())
+    with self.assertRaises(text_format.ParseError):
+      tokenizer.ConsumeInteger()
+    self.assertEqual(1.2, tokenizer.ConsumeFloat())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeIntegers(self):
+    # This test only tests the failures in the integer parsing methods as well
+    # as the '0' special cases.
+    int64_max = (1 << 63) - 1
+    uint32_max = (1 << 32) - 1
+    text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeUint32, tokenizer)
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeUint64, tokenizer)
+    self.assertEqual(-1, text_format._ConsumeInt32(tokenizer))
+
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeUint32, tokenizer)
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeInt32, tokenizer)
+    self.assertEqual(uint32_max + 1, text_format._ConsumeInt64(tokenizer))
+
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeInt64, tokenizer)
+    self.assertEqual(int64_max + 1, text_format._ConsumeUint64(tokenizer))
+    self.assertTrue(tokenizer.AtEnd())
+
+    text = '-0 -0 0 0'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
+    self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
+    self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
+    self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeOctalIntegers(self):
+    """Test support for C style octal integers."""
+    text = '00 -00 04 0755 -010 007 -0033 08 -09 01'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(4, tokenizer.ConsumeInteger())
+    self.assertEqual(0o755, tokenizer.ConsumeInteger())
+    self.assertEqual(-0o10, tokenizer.ConsumeInteger())
+    self.assertEqual(7, tokenizer.ConsumeInteger())
+    self.assertEqual(-0o033, tokenizer.ConsumeInteger())
+    with self.assertRaises(text_format.ParseError):
+      tokenizer.ConsumeInteger()  # 08
+    tokenizer.NextToken()
+    with self.assertRaises(text_format.ParseError):
+      tokenizer.ConsumeInteger()  # -09
+    tokenizer.NextToken()
+    self.assertEqual(1, tokenizer.ConsumeInteger())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeByteString(self):
+    text = '"string1\''
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = 'string1"'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = '\n"\\xt"'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = '\n"\\"'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+    text = '\n"\\x"'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
+
+  def testConsumeBool(self):
+    text = 'not-a-bool'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
+
+  def testSkipComment(self):
+    tokenizer = text_format.Tokenizer('# some comment'.splitlines())
+    self.assertTrue(tokenizer.AtEnd())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+
+  def testConsumeComment(self):
+    tokenizer = text_format.Tokenizer('# some comment'.splitlines(),
+                                      skip_comments=False)
+    self.assertFalse(tokenizer.AtEnd())
+    self.assertEqual('# some comment', tokenizer.ConsumeComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeTwoComments(self):
+    text = '# some comment\n# another comment'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertEqual('# some comment', tokenizer.ConsumeComment())
+    self.assertFalse(tokenizer.AtEnd())
+    self.assertEqual('# another comment', tokenizer.ConsumeComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeTrailingComment(self):
+    text = 'some_number: 4\n# some comment'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+
+    self.assertEqual('some_number', tokenizer.ConsumeIdentifier())
+    self.assertEqual(tokenizer.token, ':')
+    tokenizer.NextToken()
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+    self.assertEqual(4, tokenizer.ConsumeInteger())
+    self.assertFalse(tokenizer.AtEnd())
+
+    self.assertEqual('# some comment', tokenizer.ConsumeComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeLineComment(self):
+    tokenizer = text_format.Tokenizer('# some comment'.splitlines(),
+                                      skip_comments=False)
+    self.assertFalse(tokenizer.AtEnd())
+    self.assertEqual((False, '# some comment'),
+                     tokenizer.ConsumeCommentOrTrailingComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeTwoLineComments(self):
+    text = '# some comment\n# another comment'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertEqual((False, '# some comment'),
+                     tokenizer.ConsumeCommentOrTrailingComment())
+    self.assertFalse(tokenizer.AtEnd())
+    self.assertEqual((False, '# another comment'),
+                     tokenizer.ConsumeCommentOrTrailingComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeAndCheckTrailingComment(self):
+    text = 'some_number: 4  # some comment'  # trailing comment on the same line
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertRaises(text_format.ParseError,
+                      tokenizer.ConsumeCommentOrTrailingComment)
+
+    self.assertEqual('some_number', tokenizer.ConsumeIdentifier())
+    self.assertEqual(tokenizer.token, ':')
+    tokenizer.NextToken()
+    self.assertRaises(text_format.ParseError,
+                      tokenizer.ConsumeCommentOrTrailingComment)
+    self.assertEqual(4, tokenizer.ConsumeInteger())
+    self.assertFalse(tokenizer.AtEnd())
+
+    self.assertEqual((True, '# some comment'),
+                     tokenizer.ConsumeCommentOrTrailingComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testHashinComment(self):
+    text = 'some_number: 4  # some comment # not a new comment'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertEqual('some_number', tokenizer.ConsumeIdentifier())
+    self.assertEqual(tokenizer.token, ':')
+    tokenizer.NextToken()
+    self.assertEqual(4, tokenizer.ConsumeInteger())
+    self.assertEqual((True, '# some comment # not a new comment'),
+                     tokenizer.ConsumeCommentOrTrailingComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testHugeString(self):
+    # With pathologic backtracking, fails with Forge OOM.
+    text = '"' + 'a' * (10 * 1024 * 1024) + '"'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    tokenizer.ConsumeString()
+
+
+# Tests for pretty printer functionality.
+@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2))
+class PrettyPrinterTest(TextFormatBase):
+
+  def testPrettyPrintNoMatch(self, message_module):
+
+    def printer(message, indent, as_one_line):
+      del message, indent, as_one_line
+      return None
+
+    message = message_module.TestAllTypes()
+    msg = message.repeated_nested_message.add()
+    msg.bb = 42
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=True, message_formatter=printer),
+        'repeated_nested_message { bb: 42 }')
+
+  def testPrettyPrintOneLine(self, message_module):
+
+    def printer(m, indent, as_one_line):
+      del indent, as_one_line
+      if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR:
+        return 'My lucky number is %s' % m.bb
+
+    message = message_module.TestAllTypes()
+    msg = message.repeated_nested_message.add()
+    msg.bb = 42
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=True, message_formatter=printer),
+        'repeated_nested_message { My lucky number is 42 }')
+
+  def testPrettyPrintMultiLine(self, message_module):
+
+    def printer(m, indent, as_one_line):
+      if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR:
+        line_deliminator = (' ' if as_one_line else '\n') + ' ' * indent
+        return 'My lucky number is:%s%s' % (line_deliminator, m.bb)
+      return None
+
+    message = message_module.TestAllTypes()
+    msg = message.repeated_nested_message.add()
+    msg.bb = 42
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=True, message_formatter=printer),
+        'repeated_nested_message { My lucky number is: 42 }')
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=False, message_formatter=printer),
+        'repeated_nested_message {\n  My lucky number is:\n  42\n}\n')
+
+  def testPrettyPrintEntireMessage(self, message_module):
+
+    def printer(m, indent, as_one_line):
+      del indent, as_one_line
+      if m.DESCRIPTOR == message_module.TestAllTypes.DESCRIPTOR:
+        return 'The is the message!'
+      return None
+
+    message = message_module.TestAllTypes()
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=False, message_formatter=printer),
+        'The is the message!\n')
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=True, message_formatter=printer),
+        'The is the message!')
+
+  def testPrettyPrintMultipleParts(self, message_module):
+
+    def printer(m, indent, as_one_line):
+      del indent, as_one_line
+      if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR:
+        return 'My lucky number is %s' % m.bb
+      return None
+
+    message = message_module.TestAllTypes()
+    message.optional_int32 = 61
+    msg = message.repeated_nested_message.add()
+    msg.bb = 42
+    msg = message.repeated_nested_message.add()
+    msg.bb = 99
+    msg = message.optional_nested_message
+    msg.bb = 1
+    self.CompareToGoldenText(
+        text_format.MessageToString(
+            message, as_one_line=True, message_formatter=printer),
+        ('optional_int32: 61 '
+         'optional_nested_message { My lucky number is 1 } '
+         'repeated_nested_message { My lucky number is 42 } '
+         'repeated_nested_message { My lucky number is 99 }'))
+
+    out = text_format.TextWriter(False)
+    text_format.PrintField(
+        message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
+            'optional_nested_message'],
+        message.optional_nested_message,
+        out,
+        message_formatter=printer)
+    self.assertEqual(
+        'optional_nested_message {\n  My lucky number is 1\n}\n',
+        out.getvalue())
+    out.close()
+
+    out = text_format.TextWriter(False)
+    text_format.PrintFieldValue(
+        message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
+            'optional_nested_message'],
+        message.optional_nested_message,
+        out,
+        message_formatter=printer)
+    self.assertEqual(
+        '{\n  My lucky number is 1\n}',
+        out.getvalue())
+    out.close()
+
+
+class WhitespaceTest(TextFormatBase):
+
+  def setUp(self):
+    self.out = text_format.TextWriter(False)
+    self.addCleanup(self.out.close)
+    self.message = unittest_pb2.NestedTestAllTypes()
+    self.message.child.payload.optional_string = 'value'
+    self.field = self.message.DESCRIPTOR.fields_by_name['child']
+    self.value = self.message.child
+
+  def testMessageToString(self):
+    self.CompareToGoldenText(
+        text_format.MessageToString(self.message),
+        textwrap.dedent("""\
+            child {
+              payload {
+                optional_string: "value"
+              }
+            }
+            """))
+
+  def testPrintMessage(self):
+    text_format.PrintMessage(self.message, self.out)
+    self.CompareToGoldenText(
+        self.out.getvalue(),
+        textwrap.dedent("""\
+            child {
+              payload {
+                optional_string: "value"
+              }
+            }
+            """))
+
+  def testPrintField(self):
+    text_format.PrintField(self.field, self.value, self.out)
+    self.CompareToGoldenText(
+        self.out.getvalue(),
+        textwrap.dedent("""\
+            child {
+              payload {
+                optional_string: "value"
+              }
+            }
+            """))
+
+  def testPrintFieldValue(self):
+    text_format.PrintFieldValue(
+        self.field, self.value, self.out)
+    self.CompareToGoldenText(
+        self.out.getvalue(),
+        textwrap.dedent("""\
+            {
+              payload {
+                optional_string: "value"
+              }
+            }"""))
+
+
+class OptionalColonMessageToStringTest(unittest.TestCase):
+
+  def testForcePrintOptionalColon(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    output = text_format.MessageToString(
+        message,
+        force_colon=True)
+    expected = ('any_value: {\n'
+                '  [type.googleapis.com/protobuf_unittest.OneString]: {\n'
+                '    data: "string"\n'
+                '  }\n'
+                '}\n')
+    self.assertEqual(expected, output)
+
+  def testPrintShortFormatRepeatedFields(self):
+    message = unittest_pb2.TestAllTypes()
+    message.repeated_int32.append(1)
+    output = text_format.MessageToString(
+        message, use_short_repeated_primitives=True, force_colon=True)
+    self.assertEqual('repeated_int32: [1]\n', output)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
new file mode 100644
index 0000000..a53e71f
--- /dev/null
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -0,0 +1,435 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Provides type checking routines.
+
+This module defines type checking utilities in the forms of dictionaries:
+
+VALUE_CHECKERS: A dictionary of field types and a value validation object.
+TYPE_TO_BYTE_SIZE_FN: A dictionary with field types and a size computing
+  function.
+TYPE_TO_SERIALIZE_METHOD: A dictionary with field types and serialization
+  function.
+FIELD_TYPE_TO_WIRE_TYPE: A dictionary with field typed and their
+  corresponding wire types.
+TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization
+  function.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import ctypes
+import numbers
+
+from google.protobuf.internal import decoder
+from google.protobuf.internal import encoder
+from google.protobuf.internal import wire_format
+from google.protobuf import descriptor
+
+_FieldDescriptor = descriptor.FieldDescriptor
+
+
+def TruncateToFourByteFloat(original):
+  return ctypes.c_float(original).value
+
+
+def ToShortestFloat(original):
+  """Returns the shortest float that has same value in wire."""
+  # All 4 byte floats have between 6 and 9 significant digits, so we
+  # start with 6 as the lower bound.
+  # It has to be iterative because use '.9g' directly can not get rid
+  # of the noises for most values. For example if set a float_field=0.9
+  # use '.9g' will print 0.899999976.
+  precision = 6
+  rounded = float('{0:.{1}g}'.format(original, precision))
+  while TruncateToFourByteFloat(rounded) != original:
+    precision += 1
+    rounded = float('{0:.{1}g}'.format(original, precision))
+  return rounded
+
+
+def SupportsOpenEnums(field_descriptor):
+  return field_descriptor.containing_type.syntax == 'proto3'
+
+
+def GetTypeChecker(field):
+  """Returns a type checker for a message field of the specified types.
+
+  Args:
+    field: FieldDescriptor object for this field.
+
+  Returns:
+    An instance of TypeChecker which can be used to verify the types
+    of values assigned to a field of the specified type.
+  """
+  if (field.cpp_type == _FieldDescriptor.CPPTYPE_STRING and
+      field.type == _FieldDescriptor.TYPE_STRING):
+    return UnicodeValueChecker()
+  if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+    if SupportsOpenEnums(field):
+      # When open enums are supported, any int32 can be assigned.
+      return _VALUE_CHECKERS[_FieldDescriptor.CPPTYPE_INT32]
+    else:
+      return EnumValueChecker(field.enum_type)
+  return _VALUE_CHECKERS[field.cpp_type]
+
+
+# None of the typecheckers below make any attempt to guard against people
+# subclassing builtin types and doing weird things.  We're not trying to
+# protect against malicious clients here, just people accidentally shooting
+# themselves in the foot in obvious ways.
+class TypeChecker(object):
+
+  """Type checker used to catch type errors as early as possible
+  when the client is setting scalar fields in protocol messages.
+  """
+
+  def __init__(self, *acceptable_types):
+    self._acceptable_types = acceptable_types
+
+  def CheckValue(self, proposed_value):
+    """Type check the provided value and return it.
+
+    The returned value might have been normalized to another type.
+    """
+    if not isinstance(proposed_value, self._acceptable_types):
+      message = ('%.1024r has type %s, but expected one of: %s' %
+                 (proposed_value, type(proposed_value), self._acceptable_types))
+      raise TypeError(message)
+    return proposed_value
+
+
+class TypeCheckerWithDefault(TypeChecker):
+
+  def __init__(self, default_value, *acceptable_types):
+    TypeChecker.__init__(self, *acceptable_types)
+    self._default_value = default_value
+
+  def DefaultValue(self):
+    return self._default_value
+
+
+class BoolValueChecker(object):
+  """Type checker used for bool fields."""
+
+  def CheckValue(self, proposed_value):
+    if not hasattr(proposed_value, '__index__') or (
+        type(proposed_value).__module__ == 'numpy' and
+        type(proposed_value).__name__ == 'ndarray'):
+      message = ('%.1024r has type %s, but expected one of: %s' %
+                 (proposed_value, type(proposed_value), (bool, int)))
+      raise TypeError(message)
+    return bool(proposed_value)
+
+  def DefaultValue(self):
+    return False
+
+
+# IntValueChecker and its subclasses perform integer type-checks
+# and bounds-checks.
+class IntValueChecker(object):
+
+  """Checker used for integer fields.  Performs type-check and range check."""
+
+  def CheckValue(self, proposed_value):
+    if not hasattr(proposed_value, '__index__') or (
+        type(proposed_value).__module__ == 'numpy' and
+        type(proposed_value).__name__ == 'ndarray'):
+      message = ('%.1024r has type %s, but expected one of: %s' %
+                 (proposed_value, type(proposed_value), (int,)))
+      raise TypeError(message)
+
+    if not self._MIN <= int(proposed_value) <= self._MAX:
+      raise ValueError('Value out of range: %d' % proposed_value)
+    # We force all values to int to make alternate implementations where the
+    # distinction is more significant (e.g. the C++ implementation) simpler.
+    proposed_value = int(proposed_value)
+    return proposed_value
+
+  def DefaultValue(self):
+    return 0
+
+
+class EnumValueChecker(object):
+
+  """Checker used for enum fields.  Performs type-check and range check."""
+
+  def __init__(self, enum_type):
+    self._enum_type = enum_type
+
+  def CheckValue(self, proposed_value):
+    if not isinstance(proposed_value, numbers.Integral):
+      message = ('%.1024r has type %s, but expected one of: %s' %
+                 (proposed_value, type(proposed_value), (int,)))
+      raise TypeError(message)
+    if int(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):
+
+  """Checker used for string fields.
+
+  Always returns a unicode value, even if the input is of type str.
+  """
+
+  def CheckValue(self, proposed_value):
+    if not isinstance(proposed_value, (bytes, str)):
+      message = ('%.1024r has type %s, but expected one of: %s' %
+                 (proposed_value, type(proposed_value), (bytes, str)))
+      raise TypeError(message)
+
+    # If the value is of type 'bytes' make sure that it is valid UTF-8 data.
+    if isinstance(proposed_value, bytes):
+      try:
+        proposed_value = proposed_value.decode('utf-8')
+      except UnicodeDecodeError:
+        raise ValueError('%.1024r has type bytes, but isn\'t valid UTF-8 '
+                         'encoding. Non-UTF-8 strings must be converted to '
+                         'unicode objects before being added.' %
+                         (proposed_value))
+    else:
+      try:
+        proposed_value.encode('utf8')
+      except UnicodeEncodeError:
+        raise ValueError('%.1024r isn\'t a valid unicode string and '
+                         'can\'t be encoded in UTF-8.'%
+                         (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
+  # efficient.
+  _MIN = -2147483648
+  _MAX = 2147483647
+
+
+class Uint32ValueChecker(IntValueChecker):
+  _MIN = 0
+  _MAX = (1 << 32) - 1
+
+
+class Int64ValueChecker(IntValueChecker):
+  _MIN = -(1 << 63)
+  _MAX = (1 << 63) - 1
+
+
+class Uint64ValueChecker(IntValueChecker):
+  _MIN = 0
+  _MAX = (1 << 64) - 1
+
+
+# The max 4 bytes float is about 3.4028234663852886e+38
+_FLOAT_MAX = float.fromhex('0x1.fffffep+127')
+_FLOAT_MIN = -_FLOAT_MAX
+_INF = float('inf')
+_NEG_INF = float('-inf')
+
+
+class DoubleValueChecker(object):
+  """Checker used for double fields.
+
+  Performs type-check and range check.
+  """
+
+  def CheckValue(self, proposed_value):
+    """Check and convert proposed_value to float."""
+    if (not hasattr(proposed_value, '__float__') and
+        not hasattr(proposed_value, '__index__')) or (
+            type(proposed_value).__module__ == 'numpy' and
+            type(proposed_value).__name__ == 'ndarray'):
+      message = ('%.1024r has type %s, but expected one of: int, float' %
+                 (proposed_value, type(proposed_value)))
+      raise TypeError(message)
+    return float(proposed_value)
+
+  def DefaultValue(self):
+    return 0.0
+
+
+class FloatValueChecker(DoubleValueChecker):
+  """Checker used for float fields.
+
+  Performs type-check and range check.
+
+  Values exceeding a 32-bit float will be converted to inf/-inf.
+  """
+
+  def CheckValue(self, proposed_value):
+    """Check and convert proposed_value to float."""
+    converted_value = super().CheckValue(proposed_value)
+    # This inf rounding matches the C++ proto SafeDoubleToFloat logic.
+    if converted_value > _FLOAT_MAX:
+      return _INF
+    if converted_value < _FLOAT_MIN:
+      return _NEG_INF
+
+    return TruncateToFourByteFloat(converted_value)
+
+# Type-checkers for all scalar CPPTYPEs.
+_VALUE_CHECKERS = {
+    _FieldDescriptor.CPPTYPE_INT32: Int32ValueChecker(),
+    _FieldDescriptor.CPPTYPE_INT64: Int64ValueChecker(),
+    _FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
+    _FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
+    _FieldDescriptor.CPPTYPE_DOUBLE: DoubleValueChecker(),
+    _FieldDescriptor.CPPTYPE_FLOAT: FloatValueChecker(),
+    _FieldDescriptor.CPPTYPE_BOOL: BoolValueChecker(),
+    _FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes),
+}
+
+
+# Map from field type to a function F, such that F(field_num, value)
+# gives the total byte size for a value of the given type.  This
+# byte size includes tag information and any other additional space
+# associated with serializing "value".
+TYPE_TO_BYTE_SIZE_FN = {
+    _FieldDescriptor.TYPE_DOUBLE: wire_format.DoubleByteSize,
+    _FieldDescriptor.TYPE_FLOAT: wire_format.FloatByteSize,
+    _FieldDescriptor.TYPE_INT64: wire_format.Int64ByteSize,
+    _FieldDescriptor.TYPE_UINT64: wire_format.UInt64ByteSize,
+    _FieldDescriptor.TYPE_INT32: wire_format.Int32ByteSize,
+    _FieldDescriptor.TYPE_FIXED64: wire_format.Fixed64ByteSize,
+    _FieldDescriptor.TYPE_FIXED32: wire_format.Fixed32ByteSize,
+    _FieldDescriptor.TYPE_BOOL: wire_format.BoolByteSize,
+    _FieldDescriptor.TYPE_STRING: wire_format.StringByteSize,
+    _FieldDescriptor.TYPE_GROUP: wire_format.GroupByteSize,
+    _FieldDescriptor.TYPE_MESSAGE: wire_format.MessageByteSize,
+    _FieldDescriptor.TYPE_BYTES: wire_format.BytesByteSize,
+    _FieldDescriptor.TYPE_UINT32: wire_format.UInt32ByteSize,
+    _FieldDescriptor.TYPE_ENUM: wire_format.EnumByteSize,
+    _FieldDescriptor.TYPE_SFIXED32: wire_format.SFixed32ByteSize,
+    _FieldDescriptor.TYPE_SFIXED64: wire_format.SFixed64ByteSize,
+    _FieldDescriptor.TYPE_SINT32: wire_format.SInt32ByteSize,
+    _FieldDescriptor.TYPE_SINT64: wire_format.SInt64ByteSize
+    }
+
+
+# Maps from field types to encoder constructors.
+TYPE_TO_ENCODER = {
+    _FieldDescriptor.TYPE_DOUBLE: encoder.DoubleEncoder,
+    _FieldDescriptor.TYPE_FLOAT: encoder.FloatEncoder,
+    _FieldDescriptor.TYPE_INT64: encoder.Int64Encoder,
+    _FieldDescriptor.TYPE_UINT64: encoder.UInt64Encoder,
+    _FieldDescriptor.TYPE_INT32: encoder.Int32Encoder,
+    _FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Encoder,
+    _FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Encoder,
+    _FieldDescriptor.TYPE_BOOL: encoder.BoolEncoder,
+    _FieldDescriptor.TYPE_STRING: encoder.StringEncoder,
+    _FieldDescriptor.TYPE_GROUP: encoder.GroupEncoder,
+    _FieldDescriptor.TYPE_MESSAGE: encoder.MessageEncoder,
+    _FieldDescriptor.TYPE_BYTES: encoder.BytesEncoder,
+    _FieldDescriptor.TYPE_UINT32: encoder.UInt32Encoder,
+    _FieldDescriptor.TYPE_ENUM: encoder.EnumEncoder,
+    _FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Encoder,
+    _FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Encoder,
+    _FieldDescriptor.TYPE_SINT32: encoder.SInt32Encoder,
+    _FieldDescriptor.TYPE_SINT64: encoder.SInt64Encoder,
+    }
+
+
+# Maps from field types to sizer constructors.
+TYPE_TO_SIZER = {
+    _FieldDescriptor.TYPE_DOUBLE: encoder.DoubleSizer,
+    _FieldDescriptor.TYPE_FLOAT: encoder.FloatSizer,
+    _FieldDescriptor.TYPE_INT64: encoder.Int64Sizer,
+    _FieldDescriptor.TYPE_UINT64: encoder.UInt64Sizer,
+    _FieldDescriptor.TYPE_INT32: encoder.Int32Sizer,
+    _FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Sizer,
+    _FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Sizer,
+    _FieldDescriptor.TYPE_BOOL: encoder.BoolSizer,
+    _FieldDescriptor.TYPE_STRING: encoder.StringSizer,
+    _FieldDescriptor.TYPE_GROUP: encoder.GroupSizer,
+    _FieldDescriptor.TYPE_MESSAGE: encoder.MessageSizer,
+    _FieldDescriptor.TYPE_BYTES: encoder.BytesSizer,
+    _FieldDescriptor.TYPE_UINT32: encoder.UInt32Sizer,
+    _FieldDescriptor.TYPE_ENUM: encoder.EnumSizer,
+    _FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Sizer,
+    _FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Sizer,
+    _FieldDescriptor.TYPE_SINT32: encoder.SInt32Sizer,
+    _FieldDescriptor.TYPE_SINT64: encoder.SInt64Sizer,
+    }
+
+
+# Maps from field type to a decoder constructor.
+TYPE_TO_DECODER = {
+    _FieldDescriptor.TYPE_DOUBLE: decoder.DoubleDecoder,
+    _FieldDescriptor.TYPE_FLOAT: decoder.FloatDecoder,
+    _FieldDescriptor.TYPE_INT64: decoder.Int64Decoder,
+    _FieldDescriptor.TYPE_UINT64: decoder.UInt64Decoder,
+    _FieldDescriptor.TYPE_INT32: decoder.Int32Decoder,
+    _FieldDescriptor.TYPE_FIXED64: decoder.Fixed64Decoder,
+    _FieldDescriptor.TYPE_FIXED32: decoder.Fixed32Decoder,
+    _FieldDescriptor.TYPE_BOOL: decoder.BoolDecoder,
+    _FieldDescriptor.TYPE_STRING: decoder.StringDecoder,
+    _FieldDescriptor.TYPE_GROUP: decoder.GroupDecoder,
+    _FieldDescriptor.TYPE_MESSAGE: decoder.MessageDecoder,
+    _FieldDescriptor.TYPE_BYTES: decoder.BytesDecoder,
+    _FieldDescriptor.TYPE_UINT32: decoder.UInt32Decoder,
+    _FieldDescriptor.TYPE_ENUM: decoder.EnumDecoder,
+    _FieldDescriptor.TYPE_SFIXED32: decoder.SFixed32Decoder,
+    _FieldDescriptor.TYPE_SFIXED64: decoder.SFixed64Decoder,
+    _FieldDescriptor.TYPE_SINT32: decoder.SInt32Decoder,
+    _FieldDescriptor.TYPE_SINT64: decoder.SInt64Decoder,
+    }
+
+# Maps from field type to expected wiretype.
+FIELD_TYPE_TO_WIRE_TYPE = {
+    _FieldDescriptor.TYPE_DOUBLE: wire_format.WIRETYPE_FIXED64,
+    _FieldDescriptor.TYPE_FLOAT: wire_format.WIRETYPE_FIXED32,
+    _FieldDescriptor.TYPE_INT64: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_UINT64: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_INT32: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_FIXED64: wire_format.WIRETYPE_FIXED64,
+    _FieldDescriptor.TYPE_FIXED32: wire_format.WIRETYPE_FIXED32,
+    _FieldDescriptor.TYPE_BOOL: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_STRING:
+      wire_format.WIRETYPE_LENGTH_DELIMITED,
+    _FieldDescriptor.TYPE_GROUP: wire_format.WIRETYPE_START_GROUP,
+    _FieldDescriptor.TYPE_MESSAGE:
+      wire_format.WIRETYPE_LENGTH_DELIMITED,
+    _FieldDescriptor.TYPE_BYTES:
+      wire_format.WIRETYPE_LENGTH_DELIMITED,
+    _FieldDescriptor.TYPE_UINT32: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_ENUM: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_SFIXED32: wire_format.WIRETYPE_FIXED32,
+    _FieldDescriptor.TYPE_SFIXED64: wire_format.WIRETYPE_FIXED64,
+    _FieldDescriptor.TYPE_SINT32: wire_format.WIRETYPE_VARINT,
+    _FieldDescriptor.TYPE_SINT64: wire_format.WIRETYPE_VARINT,
+    }
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
new file mode 100644
index 0000000..64a0367
--- /dev/null
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -0,0 +1,461 @@
+# -*- coding: utf-8 -*-
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Test for preservation of unknown fields in the pure Python implementation."""
+
+__author__ = 'bohdank@google.com (Bohdan Koval)'
+
+import sys
+import unittest
+
+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 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 testing_refleaks
+from google.protobuf.internal import type_checkers
+from google.protobuf.internal import wire_format
+from google.protobuf import descriptor
+from google.protobuf import unknown_fields
+try:
+  import tracemalloc  # pylint: disable=g-import-not-at-top
+except ImportError:
+  # Requires python 3.4+
+  pass
+
+
+@testing_refleaks.TestCase
+class UnknownFieldsTest(unittest.TestCase):
+
+  def setUp(self):
+    self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    self.all_fields = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(self.all_fields)
+    self.all_fields_data = self.all_fields.SerializeToString()
+    self.empty_message = unittest_pb2.TestEmptyMessage()
+    self.empty_message.ParseFromString(self.all_fields_data)
+
+  def testSerialize(self):
+    data = self.empty_message.SerializeToString()
+
+    # Don't use assertEqual because we don't want to dump raw binary data to
+    # stdout.
+    self.assertTrue(data == self.all_fields_data)
+
+  def testSerializeProto3(self):
+    # Verify proto3 unknown fields behavior.
+    message = unittest_proto3_arena_pb2.TestEmptyMessage()
+    message.ParseFromString(self.all_fields_data)
+    self.assertEqual(self.all_fields_data, message.SerializeToString())
+
+  def testByteSize(self):
+    self.assertEqual(self.all_fields.ByteSize(), self.empty_message.ByteSize())
+
+  def testListFields(self):
+    # Make sure ListFields doesn't return unknown fields.
+    self.assertEqual(0, len(self.empty_message.ListFields()))
+
+  def testSerializeMessageSetWireFormatUnknownExtension(self):
+    # Create a message using the message set wire format with an unknown
+    # message.
+    raw = unittest_mset_pb2.RawMessageSet()
+
+    # Add an unknown extension.
+    item = raw.item.add()
+    item.type_id = 98218603
+    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 = message_set_extensions_pb2.TestMessageSet()
+    proto.MergeFromString(serialized)
+
+    unknown_field_set = unknown_fields.UnknownFieldSet(proto)
+    self.assertEqual(len(unknown_field_set), 1)
+    # Unknown field should have wire format data which can be parsed back to
+    # original message.
+    self.assertEqual(unknown_field_set[0].field_number, item.type_id)
+    self.assertEqual(unknown_field_set[0].wire_type,
+                     wire_format.WIRETYPE_LENGTH_DELIMITED)
+    d = unknown_field_set[0].data
+    message_new = message_set_extensions_pb2.TestMessageSetExtension1()
+    message_new.ParseFromString(d)
+    self.assertEqual(message1, message_new)
+
+    # Verify that the unknown extension is serialized unchanged
+    reserialized = proto.SerializeToString()
+    new_raw = unittest_mset_pb2.RawMessageSet()
+    new_raw.MergeFromString(reserialized)
+    self.assertEqual(raw, new_raw)
+
+  def testEquals(self):
+    message = unittest_pb2.TestEmptyMessage()
+    message.ParseFromString(self.all_fields_data)
+    self.assertEqual(self.empty_message, message)
+
+    self.all_fields.ClearField('optional_string')
+    message.ParseFromString(self.all_fields.SerializeToString())
+    self.assertNotEqual(self.empty_message, message)
+
+  def testDiscardUnknownFields(self):
+    self.empty_message.DiscardUnknownFields()
+    self.assertEqual(b'', self.empty_message.SerializeToString())
+    # Test message field and repeated message field.
+    message = unittest_pb2.TestAllTypes()
+    other_message = unittest_pb2.TestAllTypes()
+    other_message.optional_string = 'discard'
+    message.optional_nested_message.ParseFromString(
+        other_message.SerializeToString())
+    message.repeated_nested_message.add().ParseFromString(
+        other_message.SerializeToString())
+    self.assertNotEqual(
+        b'', message.optional_nested_message.SerializeToString())
+    self.assertNotEqual(
+        b'', message.repeated_nested_message[0].SerializeToString())
+    message.DiscardUnknownFields()
+    self.assertEqual(b'', message.optional_nested_message.SerializeToString())
+    self.assertEqual(
+        b'', message.repeated_nested_message[0].SerializeToString())
+
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_all_types[1].optional_nested_message.ParseFromString(
+        other_message.SerializeToString())
+    msg.map_string_string['1'] = 'test'
+    self.assertNotEqual(
+        b'',
+        msg.map_int32_all_types[1].optional_nested_message.SerializeToString())
+    msg.DiscardUnknownFields()
+    self.assertEqual(
+        b'',
+        msg.map_int32_all_types[1].optional_nested_message.SerializeToString())
+
+
+@testing_refleaks.TestCase
+class UnknownFieldsAccessorsTest(unittest.TestCase):
+
+  def setUp(self):
+    self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    self.all_fields = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(self.all_fields)
+    self.all_fields_data = self.all_fields.SerializeToString()
+    self.empty_message = unittest_pb2.TestEmptyMessage()
+    self.empty_message.ParseFromString(self.all_fields_data)
+
+  # InternalCheckUnknownField() is an additional Pure Python check which checks
+  # a detail of unknown fields. It cannot be used by the C++
+  # implementation because some protect members are called.
+  # The test is added for historical reasons. It is not necessary as
+  # serialized string is checked.
+  # TODO(jieluo): Remove message._unknown_fields.
+  def InternalCheckUnknownField(self, name, expected_value):
+    if api_implementation.Type() != 'python':
+      return
+    field_descriptor = self.descriptor.fields_by_name[name]
+    wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
+    field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
+    result_dict = {}
+    for tag_bytes, value in self.empty_message._unknown_fields:
+      if tag_bytes == field_tag:
+        decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0]
+        decoder(memoryview(value), 0, len(value), self.all_fields, result_dict)
+    self.assertEqual(expected_value, result_dict[field_descriptor])
+
+  def CheckUnknownField(self, name, unknown_field_set, expected_value):
+    field_descriptor = self.descriptor.fields_by_name[name]
+    expected_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[
+        field_descriptor.type]
+    for unknown_field in unknown_field_set:
+      if unknown_field.field_number == field_descriptor.number:
+        self.assertEqual(expected_type, unknown_field.wire_type)
+        if expected_type == 3:
+          # Check group
+          self.assertEqual(expected_value[0],
+                           unknown_field.data[0].field_number)
+          self.assertEqual(expected_value[1], unknown_field.data[0].wire_type)
+          self.assertEqual(expected_value[2], unknown_field.data[0].data)
+          continue
+        if expected_type == wire_format.WIRETYPE_LENGTH_DELIMITED:
+          self.assertIn(type(unknown_field.data), (str, bytes))
+        if field_descriptor.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          self.assertIn(unknown_field.data, expected_value)
+        else:
+          self.assertEqual(expected_value, unknown_field.data)
+
+  def testCheckUnknownFieldValue(self):
+    unknown_field_set = unknown_fields.UnknownFieldSet(self.empty_message)
+    # Test enum.
+    self.CheckUnknownField('optional_nested_enum',
+                           unknown_field_set,
+                           self.all_fields.optional_nested_enum)
+    self.InternalCheckUnknownField('optional_nested_enum',
+                                   self.all_fields.optional_nested_enum)
+
+    # Test repeated enum.
+    self.CheckUnknownField('repeated_nested_enum',
+                           unknown_field_set,
+                           self.all_fields.repeated_nested_enum)
+    self.InternalCheckUnknownField('repeated_nested_enum',
+                                   self.all_fields.repeated_nested_enum)
+
+    # Test varint.
+    self.CheckUnknownField('optional_int32',
+                           unknown_field_set,
+                           self.all_fields.optional_int32)
+    self.InternalCheckUnknownField('optional_int32',
+                                   self.all_fields.optional_int32)
+
+    # Test fixed32.
+    self.CheckUnknownField('optional_fixed32',
+                           unknown_field_set,
+                           self.all_fields.optional_fixed32)
+    self.InternalCheckUnknownField('optional_fixed32',
+                                   self.all_fields.optional_fixed32)
+
+    # Test fixed64.
+    self.CheckUnknownField('optional_fixed64',
+                           unknown_field_set,
+                           self.all_fields.optional_fixed64)
+    self.InternalCheckUnknownField('optional_fixed64',
+                                   self.all_fields.optional_fixed64)
+
+    # Test length delimited.
+    self.CheckUnknownField('optional_string',
+                           unknown_field_set,
+                           self.all_fields.optional_string.encode('utf-8'))
+    self.InternalCheckUnknownField('optional_string',
+                                   self.all_fields.optional_string)
+
+    # Test group.
+    self.CheckUnknownField('optionalgroup',
+                           unknown_field_set,
+                           (17, 0, 117))
+    self.InternalCheckUnknownField('optionalgroup',
+                                   self.all_fields.optionalgroup)
+
+    self.assertEqual(98, len(unknown_field_set))
+
+  def testCopyFrom(self):
+    message = unittest_pb2.TestEmptyMessage()
+    message.CopyFrom(self.empty_message)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
+
+  def testMergeFrom(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optional_int32 = 1
+    message.optional_uint32 = 2
+    source = unittest_pb2.TestEmptyMessage()
+    source.ParseFromString(message.SerializeToString())
+
+    message.ClearField('optional_int32')
+    message.optional_int64 = 3
+    message.optional_uint32 = 4
+    destination = unittest_pb2.TestEmptyMessage()
+    unknown_field_set = unknown_fields.UnknownFieldSet(destination)
+    self.assertEqual(0, len(unknown_field_set))
+    destination.ParseFromString(message.SerializeToString())
+    self.assertEqual(0, len(unknown_field_set))
+    unknown_field_set = unknown_fields.UnknownFieldSet(destination)
+    self.assertEqual(2, len(unknown_field_set))
+    destination.MergeFrom(source)
+    self.assertEqual(2, len(unknown_field_set))
+    # 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):
+    unknown_field_set = unknown_fields.UnknownFieldSet(self.empty_message)
+    self.empty_message.Clear()
+    # All cleared, even unknown fields.
+    self.assertEqual(self.empty_message.SerializeToString(), b'')
+    self.assertEqual(len(unknown_field_set), 98)
+
+  @unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4),
+                   'tracemalloc requires python 3.4+')
+  def testUnknownFieldsNoMemoryLeak(self):
+    # Call to UnknownFields must not leak memory
+    nb_leaks = 1234
+
+    def leaking_function():
+      for _ in range(nb_leaks):
+        unknown_fields.UnknownFieldSet(self.empty_message)
+
+    tracemalloc.start()
+    snapshot1 = tracemalloc.take_snapshot()
+    leaking_function()
+    snapshot2 = tracemalloc.take_snapshot()
+    top_stats = snapshot2.compare_to(snapshot1, 'lineno')
+    tracemalloc.stop()
+    # There's no easy way to look for a precise leak source.
+    # Rely on a "marker" count value while checking allocated memory.
+    self.assertEqual([], [x for x in top_stats if x.count_diff == nb_leaks])
+
+  def testSubUnknownFields(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optionalgroup.a = 123
+    destination = unittest_pb2.TestEmptyMessage()
+    destination.ParseFromString(message.SerializeToString())
+    sub_unknown_fields = unknown_fields.UnknownFieldSet(destination)[0].data
+    self.assertEqual(1, len(sub_unknown_fields))
+    self.assertEqual(sub_unknown_fields[0].data, 123)
+    destination.Clear()
+    self.assertEqual(1, len(sub_unknown_fields))
+    self.assertEqual(sub_unknown_fields[0].data, 123)
+    message.Clear()
+    message.optional_uint32 = 456
+    nested_message = unittest_pb2.NestedTestAllTypes()
+    nested_message.payload.optional_nested_message.ParseFromString(
+        message.SerializeToString())
+    unknown_field_set = unknown_fields.UnknownFieldSet(
+        nested_message.payload.optional_nested_message)
+    self.assertEqual(unknown_field_set[0].data, 456)
+    nested_message.ClearField('payload')
+    self.assertEqual(unknown_field_set[0].data, 456)
+    unknown_field_set = unknown_fields.UnknownFieldSet(
+        nested_message.payload.optional_nested_message)
+    self.assertEqual(0, len(unknown_field_set))
+
+  def testUnknownField(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optional_int32 = 123
+    destination = unittest_pb2.TestEmptyMessage()
+    destination.ParseFromString(message.SerializeToString())
+    unknown_field = unknown_fields.UnknownFieldSet(destination)[0]
+    destination.Clear()
+    self.assertEqual(unknown_field.data, 123)
+
+  def testUnknownExtensions(self):
+    message = unittest_pb2.TestEmptyMessageWithExtensions()
+    message.ParseFromString(self.all_fields_data)
+    self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 98)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
+
+
+@testing_refleaks.TestCase
+class UnknownEnumValuesTest(unittest.TestCase):
+
+  def setUp(self):
+    self.descriptor = missing_enum_values_pb2.TestEnumValues.DESCRIPTOR
+
+    self.message = missing_enum_values_pb2.TestEnumValues()
+    # TestEnumValues.ZERO = 0, but does not exist in the other NestedEnum.
+    self.message.optional_nested_enum = (
+        missing_enum_values_pb2.TestEnumValues.ZERO)
+    self.message.repeated_nested_enum.extend([
+        missing_enum_values_pb2.TestEnumValues.ZERO,
+        missing_enum_values_pb2.TestEnumValues.ONE,
+        ])
+    self.message.packed_nested_enum.extend([
+        missing_enum_values_pb2.TestEnumValues.ZERO,
+        missing_enum_values_pb2.TestEnumValues.ONE,
+        ])
+    self.message_data = self.message.SerializeToString()
+    self.missing_message = missing_enum_values_pb2.TestMissingEnumValues()
+    self.missing_message.ParseFromString(self.message_data)
+
+  # CheckUnknownField() is an additional Pure Python check which checks
+  # a detail of unknown fields. It cannot be used by the C++
+  # implementation because some protect members are called.
+  # The test is added for historical reasons. It is not necessary as
+  # serialized string is checked.
+
+  def CheckUnknownField(self, name, expected_value):
+    field_descriptor = self.descriptor.fields_by_name[name]
+    unknown_field_set = unknown_fields.UnknownFieldSet(self.missing_message)
+    self.assertIsInstance(unknown_field_set, unknown_fields.UnknownFieldSet)
+    count = 0
+    for field in unknown_field_set:
+      if field.field_number == field_descriptor.number:
+        count += 1
+        if field_descriptor.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          self.assertIn(field.data, expected_value)
+        else:
+          self.assertEqual(expected_value, field.data)
+    if field_descriptor.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+      self.assertEqual(count, len(expected_value))
+    else:
+      self.assertEqual(count, 1)
+
+  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)
+
+  def testUnknownEnumValue(self):
+    self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
+    self.assertEqual(self.missing_message.optional_nested_enum, 2)
+    # Clear does not do anything.
+    serialized = self.missing_message.SerializeToString()
+    self.missing_message.ClearField('optional_nested_enum')
+    self.assertEqual(self.missing_message.SerializeToString(), serialized)
+
+  def testUnknownRepeatedEnumValue(self):
+    self.assertEqual([], self.missing_message.repeated_nested_enum)
+
+  def testUnknownPackedEnumValue(self):
+    self.assertEqual([], self.missing_message.packed_nested_enum)
+
+  def testCheckUnknownFieldValueForEnum(self):
+    unknown_field_set = unknown_fields.UnknownFieldSet(self.missing_message)
+    self.assertEqual(len(unknown_field_set), 5)
+    self.CheckUnknownField('optional_nested_enum',
+                           self.message.optional_nested_enum)
+    self.CheckUnknownField('repeated_nested_enum',
+                           self.message.repeated_nested_enum)
+    self.CheckUnknownField('packed_nested_enum',
+                           self.message.packed_nested_enum)
+
+  def testRoundTrip(self):
+    new_message = missing_enum_values_pb2.TestEnumValues()
+    new_message.ParseFromString(self.missing_message.SerializeToString())
+    self.assertEqual(self.message, new_message)
+
+
+if __name__ == '__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..8881d75
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -0,0 +1,880 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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)'
+
+import calendar
+import collections.abc
+import datetime
+
+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
+_DURATION_SECONDS_MAX = 315576000000
+
+
+class Any(object):
+  """Class for Any Message type."""
+
+  __slots__ = ()
+
+  def Pack(self, msg, type_url_prefix='type.googleapis.com/',
+           deterministic=None):
+    """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(deterministic=deterministic)
+
+  def Unpack(self, msg):
+    """Unpacks the current Any message into specified message."""
+    descriptor = msg.DESCRIPTOR
+    if not self.Is(descriptor):
+      return False
+    msg.ParseFromString(self.value)
+    return True
+
+  def TypeName(self):
+    """Returns the protobuf type name of the inner message."""
+    # Only last part is to be used: b/25630112
+    return self.type_url.split('/')[-1]
+
+  def Is(self, descriptor):
+    """Checks if this Any represents the given protobuf type."""
+    return '/' in self.type_url and self.TypeName() == descriptor.full_name
+
+
+_EPOCH_DATETIME_NAIVE = datetime.datetime.utcfromtimestamp(0)
+_EPOCH_DATETIME_AWARE = datetime.datetime.fromtimestamp(
+    0, tz=datetime.timezone.utc)
+
+
+class Timestamp(object):
+  """Class for Timestamp message type."""
+
+  __slots__ = ()
+
+  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.datetime(1970, 1, 1) + datetime.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:
+      ValueError: On parsing problems.
+    """
+    if not isinstance(value, str):
+      raise ValueError('Timestamp JSON value not a string: {!r}'.format(value))
+    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 ValueError(
+          '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:]
+    if 't' in second_value:
+      raise ValueError(
+          'time data \'{0}\' does not match format \'%Y-%m-%dT%H:%M:%S\', '
+          'lowercase \'t\' is not accepted'.format(second_value))
+    date_object = datetime.datetime.strptime(second_value, _TIMESTAMPFOMAT)
+    td = date_object - datetime.datetime(1970, 1, 1)
+    seconds = td.seconds + td.days * _SECONDS_PER_DAY
+    if len(nano_value) > 9:
+      raise ValueError(
+          '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 ValueError('Failed to parse timestamp: invalid trailing'
+                         ' data {0}.'.format(value))
+    else:
+      timezone = value[timezone_offset:]
+      pos = timezone.find(':')
+      if pos == -1:
+        raise ValueError(
+            '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.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, tzinfo=None):
+    """Converts Timestamp to a datetime.
+
+    Args:
+      tzinfo: A datetime.tzinfo subclass; defaults to None.
+
+    Returns:
+      If tzinfo is None, returns a timezone-naive UTC datetime (with no timezone
+      information, i.e. not aware that it's UTC).
+
+      Otherwise, returns a timezone-aware datetime in the input timezone.
+    """
+    delta = datetime.timedelta(
+        seconds=self.seconds,
+        microseconds=_RoundTowardZero(self.nanos, _NANOS_PER_MICROSECOND))
+    if tzinfo is None:
+      return _EPOCH_DATETIME_NAIVE + delta
+    else:
+      return _EPOCH_DATETIME_AWARE.astimezone(tzinfo) + delta
+
+  def FromDatetime(self, dt):
+    """Converts datetime to Timestamp.
+
+    Args:
+      dt: A datetime. If it's timezone-naive, it's assumed to be in UTC.
+    """
+    # Using this guide: http://wiki.python.org/moin/WorkingWithTime
+    # And this conversion guide: http://docs.python.org/library/time.html
+
+    # Turn the date parameter into a tuple (struct_time) that can then be
+    # manipulated into a long value of seconds.  During the conversion from
+    # struct_time to long, the source date in UTC, and so it follows that the
+    # correct transformation is calendar.timegm()
+    self.seconds = calendar.timegm(dt.utctimetuple())
+    self.nanos = dt.microsecond * _NANOS_PER_MICROSECOND
+
+
+class Duration(object):
+  """Class for Duration message type."""
+
+  __slots__ = ()
+
+  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"
+    """
+    _CheckDurationValid(self.seconds, self.nanos)
+    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:
+      ValueError: On parsing problems.
+    """
+    if not isinstance(value, str):
+      raise ValueError('Duration JSON value not a string: {!r}'.format(value))
+    if len(value) < 1 or value[-1] != 's':
+      raise ValueError(
+          'Duration must end with letter "s": {0}.'.format(value))
+    try:
+      pos = value.find('.')
+      if pos == -1:
+        seconds = int(value[:-1])
+        nanos = 0
+      else:
+        seconds = int(value[:pos])
+        if value[0] == '-':
+          nanos = int(round(float('-0{0}'.format(value[pos: -1])) *1e9))
+        else:
+          nanos = int(round(float('0{0}'.format(value[pos: -1])) *1e9))
+      _CheckDurationValid(seconds, nanos)
+      self.seconds = seconds
+      self.nanos = nanos
+    except ValueError as e:
+      raise ValueError(
+          'Couldn\'t parse duration: {0} : {1}.'.format(value, e))
+
+  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 datetime.timedelta(
+        seconds=self.seconds, microseconds=_RoundTowardZero(
+            self.nanos, _NANOS_PER_MICROSECOND))
+
+  def FromTimedelta(self, td):
+    """Converts 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 nanos."""
+    # 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 _CheckDurationValid(seconds, nanos):
+  if seconds < -_DURATION_SECONDS_MAX or seconds > _DURATION_SECONDS_MAX:
+    raise ValueError(
+        'Duration is not valid: Seconds {0} must be in range '
+        '[-315576000000, 315576000000].'.format(seconds))
+  if nanos <= -_NANOS_PER_SECOND or nanos >= _NANOS_PER_SECOND:
+    raise ValueError(
+        'Duration is not valid: Nanos {0} must be in range '
+        '[-999999999, 999999999].'.format(nanos))
+  if (nanos < 0 and seconds > 0) or (nanos > 0 and seconds < 0):
+    raise ValueError(
+        'Duration is not valid: Sign mismatch.')
+
+
+def _RoundTowardZero(value, divider):
+  """Truncates the remainder part after division."""
+  # For some languages, 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."""
+
+  __slots__ = ()
+
+  def ToJsonString(self):
+    """Converts FieldMask to string according to proto3 JSON spec."""
+    camelcase_paths = []
+    for path in self.paths:
+      camelcase_paths.append(_SnakeCaseToCamelCase(path))
+    return ','.join(camelcase_paths)
+
+  def FromJsonString(self, value):
+    """Converts string to FieldMask according to proto3 JSON spec."""
+    if not isinstance(value, str):
+      raise ValueError('FieldMask JSON value not a string: {!r}'.format(value))
+    self.Clear()
+    if value:
+      for path in value.split(','):
+        self.paths.append(_CamelCaseToSnakeCase(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.get(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))
+
+
+def _SnakeCaseToCamelCase(path_name):
+  """Converts a path name from snake_case to camelCase."""
+  result = []
+  after_underscore = False
+  for c in path_name:
+    if c.isupper():
+      raise ValueError(
+          'Fail to print FieldMask to Json string: Path name '
+          '{0} must not contain uppercase letters.'.format(path_name))
+    if after_underscore:
+      if c.islower():
+        result.append(c.upper())
+        after_underscore = False
+      else:
+        raise ValueError(
+            'Fail to print FieldMask to Json string: The '
+            'character after a "_" must be a lowercase letter '
+            'in path name {0}.'.format(path_name))
+    elif c == '_':
+      after_underscore = True
+    else:
+      result += c
+
+  if after_underscore:
+    raise ValueError('Fail to print FieldMask to Json string: Trailing "_" '
+                     'in path name {0}.'.format(path_name))
+  return ''.join(result)
+
+
+def _CamelCaseToSnakeCase(path_name):
+  """Converts a field name from camelCase to snake_case."""
+  result = []
+  for c in path_name:
+    if c == '_':
+      raise ValueError('Fail to parse FieldMask: Path name '
+                       '{0} must not contain "_"s.'.format(path_name))
+    if c.isupper():
+      result += '_'
+      result += c.lower()
+    else:
+      result += c
+  return ''.join(result)
+
+
+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.
+  """
+
+  __slots__ = ('_root',)
+
+  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))
+      if source.HasField(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)
+      repeated_destination.MergeFrom(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 and prefix:
+    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)
+
+
+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, str):
+    struct_value.string_value = value
+  elif isinstance(value, (int, float)):
+    struct_value.number_value = value
+  elif isinstance(value, (dict, Struct)):
+    struct_value.struct_value.Clear()
+    struct_value.struct_value.update(value)
+  elif isinstance(value, (list, ListValue)):
+    struct_value.list_value.Clear()
+    struct_value.list_value.extend(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 __contains__(self, item):
+    return item in self.fields
+
+  def __setitem__(self, key, value):
+    _SetStructValue(self.fields[key], value)
+
+  def __delitem__(self, key):
+    del self.fields[key]
+
+  def __len__(self):
+    return len(self.fields)
+
+  def __iter__(self):
+    return iter(self.fields)
+
+  def keys(self):  # pylint: disable=invalid-name
+    return self.fields.keys()
+
+  def values(self):  # pylint: disable=invalid-name
+    return [self[key] for key in self]
+
+  def items(self):  # pylint: disable=invalid-name
+    return [(key, self[key]) for key in self]
+
+  def get_or_create_list(self, key):
+    """Returns a list for this key, creating if it didn't exist already."""
+    if not self.fields[key].HasField('list_value'):
+      # Clear will mark list_value modified which will indeed create a list.
+      self.fields[key].list_value.Clear()
+    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."""
+    if not self.fields[key].HasField('struct_value'):
+      # Clear will mark struct_value modified which will indeed create a struct.
+      self.fields[key].struct_value.Clear()
+    return self.fields[key].struct_value
+
+  def update(self, dictionary):  # pylint: disable=invalid-name
+    for key, value in dictionary.items():
+      _SetStructValue(self.fields[key], value)
+
+collections.abc.MutableMapping.register(Struct)
+
+
+class ListValue(object):
+  """Class for ListValue message type."""
+
+  __slots__ = ()
+
+  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 __delitem__(self, key):
+    del self.values[key]
+
+  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."""
+    struct_value = self.values.add().struct_value
+    # Clear will mark struct_value modified which will indeed create a struct.
+    struct_value.Clear()
+    return struct_value
+
+  def add_list(self):
+    """Appends and returns a list value as the next value in the list."""
+    list_value = self.values.add().list_value
+    # Clear will mark list_value modified which will indeed create a list.
+    list_value.Clear()
+    return list_value
+
+collections.abc.MutableSequence.register(ListValue)
+
+
+# LINT.IfChange(wktbases)
+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,
+}
+# LINT.ThenChange(//depot/google.protobuf/compiler/python/pyi_generator.cc:wktbases)
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..a32459a
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -0,0 +1,1013 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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)'
+
+import collections.abc as collections_abc
+import datetime
+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 map_unittest_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
+from google.protobuf.internal import _parameterized
+
+try:
+  # New module in Python 3.9:
+  import zoneinfo  # pylint:disable=g-import-not-at-top
+  _TZ_JAPAN = zoneinfo.ZoneInfo('Japan')
+  _TZ_PACIFIC = zoneinfo.ZoneInfo('US/Pacific')
+except ImportError:
+  _TZ_JAPAN = datetime.timezone(datetime.timedelta(hours=9), 'Japan')
+  _TZ_PACIFIC = datetime.timezone(datetime.timedelta(hours=-8), 'US/Pacific')
+
+
+class TimeUtilTestBase(_parameterized.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 accepts offsets.
+    message.FromJsonString('1970-01-01T00:00:00-08:00')
+    self.assertEqual(8 * 3600, message.seconds)
+    self.assertEqual(0, message.nanos)
+
+    # It is not easy to check with current time. For test coverage only.
+    message.GetCurrentTime()
+    self.assertNotEqual(8 * 3600, message.seconds)
+
+  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 testTimezoneNaiveDatetimeConversion(self):
+    message = timestamp_pb2.Timestamp()
+    naive_utc_epoch = datetime.datetime(1970, 1, 1)
+    message.FromDatetime(naive_utc_epoch)
+    self.assertEqual(0, message.seconds)
+    self.assertEqual(0, message.nanos)
+
+    self.assertEqual(naive_utc_epoch, message.ToDatetime())
+
+    naive_epoch_morning = datetime.datetime(1970, 1, 1, 8, 0, 0, 1)
+    message.FromDatetime(naive_epoch_morning)
+    self.assertEqual(8 * 3600, message.seconds)
+    self.assertEqual(1000, message.nanos)
+
+    self.assertEqual(naive_epoch_morning, message.ToDatetime())
+
+    message.FromMilliseconds(1999)
+    self.assertEqual(1, message.seconds)
+    self.assertEqual(999_000_000, message.nanos)
+
+    self.assertEqual(datetime.datetime(1970, 1, 1, 0, 0, 1, 999000),
+                     message.ToDatetime())
+
+    naive_future = datetime.datetime(2555, 2, 22, 1, 2, 3, 456789)
+    message.FromDatetime(naive_future)
+    self.assertEqual(naive_future, message.ToDatetime())
+
+    naive_end_of_time = datetime.datetime.max
+    message.FromDatetime(naive_end_of_time)
+    self.assertEqual(naive_end_of_time, message.ToDatetime())
+
+  # Two hours after the Unix Epoch, around the world.
+  @_parameterized.named_parameters(
+      ('London', [1970, 1, 1, 2], datetime.timezone.utc),
+      ('Tokyo', [1970, 1, 1, 11], _TZ_JAPAN),
+      ('LA', [1969, 12, 31, 18], _TZ_PACIFIC),
+  )
+  def testTimezoneAwareDatetimeConversion(self, date_parts, tzinfo):
+    original_datetime = datetime.datetime(*date_parts, tzinfo=tzinfo)  # pylint:disable=g-tzinfo-datetime
+
+    message = timestamp_pb2.Timestamp()
+    message.FromDatetime(original_datetime)
+    self.assertEqual(7200, message.seconds)
+    self.assertEqual(0, message.nanos)
+
+    # ToDatetime() with no parameters produces a naive UTC datetime, i.e. it not
+    # only loses the original timezone information (e.g. US/Pacific) as it's
+    # "normalised" to UTC, but also drops the information that the datetime
+    # represents a UTC one.
+    naive_datetime = message.ToDatetime()
+    self.assertEqual(datetime.datetime(1970, 1, 1, 2), naive_datetime)
+    self.assertIsNone(naive_datetime.tzinfo)
+    self.assertNotEqual(original_datetime, naive_datetime)  # not even for UTC!
+
+    # In contrast, ToDatetime(tzinfo=) produces an aware datetime in the given
+    # timezone.
+    aware_datetime = message.ToDatetime(tzinfo=tzinfo)
+    self.assertEqual(original_datetime, aware_datetime)
+    self.assertEqual(
+        datetime.datetime(1970, 1, 1, 2, tzinfo=datetime.timezone.utc),
+        aware_datetime)
+    self.assertEqual(tzinfo, aware_datetime.tzinfo)
+
+  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.assertRaisesRegex(
+        ValueError, 'Failed to parse timestamp: missing valid timezone offset.',
+        message.FromJsonString, '')
+    self.assertRaisesRegex(
+        ValueError, 'Failed to parse timestamp: invalid trailing data '
+        '1970-01-01T00:00:01Ztrail.', message.FromJsonString,
+        '1970-01-01T00:00:01Ztrail')
+    self.assertRaisesRegex(
+        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.assertRaisesRegex(
+        ValueError, 'nanos 0123456789012 more than 9 fractional digits.',
+        message.FromJsonString, '1970-01-01T00:00:00.0123456789012Z')
+    self.assertRaisesRegex(
+        ValueError,
+        (r'Invalid timezone offset value: \+08.'),
+        message.FromJsonString,
+        '1972-01-01T01:00:00.01+08',
+    )
+    self.assertRaisesRegex(ValueError, 'year (0 )?is out of range',
+                           message.FromJsonString, '0000-01-01T00:00:00Z')
+    message.seconds = 253402300800
+    self.assertRaisesRegex(OverflowError, 'date value out of range',
+                           message.ToJsonString)
+
+  def testInvalidDuration(self):
+    message = duration_pb2.Duration()
+    self.assertRaisesRegex(ValueError, 'Duration must end with letter "s": 1.',
+                           message.FromJsonString, '1')
+    self.assertRaisesRegex(ValueError, 'Couldn\'t parse duration: 1...2s.',
+                           message.FromJsonString, '1...2s')
+    text = '-315576000001.000000000s'
+    self.assertRaisesRegex(
+        ValueError,
+        r'Duration is not valid\: Seconds -315576000001 must be in range'
+        r' \[-315576000000\, 315576000000\].', message.FromJsonString, text)
+    text = '315576000001.000000000s'
+    self.assertRaisesRegex(
+        ValueError,
+        r'Duration is not valid\: Seconds 315576000001 must be in range'
+        r' \[-315576000000\, 315576000000\].', message.FromJsonString, text)
+    message.seconds = -315576000001
+    message.nanos = 0
+    self.assertRaisesRegex(
+        ValueError,
+        r'Duration is not valid\: Seconds -315576000001 must be in range'
+        r' \[-315576000000\, 315576000000\].', message.ToJsonString)
+    message.seconds = 0
+    message.nanos = 999999999 + 1
+    self.assertRaisesRegex(
+        ValueError, r'Duration is not valid\: Nanos 1000000000 must be in range'
+        r' \[-999999999\, 999999999\].', message.ToJsonString)
+    message.seconds = -1
+    message.nanos = 1
+    self.assertRaisesRegex(ValueError,
+                           r'Duration is not valid\: Sign mismatch.',
+                           message.ToJsonString)
+
+
+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)
+
+    # Test camel case
+    mask.Clear()
+    mask.paths.append('foo_bar')
+    self.assertEqual('fooBar', mask.ToJsonString())
+    mask.paths.append('bar_quz')
+    self.assertEqual('fooBar,barQuz', mask.ToJsonString())
+
+    mask.FromJsonString('')
+    self.assertEqual('', mask.ToJsonString())
+    self.assertEqual([], mask.paths)
+    mask.FromJsonString('fooBar')
+    self.assertEqual(['foo_bar'], mask.paths)
+    mask.FromJsonString('fooBar,barQuz')
+    self.assertEqual(['foo_bar', 'bar_quz'], mask.paths)
+
+  def testDescriptorToFieldMask(self):
+    mask = field_mask_pb2.FieldMask()
+    msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    mask.AllFieldsFromDescriptor(msg_descriptor)
+    self.assertEqual(76, len(mask.paths))
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    for field in msg_descriptor.fields:
+      self.assertTrue(field.name in mask.paths)
+
+  def testIsValidForDescriptor(self):
+    msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    # Empty mask
+    mask = field_mask_pb2.FieldMask()
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    # All fields from descriptor
+    mask.AllFieldsFromDescriptor(msg_descriptor)
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    # Child under optional message
+    mask.paths.append('optional_nested_message.bb')
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    # Repeated field is only allowed in the last position of path
+    mask.paths.append('repeated_nested_message.bb')
+    self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
+    # Invalid top level field
+    mask = field_mask_pb2.FieldMask()
+    mask.paths.append('xxx')
+    self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
+    # Invalid field in root
+    mask = field_mask_pb2.FieldMask()
+    mask.paths.append('xxx.zzz')
+    self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
+    # Invalid field in internal node
+    mask = field_mask_pb2.FieldMask()
+    mask.paths.append('optional_nested_message.xxx.zzz')
+    self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
+    # Invalid field in leaf
+    mask = field_mask_pb2.FieldMask()
+    mask.paths.append('optional_nested_message.xxx')
+    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())
+    src = unittest_pb2.TestAllTypes()
+    with self.assertRaises(ValueError):
+      out_mask.Union(src, mask2)
+
+  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())
+    self.assertEqual(len(out_mask.paths), 0)
+    self.assertEqual(out_mask.paths, [])
+    # 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())
+    # Intersect '' with ''
+    mask1.Clear()
+    mask2.Clear()
+    mask1.paths.append('')
+    mask2.paths.append('')
+    self.assertEqual(mask1.paths, [''])
+    self.assertEqual('', mask1.ToJsonString())
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual(out_mask.paths, [])
+
+  def testMergeMessageWithoutMapFields(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.repeatedInt32')
+    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.repeatedInt32')
+    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])
+
+    # Test Merge oneof field.
+    new_msg = unittest_pb2.TestOneof2()
+    dst = unittest_pb2.TestOneof2()
+    dst.foo_message.moo_int = 1
+    mask = field_mask_pb2.FieldMask()
+    mask.FromJsonString('fooMessage,fooLazyMessage.mooInt')
+    mask.MergeMessage(new_msg, dst)
+    self.assertTrue(dst.HasField('foo_message'))
+    self.assertFalse(dst.HasField('foo_lazy_message'))
+
+  def testMergeMessageWithMapField(self):
+    empty_map = map_unittest_pb2.TestRecursiveMapMessage()
+    src_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
+    src_level_2.a['src level 2'].CopyFrom(empty_map)
+    src = map_unittest_pb2.TestRecursiveMapMessage()
+    src.a['common key'].CopyFrom(src_level_2)
+    src.a['src level 1'].CopyFrom(src_level_2)
+
+    dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
+    dst_level_2.a['dst level 2'].CopyFrom(empty_map)
+    dst = map_unittest_pb2.TestRecursiveMapMessage()
+    dst.a['common key'].CopyFrom(dst_level_2)
+    dst.a['dst level 1'].CopyFrom(empty_map)
+
+    mask = field_mask_pb2.FieldMask()
+    mask.FromJsonString('a')
+    mask.MergeMessage(src, dst)
+
+    # map from dst is replaced with map from src.
+    self.assertEqual(dst.a['common key'], src_level_2)
+    self.assertEqual(dst.a['src level 1'], src_level_2)
+    self.assertEqual(dst.a['dst level 1'], empty_map)
+
+  def testMergeErrors(self):
+    src = unittest_pb2.TestAllTypes()
+    dst = unittest_pb2.TestAllTypes()
+    mask = field_mask_pb2.FieldMask()
+    test_util.SetAllFields(src)
+    mask.FromJsonString('optionalInt32.field')
+    with self.assertRaises(ValueError) as e:
+      mask.MergeMessage(src, dst)
+    self.assertEqual('Error: Field optional_int32 in message '
+                     'protobuf_unittest.TestAllTypes is not a singular '
+                     'message field and cannot have sub-fields.',
+                     str(e.exception))
+
+  def testSnakeCaseToCamelCase(self):
+    self.assertEqual('fooBar',
+                     well_known_types._SnakeCaseToCamelCase('foo_bar'))
+    self.assertEqual('FooBar',
+                     well_known_types._SnakeCaseToCamelCase('_foo_bar'))
+    self.assertEqual('foo3Bar',
+                     well_known_types._SnakeCaseToCamelCase('foo3_bar'))
+
+    # No uppercase letter is allowed.
+    self.assertRaisesRegex(
+        ValueError,
+        'Fail to print FieldMask to Json string: Path name Foo must '
+        'not contain uppercase letters.',
+        well_known_types._SnakeCaseToCamelCase, 'Foo')
+    # Any character after a "_" must be a lowercase letter.
+    #   1. "_" cannot be followed by another "_".
+    #   2. "_" cannot be followed by a digit.
+    #   3. "_" cannot appear as the last character.
+    self.assertRaisesRegex(
+        ValueError,
+        'Fail to print FieldMask to Json string: The character after a '
+        '"_" must be a lowercase letter in path name foo__bar.',
+        well_known_types._SnakeCaseToCamelCase, 'foo__bar')
+    self.assertRaisesRegex(
+        ValueError,
+        'Fail to print FieldMask to Json string: The character after a '
+        '"_" must be a lowercase letter in path name foo_3bar.',
+        well_known_types._SnakeCaseToCamelCase, 'foo_3bar')
+    self.assertRaisesRegex(
+        ValueError,
+        'Fail to print FieldMask to Json string: Trailing "_" in path '
+        'name foo_bar_.', well_known_types._SnakeCaseToCamelCase, 'foo_bar_')
+
+  def testCamelCaseToSnakeCase(self):
+    self.assertEqual('foo_bar',
+                     well_known_types._CamelCaseToSnakeCase('fooBar'))
+    self.assertEqual('_foo_bar',
+                     well_known_types._CamelCaseToSnakeCase('FooBar'))
+    self.assertEqual('foo3_bar',
+                     well_known_types._CamelCaseToSnakeCase('foo3Bar'))
+    self.assertRaisesRegex(
+        ValueError,
+        'Fail to parse FieldMask: Path name foo_bar must not contain "_"s.',
+        well_known_types._CamelCaseToSnakeCase, 'foo_bar')
+
+
+class StructTest(unittest.TestCase):
+
+  def testStruct(self):
+    struct = struct_pb2.Struct()
+    self.assertIsInstance(struct, collections_abc.Mapping)
+    self.assertEqual(0, len(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')
+    self.assertIsInstance(struct_list, collections_abc.Sequence)
+    struct_list.extend([6, 'seven', True, False, None])
+    struct_list.add_struct()['subkey2'] = 9
+    struct['key6'] = {'subkey': {}}
+    struct['key7'] = [2, False]
+
+    self.assertEqual(7, len(struct))
+    self.assertTrue(isinstance(struct, well_known_types.Struct))
+    self.assertEqual(5, struct['key1'])
+    self.assertEqual('abc', struct['key2'])
+    self.assertIs(True, struct['key3'])
+    self.assertEqual(11, struct['key4']['subkey'])
+    inner_struct = struct_class()
+    inner_struct['subkey2'] = 9
+    self.assertEqual([6, 'seven', True, False, None, inner_struct],
+                     list(struct['key5'].items()))
+    self.assertEqual({}, dict(struct['key6']['subkey'].fields))
+    self.assertEqual([2, False], list(struct['key7'].items()))
+
+    serialized = struct.SerializeToString()
+    struct2 = struct_pb2.Struct()
+    struct2.ParseFromString(serialized)
+
+    self.assertEqual(struct, struct2)
+    for key, value in struct.items():
+      self.assertIn(key, struct)
+      self.assertIn(key, struct2)
+      self.assertEqual(value, struct2[key])
+
+    self.assertEqual(7, len(struct.keys()))
+    self.assertEqual(7, len(struct.values()))
+    for key in struct.keys():
+      self.assertIn(key, struct)
+      self.assertIn(key, struct2)
+      self.assertEqual(struct[key], struct2[key])
+
+    item = (next(iter(struct.keys())), next(iter(struct.values())))
+    self.assertEqual(item, next(iter(struct.items())))
+
+    self.assertTrue(isinstance(struct2, well_known_types.Struct))
+    self.assertEqual(5, struct2['key1'])
+    self.assertEqual('abc', struct2['key2'])
+    self.assertIs(True, struct2['key3'])
+    self.assertEqual(11, struct2['key4']['subkey'])
+    self.assertEqual([6, 'seven', True, False, None, inner_struct],
+                     list(struct2['key5'].items()))
+
+    struct_list = struct2['key5']
+    self.assertEqual(6, struct_list[0])
+    self.assertEqual('seven', struct_list[1])
+    self.assertEqual(True, struct_list[2])
+    self.assertEqual(False, struct_list[3])
+    self.assertEqual(None, struct_list[4])
+    self.assertEqual(inner_struct, struct_list[5])
+
+    struct_list[1] = 7
+    self.assertEqual(7, struct_list[1])
+
+    struct_list.add_list().extend([1, 'two', True, False, None])
+    self.assertEqual([1, 'two', True, False, None],
+                     list(struct_list[6].items()))
+    struct_list.extend([{'nested_struct': 30}, ['nested_list', 99], {}, []])
+    self.assertEqual(11, len(struct_list.values))
+    self.assertEqual(30, struct_list[7]['nested_struct'])
+    self.assertEqual('nested_list', struct_list[8][0])
+    self.assertEqual(99, struct_list[8][1])
+    self.assertEqual({}, dict(struct_list[9].fields))
+    self.assertEqual([], list(struct_list[10].items()))
+    struct_list[0] = {'replace': 'set'}
+    struct_list[1] = ['replace', 'set']
+    self.assertEqual('set', struct_list[0]['replace'])
+    self.assertEqual(['replace', 'set'], list(struct_list[1].items()))
+
+    text_serialized = str(struct)
+    struct3 = struct_pb2.Struct()
+    text_format.Merge(text_serialized, struct3)
+    self.assertEqual(struct, struct3)
+
+    struct.get_or_create_struct('key3')['replace'] = 12
+    self.assertEqual(12, struct['key3']['replace'])
+
+    # Tests empty list.
+    struct.get_or_create_list('empty_list')
+    empty_list = struct['empty_list']
+    self.assertEqual([], list(empty_list.items()))
+    list2 = struct_pb2.ListValue()
+    list2.add_list()
+    empty_list = list2[0]
+    self.assertEqual([], list(empty_list.items()))
+
+    # Tests empty struct.
+    struct.get_or_create_struct('empty_struct')
+    empty_struct = struct['empty_struct']
+    self.assertEqual({}, dict(empty_struct.fields))
+    list2.add_struct()
+    empty_struct = list2[1]
+    self.assertEqual({}, dict(empty_struct.fields))
+
+    self.assertEqual(9, len(struct))
+    del struct['key3']
+    del struct['key4']
+    self.assertEqual(7, len(struct))
+    self.assertEqual(6, len(struct['key5']))
+    del struct['key5'][1]
+    self.assertEqual(5, len(struct['key5']))
+    self.assertEqual([6, True, False, None, inner_struct],
+                     list(struct['key5'].items()))
+
+  def testStructAssignment(self):
+    # Tests struct assignment from another struct
+    s1 = struct_pb2.Struct()
+    s2 = struct_pb2.Struct()
+    for value in [1, 'a', [1], ['a'], {'a': 'b'}]:
+      s1['x'] = value
+      s2['x'] = s1['x']
+      self.assertEqual(s1['x'], s2['x'])
+
+  def testMergeFrom(self):
+    struct = struct_pb2.Struct()
+    struct_class = struct.__class__
+
+    dictionary = {
+        'key1': 5,
+        'key2': 'abc',
+        'key3': True,
+        'key4': {'subkey': 11.0},
+        'key5': [6, 'seven', True, False, None, {'subkey2': 9}],
+        'key6': [['nested_list', True]],
+        'empty_struct': {},
+        'empty_list': []
+    }
+    struct.update(dictionary)
+    self.assertEqual(5, struct['key1'])
+    self.assertEqual('abc', struct['key2'])
+    self.assertIs(True, struct['key3'])
+    self.assertEqual(11, struct['key4']['subkey'])
+    inner_struct = struct_class()
+    inner_struct['subkey2'] = 9
+    self.assertEqual([6, 'seven', True, False, None, inner_struct],
+                     list(struct['key5'].items()))
+    self.assertEqual(2, len(struct['key6'][0].values))
+    self.assertEqual('nested_list', struct['key6'][0][0])
+    self.assertEqual(True, struct['key6'][0][1])
+    empty_list = struct['empty_list']
+    self.assertEqual([], list(empty_list.items()))
+    empty_struct = struct['empty_struct']
+    self.assertEqual({}, dict(empty_struct.fields))
+
+    # According to documentation: "When parsing from the wire or when merging,
+    # if there are duplicate map keys the last key seen is used".
+    duplicate = {
+        'key4': {'replace': 20},
+        'key5': [[False, 5]]
+    }
+    struct.update(duplicate)
+    self.assertEqual(1, len(struct['key4'].fields))
+    self.assertEqual(20, struct['key4']['replace'])
+    self.assertEqual(1, len(struct['key5'].values))
+    self.assertEqual(False, struct['key5'][0][0])
+    self.assertEqual(5, struct['key5'][0][1])
+
+
+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 testUnpackWithNoSlashInTypeUrl(self):
+    msg = any_test_pb2.TestAny()
+    all_types = unittest_pb2.TestAllTypes()
+    all_descriptor = all_types.DESCRIPTOR
+    msg.value.Pack(all_types)
+    # Reset type_url to part of type_url after '/'
+    msg.value.type_url = msg.value.TypeName()
+    self.assertFalse(msg.value.Is(all_descriptor))
+    unpacked_message = unittest_pb2.TestAllTypes()
+    self.assertFalse(msg.value.Unpack(unpacked_message))
+
+  def testMessageName(self):
+    # Creates and sets message.
+    submessage = any_test_pb2.TestAny()
+    submessage.int_value = 12345
+    msg = any_pb2.Any()
+    msg.Pack(submessage)
+    self.assertEqual(msg.TypeName(), 'google.protobuf.internal.TestAny')
+
+  def testPackWithCustomTypeUrl(self):
+    submessage = any_test_pb2.TestAny()
+    submessage.int_value = 12345
+    msg = any_pb2.Any()
+    # Pack with a custom type URL prefix.
+    msg.Pack(submessage, 'type.myservice.com')
+    self.assertEqual(msg.type_url,
+                     'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
+    # Pack with a custom type URL prefix ending with '/'.
+    msg.Pack(submessage, 'type.myservice.com/')
+    self.assertEqual(msg.type_url,
+                     'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
+    # Pack with an empty type URL prefix.
+    msg.Pack(submessage, '')
+    self.assertEqual(msg.type_url,
+                     '/%s' % submessage.DESCRIPTOR.full_name)
+    # Test unpacking the type.
+    unpacked_message = any_test_pb2.TestAny()
+    self.assertTrue(msg.Unpack(unpacked_message))
+    self.assertEqual(submessage, unpacked_message)
+
+  def testPackDeterministic(self):
+    submessage = any_test_pb2.TestAny()
+    for i in range(10):
+      submessage.map_value[str(i)] = i * 2
+    msg = any_pb2.Any()
+    msg.Pack(submessage, deterministic=True)
+    serialized = msg.SerializeToString(deterministic=True)
+    golden = (b'\n4type.googleapis.com/google.protobuf.internal.TestAny\x12F'
+              b'\x1a\x05\n\x010\x10\x00\x1a\x05\n\x011\x10\x02\x1a\x05\n\x01'
+              b'2\x10\x04\x1a\x05\n\x013\x10\x06\x1a\x05\n\x014\x10\x08\x1a'
+              b'\x05\n\x015\x10\n\x1a\x05\n\x016\x10\x0c\x1a\x05\n\x017\x10'
+              b'\x0e\x1a\x05\n\x018\x10\x10\x1a\x05\n\x019\x10\x12')
+    self.assertEqual(golden, serialized)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/wire_format.py b/python/google/protobuf/internal/wire_format.py
new file mode 100644
index 0000000..883f525
--- /dev/null
+++ b/python/google/protobuf/internal/wire_format.py
@@ -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.
+
+"""Constants and static functions to support protocol buffer wire format."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+from google.protobuf import descriptor
+from google.protobuf import message
+
+
+TAG_TYPE_BITS = 3  # Number of bits used to hold type info in a proto tag.
+TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1  # 0x7
+
+# These numbers identify the wire type of a protocol buffer value.
+# We use the least-significant TAG_TYPE_BITS bits of the varint-encoded
+# tag-and-type to store one of these WIRETYPE_* constants.
+# These values must match WireType enum in google/protobuf/wire_format.h.
+WIRETYPE_VARINT = 0
+WIRETYPE_FIXED64 = 1
+WIRETYPE_LENGTH_DELIMITED = 2
+WIRETYPE_START_GROUP = 3
+WIRETYPE_END_GROUP = 4
+WIRETYPE_FIXED32 = 5
+_WIRETYPE_MAX = 5
+
+
+# Bounds for various integer types.
+INT32_MAX = int((1 << 31) - 1)
+INT32_MIN = int(-(1 << 31))
+UINT32_MAX = (1 << 32) - 1
+
+INT64_MAX = (1 << 63) - 1
+INT64_MIN = -(1 << 63)
+UINT64_MAX = (1 << 64) - 1
+
+# "struct" format strings that will encode/decode the specified formats.
+FORMAT_UINT32_LITTLE_ENDIAN = '<I'
+FORMAT_UINT64_LITTLE_ENDIAN = '<Q'
+FORMAT_FLOAT_LITTLE_ENDIAN = '<f'
+FORMAT_DOUBLE_LITTLE_ENDIAN = '<d'
+
+
+# We'll have to provide alternate implementations of AppendLittleEndian*() on
+# any architectures where these checks fail.
+if struct.calcsize(FORMAT_UINT32_LITTLE_ENDIAN) != 4:
+  raise AssertionError('Format "I" is not a 32-bit number.')
+if struct.calcsize(FORMAT_UINT64_LITTLE_ENDIAN) != 8:
+  raise AssertionError('Format "Q" is not a 64-bit number.')
+
+
+def PackTag(field_number, wire_type):
+  """Returns an unsigned 32-bit integer that encodes the field number and
+  wire type information in standard protocol message wire format.
+
+  Args:
+    field_number: Expected to be an integer in the range [1, 1 << 29)
+    wire_type: One of the WIRETYPE_* constants.
+  """
+  if not 0 <= wire_type <= _WIRETYPE_MAX:
+    raise message.EncodeError('Unknown wire type: %d' % wire_type)
+  return (field_number << TAG_TYPE_BITS) | wire_type
+
+
+def UnpackTag(tag):
+  """The inverse of PackTag().  Given an unsigned 32-bit number,
+  returns a (field_number, wire_type) tuple.
+  """
+  return (tag >> TAG_TYPE_BITS), (tag & TAG_TYPE_MASK)
+
+
+def ZigZagEncode(value):
+  """ZigZag Transform:  Encodes signed integers so that they can be
+  effectively used with varint encoding.  See wire_format.h for
+  more details.
+  """
+  if value >= 0:
+    return value << 1
+  return (value << 1) ^ (~0)
+
+
+def ZigZagDecode(value):
+  """Inverse of ZigZagEncode()."""
+  if not value & 0x1:
+    return value >> 1
+  return (value >> 1) ^ (~0)
+
+
+
+# The *ByteSize() functions below return the number of bytes required to
+# serialize "field number + type" information and then serialize the value.
+
+
+def Int32ByteSize(field_number, int32):
+  return Int64ByteSize(field_number, int32)
+
+
+def Int32ByteSizeNoTag(int32):
+  return _VarUInt64ByteSizeNoTag(0xffffffffffffffff & int32)
+
+
+def Int64ByteSize(field_number, int64):
+  # Have to convert to uint before calling UInt64ByteSize().
+  return UInt64ByteSize(field_number, 0xffffffffffffffff & int64)
+
+
+def UInt32ByteSize(field_number, uint32):
+  return UInt64ByteSize(field_number, uint32)
+
+
+def UInt64ByteSize(field_number, uint64):
+  return TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(uint64)
+
+
+def SInt32ByteSize(field_number, int32):
+  return UInt32ByteSize(field_number, ZigZagEncode(int32))
+
+
+def SInt64ByteSize(field_number, int64):
+  return UInt64ByteSize(field_number, ZigZagEncode(int64))
+
+
+def Fixed32ByteSize(field_number, fixed32):
+  return TagByteSize(field_number) + 4
+
+
+def Fixed64ByteSize(field_number, fixed64):
+  return TagByteSize(field_number) + 8
+
+
+def SFixed32ByteSize(field_number, sfixed32):
+  return TagByteSize(field_number) + 4
+
+
+def SFixed64ByteSize(field_number, sfixed64):
+  return TagByteSize(field_number) + 8
+
+
+def FloatByteSize(field_number, flt):
+  return TagByteSize(field_number) + 4
+
+
+def DoubleByteSize(field_number, double):
+  return TagByteSize(field_number) + 8
+
+
+def BoolByteSize(field_number, b):
+  return TagByteSize(field_number) + 1
+
+
+def EnumByteSize(field_number, enum):
+  return UInt32ByteSize(field_number, enum)
+
+
+def StringByteSize(field_number, string):
+  return BytesByteSize(field_number, string.encode('utf-8'))
+
+
+def BytesByteSize(field_number, b):
+  return (TagByteSize(field_number)
+          + _VarUInt64ByteSizeNoTag(len(b))
+          + len(b))
+
+
+def GroupByteSize(field_number, message):
+  return (2 * TagByteSize(field_number)  # START and END group.
+          + message.ByteSize())
+
+
+def MessageByteSize(field_number, message):
+  return (TagByteSize(field_number)
+          + _VarUInt64ByteSizeNoTag(message.ByteSize())
+          + message.ByteSize())
+
+
+def MessageSetItemByteSize(field_number, msg):
+  # First compute the sizes of the tags.
+  # There are 2 tags for the beginning and ending of the repeated group, that
+  # is field number 1, one with field number 2 (type_id) and one with field
+  # number 3 (message).
+  total_size = (2 * TagByteSize(1) + TagByteSize(2) + TagByteSize(3))
+
+  # Add the number of bytes for type_id.
+  total_size += _VarUInt64ByteSizeNoTag(field_number)
+
+  message_size = msg.ByteSize()
+
+  # The number of bytes for encoding the length of the message.
+  total_size += _VarUInt64ByteSizeNoTag(message_size)
+
+  # The size of the message.
+  total_size += message_size
+  return total_size
+
+
+def TagByteSize(field_number):
+  """Returns the bytes required to serialize a tag with this field number."""
+  # Just pass in type 0, since the type won't affect the tag+type size.
+  return _VarUInt64ByteSizeNoTag(PackTag(field_number, 0))
+
+
+# Private helper function for the *ByteSize() functions above.
+
+def _VarUInt64ByteSizeNoTag(uint64):
+  """Returns the number of bytes required to serialize a single varint
+  using boundary value comparisons. (unrolled loop optimization -WPierce)
+  uint64 must be unsigned.
+  """
+  if uint64 <= 0x7f: return 1
+  if uint64 <= 0x3fff: return 2
+  if uint64 <= 0x1fffff: return 3
+  if uint64 <= 0xfffffff: return 4
+  if uint64 <= 0x7ffffffff: return 5
+  if uint64 <= 0x3ffffffffff: return 6
+  if uint64 <= 0x1ffffffffffff: return 7
+  if uint64 <= 0xffffffffffffff: return 8
+  if uint64 <= 0x7fffffffffffffff: return 9
+  if uint64 > UINT64_MAX:
+    raise message.EncodeError('Value out of range: %d' % uint64)
+  return 10
+
+
+NON_PACKABLE_TYPES = (
+  descriptor.FieldDescriptor.TYPE_STRING,
+  descriptor.FieldDescriptor.TYPE_GROUP,
+  descriptor.FieldDescriptor.TYPE_MESSAGE,
+  descriptor.FieldDescriptor.TYPE_BYTES
+)
+
+
+def IsTypePackable(field_type):
+  """Return true iff packable = true is valid for fields of this type.
+
+  Args:
+    field_type: a FieldDescriptor::Type value.
+
+  Returns:
+    True iff fields of this type are packable.
+  """
+  return field_type not in NON_PACKABLE_TYPES
diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py
new file mode 100644
index 0000000..f7ad0c7
--- /dev/null
+++ b/python/google/protobuf/internal/wire_format_test.py
@@ -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.
+
+"""Test for google.protobuf.internal.wire_format."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import unittest
+
+from google.protobuf import message
+from google.protobuf.internal import wire_format
+
+
+class WireFormatTest(unittest.TestCase):
+
+  def testPackTag(self):
+    field_number = 0xabc
+    tag_type = 2
+    self.assertEqual((field_number << 3) | tag_type,
+                     wire_format.PackTag(field_number, tag_type))
+    PackTag = wire_format.PackTag
+    # Number too high.
+    self.assertRaises(message.EncodeError, PackTag, field_number, 6)
+    # Number too low.
+    self.assertRaises(message.EncodeError, PackTag, field_number, -1)
+
+  def testUnpackTag(self):
+    # Test field numbers that will require various varint sizes.
+    for expected_field_number in (1, 15, 16, 2047, 2048):
+      for expected_wire_type in range(6):  # Highest-numbered wiretype is 5.
+        field_number, wire_type = wire_format.UnpackTag(
+            wire_format.PackTag(expected_field_number, expected_wire_type))
+        self.assertEqual(expected_field_number, field_number)
+        self.assertEqual(expected_wire_type, wire_type)
+
+    self.assertRaises(TypeError, wire_format.UnpackTag, None)
+    self.assertRaises(TypeError, wire_format.UnpackTag, 'abc')
+    self.assertRaises(TypeError, wire_format.UnpackTag, 0.0)
+    self.assertRaises(TypeError, wire_format.UnpackTag, object())
+
+  def testZigZagEncode(self):
+    Z = wire_format.ZigZagEncode
+    self.assertEqual(0, Z(0))
+    self.assertEqual(1, Z(-1))
+    self.assertEqual(2, Z(1))
+    self.assertEqual(3, Z(-2))
+    self.assertEqual(4, Z(2))
+    self.assertEqual(0xfffffffe, Z(0x7fffffff))
+    self.assertEqual(0xffffffff, Z(-0x80000000))
+    self.assertEqual(0xfffffffffffffffe, Z(0x7fffffffffffffff))
+    self.assertEqual(0xffffffffffffffff, Z(-0x8000000000000000))
+
+    self.assertRaises(TypeError, Z, None)
+    self.assertRaises(TypeError, Z, 'abcd')
+    self.assertRaises(TypeError, Z, 0.0)
+    self.assertRaises(TypeError, Z, object())
+
+  def testZigZagDecode(self):
+    Z = wire_format.ZigZagDecode
+    self.assertEqual(0, Z(0))
+    self.assertEqual(-1, Z(1))
+    self.assertEqual(1, Z(2))
+    self.assertEqual(-2, Z(3))
+    self.assertEqual(2, Z(4))
+    self.assertEqual(0x7fffffff, Z(0xfffffffe))
+    self.assertEqual(-0x80000000, Z(0xffffffff))
+    self.assertEqual(0x7fffffffffffffff, Z(0xfffffffffffffffe))
+    self.assertEqual(-0x8000000000000000, Z(0xffffffffffffffff))
+
+    self.assertRaises(TypeError, Z, None)
+    self.assertRaises(TypeError, Z, 'abcd')
+    self.assertRaises(TypeError, Z, 0.0)
+    self.assertRaises(TypeError, Z, object())
+
+  def NumericByteSizeTestHelper(self, byte_size_fn, value, expected_value_size):
+    # Use field numbers that cause various byte sizes for the tag information.
+    for field_number, tag_bytes in ((15, 1), (16, 2), (2047, 2), (2048, 3)):
+      expected_size = expected_value_size + tag_bytes
+      actual_size = byte_size_fn(field_number, value)
+      self.assertEqual(expected_size, actual_size,
+                       'byte_size_fn: %s, field_number: %d, value: %r\n'
+                       'Expected: %d, Actual: %d'% (
+          byte_size_fn, field_number, value, expected_size, actual_size))
+
+  def testByteSizeFunctions(self):
+    # Test all numeric *ByteSize() functions.
+    NUMERIC_ARGS = [
+        # Int32ByteSize().
+        [wire_format.Int32ByteSize, 0, 1],
+        [wire_format.Int32ByteSize, 127, 1],
+        [wire_format.Int32ByteSize, 128, 2],
+        [wire_format.Int32ByteSize, -1, 10],
+        # Int64ByteSize().
+        [wire_format.Int64ByteSize, 0, 1],
+        [wire_format.Int64ByteSize, 127, 1],
+        [wire_format.Int64ByteSize, 128, 2],
+        [wire_format.Int64ByteSize, -1, 10],
+        # UInt32ByteSize().
+        [wire_format.UInt32ByteSize, 0, 1],
+        [wire_format.UInt32ByteSize, 127, 1],
+        [wire_format.UInt32ByteSize, 128, 2],
+        [wire_format.UInt32ByteSize, wire_format.UINT32_MAX, 5],
+        # UInt64ByteSize().
+        [wire_format.UInt64ByteSize, 0, 1],
+        [wire_format.UInt64ByteSize, 127, 1],
+        [wire_format.UInt64ByteSize, 128, 2],
+        [wire_format.UInt64ByteSize, wire_format.UINT64_MAX, 10],
+        # SInt32ByteSize().
+        [wire_format.SInt32ByteSize, 0, 1],
+        [wire_format.SInt32ByteSize, -1, 1],
+        [wire_format.SInt32ByteSize, 1, 1],
+        [wire_format.SInt32ByteSize, -63, 1],
+        [wire_format.SInt32ByteSize, 63, 1],
+        [wire_format.SInt32ByteSize, -64, 1],
+        [wire_format.SInt32ByteSize, 64, 2],
+        # SInt64ByteSize().
+        [wire_format.SInt64ByteSize, 0, 1],
+        [wire_format.SInt64ByteSize, -1, 1],
+        [wire_format.SInt64ByteSize, 1, 1],
+        [wire_format.SInt64ByteSize, -63, 1],
+        [wire_format.SInt64ByteSize, 63, 1],
+        [wire_format.SInt64ByteSize, -64, 1],
+        [wire_format.SInt64ByteSize, 64, 2],
+        # Fixed32ByteSize().
+        [wire_format.Fixed32ByteSize, 0, 4],
+        [wire_format.Fixed32ByteSize, wire_format.UINT32_MAX, 4],
+        # Fixed64ByteSize().
+        [wire_format.Fixed64ByteSize, 0, 8],
+        [wire_format.Fixed64ByteSize, wire_format.UINT64_MAX, 8],
+        # SFixed32ByteSize().
+        [wire_format.SFixed32ByteSize, 0, 4],
+        [wire_format.SFixed32ByteSize, wire_format.INT32_MIN, 4],
+        [wire_format.SFixed32ByteSize, wire_format.INT32_MAX, 4],
+        # SFixed64ByteSize().
+        [wire_format.SFixed64ByteSize, 0, 8],
+        [wire_format.SFixed64ByteSize, wire_format.INT64_MIN, 8],
+        [wire_format.SFixed64ByteSize, wire_format.INT64_MAX, 8],
+        # FloatByteSize().
+        [wire_format.FloatByteSize, 0.0, 4],
+        [wire_format.FloatByteSize, 1000000000.0, 4],
+        [wire_format.FloatByteSize, -1000000000.0, 4],
+        # DoubleByteSize().
+        [wire_format.DoubleByteSize, 0.0, 8],
+        [wire_format.DoubleByteSize, 1000000000.0, 8],
+        [wire_format.DoubleByteSize, -1000000000.0, 8],
+        # BoolByteSize().
+        [wire_format.BoolByteSize, False, 1],
+        [wire_format.BoolByteSize, True, 1],
+        # EnumByteSize().
+        [wire_format.EnumByteSize, 0, 1],
+        [wire_format.EnumByteSize, 127, 1],
+        [wire_format.EnumByteSize, 128, 2],
+        [wire_format.EnumByteSize, wire_format.UINT32_MAX, 5],
+        ]
+    for args in NUMERIC_ARGS:
+      self.NumericByteSizeTestHelper(*args)
+
+    # Test strings and bytes.
+    for byte_size_fn in (wire_format.StringByteSize, wire_format.BytesByteSize):
+      # 1 byte for tag, 1 byte for length, 3 bytes for contents.
+      self.assertEqual(5, byte_size_fn(10, 'abc'))
+      # 2 bytes for tag, 1 byte for length, 3 bytes for contents.
+      self.assertEqual(6, byte_size_fn(16, 'abc'))
+      # 2 bytes for tag, 2 bytes for length, 128 bytes for contents.
+      self.assertEqual(132, byte_size_fn(16, 'a' * 128))
+
+    # Test UTF-8 string byte size calculation.
+    # 1 byte for tag, 1 byte for length, 8 bytes for content.
+    self.assertEqual(10, wire_format.StringByteSize(
+        5, b'\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82'.decode('utf-8')))
+
+    class MockMessage(object):
+      def __init__(self, byte_size):
+        self.byte_size = byte_size
+      def ByteSize(self):
+        return self.byte_size
+
+    message_byte_size = 10
+    mock_message = MockMessage(byte_size=message_byte_size)
+    # Test groups.
+    # (2 * 1) bytes for begin and end tags, plus message_byte_size.
+    self.assertEqual(2 + message_byte_size,
+                     wire_format.GroupByteSize(1, mock_message))
+    # (2 * 2) bytes for begin and end tags, plus message_byte_size.
+    self.assertEqual(4 + message_byte_size,
+                     wire_format.GroupByteSize(16, mock_message))
+
+    # Test messages.
+    # 1 byte for tag, plus 1 byte for length, plus contents.
+    self.assertEqual(2 + mock_message.byte_size,
+                     wire_format.MessageByteSize(1, mock_message))
+    # 2 bytes for tag, plus 1 byte for length, plus contents.
+    self.assertEqual(3 + mock_message.byte_size,
+                     wire_format.MessageByteSize(16, mock_message))
+    # 2 bytes for tag, plus 2 bytes for length, plus contents.
+    mock_message.byte_size = 128
+    self.assertEqual(4 + mock_message.byte_size,
+                     wire_format.MessageByteSize(16, mock_message))
+
+
+    # Test message set item byte size.
+    # 4 bytes for tags, plus 1 byte for length, plus 1 byte for type_id,
+    # plus contents.
+    mock_message.byte_size = 10
+    self.assertEqual(mock_message.byte_size + 6,
+                     wire_format.MessageSetItemByteSize(1, mock_message))
+
+    # 4 bytes for tags, plus 2 bytes for length, plus 1 byte for type_id,
+    # plus contents.
+    mock_message.byte_size = 128
+    self.assertEqual(mock_message.byte_size + 7,
+                     wire_format.MessageSetItemByteSize(1, mock_message))
+
+    # 4 bytes for tags, plus 2 bytes for length, plus 2 byte for type_id,
+    # plus contents.
+    self.assertEqual(mock_message.byte_size + 8,
+                     wire_format.MessageSetItemByteSize(128, mock_message))
+
+    # Too-long varint.
+    self.assertRaises(message.EncodeError,
+                      wire_format.UInt64ByteSize, 1, 1 << 128)
+
+
+if __name__ == '__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..5024ed8
--- /dev/null
+++ b/python/google/protobuf/json_format.py
@@ -0,0 +1,912 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+from collections import OrderedDict
+import json
+import math
+from operator import methodcaller
+import re
+import sys
+
+from google.protobuf.internal import type_checkers
+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'
+
+_UNPAIRED_SURROGATE_PATTERN = re.compile(
+    u'[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]')
+
+_VALID_EXTENSION_NAME = re.compile(r'\[[a-zA-Z0-9\._]*\]$')
+
+
+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,
+    preserving_proto_field_name=False,
+    indent=2,
+    sort_keys=False,
+    use_integers_for_enums=False,
+    descriptor_pool=None,
+    float_precision=None,
+    ensure_ascii=True):
+  """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.
+    preserving_proto_field_name: If True, use the original proto field
+        names as defined in the .proto file. If False, convert the field
+        names to lowerCamelCase.
+    indent: The JSON object will be pretty-printed with this indent level.
+        An indent level of 0 or negative will only insert newlines.
+    sort_keys: If True, then the output will be sorted by field names.
+    use_integers_for_enums: If true, print integers instead of enum names.
+    descriptor_pool: A Descriptor Pool for resolving types. If None use the
+        default.
+    float_precision: If set, use this to specify float field valid digits.
+    ensure_ascii: If True, strings with non-ASCII characters are escaped.
+        If False, Unicode strings are returned unchanged.
+
+  Returns:
+    A string containing the JSON formatted protocol buffer message.
+  """
+  printer = _Printer(
+      including_default_value_fields,
+      preserving_proto_field_name,
+      use_integers_for_enums,
+      descriptor_pool,
+      float_precision=float_precision)
+  return printer.ToJsonString(message, indent, sort_keys, ensure_ascii)
+
+
+def MessageToDict(
+    message,
+    including_default_value_fields=False,
+    preserving_proto_field_name=False,
+    use_integers_for_enums=False,
+    descriptor_pool=None,
+    float_precision=None):
+  """Converts protobuf message to a dictionary.
+
+  When the dictionary is encoded to JSON, it conforms to proto3 JSON spec.
+
+  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.
+    preserving_proto_field_name: If True, use the original proto field
+        names as defined in the .proto file. If False, convert the field
+        names to lowerCamelCase.
+    use_integers_for_enums: If true, print integers instead of enum names.
+    descriptor_pool: A Descriptor Pool for resolving types. If None use the
+        default.
+    float_precision: If set, use this to specify float field valid digits.
+
+  Returns:
+    A dict representation of the protocol buffer message.
+  """
+  printer = _Printer(
+      including_default_value_fields,
+      preserving_proto_field_name,
+      use_integers_for_enums,
+      descriptor_pool,
+      float_precision=float_precision)
+  # pylint: disable=protected-access
+  return printer._MessageToJsonObject(message)
+
+
+def _IsMapEntry(field):
+  return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
+
+
+class _Printer(object):
+  """JSON format printer for protocol message."""
+
+  def __init__(
+      self,
+      including_default_value_fields=False,
+      preserving_proto_field_name=False,
+      use_integers_for_enums=False,
+      descriptor_pool=None,
+      float_precision=None):
+    self.including_default_value_fields = including_default_value_fields
+    self.preserving_proto_field_name = preserving_proto_field_name
+    self.use_integers_for_enums = use_integers_for_enums
+    self.descriptor_pool = descriptor_pool
+    if float_precision:
+      self.float_format = '.{}g'.format(float_precision)
+    else:
+      self.float_format = None
+
+  def ToJsonString(self, message, indent, sort_keys, ensure_ascii):
+    js = self._MessageToJsonObject(message)
+    return json.dumps(
+        js, indent=indent, sort_keys=sort_keys, ensure_ascii=ensure_ascii)
+
+  def _MessageToJsonObject(self, message):
+    """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 self._WrapperMessageToJsonObject(message)
+    if full_name in _WKTJSONMETHODS:
+      return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self)
+    js = {}
+    return self._RegularMessageToJsonObject(message, js)
+
+  def _RegularMessageToJsonObject(self, message, js):
+    """Converts normal message according to Proto3 JSON Specification."""
+    fields = message.ListFields()
+
+    try:
+      for field, value in fields:
+        if self.preserving_proto_field_name:
+          name = field.name
+        else:
+          name = field.json_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 = str(key)
+            js_map[recorded_key] = self._FieldToJsonObject(
+                v_field, value[key])
+          js[name] = js_map
+        elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          # Convert a repeated field.
+          js[name] = [self._FieldToJsonObject(field, k)
+                      for k in value]
+        elif field.is_extension:
+          name = '[%s]' % field.full_name
+          js[name] = self._FieldToJsonObject(field, value)
+        else:
+          js[name] = self._FieldToJsonObject(field, value)
+
+      # Serialize default value if including_default_value_fields is True.
+      if self.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
+          if self.preserving_proto_field_name:
+            name = field.name
+          else:
+            name = field.json_name
+          if name in js:
+            # Skip the field which has been serialized already.
+            continue
+          if _IsMapEntry(field):
+            js[name] = {}
+          elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+            js[name] = []
+          else:
+            js[name] = self._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(self, field, value):
+    """Converts field value according to Proto3 JSON Specification."""
+    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      return self._MessageToJsonObject(value)
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+      if self.use_integers_for_enums:
+        return value
+      if field.enum_type.full_name == 'google.protobuf.NullValue':
+        return None
+      enum_value = field.enum_type.values_by_number.get(value, None)
+      if enum_value is not None:
+        return enum_value.name
+      else:
+        if field.file.syntax == 'proto3':
+          return value
+        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
+      if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT:
+        if self.float_format:
+          return float(format(value, self.float_format))
+        else:
+          return type_checkers.ToShortestFloat(value)
+
+    return value
+
+  def _AnyMessageToJsonObject(self, message):
+    """Converts Any message according to Proto3 JSON Specification."""
+    if not message.ListFields():
+      return {}
+    # Must print @type first, use OrderedDict instead of {}
+    js = OrderedDict()
+    type_url = message.type_url
+    js['@type'] = type_url
+    sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool)
+    sub_message.ParseFromString(message.value)
+    message_descriptor = sub_message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if _IsWrapperMessage(message_descriptor):
+      js['value'] = self._WrapperMessageToJsonObject(sub_message)
+      return js
+    if full_name in _WKTJSONMETHODS:
+      js['value'] = methodcaller(_WKTJSONMETHODS[full_name][0],
+                                 sub_message)(self)
+      return js
+    return self._RegularMessageToJsonObject(sub_message, js)
+
+  def _GenericMessageToJsonObject(self, message):
+    """Converts message 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(self, message):
+    """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 self._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 self._FieldToJsonObject(oneof_descriptor, value)
+
+  def _ListValueMessageToJsonObject(self, message):
+    """Converts ListValue message according to Proto3 JSON Specification."""
+    return [self._ValueMessageToJsonObject(value)
+            for value in message.values]
+
+  def _StructMessageToJsonObject(self, message):
+    """Converts Struct message according to Proto3 JSON Specification."""
+    fields = message.fields
+    ret = {}
+    for key in fields:
+      ret[key] = self._ValueMessageToJsonObject(fields[key])
+    return ret
+
+  def _WrapperMessageToJsonObject(self, message):
+    return self._FieldToJsonObject(
+        message.DESCRIPTOR.fields_by_name['value'], message.value)
+
+
+def _IsWrapperMessage(message_descriptor):
+  return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
+
+
+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 _CreateMessageFromTypeUrl(type_url, descriptor_pool):
+  """Creates a message from a type URL."""
+  db = symbol_database.Default()
+  pool = db.pool if descriptor_pool is None else descriptor_pool
+  type_name = type_url.split('/')[-1]
+  try:
+    message_descriptor = 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 Parse(text,
+          message,
+          ignore_unknown_fields=False,
+          descriptor_pool=None,
+          max_recursion_depth=100):
+  """Parses a JSON representation of a protocol message into a message.
+
+  Args:
+    text: Message JSON representation.
+    message: A protocol buffer message to merge into.
+    ignore_unknown_fields: If True, do not raise errors for unknown fields.
+    descriptor_pool: A Descriptor Pool for resolving types. If None use the
+      default.
+    max_recursion_depth: max recursion depth of JSON message to be
+      deserialized. JSON messages over this depth will fail to be
+      deserialized. Default value is 100.
+
+  Returns:
+    The same message passed as argument.
+
+  Raises::
+    ParseError: On JSON parsing problems.
+  """
+  if not isinstance(text, str):
+    text = text.decode('utf-8')
+  try:
+    js = json.loads(text, object_pairs_hook=_DuplicateChecker)
+  except ValueError as e:
+    raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
+  return ParseDict(js, message, ignore_unknown_fields, descriptor_pool,
+                   max_recursion_depth)
+
+
+def ParseDict(js_dict,
+              message,
+              ignore_unknown_fields=False,
+              descriptor_pool=None,
+              max_recursion_depth=100):
+  """Parses a JSON dictionary representation into a message.
+
+  Args:
+    js_dict: Dict representation of a JSON message.
+    message: A protocol buffer message to merge into.
+    ignore_unknown_fields: If True, do not raise errors for unknown fields.
+    descriptor_pool: A Descriptor Pool for resolving types. If None use the
+      default.
+    max_recursion_depth: max recursion depth of JSON message to be
+      deserialized. JSON messages over this depth will fail to be
+      deserialized. Default value is 100.
+
+  Returns:
+    The same message passed as argument.
+  """
+  parser = _Parser(ignore_unknown_fields, descriptor_pool, max_recursion_depth)
+  parser.ConvertMessage(js_dict, message, '')
+  return message
+
+
+_INT_OR_FLOAT = (int, float)
+
+
+class _Parser(object):
+  """JSON format parser for protocol message."""
+
+  def __init__(self, ignore_unknown_fields, descriptor_pool,
+               max_recursion_depth):
+    self.ignore_unknown_fields = ignore_unknown_fields
+    self.descriptor_pool = descriptor_pool
+    self.max_recursion_depth = max_recursion_depth
+    self.recursion_depth = 0
+
+  def ConvertMessage(self, value, message, path):
+    """Convert a JSON object into a message.
+
+    Args:
+      value: A JSON object.
+      message: A WKT or regular protocol message to record the data.
+      path: parent path to log parse error info.
+
+    Raises:
+      ParseError: In case of convert problems.
+    """
+    self.recursion_depth += 1
+    if self.recursion_depth > self.max_recursion_depth:
+      raise ParseError('Message too deep. Max recursion depth is {0}'.format(
+          self.max_recursion_depth))
+    message_descriptor = message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if not path:
+      path = message_descriptor.name
+    if _IsWrapperMessage(message_descriptor):
+      self._ConvertWrapperMessage(value, message, path)
+    elif full_name in _WKTJSONMETHODS:
+      methodcaller(_WKTJSONMETHODS[full_name][1], value, message, path)(self)
+    else:
+      self._ConvertFieldValuePair(value, message, path)
+    self.recursion_depth -= 1
+
+  def _ConvertFieldValuePair(self, js, message, path):
+    """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.
+      path: parent path to log parse error info.
+
+    Raises:
+      ParseError: In case of problems converting.
+    """
+    names = []
+    message_descriptor = message.DESCRIPTOR
+    fields_by_json_name = dict((f.json_name, f)
+                               for f in message_descriptor.fields)
+    for name in js:
+      try:
+        field = fields_by_json_name.get(name, None)
+        if not field:
+          field = message_descriptor.fields_by_name.get(name, None)
+        if not field and _VALID_EXTENSION_NAME.match(name):
+          if not message_descriptor.is_extendable:
+            raise ParseError(
+                'Message type {0} does not have extensions at {1}'.format(
+                    message_descriptor.full_name, path))
+          identifier = name[1:-1]  # strip [] brackets
+          # pylint: disable=protected-access
+          field = message.Extensions._FindExtensionByName(identifier)
+          # pylint: enable=protected-access
+          if not field:
+            # Try looking for extension by the message type name, dropping the
+            # field name following the final . separator in full_name.
+            identifier = '.'.join(identifier.split('.')[:-1])
+            # pylint: disable=protected-access
+            field = message.Extensions._FindExtensionByName(identifier)
+            # pylint: enable=protected-access
+        if not field:
+          if self.ignore_unknown_fields:
+            continue
+          raise ParseError(
+              ('Message type "{0}" has no field named "{1}" at "{2}".\n'
+               ' Available Fields(except extensions): "{3}"').format(
+                   message_descriptor.full_name, name, path,
+                   [f.json_name for f in message_descriptor.fields]))
+        if name in names:
+          raise ParseError('Message type "{0}" should not have multiple '
+                           '"{1}" fields at "{2}".'.format(
+                               message.DESCRIPTOR.full_name, name, path))
+        names.append(name)
+        value = js[name]
+        # Check no other oneof field is parsed.
+        if field.containing_oneof is not None and value 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 at "{2}".'.format(
+                                 message.DESCRIPTOR.full_name, oneof_name,
+                                 path))
+          names.append(oneof_name)
+
+        if value is None:
+          if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE
+              and field.message_type.full_name == 'google.protobuf.Value'):
+            sub_message = getattr(message, field.name)
+            sub_message.null_value = 0
+          elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM
+                and field.enum_type.full_name == 'google.protobuf.NullValue'):
+            setattr(message, field.name, 0)
+          else:
+            message.ClearField(field.name)
+          continue
+
+        # Parse field value.
+        if _IsMapEntry(field):
+          message.ClearField(field.name)
+          self._ConvertMapFieldValue(value, message, field,
+                                     '{0}.{1}'.format(path, name))
+        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} at {2}'.format(name, value, path))
+          if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+            # Repeated message field.
+            for index, item in enumerate(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 at {0}.{1}[{2}]'.format(
+                                     path, name, index))
+              self.ConvertMessage(item, sub_message,
+                                  '{0}.{1}[{2}]'.format(path, name, index))
+          else:
+            # Repeated scalar field.
+            for index, item in enumerate(value):
+              if item is None:
+                raise ParseError('null is not allowed to be used as an element'
+                                 ' in a repeated field at {0}.{1}[{2}]'.format(
+                                     path, name, index))
+              getattr(message, field.name).append(
+                  _ConvertScalarFieldValue(
+                      item, field, '{0}.{1}[{2}]'.format(path, name, index)))
+        elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+          if field.is_extension:
+            sub_message = message.Extensions[field]
+          else:
+            sub_message = getattr(message, field.name)
+          sub_message.SetInParent()
+          self.ConvertMessage(value, sub_message, '{0}.{1}'.format(path, name))
+        else:
+          if field.is_extension:
+            message.Extensions[field] = _ConvertScalarFieldValue(
+                value, field, '{0}.{1}'.format(path, name))
+          else:
+            setattr(
+                message, field.name,
+                _ConvertScalarFieldValue(value, field,
+                                         '{0}.{1}'.format(path, name)))
+      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 _ConvertAnyMessage(self, value, message, path):
+    """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 at {0}'.format(path))
+
+    try:
+      sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool)
+    except TypeError as e:
+      raise ParseError('{0} at {1}'.format(e, path))
+    message_descriptor = sub_message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if _IsWrapperMessage(message_descriptor):
+      self._ConvertWrapperMessage(value['value'], sub_message,
+                                  '{0}.value'.format(path))
+    elif full_name in _WKTJSONMETHODS:
+      methodcaller(_WKTJSONMETHODS[full_name][1], value['value'], sub_message,
+                   '{0}.value'.format(path))(
+                       self)
+    else:
+      del value['@type']
+      self._ConvertFieldValuePair(value, sub_message, path)
+      value['@type'] = type_url
+    # Sets Any message
+    message.value = sub_message.SerializeToString()
+    message.type_url = type_url
+
+  def _ConvertGenericMessage(self, value, message, path):
+    """Convert a JSON representation into message with FromJsonString."""
+    # Duration, Timestamp, FieldMask have a FromJsonString method to do the
+    # conversion. Users can also call the method directly.
+    try:
+      message.FromJsonString(value)
+    except ValueError as e:
+      raise ParseError('{0} at {1}'.format(e, path))
+
+  def _ConvertValueMessage(self, value, message, path):
+    """Convert a JSON representation into Value message."""
+    if isinstance(value, dict):
+      self._ConvertStructMessage(value, message.struct_value, path)
+    elif isinstance(value, list):
+      self._ConvertListValueMessage(value, message.list_value, path)
+    elif value is None:
+      message.null_value = 0
+    elif isinstance(value, bool):
+      message.bool_value = value
+    elif isinstance(value, str):
+      message.string_value = value
+    elif isinstance(value, _INT_OR_FLOAT):
+      message.number_value = value
+    else:
+      raise ParseError('Value {0} has unexpected type {1} at {2}'.format(
+          value, type(value), path))
+
+  def _ConvertListValueMessage(self, value, message, path):
+    """Convert a JSON representation into ListValue message."""
+    if not isinstance(value, list):
+      raise ParseError('ListValue must be in [] which is {0} at {1}'.format(
+          value, path))
+    message.ClearField('values')
+    for index, item in enumerate(value):
+      self._ConvertValueMessage(item, message.values.add(),
+                                '{0}[{1}]'.format(path, index))
+
+  def _ConvertStructMessage(self, value, message, path):
+    """Convert a JSON representation into Struct message."""
+    if not isinstance(value, dict):
+      raise ParseError('Struct must be in a dict which is {0} at {1}'.format(
+          value, path))
+    # Clear will mark the struct as modified so it will be created even if
+    # there are no values.
+    message.Clear()
+    for key in value:
+      self._ConvertValueMessage(value[key], message.fields[key],
+                                '{0}.{1}'.format(path, key))
+    return
+
+  def _ConvertWrapperMessage(self, value, message, path):
+    """Convert a JSON representation into Wrapper message."""
+    field = message.DESCRIPTOR.fields_by_name['value']
+    setattr(
+        message, 'value',
+        _ConvertScalarFieldValue(value, field, path='{0}.value'.format(path)))
+
+  def _ConvertMapFieldValue(self, value, message, field, path):
+    """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.
+      path: parent path to log parse error info.
+
+    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} at {2}'.format(
+              field.name, value, path))
+    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,
+                                           '{0}.key'.format(path), True)
+      if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        self.ConvertMessage(value[key],
+                            getattr(message, field.name)[key_value],
+                            '{0}[{1}]'.format(path, key_value))
+      else:
+        getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
+            value[key], value_field, path='{0}[{1}]'.format(path, key_value))
+
+
+def _ConvertScalarFieldValue(value, field, path, 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.
+    path: parent path to log parse error info.
+    require_str: If True, the field value must be a str.
+
+  Returns:
+    The converted scalar field value
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  try:
+    if field.cpp_type in _INT_TYPES:
+      return _ConvertInteger(value)
+    elif field.cpp_type in _FLOAT_TYPES:
+      return _ConvertFloat(value, field)
+    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:
+        if isinstance(value, str):
+          encoded = value.encode('utf-8')
+        else:
+          encoded = value
+        # Add extra padding '='
+        padded_value = encoded + b'=' * (4 - len(encoded) % 4)
+        return base64.urlsafe_b64decode(padded_value)
+      else:
+        # Checking for unpaired surrogates appears to be unreliable,
+        # depending on the specific Python version, so we check manually.
+        if _UNPAIRED_SURROGATE_PATTERN.search(value):
+          raise ParseError('Unpaired surrogate')
+        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:
+        try:
+          number = int(value)
+          enum_value = field.enum_type.values_by_number.get(number, None)
+        except ValueError:
+          raise ParseError('Invalid enum value {0} for enum type {1}'.format(
+              value, field.enum_type.full_name))
+        if enum_value is None:
+          if field.file.syntax == 'proto3':
+            # Proto3 accepts unknown enums.
+            return number
+          raise ParseError('Invalid enum value {0} for enum type {1}'.format(
+              value, field.enum_type.full_name))
+      return enum_value.number
+  except ParseError as e:
+    raise ParseError('{0} at {1}'.format(e, path))
+
+
+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) and not value.is_integer():
+    raise ParseError('Couldn\'t parse integer: {0}'.format(value))
+
+  if isinstance(value, str) and value.find(' ') != -1:
+    raise ParseError('Couldn\'t parse integer: "{0}"'.format(value))
+
+  if isinstance(value, bool):
+    raise ParseError('Bool value {0} is not acceptable for '
+                     'integer field'.format(value))
+
+  return int(value)
+
+
+def _ConvertFloat(value, field):
+  """Convert an floating point number."""
+  if isinstance(value, float):
+    if math.isnan(value):
+      raise ParseError('Couldn\'t parse NaN, use quoted "NaN" instead')
+    if math.isinf(value):
+      if value > 0:
+        raise ParseError('Couldn\'t parse Infinity or value too large, '
+                         'use quoted "Infinity" instead')
+      else:
+        raise ParseError('Couldn\'t parse -Infinity or value too small, '
+                         'use quoted "-Infinity" instead')
+    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT:
+      # pylint: disable=protected-access
+      if value > type_checkers._FLOAT_MAX:
+        raise ParseError('Float value too large')
+      # pylint: disable=protected-access
+      if value < type_checkers._FLOAT_MIN:
+        raise ParseError('Float value too small')
+  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/map_proto2_unittest_pb2.py b/python/google/protobuf/map_proto2_unittest_pb2.py
new file mode 100644
index 0000000..1863ff3
--- /dev/null
+++ b/python/google/protobuf/map_proto2_unittest_pb2.py
@@ -0,0 +1,1345 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/map_proto2_unittest.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import unittest_import_pb2 as google_dot_protobuf_dot_unittest__import__pb2
+try:
+  google_dot_protobuf_dot_unittest__import__public__pb2 = google_dot_protobuf_dot_unittest__import__pb2.google_dot_protobuf_dot_unittest__import__public__pb2
+except AttributeError:
+  google_dot_protobuf_dot_unittest__import__public__pb2 = google_dot_protobuf_dot_unittest__import__pb2.google.protobuf.unittest_import_public_pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/map_proto2_unittest.proto',
+  package='protobuf_unittest',
+  syntax='proto2',
+  serialized_options=b'\370\001\001',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n)google/protobuf/map_proto2_unittest.proto\x12\x11protobuf_unittest\x1a%google/protobuf/unittest_import.proto\"\xdb\x02\n\x0bTestEnumMap\x12J\n\x0fknown_map_field\x18\x65 \x03(\x0b\x32\x31.protobuf_unittest.TestEnumMap.KnownMapFieldEntry\x12N\n\x11unknown_map_field\x18\x66 \x03(\x0b\x32\x33.protobuf_unittest.TestEnumMap.UnknownMapFieldEntry\x1aV\n\x12KnownMapFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12/\n\x05value\x18\x02 \x01(\x0e\x32 .protobuf_unittest.Proto2MapEnum:\x02\x38\x01\x1aX\n\x14UnknownMapFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12/\n\x05value\x18\x02 \x01(\x0e\x32 .protobuf_unittest.Proto2MapEnum:\x02\x38\x01\"\x88\x03\n\x14TestEnumMapPlusExtra\x12S\n\x0fknown_map_field\x18\x65 \x03(\x0b\x32:.protobuf_unittest.TestEnumMapPlusExtra.KnownMapFieldEntry\x12W\n\x11unknown_map_field\x18\x66 \x03(\x0b\x32<.protobuf_unittest.TestEnumMapPlusExtra.UnknownMapFieldEntry\x1a_\n\x12KnownMapFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x38\n\x05value\x18\x02 \x01(\x0e\x32).protobuf_unittest.Proto2MapEnumPlusExtra:\x02\x38\x01\x1a\x61\n\x14UnknownMapFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x38\n\x05value\x18\x02 \x01(\x0e\x32).protobuf_unittest.Proto2MapEnumPlusExtra:\x02\x38\x01\"\xc7\x01\n\x11TestImportEnumMap\x12P\n\x0fimport_enum_amp\x18\x01 \x03(\x0b\x32\x37.protobuf_unittest.TestImportEnumMap.ImportEnumAmpEntry\x1a`\n\x12ImportEnumAmpEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\x39\n\x05value\x18\x02 \x01(\x0e\x32*.protobuf_unittest_import.ImportEnumForMap:\x02\x38\x01\"m\n\rTestIntIntMap\x12\x32\n\x01m\x18\x01 \x03(\x0b\x32\'.protobuf_unittest.TestIntIntMap.MEntry\x1a(\n\x06MEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"\xb8\r\n\x08TestMaps\x12\x38\n\x07m_int32\x18\x01 \x03(\x0b\x32\'.protobuf_unittest.TestMaps.MInt32Entry\x12\x38\n\x07m_int64\x18\x02 \x03(\x0b\x32\'.protobuf_unittest.TestMaps.MInt64Entry\x12:\n\x08m_uint32\x18\x03 \x03(\x0b\x32(.protobuf_unittest.TestMaps.MUint32Entry\x12:\n\x08m_uint64\x18\x04 \x03(\x0b\x32(.protobuf_unittest.TestMaps.MUint64Entry\x12:\n\x08m_sint32\x18\x05 \x03(\x0b\x32(.protobuf_unittest.TestMaps.MSint32Entry\x12:\n\x08m_sint64\x18\x06 \x03(\x0b\x32(.protobuf_unittest.TestMaps.MSint64Entry\x12<\n\tm_fixed32\x18\x07 \x03(\x0b\x32).protobuf_unittest.TestMaps.MFixed32Entry\x12<\n\tm_fixed64\x18\x08 \x03(\x0b\x32).protobuf_unittest.TestMaps.MFixed64Entry\x12>\n\nm_sfixed32\x18\t \x03(\x0b\x32*.protobuf_unittest.TestMaps.MSfixed32Entry\x12>\n\nm_sfixed64\x18\n \x03(\x0b\x32*.protobuf_unittest.TestMaps.MSfixed64Entry\x12\x36\n\x06m_bool\x18\x0b \x03(\x0b\x32&.protobuf_unittest.TestMaps.MBoolEntry\x12:\n\x08m_string\x18\x0c \x03(\x0b\x32(.protobuf_unittest.TestMaps.MStringEntry\x1aO\n\x0bMInt32Entry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aO\n\x0bMInt64Entry\x12\x0b\n\x03key\x18\x01 \x01(\x03\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aP\n\x0cMUint32Entry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aP\n\x0cMUint64Entry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aP\n\x0cMSint32Entry\x12\x0b\n\x03key\x18\x01 \x01(\x11\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aP\n\x0cMSint64Entry\x12\x0b\n\x03key\x18\x01 \x01(\x12\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aQ\n\rMFixed32Entry\x12\x0b\n\x03key\x18\x01 \x01(\x07\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aQ\n\rMFixed64Entry\x12\x0b\n\x03key\x18\x01 \x01(\x06\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aR\n\x0eMSfixed32Entry\x12\x0b\n\x03key\x18\x01 \x01(\x0f\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aR\n\x0eMSfixed64Entry\x12\x0b\n\x03key\x18\x01 \x01(\x10\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aN\n\nMBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\x1aP\n\x0cMStringEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestIntIntMap:\x02\x38\x01\"<\n\x12TestSubmessageMaps\x12&\n\x01m\x18\x01 \x01(\x0b\x32\x1b.protobuf_unittest.TestMaps*Z\n\rProto2MapEnum\x12\x17\n\x13PROTO2_MAP_ENUM_FOO\x10\x00\x12\x17\n\x13PROTO2_MAP_ENUM_BAR\x10\x01\x12\x17\n\x13PROTO2_MAP_ENUM_BAZ\x10\x02*\x86\x01\n\x16Proto2MapEnumPlusExtra\x12\x19\n\x15\x45_PROTO2_MAP_ENUM_FOO\x10\x00\x12\x19\n\x15\x45_PROTO2_MAP_ENUM_BAR\x10\x01\x12\x19\n\x15\x45_PROTO2_MAP_ENUM_BAZ\x10\x02\x12\x1b\n\x17\x45_PROTO2_MAP_ENUM_EXTRA\x10\x03\x42\x03\xf8\x01\x01'
+  ,
+  dependencies=[google_dot_protobuf_dot_unittest__import__pb2.DESCRIPTOR,])
+
+_PROTO2MAPENUM = _descriptor.EnumDescriptor(
+  name='Proto2MapEnum',
+  full_name='protobuf_unittest.Proto2MapEnum',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='PROTO2_MAP_ENUM_FOO', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PROTO2_MAP_ENUM_BAR', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PROTO2_MAP_ENUM_BAZ', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=2946,
+  serialized_end=3036,
+)
+_sym_db.RegisterEnumDescriptor(_PROTO2MAPENUM)
+
+Proto2MapEnum = enum_type_wrapper.EnumTypeWrapper(_PROTO2MAPENUM)
+_PROTO2MAPENUMPLUSEXTRA = _descriptor.EnumDescriptor(
+  name='Proto2MapEnumPlusExtra',
+  full_name='protobuf_unittest.Proto2MapEnumPlusExtra',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='E_PROTO2_MAP_ENUM_FOO', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='E_PROTO2_MAP_ENUM_BAR', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='E_PROTO2_MAP_ENUM_BAZ', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='E_PROTO2_MAP_ENUM_EXTRA', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=3039,
+  serialized_end=3173,
+)
+_sym_db.RegisterEnumDescriptor(_PROTO2MAPENUMPLUSEXTRA)
+
+Proto2MapEnumPlusExtra = enum_type_wrapper.EnumTypeWrapper(_PROTO2MAPENUMPLUSEXTRA)
+PROTO2_MAP_ENUM_FOO = 0
+PROTO2_MAP_ENUM_BAR = 1
+PROTO2_MAP_ENUM_BAZ = 2
+E_PROTO2_MAP_ENUM_FOO = 0
+E_PROTO2_MAP_ENUM_BAR = 1
+E_PROTO2_MAP_ENUM_BAZ = 2
+E_PROTO2_MAP_ENUM_EXTRA = 3
+
+
+
+_TESTENUMMAP_KNOWNMAPFIELDENTRY = _descriptor.Descriptor(
+  name='KnownMapFieldEntry',
+  full_name='protobuf_unittest.TestEnumMap.KnownMapFieldEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestEnumMap.KnownMapFieldEntry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestEnumMap.KnownMapFieldEntry.value', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=275,
+  serialized_end=361,
+)
+
+_TESTENUMMAP_UNKNOWNMAPFIELDENTRY = _descriptor.Descriptor(
+  name='UnknownMapFieldEntry',
+  full_name='protobuf_unittest.TestEnumMap.UnknownMapFieldEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestEnumMap.UnknownMapFieldEntry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestEnumMap.UnknownMapFieldEntry.value', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=363,
+  serialized_end=451,
+)
+
+_TESTENUMMAP = _descriptor.Descriptor(
+  name='TestEnumMap',
+  full_name='protobuf_unittest.TestEnumMap',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='known_map_field', full_name='protobuf_unittest.TestEnumMap.known_map_field', index=0,
+      number=101, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='unknown_map_field', full_name='protobuf_unittest.TestEnumMap.unknown_map_field', index=1,
+      number=102, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_TESTENUMMAP_KNOWNMAPFIELDENTRY, _TESTENUMMAP_UNKNOWNMAPFIELDENTRY, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=104,
+  serialized_end=451,
+)
+
+
+_TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY = _descriptor.Descriptor(
+  name='KnownMapFieldEntry',
+  full_name='protobuf_unittest.TestEnumMapPlusExtra.KnownMapFieldEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestEnumMapPlusExtra.KnownMapFieldEntry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestEnumMapPlusExtra.KnownMapFieldEntry.value', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=652,
+  serialized_end=747,
+)
+
+_TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY = _descriptor.Descriptor(
+  name='UnknownMapFieldEntry',
+  full_name='protobuf_unittest.TestEnumMapPlusExtra.UnknownMapFieldEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestEnumMapPlusExtra.UnknownMapFieldEntry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestEnumMapPlusExtra.UnknownMapFieldEntry.value', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=749,
+  serialized_end=846,
+)
+
+_TESTENUMMAPPLUSEXTRA = _descriptor.Descriptor(
+  name='TestEnumMapPlusExtra',
+  full_name='protobuf_unittest.TestEnumMapPlusExtra',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='known_map_field', full_name='protobuf_unittest.TestEnumMapPlusExtra.known_map_field', index=0,
+      number=101, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='unknown_map_field', full_name='protobuf_unittest.TestEnumMapPlusExtra.unknown_map_field', index=1,
+      number=102, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY, _TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=454,
+  serialized_end=846,
+)
+
+
+_TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY = _descriptor.Descriptor(
+  name='ImportEnumAmpEntry',
+  full_name='protobuf_unittest.TestImportEnumMap.ImportEnumAmpEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestImportEnumMap.ImportEnumAmpEntry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestImportEnumMap.ImportEnumAmpEntry.value', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=952,
+  serialized_end=1048,
+)
+
+_TESTIMPORTENUMMAP = _descriptor.Descriptor(
+  name='TestImportEnumMap',
+  full_name='protobuf_unittest.TestImportEnumMap',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='import_enum_amp', full_name='protobuf_unittest.TestImportEnumMap.import_enum_amp', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=849,
+  serialized_end=1048,
+)
+
+
+_TESTINTINTMAP_MENTRY = _descriptor.Descriptor(
+  name='MEntry',
+  full_name='protobuf_unittest.TestIntIntMap.MEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestIntIntMap.MEntry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestIntIntMap.MEntry.value', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1119,
+  serialized_end=1159,
+)
+
+_TESTINTINTMAP = _descriptor.Descriptor(
+  name='TestIntIntMap',
+  full_name='protobuf_unittest.TestIntIntMap',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='m', full_name='protobuf_unittest.TestIntIntMap.m', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_TESTINTINTMAP_MENTRY, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1050,
+  serialized_end=1159,
+)
+
+
+_TESTMAPS_MINT32ENTRY = _descriptor.Descriptor(
+  name='MInt32Entry',
+  full_name='protobuf_unittest.TestMaps.MInt32Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MInt32Entry.key', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MInt32Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1898,
+  serialized_end=1977,
+)
+
+_TESTMAPS_MINT64ENTRY = _descriptor.Descriptor(
+  name='MInt64Entry',
+  full_name='protobuf_unittest.TestMaps.MInt64Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MInt64Entry.key', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MInt64Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1979,
+  serialized_end=2058,
+)
+
+_TESTMAPS_MUINT32ENTRY = _descriptor.Descriptor(
+  name='MUint32Entry',
+  full_name='protobuf_unittest.TestMaps.MUint32Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MUint32Entry.key', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MUint32Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2060,
+  serialized_end=2140,
+)
+
+_TESTMAPS_MUINT64ENTRY = _descriptor.Descriptor(
+  name='MUint64Entry',
+  full_name='protobuf_unittest.TestMaps.MUint64Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MUint64Entry.key', index=0,
+      number=1, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MUint64Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2142,
+  serialized_end=2222,
+)
+
+_TESTMAPS_MSINT32ENTRY = _descriptor.Descriptor(
+  name='MSint32Entry',
+  full_name='protobuf_unittest.TestMaps.MSint32Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MSint32Entry.key', index=0,
+      number=1, type=17, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MSint32Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2224,
+  serialized_end=2304,
+)
+
+_TESTMAPS_MSINT64ENTRY = _descriptor.Descriptor(
+  name='MSint64Entry',
+  full_name='protobuf_unittest.TestMaps.MSint64Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MSint64Entry.key', index=0,
+      number=1, type=18, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MSint64Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2306,
+  serialized_end=2386,
+)
+
+_TESTMAPS_MFIXED32ENTRY = _descriptor.Descriptor(
+  name='MFixed32Entry',
+  full_name='protobuf_unittest.TestMaps.MFixed32Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MFixed32Entry.key', index=0,
+      number=1, type=7, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MFixed32Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2388,
+  serialized_end=2469,
+)
+
+_TESTMAPS_MFIXED64ENTRY = _descriptor.Descriptor(
+  name='MFixed64Entry',
+  full_name='protobuf_unittest.TestMaps.MFixed64Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MFixed64Entry.key', index=0,
+      number=1, type=6, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MFixed64Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2471,
+  serialized_end=2552,
+)
+
+_TESTMAPS_MSFIXED32ENTRY = _descriptor.Descriptor(
+  name='MSfixed32Entry',
+  full_name='protobuf_unittest.TestMaps.MSfixed32Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MSfixed32Entry.key', index=0,
+      number=1, type=15, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MSfixed32Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2554,
+  serialized_end=2636,
+)
+
+_TESTMAPS_MSFIXED64ENTRY = _descriptor.Descriptor(
+  name='MSfixed64Entry',
+  full_name='protobuf_unittest.TestMaps.MSfixed64Entry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MSfixed64Entry.key', index=0,
+      number=1, type=16, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MSfixed64Entry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2638,
+  serialized_end=2720,
+)
+
+_TESTMAPS_MBOOLENTRY = _descriptor.Descriptor(
+  name='MBoolEntry',
+  full_name='protobuf_unittest.TestMaps.MBoolEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MBoolEntry.key', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MBoolEntry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2722,
+  serialized_end=2800,
+)
+
+_TESTMAPS_MSTRINGENTRY = _descriptor.Descriptor(
+  name='MStringEntry',
+  full_name='protobuf_unittest.TestMaps.MStringEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='protobuf_unittest.TestMaps.MStringEntry.key', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='protobuf_unittest.TestMaps.MStringEntry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2802,
+  serialized_end=2882,
+)
+
+_TESTMAPS = _descriptor.Descriptor(
+  name='TestMaps',
+  full_name='protobuf_unittest.TestMaps',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='m_int32', full_name='protobuf_unittest.TestMaps.m_int32', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_int64', full_name='protobuf_unittest.TestMaps.m_int64', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_uint32', full_name='protobuf_unittest.TestMaps.m_uint32', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_uint64', full_name='protobuf_unittest.TestMaps.m_uint64', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_sint32', full_name='protobuf_unittest.TestMaps.m_sint32', index=4,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_sint64', full_name='protobuf_unittest.TestMaps.m_sint64', index=5,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_fixed32', full_name='protobuf_unittest.TestMaps.m_fixed32', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_fixed64', full_name='protobuf_unittest.TestMaps.m_fixed64', index=7,
+      number=8, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_sfixed32', full_name='protobuf_unittest.TestMaps.m_sfixed32', index=8,
+      number=9, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_sfixed64', full_name='protobuf_unittest.TestMaps.m_sfixed64', index=9,
+      number=10, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_bool', full_name='protobuf_unittest.TestMaps.m_bool', index=10,
+      number=11, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='m_string', full_name='protobuf_unittest.TestMaps.m_string', index=11,
+      number=12, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_TESTMAPS_MINT32ENTRY, _TESTMAPS_MINT64ENTRY, _TESTMAPS_MUINT32ENTRY, _TESTMAPS_MUINT64ENTRY, _TESTMAPS_MSINT32ENTRY, _TESTMAPS_MSINT64ENTRY, _TESTMAPS_MFIXED32ENTRY, _TESTMAPS_MFIXED64ENTRY, _TESTMAPS_MSFIXED32ENTRY, _TESTMAPS_MSFIXED64ENTRY, _TESTMAPS_MBOOLENTRY, _TESTMAPS_MSTRINGENTRY, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1162,
+  serialized_end=2882,
+)
+
+
+_TESTSUBMESSAGEMAPS = _descriptor.Descriptor(
+  name='TestSubmessageMaps',
+  full_name='protobuf_unittest.TestSubmessageMaps',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='m', full_name='protobuf_unittest.TestSubmessageMaps.m', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto2',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2884,
+  serialized_end=2944,
+)
+
+_TESTENUMMAP_KNOWNMAPFIELDENTRY.fields_by_name['value'].enum_type = _PROTO2MAPENUM
+_TESTENUMMAP_KNOWNMAPFIELDENTRY.containing_type = _TESTENUMMAP
+_TESTENUMMAP_UNKNOWNMAPFIELDENTRY.fields_by_name['value'].enum_type = _PROTO2MAPENUM
+_TESTENUMMAP_UNKNOWNMAPFIELDENTRY.containing_type = _TESTENUMMAP
+_TESTENUMMAP.fields_by_name['known_map_field'].message_type = _TESTENUMMAP_KNOWNMAPFIELDENTRY
+_TESTENUMMAP.fields_by_name['unknown_map_field'].message_type = _TESTENUMMAP_UNKNOWNMAPFIELDENTRY
+_TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY.fields_by_name['value'].enum_type = _PROTO2MAPENUMPLUSEXTRA
+_TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY.containing_type = _TESTENUMMAPPLUSEXTRA
+_TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY.fields_by_name['value'].enum_type = _PROTO2MAPENUMPLUSEXTRA
+_TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY.containing_type = _TESTENUMMAPPLUSEXTRA
+_TESTENUMMAPPLUSEXTRA.fields_by_name['known_map_field'].message_type = _TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY
+_TESTENUMMAPPLUSEXTRA.fields_by_name['unknown_map_field'].message_type = _TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY
+_TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY.fields_by_name['value'].enum_type = google_dot_protobuf_dot_unittest__import__pb2._IMPORTENUMFORMAP
+_TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY.containing_type = _TESTIMPORTENUMMAP
+_TESTIMPORTENUMMAP.fields_by_name['import_enum_amp'].message_type = _TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY
+_TESTINTINTMAP_MENTRY.containing_type = _TESTINTINTMAP
+_TESTINTINTMAP.fields_by_name['m'].message_type = _TESTINTINTMAP_MENTRY
+_TESTMAPS_MINT32ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MINT32ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MINT64ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MINT64ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MUINT32ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MUINT32ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MUINT64ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MUINT64ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MSINT32ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MSINT32ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MSINT64ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MSINT64ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MFIXED32ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MFIXED32ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MFIXED64ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MFIXED64ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MSFIXED32ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MSFIXED32ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MSFIXED64ENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MSFIXED64ENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MBOOLENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MBOOLENTRY.containing_type = _TESTMAPS
+_TESTMAPS_MSTRINGENTRY.fields_by_name['value'].message_type = _TESTINTINTMAP
+_TESTMAPS_MSTRINGENTRY.containing_type = _TESTMAPS
+_TESTMAPS.fields_by_name['m_int32'].message_type = _TESTMAPS_MINT32ENTRY
+_TESTMAPS.fields_by_name['m_int64'].message_type = _TESTMAPS_MINT64ENTRY
+_TESTMAPS.fields_by_name['m_uint32'].message_type = _TESTMAPS_MUINT32ENTRY
+_TESTMAPS.fields_by_name['m_uint64'].message_type = _TESTMAPS_MUINT64ENTRY
+_TESTMAPS.fields_by_name['m_sint32'].message_type = _TESTMAPS_MSINT32ENTRY
+_TESTMAPS.fields_by_name['m_sint64'].message_type = _TESTMAPS_MSINT64ENTRY
+_TESTMAPS.fields_by_name['m_fixed32'].message_type = _TESTMAPS_MFIXED32ENTRY
+_TESTMAPS.fields_by_name['m_fixed64'].message_type = _TESTMAPS_MFIXED64ENTRY
+_TESTMAPS.fields_by_name['m_sfixed32'].message_type = _TESTMAPS_MSFIXED32ENTRY
+_TESTMAPS.fields_by_name['m_sfixed64'].message_type = _TESTMAPS_MSFIXED64ENTRY
+_TESTMAPS.fields_by_name['m_bool'].message_type = _TESTMAPS_MBOOLENTRY
+_TESTMAPS.fields_by_name['m_string'].message_type = _TESTMAPS_MSTRINGENTRY
+_TESTSUBMESSAGEMAPS.fields_by_name['m'].message_type = _TESTMAPS
+DESCRIPTOR.message_types_by_name['TestEnumMap'] = _TESTENUMMAP
+DESCRIPTOR.message_types_by_name['TestEnumMapPlusExtra'] = _TESTENUMMAPPLUSEXTRA
+DESCRIPTOR.message_types_by_name['TestImportEnumMap'] = _TESTIMPORTENUMMAP
+DESCRIPTOR.message_types_by_name['TestIntIntMap'] = _TESTINTINTMAP
+DESCRIPTOR.message_types_by_name['TestMaps'] = _TESTMAPS
+DESCRIPTOR.message_types_by_name['TestSubmessageMaps'] = _TESTSUBMESSAGEMAPS
+DESCRIPTOR.enum_types_by_name['Proto2MapEnum'] = _PROTO2MAPENUM
+DESCRIPTOR.enum_types_by_name['Proto2MapEnumPlusExtra'] = _PROTO2MAPENUMPLUSEXTRA
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TestEnumMap = _reflection.GeneratedProtocolMessageType('TestEnumMap', (_message.Message,), {
+
+  'KnownMapFieldEntry' : _reflection.GeneratedProtocolMessageType('KnownMapFieldEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTENUMMAP_KNOWNMAPFIELDENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestEnumMap.KnownMapFieldEntry)
+    })
+  ,
+
+  'UnknownMapFieldEntry' : _reflection.GeneratedProtocolMessageType('UnknownMapFieldEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTENUMMAP_UNKNOWNMAPFIELDENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestEnumMap.UnknownMapFieldEntry)
+    })
+  ,
+  'DESCRIPTOR' : _TESTENUMMAP,
+  '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestEnumMap)
+  })
+_sym_db.RegisterMessage(TestEnumMap)
+_sym_db.RegisterMessage(TestEnumMap.KnownMapFieldEntry)
+_sym_db.RegisterMessage(TestEnumMap.UnknownMapFieldEntry)
+
+TestEnumMapPlusExtra = _reflection.GeneratedProtocolMessageType('TestEnumMapPlusExtra', (_message.Message,), {
+
+  'KnownMapFieldEntry' : _reflection.GeneratedProtocolMessageType('KnownMapFieldEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestEnumMapPlusExtra.KnownMapFieldEntry)
+    })
+  ,
+
+  'UnknownMapFieldEntry' : _reflection.GeneratedProtocolMessageType('UnknownMapFieldEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestEnumMapPlusExtra.UnknownMapFieldEntry)
+    })
+  ,
+  'DESCRIPTOR' : _TESTENUMMAPPLUSEXTRA,
+  '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestEnumMapPlusExtra)
+  })
+_sym_db.RegisterMessage(TestEnumMapPlusExtra)
+_sym_db.RegisterMessage(TestEnumMapPlusExtra.KnownMapFieldEntry)
+_sym_db.RegisterMessage(TestEnumMapPlusExtra.UnknownMapFieldEntry)
+
+TestImportEnumMap = _reflection.GeneratedProtocolMessageType('TestImportEnumMap', (_message.Message,), {
+
+  'ImportEnumAmpEntry' : _reflection.GeneratedProtocolMessageType('ImportEnumAmpEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestImportEnumMap.ImportEnumAmpEntry)
+    })
+  ,
+  'DESCRIPTOR' : _TESTIMPORTENUMMAP,
+  '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestImportEnumMap)
+  })
+_sym_db.RegisterMessage(TestImportEnumMap)
+_sym_db.RegisterMessage(TestImportEnumMap.ImportEnumAmpEntry)
+
+TestIntIntMap = _reflection.GeneratedProtocolMessageType('TestIntIntMap', (_message.Message,), {
+
+  'MEntry' : _reflection.GeneratedProtocolMessageType('MEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTINTINTMAP_MENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestIntIntMap.MEntry)
+    })
+  ,
+  'DESCRIPTOR' : _TESTINTINTMAP,
+  '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestIntIntMap)
+  })
+_sym_db.RegisterMessage(TestIntIntMap)
+_sym_db.RegisterMessage(TestIntIntMap.MEntry)
+
+TestMaps = _reflection.GeneratedProtocolMessageType('TestMaps', (_message.Message,), {
+
+  'MInt32Entry' : _reflection.GeneratedProtocolMessageType('MInt32Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MINT32ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MInt32Entry)
+    })
+  ,
+
+  'MInt64Entry' : _reflection.GeneratedProtocolMessageType('MInt64Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MINT64ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MInt64Entry)
+    })
+  ,
+
+  'MUint32Entry' : _reflection.GeneratedProtocolMessageType('MUint32Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MUINT32ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MUint32Entry)
+    })
+  ,
+
+  'MUint64Entry' : _reflection.GeneratedProtocolMessageType('MUint64Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MUINT64ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MUint64Entry)
+    })
+  ,
+
+  'MSint32Entry' : _reflection.GeneratedProtocolMessageType('MSint32Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MSINT32ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MSint32Entry)
+    })
+  ,
+
+  'MSint64Entry' : _reflection.GeneratedProtocolMessageType('MSint64Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MSINT64ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MSint64Entry)
+    })
+  ,
+
+  'MFixed32Entry' : _reflection.GeneratedProtocolMessageType('MFixed32Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MFIXED32ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MFixed32Entry)
+    })
+  ,
+
+  'MFixed64Entry' : _reflection.GeneratedProtocolMessageType('MFixed64Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MFIXED64ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MFixed64Entry)
+    })
+  ,
+
+  'MSfixed32Entry' : _reflection.GeneratedProtocolMessageType('MSfixed32Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MSFIXED32ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MSfixed32Entry)
+    })
+  ,
+
+  'MSfixed64Entry' : _reflection.GeneratedProtocolMessageType('MSfixed64Entry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MSFIXED64ENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MSfixed64Entry)
+    })
+  ,
+
+  'MBoolEntry' : _reflection.GeneratedProtocolMessageType('MBoolEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MBOOLENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MBoolEntry)
+    })
+  ,
+
+  'MStringEntry' : _reflection.GeneratedProtocolMessageType('MStringEntry', (_message.Message,), {
+    'DESCRIPTOR' : _TESTMAPS_MSTRINGENTRY,
+    '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+    # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps.MStringEntry)
+    })
+  ,
+  'DESCRIPTOR' : _TESTMAPS,
+  '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestMaps)
+  })
+_sym_db.RegisterMessage(TestMaps)
+_sym_db.RegisterMessage(TestMaps.MInt32Entry)
+_sym_db.RegisterMessage(TestMaps.MInt64Entry)
+_sym_db.RegisterMessage(TestMaps.MUint32Entry)
+_sym_db.RegisterMessage(TestMaps.MUint64Entry)
+_sym_db.RegisterMessage(TestMaps.MSint32Entry)
+_sym_db.RegisterMessage(TestMaps.MSint64Entry)
+_sym_db.RegisterMessage(TestMaps.MFixed32Entry)
+_sym_db.RegisterMessage(TestMaps.MFixed64Entry)
+_sym_db.RegisterMessage(TestMaps.MSfixed32Entry)
+_sym_db.RegisterMessage(TestMaps.MSfixed64Entry)
+_sym_db.RegisterMessage(TestMaps.MBoolEntry)
+_sym_db.RegisterMessage(TestMaps.MStringEntry)
+
+TestSubmessageMaps = _reflection.GeneratedProtocolMessageType('TestSubmessageMaps', (_message.Message,), {
+  'DESCRIPTOR' : _TESTSUBMESSAGEMAPS,
+  '__module__' : 'google.protobuf.map_proto2_unittest_pb2'
+  # @@protoc_insertion_point(class_scope:protobuf_unittest.TestSubmessageMaps)
+  })
+_sym_db.RegisterMessage(TestSubmessageMaps)
+
+
+DESCRIPTOR._options = None
+_TESTENUMMAP_KNOWNMAPFIELDENTRY._options = None
+_TESTENUMMAP_UNKNOWNMAPFIELDENTRY._options = None
+_TESTENUMMAPPLUSEXTRA_KNOWNMAPFIELDENTRY._options = None
+_TESTENUMMAPPLUSEXTRA_UNKNOWNMAPFIELDENTRY._options = None
+_TESTIMPORTENUMMAP_IMPORTENUMAMPENTRY._options = None
+_TESTINTINTMAP_MENTRY._options = None
+_TESTMAPS_MINT32ENTRY._options = None
+_TESTMAPS_MINT64ENTRY._options = None
+_TESTMAPS_MUINT32ENTRY._options = None
+_TESTMAPS_MUINT64ENTRY._options = None
+_TESTMAPS_MSINT32ENTRY._options = None
+_TESTMAPS_MSINT64ENTRY._options = None
+_TESTMAPS_MFIXED32ENTRY._options = None
+_TESTMAPS_MFIXED64ENTRY._options = None
+_TESTMAPS_MSFIXED32ENTRY._options = None
+_TESTMAPS_MSFIXED64ENTRY._options = None
+_TESTMAPS_MBOOLENTRY._options = None
+_TESTMAPS_MSTRINGENTRY._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py
new file mode 100644
index 0000000..76c6802
--- /dev/null
+++ b/python/google/protobuf/message.py
@@ -0,0 +1,424 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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(robinson): We should just make these methods all "pure-virtual" and move
+# all implementation out, into reflection.py for now.
+
+
+"""Contains an abstract base class for protocol messages."""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+class Error(Exception):
+  """Base error type for this module."""
+  pass
+
+
+class DecodeError(Error):
+  """Exception raised when deserializing messages."""
+  pass
+
+
+class EncodeError(Error):
+  """Exception raised when serializing messages."""
+  pass
+
+
+class Message(object):
+
+  """Abstract base class for protocol messages.
+
+  Protocol message classes are almost always generated by the protocol
+  compiler.  These generated types subclass Message and implement the methods
+  shown below.
+  """
+
+  # TODO(robinson): Link to an HTML document here.
+
+  # TODO(robinson): Document that instances of this class will also
+  # have an Extensions attribute with __getitem__ and __setitem__.
+  # Again, not sure how to best convey this.
+
+  # TODO(robinson): Document that the class must also have a static
+  #   RegisterExtension(extension_field) method.
+  #   Not sure how to best express at this point.
+
+  # TODO(robinson): Document these fields and methods.
+
+  __slots__ = []
+
+  #: The :class:`google.protobuf.descriptor.Descriptor` for this message type.
+  DESCRIPTOR = None
+
+  def __deepcopy__(self, memo=None):
+    clone = type(self)()
+    clone.MergeFrom(self)
+    return clone
+
+  def __eq__(self, other_msg):
+    """Recursively compares two messages by value and structure."""
+    raise NotImplementedError
+
+  def __ne__(self, other_msg):
+    # Can't just say self != other_msg, since that would infinitely recurse. :)
+    return not self == other_msg
+
+  def __hash__(self):
+    raise TypeError('unhashable object')
+
+  def __str__(self):
+    """Outputs a human-readable representation of the message."""
+    raise NotImplementedError
+
+  def __unicode__(self):
+    """Outputs a human-readable representation of the message."""
+    raise NotImplementedError
+
+  def MergeFrom(self, other_msg):
+    """Merges the contents of the specified message into current message.
+
+    This method merges the contents of the specified message into the current
+    message. Singular fields that are set in the specified message overwrite
+    the corresponding fields in the current message. Repeated fields are
+    appended. Singular sub-messages and groups are recursively merged.
+
+    Args:
+      other_msg (Message): A message to merge into the current message.
+    """
+    raise NotImplementedError
+
+  def CopyFrom(self, other_msg):
+    """Copies the content of the specified message into the current message.
+
+    The method clears the current message and then merges the specified
+    message using MergeFrom.
+
+    Args:
+      other_msg (Message): A message to copy into the current one.
+    """
+    if self is other_msg:
+      return
+    self.Clear()
+    self.MergeFrom(other_msg)
+
+  def Clear(self):
+    """Clears all data that was set in the message."""
+    raise NotImplementedError
+
+  def SetInParent(self):
+    """Mark this as present in the parent.
+
+    This normally happens automatically when you assign a field of a
+    sub-message, but sometimes you want to make the sub-message
+    present while keeping it empty.  If you find yourself using this,
+    you may want to reconsider your design.
+    """
+    raise NotImplementedError
+
+  def IsInitialized(self):
+    """Checks if the message is initialized.
+
+    Returns:
+      bool: The method returns True if the message is initialized (i.e. all of
+      its required fields are set).
+    """
+    raise NotImplementedError
+
+  # TODO(robinson): MergeFromString() should probably return None and be
+  # implemented in terms of a helper that returns the # of bytes read.  Our
+  # deserialization routines would use the helper when recursively
+  # deserializing, but the end user would almost always just want the no-return
+  # MergeFromString().
+
+  def MergeFromString(self, serialized):
+    """Merges serialized protocol buffer data into this message.
+
+    When we find a field in `serialized` that is already present
+    in this message:
+
+    -   If it's a "repeated" field, we append to the end of our list.
+    -   Else, if it's a scalar, we overwrite our field.
+    -   Else, (it's a nonrepeated composite), we recursively merge
+        into the existing composite.
+
+    Args:
+      serialized (bytes): Any object that allows us to call
+        ``memoryview(serialized)`` to access a string of bytes using the
+        buffer interface.
+
+    Returns:
+      int: The number of bytes read from `serialized`.
+      For non-group messages, this will always be `len(serialized)`,
+      but for messages which are actually groups, this will
+      generally be less than `len(serialized)`, since we must
+      stop when we reach an ``END_GROUP`` tag.  Note that if
+      we *do* stop because of an ``END_GROUP`` tag, the number
+      of bytes returned does not include the bytes
+      for the ``END_GROUP`` tag information.
+
+    Raises:
+      DecodeError: if the input cannot be parsed.
+    """
+    # TODO(robinson): Document handling of unknown fields.
+    # TODO(robinson): When we switch to a helper, this will return None.
+    raise NotImplementedError
+
+  def ParseFromString(self, serialized):
+    """Parse serialized protocol buffer data into this message.
+
+    Like :func:`MergeFromString()`, except we clear the object first.
+
+    Raises:
+      message.DecodeError if the input cannot be parsed.
+    """
+    self.Clear()
+    return self.MergeFromString(serialized)
+
+  def SerializeToString(self, **kwargs):
+    """Serializes the protocol message to a binary string.
+
+    Keyword Args:
+      deterministic (bool): If true, requests deterministic serialization
+        of the protobuf, with predictable ordering of map keys.
+
+    Returns:
+      A binary string representation of the message if all of the required
+      fields in the message are set (i.e. the message is initialized).
+
+    Raises:
+      EncodeError: if the message isn't initialized (see :func:`IsInitialized`).
+    """
+    raise NotImplementedError
+
+  def SerializePartialToString(self, **kwargs):
+    """Serializes the protocol message to a binary string.
+
+    This method is similar to SerializeToString but doesn't check if the
+    message is initialized.
+
+    Keyword Args:
+      deterministic (bool): If true, requests deterministic serialization
+        of the protobuf, with predictable ordering of map keys.
+
+    Returns:
+      bytes: A serialized representation of the partial message.
+    """
+    raise NotImplementedError
+
+  # TODO(robinson): Decide whether we like these better
+  # than auto-generated has_foo() and clear_foo() methods
+  # on the instances themselves.  This way is less consistent
+  # with C++, but it makes reflection-type access easier and
+  # reduces the number of magically autogenerated things.
+  #
+  # TODO(robinson): Be sure to document (and test) exactly
+  # which field names are accepted here.  Are we case-sensitive?
+  # What do we do with fields that share names with Python keywords
+  # like 'lambda' and 'yield'?
+  #
+  # nnorwitz says:
+  # """
+  # Typically (in python), an underscore is appended to names that are
+  # keywords. So they would become lambda_ or yield_.
+  # """
+  def ListFields(self):
+    """Returns a list of (FieldDescriptor, value) tuples for present fields.
+
+    A message field is non-empty if HasField() would return true. A singular
+    primitive field is non-empty if HasField() would return true in proto2 or it
+    is non zero in proto3. A repeated field is non-empty if it contains at least
+    one element. The fields are ordered by field number.
+
+    Returns:
+      list[tuple(FieldDescriptor, value)]: field descriptors and values
+      for all fields in the message which are not empty. The values vary by
+      field type.
+    """
+    raise NotImplementedError
+
+  def HasField(self, field_name):
+    """Checks if a certain field is set for the message.
+
+    For a oneof group, checks if any field inside is set. Note that if the
+    field_name is not defined in the message descriptor, :exc:`ValueError` will
+    be raised.
+
+    Args:
+      field_name (str): The name of the field to check for presence.
+
+    Returns:
+      bool: Whether a value has been set for the named field.
+
+    Raises:
+      ValueError: if the `field_name` is not a member of this message.
+    """
+    raise NotImplementedError
+
+  def ClearField(self, field_name):
+    """Clears the contents of a given field.
+
+    Inside a oneof group, clears the field set. If the name neither refers to a
+    defined field or oneof group, :exc:`ValueError` is raised.
+
+    Args:
+      field_name (str): The name of the field to check for presence.
+
+    Raises:
+      ValueError: if the `field_name` is not a member of this message.
+    """
+    raise NotImplementedError
+
+  def WhichOneof(self, oneof_group):
+    """Returns the name of the field that is set inside a oneof group.
+
+    If no field is set, returns None.
+
+    Args:
+      oneof_group (str): the name of the oneof group to check.
+
+    Returns:
+      str or None: The name of the group that is set, or None.
+
+    Raises:
+      ValueError: no group with the given name exists
+    """
+    raise NotImplementedError
+
+  def HasExtension(self, extension_handle):
+    """Checks if a certain extension is present for this message.
+
+    Extensions are retrieved using the :attr:`Extensions` mapping (if present).
+
+    Args:
+      extension_handle: The handle for the extension to check.
+
+    Returns:
+      bool: Whether the extension is present for this message.
+
+    Raises:
+      KeyError: if the extension is repeated. Similar to repeated fields,
+        there is no separate notion of presence: a "not present" repeated
+        extension is an empty list.
+    """
+    raise NotImplementedError
+
+  def ClearExtension(self, extension_handle):
+    """Clears the contents of a given extension.
+
+    Args:
+      extension_handle: The handle for the extension to clear.
+    """
+    raise NotImplementedError
+
+  def UnknownFields(self):
+    """Returns the UnknownFieldSet.
+
+    Returns:
+      UnknownFieldSet: The unknown fields stored in this message.
+    """
+    raise NotImplementedError
+
+  def DiscardUnknownFields(self):
+    """Clears all fields in the :class:`UnknownFieldSet`.
+
+    This operation is recursive for nested message.
+    """
+    raise NotImplementedError
+
+  def ByteSize(self):
+    """Returns the serialized size of this message.
+
+    Recursively calls ByteSize() on all contained messages.
+
+    Returns:
+      int: The number of bytes required to serialize this message.
+    """
+    raise NotImplementedError
+
+  @classmethod
+  def FromString(cls, s):
+    raise NotImplementedError
+
+  @staticmethod
+  def RegisterExtension(extension_handle):
+    raise NotImplementedError
+
+  def _SetListener(self, message_listener):
+    """Internal method used by the protocol message implementation.
+    Clients should not call this directly.
+
+    Sets a listener that this message will call on certain state transitions.
+
+    The purpose of this method is to register back-edges from children to
+    parents at runtime, for the purpose of setting "has" bits and
+    byte-size-dirty bits in the parent and ancestor objects whenever a child or
+    descendant object is modified.
+
+    If the client wants to disconnect this Message from the object tree, she
+    explicitly sets callback to None.
+
+    If message_listener is None, unregisters any existing listener.  Otherwise,
+    message_listener must implement the MessageListener interface in
+    internal/message_listener.py, and we discard any listener registered
+    via a previous _SetListener() call.
+    """
+    raise NotImplementedError
+
+  def __getstate__(self):
+    """Support the pickle protocol."""
+    return dict(serialized=self.SerializePartialToString())
+
+  def __setstate__(self, state):
+    """Support the pickle protocol."""
+    self.__init__()
+    serialized = state['serialized']
+    # On Python 3, using encoding='latin1' is required for unpickling
+    # protos pickled by Python 2.
+    if not isinstance(serialized, bytes):
+      serialized = serialized.encode('latin1')
+    self.ParseFromString(serialized)
+
+  def __reduce__(self):
+    message_descriptor = self.DESCRIPTOR
+    if message_descriptor.containing_type is None:
+      return type(self), (), self.__getstate__()
+    # the message type must be nested.
+    # Python does not pickle nested classes; use the symbol_database on the
+    # receiving end.
+    container = message_descriptor
+    return (_InternalConstructMessage, (container.full_name,),
+            self.__getstate__())
+
+
+def _InternalConstructMessage(full_name):
+  """Constructs a nested message."""
+  from google.protobuf import symbol_database  # pylint:disable=g-import-not-at-top
+
+  return symbol_database.Default().GetSymbol(full_name)()
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
new file mode 100644
index 0000000..8d65204
--- /dev/null
+++ b/python/google/protobuf/message_factory.py
@@ -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.
+
+"""Provides a factory class for generating dynamic messages.
+
+The easiest way to use this class is if you have access to the FileDescriptor
+protos containing the messages you want to create you can just do the following:
+
+message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
+my_proto_instance = message_classes['some.proto.package.MessageName']()
+"""
+
+__author__ = 'matthewtoia@google.com (Matt Toia)'
+
+from google.protobuf.internal import api_implementation
+from google.protobuf import descriptor_pool
+from google.protobuf import message
+
+if api_implementation.Type() == 'python':
+  from google.protobuf.internal import python_message as message_impl
+else:
+  from google.protobuf.pyext import cpp_message as message_impl  # pylint: disable=g-import-not-at-top
+
+
+# The type of all Message classes.
+_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType
+
+
+class MessageFactory(object):
+  """Factory for creating Proto2 messages from descriptors in a pool."""
+
+  def __init__(self, pool=None):
+    """Initializes a new factory."""
+    self.pool = pool or descriptor_pool.DescriptorPool()
+
+    # local cache of all classes built from protobuf descriptors
+    self._classes = {}
+
+  def GetPrototype(self, descriptor):
+    """Obtains a proto2 message class based on the passed in descriptor.
+
+    Passing a descriptor with a fully qualified name matching a previous
+    invocation will cause the same class to be returned.
+
+    Args:
+      descriptor: The descriptor to build from.
+
+    Returns:
+      A class describing the passed in descriptor.
+    """
+    if descriptor not in self._classes:
+      result_class = self.CreatePrototype(descriptor)
+      # The assignment to _classes is redundant for the base implementation, but
+      # might avoid confusion in cases where CreatePrototype gets overridden and
+      # does not call the base implementation.
+      self._classes[descriptor] = result_class
+      return result_class
+    return self._classes[descriptor]
+
+  def CreatePrototype(self, descriptor):
+    """Builds a proto2 message class based on the passed in descriptor.
+
+    Don't call this function directly, it always creates a new class. Call
+    GetPrototype() instead. This method is meant to be overridden in subblasses
+    to perform additional operations on the newly constructed class.
+
+    Args:
+      descriptor: The descriptor to build from.
+
+    Returns:
+      A class describing the passed in descriptor.
+    """
+    descriptor_name = descriptor.name
+    result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE(
+        descriptor_name,
+        (message.Message,),
+        {
+            'DESCRIPTOR': descriptor,
+            # If module not set, it wrongly points to message_factory module.
+            '__module__': None,
+        })
+    result_class._FACTORY = self  # pylint: disable=protected-access
+    # Assign in _classes before doing recursive calls to avoid infinite
+    # recursion.
+    self._classes[descriptor] = result_class
+    for field in descriptor.fields:
+      if field.message_type:
+        self.GetPrototype(field.message_type)
+    for extension in result_class.DESCRIPTOR.extensions:
+      if extension.containing_type not in self._classes:
+        self.GetPrototype(extension.containing_type)
+      extended_class = self._classes[extension.containing_type]
+      extended_class.RegisterExtension(extension)
+      if extension.message_type:
+        self.GetPrototype(extension.message_type)
+    return result_class
+
+  def GetMessages(self, files):
+    """Gets all the messages from a specified file.
+
+    This will find and resolve dependencies, failing if the descriptor
+    pool cannot satisfy them.
+
+    Args:
+      files: The file names to extract messages from.
+
+    Returns:
+      A dictionary mapping proto names to the message classes. This will include
+      any dependent messages as well as any messages defined in the same file as
+      a specified message.
+    """
+    result = {}
+    for file_name in files:
+      file_desc = self.pool.FindFileByName(file_name)
+      for desc in file_desc.message_types_by_name.values():
+        result[desc.full_name] = self.GetPrototype(desc)
+
+      # While the extension FieldDescriptors are created by the descriptor pool,
+      # the python classes created in the factory need them to be registered
+      # explicitly, which is done below.
+      #
+      # The call to RegisterExtension will specifically check if the
+      # extension was already registered on the object and either
+      # ignore the registration if the original was the same, or raise
+      # an error if they were different.
+
+      for extension in file_desc.extensions_by_name.values():
+        if extension.containing_type not in self._classes:
+          self.GetPrototype(extension.containing_type)
+        extended_class = self._classes[extension.containing_type]
+        extended_class.RegisterExtension(extension)
+        if extension.message_type:
+          self.GetPrototype(extension.message_type)
+    return result
+
+
+_FACTORY = MessageFactory()
+
+
+def GetMessages(file_protos):
+  """Builds a dictionary of all the messages available in a set of files.
+
+  Args:
+    file_protos: Iterable of FileDescriptorProto to build messages out of.
+
+  Returns:
+    A dictionary mapping proto names to the message classes. This will include
+    any dependent messages as well as any messages defined in the same file as
+    a specified message.
+  """
+  # The cpp implementation of the protocol buffer library requires to add the
+  # message in topological order of the dependency graph.
+  file_by_name = {file_proto.name: file_proto for file_proto in file_protos}
+  def _AddFile(file_proto):
+    for dependency in file_proto.dependency:
+      if dependency in file_by_name:
+        # Remove from elements to be visited, in order to cut cycles.
+        _AddFile(file_by_name.pop(dependency))
+    _FACTORY.pool.Add(file_proto)
+  while file_by_name:
+    _AddFile(file_by_name.popitem()[1])
+  return _FACTORY.GetMessages([file_proto.name for file_proto in file_protos])
diff --git a/python/google/protobuf/proto_api.h b/python/google/protobuf/proto_api.h
new file mode 100644
index 0000000..9969a91
--- /dev/null
+++ b/python/google/protobuf/proto_api.h
@@ -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 can be included by other C++ libraries, typically extension modules
+// which want to interact with the Python Messages coming from the "cpp"
+// implementation of protocol buffers.
+//
+// Usage:
+// Declare a (probably static) variable to hold the API:
+//    const PyProto_API* py_proto_api;
+// In some initialization function, write:
+//    py_proto_api = static_cast<const PyProto_API*>(PyCapsule_Import(
+//        PyProtoAPICapsuleName(), 0));
+//    if (!py_proto_api) { ...handle ImportError... }
+// Then use the methods of the returned class:
+//    py_proto_api->GetMessagePointer(...);
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__
+#define GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Note on the implementation:
+// This API is designed after
+// https://docs.python.org/3/extending/extending.html#providing-a-c-api-for-an-extension-module
+// The class below contains no mutable state, and all methods are "const";
+// we use a C++ class instead of a C struct with functions pointers just because
+// the code looks more readable.
+struct PyProto_API {
+  // The API object is created at initialization time and never freed.
+  // This destructor is never called.
+  virtual ~PyProto_API() {}
+
+  // Operations on Messages.
+
+  // If the passed object is a Python Message, returns its internal pointer.
+  // Otherwise, returns NULL with an exception set.
+  virtual const Message* GetMessagePointer(PyObject* msg) const = 0;
+
+  // If the passed object is a Python Message, returns a mutable pointer.
+  // Otherwise, returns NULL with an exception set.
+  // This function will succeed only if there are no other Python objects
+  // pointing to the message, like submessages or repeated containers.
+  // With the current implementation, only empty messages are in this case.
+  virtual Message* GetMutableMessagePointer(PyObject* msg) const = 0;
+
+  // If the passed object is a Python Message Descriptor, returns its internal
+  // pointer.
+  // Otherwise, returns NULL with an exception set.
+  virtual const Descriptor* MessageDescriptor_AsDescriptor(
+      PyObject* desc) const = 0;
+
+  // If the passed object is a Python Enum Descriptor, returns its internal
+  // pointer.
+  // Otherwise, returns NULL with an exception set.
+  virtual const EnumDescriptor* EnumDescriptor_AsDescriptor(
+      PyObject* enum_desc) const = 0;
+
+  // Expose the underlying DescriptorPool and MessageFactory to enable C++ code
+  // to create Python-compatible message.
+  virtual const DescriptorPool* GetDefaultDescriptorPool() const = 0;
+  virtual MessageFactory* GetDefaultMessageFactory() const = 0;
+
+  // Allocate a new protocol buffer as a python object for the provided
+  // descriptor. This function works even if no Python module has been imported
+  // for the corresponding protocol buffer class.
+  // The factory is usually null; when provided, it is the MessageFactory which
+  // owns the Python class, and will be used to find and create Extensions for
+  // this message.
+  // When null is returned, a python error has already been set.
+  virtual PyObject* NewMessage(const Descriptor* descriptor,
+                               PyObject* py_message_factory) const = 0;
+
+  // Allocate a new protocol buffer where the underlying object is owned by C++.
+  // The factory must currently be null.  This function works even if no Python
+  // module has been imported for the corresponding protocol buffer class.
+  // When null is returned, a python error has already been set.
+  //
+  // Since this call returns a python object owned by C++, some operations
+  // are risky, and it must be used carefully. In particular:
+  // * Avoid modifying the returned object from the C++ side while there are
+  // existing python references to it or it's subobjects.
+  // * Avoid using python references to this object or any subobjects after the
+  // C++ object has been freed.
+  // * Calling this with the same C++ pointer will result in multiple distinct
+  // python objects referencing the same C++ object.
+  virtual PyObject* NewMessageOwnedExternally(
+      Message* msg, PyObject* py_message_factory) const = 0;
+
+  // Returns a new reference for the given DescriptorPool.
+  // The returned object does not manage the C++ DescriptorPool: it is the
+  // responsibility of the caller to keep it alive.
+  // As long as the returned Python DescriptorPool object is kept alive,
+  // functions that process C++ descriptors or messages created from this pool
+  // can work and return their Python counterparts.
+  virtual PyObject* DescriptorPool_FromPool(
+      const google::protobuf::DescriptorPool* pool) const = 0;
+};
+
+inline const char* PyProtoAPICapsuleName() {
+  static const char kCapsuleName[] =
+      "google.protobuf.pyext._message.proto_API";
+  return kCapsuleName;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__
diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py
new file mode 100644
index 0000000..a4667ce
--- /dev/null
+++ b/python/google/protobuf/proto_builder.py
@@ -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.
+
+"""Dynamic Protobuf class creator."""
+
+from collections import OrderedDict
+import hashlib
+import os
+
+from google.protobuf import descriptor_pb2
+from google.protobuf import descriptor
+from google.protobuf import message_factory
+
+
+def _GetMessageFromFactory(factory, full_name):
+  """Get a proto class from the MessageFactory by name.
+
+  Args:
+    factory: a MessageFactory instance.
+    full_name: str, the fully qualified name of the proto type.
+  Returns:
+    A class, for the type identified by full_name.
+  Raises:
+    KeyError, if the proto is not found in the factory's descriptor pool.
+  """
+  proto_descriptor = factory.pool.FindMessageTypeByName(full_name)
+  proto_cls = factory.GetPrototype(proto_descriptor)
+  return proto_cls
+
+
+def MakeSimpleProtoClass(fields, full_name=None, pool=None):
+  """Create a Protobuf class whose fields are basic types.
+
+  Note: this doesn't validate field names!
+
+  Args:
+    fields: dict of {name: field_type} mappings for each field in the proto. If
+        this is an OrderedDict the order will be maintained, otherwise the
+        fields will be sorted by name.
+    full_name: optional str, the fully-qualified name of the proto type.
+    pool: optional DescriptorPool instance.
+  Returns:
+    a class, the new protobuf class with a FileDescriptor.
+  """
+  factory = message_factory.MessageFactory(pool=pool)
+
+  if full_name is not None:
+    try:
+      proto_cls = _GetMessageFromFactory(factory, full_name)
+      return proto_cls
+    except KeyError:
+      # The factory's DescriptorPool doesn't know about this class yet.
+      pass
+
+  # Get a list of (name, field_type) tuples from the fields dict. If fields was
+  # an OrderedDict we keep the order, but otherwise we sort the field to ensure
+  # consistent ordering.
+  field_items = fields.items()
+  if not isinstance(fields, OrderedDict):
+    field_items = sorted(field_items)
+
+  # Use a consistent file name that is unlikely to conflict with any imported
+  # proto files.
+  fields_hash = hashlib.sha1()
+  for f_name, f_type in field_items:
+    fields_hash.update(f_name.encode('utf-8'))
+    fields_hash.update(str(f_type).encode('utf-8'))
+  proto_file_name = fields_hash.hexdigest() + '.proto'
+
+  # If the proto is anonymous, use the same hash to name it.
+  if full_name is None:
+    full_name = ('net.proto2.python.public.proto_builder.AnonymousProto_' +
+                 fields_hash.hexdigest())
+    try:
+      proto_cls = _GetMessageFromFactory(factory, full_name)
+      return proto_cls
+    except KeyError:
+      # The factory's DescriptorPool doesn't know about this class yet.
+      pass
+
+  # This is the first time we see this proto: add a new descriptor to the pool.
+  factory.pool.Add(
+      _MakeFileDescriptorProto(proto_file_name, full_name, field_items))
+  return _GetMessageFromFactory(factory, full_name)
+
+
+def _MakeFileDescriptorProto(proto_file_name, full_name, field_items):
+  """Populate FileDescriptorProto for MessageFactory's DescriptorPool."""
+  package, name = full_name.rsplit('.', 1)
+  file_proto = descriptor_pb2.FileDescriptorProto()
+  file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name)
+  file_proto.package = package
+  desc_proto = file_proto.message_type.add()
+  desc_proto.name = name
+  for f_number, (f_name, f_type) in enumerate(field_items, 1):
+    field_proto = desc_proto.field.add()
+    field_proto.name = f_name
+    # # If the number falls in the reserved range, reassign it to the correct
+    # # number after the range.
+    if f_number >= descriptor.FieldDescriptor.FIRST_RESERVED_FIELD_NUMBER:
+      f_number += (
+          descriptor.FieldDescriptor.LAST_RESERVED_FIELD_NUMBER -
+          descriptor.FieldDescriptor.FIRST_RESERVED_FIELD_NUMBER + 1)
+    field_proto.number = f_number
+    field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
+    field_proto.type = f_type
+  return file_proto
diff --git a/python/google/protobuf/pyext/README b/python/google/protobuf/pyext/README
new file mode 100644
index 0000000..6d61cb4
--- /dev/null
+++ b/python/google/protobuf/pyext/README
@@ -0,0 +1,6 @@
+This is the 'v2' C++ implementation for python proto2.
+
+It is active when:
+
+PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
diff --git a/python/google/protobuf/pyext/__init__.py b/python/google/protobuf/pyext/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/google/protobuf/pyext/__init__.py
diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py
new file mode 100644
index 0000000..ca29029
--- /dev/null
+++ b/python/google/protobuf/pyext/cpp_message.py
@@ -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.
+
+"""Protocol message implementation hooks for C++ implementation.
+
+Contains helper functions used to create protocol message classes from
+Descriptor objects at runtime backed by the protocol buffer C++ API.
+"""
+
+__author__ = 'tibell@google.com (Johan Tibell)'
+
+from google.protobuf.internal import api_implementation
+
+
+# pylint: disable=protected-access
+_message = api_implementation._c_module
+# TODO(jieluo): Remove this import after fix api_implementation
+if _message is None:
+  from google.protobuf.pyext import _message
+
+
+class GeneratedProtocolMessageType(_message.MessageMeta):
+
+  """Metaclass for protocol message classes created at runtime from Descriptors.
+
+  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(.....)
+  factory = symbol_database.Default()
+  factory.pool.AddDescriptor(mydescriptor)
+  MyProtoClass = factory.GetPrototype(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
new file mode 100644
index 0000000..1625312
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -0,0 +1,2040 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: petar@google.com (Petar Petrov)
+
+#include <google/protobuf/pyext/descriptor.h>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <frameobject.h>
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/pyext/descriptor_containers.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/hash.h>
+
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Store interned descriptors, so that the same C++ descriptor yields the same
+// Python object. Objects are not immortal: this map does not own the
+// references, and items are deleted when the last reference to the object is
+// released.
+// This is enough to support the "is" operator on live objects.
+// All descriptors are stored here.
+std::unordered_map<const void*, PyObject*>* interned_descriptors;
+
+PyObject* PyString_FromCppString(const std::string& str) {
+  return PyUnicode_FromStringAndSize(str.c_str(), str.size());
+}
+
+// Check that the calling Python code is the global scope of a _pb2.py module.
+// This function is used to support the current code generated by the proto
+// compiler, which creates descriptors, then update some properties.
+// For example:
+//   message_descriptor = Descriptor(
+//       name='Message',
+//       fields = [FieldDescriptor(name='field')]
+//   message_descriptor.fields[0].containing_type = message_descriptor
+//
+// This code is still executed, but the descriptors now have no other storage
+// than the (const) C++ pointer, and are immutable.
+// So we let this code pass, by simply ignoring the new value.
+//
+// From user code, descriptors still look immutable.
+//
+// TODO(amauryfa): Change the proto2 compiler to remove the assignments, and
+// remove this hack.
+bool _CalledFromGeneratedFile(int stacklevel) {
+#ifndef PYPY_VERSION
+  // This check is not critical and is somewhat difficult to implement correctly
+  // in PyPy.
+  PyFrameObject* frame = PyEval_GetFrame();
+  if (frame == nullptr) {
+    return false;
+  }
+  while (stacklevel-- > 0) {
+    frame = frame->f_back;
+    if (frame == nullptr) {
+      return false;
+    }
+  }
+
+  if (frame->f_code->co_filename == nullptr) {
+    return false;
+  }
+  char* filename;
+  Py_ssize_t filename_size;
+  if (PyString_AsStringAndSize(frame->f_code->co_filename,
+                               &filename, &filename_size) < 0) {
+    // filename is not a string.
+    PyErr_Clear();
+    return false;
+  }
+  if ((filename_size < 3) ||
+      (strcmp(&filename[filename_size - 3], ".py") != 0)) {
+    // Cython's stack does not have .py file name and is not at global module
+    // scope.
+    return true;
+  }
+  if (filename_size < 7) {
+    // filename is too short.
+    return false;
+  }
+  if (strcmp(&filename[filename_size - 7], "_pb2.py") != 0) {
+    // Filename is not ending with _pb2.
+    return false;
+  }
+
+  if (frame->f_globals != frame->f_locals) {
+    // Not at global module scope
+    return false;
+  }
+#endif
+  return true;
+}
+
+// If the calling code is not a _pb2.py file, raise AttributeError.
+// To be used in attribute setters.
+static int CheckCalledFromGeneratedFile(const char* attr_name) {
+  if (_CalledFromGeneratedFile(0)) {
+    return 0;
+  }
+  PyErr_Format(PyExc_AttributeError,
+               "attribute is not writable: %s", attr_name);
+  return -1;
+}
+
+
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
+#endif
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
+
+// 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();
+}
+template<>
+const FileDescriptor* GetFileDescriptor(const MethodDescriptor* descriptor) {
+  return descriptor->service()->file();
+}
+
+bool Reparse(
+    PyMessageFactory* message_factory, const Message& from, Message* to) {
+  // Reparse message.
+  std::string serialized;
+  from.SerializeToString(&serialized);
+  io::CodedInputStream input(
+      reinterpret_cast<const uint8_t*>(serialized.c_str()), serialized.size());
+  input.SetExtensionRegistry(message_factory->pool->pool,
+                             message_factory->message_factory);
+  bool success = to->ParseFromCodedStream(&input);
+  if (!success) {
+    return false;
+  }
+  return true;
+}
+// Converts options into a Python protobuf, and cache the result.
+//
+// This is a bit tricky because options can contain extension fields defined in
+// the same proto file. In this case the options parsed from the serialized_pb
+// have unknown fields, and we need to parse them again.
+//
+// Always returns a new reference.
+template<class DescriptorClass>
+static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
+  // Options are cached in the pool that owns the descriptor.
+  // First search in the cache.
+  PyDescriptorPool* caching_pool = GetDescriptorPool_FromPool(
+      GetFileDescriptor(descriptor)->pool());
+  std::unordered_map<const void*, PyObject*>* descriptor_options =
+      caching_pool->descriptor_options;
+  if (descriptor_options->find(descriptor) != descriptor_options->end()) {
+    PyObject *value = (*descriptor_options)[descriptor];
+    Py_INCREF(value);
+    return value;
+  }
+
+  // Similar to the C++ implementation, we return an Options object from the
+  // default (generated) factory, so that client code know that they can use
+  // extensions from generated files:
+  //    d.GetOptions().Extensions[some_pb2.extension]
+  //
+  // The consequence is that extensions not defined in the default pool won't
+  // be available.  If needed, we could add an optional 'message_factory'
+  // parameter to the GetOptions() function.
+  PyMessageFactory* message_factory =
+      GetDefaultDescriptorPool()->py_message_factory;
+
+  // Build the Options object: get its Python class, and make a copy of the C++
+  // read-only instance.
+  const Message& options(descriptor->options());
+  const Descriptor *message_type = options.GetDescriptor();
+  CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
+      message_factory, message_type);
+  if (message_class == nullptr) {
+    PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
+                 message_type->full_name().c_str());
+    return nullptr;
+  }
+  ScopedPyObjectPtr args(PyTuple_New(0));
+  ScopedPyObjectPtr value(
+      PyObject_Call(message_class->AsPyObject(), args.get(), nullptr));
+  Py_DECREF(message_class);
+  if (value == nullptr) {
+    return nullptr;
+  }
+  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 nullptr;
+  }
+  CMessage* cmsg = reinterpret_cast<CMessage*>(value.get());
+
+  const Reflection* reflection = options.GetReflection();
+  const UnknownFieldSet& unknown_fields(reflection->GetUnknownFields(options));
+  if (unknown_fields.empty()) {
+    cmsg->message->CopyFrom(options);
+  } else {
+    // Reparse options string!  XXX call cmessage::MergeFromString
+    if (!Reparse(message_factory, options, cmsg->message)) {
+      PyErr_Format(PyExc_ValueError, "Error reparsing Options message");
+      return nullptr;
+    }
+  }
+
+  // Cache the result.
+  Py_INCREF(value.get());
+  (*descriptor_options)[descriptor] = value.get();
+
+  return value.release();
+}
+
+// Copy the C++ descriptor to a Python message.
+// The Python message is an instance of descriptor_pb2.DescriptorProto
+// or similar.
+template<class DescriptorProtoClass, class DescriptorClass>
+static PyObject* CopyToPythonProto(const DescriptorClass *descriptor,
+                                   PyObject *target) {
+  const Descriptor* self_descriptor =
+      DescriptorProtoClass::default_instance().GetDescriptor();
+  CMessage* message = reinterpret_cast<CMessage*>(target);
+  if (!PyObject_TypeCheck(target, CMessage_Type) ||
+      message->message->GetDescriptor() != self_descriptor) {
+    PyErr_Format(PyExc_TypeError, "Not a %s message",
+                 self_descriptor->full_name().c_str());
+    return nullptr;
+  }
+  cmessage::AssureWritable(message);
+  DescriptorProtoClass* descriptor_message =
+      static_cast<DescriptorProtoClass*>(message->message);
+  descriptor->CopyTo(descriptor_message);
+  // Custom options might in unknown extensions. Reparse
+  // the descriptor_message. Can't skip reparse when options unknown
+  // fields is empty, because they might in sub descriptors' options.
+  PyMessageFactory* message_factory =
+      GetDefaultDescriptorPool()->py_message_factory;
+  if (!Reparse(message_factory, *descriptor_message, descriptor_message)) {
+    PyErr_Format(PyExc_ValueError, "Error reparsing descriptor message");
+    return nullptr;
+  }
+
+  Py_RETURN_NONE;
+}
+
+// All Descriptors classes share the same memory layout.
+typedef struct PyBaseDescriptor {
+  PyObject_HEAD
+
+  // Pointer to the C++ proto2 descriptor.
+  // Like all descriptors, it is owned by the global DescriptorPool.
+  const void* descriptor;
+
+  // Owned reference to the DescriptorPool, to ensure it is kept alive.
+  PyDescriptorPool* pool;
+} PyBaseDescriptor;
+
+
+// FileDescriptor structure "inherits" from the base descriptor.
+typedef struct PyFileDescriptor {
+  PyBaseDescriptor base;
+
+  // The cached version of serialized pb. Either null, or a Bytes string.
+  // We own the reference.
+  PyObject *serialized_pb;
+} PyFileDescriptor;
+
+
+namespace descriptor {
+
+// Creates or retrieve a Python descriptor of the specified type.
+// Objects are interned: the same descriptor will return the same object if it
+// was kept alive.
+// 'was_created' is an optional pointer to a bool, and is set to true if a new
+// object was allocated.
+// Always return a new reference.
+template<class DescriptorClass>
+PyObject* NewInternedDescriptor(PyTypeObject* type,
+                                const DescriptorClass* descriptor,
+                                bool* was_created) {
+  if (was_created) {
+    *was_created = false;
+  }
+  if (descriptor == nullptr) {
+    PyErr_BadInternalCall();
+    return nullptr;
+  }
+
+  // See if the object is in the map of interned descriptors
+  std::unordered_map<const void*, PyObject*>::iterator it =
+      interned_descriptors->find(descriptor);
+  if (it != interned_descriptors->end()) {
+    GOOGLE_DCHECK(Py_TYPE(it->second) == type);
+    Py_INCREF(it->second);
+    return it->second;
+  }
+  // Create a new descriptor object
+  PyBaseDescriptor* py_descriptor = PyObject_GC_New(
+      PyBaseDescriptor, type);
+  if (py_descriptor == nullptr) {
+    return nullptr;
+  }
+  py_descriptor->descriptor = descriptor;
+
+  // and cache it.
+  interned_descriptors->insert(
+      std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor)));
+
+  // Ensures that the DescriptorPool stays alive.
+  PyDescriptorPool* pool = GetDescriptorPool_FromPool(
+      GetFileDescriptor(descriptor)->pool());
+  if (pool == nullptr) {
+    // Don't DECREF, the object is not fully initialized.
+    PyObject_Del(py_descriptor);
+    return nullptr;
+  }
+  Py_INCREF(pool);
+  py_descriptor->pool = pool;
+
+  PyObject_GC_Track(py_descriptor);
+
+  if (was_created) {
+    *was_created = true;
+  }
+  return reinterpret_cast<PyObject*>(py_descriptor);
+}
+
+static void Dealloc(PyObject* pself) {
+  PyBaseDescriptor* self = reinterpret_cast<PyBaseDescriptor*>(pself);
+  // Remove from interned dictionary
+  interned_descriptors->erase(self->descriptor);
+  Py_CLEAR(self->pool);
+  Py_TYPE(self)->tp_free(pself);
+}
+
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  PyBaseDescriptor* self = reinterpret_cast<PyBaseDescriptor*>(pself);
+  Py_VISIT(self->pool);
+  return 0;
+}
+
+static int GcClear(PyObject* pself) {
+  PyBaseDescriptor* self = reinterpret_cast<PyBaseDescriptor*>(pself);
+  Py_CLEAR(self->pool);
+  return 0;
+}
+
+static PyGetSetDef Getters[] = {
+    {nullptr},
+};
+
+PyTypeObject PyBaseDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".DescriptorBase",         // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    (destructor)Dealloc,       // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                                  // tp_getattr
+    nullptr,                                  // tp_setattr
+    nullptr,                                  // tp_compare
+    nullptr,                                  // tp_repr
+    nullptr,                                  // tp_as_number
+    nullptr,                                  // tp_as_sequence
+    nullptr,                                  // tp_as_mapping
+    nullptr,                                  // tp_hash
+    nullptr,                                  // tp_call
+    nullptr,                                  // tp_str
+    nullptr,                                  // tp_getattro
+    nullptr,                                  // tp_setattro
+    nullptr,                                  // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "Descriptors base class",                 // tp_doc
+    GcTraverse,                               // tp_traverse
+    GcClear,                                  // tp_clear
+    nullptr,                                  // tp_richcompare
+    0,                                        // tp_weaklistoffset
+    nullptr,                                  // tp_iter
+    nullptr,                                  // tp_iternext
+    nullptr,                                  // tp_methods
+    nullptr,                                  // tp_members
+    Getters,                                  // tp_getset
+};
+
+}  // namespace descriptor
+
+const void* PyDescriptor_AsVoidPtr(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &descriptor::PyBaseDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a BaseDescriptor");
+    return nullptr;
+  }
+  return reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor;
+}
+
+namespace message_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const Descriptor* _GetDescriptor(PyBaseDescriptor* self) {
+  return reinterpret_cast<const Descriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
+  // Returns the canonical class for the given descriptor.
+  // This is the class that was registered with the primary descriptor pool
+  // which contains this descriptor.
+  // This might not be the one you expect! For example the returned object does
+  // not know about extensions defined in a custom pool.
+  CMessageClass* concrete_class(message_factory::GetMessageClass(
+      GetDescriptorPool_FromPool(
+          _GetDescriptor(self)->file()->pool())->py_message_factory,
+      _GetDescriptor(self)));
+  Py_XINCREF(concrete_class);
+  return concrete_class->AsPyObject();
+}
+
+static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageFieldsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self,
+                                          void *closure) {
+  return NewMessageFieldsByCamelcaseName(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) {
+  return NewMessageFieldsByNumber(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageFieldsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetNestedTypesByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageNestedTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetNestedTypesSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageNestedTypesSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensionsByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageExtensionsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensions(PyBaseDescriptor* self, void *closure) {
+  return NewMessageExtensionsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumsSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageEnumsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumTypesByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageEnumsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumValuesByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageEnumValuesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetOneofsByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageOneofsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetOneofsSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageOneofsSeq(_GetDescriptor(self));
+}
+
+static PyObject* IsExtendable(PyBaseDescriptor *self, void *closure) {
+  if (_GetDescriptor(self)->extension_range_count() > 0) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static PyObject* GetExtensionRanges(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* descriptor = _GetDescriptor(self);
+  PyObject* range_list = PyList_New(descriptor->extension_range_count());
+
+  for (int i = 0; i < descriptor->extension_range_count(); i++) {
+    const Descriptor::ExtensionRange* range = descriptor->extension_range(i);
+    PyObject* start = PyLong_FromLong(range->start);
+    PyObject* end = PyLong_FromLong(range->end);
+    PyList_SetItem(range_list, i, PyTuple_Pack(2, start, end));
+  }
+
+  return range_list;
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("containing_type");
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const MessageOptions& options(_GetDescriptor(self)->options());
+  if (&options != &MessageOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
+                                void *closure) {
+  return CheckCalledFromGeneratedFile("_serialized_options");
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<DescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyObject* EnumValueName(PyBaseDescriptor *self, PyObject *args) {
+  const char *enum_name;
+  int number;
+  if (!PyArg_ParseTuple(args, "si", &enum_name, &number)) return nullptr;
+  const EnumDescriptor *enum_type =
+      _GetDescriptor(self)->FindEnumTypeByName(enum_name);
+  if (enum_type == nullptr) {
+    PyErr_SetString(PyExc_KeyError, enum_name);
+    return nullptr;
+  }
+  const EnumValueDescriptor *enum_value =
+      enum_type->FindValueByNumber(number);
+  if (enum_value == nullptr) {
+    PyErr_Format(PyExc_KeyError, "%d", number);
+    return nullptr;
+  }
+  return PyString_FromCppString(enum_value->name());
+}
+
+static PyObject* GetSyntax(PyBaseDescriptor *self, void *closure) {
+  return PyUnicode_InternFromString(
+      FileDescriptor::SyntaxName(_GetDescriptor(self)->file()->syntax()));
+}
+
+static PyGetSetDef Getters[] = {
+    {"name", (getter)GetName, nullptr, "Last name"},
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"_concrete_class", (getter)GetConcreteClass, nullptr, "concrete class"},
+    {"file", (getter)GetFile, nullptr, "File descriptor"},
+
+    {"fields", (getter)GetFieldsSeq, nullptr, "Fields sequence"},
+    {"fields_by_name", (getter)GetFieldsByName, nullptr, "Fields by name"},
+    {"fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, nullptr,
+     "Fields by camelCase name"},
+    {"fields_by_number", (getter)GetFieldsByNumber, nullptr,
+     "Fields by number"},
+    {"nested_types", (getter)GetNestedTypesSeq, nullptr,
+     "Nested types sequence"},
+    {"nested_types_by_name", (getter)GetNestedTypesByName, nullptr,
+     "Nested types by name"},
+    {"extensions", (getter)GetExtensions, nullptr, "Extensions Sequence"},
+    {"extensions_by_name", (getter)GetExtensionsByName, nullptr,
+     "Extensions by name"},
+    {"extension_ranges", (getter)GetExtensionRanges, nullptr,
+     "Extension ranges"},
+    {"enum_types", (getter)GetEnumsSeq, nullptr, "Enum sequence"},
+    {"enum_types_by_name", (getter)GetEnumTypesByName, nullptr,
+     "Enum types by name"},
+    {"enum_values_by_name", (getter)GetEnumValuesByName, nullptr,
+     "Enum values by name"},
+    {"oneofs_by_name", (getter)GetOneofsByName, nullptr, "Oneofs by name"},
+    {"oneofs", (getter)GetOneofsSeq, nullptr, "Oneofs by name"},
+    {"containing_type", (getter)GetContainingType, (setter)SetContainingType,
+     "Containing type"},
+    {"is_extendable", (getter)IsExtendable, (setter) nullptr},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {"syntax", (getter)GetSyntax, (setter) nullptr, "Syntax"},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {"EnumValueName", (PyCFunction)EnumValueName, METH_VARARGS},
+    {nullptr},
+};
+
+}  // namespace message_descriptor
+
+PyTypeObject PyMessageDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MessageDescriptor",      // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Message Descriptor",              // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    message_descriptor::Methods,         // tp_methods
+    nullptr,                             // tp_members
+    message_descriptor::Getters,         // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyMessageDescriptor_FromDescriptor(
+    const Descriptor* message_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyMessageDescriptor_Type,
+                                           message_descriptor, nullptr);
+}
+
+const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyMessageDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a MessageDescriptor");
+    return nullptr;
+  }
+  return reinterpret_cast<const Descriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace field_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const FieldDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const FieldDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->camelcase_name());
+}
+
+static PyObject* GetJsonName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->json_name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->type());
+}
+
+static PyObject* GetCppType(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->cpp_type());
+}
+
+static PyObject* GetLabel(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->label());
+}
+
+static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->number());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetID(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromVoidPtr(self);
+}
+
+static PyObject* IsExtension(PyBaseDescriptor *self, void *closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->is_extension());
+}
+
+static PyObject* HasDefaultValue(PyBaseDescriptor *self, void *closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->has_default_value());
+}
+
+static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
+  PyObject *result;
+
+  if (_GetDescriptor(self)->is_repeated()) {
+    return PyList_New(0);
+  }
+
+
+  switch (_GetDescriptor(self)->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      int32_t value = _GetDescriptor(self)->default_value_int32();
+      result = PyLong_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      int64_t value = _GetDescriptor(self)->default_value_int64();
+      result = PyLong_FromLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      uint32_t value = _GetDescriptor(self)->default_value_uint32();
+      result = PyLong_FromSsize_t(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      uint64_t value = _GetDescriptor(self)->default_value_uint64();
+      result = PyLong_FromUnsignedLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value = _GetDescriptor(self)->default_value_float();
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value = _GetDescriptor(self)->default_value_double();
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      bool value = _GetDescriptor(self)->default_value_bool();
+      result = PyBool_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      const std::string& value = _GetDescriptor(self)->default_value_string();
+      result = ToStringObject(_GetDescriptor(self), value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      const EnumValueDescriptor* value =
+          _GetDescriptor(self)->default_value_enum();
+      result = PyLong_FromLong(value->number());
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      Py_RETURN_NONE;
+      break;
+    }
+    default:
+      PyErr_Format(PyExc_NotImplementedError, "default value for %s",
+                   _GetDescriptor(self)->full_name().c_str());
+      return nullptr;
+  }
+  return result;
+}
+
+static PyObject* GetCDescriptor(PyObject *self, void *closure) {
+  Py_INCREF(self);
+  return self;
+}
+
+static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) {
+  const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type();
+  if (enum_type) {
+    return PyEnumDescriptor_FromDescriptor(enum_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetEnumType(PyBaseDescriptor *self, PyObject *value, void *closure) {
+  return CheckCalledFromGeneratedFile("enum_type");
+}
+
+static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* message_type = _GetDescriptor(self)->message_type();
+  if (message_type) {
+    return PyMessageDescriptor_FromDescriptor(message_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetMessageType(PyBaseDescriptor *self, PyObject *value,
+                          void *closure) {
+  return CheckCalledFromGeneratedFile("message_type");
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("containing_type");
+}
+
+static PyObject* GetExtensionScope(PyBaseDescriptor *self, void *closure) {
+  const auto* desc = _GetDescriptor(self);
+  const Descriptor* extension_scope =
+      desc->is_extension() ? desc->extension_scope() : nullptr;
+  if (extension_scope) {
+    return PyMessageDescriptor_FromDescriptor(extension_scope);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static PyObject* GetContainingOneof(PyBaseDescriptor *self, void *closure) {
+  const OneofDescriptor* containing_oneof =
+      _GetDescriptor(self)->containing_oneof();
+  if (containing_oneof) {
+    return PyOneofDescriptor_FromDescriptor(containing_oneof);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingOneof(PyBaseDescriptor *self, PyObject *value,
+                              void *closure) {
+  return CheckCalledFromGeneratedFile("containing_oneof");
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const FieldOptions& options(_GetDescriptor(self)->options());
+  if (&options != &FieldOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetHasPresence(PyBaseDescriptor* self, void* closure) {
+  if (_GetDescriptor(self)->has_presence()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
+                                void *closure) {
+  return CheckCalledFromGeneratedFile("_serialized_options");
+}
+
+static PyGetSetDef Getters[] = {
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"name", (getter)GetName, nullptr, "Unqualified name"},
+    {"camelcase_name", (getter)GetCamelcaseName, nullptr, "Camelcase name"},
+    {"json_name", (getter)GetJsonName, nullptr, "Json name"},
+    {"file", (getter)GetFile, nullptr, "File Descriptor"},
+    {"type", (getter)GetType, nullptr, "C++ Type"},
+    {"cpp_type", (getter)GetCppType, nullptr, "C++ Type"},
+    {"label", (getter)GetLabel, nullptr, "Label"},
+    {"number", (getter)GetNumber, nullptr, "Number"},
+    {"index", (getter)GetIndex, nullptr, "Index"},
+    {"default_value", (getter)GetDefaultValue, nullptr, "Default Value"},
+    {"has_default_value", (getter)HasDefaultValue},
+    {"is_extension", (getter)IsExtension, nullptr, "ID"},
+    {"id", (getter)GetID, nullptr, "ID"},
+    {"_cdescriptor", (getter)GetCDescriptor, nullptr, "HAACK REMOVE ME"},
+
+    {"message_type", (getter)GetMessageType, (setter)SetMessageType,
+     "Message type"},
+    {"enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"},
+    {"containing_type", (getter)GetContainingType, (setter)SetContainingType,
+     "Containing type"},
+    {"extension_scope", (getter)GetExtensionScope, (setter) nullptr,
+     "Extension scope"},
+    {"containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof,
+     "Containing oneof"},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"has_presence", (getter)GetHasPresence, (setter) nullptr, "Has Presence"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {nullptr},
+};
+
+}  // namespace field_descriptor
+
+PyTypeObject PyFieldDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".FieldDescriptor",        // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Field Descriptor",                // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    field_descriptor::Methods,           // tp_methods
+    nullptr,                             // tp_members
+    field_descriptor::Getters,           // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyFieldDescriptor_FromDescriptor(
+    const FieldDescriptor* field_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyFieldDescriptor_Type,
+                                           field_descriptor, nullptr);
+}
+
+const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyFieldDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a FieldDescriptor");
+    return nullptr;
+  }
+  return reinterpret_cast<const FieldDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace enum_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const EnumDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const EnumDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) {
+  return NewEnumValuesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumvaluesByNumber(PyBaseDescriptor* self, void *closure) {
+  return NewEnumValuesByNumber(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumvaluesSeq(PyBaseDescriptor* self, void *closure) {
+  return NewEnumValuesSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("containing_type");
+}
+
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const EnumOptions& options(_GetDescriptor(self)->options());
+  if (&options != &EnumOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
+                                void *closure) {
+  return CheckCalledFromGeneratedFile("_serialized_options");
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<EnumDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {nullptr},
+};
+
+static PyGetSetDef Getters[] = {
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"name", (getter)GetName, nullptr, "last name"},
+    {"file", (getter)GetFile, nullptr, "File descriptor"},
+    {"values", (getter)GetEnumvaluesSeq, nullptr, "values"},
+    {"values_by_name", (getter)GetEnumvaluesByName, nullptr,
+     "Enum values by name"},
+    {"values_by_number", (getter)GetEnumvaluesByNumber, nullptr,
+     "Enum values by number"},
+
+    {"containing_type", (getter)GetContainingType, (setter)SetContainingType,
+     "Containing type"},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {nullptr},
+};
+
+}  // namespace enum_descriptor
+
+PyTypeObject PyEnumDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".EnumDescriptor",         // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Enum Descriptor",                 // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    enum_descriptor::Methods,            // tp_methods
+    nullptr,                             // tp_members
+    enum_descriptor::Getters,            // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyEnumDescriptor_FromDescriptor(
+    const EnumDescriptor* enum_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyEnumDescriptor_Type,
+                                           enum_descriptor, nullptr);
+}
+
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor");
+    return nullptr;
+  }
+  return reinterpret_cast<const EnumDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace enumvalue_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const EnumValueDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const EnumValueDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->number());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
+  return PyEnumDescriptor_FromDescriptor(_GetDescriptor(self)->type());
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const EnumValueOptions& options(_GetDescriptor(self)->options());
+  if (&options != &EnumValueOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
+                                void *closure) {
+  return CheckCalledFromGeneratedFile("_serialized_options");
+}
+
+static PyGetSetDef Getters[] = {
+    {"name", (getter)GetName, nullptr, "name"},
+    {"number", (getter)GetNumber, nullptr, "number"},
+    {"index", (getter)GetIndex, nullptr, "index"},
+    {"type", (getter)GetType, nullptr, "index"},
+
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {nullptr},
+};
+
+}  // namespace enumvalue_descriptor
+
+PyTypeObject PyEnumValueDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".EnumValueDescriptor",    // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A EnumValue Descriptor",            // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    enumvalue_descriptor::Methods,       // tp_methods
+    nullptr,                             // tp_members
+    enumvalue_descriptor::Getters,       // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyEnumValueDescriptor_FromDescriptor(
+    const EnumValueDescriptor* enumvalue_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyEnumValueDescriptor_Type,
+                                           enumvalue_descriptor, nullptr);
+}
+
+namespace file_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const FileDescriptor* _GetDescriptor(PyFileDescriptor *self) {
+  return reinterpret_cast<const FileDescriptor*>(self->base.descriptor);
+}
+
+static void Dealloc(PyFileDescriptor* self) {
+  Py_XDECREF(self->serialized_pb);
+  descriptor::Dealloc(reinterpret_cast<PyObject*>(self));
+}
+
+static PyObject* GetPool(PyFileDescriptor *self, void *closure) {
+  PyObject* pool = reinterpret_cast<PyObject*>(
+      GetDescriptorPool_FromPool(_GetDescriptor(self)->pool()));
+  Py_XINCREF(pool);
+  return pool;
+}
+
+static PyObject* GetName(PyFileDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetPackage(PyFileDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->package());
+}
+
+static PyObject* GetSerializedPb(PyFileDescriptor *self, void *closure) {
+  PyObject *serialized_pb = self->serialized_pb;
+  if (serialized_pb != nullptr) {
+    Py_INCREF(serialized_pb);
+    return serialized_pb;
+  }
+  FileDescriptorProto file_proto;
+  _GetDescriptor(self)->CopyTo(&file_proto);
+  std::string contents;
+  file_proto.SerializePartialToString(&contents);
+  self->serialized_pb = PyBytes_FromStringAndSize(
+      contents.c_str(), contents.size());
+  if (self->serialized_pb == nullptr) {
+    return nullptr;
+  }
+  Py_INCREF(self->serialized_pb);
+  return self->serialized_pb;
+}
+
+static PyObject* GetMessageTypesByName(PyFileDescriptor* self, void *closure) {
+  return NewFileMessageTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumTypesByName(PyFileDescriptor* self, void *closure) {
+  return NewFileEnumTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensionsByName(PyFileDescriptor* self, void *closure) {
+  return NewFileExtensionsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetServicesByName(PyFileDescriptor* self, void *closure) {
+  return NewFileServicesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetDependencies(PyFileDescriptor* self, void *closure) {
+  return NewFileDependencies(_GetDescriptor(self));
+}
+
+static PyObject* GetPublicDependencies(PyFileDescriptor* self, void *closure) {
+  return NewFilePublicDependencies(_GetDescriptor(self));
+}
+
+static PyObject* GetHasOptions(PyFileDescriptor *self, void *closure) {
+  const FileOptions& options(_GetDescriptor(self)->options());
+  if (&options != &FileOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyFileDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetDebugString(PyFileDescriptor* self) {
+  return PyString_FromCppString(_GetDescriptor(self)->DebugString());
+}
+
+static PyObject* GetOptions(PyFileDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyFileDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static int SetSerializedOptions(PyFileDescriptor *self, PyObject *value,
+                                void *closure) {
+  return CheckCalledFromGeneratedFile("_serialized_options");
+}
+
+static PyObject* GetSyntax(PyFileDescriptor *self, void *closure) {
+  return PyUnicode_InternFromString(
+      FileDescriptor::SyntaxName(_GetDescriptor(self)->syntax()));
+}
+
+static PyObject* CopyToProto(PyFileDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<FileDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyGetSetDef Getters[] = {
+    {"pool", (getter)GetPool, nullptr, "pool"},
+    {"name", (getter)GetName, nullptr, "name"},
+    {"package", (getter)GetPackage, nullptr, "package"},
+    {"serialized_pb", (getter)GetSerializedPb},
+    {"message_types_by_name", (getter)GetMessageTypesByName, nullptr,
+     "Messages by name"},
+    {"enum_types_by_name", (getter)GetEnumTypesByName, nullptr,
+     "Enums by name"},
+    {"extensions_by_name", (getter)GetExtensionsByName, nullptr,
+     "Extensions by name"},
+    {"services_by_name", (getter)GetServicesByName, nullptr,
+     "Services by name"},
+    {"dependencies", (getter)GetDependencies, nullptr, "Dependencies"},
+    {"public_dependencies", (getter)GetPublicDependencies, nullptr,
+     "Dependencies"},
+
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {"syntax", (getter)GetSyntax, (setter) nullptr, "Syntax"},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetDebugString", (PyCFunction)GetDebugString, METH_NOARGS},
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {nullptr},
+};
+
+}  // namespace file_descriptor
+
+PyTypeObject PyFileDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".FileDescriptor",                     // tp_name
+    sizeof(PyFileDescriptor),              // tp_basicsize
+    0,                                     // tp_itemsize
+    (destructor)file_descriptor::Dealloc,  // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A File Descriptor",                 // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    file_descriptor::Methods,            // tp_methods
+    nullptr,                             // tp_members
+    file_descriptor::Getters,            // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+    nullptr,                             // tp_dict
+    nullptr,                             // tp_descr_get
+    nullptr,                             // tp_descr_set
+    0,                                   // tp_dictoffset
+    nullptr,                             // tp_init
+    nullptr,                             // tp_alloc
+    nullptr,                             // tp_new
+    PyObject_GC_Del,                     // tp_free
+};
+
+PyObject* PyFileDescriptor_FromDescriptor(
+    const FileDescriptor* file_descriptor) {
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor,
+                                                         nullptr);
+}
+
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
+    const FileDescriptor* file_descriptor, PyObject *serialized_pb) {
+  bool was_created;
+  PyObject* py_descriptor = descriptor::NewInternedDescriptor(
+      &PyFileDescriptor_Type, file_descriptor, &was_created);
+  if (py_descriptor == nullptr) {
+    return nullptr;
+  }
+  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 nullptr;
+  }
+  return reinterpret_cast<const FileDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace oneof_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const OneofDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const OneofDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetFields(PyBaseDescriptor* self, void *closure) {
+  return NewOneofFieldsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const OneofOptions& options(_GetDescriptor(self)->options());
+  if (&options != &OneofOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
+                                void *closure) {
+  return CheckCalledFromGeneratedFile("_serialized_options");
+}
+
+static PyGetSetDef Getters[] = {
+    {"name", (getter)GetName, nullptr, "Name"},
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"index", (getter)GetIndex, nullptr, "Index"},
+
+    {"containing_type", (getter)GetContainingType, nullptr, "Containing type"},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {"fields", (getter)GetFields, nullptr, "Fields"},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {nullptr},
+};
+
+}  // namespace oneof_descriptor
+
+PyTypeObject PyOneofDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".OneofDescriptor",        // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Oneof Descriptor",                // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    oneof_descriptor::Methods,           // tp_methods
+    nullptr,                             // tp_members
+    oneof_descriptor::Getters,           // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyOneofDescriptor_FromDescriptor(
+    const OneofDescriptor* oneof_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyOneofDescriptor_Type,
+                                           oneof_descriptor, nullptr);
+}
+
+namespace service_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const ServiceDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const ServiceDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetMethods(PyBaseDescriptor* self, void *closure) {
+  return NewServiceMethodsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetMethodsByName(PyBaseDescriptor* self, void *closure) {
+  return NewServiceMethodsByName(_GetDescriptor(self));
+}
+
+static PyObject* FindMethodByName(PyBaseDescriptor *self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const MethodDescriptor* method_descriptor =
+      _GetDescriptor(self)->FindMethodByName(StringParam(name, name_size));
+  if (method_descriptor == nullptr) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
+    return nullptr;
+  }
+
+  return PyMethodDescriptor_FromDescriptor(method_descriptor);
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<ServiceDescriptorProto>(_GetDescriptor(self),
+                                                   target);
+}
+
+static PyGetSetDef Getters[] = {
+    {"name", (getter)GetName, nullptr, "Name", nullptr},
+    {"full_name", (getter)GetFullName, nullptr, "Full name", nullptr},
+    {"file", (getter)GetFile, nullptr, "File descriptor"},
+    {"index", (getter)GetIndex, nullptr, "Index", nullptr},
+    {"methods", (getter)GetMethods, nullptr, "Methods", nullptr},
+    {"methods_by_name", (getter)GetMethodsByName, nullptr, "Methods by name",
+     nullptr},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {"FindMethodByName", (PyCFunction)FindMethodByName, METH_O},
+    {nullptr},
+};
+
+}  // namespace service_descriptor
+
+PyTypeObject PyServiceDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".ServiceDescriptor",      // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Service Descriptor",              // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    service_descriptor::Methods,         // tp_methods
+    nullptr,                             // tp_members
+    service_descriptor::Getters,         // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyServiceDescriptor_FromDescriptor(
+    const ServiceDescriptor* service_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyServiceDescriptor_Type,
+                                           service_descriptor, nullptr);
+}
+
+const ServiceDescriptor* PyServiceDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyServiceDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a ServiceDescriptor");
+    return nullptr;
+  }
+  return reinterpret_cast<const ServiceDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace method_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const MethodDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const MethodDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetContainingService(PyBaseDescriptor *self, void *closure) {
+  const ServiceDescriptor* containing_service =
+      _GetDescriptor(self)->service();
+  return PyServiceDescriptor_FromDescriptor(containing_service);
+}
+
+static PyObject* GetInputType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* input_type = _GetDescriptor(self)->input_type();
+  return PyMessageDescriptor_FromDescriptor(input_type);
+}
+
+static PyObject* GetOutputType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* output_type = _GetDescriptor(self)->output_type();
+  return PyMessageDescriptor_FromDescriptor(output_type);
+}
+
+static PyObject* GetClientStreaming(PyBaseDescriptor* self, void* closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->client_streaming() ? 1 : 0);
+}
+
+static PyObject* GetServerStreaming(PyBaseDescriptor* self, void* closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->server_streaming() ? 1 : 0);
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<MethodDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyGetSetDef Getters[] = {
+    {"name", (getter)GetName, nullptr, "Name", nullptr},
+    {"full_name", (getter)GetFullName, nullptr, "Full name", nullptr},
+    {"index", (getter)GetIndex, nullptr, "Index", nullptr},
+    {"containing_service", (getter)GetContainingService, nullptr,
+     "Containing service", nullptr},
+    {"input_type", (getter)GetInputType, nullptr, "Input type", nullptr},
+    {"output_type", (getter)GetOutputType, nullptr, "Output type", nullptr},
+    {"client_streaming", (getter)GetClientStreaming, nullptr,
+     "Client streaming", nullptr},
+    {"server_streaming", (getter)GetServerStreaming, nullptr,
+     "Server streaming", nullptr},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {nullptr},
+};
+
+}  // namespace method_descriptor
+
+PyTypeObject PyMethodDescriptor_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MethodDescriptor",       // tp_name
+    sizeof(PyBaseDescriptor),  // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Method Descriptor",               // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    method_descriptor::Methods,          // tp_methods
+    nullptr,                             // tp_members
+    method_descriptor::Getters,          // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
+};
+
+PyObject* PyMethodDescriptor_FromDescriptor(
+    const MethodDescriptor* method_descriptor) {
+  return descriptor::NewInternedDescriptor(&PyMethodDescriptor_Type,
+                                           method_descriptor, nullptr);
+}
+
+// Add a enum values to a type dictionary.
+static bool AddEnumValues(PyTypeObject *type,
+                          const EnumDescriptor* enum_descriptor) {
+  for (int i = 0; i < enum_descriptor->value_count(); ++i) {
+    const EnumValueDescriptor* value = enum_descriptor->value(i);
+    ScopedPyObjectPtr obj(PyLong_FromLong(value->number()));
+    if (obj == nullptr) {
+      return false;
+    }
+    if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj.get()) <
+        0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static bool AddIntConstant(PyTypeObject *type, const char* name, int value) {
+  ScopedPyObjectPtr obj(PyLong_FromLong(value));
+  if (PyDict_SetItemString(type->tp_dict, name, obj.get()) < 0) {
+    return false;
+  }
+  return true;
+}
+
+
+bool InitDescriptor() {
+  if (PyType_Ready(&PyMessageDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyFieldDescriptor_Type) < 0)
+    return false;
+
+  if (!AddEnumValues(&PyFieldDescriptor_Type,
+                     FieldDescriptorProto::Label_descriptor())) {
+    return false;
+  }
+  if (!AddEnumValues(&PyFieldDescriptor_Type,
+                     FieldDescriptorProto::Type_descriptor())) {
+    return false;
+  }
+#define ADD_FIELDDESC_CONSTANT(NAME) AddIntConstant( \
+    &PyFieldDescriptor_Type, #NAME, FieldDescriptor::NAME)
+  if (!ADD_FIELDDESC_CONSTANT(CPPTYPE_INT32) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_INT64) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT32) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT64) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_DOUBLE) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_FLOAT) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_BOOL) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_ENUM) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_STRING) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_MESSAGE)) {
+    return false;
+  }
+#undef ADD_FIELDDESC_CONSTANT
+
+  if (PyType_Ready(&PyEnumDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyEnumValueDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyFileDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyOneofDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyServiceDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyMethodDescriptor_Type) < 0)
+    return false;
+
+  if (!InitDescriptorMappingTypes())
+    return false;
+
+  // Initialize globals defined in this file.
+  interned_descriptors = new std::unordered_map<const void*, PyObject*>;
+
+  return true;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
new file mode 100644
index 0000000..d97e2f8
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -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.
+
+// Author: petar@google.com (Petar Petrov)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Should match the type of ConstStringParam.
+using StringParam = std::string;
+
+extern PyTypeObject PyMessageDescriptor_Type;
+extern PyTypeObject PyFieldDescriptor_Type;
+extern PyTypeObject PyEnumDescriptor_Type;
+extern PyTypeObject PyEnumValueDescriptor_Type;
+extern PyTypeObject PyFileDescriptor_Type;
+extern PyTypeObject PyOneofDescriptor_Type;
+extern PyTypeObject PyServiceDescriptor_Type;
+extern PyTypeObject PyMethodDescriptor_Type;
+
+// Wraps a Descriptor in a Python object.
+// The C++ pointer is usually borrowed from the global DescriptorPool.
+// In any case, it must stay alive as long as the Python object.
+// Returns a new reference.
+PyObject* 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);
+PyObject* PyServiceDescriptor_FromDescriptor(
+    const ServiceDescriptor* descriptor);
+PyObject* PyMethodDescriptor_FromDescriptor(
+    const MethodDescriptor* descriptor);
+
+// Alternate constructor of PyFileDescriptor, used when we already have a
+// serialized FileDescriptorProto that can be cached.
+// Returns a new reference.
+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);
+const ServiceDescriptor* PyServiceDescriptor_AsDescriptor(PyObject* obj);
+
+// Returns the raw C++ pointer.
+const void* PyDescriptor_AsVoidPtr(PyObject* obj);
+
+// Check that the calling Python code is the global scope of a _pb2.py module.
+// This function is used to support the current code generated by the proto
+// compiler, which insists on modifying descriptors after they have been
+// created.
+//
+// stacklevel indicates which Python frame should be the _pb2.py module.
+//
+// Don't use this function outside descriptor classes.
+bool _CalledFromGeneratedFile(int stacklevel);
+
+bool InitDescriptor();
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
new file mode 100644
index 0000000..a87155b
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -0,0 +1,1689 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Mappings and Sequences of descriptors.
+// Used by Descriptor.fields_by_name, EnumDescriptor.values...
+//
+// They avoid the allocation of a full dictionary or a full list: they simply
+// store a pointer to the parent descriptor, use the C++ Descriptor methods (see
+// net/proto2/public/descriptor.h) to retrieve other descriptors, and create
+// Python objects on the fly.
+//
+// The containers fully conform to abc.Mapping and abc.Sequence, and behave just
+// like read-only dictionaries and lists.
+//
+// Because the interface of C++ Descriptors is quite regular, this file actually
+// defines only three types, the exact behavior of a container is controlled by
+// a DescriptorContainerDef structure, which contains functions that uses the
+// public Descriptor API.
+//
+// Note: This DescriptorContainerDef is similar to the "virtual methods table"
+// that a C++ compiler generates for a class. We have to make it explicit
+// because the Python API is based on C, and does not play well with C++
+// inheritance.
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/pyext/descriptor_containers.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+struct PyContainer;
+
+typedef int (*CountMethod)(PyContainer* self);
+typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
+typedef const void* (*GetByNameMethod)(PyContainer* self,
+                                       ConstStringParam name);
+typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self,
+                                                ConstStringParam name);
+typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
+typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
+typedef const std::string& (*GetItemNameMethod)(const void* descriptor);
+typedef const std::string& (*GetItemCamelcaseNameMethod)(
+    const void* descriptor);
+typedef int (*GetItemNumberMethod)(const void* descriptor);
+typedef int (*GetItemIndexMethod)(const void* descriptor);
+
+struct DescriptorContainerDef {
+  const char* mapping_name;
+  // Returns the number of items in the container.
+  CountMethod count_fn;
+  // Retrieve item by index (usually the order of declaration in the proto file)
+  // Used by sequences, but also iterators. 0 <= index < Count().
+  GetByIndexMethod get_by_index_fn;
+  // Retrieve item by name (usually a call to some 'FindByName' method).
+  // Used by "by_name" mappings.
+  GetByNameMethod get_by_name_fn;
+  // Retrieve item by camelcase name (usually a call to some
+  // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings.
+  GetByCamelcaseNameMethod get_by_camelcase_name_fn;
+  // Retrieve item by declared number (field tag, or enum value).
+  // Used by "by_number" mappings.
+  GetByNumberMethod get_by_number_fn;
+  // Converts a item C++ descriptor to a Python object. Returns a new reference.
+  NewObjectFromItemMethod new_object_from_item_fn;
+  // Retrieve the name of an item. Used by iterators on "by_name" mappings.
+  GetItemNameMethod get_item_name_fn;
+  // Retrieve the camelcase name of an item. Used by iterators on
+  // "by_camelcase_name" mappings.
+  GetItemCamelcaseNameMethod get_item_camelcase_name_fn;
+  // Retrieve the number of an item. Used by iterators on "by_number" mappings.
+  GetItemNumberMethod get_item_number_fn;
+  // Retrieve the index of an item for the container type.
+  // Used by "__contains__".
+  // If not set, "x in sequence" will do a linear search.
+  GetItemIndexMethod get_item_index_fn;
+};
+
+struct PyContainer {
+  PyObject_HEAD
+
+  // The proto2 descriptor this container belongs to the global DescriptorPool.
+  const void* descriptor;
+
+  // A pointer to a static structure with function pointers that control the
+  // behavior of the container. Very similar to the table of virtual functions
+  // of a C++ class.
+  const DescriptorContainerDef* container_def;
+
+  // The kind of container: list, or dict by name or value.
+  enum ContainerKind {
+    KIND_SEQUENCE,
+    KIND_BYNAME,
+    KIND_BYCAMELCASENAME,
+    KIND_BYNUMBER,
+  } kind;
+};
+
+struct PyContainerIterator {
+  PyObject_HEAD
+
+  // The container we are iterating over. Own a reference.
+  PyContainer* container;
+
+  // The current index in the iterator.
+  int index;
+
+  // The kind of container: list, or dict by name or value.
+  enum IterKind {
+    KIND_ITERKEY,
+    KIND_ITERVALUE,
+    KIND_ITERITEM,
+    KIND_ITERVALUE_REVERSED,  // For sequences
+  } kind;
+};
+
+namespace descriptor {
+
+// Returns the C++ item descriptor for a given Python key.
+// When the descriptor is found, return true and set *item.
+// When the descriptor is not found, return true, but set *item to null.
+// On error, returns false with an exception set.
+static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
+  switch (self->kind) {
+    case PyContainer::KIND_BYNAME: {
+      char* name;
+      Py_ssize_t name_size;
+      if (PyString_AsStringAndSize(key, &name, &name_size) < 0) {
+        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+          // Not a string, cannot be in the container.
+          PyErr_Clear();
+          *item = nullptr;
+          return true;
+        }
+        return false;
+      }
+      *item = self->container_def->get_by_name_fn(self,
+                                                  StringParam(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 = nullptr;
+          return true;
+        }
+        return false;
+      }
+      *item = self->container_def->get_by_camelcase_name_fn(
+          self, StringParam(camelcase_name, name_size));
+      return true;
+    }
+    case PyContainer::KIND_BYNUMBER: {
+      Py_ssize_t number = PyNumber_AsSsize_t(key, nullptr);
+      if (number == -1 && PyErr_Occurred()) {
+        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+          // Not a number, cannot be in the container.
+          PyErr_Clear();
+          *item = nullptr;
+          return true;
+        }
+        return false;
+      }
+      *item = self->container_def->get_by_number_fn(self, number);
+      return true;
+    }
+    default:
+      PyErr_SetNone(PyExc_NotImplementedError);
+      return false;
+  }
+}
+
+// Returns the key of the object at the given index.
+// Used when iterating over mappings.
+static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
+  const void* item = self->container_def->get_by_index_fn(self, index);
+  switch (self->kind) {
+    case PyContainer::KIND_BYNAME: {
+      const std::string& name(self->container_def->get_item_name_fn(item));
+      return PyUnicode_FromStringAndSize(name.c_str(), name.size());
+    }
+    case PyContainer::KIND_BYCAMELCASENAME: {
+      const std::string& name(
+          self->container_def->get_item_camelcase_name_fn(item));
+      return PyUnicode_FromStringAndSize(name.c_str(), name.size());
+    }
+    case PyContainer::KIND_BYNUMBER: {
+      int value = self->container_def->get_item_number_fn(item);
+      return PyLong_FromLong(value);
+    }
+    default:
+      PyErr_SetNone(PyExc_NotImplementedError);
+      return nullptr;
+  }
+}
+
+// Returns the object at the given index.
+// Also used when iterating over mappings.
+static PyObject* _NewObj_ByIndex(PyContainer* self, Py_ssize_t index) {
+  return self->container_def->new_object_from_item_fn(
+      self->container_def->get_by_index_fn(self, index));
+}
+
+static Py_ssize_t Length(PyContainer* self) {
+  return self->container_def->count_fn(self);
+}
+
+// The DescriptorMapping type.
+
+static PyObject* Subscript(PyContainer* self, PyObject* key) {
+  const void* item = nullptr;
+  if (!_GetItemByKey(self, key, &item)) {
+    return nullptr;
+  }
+  if (!item) {
+    PyErr_SetObject(PyExc_KeyError, key);
+    return nullptr;
+  }
+  return self->container_def->new_object_from_item_fn(item);
+}
+
+static int AssSubscript(PyContainer* self, PyObject* key, PyObject* value) {
+  if (_CalledFromGeneratedFile(0)) {
+    return 0;
+  }
+  PyErr_Format(PyExc_TypeError,
+               "'%.200s' object does not support item assignment",
+               Py_TYPE(self)->tp_name);
+  return -1;
+}
+
+static PyMappingMethods MappingMappingMethods = {
+  (lenfunc)Length,               // mp_length
+  (binaryfunc)Subscript,         // mp_subscript
+  (objobjargproc)AssSubscript,   // mp_ass_subscript
+};
+
+static int Contains(PyContainer* self, PyObject* key) {
+  const void* item = nullptr;
+  if (!_GetItemByKey(self, key, &item)) {
+    return -1;
+  }
+  if (item) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+static PyObject* ContainerRepr(PyContainer* self) {
+  const char* kind = "";
+  switch (self->kind) {
+    case PyContainer::KIND_SEQUENCE:
+      kind = "sequence";
+      break;
+    case PyContainer::KIND_BYNAME:
+      kind = "mapping by name";
+      break;
+    case PyContainer::KIND_BYCAMELCASENAME:
+      kind = "mapping by camelCase name";
+      break;
+    case PyContainer::KIND_BYNUMBER:
+      kind = "mapping by number";
+      break;
+  }
+  return PyUnicode_FromFormat("<%s %s>", self->container_def->mapping_name,
+                              kind);
+}
+
+extern PyTypeObject DescriptorMapping_Type;
+extern PyTypeObject DescriptorSequence_Type;
+
+// A sequence container can only be equal to another sequence container, or (for
+// backward compatibility) to a list containing the same items.
+// Returns 1 if equal, 0 if unequal, -1 on error.
+static int DescriptorSequence_Equal(PyContainer* self, PyObject* other) {
+  // Check the identity of C++ pointers.
+  if (PyObject_TypeCheck(other, &DescriptorSequence_Type)) {
+    PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
+    if (self->descriptor == other_container->descriptor &&
+        self->container_def == other_container->container_def &&
+        self->kind == other_container->kind) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+
+  // If other is a list
+  if (PyList_Check(other)) {
+    // return list(self) == other
+    int size = Length(self);
+    if (size != PyList_Size(other)) {
+      return false;
+    }
+    for (int index = 0; index < size; index++) {
+      ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
+      if (value1 == nullptr) {
+        return -1;
+      }
+      PyObject* value2 = PyList_GetItem(other, index);
+      if (value2 == nullptr) {
+        return -1;
+      }
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
+      if (cmp != 1)  // error or not equal
+          return cmp;
+    }
+    // All items were found and equal
+    return 1;
+  }
+
+  // Any other object is different.
+  return 0;
+}
+
+// A mapping container can only be equal to another mapping container, or (for
+// backward compatibility) to a dict containing the same items.
+// Returns 1 if equal, 0 if unequal, -1 on error.
+static int DescriptorMapping_Equal(PyContainer* self, PyObject* other) {
+  // Check the identity of C++ pointers.
+  if (PyObject_TypeCheck(other, &DescriptorMapping_Type)) {
+    PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
+    if (self->descriptor == other_container->descriptor &&
+        self->container_def == other_container->container_def &&
+        self->kind == other_container->kind) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+
+  // If other is a dict
+  if (PyDict_Check(other)) {
+    // equivalent to dict(self.items()) == other
+    int size = Length(self);
+    if (size != PyDict_Size(other)) {
+      return false;
+    }
+    for (int index = 0; index < size; index++) {
+      ScopedPyObjectPtr key(_NewKey_ByIndex(self, index));
+      if (key == nullptr) {
+        return -1;
+      }
+      ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
+      if (value1 == nullptr) {
+        return -1;
+      }
+      PyObject* value2 = PyDict_GetItem(other, key.get());
+      if (value2 == nullptr) {
+        // Not found in the other dictionary
+        return 0;
+      }
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
+      if (cmp != 1)  // error or not equal
+          return cmp;
+    }
+    // All items were found and equal
+    return 1;
+  }
+
+  // Any other object is different.
+  return 0;
+}
+
+static PyObject* RichCompare(PyContainer* self, PyObject* other, int opid) {
+  if (opid != Py_EQ && opid != Py_NE) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int result;
+
+  if (self->kind == PyContainer::KIND_SEQUENCE) {
+    result = DescriptorSequence_Equal(self, other);
+  } else {
+    result = DescriptorMapping_Equal(self, other);
+  }
+  if (result < 0) {
+    return nullptr;
+  }
+  if (result ^ (opid == Py_NE)) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static PySequenceMethods MappingSequenceMethods = {
+    nullptr,               // sq_length
+    nullptr,               // sq_concat
+    nullptr,               // sq_repeat
+    nullptr,               // sq_item
+    nullptr,               // sq_slice
+    nullptr,               // sq_ass_item
+    nullptr,               // sq_ass_slice
+    (objobjproc)Contains,  // sq_contains
+};
+
+static PyObject* Get(PyContainer* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = Py_None;
+  if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) {
+    return nullptr;
+  }
+
+  const void* item;
+  if (!_GetItemByKey(self, key, &item)) {
+    return nullptr;
+  }
+  if (item == nullptr) {
+    Py_INCREF(default_value);
+    return default_value;
+  }
+  return self->container_def->new_object_from_item_fn(item);
+}
+
+static PyObject* Keys(PyContainer* self, PyObject* args) {
+  Py_ssize_t count = Length(self);
+  ScopedPyObjectPtr list(PyList_New(count));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  for (Py_ssize_t index = 0; index < count; ++index) {
+    PyObject* key = _NewKey_ByIndex(self, index);
+    if (key == nullptr) {
+      return nullptr;
+    }
+    PyList_SET_ITEM(list.get(), index, key);
+  }
+  return list.release();
+}
+
+static PyObject* Values(PyContainer* self, PyObject* args) {
+  Py_ssize_t count = Length(self);
+  ScopedPyObjectPtr list(PyList_New(count));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  for (Py_ssize_t index = 0; index < count; ++index) {
+    PyObject* value = _NewObj_ByIndex(self, index);
+    if (value == nullptr) {
+      return nullptr;
+    }
+    PyList_SET_ITEM(list.get(), index, value);
+  }
+  return list.release();
+}
+
+static PyObject* Items(PyContainer* self, PyObject* args) {
+  Py_ssize_t count = Length(self);
+  ScopedPyObjectPtr list(PyList_New(count));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  for (Py_ssize_t index = 0; index < count; ++index) {
+    ScopedPyObjectPtr obj(PyTuple_New(2));
+    if (obj == nullptr) {
+      return nullptr;
+    }
+    PyObject* key = _NewKey_ByIndex(self, index);
+    if (key == nullptr) {
+      return nullptr;
+    }
+    PyTuple_SET_ITEM(obj.get(), 0, key);
+    PyObject* value = _NewObj_ByIndex(self, index);
+    if (value == nullptr) {
+      return nullptr;
+    }
+    PyTuple_SET_ITEM(obj.get(), 1, value);
+    PyList_SET_ITEM(list.get(), index, obj.release());
+  }
+  return list.release();
+}
+
+static PyObject* NewContainerIterator(PyContainer* mapping,
+                                      PyContainerIterator::IterKind kind);
+
+static PyObject* Iter(PyContainer* self) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
+}
+static PyObject* IterKeys(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
+}
+static PyObject* IterValues(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERVALUE);
+}
+static PyObject* IterItems(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERITEM);
+}
+
+static PyMethodDef MappingMethods[] = {
+    {"get", (PyCFunction)Get, METH_VARARGS},
+    {"keys", (PyCFunction)Keys, METH_NOARGS},
+    {"values", (PyCFunction)Values, METH_NOARGS},
+    {"items", (PyCFunction)Items, METH_NOARGS},
+    {"iterkeys", (PyCFunction)IterKeys, METH_NOARGS},
+    {"itervalues", (PyCFunction)IterValues, METH_NOARGS},
+    {"iteritems", (PyCFunction)IterItems, METH_NOARGS},
+    {nullptr},
+};
+
+PyTypeObject DescriptorMapping_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) "DescriptorMapping",  // tp_name
+    sizeof(PyContainer),                                         // tp_basicsize
+    0,                                                           // tp_itemsize
+    nullptr,                                                     // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                   // tp_getattr
+    nullptr,                   // tp_setattr
+    nullptr,                   // tp_compare
+    (reprfunc)ContainerRepr,   // tp_repr
+    nullptr,                   // tp_as_number
+    &MappingSequenceMethods,   // tp_as_sequence
+    &MappingMappingMethods,    // tp_as_mapping
+    nullptr,                   // tp_hash
+    nullptr,                   // tp_call
+    nullptr,                   // tp_str
+    nullptr,                   // tp_getattro
+    nullptr,                   // tp_setattro
+    nullptr,                   // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,        // tp_flags
+    nullptr,                   // tp_doc
+    nullptr,                   // tp_traverse
+    nullptr,                   // tp_clear
+    (richcmpfunc)RichCompare,  // tp_richcompare
+    0,                         // tp_weaklistoffset
+    (getiterfunc)Iter,         // tp_iter
+    nullptr,                   // tp_iternext
+    MappingMethods,            // tp_methods
+    nullptr,                   // tp_members
+    nullptr,                   // tp_getset
+    nullptr,                   // tp_base
+    nullptr,                   // tp_dict
+    nullptr,                   // tp_descr_get
+    nullptr,                   // tp_descr_set
+    0,                         // tp_dictoffset
+    nullptr,                   // tp_init
+    nullptr,                   // tp_alloc
+    nullptr,                   // tp_new
+    nullptr,                   // tp_free
+};
+
+// The DescriptorSequence type.
+
+static PyObject* GetItem(PyContainer* self, Py_ssize_t index) {
+  if (index < 0) {
+    index += Length(self);
+  }
+  if (index < 0 || index >= Length(self)) {
+    PyErr_SetString(PyExc_IndexError, "index out of range");
+    return nullptr;
+  }
+  return _NewObj_ByIndex(self, index);
+}
+
+static PyObject *
+SeqSubscript(PyContainer* self, PyObject* item) {
+  if (PyIndex_Check(item)) {
+      Py_ssize_t index;
+      index = PyNumber_AsSsize_t(item, PyExc_IndexError);
+      if (index == -1 && PyErr_Occurred()) return nullptr;
+      return GetItem(self, index);
+  }
+  // Materialize the list and delegate the operation to it.
+  ScopedPyObjectPtr list(PyObject_CallFunctionObjArgs(
+      reinterpret_cast<PyObject*>(&PyList_Type), self, nullptr));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  return Py_TYPE(list.get())->tp_as_mapping->mp_subscript(list.get(), item);
+}
+
+// Returns the position of the item in the sequence, of -1 if not found.
+// This function never fails.
+int Find(PyContainer* self, PyObject* item) {
+  // The item can only be in one position: item.index.
+  // Check that self[item.index] == item, it's faster than a linear search.
+  //
+  // This assumes that sequences are only defined by syntax of the .proto file:
+  // a specific item belongs to only one sequence, depending on its position in
+  // the .proto file definition.
+  const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item);
+  if (descriptor_ptr == nullptr) {
+    PyErr_Clear();
+    // Not a descriptor, it cannot be in the list.
+    return -1;
+  }
+  if (self->container_def->get_item_index_fn) {
+    int index = self->container_def->get_item_index_fn(descriptor_ptr);
+    if (index < 0 || index >= Length(self)) {
+      // This index is not from this collection.
+      return -1;
+    }
+    if (self->container_def->get_by_index_fn(self, index) != descriptor_ptr) {
+      // The descriptor at this index is not the same.
+      return -1;
+    }
+    // self[item.index] == item, so return the index.
+    return index;
+  } else {
+    // Fall back to linear search.
+    int length = Length(self);
+    for (int index=0; index < length; index++) {
+      if (self->container_def->get_by_index_fn(self, index) == descriptor_ptr) {
+        return index;
+      }
+    }
+    // Not found
+    return -1;
+  }
+}
+
+// Implements list.index(): the position of the item is in the sequence.
+static PyObject* Index(PyContainer* self, PyObject* item) {
+  int position = Find(self, item);
+  if (position < 0) {
+    // Not found
+    PyErr_SetNone(PyExc_ValueError);
+    return nullptr;
+  } else {
+    return PyLong_FromLong(position);
+  }
+}
+// Implements "list.__contains__()": is the object in the sequence.
+static int SeqContains(PyContainer* self, PyObject* item) {
+  int position = Find(self, item);
+  if (position < 0) {
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
+// Implements list.count(): number of occurrences of the item in the sequence.
+// An item can only appear once in a sequence. If it exists, return 1.
+static PyObject* Count(PyContainer* self, PyObject* item) {
+  int position = Find(self, item);
+  if (position < 0) {
+    return PyLong_FromLong(0);
+  } else {
+    return PyLong_FromLong(1);
+  }
+}
+
+static PyObject* Append(PyContainer* self, PyObject* args) {
+  if (_CalledFromGeneratedFile(0)) {
+    Py_RETURN_NONE;
+  }
+  PyErr_Format(PyExc_TypeError,
+               "'%.200s' object is not a mutable sequence",
+               Py_TYPE(self)->tp_name);
+  return nullptr;
+}
+
+static PyObject* Reversed(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self,
+                              PyContainerIterator::KIND_ITERVALUE_REVERSED);
+}
+
+static PyMethodDef SeqMethods[] = {
+    {"index", (PyCFunction)Index, METH_O},
+    {"count", (PyCFunction)Count, METH_O},
+    {"append", (PyCFunction)Append, METH_O},
+    {"__reversed__", (PyCFunction)Reversed, METH_NOARGS},
+    {nullptr},
+};
+
+static PySequenceMethods SeqSequenceMethods = {
+    (lenfunc)Length,          // sq_length
+    nullptr,                  // sq_concat
+    nullptr,                  // sq_repeat
+    (ssizeargfunc)GetItem,    // sq_item
+    nullptr,                  // sq_slice
+    nullptr,                  // sq_ass_item
+    nullptr,                  // sq_ass_slice
+    (objobjproc)SeqContains,  // sq_contains
+};
+
+static PyMappingMethods SeqMappingMethods = {
+    (lenfunc)Length,           // mp_length
+    (binaryfunc)SeqSubscript,  // mp_subscript
+    nullptr,                   // mp_ass_subscript
+};
+
+PyTypeObject DescriptorSequence_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) "DescriptorSequence",  // tp_name
+    sizeof(PyContainer),  // tp_basicsize
+    0,                    // tp_itemsize
+    nullptr,              // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                   // tp_getattr
+    nullptr,                   // tp_setattr
+    nullptr,                   // tp_compare
+    (reprfunc)ContainerRepr,   // tp_repr
+    nullptr,                   // tp_as_number
+    &SeqSequenceMethods,       // tp_as_sequence
+    &SeqMappingMethods,        // tp_as_mapping
+    nullptr,                   // tp_hash
+    nullptr,                   // tp_call
+    nullptr,                   // tp_str
+    nullptr,                   // tp_getattro
+    nullptr,                   // tp_setattro
+    nullptr,                   // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,        // tp_flags
+    nullptr,                   // tp_doc
+    nullptr,                   // tp_traverse
+    nullptr,                   // tp_clear
+    (richcmpfunc)RichCompare,  // tp_richcompare
+    0,                         // tp_weaklistoffset
+    nullptr,                   // tp_iter
+    nullptr,                   // tp_iternext
+    SeqMethods,                // tp_methods
+    nullptr,                   // tp_members
+    nullptr,                   // tp_getset
+    nullptr,                   // tp_base
+    nullptr,                   // tp_dict
+    nullptr,                   // tp_descr_get
+    nullptr,                   // tp_descr_set
+    0,                         // tp_dictoffset
+    nullptr,                   // tp_init
+    nullptr,                   // tp_alloc
+    nullptr,                   // tp_new
+    nullptr,                   // tp_free
+};
+
+static PyObject* NewMappingByName(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_BYNAME;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewMappingByCamelcaseName(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  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 == nullptr ||
+      container_def->get_item_number_fn == nullptr) {
+    PyErr_SetNone(PyExc_NotImplementedError);
+    return nullptr;
+  }
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_BYNUMBER;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewSequence(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_SEQUENCE;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+// Implement iterators over PyContainers.
+
+static void Iterator_Dealloc(PyContainerIterator* self) {
+  Py_CLEAR(self->container);
+  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+static PyObject* Iterator_Next(PyContainerIterator* self) {
+  int count = self->container->container_def->count_fn(self->container);
+  if (self->index >= count) {
+    // Return null with no exception to indicate the end.
+    return nullptr;
+  }
+  int index = self->index;
+  self->index += 1;
+  switch (self->kind) {
+    case PyContainerIterator::KIND_ITERKEY:
+      return _NewKey_ByIndex(self->container, index);
+    case PyContainerIterator::KIND_ITERVALUE:
+      return _NewObj_ByIndex(self->container, index);
+    case PyContainerIterator::KIND_ITERVALUE_REVERSED:
+      return _NewObj_ByIndex(self->container, count - index - 1);
+    case PyContainerIterator::KIND_ITERITEM: {
+      PyObject* obj = PyTuple_New(2);
+      if (obj == nullptr) {
+        return nullptr;
+      }
+      PyObject* key = _NewKey_ByIndex(self->container, index);
+      if (key == nullptr) {
+        Py_DECREF(obj);
+        return nullptr;
+      }
+      PyTuple_SET_ITEM(obj, 0, key);
+      PyObject* value = _NewObj_ByIndex(self->container, index);
+      if (value == nullptr) {
+        Py_DECREF(obj);
+        return nullptr;
+      }
+      PyTuple_SET_ITEM(obj, 1, value);
+      return obj;
+    }
+    default:
+      PyErr_SetNone(PyExc_NotImplementedError);
+      return nullptr;
+  }
+}
+
+static PyTypeObject ContainerIterator_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type,
+                          0) "DescriptorContainerIterator",  // tp_name
+    sizeof(PyContainerIterator),                             // tp_basicsize
+    0,                                                       // tp_itemsize
+    (destructor)Iterator_Dealloc,                            // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                      // tp_getattr
+    nullptr,                      // tp_setattr
+    nullptr,                      // tp_compare
+    nullptr,                      // tp_repr
+    nullptr,                      // tp_as_number
+    nullptr,                      // tp_as_sequence
+    nullptr,                      // tp_as_mapping
+    nullptr,                      // tp_hash
+    nullptr,                      // tp_call
+    nullptr,                      // tp_str
+    nullptr,                      // tp_getattro
+    nullptr,                      // tp_setattro
+    nullptr,                      // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,           // tp_flags
+    nullptr,                      // tp_doc
+    nullptr,                      // tp_traverse
+    nullptr,                      // tp_clear
+    nullptr,                      // tp_richcompare
+    0,                            // tp_weaklistoffset
+    PyObject_SelfIter,            // tp_iter
+    (iternextfunc)Iterator_Next,  // tp_iternext
+    nullptr,                      // tp_methods
+    nullptr,                      // tp_members
+    nullptr,                      // tp_getset
+    nullptr,                      // tp_base
+    nullptr,                      // tp_dict
+    nullptr,                      // tp_descr_get
+    nullptr,                      // tp_descr_set
+    0,                            // tp_dictoffset
+    nullptr,                      // tp_init
+    nullptr,                      // tp_alloc
+    nullptr,                      // tp_new
+    nullptr,                      // tp_free
+};
+
+static PyObject* NewContainerIterator(PyContainer* container,
+                                      PyContainerIterator::IterKind kind) {
+  PyContainerIterator* self = PyObject_New(PyContainerIterator,
+                                           &ContainerIterator_Type);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  Py_INCREF(container);
+  self->container = container;
+  self->kind = kind;
+  self->index = 0;
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+}  // namespace descriptor
+
+// Now define the real collections!
+
+namespace message_descriptor {
+
+typedef const Descriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace fields {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->field_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindFieldByName(name);
+}
+
+static const void* GetByCamelcaseName(PyContainer* self,
+                                      ConstStringParam name) {
+  return GetDescriptor(self)->FindFieldByCamelcaseName(name);
+}
+
+static const void* GetByNumber(PyContainer* self, int number) {
+  return GetDescriptor(self)->FindFieldByNumber(number);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->field(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static const std::string& GetItemCamelcaseName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->camelcase_name();
+}
+
+static int GetItemNumber(const void* item) {
+  return static_cast<ItemDescriptor>(item)->number();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "MessageFields",      Count,         GetByIndex,        GetByName,
+    GetByCamelcaseName,   GetByNumber,   NewObjectFromItem, GetItemName,
+    GetItemCamelcaseName, GetItemNumber, GetItemIndex,
+};
+
+}  // namespace fields
+
+PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef,
+                                               descriptor);
+}
+
+PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageFieldsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&fields::ContainerDef, descriptor);
+}
+
+namespace nested_types {
+
+typedef const Descriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->nested_type_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindNestedTypeByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->nested_type(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyMessageDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "MessageNestedTypes",
+    Count,
+    GetByIndex,
+    GetByName,
+    nullptr,
+    nullptr,
+    NewObjectFromItem,
+    GetItemName,
+    nullptr,
+    nullptr,
+    GetItemIndex,
+};
+
+}  // namespace nested_types
+
+PyObject* NewMessageNestedTypesSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&nested_types::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageNestedTypesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&nested_types::ContainerDef, descriptor);
+}
+
+namespace enums {
+
+typedef const EnumDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->enum_type_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindEnumTypeByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->enum_type(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "MessageNestedEnums",
+    Count,
+    GetByIndex,
+    GetByName,
+    nullptr,
+    nullptr,
+    NewObjectFromItem,
+    GetItemName,
+    nullptr,
+    nullptr,
+    GetItemIndex,
+};
+
+}  // namespace enums
+
+PyObject* NewMessageEnumsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageEnumsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&enums::ContainerDef, descriptor);
+}
+
+namespace enumvalues {
+
+// This is the "enum_values_by_name" mapping, which collects values from all
+// enum types in a message.
+//
+// Note that the behavior of the C++ descriptor is different: it will search and
+// return the first value that matches the name, whereas the Python
+// implementation retrieves the last one.
+
+typedef const EnumValueDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  int count = 0;
+  for (int i = 0; i < GetDescriptor(self)->enum_type_count(); ++i) {
+    count += GetDescriptor(self)->enum_type(i)->value_count();
+  }
+  return count;
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindEnumValueByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  // This is not optimal, but the number of enums *types* in a given message
+  // is small.  This function is only used when iterating over the mapping.
+  const EnumDescriptor* enum_type = nullptr;
+  int enum_type_count = GetDescriptor(self)->enum_type_count();
+  for (int i = 0; i < enum_type_count; ++i) {
+    enum_type = GetDescriptor(self)->enum_type(i);
+    int enum_value_count = enum_type->value_count();
+    if (index < enum_value_count) {
+      // Found it!
+      break;
+    }
+    index -= enum_value_count;
+  }
+  // The next statement cannot overflow, because this function is only called by
+  // internal iterators which ensure that 0 <= index < Count().
+  return enum_type->value(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumValueDescriptor_FromDescriptor(
+      static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "MessageEnumValues", Count,       GetByIndex, GetByName, nullptr, nullptr,
+    NewObjectFromItem,   GetItemName, nullptr,    nullptr,   nullptr,
+};
+
+}  // namespace enumvalues
+
+PyObject* NewMessageEnumValuesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
+}
+
+namespace extensions {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->extension_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindExtensionByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->extension(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "MessageExtensions",
+    Count,
+    GetByIndex,
+    GetByName,
+    nullptr,
+    nullptr,
+    NewObjectFromItem,
+    GetItemName,
+    nullptr,
+    nullptr,
+    GetItemIndex,
+};
+
+}  // namespace extensions
+
+PyObject* NewMessageExtensionsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageExtensionsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&extensions::ContainerDef, descriptor);
+}
+
+namespace oneofs {
+
+typedef const OneofDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->oneof_decl_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindOneofByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->oneof_decl(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyOneofDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "MessageOneofs", Count,   GetByIndex,        GetByName,
+    nullptr,         nullptr, NewObjectFromItem, GetItemName,
+    nullptr,         nullptr, GetItemIndex,
+};
+
+}  // namespace oneofs
+
+PyObject* NewMessageOneofsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&oneofs::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageOneofsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&oneofs::ContainerDef, descriptor);
+}
+
+}  // namespace message_descriptor
+
+namespace enum_descriptor {
+
+typedef const EnumDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace enumvalues {
+
+typedef const EnumValueDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->value_count();
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->value(index);
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindValueByName(name);
+}
+
+static const void* GetByNumber(PyContainer* self, int number) {
+  return GetDescriptor(self)->FindValueByNumber(number);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumValueDescriptor_FromDescriptor(
+      static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemNumber(const void* item) {
+  return static_cast<ItemDescriptor>(item)->number();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "EnumValues", Count,         GetByIndex,        GetByName,
+    nullptr,      GetByNumber,   NewObjectFromItem, GetItemName,
+    nullptr,      GetItemNumber, GetItemIndex,
+};
+
+}  // namespace enumvalues
+
+PyObject* NewEnumValuesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
+}
+
+PyObject* NewEnumValuesByNumber(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByNumber(&enumvalues::ContainerDef, descriptor);
+}
+
+PyObject* NewEnumValuesSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&enumvalues::ContainerDef, descriptor);
+}
+
+}  // namespace enum_descriptor
+
+namespace oneof_descriptor {
+
+typedef const OneofDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace fields {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->field_count();
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->field(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index_in_oneof();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "OneofFields",     Count,   GetByIndex, nullptr, nullptr,      nullptr,
+    NewObjectFromItem, nullptr, nullptr,    nullptr, GetItemIndex,
+};
+
+}  // namespace fields
+
+PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&fields::ContainerDef, descriptor);
+}
+
+}  // namespace oneof_descriptor
+
+namespace service_descriptor {
+
+typedef const ServiceDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace methods {
+
+typedef const MethodDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->method_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindMethodByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->method(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyMethodDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "ServiceMethods", Count,   GetByIndex,        GetByName,
+    nullptr,          nullptr, NewObjectFromItem, GetItemName,
+    nullptr,          nullptr, GetItemIndex,
+};
+
+}  // namespace methods
+
+PyObject* NewServiceMethodsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&methods::ContainerDef, descriptor);
+}
+
+PyObject* NewServiceMethodsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&methods::ContainerDef, descriptor);
+}
+
+}  // namespace service_descriptor
+
+namespace file_descriptor {
+
+typedef const FileDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace messages {
+
+typedef const Descriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->message_type_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindMessageTypeByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->message_type(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyMessageDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "FileMessages", Count,   GetByIndex,        GetByName,
+    nullptr,        nullptr, NewObjectFromItem, GetItemName,
+    nullptr,        nullptr, GetItemIndex,
+};
+
+}  // namespace messages
+
+PyObject* NewFileMessageTypesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&messages::ContainerDef, descriptor);
+}
+
+namespace enums {
+
+typedef const EnumDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->enum_type_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindEnumTypeByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->enum_type(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "FileEnums", Count,   GetByIndex,        GetByName,
+    nullptr,     nullptr, NewObjectFromItem, GetItemName,
+    nullptr,     nullptr, GetItemIndex,
+};
+
+}  // namespace enums
+
+PyObject* NewFileEnumTypesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
+}
+
+namespace extensions {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->extension_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindExtensionByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->extension(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "FileExtensions", Count,   GetByIndex,        GetByName,
+    nullptr,          nullptr, NewObjectFromItem, GetItemName,
+    nullptr,          nullptr, GetItemIndex,
+};
+
+}  // namespace extensions
+
+PyObject* NewFileExtensionsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
+}
+
+namespace services {
+
+typedef const ServiceDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->service_count();
+}
+
+static const void* GetByName(PyContainer* self, ConstStringParam name) {
+  return GetDescriptor(self)->FindServiceByName(name);
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->service(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyServiceDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static const std::string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
+}
+
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "FileServices", Count,   GetByIndex,        GetByName,
+    nullptr,        nullptr, NewObjectFromItem, GetItemName,
+    nullptr,        nullptr, GetItemIndex,
+};
+
+}  // namespace services
+
+PyObject* NewFileServicesByName(const FileDescriptor* descriptor) {
+  return descriptor::NewMappingByName(&services::ContainerDef, descriptor);
+}
+
+namespace dependencies {
+
+typedef const FileDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->dependency_count();
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->dependency(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFileDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "FileDependencies", Count,   GetByIndex, nullptr, nullptr, nullptr,
+    NewObjectFromItem,  nullptr, nullptr,    nullptr, nullptr,
+};
+
+}  // namespace dependencies
+
+PyObject* NewFileDependencies(const FileDescriptor* descriptor) {
+  return descriptor::NewSequence(&dependencies::ContainerDef, descriptor);
+}
+
+namespace public_dependencies {
+
+typedef const FileDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->public_dependency_count();
+}
+
+static const void* GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->public_dependency(index);
+}
+
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFileDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
+}
+
+static DescriptorContainerDef ContainerDef = {
+    "FilePublicDependencies", Count,   GetByIndex, nullptr, nullptr, nullptr,
+    NewObjectFromItem,        nullptr, nullptr,    nullptr, nullptr,
+};
+
+}  // namespace public_dependencies
+
+PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor) {
+  return descriptor::NewSequence(&public_dependencies::ContainerDef,
+                                 descriptor);
+}
+
+}  // namespace file_descriptor
+
+
+// Register all implementations
+
+bool InitDescriptorMappingTypes() {
+  if (PyType_Ready(&descriptor::DescriptorMapping_Type) < 0)
+    return false;
+  if (PyType_Ready(&descriptor::DescriptorSequence_Type) < 0)
+    return false;
+  if (PyType_Ready(&descriptor::ContainerIterator_Type) < 0)
+    return false;
+  return true;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
new file mode 100644
index 0000000..cf2cf4a
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -0,0 +1,110 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#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.
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class FileDescriptor;
+class EnumDescriptor;
+class OneofDescriptor;
+class ServiceDescriptor;
+
+namespace python {
+
+// Initialize the various types and objects.
+bool InitDescriptorMappingTypes();
+
+// Each function below returns a Mapping, or a Sequence of descriptors.
+// They all return a new reference.
+
+namespace message_descriptor {
+PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
+PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);
+
+PyObject* NewMessageNestedTypesSeq(const Descriptor* descriptor);
+PyObject* NewMessageNestedTypesByName(const Descriptor* descriptor);
+
+PyObject* NewMessageEnumsByName(const Descriptor* descriptor);
+PyObject* NewMessageEnumsSeq(const Descriptor* descriptor);
+PyObject* NewMessageEnumValuesByName(const Descriptor* descriptor);
+
+PyObject* NewMessageExtensionsByName(const Descriptor* descriptor);
+PyObject* NewMessageExtensionsSeq(const Descriptor* descriptor);
+
+PyObject* NewMessageOneofsByName(const Descriptor* descriptor);
+PyObject* NewMessageOneofsSeq(const Descriptor* descriptor);
+}  // namespace message_descriptor
+
+namespace enum_descriptor {
+PyObject* NewEnumValuesByName(const EnumDescriptor* descriptor);
+PyObject* NewEnumValuesByNumber(const EnumDescriptor* descriptor);
+PyObject* NewEnumValuesSeq(const EnumDescriptor* descriptor);
+}  // namespace enum_descriptor
+
+namespace oneof_descriptor {
+PyObject* NewOneofFieldsSeq(const OneofDescriptor* descriptor);
+}  // namespace oneof_descriptor
+
+namespace file_descriptor {
+PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileServicesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileDependencies(const FileDescriptor* descriptor);
+PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor);
+}  // namespace file_descriptor
+
+namespace service_descriptor {
+PyObject* NewServiceMethodsSeq(const ServiceDescriptor* descriptor);
+PyObject* NewServiceMethodsByName(const ServiceDescriptor* descriptor);
+}  // namespace service_descriptor
+
+
+}  // 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..f87f23d
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.cc
@@ -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.
+
+// 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 <cstdint>
+
+#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 == nullptr) {
+    if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+      // Expected error: item was simply not found.
+      PyErr_Clear();
+    } else {
+      GOOGLE_LOG(ERROR) << "DescriptorDatabase method raised an error";
+      PyErr_Print();
+    }
+    return false;
+  }
+  if (py_descriptor == Py_None) {
+    return false;
+  }
+  const Descriptor* filedescriptor_descriptor =
+      FileDescriptorProto::default_instance().GetDescriptor();
+  CMessage* message = reinterpret_cast<CMessage*>(py_descriptor);
+  if (PyObject_TypeCheck(py_descriptor, CMessage_Type) &&
+      message->message->GetDescriptor() == filedescriptor_descriptor) {
+    // Fast path: Just use the pointer.
+    FileDescriptorProto* file_proto =
+        static_cast<FileDescriptorProto*>(message->message);
+    *output = *file_proto;
+    return true;
+  } else {
+    // Slow path: serialize the message. This allows to use databases which
+    // use a different implementation of FileDescriptorProto.
+    ScopedPyObjectPtr serialized_pb(
+        PyObject_CallMethod(py_descriptor, "SerializeToString", nullptr));
+    if (serialized_pb == nullptr) {
+      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 std::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 std::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 std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_method(
+      PyObject_GetAttrString(py_database_, "FindFileContainingExtension"));
+  if (py_method == nullptr) {
+    // 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);
+}
+
+// Finds the tag numbers used by all known extensions of
+// containing_type, and appends them to output in an undefined
+// order.
+// Python DescriptorDatabases are not required to implement this method.
+bool PyDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& containing_type, std::vector<int>* output) {
+  ScopedPyObjectPtr py_method(
+      PyObject_GetAttrString(py_database_, "FindAllExtensionNumbers"));
+  if (py_method == nullptr) {
+    // This method is not implemented, returns without error.
+    PyErr_Clear();
+    return false;
+  }
+  ScopedPyObjectPtr py_list(
+      PyObject_CallFunction(py_method.get(), "s#", containing_type.c_str(),
+                            containing_type.size()));
+  if (py_list == nullptr) {
+    PyErr_Print();
+    return false;
+  }
+  Py_ssize_t size = PyList_Size(py_list.get());
+  int64_t item_value;
+  for (Py_ssize_t i = 0 ; i < size; ++i) {
+    ScopedPyObjectPtr item(PySequence_GetItem(py_list.get(), i));
+    item_value = PyLong_AsLong(item.get());
+    if (item_value < 0) {
+      GOOGLE_LOG(ERROR)
+          << "FindAllExtensionNumbers method did not return "
+          << "valid extension numbers.";
+      PyErr_Print();
+      return false;
+    }
+    output->push_back(item_value);
+  }
+  return true;
+}
+
+}  // 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..5621a22
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
+
+#define PY_SSIZE_T_CLEAN
+#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() override;
+
+  // Implement the abstract interface. All these functions fill the output
+  // with a copy of FileDescriptorProto.
+
+  // Find a file by file name.
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+
+  // Find the file that declares the given fully-qualified symbol name.
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+
+  // 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 std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+
+  // Finds the tag numbers used by all known extensions of
+  // containing_type, and appends them to output in an undefined
+  // order.
+  // Python objects are not required to implement this method.
+  bool FindAllExtensionNumbers(const std::string& containing_type,
+                               std::vector<int>* output) override;
+
+ private:
+  // The python object that implements the database. The reference is owned.
+  PyObject* py_database_;
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
new file mode 100644
index 0000000..2f39281
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -0,0 +1,817 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Implements the DescriptorPool, which collects all descriptors.
+
+#include <unordered_map>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/descriptor.pb.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/message_factory.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/hash.h>
+
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// A map to cache Python Pools per C++ pointer.
+// Pointers are not owned here, and belong to the PyDescriptorPool.
+static std::unordered_map<const DescriptorPool*, PyDescriptorPool*>*
+    descriptor_pool_map;
+
+namespace cdescriptor_pool {
+
+// Collects errors that occur during proto file building to allow them to be
+// propagated in the python exception instead of only living in ERROR logs.
+class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  BuildFileErrorCollector() : error_message(""), had_errors_(false) {}
+
+  void AddError(const std::string& filename, const std::string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const std::string& message) override {
+    // Replicates the logging behavior that happens in the C++ implementation
+    // when an error collector is not passed in.
+    if (!had_errors_) {
+      error_message +=
+          ("Invalid proto descriptor for file \"" + filename + "\":\n");
+      had_errors_ = true;
+    }
+    // As this only happens on failure and will result in the program not
+    // running at all, no effort is made to optimize this string manipulation.
+    error_message += ("  " + element_name + ": " + message + "\n");
+  }
+
+  void Clear() {
+    had_errors_ = false;
+    error_message = "";
+  }
+
+  std::string error_message;
+
+ private:
+  bool had_errors_;
+};
+
+// Create a Python DescriptorPool object, but does not fill the "pool"
+// attribute.
+static PyDescriptorPool* _CreateDescriptorPool() {
+  PyDescriptorPool* cpool = PyObject_GC_New(
+      PyDescriptorPool, &PyDescriptorPool_Type);
+  if (cpool == nullptr) {
+    return nullptr;
+  }
+
+  cpool->error_collector = nullptr;
+  cpool->underlay = nullptr;
+  cpool->database = nullptr;
+  cpool->is_owned = false;
+  cpool->is_mutable = false;
+
+  cpool->descriptor_options = new std::unordered_map<const void*, PyObject*>();
+
+  cpool->py_message_factory = message_factory::NewMessageFactory(
+      &PyMessageFactory_Type, cpool);
+  if (cpool->py_message_factory == nullptr) {
+    Py_DECREF(cpool);
+    return nullptr;
+  }
+
+  PyObject_GC_Track(cpool);
+
+  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 == nullptr) {
+    return nullptr;
+  }
+  cpool->pool = new DescriptorPool(underlay);
+  cpool->is_owned = true;
+  cpool->is_mutable = true;
+  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 nullptr;
+  }
+
+  return cpool;
+}
+
+static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
+    DescriptorDatabase* database) {
+  PyDescriptorPool* cpool = _CreateDescriptorPool();
+  if (cpool == nullptr) {
+    return nullptr;
+  }
+  if (database != nullptr) {
+    cpool->error_collector = new BuildFileErrorCollector();
+    cpool->pool = new DescriptorPool(database, cpool->error_collector);
+    cpool->is_mutable = false;
+    cpool->database = database;
+  } else {
+    cpool->pool = new DescriptorPool();
+    cpool->is_mutable = true;
+  }
+  cpool->is_owned = true;
+
+  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 nullptr;
+  }
+
+  return cpool;
+}
+
+// The public DescriptorPool constructor.
+static PyObject* New(PyTypeObject* type,
+                     PyObject* args, PyObject* kwargs) {
+  static const char* kwlist[] = {"descriptor_db", nullptr};
+  PyObject* py_database = nullptr;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
+                                   const_cast<char**>(kwlist), &py_database)) {
+    return nullptr;
+  }
+  DescriptorDatabase* database = nullptr;
+  if (py_database && py_database != Py_None) {
+    database = new PyDescriptorDatabase(py_database);
+  }
+  return reinterpret_cast<PyObject*>(
+      PyDescriptorPool_NewWithDatabase(database));
+}
+
+static void Dealloc(PyObject* pself) {
+  PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
+  descriptor_pool_map->erase(self->pool);
+  Py_CLEAR(self->py_message_factory);
+  for (std::unordered_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->database;
+  if (self->is_owned) {
+    delete self->pool;
+  }
+  delete self->error_collector;
+  Py_TYPE(self)->tp_free(pself);
+}
+
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
+  Py_VISIT(self->py_message_factory);
+  return 0;
+}
+
+static int GcClear(PyObject* pself) {
+  PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
+  Py_CLEAR(self->py_message_factory);
+  return 0;
+}
+
+PyObject* SetErrorFromCollector(DescriptorPool::ErrorCollector* self,
+                                const char* name, const char* error_type) {
+  BuildFileErrorCollector* error_collector =
+      reinterpret_cast<BuildFileErrorCollector*>(self);
+  if (error_collector && !error_collector->error_message.empty()) {
+    PyErr_Format(PyExc_KeyError, "Couldn't build file for %s %.200s\n%s",
+                 error_type, name, error_collector->error_message.c_str());
+    error_collector->Clear();
+    return nullptr;
+  }
+  PyErr_Format(PyExc_KeyError, "Couldn't find %s %.200s", error_type, name);
+  return nullptr;
+}
+
+static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const Descriptor* message_descriptor =
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
+          StringParam(name, name_size));
+
+  if (message_descriptor == nullptr) {
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "message");
+  }
+
+
+  return PyMessageDescriptor_FromDescriptor(message_descriptor);
+}
+
+
+
+
+static PyObject* FindFileByName(PyObject* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  PyDescriptorPool* py_pool = reinterpret_cast<PyDescriptorPool*>(self);
+  const FileDescriptor* file_descriptor =
+      py_pool->pool->FindFileByName(StringParam(name, name_size));
+
+  if (file_descriptor == nullptr) {
+    return SetErrorFromCollector(py_pool->error_collector, name, "file");
+  }
+  return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
+PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const FieldDescriptor* field_descriptor =
+      self->pool->FindFieldByName(StringParam(name, name_size));
+  if (field_descriptor == nullptr) {
+    return SetErrorFromCollector(self->error_collector, name, "field");
+  }
+
+
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
+}
+
+static PyObject* FindFieldByNameMethod(PyObject* self, PyObject* arg) {
+  return FindFieldByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
+}
+
+PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const FieldDescriptor* field_descriptor =
+      self->pool->FindExtensionByName(StringParam(name, name_size));
+  if (field_descriptor == nullptr) {
+    return SetErrorFromCollector(self->error_collector, name,
+                                 "extension field");
+  }
+
+
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
+}
+
+static PyObject* FindExtensionByNameMethod(PyObject* self, PyObject* arg) {
+  return FindExtensionByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
+}
+
+PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const EnumDescriptor* enum_descriptor =
+      self->pool->FindEnumTypeByName(StringParam(name, name_size));
+  if (enum_descriptor == nullptr) {
+    return SetErrorFromCollector(self->error_collector, name, "enum");
+  }
+
+
+  return PyEnumDescriptor_FromDescriptor(enum_descriptor);
+}
+
+static PyObject* FindEnumTypeByNameMethod(PyObject* self, PyObject* arg) {
+  return FindEnumTypeByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
+}
+
+PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const OneofDescriptor* oneof_descriptor =
+      self->pool->FindOneofByName(StringParam(name, name_size));
+  if (oneof_descriptor == nullptr) {
+    return SetErrorFromCollector(self->error_collector, name, "oneof");
+  }
+
+
+  return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
+}
+
+static PyObject* FindOneofByNameMethod(PyObject* self, PyObject* arg) {
+  return FindOneofByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
+}
+
+static PyObject* FindServiceByName(PyObject* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const ServiceDescriptor* service_descriptor =
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
+          StringParam(name, name_size));
+  if (service_descriptor == nullptr) {
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "service");
+  }
+
+
+  return PyServiceDescriptor_FromDescriptor(service_descriptor);
+}
+
+static PyObject* FindMethodByName(PyObject* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const MethodDescriptor* method_descriptor =
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMethodByName(
+          StringParam(name, name_size));
+  if (method_descriptor == nullptr) {
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "method");
+  }
+
+
+  return PyMethodDescriptor_FromDescriptor(method_descriptor);
+}
+
+static PyObject* FindFileContainingSymbol(PyObject* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  const FileDescriptor* file_descriptor =
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileContainingSymbol(
+          StringParam(name, name_size));
+  if (file_descriptor == nullptr) {
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "symbol");
+  }
+
+
+  return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
+static PyObject* FindExtensionByNumber(PyObject* self, PyObject* args) {
+  PyObject* message_descriptor;
+  int number;
+  if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
+    return nullptr;
+  }
+  const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(
+      message_descriptor);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+
+  const FieldDescriptor* extension_descriptor =
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByNumber(
+          descriptor, number);
+  if (extension_descriptor == nullptr) {
+    BuildFileErrorCollector* error_collector =
+        reinterpret_cast<BuildFileErrorCollector*>(
+            reinterpret_cast<PyDescriptorPool*>(self)->error_collector);
+    if (error_collector && !error_collector->error_message.empty()) {
+      PyErr_Format(PyExc_KeyError, "Couldn't build file for Extension %.d\n%s",
+                   number, error_collector->error_message.c_str());
+      error_collector->Clear();
+      return nullptr;
+    }
+    PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
+    return nullptr;
+  }
+
+
+  return PyFieldDescriptor_FromDescriptor(extension_descriptor);
+}
+
+static PyObject* FindAllExtensions(PyObject* self, PyObject* arg) {
+  const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(arg);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+
+  std::vector<const FieldDescriptor*> extensions;
+  reinterpret_cast<PyDescriptorPool*>(self)->pool->FindAllExtensions(
+      descriptor, &extensions);
+
+  ScopedPyObjectPtr result(PyList_New(extensions.size()));
+  if (result == nullptr) {
+    return nullptr;
+  }
+  for (int i = 0; i < extensions.size(); i++) {
+    PyObject* extension = PyFieldDescriptor_FromDescriptor(extensions[i]);
+    if (extension == nullptr) {
+      return nullptr;
+    }
+    PyList_SET_ITEM(result.get(), i, extension);  // Steals the reference.
+  }
+  return result.release();
+}
+
+// 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.
+
+static PyObject* AddFileDescriptor(PyObject* self, PyObject* descriptor) {
+  const FileDescriptor* file_descriptor =
+      PyFileDescriptor_AsDescriptor(descriptor);
+  if (!file_descriptor) {
+    return nullptr;
+  }
+  if (file_descriptor !=
+      reinterpret_cast<PyDescriptorPool*>(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 nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* AddDescriptor(PyObject* self, PyObject* descriptor) {
+  const Descriptor* message_descriptor =
+      PyMessageDescriptor_AsDescriptor(descriptor);
+  if (!message_descriptor) {
+    return nullptr;
+  }
+  if (message_descriptor !=
+      reinterpret_cast<PyDescriptorPool*>(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 nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* AddEnumDescriptor(PyObject* self, PyObject* descriptor) {
+  const EnumDescriptor* enum_descriptor =
+      PyEnumDescriptor_AsDescriptor(descriptor);
+  if (!enum_descriptor) {
+    return nullptr;
+  }
+  if (enum_descriptor !=
+      reinterpret_cast<PyDescriptorPool*>(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 nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* AddExtensionDescriptor(PyObject* self, PyObject* descriptor) {
+  const FieldDescriptor* extension_descriptor =
+      PyFieldDescriptor_AsDescriptor(descriptor);
+  if (!extension_descriptor) {
+    return nullptr;
+  }
+  if (extension_descriptor !=
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByName(
+          extension_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The extension descriptor %s does not belong to this pool",
+                 extension_descriptor->full_name().c_str());
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* AddServiceDescriptor(PyObject* self, PyObject* descriptor) {
+  const ServiceDescriptor* service_descriptor =
+      PyServiceDescriptor_AsDescriptor(descriptor);
+  if (!service_descriptor) {
+    return nullptr;
+  }
+  if (service_descriptor !=
+      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
+          service_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The service descriptor %s does not belong to this pool",
+                 service_descriptor->full_name().c_str());
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+// The code below loads new Descriptors from a serialized FileDescriptorProto.
+static PyObject* AddSerializedFile(PyObject* pself, PyObject* serialized_pb) {
+  PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
+  char* message_type;
+  Py_ssize_t message_len;
+
+  if (self->database != nullptr) {
+    PyErr_SetString(
+        PyExc_ValueError,
+        "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
+        "Add your file to the underlying database.");
+    return nullptr;
+  }
+  if (!self->is_mutable) {
+    PyErr_SetString(
+        PyExc_ValueError,
+        "This DescriptorPool is not mutable and cannot add new definitions.");
+    return nullptr;
+  }
+
+  if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
+    return nullptr;
+  }
+
+  FileDescriptorProto file_proto;
+  if (!file_proto.ParseFromArray(message_type, message_len)) {
+    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
+    return nullptr;
+  }
+
+  // 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 = nullptr;
+  if (self->underlay) {
+    generated_file = self->underlay->FindFileByName(file_proto.name());
+  }
+  if (generated_file != nullptr) {
+    return PyFileDescriptor_FromDescriptorWithSerializedPb(
+        generated_file, serialized_pb);
+  }
+
+  BuildFileErrorCollector error_collector;
+  const FileDescriptor* descriptor =
+      // Pool is mutable, we can remove the "const".
+      const_cast<DescriptorPool*>(self->pool)
+          ->BuildFileCollectingErrors(file_proto, &error_collector);
+  if (descriptor == nullptr) {
+    PyErr_Format(PyExc_TypeError,
+                 "Couldn't build proto file into descriptor pool!\n%s",
+                 error_collector.error_message.c_str());
+    return nullptr;
+  }
+
+
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(
+      descriptor, serialized_pb);
+}
+
+static PyObject* Add(PyObject* self, PyObject* file_descriptor_proto) {
+  ScopedPyObjectPtr serialized_pb(
+      PyObject_CallMethod(file_descriptor_proto, "SerializeToString", nullptr));
+  if (serialized_pb == nullptr) {
+    return nullptr;
+  }
+  return AddSerializedFile(self, serialized_pb.get());
+}
+
+static PyMethodDef Methods[] = {
+    {"Add", Add, METH_O,
+     "Adds the FileDescriptorProto and its types to this pool."},
+    {"AddSerializedFile", 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", AddFileDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddDescriptor", AddDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddEnumDescriptor", AddEnumDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddExtensionDescriptor", AddExtensionDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddServiceDescriptor", AddServiceDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+
+    {"FindFileByName", FindFileByName, METH_O,
+     "Searches for a file descriptor by its .proto name."},
+    {"FindMessageTypeByName", FindMessageByName, METH_O,
+     "Searches for a message descriptor by full name."},
+    {"FindFieldByName", FindFieldByNameMethod, METH_O,
+     "Searches for a field descriptor by full name."},
+    {"FindExtensionByName", FindExtensionByNameMethod, METH_O,
+     "Searches for extension descriptor by full name."},
+    {"FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
+     "Searches for enum type descriptor by full name."},
+    {"FindOneofByName", FindOneofByNameMethod, METH_O,
+     "Searches for oneof descriptor by full name."},
+    {"FindServiceByName", FindServiceByName, METH_O,
+     "Searches for service descriptor by full name."},
+    {"FindMethodByName", FindMethodByName, METH_O,
+     "Searches for method descriptor by full name."},
+
+    {"FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
+     "Gets the FileDescriptor containing the specified symbol."},
+    {"FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
+     "Gets the extension descriptor for the given number."},
+    {"FindAllExtensions", FindAllExtensions, METH_O,
+     "Gets all known extensions of the given message descriptor."},
+    {nullptr},
+};
+
+}  // 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
+    cdescriptor_pool::Dealloc,  // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                                  // tp_getattr
+    nullptr,                                  // tp_setattr
+    nullptr,                                  // tp_compare
+    nullptr,                                  // tp_repr
+    nullptr,                                  // tp_as_number
+    nullptr,                                  // tp_as_sequence
+    nullptr,                                  // tp_as_mapping
+    nullptr,                                  // tp_hash
+    nullptr,                                  // tp_call
+    nullptr,                                  // tp_str
+    nullptr,                                  // tp_getattro
+    nullptr,                                  // tp_setattro
+    nullptr,                                  // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "A Descriptor Pool",                      // tp_doc
+    cdescriptor_pool::GcTraverse,             // tp_traverse
+    cdescriptor_pool::GcClear,                // tp_clear
+    nullptr,                                  // tp_richcompare
+    0,                                        // tp_weaklistoffset
+    nullptr,                                  // tp_iter
+    nullptr,                                  // tp_iternext
+    cdescriptor_pool::Methods,                // tp_methods
+    nullptr,                                  // tp_members
+    nullptr,                                  // tp_getset
+    nullptr,                                  // tp_base
+    nullptr,                                  // tp_dict
+    nullptr,                                  // tp_descr_get
+    nullptr,                                  // tp_descr_set
+    0,                                        // tp_dictoffset
+    nullptr,                                  // tp_init
+    nullptr,                                  // tp_alloc
+    cdescriptor_pool::New,                    // tp_new
+    PyObject_GC_Del,                          // tp_free
+};
+
+// This is the DescriptorPool which contains all the definitions from the
+// generated _pb2.py modules.
+static PyDescriptorPool* python_generated_pool = nullptr;
+
+bool InitDescriptorPool() {
+  if (PyType_Ready(&PyDescriptorPool_Type) < 0)
+    return false;
+
+  // The Pool of messages declared in Python libraries.
+  // generated_pool() contains all messages already linked in C++ libraries, and
+  // is used as underlay.
+  descriptor_pool_map =
+      new std::unordered_map<const DescriptorPool*, PyDescriptorPool*>;
+  python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay(
+      DescriptorPool::generated_pool());
+  if (python_generated_pool == nullptr) {
+    delete descriptor_pool_map;
+    return false;
+  }
+
+  // Register this pool to be found for C++-generated descriptors.
+  descriptor_pool_map->insert(
+      std::make_pair(DescriptorPool::generated_pool(),
+                     python_generated_pool));
+
+  return true;
+}
+
+// The default DescriptorPool used everywhere in this module.
+// Today it's the python_generated_pool.
+// TODO(amauryfa): Remove all usages of this function: the pool should be
+// derived from the context.
+PyDescriptorPool* GetDefaultDescriptorPool() {
+  return python_generated_pool;
+}
+
+PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) {
+  // Fast path for standard descriptors.
+  if (pool == python_generated_pool->pool ||
+      pool == DescriptorPool::generated_pool()) {
+    return python_generated_pool;
+  }
+  std::unordered_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 nullptr;
+  }
+  return it->second;
+}
+
+PyObject* PyDescriptorPool_FromPool(const DescriptorPool* pool) {
+  PyDescriptorPool* existing_pool = GetDescriptorPool_FromPool(pool);
+  if (existing_pool != nullptr) {
+    Py_INCREF(existing_pool);
+    return reinterpret_cast<PyObject*>(existing_pool);
+  } else {
+    PyErr_Clear();
+  }
+
+  PyDescriptorPool* cpool = cdescriptor_pool::_CreateDescriptorPool();
+  if (cpool == nullptr) {
+    return nullptr;
+  }
+  cpool->pool = const_cast<DescriptorPool*>(pool);
+  cpool->is_owned = false;
+  cpool->is_mutable = false;
+  cpool->underlay = nullptr;
+
+  if (!descriptor_pool_map->insert(std::make_pair(cpool->pool, cpool)).second) {
+    // Should never happen -- We already checked the existence above.
+    PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
+    return nullptr;
+  }
+
+  return reinterpret_cast<PyObject*>(cpool);
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
new file mode 100644
index 0000000..5d3c3a9
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -0,0 +1,149 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <unordered_map>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+struct PyMessageFactory;
+
+// The (meta) type of all Messages classes.
+struct CMessageClass;
+
+// Wraps operations to the global DescriptorPool which contains information
+// about all messages and fields.
+//
+// There is normally one pool per process. We make it a Python object only
+// because it contains many Python references.
+//
+// "Methods" that interacts with this DescriptorPool are in the cdescriptor_pool
+// namespace.
+typedef struct PyDescriptorPool {
+  PyObject_HEAD;
+
+  // The C++ pool containing Descriptors.
+  const DescriptorPool* pool;
+
+  // True if we should free the pointer above.
+  bool is_owned;
+
+  // True if this pool accepts new proto definitions.
+  // In this case it is allowed to const_cast<DescriptorPool*>(pool).
+  bool is_mutable;
+
+
+  // The error collector to store error info. Can be NULL. This pointer is
+  // owned.
+  DescriptorPool::ErrorCollector* error_collector;
+
+  // 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;
+
+  // The preferred MessageFactory to be used by descriptors.
+  // TODO(amauryfa): Don't create the Factory from the DescriptorPool, but
+  // use the one passed while creating message classes. And remove this member.
+  PyMessageFactory* py_message_factory;
+
+  // Cache the options for any kind of descriptor.
+  // Descriptor pointers are owned by the DescriptorPool above.
+  // Python objects are owned by the map.
+  std::unordered_map<const void*, PyObject*>* descriptor_options;
+} PyDescriptorPool;
+
+
+extern PyTypeObject PyDescriptorPool_Type;
+
+namespace cdescriptor_pool {
+
+
+// The functions below are also exposed as methods of the DescriptorPool type.
+
+// Looks up a field by name. Returns a PyFieldDescriptor corresponding to
+// the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* name);
+
+// Looks up an extension by name. Returns a PyFieldDescriptor corresponding
+// to the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg);
+
+// Looks up an enum type by name. Returns a PyEnumDescriptor corresponding
+// to the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg);
+
+// Looks up a oneof by name. Returns a COneofDescriptor corresponding
+// to the oneof on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg);
+
+}  // namespace cdescriptor_pool
+
+// Retrieves the global descriptor pool owned by the _message module.
+// This is the one used by pb2.py generated modules.
+// Returns a *borrowed* reference.
+// "Default" pool used to register messages from _pb2.py modules.
+PyDescriptorPool* GetDefaultDescriptorPool();
+
+// Retrieves an existing python descriptor pool owning the C++ descriptor pool.
+// Returns a *borrowed* reference.
+PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool);
+
+// Wraps a C++ descriptor pool in a Python object, creates it if necessary.
+// Returns a new reference.
+PyObject* PyDescriptorPool_FromPool(const DescriptorPool* pool);
+
+// Initialize objects used by this module.
+bool InitDescriptorPool();
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
new file mode 100644
index 0000000..66703da
--- /dev/null
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -0,0 +1,484 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/extension_dict.h>
+
+#include <cstdint>
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/repeated_composite_container.h>
+#include <google/protobuf/pyext/repeated_scalar_container.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace extension_dict {
+
+static Py_ssize_t len(ExtensionDict* self) {
+  Py_ssize_t size = 0;
+  std::vector<const FieldDescriptor*> fields;
+  self->parent->message->GetReflection()->ListFields(*self->parent->message,
+                                                     &fields);
+
+  for (size_t i = 0; i < fields.size(); ++i) {
+    if (fields[i]->is_extension()) {
+      // With C++ descriptors, the field can always be retrieved, but for
+      // unknown extensions which have not been imported in Python code, there
+      // is no message class and we cannot retrieve the value.
+      // ListFields() has the same behavior.
+      if (fields[i]->message_type() != nullptr &&
+          message_factory::GetMessageClass(
+              cmessage::GetFactoryForMessage(self->parent),
+              fields[i]->message_type()) == nullptr) {
+        PyErr_Clear();
+        continue;
+      }
+      ++size;
+    }
+  }
+  return size;
+}
+
+struct ExtensionIterator {
+  PyObject_HEAD;
+  Py_ssize_t index;
+  std::vector<const FieldDescriptor*> fields;
+
+  // Owned reference, to keep the FieldDescriptors alive.
+  ExtensionDict* extension_dict;
+};
+
+PyObject* GetIter(PyObject* _self) {
+  ExtensionDict* self = reinterpret_cast<ExtensionDict*>(_self);
+
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ExtensionIterator_Type, 0));
+  if (obj == nullptr) {
+    return PyErr_Format(PyExc_MemoryError,
+                        "Could not allocate extension iterator");
+  }
+
+  ExtensionIterator* iter = reinterpret_cast<ExtensionIterator*>(obj.get());
+
+  // Call "placement new" to initialize. So the constructor of
+  // std::vector<...> fields will be called.
+  new (iter) ExtensionIterator;
+
+  self->parent->message->GetReflection()->ListFields(*self->parent->message,
+                                                     &iter->fields);
+  iter->index = 0;
+  Py_INCREF(self);
+  iter->extension_dict = self;
+
+  return obj.release();
+}
+
+static void DeallocExtensionIterator(PyObject* _self) {
+  ExtensionIterator* self = reinterpret_cast<ExtensionIterator*>(_self);
+  self->fields.clear();
+  Py_XDECREF(self->extension_dict);
+  self->~ExtensionIterator();
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+PyObject* subscript(ExtensionDict* self, PyObject* key) {
+  const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+  if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+    return nullptr;
+  }
+
+  if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
+      descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    return cmessage::InternalGetScalar(self->parent->message, descriptor);
+  }
+
+  CMessage::CompositeFieldsMap::iterator iterator =
+      self->parent->composite_fields->find(descriptor);
+  if (iterator != self->parent->composite_fields->end()) {
+    Py_INCREF(iterator->second);
+    return iterator->second->AsPyObject();
+  }
+
+  if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
+      descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // TODO(plabatut): consider building the class on the fly!
+    ContainerBase* sub_message = cmessage::InternalGetSubMessage(
+        self->parent, descriptor);
+    if (sub_message == nullptr) {
+      return nullptr;
+    }
+    (*self->parent->composite_fields)[descriptor] = sub_message;
+    return sub_message->AsPyObject();
+  }
+
+  if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // On the fly message class creation is needed to support the following
+      // situation:
+      // 1- add FileDescriptor to the pool that contains extensions of a message
+      //    defined by another proto file. Do not create any message classes.
+      // 2- instantiate an extended message, and access the extension using
+      //    the field descriptor.
+      // 3- the extension submessage fails to be returned, because no class has
+      //    been created.
+      // It happens when deserializing text proto format, or when enumerating
+      // fields of a deserialized message.
+      CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
+          cmessage::GetFactoryForMessage(self->parent),
+          descriptor->message_type());
+      ScopedPyObjectPtr message_class_handler(
+        reinterpret_cast<PyObject*>(message_class));
+      if (message_class == nullptr) {
+        return nullptr;
+      }
+      ContainerBase* py_container = repeated_composite_container::NewContainer(
+          self->parent, descriptor, message_class);
+      if (py_container == nullptr) {
+        return nullptr;
+      }
+      (*self->parent->composite_fields)[descriptor] = py_container;
+      return py_container->AsPyObject();
+    } else {
+      ContainerBase* py_container = repeated_scalar_container::NewContainer(
+          self->parent, descriptor);
+      if (py_container == nullptr) {
+        return nullptr;
+      }
+      (*self->parent->composite_fields)[descriptor] = py_container;
+      return py_container->AsPyObject();
+    }
+  }
+  PyErr_SetString(PyExc_ValueError, "control reached unexpected line");
+  return nullptr;
+}
+
+int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) {
+  const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+  if (descriptor == nullptr) {
+    return -1;
+  }
+  if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+    return -1;
+  }
+
+  if (value == nullptr) {
+    return cmessage::ClearFieldByDescriptor(self->parent, descriptor);
+  }
+
+  if (descriptor->label() != FieldDescriptor::LABEL_OPTIONAL ||
+      descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    PyErr_SetString(PyExc_TypeError, "Extension is repeated and/or composite "
+                    "type");
+    return -1;
+  }
+  cmessage::AssureWritable(self->parent);
+  if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* arg) {
+  char* name;
+  Py_ssize_t name_size;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return nullptr;
+  }
+
+  PyDescriptorPool* pool = cmessage::GetFactoryForMessage(self->parent)->pool;
+  const FieldDescriptor* message_extension =
+      pool->pool->FindExtensionByName(StringParam(name, name_size));
+  if (message_extension == nullptr) {
+    // Is is the name of a message set extension?
+    const Descriptor* message_descriptor =
+        pool->pool->FindMessageTypeByName(StringParam(name, name_size));
+    if (message_descriptor && message_descriptor->extension_count() > 0) {
+      const FieldDescriptor* extension = message_descriptor->extension(0);
+      if (extension->is_extension() &&
+          extension->containing_type()->options().message_set_wire_format() &&
+          extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+          extension->label() == FieldDescriptor::LABEL_OPTIONAL) {
+        message_extension = extension;
+      }
+    }
+  }
+  if (message_extension == nullptr) {
+    Py_RETURN_NONE;
+  }
+
+  return PyFieldDescriptor_FromDescriptor(message_extension);
+}
+
+PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* arg) {
+  int64_t number = PyLong_AsLong(arg);
+  if (number == -1 && PyErr_Occurred()) {
+    return nullptr;
+  }
+
+  PyDescriptorPool* pool = cmessage::GetFactoryForMessage(self->parent)->pool;
+  const FieldDescriptor* message_extension = pool->pool->FindExtensionByNumber(
+      self->parent->message->GetDescriptor(), number);
+  if (message_extension == nullptr) {
+    Py_RETURN_NONE;
+  }
+
+  return PyFieldDescriptor_FromDescriptor(message_extension);
+}
+
+static int Contains(PyObject* _self, PyObject* key) {
+  ExtensionDict* self = reinterpret_cast<ExtensionDict*>(_self);
+  const FieldDescriptor* field_descriptor =
+      cmessage::GetExtensionDescriptor(key);
+  if (field_descriptor == nullptr) {
+    return -1;
+  }
+
+  if (!field_descriptor->is_extension()) {
+    PyErr_Format(PyExc_KeyError, "%s is not an extension",
+                 field_descriptor->full_name().c_str());
+    return -1;
+  }
+
+  const Message* message = self->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  if (field_descriptor->is_repeated()) {
+    if (reflection->FieldSize(*message, field_descriptor) > 0) {
+      return 1;
+    }
+  } else {
+    if (reflection->HasField(*message, field_descriptor)) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+ExtensionDict* NewExtensionDict(CMessage *parent) {
+  ExtensionDict* self = reinterpret_cast<ExtensionDict*>(
+      PyType_GenericAlloc(&ExtensionDict_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  return self;
+}
+
+void dealloc(PyObject* pself) {
+  ExtensionDict* self = reinterpret_cast<ExtensionDict*>(pself);
+  Py_CLEAR(self->parent);
+  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+static PyObject* RichCompare(ExtensionDict* self, PyObject* other, int opid) {
+  // Only equality comparisons are implemented.
+  if (opid != Py_EQ && opid != Py_NE) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+  bool equals = false;
+  if (PyObject_TypeCheck(other, &ExtensionDict_Type)) {
+    equals = self->parent == reinterpret_cast<ExtensionDict*>(other)->parent;
+  }
+  if (equals ^ (opid == Py_EQ)) {
+    Py_RETURN_FALSE;
+  } else {
+    Py_RETURN_TRUE;
+  }
+}
+static PySequenceMethods SeqMethods = {
+    (lenfunc)len,          // sq_length
+    nullptr,               // sq_concat
+    nullptr,               // sq_repeat
+    nullptr,               // sq_item
+    nullptr,               // sq_slice
+    nullptr,               // sq_ass_item
+    nullptr,               // sq_ass_slice
+    (objobjproc)Contains,  // sq_contains
+};
+
+static PyMappingMethods MpMethods = {
+  (lenfunc)len,                /* mp_length */
+  (binaryfunc)subscript,       /* mp_subscript */
+  (objobjargproc)ass_subscript,/* mp_ass_subscript */
+};
+
+#define EDMETHOD(name, args, doc) { #name, (PyCFunction)name, args, doc }
+static PyMethodDef Methods[] = {
+    EDMETHOD(_FindExtensionByName, METH_O, "Finds an extension by name."),
+    EDMETHOD(_FindExtensionByNumber, METH_O,
+             "Finds an extension by field number."),
+    {nullptr, nullptr},
+};
+
+}  // namespace extension_dict
+
+PyTypeObject ExtensionDict_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)  //
+    FULL_MODULE_NAME ".ExtensionDict",      // tp_name
+    sizeof(ExtensionDict),                  // tp_basicsize
+    0,                                      //  tp_itemsize
+    (destructor)extension_dict::dealloc,    //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                                   //  tp_getattr
+    nullptr,                                   //  tp_setattr
+    nullptr,                                   //  tp_compare
+    nullptr,                                   //  tp_repr
+    nullptr,                                   //  tp_as_number
+    &extension_dict::SeqMethods,               //  tp_as_sequence
+    &extension_dict::MpMethods,                //  tp_as_mapping
+    PyObject_HashNotImplemented,               //  tp_hash
+    nullptr,                                   //  tp_call
+    nullptr,                                   //  tp_str
+    nullptr,                                   //  tp_getattro
+    nullptr,                                   //  tp_setattro
+    nullptr,                                   //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                        //  tp_flags
+    "An extension dict",                       //  tp_doc
+    nullptr,                                   //  tp_traverse
+    nullptr,                                   //  tp_clear
+    (richcmpfunc)extension_dict::RichCompare,  //  tp_richcompare
+    0,                                         //  tp_weaklistoffset
+    extension_dict::GetIter,                   //  tp_iter
+    nullptr,                                   //  tp_iternext
+    extension_dict::Methods,                   //  tp_methods
+    nullptr,                                   //  tp_members
+    nullptr,                                   //  tp_getset
+    nullptr,                                   //  tp_base
+    nullptr,                                   //  tp_dict
+    nullptr,                                   //  tp_descr_get
+    nullptr,                                   //  tp_descr_set
+    0,                                         //  tp_dictoffset
+    nullptr,                                   //  tp_init
+};
+
+PyObject* IterNext(PyObject* _self) {
+  extension_dict::ExtensionIterator* self =
+      reinterpret_cast<extension_dict::ExtensionIterator*>(_self);
+  Py_ssize_t total_size = self->fields.size();
+  Py_ssize_t index = self->index;
+  while (self->index < total_size) {
+    index = self->index;
+    ++self->index;
+    if (self->fields[index]->is_extension()) {
+      // With C++ descriptors, the field can always be retrieved, but for
+      // unknown extensions which have not been imported in Python code, there
+      // is no message class and we cannot retrieve the value.
+      // ListFields() has the same behavior.
+      if (self->fields[index]->message_type() != nullptr &&
+          message_factory::GetMessageClass(
+              cmessage::GetFactoryForMessage(self->extension_dict->parent),
+              self->fields[index]->message_type()) == nullptr) {
+        PyErr_Clear();
+        continue;
+      }
+
+      return PyFieldDescriptor_FromDescriptor(self->fields[index]);
+    }
+  }
+
+  return nullptr;
+}
+
+PyTypeObject ExtensionIterator_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)      //
+    FULL_MODULE_NAME ".ExtensionIterator",      //  tp_name
+    sizeof(extension_dict::ExtensionIterator),  //  tp_basicsize
+    0,                                          //  tp_itemsize
+    extension_dict::DeallocExtensionIterator,   //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                  //  tp_getattr
+    nullptr,                  //  tp_setattr
+    nullptr,                  //  tp_compare
+    nullptr,                  //  tp_repr
+    nullptr,                  //  tp_as_number
+    nullptr,                  //  tp_as_sequence
+    nullptr,                  //  tp_as_mapping
+    nullptr,                  //  tp_hash
+    nullptr,                  //  tp_call
+    nullptr,                  //  tp_str
+    nullptr,                  //  tp_getattro
+    nullptr,                  //  tp_setattro
+    nullptr,                  //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,       //  tp_flags
+    "A scalar map iterator",  //  tp_doc
+    nullptr,                  //  tp_traverse
+    nullptr,                  //  tp_clear
+    nullptr,                  //  tp_richcompare
+    0,                        //  tp_weaklistoffset
+    PyObject_SelfIter,        //  tp_iter
+    IterNext,                 //  tp_iternext
+    nullptr,                  //  tp_methods
+    nullptr,                  //  tp_members
+    nullptr,                  //  tp_getset
+    nullptr,                  //  tp_base
+    nullptr,                  //  tp_dict
+    nullptr,                  //  tp_descr_get
+    nullptr,                  //  tp_descr_set
+    0,                        //  tp_dictoffset
+    nullptr,                  //  tp_init
+};
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h
new file mode 100644
index 0000000..86d2451
--- /dev/null
+++ b/python/google/protobuf/pyext/extension_dict.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class FieldDescriptor;
+
+namespace python {
+
+typedef struct ExtensionDict {
+  PyObject_HEAD;
+
+  // Strong, owned reference to the parent message. Never NULL.
+  CMessage* parent;
+} ExtensionDict;
+
+extern PyTypeObject ExtensionDict_Type;
+extern PyTypeObject ExtensionIterator_Type;
+
+namespace extension_dict {
+
+// Builds an Extensions dict for a specific message.
+ExtensionDict* NewExtensionDict(CMessage *parent);
+
+}  // namespace extension_dict
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__
diff --git a/python/google/protobuf/pyext/field.cc b/python/google/protobuf/pyext/field.cc
new file mode 100644
index 0000000..0d3b0b9
--- /dev/null
+++ b/python/google/protobuf/pyext/field.cc
@@ -0,0 +1,143 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/pyext/field.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace field {
+
+static PyObject* Repr(PyMessageFieldProperty* self) {
+  return PyUnicode_FromFormat("<field property '%s'>",
+                              self->field_descriptor->full_name().c_str());
+}
+
+static PyObject* DescrGet(PyMessageFieldProperty* self, PyObject* obj,
+                          PyObject* type) {
+  if (obj == nullptr) {
+    Py_INCREF(self);
+    return reinterpret_cast<PyObject*>(self);
+  }
+  return cmessage::GetFieldValue(reinterpret_cast<CMessage*>(obj),
+                                 self->field_descriptor);
+}
+
+static int DescrSet(PyMessageFieldProperty* self, PyObject* obj,
+                    PyObject* value) {
+  if (value == nullptr) {
+    PyErr_SetString(PyExc_AttributeError, "Cannot delete field attribute");
+    return -1;
+  }
+  return cmessage::SetFieldValue(reinterpret_cast<CMessage*>(obj),
+                                 self->field_descriptor, value);
+}
+
+static PyObject* GetDescriptor(PyMessageFieldProperty* self, void* closure) {
+  return PyFieldDescriptor_FromDescriptor(self->field_descriptor);
+}
+
+static PyObject* GetDoc(PyMessageFieldProperty* self, void* closure) {
+  return PyUnicode_FromFormat("Field %s",
+                              self->field_descriptor->full_name().c_str());
+}
+
+static PyGetSetDef Getters[] = {
+    {"DESCRIPTOR", (getter)GetDescriptor, nullptr, "Field descriptor"},
+    {"__doc__", (getter)GetDoc, nullptr, nullptr},
+    {nullptr},
+};
+}  // namespace field
+
+static PyTypeObject _CFieldProperty_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)  // head
+    FULL_MODULE_NAME ".FieldProperty",      // tp_name
+    sizeof(PyMessageFieldProperty),         // tp_basicsize
+    0,                                      // tp_itemsize
+    nullptr,                                // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                        // tp_getattr
+    nullptr,                        // tp_setattr
+    nullptr,                        // tp_compare
+    (reprfunc)field::Repr,          // tp_repr
+    nullptr,                        // tp_as_number
+    nullptr,                        // tp_as_sequence
+    nullptr,                        // tp_as_mapping
+    nullptr,                        // tp_hash
+    nullptr,                        // tp_call
+    nullptr,                        // tp_str
+    nullptr,                        // tp_getattro
+    nullptr,                        // tp_setattro
+    nullptr,                        // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,             // tp_flags
+    "Field property of a Message",  // tp_doc
+    nullptr,                        // tp_traverse
+    nullptr,                        // tp_clear
+    nullptr,                        // tp_richcompare
+    0,                              // tp_weaklistoffset
+    nullptr,                        // tp_iter
+    nullptr,                        // tp_iternext
+    nullptr,                        // tp_methods
+    nullptr,                        // tp_members
+    field::Getters,                 // tp_getset
+    nullptr,                        // tp_base
+    nullptr,                        // tp_dict
+    (descrgetfunc)field::DescrGet,  // tp_descr_get
+    (descrsetfunc)field::DescrSet,  // tp_descr_set
+    0,                              // tp_dictoffset
+    nullptr,                        // tp_init
+    nullptr,                        // tp_alloc
+    nullptr,                        // tp_new
+};
+PyTypeObject* CFieldProperty_Type = &_CFieldProperty_Type;
+
+PyObject* NewFieldProperty(const FieldDescriptor* field_descriptor) {
+  // Create a new descriptor object
+  PyMessageFieldProperty* property =
+      PyObject_New(PyMessageFieldProperty, CFieldProperty_Type);
+  if (property == nullptr) {
+    return nullptr;
+  }
+  property->field_descriptor = field_descriptor;
+  return reinterpret_cast<PyObject*>(property);
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/field.h b/python/google/protobuf/pyext/field.h
new file mode 100644
index 0000000..f9f94c4
--- /dev/null
+++ b/python/google/protobuf/pyext/field.h
@@ -0,0 +1,60 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_FIELD_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_FIELD_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+namespace google {
+namespace protobuf {
+
+class FieldDescriptor;
+
+namespace python {
+
+// A data descriptor that represents a field in a Message class.
+struct PyMessageFieldProperty {
+  PyObject_HEAD;
+
+  // This pointer is owned by the same pool as the Message class it belongs to.
+  const FieldDescriptor* field_descriptor;
+};
+
+extern PyTypeObject* CFieldProperty_Type;
+
+PyObject* NewFieldProperty(const FieldDescriptor* field_descriptor);
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_FIELD_H__
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
new file mode 100644
index 0000000..e8a6888
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -0,0 +1,931 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/repeated_composite_container.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/map_util.h>
+
+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);
+  static PyObject* MergeFrom(PyObject* _self, PyObject* arg);
+
+  // 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);
+  static PyObject* ScalarMapToStr(PyObject* _self);
+  static PyObject* MessageMapToStr(PyObject* _self);
+};
+
+struct MapIterator {
+  PyObject_HEAD;
+
+  std::unique_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 parent 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(), the MapContainer points 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.
+  CMessage* parent;
+  // 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_t version;
+};
+
+Message* MapContainer::GetMutableMessage() {
+  cmessage::AssureWritable(parent);
+  return parent->message;
+}
+
+// Consumes a reference on the Python string object.
+static bool PyStringToSTL(PyObject* py_string, std::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(MapContainer* self, PyObject* obj, MapKey* key) {
+  const FieldDescriptor* field_descriptor =
+      self->parent_field_descriptor->message_type()->map_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: {
+      std::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(MapContainer* self, const MapKey& key) {
+  const FieldDescriptor* field_descriptor =
+      self->parent_field_descriptor->message_type()->map_key();
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return PyLong_FromLong(key.GetInt32Value());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return PyLong_FromLongLong(key.GetInt64Value());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return PyLong_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 nullptr;
+  }
+}
+
+// This is only used for ScalarMap, so we don't need to handle the
+// CPPTYPE_MESSAGE case.
+PyObject* MapValueRefToPython(MapContainer* self, const MapValueRef& value) {
+  const FieldDescriptor* field_descriptor =
+      self->parent_field_descriptor->message_type()->map_value();
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return PyLong_FromLong(value.GetInt32Value());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return PyLong_FromLongLong(value.GetInt64Value());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return PyLong_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 PyLong_FromLong(value.GetEnumValue());
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Couldn't convert type %d to value",
+          field_descriptor->cpp_type());
+      return nullptr;
+  }
+}
+
+// This is only used for ScalarMap, so we don't need to handle the
+// CPPTYPE_MESSAGE case.
+static bool PythonToMapValueRef(MapContainer* self, PyObject* obj,
+                                bool allow_unknown_enum_values,
+                                MapValueRef* value_ref) {
+  const FieldDescriptor* field_descriptor =
+      self->parent_field_descriptor->message_type()->map_value();
+  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: {
+      std::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 != nullptr) {
+          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->parent->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* GetEntryClass(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  CMessageClass* message_class = message_factory::GetMessageClass(
+      cmessage::GetFactoryForMessage(self->parent),
+      self->parent_field_descriptor->message_type());
+  Py_XINCREF(message_class);
+  return reinterpret_cast<PyObject*>(message_class);
+}
+
+PyObject* MapReflectionFriend::MergeFrom(PyObject* _self, PyObject* arg) {
+  MapContainer* self = GetMap(_self);
+  if (!PyObject_TypeCheck(arg, ScalarMapContainer_Type) &&
+      !PyObject_TypeCheck(arg, MessageMapContainer_Type)) {
+    PyErr_SetString(PyExc_AttributeError, "Not a map field");
+    return nullptr;
+  }
+  MapContainer* other_map = GetMap(arg);
+  Message* message = self->GetMutableMessage();
+  const Message* other_message = other_map->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  const Reflection* other_reflection = other_message->GetReflection();
+  internal::MapFieldBase* field = reflection->MutableMapData(
+      message, self->parent_field_descriptor);
+  const internal::MapFieldBase* other_field = other_reflection->GetMapData(
+      *other_message, other_map->parent_field_descriptor);
+  field->MergeFrom(*other_field);
+  self->version++;
+  Py_RETURN_NONE;
+}
+
+PyObject* MapReflectionFriend::Contains(PyObject* _self, PyObject* key) {
+  MapContainer* self = GetMap(_self);
+
+  const Message* message = self->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+
+  if (!PythonToMapKey(self, key, &map_key)) {
+    return nullptr;
+  }
+
+  if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
+                                 map_key)) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+// ScalarMap ///////////////////////////////////////////////////////////////////
+
+MapContainer* NewScalarMapContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return nullptr;
+  }
+
+  PyObject* obj(PyType_GenericAlloc(ScalarMapContainer_Type, 0));
+  if (obj == nullptr) {
+    PyErr_Format(PyExc_RuntimeError,
+                 "Could not allocate new container.");
+    return nullptr;
+  }
+
+  MapContainer* self = GetMap(obj);
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->version = 0;
+
+  return self;
+}
+
+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(self, key, &map_key)) {
+    return nullptr;
+  }
+
+  if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                         map_key, &value)) {
+    self->version++;
+  }
+
+  return MapValueRefToPython(self, 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(self, key, &map_key)) {
+    return -1;
+  }
+
+  if (v) {
+    // Set item to v.
+    if (reflection->InsertOrLookupMapValue(
+            message, self->parent_field_descriptor, map_key, &value)) {
+      self->version++;
+    }
+
+    if (!PythonToMapValueRef(self, v, reflection->SupportsUnknownEnumValues(),
+                             &value)) {
+      return -1;
+    }
+    return 0;
+  } else {
+    // Delete key from map.
+    if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
+                                   map_key)) {
+      self->version++;
+      return 0;
+    } else {
+      PyErr_Format(PyExc_KeyError, "Key not present in map");
+      return -1;
+    }
+  }
+}
+
+static PyObject* ScalarMapGet(PyObject* self, PyObject* args,
+                              PyObject* kwargs) {
+  static const char* kwlist[] = {"key", "default", nullptr};
+  PyObject* key;
+  PyObject* default_value = nullptr;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
+                                   const_cast<char**>(kwlist), &key,
+                                   &default_value)) {
+    return nullptr;
+  }
+
+  ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
+  if (is_present.get() == nullptr) {
+    return nullptr;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return MapReflectionFriend::ScalarMapGetItem(self, key);
+  } else {
+    if (default_value != nullptr) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+PyObject* MapReflectionFriend::ScalarMapToStr(PyObject* _self) {
+  ScopedPyObjectPtr dict(PyDict_New());
+  if (dict == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr key;
+  ScopedPyObjectPtr value;
+
+  MapContainer* self = GetMap(_self);
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  for (google::protobuf::MapIterator it = reflection->MapBegin(
+           message, self->parent_field_descriptor);
+       it != reflection->MapEnd(message, self->parent_field_descriptor);
+       ++it) {
+    key.reset(MapKeyToPython(self, it.GetKey()));
+    if (key == nullptr) {
+      return nullptr;
+    }
+    value.reset(MapValueRefToPython(self, it.GetValueRef()));
+    if (value == nullptr) {
+      return nullptr;
+    }
+    if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
+      return nullptr;
+    }
+  }
+  return PyObject_Repr(dict.get());
+}
+
+static void ScalarMapDealloc(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  self->RemoveFromParentCache();
+  PyTypeObject *type = Py_TYPE(_self);
+  type->tp_free(_self);
+  if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+    // With Python3, the Map class is not static, and must be managed.
+    Py_DECREF(type);
+  }
+}
+
+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", (PyCFunction)ScalarMapGet, METH_VARARGS | METH_KEYWORDS,
+     "Gets the value for the given key if present, or otherwise a default"},
+    {"GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
+     "Return the class used to build Entries of (key, value) pairs."},
+    {"MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
+     "Merges a map into the current map."},
+    /*
+    { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+      "Makes a deep copy of the class." },
+    { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+      "Outputs picklable representation of the repeated field." },
+    */
+    {nullptr, nullptr},
+};
+
+PyTypeObject* ScalarMapContainer_Type;
+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},
+    {Py_tp_repr, (void*)MapReflectionFriend::ScalarMapToStr},
+    {0, nullptr},
+};
+
+PyType_Spec ScalarMapContainer_Type_spec = {
+    FULL_MODULE_NAME ".ScalarMapContainer", sizeof(MapContainer), 0,
+    Py_TPFLAGS_DEFAULT, ScalarMapContainer_Type_slots};
+
+// 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.
+  return self->parent
+      ->BuildSubMessageFromPointer(self->parent_field_descriptor, message,
+                                   self->message_class)
+      ->AsPyObject();
+}
+
+MessageMapContainer* NewMessageMapContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor,
+    CMessageClass* message_class) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return nullptr;
+  }
+
+  PyObject* obj = PyType_GenericAlloc(MessageMapContainer_Type, 0);
+  if (obj == nullptr) {
+    PyErr_SetString(PyExc_RuntimeError, "Could not allocate new container.");
+    return nullptr;
+  }
+
+  MessageMapContainer* self = GetMessageMap(obj);
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->version = 0;
+
+  Py_INCREF(message_class);
+  self->message_class = message_class;
+
+  return self;
+}
+
+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(self, key, &map_key)) {
+    return -1;
+  }
+
+  // Delete key from map.
+  if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
+                                 map_key)) {
+    // Delete key from CMessage dict.
+    MapValueRef value;
+    reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                       map_key, &value);
+    Message* sub_message = value.MutableMessageValue();
+    // If there is a living weak reference to an item, we "Release" it,
+    // otherwise we just discard the C++ value.
+    if (CMessage* released =
+            self->parent->MaybeReleaseSubMessage(sub_message)) {
+      Message* msg = released->message;
+      released->message = msg->New();
+      msg->GetReflection()->Swap(msg, released->message);
+    }
+
+    // Delete key from map.
+    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(self, key, &map_key)) {
+    return nullptr;
+  }
+
+  if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                         map_key, &value)) {
+    self->version++;
+  }
+
+  return GetCMessage(self, value.MutableMessageValue());
+}
+
+PyObject* MapReflectionFriend::MessageMapToStr(PyObject* _self) {
+  ScopedPyObjectPtr dict(PyDict_New());
+  if (dict == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr key;
+  ScopedPyObjectPtr value;
+
+  MessageMapContainer* self = GetMessageMap(_self);
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  for (google::protobuf::MapIterator it = reflection->MapBegin(
+           message, self->parent_field_descriptor);
+       it != reflection->MapEnd(message, self->parent_field_descriptor);
+       ++it) {
+    key.reset(MapKeyToPython(self, it.GetKey()));
+    if (key == nullptr) {
+      return nullptr;
+    }
+    value.reset(GetCMessage(self, it.MutableValueRef()->MutableMessageValue()));
+    if (value == nullptr) {
+      return nullptr;
+    }
+    if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
+      return nullptr;
+    }
+  }
+  return PyObject_Repr(dict.get());
+}
+
+PyObject* MessageMapGet(PyObject* self, PyObject* args, PyObject* kwargs) {
+  static const char* kwlist[] = {"key", "default", nullptr};
+  PyObject* key;
+  PyObject* default_value = nullptr;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
+                                   const_cast<char**>(kwlist), &key,
+                                   &default_value)) {
+    return nullptr;
+  }
+
+  ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
+  if (is_present.get() == nullptr) {
+    return nullptr;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return MapReflectionFriend::MessageMapGetItem(self, key);
+  } else {
+    if (default_value != nullptr) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static void MessageMapDealloc(PyObject* _self) {
+  MessageMapContainer* self = GetMessageMap(_self);
+  self->RemoveFromParentCache();
+  Py_DECREF(self->message_class);
+  PyTypeObject *type = Py_TYPE(_self);
+  type->tp_free(_self);
+  if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+    // With Python3, the Map class is not static, and must be managed.
+    Py_DECREF(type);
+  }
+}
+
+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", (PyCFunction)MessageMapGet, METH_VARARGS | METH_KEYWORDS,
+     "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."},
+    {"GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
+     "Return the class used to build Entries of (key, value) pairs."},
+    {"MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
+     "Merges a map into the current map."},
+    /*
+    { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+      "Makes a deep copy of the class." },
+    { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+      "Outputs picklable representation of the repeated field." },
+    */
+    {nullptr, nullptr},
+};
+
+PyTypeObject* MessageMapContainer_Type;
+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},
+    {Py_tp_repr, (void*)MapReflectionFriend::MessageMapToStr},
+    {0, nullptr}};
+
+PyType_Spec MessageMapContainer_Type_spec = {
+    FULL_MODULE_NAME ".MessageMapContainer", sizeof(MessageMapContainer), 0,
+    Py_TPFLAGS_DEFAULT, MessageMapContainer_Type_slots};
+
+// 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 == nullptr) {
+    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
+  }
+
+  MapIterator* iter = GetIter(obj.get());
+
+  Py_INCREF(self);
+  iter->container = self;
+  iter->version = self->version;
+  Py_INCREF(self->parent);
+  iter->parent = self->parent;
+
+  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->parent != self->container->parent) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Map cleared during iteration.");
+  }
+
+  if (self->iter.get() == nullptr) {
+    return nullptr;
+  }
+
+  Message* message = self->container->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+
+  if (*self->iter ==
+      reflection->MapEnd(message, self->container->parent_field_descriptor)) {
+    return nullptr;
+  }
+
+  PyObject* ret = MapKeyToPython(self->container, self->iter->GetKey());
+
+  ++(*self->iter);
+
+  return ret;
+}
+
+static void DeallocMapIterator(PyObject* _self) {
+  MapIterator* self = GetIter(_self);
+  self->iter.reset();
+  Py_CLEAR(self->container);
+  Py_CLEAR(self->parent);
+  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
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                        //  tp_getattr
+    nullptr,                        //  tp_setattr
+    nullptr,                        //  tp_compare
+    nullptr,                        //  tp_repr
+    nullptr,                        //  tp_as_number
+    nullptr,                        //  tp_as_sequence
+    nullptr,                        //  tp_as_mapping
+    nullptr,                        //  tp_hash
+    nullptr,                        //  tp_call
+    nullptr,                        //  tp_str
+    nullptr,                        //  tp_getattro
+    nullptr,                        //  tp_setattro
+    nullptr,                        //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,             //  tp_flags
+    "A scalar map iterator",        //  tp_doc
+    nullptr,                        //  tp_traverse
+    nullptr,                        //  tp_clear
+    nullptr,                        //  tp_richcompare
+    0,                              //  tp_weaklistoffset
+    PyObject_SelfIter,              //  tp_iter
+    MapReflectionFriend::IterNext,  //  tp_iternext
+    nullptr,                        //  tp_methods
+    nullptr,                        //  tp_members
+    nullptr,                        //  tp_getset
+    nullptr,                        //  tp_base
+    nullptr,                        //  tp_dict
+    nullptr,                        //  tp_descr_get
+    nullptr,                        //  tp_descr_set
+    0,                              //  tp_dictoffset
+    nullptr,                        //  tp_init
+};
+
+bool InitMapContainers() {
+  // ScalarMapContainer_Type derives from our MutableMapping type.
+  ScopedPyObjectPtr abc(PyImport_ImportModule("collections.abc"));
+  if (abc == nullptr) {
+    return false;
+  }
+
+  ScopedPyObjectPtr mutable_mapping(
+      PyObject_GetAttrString(abc.get(), "MutableMapping"));
+  if (mutable_mapping == nullptr) {
+    return false;
+  }
+
+  Py_INCREF(mutable_mapping.get());
+  ScopedPyObjectPtr bases(PyTuple_Pack(1, mutable_mapping.get()));
+  if (bases == nullptr) {
+    return false;
+  }
+
+  ScalarMapContainer_Type = reinterpret_cast<PyTypeObject*>(
+      PyType_FromSpecWithBases(&ScalarMapContainer_Type_spec, bases.get()));
+
+  if (PyType_Ready(&MapIterator_Type) < 0) {
+    return false;
+  }
+
+  MessageMapContainer_Type = reinterpret_cast<PyTypeObject*>(
+      PyType_FromSpecWithBases(&MessageMapContainer_Type_spec, bases.get()));
+  return true;
+}
+
+}  // 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..af334d2
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.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_PYTHON_CPP_MAP_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <cstdint>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace python {
+
+struct CMessageClass;
+
+// This struct is used directly for ScalarMap, and is the base class of
+// MessageMapContainer, which is used for MessageMap.
+struct MapContainer : public ContainerBase {
+  // Use to get a mutable message when necessary.
+  Message* GetMutableMessage();
+
+  // We bump this whenever we perform a mutation, to invalidate existing
+  // iterators.
+  uint64_t version;
+};
+
+struct MessageMapContainer : public MapContainer {
+  // The type used to create new child messages.
+  CMessageClass* message_class;
+};
+
+bool InitMapContainers();
+
+extern PyTypeObject* MessageMapContainer_Type;
+extern PyTypeObject* ScalarMapContainer_Type;
+extern PyTypeObject MapIterator_Type;  // Both map types use the same iterator.
+
+// Builds a MapContainer object, from a parent message and a
+// field descriptor.
+extern MapContainer* NewScalarMapContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
+
+// Builds a MessageMap object, from a parent message and a
+// field descriptor.
+extern MessageMapContainer* NewMessageMapContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor,
+    CMessageClass* message_class);
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
new file mode 100644
index 0000000..2c4a957
--- /dev/null
+++ b/python/google/protobuf/pyext/message.cc
@@ -0,0 +1,3072 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/message.h>
+
+#include <structmember.h>  // A Python header file.
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/strutil.h>
+
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
+#endif
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.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/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/field.h>
+#include <google/protobuf/pyext/map_container.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/repeated_composite_container.h>
+#include <google/protobuf/pyext/repeated_scalar_container.h>
+#include <google/protobuf/pyext/safe_numerics.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/pyext/unknown_field_set.h>
+#include <google/protobuf/pyext/unknown_fields.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/stubs/map_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+#define PyString_AsString(ob) \
+  (PyUnicode_Check(ob) ? PyUnicode_AsUTF8(ob) : PyBytes_AsString(ob))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+class MessageReflectionFriend {
+ public:
+  static void UnsafeShallowSwapFields(
+      Message* lhs, Message* rhs,
+      const std::vector<const FieldDescriptor*>& fields) {
+    lhs->GetReflection()->UnsafeShallowSwapFields(lhs, rhs, fields);
+  }
+  static bool IsLazyField(const Reflection* reflection, const Message& message,
+                          const FieldDescriptor* field) {
+    return reflection->IsLazyField(field) ||
+           reflection->IsLazyExtension(message, field);
+  }
+};
+
+static PyObject* kDESCRIPTOR;
+PyObject* EnumTypeWrapper_class;
+static PyObject* PythonMessage_class;
+static PyObject* kEmptyWeakref;
+static PyObject* WKT_classes = nullptr;
+
+namespace message_meta {
+
+namespace {
+// Copied over from internal 'google/protobuf/stubs/strutil.h'.
+inline void LowerString(std::string* s) {
+  std::string::iterator end = s->end();
+  for (std::string::iterator i = s->begin(); i != end; ++i) {
+    // tolower() changes based on locale.  We don't want this!
+    if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
+  }
+}
+}  // namespace
+
+// Finalize the creation of the Message class.
+static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
+  // For each field set: cls.<field>_FIELD_NUMBER = <number>
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* field_descriptor = descriptor->field(i);
+    ScopedPyObjectPtr property(NewFieldProperty(field_descriptor));
+    if (property == nullptr) {
+      return -1;
+    }
+    if (PyObject_SetAttrString(cls, field_descriptor->name().c_str(),
+                               property.get()) < 0) {
+      return -1;
+    }
+  }
+
+  // For each enum set cls.<enum name> = EnumTypeWrapper(<enum descriptor>).
+  for (int i = 0; i < descriptor->enum_type_count(); ++i) {
+    const EnumDescriptor* enum_descriptor = descriptor->enum_type(i);
+    ScopedPyObjectPtr enum_type(
+        PyEnumDescriptor_FromDescriptor(enum_descriptor));
+    if (enum_type == nullptr) {
+      return -1;
+    }
+    // Add wrapped enum type to message class.
+    ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
+        EnumTypeWrapper_class, enum_type.get(), nullptr));
+    if (wrapped == nullptr) {
+      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(
+          PyLong_FromLong(enum_value_descriptor->number()));
+      if (value_number == nullptr) {
+        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 == nullptr) {
+      return -1;
+    }
+
+    // Add the extension field to the message class.
+    if (PyObject_SetAttrString(
+            cls, field->name().c_str(), extension_field.get()) == -1) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
+  static const char* kwlist[] = {"name", "bases", "dict", nullptr};
+  PyObject *bases, *dict;
+  const char* name;
+
+  // Check arguments: (name, bases, dict)
+  if (!PyArg_ParseTupleAndKeywords(
+          args, kwargs, "sO!O!:type", const_cast<char**>(kwlist), &name,
+          &PyTuple_Type, &bases, &PyDict_Type, &dict)) {
+    return nullptr;
+  }
+
+  // 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 nullptr;
+  }
+
+  // Check dict['DESCRIPTOR']
+  PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
+  if (py_descriptor == nullptr) {
+    PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
+    return nullptr;
+  }
+  if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) {
+    PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
+                 py_descriptor->ob_type->tp_name);
+    return nullptr;
+  }
+  const Descriptor* message_descriptor =
+      PyMessageDescriptor_AsDescriptor(py_descriptor);
+  if (message_descriptor == nullptr) {
+    return nullptr;
+  }
+
+  // Messages have no __dict__
+  ScopedPyObjectPtr slots(PyTuple_New(0));
+  if (PyDict_SetItemString(dict, "__slots__", slots.get()) < 0) {
+    return nullptr;
+  }
+
+  // Build the arguments to the base metaclass.
+  // We change the __bases__ classes.
+  ScopedPyObjectPtr new_args;
+
+  if (WKT_classes == nullptr) {
+    ScopedPyObjectPtr well_known_types(PyImport_ImportModule(
+        "google.protobuf.internal.well_known_types"));
+    GOOGLE_DCHECK(well_known_types != nullptr);
+
+    WKT_classes = PyObject_GetAttrString(well_known_types.get(), "WKTBASES");
+    GOOGLE_DCHECK(WKT_classes != nullptr);
+  }
+
+  PyObject* well_known_class = PyDict_GetItemString(
+      WKT_classes, message_descriptor->full_name().c_str());
+  if (well_known_class == nullptr) {
+    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 == nullptr) {
+    return nullptr;
+  }
+  // Call the base metaclass.
+  ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args.get(), nullptr));
+  if (result == nullptr) {
+    return nullptr;
+  }
+  CMessageClass* newtype = reinterpret_cast<CMessageClass*>(result.get());
+
+  // Cache the descriptor, both as Python object and as C++ pointer.
+  const Descriptor* descriptor =
+      PyMessageDescriptor_AsDescriptor(py_descriptor);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+  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.
+  PyDescriptorPool* py_descriptor_pool =
+      GetDescriptorPool_FromPool(descriptor->file()->pool());
+  if (py_descriptor_pool == nullptr) {
+    return nullptr;
+  }
+  newtype->py_message_factory = py_descriptor_pool->py_message_factory;
+  Py_INCREF(newtype->py_message_factory);
+
+  // Register the message in the MessageFactory.
+  // TODO(amauryfa): Move this call to MessageFactory.GetPrototype() when the
+  // MessageFactory is fully implemented in C++.
+  if (message_factory::RegisterMessageClass(newtype->py_message_factory,
+                                            descriptor, newtype) < 0) {
+    return nullptr;
+  }
+
+  // Continue with type initialization: add other descriptors, enum values...
+  if (AddDescriptors(result.get(), descriptor) < 0) {
+    return nullptr;
+  }
+  return result.release();
+}
+
+static void Dealloc(PyObject* pself) {
+  CMessageClass* self = reinterpret_cast<CMessageClass*>(pself);
+  Py_XDECREF(self->py_message_descriptor);
+  Py_XDECREF(self->py_message_factory);
+  return PyType_Type.tp_dealloc(pself);
+}
+
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  CMessageClass* self = reinterpret_cast<CMessageClass*>(pself);
+  Py_VISIT(self->py_message_descriptor);
+  Py_VISIT(self->py_message_factory);
+  return PyType_Type.tp_traverse(pself, visit, arg);
+}
+
+static int GcClear(PyObject* pself) {
+  // It's important to keep the descriptor and factory alive, until the
+  // C++ message is fully destructed.
+  return PyType_Type.tp_clear(pself);
+}
+
+// The _extensions_by_name dictionary is built on every access.
+// TODO(amauryfa): Migrate all users to pool.FindAllExtensions()
+static PyObject* GetExtensionsByName(CMessageClass *self, void *closure) {
+  if (self->message_descriptor == nullptr) {
+    // This is the base Message object, simply raise AttributeError.
+    PyErr_SetString(PyExc_AttributeError,
+                    "Base Message class has no DESCRIPTOR");
+    return nullptr;
+  }
+
+  const PyDescriptorPool* pool = self->py_message_factory->pool;
+
+  std::vector<const FieldDescriptor*> extensions;
+  pool->pool->FindAllExtensions(self->message_descriptor, &extensions);
+
+  ScopedPyObjectPtr result(PyDict_New());
+  for (int i = 0; i < extensions.size(); i++) {
+    ScopedPyObjectPtr extension(
+        PyFieldDescriptor_FromDescriptor(extensions[i]));
+    if (extension == nullptr) {
+      return nullptr;
+    }
+    if (PyDict_SetItemString(result.get(), extensions[i]->full_name().c_str(),
+                             extension.get()) < 0) {
+      return nullptr;
+    }
+  }
+  return result.release();
+}
+
+// The _extensions_by_number dictionary is built on every access.
+// TODO(amauryfa): Migrate all users to pool.FindExtensionByNumber()
+static PyObject* GetExtensionsByNumber(CMessageClass *self, void *closure) {
+  if (self->message_descriptor == nullptr) {
+    // This is the base Message object, simply raise AttributeError.
+    PyErr_SetString(PyExc_AttributeError,
+                    "Base Message class has no DESCRIPTOR");
+    return nullptr;
+  }
+
+  const PyDescriptorPool* pool = self->py_message_factory->pool;
+
+  std::vector<const FieldDescriptor*> extensions;
+  pool->pool->FindAllExtensions(self->message_descriptor, &extensions);
+
+  ScopedPyObjectPtr result(PyDict_New());
+  for (int i = 0; i < extensions.size(); i++) {
+    ScopedPyObjectPtr extension(
+        PyFieldDescriptor_FromDescriptor(extensions[i]));
+    if (extension == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr number(PyLong_FromLong(extensions[i]->number()));
+    if (number == nullptr) {
+      return nullptr;
+    }
+    if (PyDict_SetItem(result.get(), number.get(), extension.get()) < 0) {
+      return nullptr;
+    }
+  }
+  return result.release();
+}
+
+static PyGetSetDef Getters[] = {
+    {"_extensions_by_name", (getter)GetExtensionsByName, nullptr},
+    {"_extensions_by_number", (getter)GetExtensionsByNumber, nullptr},
+    {nullptr},
+};
+
+// Compute some class attributes on the fly:
+// - All the _FIELD_NUMBER attributes, for all fields and nested extensions.
+// Returns a new reference, or NULL with an exception set.
+static PyObject* GetClassAttribute(CMessageClass *self, PyObject* name) {
+  char* attr;
+  Py_ssize_t attr_size;
+  static const char kSuffix[] = "_FIELD_NUMBER";
+  if (PyString_AsStringAndSize(name, &attr, &attr_size) >= 0 &&
+      HasSuffixString(StringPiece(attr, attr_size), kSuffix)) {
+    std::string field_name(attr, attr_size - sizeof(kSuffix) + 1);
+    LowerString(&field_name);
+
+    // Try to find a field with the given name, without the suffix.
+    const FieldDescriptor* field =
+        self->message_descriptor->FindFieldByLowercaseName(field_name);
+    if (!field) {
+      // Search nested extensions as well.
+      field =
+          self->message_descriptor->FindExtensionByLowercaseName(field_name);
+    }
+    if (field) {
+      return PyLong_FromLong(field->number());
+    }
+  }
+  PyErr_SetObject(PyExc_AttributeError, name);
+  return nullptr;
+}
+
+static PyObject* GetAttr(CMessageClass* self, PyObject* name) {
+  PyObject* result = CMessageClass_Type->tp_base->tp_getattro(
+      reinterpret_cast<PyObject*>(self), name);
+  if (result != nullptr) {
+    return result;
+  }
+  if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+    return nullptr;
+  }
+
+  PyErr_Clear();
+  return GetClassAttribute(self, name);
+}
+
+}  // namespace message_meta
+
+// Protobuf has a 64MB limit built in, this variable will override this. Please
+// do not enable this unless you fully understand the implications: protobufs
+// must all be kept in memory at the same time, so if they grow too big you may
+// get OOM errors. The protobuf APIs do not provide any tools for processing
+// protobufs in chunks.  If you have protos this big you should break them up if
+// it is at all convenient to do so.
+#ifdef PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
+static bool allow_oversize_protos = true;
+#else
+static bool allow_oversize_protos = false;
+#endif
+
+static PyTypeObject _CMessageClass_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MessageMeta",         // tp_name
+    sizeof(CMessageClass),  // tp_basicsize
+    0,                      // tp_itemsize
+    message_meta::Dealloc,  // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr, /* tp_print */
+#else
+    0, /* tp_vectorcall_offset */
+#endif
+    nullptr,                              // tp_getattr
+    nullptr,                              // tp_setattr
+    nullptr,                              // tp_compare
+    nullptr,                              // tp_repr
+    nullptr,                              // tp_as_number
+    nullptr,                              // tp_as_sequence
+    nullptr,                              // tp_as_mapping
+    nullptr,                              // tp_hash
+    nullptr,                              // tp_call
+    nullptr,                              // tp_str
+    (getattrofunc)message_meta::GetAttr,  // tp_getattro
+    nullptr,                              // tp_setattro
+    nullptr,                              // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "The metaclass of ProtocolMessages",                            // tp_doc
+    message_meta::GcTraverse,  // tp_traverse
+    message_meta::GcClear,     // tp_clear
+    nullptr,                   // tp_richcompare
+    0,                         // tp_weaklistoffset
+    nullptr,                   // tp_iter
+    nullptr,                   // tp_iternext
+    nullptr,                   // tp_methods
+    nullptr,                   // tp_members
+    message_meta::Getters,     // tp_getset
+    nullptr,                   // tp_base
+    nullptr,                   // tp_dict
+    nullptr,                   // tp_descr_get
+    nullptr,                   // tp_descr_set
+    0,                         // tp_dictoffset
+    nullptr,                   // tp_init
+    nullptr,                   // tp_alloc
+    message_meta::New,         // tp_new
+};
+PyTypeObject* CMessageClass_Type = &_CMessageClass_Type;
+
+static CMessageClass* CheckMessageClass(PyTypeObject* cls) {
+  if (!PyObject_TypeCheck(cls, CMessageClass_Type)) {
+    PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
+    return nullptr;
+  }
+  return reinterpret_cast<CMessageClass*>(cls);
+}
+
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+  CMessageClass* type = CheckMessageClass(cls);
+  if (type == nullptr) {
+    return nullptr;
+  }
+  return type->message_descriptor;
+}
+
+// Forward declarations
+namespace cmessage {
+int InternalReleaseFieldByDescriptor(
+    CMessage* self,
+    const FieldDescriptor* field_descriptor);
+}  // namespace cmessage
+
+// ---------------------------------------------------------------------
+
+PyObject* EncodeError_class;
+PyObject* DecodeError_class;
+PyObject* PickleError_class;
+
+// Format an error message for unexpected types.
+// Always return with an exception set.
+void FormatTypeError(PyObject* arg, const char* expected_types) {
+  // This function is often called with an exception set.
+  // Clear it to call PyObject_Repr() in good conditions.
+  PyErr_Clear();
+  PyObject* repr = PyObject_Repr(arg);
+  if (repr) {
+    PyErr_Format(PyExc_TypeError,
+                 "%.100s has type %.100s, but expected one of: %s",
+                 PyString_AsString(repr),
+                 Py_TYPE(arg)->tp_name,
+                 expected_types);
+    Py_DECREF(repr);
+  }
+}
+
+void OutOfRangeError(PyObject* arg) {
+  PyObject *s = PyObject_Str(arg);
+  if (s) {
+    PyErr_Format(PyExc_ValueError,
+                 "Value out of range: %s",
+                 PyString_AsString(s));
+    Py_DECREF(s);
+  }
+}
+
+template<class RangeType, class ValueType>
+bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
+  if (PROTOBUF_PREDICT_FALSE(value == -1 && PyErr_Occurred())) {
+    if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+      // Replace it with the same ValueError as pure python protos instead of
+      // the default one.
+      PyErr_Clear();
+      OutOfRangeError(arg);
+    }  // Otherwise propagate existing error.
+    return false;
+  }
+  if (PROTOBUF_PREDICT_FALSE(!IsValidNumericCast<RangeType>(value))) {
+    OutOfRangeError(arg);
+    return false;
+  }
+  return true;
+}
+
+template <class T>
+bool CheckAndGetInteger(PyObject* arg, T* value) {
+  // This effectively defines an integer as "an object that can be cast as
+  // an integer and can be used as an ordinal number".
+  // This definition includes everything with a valid __index__() implementation
+  // and shouldn't cast the net too wide.
+  if (!strcmp(Py_TYPE(arg)->tp_name, "numpy.ndarray") ||
+      PROTOBUF_PREDICT_FALSE(!PyIndex_Check(arg))) {
+    FormatTypeError(arg, "int");
+    return false;
+  }
+
+  PyObject* arg_py_int = PyNumber_Index(arg);
+  if (PyErr_Occurred()) {
+    // Propagate existing error.
+    return false;
+  }
+
+  if (std::numeric_limits<T>::min() == 0) {
+    // Unsigned case.
+    unsigned PY_LONG_LONG ulong_result = PyLong_AsUnsignedLongLong(arg_py_int);
+    Py_DECREF(arg_py_int);
+    if (VerifyIntegerCastAndRange<T, unsigned PY_LONG_LONG>(arg,
+                                                            ulong_result)) {
+      *value = static_cast<T>(ulong_result);
+    } else {
+      return false;
+    }
+  } else {
+    // Signed case.
+    Py_DECREF(arg_py_int);
+    PY_LONG_LONG long_result = PyLong_AsLongLong(arg);
+    if (VerifyIntegerCastAndRange<T, PY_LONG_LONG>(arg, long_result)) {
+      *value = static_cast<T>(long_result);
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+// These are referenced by repeated_scalar_container, and must
+// be explicitly instantiated.
+template bool CheckAndGetInteger<int32>(PyObject*, int32*);
+template bool CheckAndGetInteger<int64>(PyObject*, int64*);
+template bool CheckAndGetInteger<uint32>(PyObject*, uint32*);
+template bool CheckAndGetInteger<uint64>(PyObject*, uint64*);
+
+bool CheckAndGetDouble(PyObject* arg, double* value) {
+  *value = PyFloat_AsDouble(arg);
+  if (!strcmp(Py_TYPE(arg)->tp_name, "numpy.ndarray") ||
+      PROTOBUF_PREDICT_FALSE(*value == -1 && PyErr_Occurred())) {
+    FormatTypeError(arg, "int, float");
+    return false;
+  }
+  return true;
+}
+
+bool CheckAndGetFloat(PyObject* arg, float* value) {
+  double double_value;
+  if (!CheckAndGetDouble(arg, &double_value)) {
+    return false;
+  }
+  *value = io::SafeDoubleToFloat(double_value);
+  return true;
+}
+
+bool CheckAndGetBool(PyObject* arg, bool* value) {
+  long long_value = PyLong_AsLong(arg);  // NOLINT
+  if (!strcmp(Py_TYPE(arg)->tp_name, "numpy.ndarray") ||
+      (long_value == -1 && PyErr_Occurred())) {
+    FormatTypeError(arg, "int, bool");
+    return false;
+  }
+  *value = static_cast<bool>(long_value);
+
+  return true;
+}
+
+// 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", nullptr);
+
+    // 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 nullptr;
+    }
+
+    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 nullptr;
+    }
+  } else if (!PyBytes_Check(arg)) {
+    FormatTypeError(arg, "bytes");
+    return nullptr;
+  }
+
+  PyObject* encoded_string = nullptr;
+  if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
+    if (PyBytes_Check(arg)) {
+      // The bytes were already validated as correctly encoded UTF-8 above.
+      encoded_string = arg;  // Already encoded.
+      Py_INCREF(encoded_string);
+    } else {
+      encoded_string = PyUnicode_AsEncodedString(arg, "utf-8", nullptr);
+    }
+  } else {
+    // In this case field type is "bytes".
+    encoded_string = arg;
+    Py_INCREF(encoded_string);
+  }
+
+  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() == nullptr) {
+    return false;
+  }
+
+  char* value;
+  Py_ssize_t value_len;
+  if (PyBytes_AsStringAndSize(encoded_string.get(), &value, &value_len) < 0) {
+    return false;
+  }
+
+  std::string value_string(value, value_len);
+  if (append) {
+    reflection->AddString(message, descriptor, std::move(value_string));
+  } else if (index < 0) {
+    reflection->SetString(message, descriptor, std::move(value_string));
+  } else {
+    reflection->SetRepeatedString(message, descriptor, index,
+                                  std::move(value_string));
+  }
+  return true;
+}
+
+PyObject* ToStringObject(const FieldDescriptor* descriptor,
+                         const std::string& value) {
+  if (descriptor->type() != FieldDescriptor::TYPE_STRING) {
+    return PyBytes_FromStringAndSize(value.c_str(), value.length());
+  }
+
+  PyObject* result =
+      PyUnicode_DecodeUTF8(value.c_str(), value.length(), nullptr);
+  // If the string can't be decoded in UTF-8, just return a string object that
+  // contains the raw bytes. This can't happen if the value was assigned using
+  // the members of the Python message object, but can happen if the values were
+  // parsed from the wire (binary).
+  if (result == nullptr) {
+    PyErr_Clear();
+    result = PyBytes_FromStringAndSize(value.c_str(), value.length());
+  }
+  return result;
+}
+
+bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
+                                const Message* message) {
+  if (message->GetDescriptor() == field_descriptor->containing_type()) {
+    return true;
+  }
+  PyErr_Format(PyExc_KeyError, "Field '%s' does not belong to message '%s'",
+               field_descriptor->full_name().c_str(),
+               message->GetDescriptor()->full_name().c_str());
+  return false;
+}
+
+namespace cmessage {
+
+PyMessageFactory* GetFactoryForMessage(CMessage* message) {
+  GOOGLE_DCHECK(PyObject_TypeCheck(message, CMessage_Type));
+  return reinterpret_cast<CMessageClass*>(Py_TYPE(message))->py_message_factory;
+}
+
+static int MaybeReleaseOverlappingOneofField(
+    CMessage* cmessage,
+    const FieldDescriptor* field) {
+  Message* message = cmessage->message;
+  const Reflection* reflection = message->GetReflection();
+  if (!field->containing_oneof() ||
+      !reflection->HasOneof(*message, field->containing_oneof()) ||
+      reflection->HasField(*message, field)) {
+    // No other field in this oneof, no need to release.
+    return 0;
+  }
+
+  const OneofDescriptor* oneof = field->containing_oneof();
+  const FieldDescriptor* existing_field =
+      reflection->GetOneofFieldDescriptor(*message, oneof);
+  if (existing_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Non-message fields don't need to be released.
+    return 0;
+  }
+  if (InternalReleaseFieldByDescriptor(cmessage, existing_field) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+// After a Merge, visit every sub-message that was read-only, and
+// eventually update their pointer if the Merge operation modified them.
+int FixupMessageAfterMerge(CMessage* self) {
+  if (!self->composite_fields) {
+    return 0;
+  }
+  PyMessageFactory* factory = GetFactoryForMessage(self);
+  for (const auto& item : *self->composite_fields) {
+    const FieldDescriptor* descriptor = item.first;
+    if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !descriptor->is_repeated()) {
+      CMessage* cmsg = reinterpret_cast<CMessage*>(item.second);
+      if (cmsg->read_only == false) {
+        return 0;
+      }
+      Message* message = self->message;
+      const Reflection* reflection = message->GetReflection();
+      if (reflection->HasField(*message, descriptor)) {
+        // Message used to be read_only, but is no longer. Get the new pointer
+        // and record it.
+        Message* mutable_message = reflection->MutableMessage(
+            message, descriptor, factory->message_factory);
+        cmsg->message = mutable_message;
+        cmsg->read_only = false;
+        if (FixupMessageAfterMerge(cmsg) < 0) {
+          return -1;
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+// ---------------------------------------------------------------------
+// Making a message writable
+
+int AssureWritable(CMessage* self) {
+  if (self == nullptr || !self->read_only) {
+    return 0;
+  }
+
+  // Toplevel messages are always mutable.
+  GOOGLE_DCHECK(self->parent);
+
+  if (AssureWritable(self->parent) == -1) {
+    return -1;
+  }
+  // If this message is part of a oneof, there might be a field to release in
+  // the parent.
+  if (MaybeReleaseOverlappingOneofField(self->parent,
+                                        self->parent_field_descriptor) < 0) {
+    return -1;
+  }
+
+  // Make self->message writable.
+  Message* parent_message = self->parent->message;
+  const Reflection* reflection = parent_message->GetReflection();
+  Message* mutable_message = reflection->MutableMessage(
+      parent_message, self->parent_field_descriptor,
+      GetFactoryForMessage(self->parent)->message_factory);
+  if (mutable_message == nullptr) {
+    return -1;
+  }
+  self->message = mutable_message;
+  self->read_only = false;
+
+  return 0;
+}
+
+// --- Globals:
+
+// Retrieve a C++ FieldDescriptor for an extension handle.
+const FieldDescriptor* GetExtensionDescriptor(PyObject* extension) {
+  ScopedPyObjectPtr cdescriptor;
+  if (!PyObject_TypeCheck(extension, &PyFieldDescriptor_Type)) {
+    // Most callers consider extensions as a plain dictionary.  We should
+    // allow input which is not a field descriptor, and simply pretend it does
+    // not exist.
+    PyErr_SetObject(PyExc_KeyError, extension);
+    return nullptr;
+  }
+  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 (PyUnicode_Check(value)) {
+    const EnumDescriptor* enum_descriptor = descriptor.enum_type();
+    if (enum_descriptor == nullptr) {
+      PyErr_SetString(PyExc_TypeError, "not an enum field");
+      return nullptr;
+    }
+    char* enum_label;
+    Py_ssize_t size;
+    if (PyString_AsStringAndSize(value, &enum_label, &size) < 0) {
+      return nullptr;
+    }
+    const EnumValueDescriptor* enum_value_descriptor =
+        enum_descriptor->FindValueByName(StringParam(enum_label, size));
+    if (enum_value_descriptor == nullptr) {
+      PyErr_Format(PyExc_ValueError, "unknown enum label \"%s\"", enum_label);
+      return nullptr;
+    }
+    return PyLong_FromLong(enum_value_descriptor->number());
+  }
+  Py_INCREF(value);
+  return value;
+}
+
+// Delete a slice from a repeated field.
+// The only way to remove items in C++ protos is to delete the last one,
+// so we swap items to move the deleted ones at the end, and then strip the
+// sequence.
+int DeleteRepeatedField(
+    CMessage* self,
+    const FieldDescriptor* field_descriptor,
+    PyObject* slice) {
+  Py_ssize_t length, from, to, step, slice_length;
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+  int min, max;
+  length = reflection->FieldSize(*message, field_descriptor);
+
+  if (PySlice_Check(slice)) {
+    from = to = step = slice_length = 0;
+    PySlice_GetIndicesEx(slice, length, &from, &to, &step, &slice_length);
+    if (from < to) {
+      min = from;
+      max = to - 1;
+    } else {
+      min = to + 1;
+      max = from;
+    }
+  } else {
+    from = to = PyLong_AsLong(slice);
+    if (from == -1 && PyErr_Occurred()) {
+      PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+      return -1;
+    }
+
+    if (from < 0) {
+      from = to = length + from;
+    }
+    step = 1;
+    min = max = from;
+
+    // Range check.
+    if (from < 0 || from >= length) {
+      PyErr_Format(PyExc_IndexError, "list assignment index out of range");
+      return -1;
+    }
+  }
+
+  Py_ssize_t i = from;
+  std::vector<bool> to_delete(length, false);
+  while (i >= min && i <= max) {
+    to_delete[i] = true;
+    i += step;
+  }
+
+  // Swap elements so that items to delete are at the end.
+  to = 0;
+  for (i = 0; i < length; ++i) {
+    if (!to_delete[i]) {
+      if (i != to) {
+        reflection->SwapElements(message, field_descriptor, i, to);
+      }
+      ++to;
+    }
+  }
+
+  Arena* arena = Arena::InternalGetArenaForAllocation(message);
+  GOOGLE_DCHECK_EQ(arena, nullptr)
+      << "python protobuf is expected to be allocated from heap";
+  // Remove items, starting from the end.
+  for (; length > to; length--) {
+    if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+      reflection->RemoveLast(message, field_descriptor);
+      continue;
+    }
+    // It seems that RemoveLast() is less efficient for sub-messages, and
+    // the memory is not completely released. Prefer ReleaseLast().
+    //
+    // To work around a debug hardening (PROTOBUF_FORCE_COPY_IN_RELEASE),
+    // explicitly use UnsafeArenaReleaseLast. To not break rare use cases where
+    // arena is used, we fallback to ReleaseLast (but GOOGLE_DCHECK to find/fix it).
+    //
+    // Note that arena is likely null and GOOGLE_DCHECK and ReleaesLast might be
+    // redundant. The current approach takes extra cautious path not to disrupt
+    // production.
+    Message* sub_message =
+        (arena == nullptr)
+            ? reflection->UnsafeArenaReleaseLast(message, field_descriptor)
+            : reflection->ReleaseLast(message, field_descriptor);
+    // If there is a live weak reference to an item being removed, we "Release"
+    // it, and it takes ownership of the message.
+    if (CMessage* released = self->MaybeReleaseSubMessage(sub_message)) {
+      released->message = sub_message;
+    } else {
+      // sub_message was not transferred, delete it.
+      delete sub_message;
+    }
+  }
+
+  return 0;
+}
+
+// Initializes fields of a message. Used in constructors.
+int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
+  if (args != nullptr && PyTuple_Size(args) != 0) {
+    PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
+    return -1;
+  }
+
+  if (kwargs == nullptr) {
+    return 0;
+  }
+
+  Py_ssize_t pos = 0;
+  PyObject* name;
+  PyObject* value;
+  while (PyDict_Next(kwargs, &pos, &name, &value)) {
+    if (!(PyUnicode_Check(name))) {
+      PyErr_SetString(PyExc_ValueError, "Field name must be a string");
+      return -1;
+    }
+    ScopedPyObjectPtr property(
+        PyObject_GetAttr(reinterpret_cast<PyObject*>(Py_TYPE(self)), name));
+    if (property == nullptr ||
+        !PyObject_TypeCheck(property.get(), CFieldProperty_Type)) {
+      PyErr_Format(PyExc_ValueError, "Protocol message %s has no \"%s\" field.",
+                   self->message->GetDescriptor()->name().c_str(),
+                   PyString_AsString(name));
+      return -1;
+    }
+    const FieldDescriptor* descriptor =
+        reinterpret_cast<PyMessageFieldProperty*>(property.get())
+            ->field_descriptor;
+    if (value == Py_None) {
+      // field=None is the same as no field at all.
+      continue;
+    }
+    if (descriptor->is_map()) {
+      ScopedPyObjectPtr map(GetFieldValue(self, descriptor));
+      const FieldDescriptor* value_descriptor =
+          descriptor->message_type()->map_value();
+      if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        ScopedPyObjectPtr iter(PyObject_GetIter(value));
+        if (iter == nullptr) {
+          PyErr_Format(PyExc_TypeError, "Argument %s is not iterable",
+                       PyString_AsString(name));
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
+          ScopedPyObjectPtr source_value(PyObject_GetItem(value, next.get()));
+          ScopedPyObjectPtr dest_value(PyObject_GetItem(map.get(), next.get()));
+          if (source_value.get() == nullptr || dest_value.get() == nullptr) {
+            return -1;
+          }
+          ScopedPyObjectPtr ok(PyObject_CallMethod(
+              dest_value.get(), "MergeFrom", "O", source_value.get()));
+          if (ok.get() == nullptr) {
+            return -1;
+          }
+        }
+      } else {
+        ScopedPyObjectPtr function_return;
+        function_return.reset(
+            PyObject_CallMethod(map.get(), "update", "O", value));
+        if (function_return.get() == nullptr) {
+          return -1;
+        }
+      }
+    } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+      ScopedPyObjectPtr container(GetFieldValue(self, descriptor));
+      if (container == nullptr) {
+        return -1;
+      }
+      if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        RepeatedCompositeContainer* rc_container =
+            reinterpret_cast<RepeatedCompositeContainer*>(container.get());
+        ScopedPyObjectPtr iter(PyObject_GetIter(value));
+        if (iter == nullptr) {
+          PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
+          PyObject* kwargs = (PyDict_Check(next.get()) ? next.get() : nullptr);
+          ScopedPyObjectPtr new_msg(
+              repeated_composite_container::Add(rc_container, nullptr, kwargs));
+          if (new_msg == nullptr) {
+            return -1;
+          }
+          if (kwargs == nullptr) {
+            // 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() == nullptr) {
+              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 == nullptr) {
+          PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
+          ScopedPyObjectPtr enum_value(
+              GetIntegerEnumValue(*descriptor, next.get()));
+          if (enum_value == nullptr) {
+            return -1;
+          }
+          ScopedPyObjectPtr new_msg(repeated_scalar_container::Append(
+              rs_container, enum_value.get()));
+          if (new_msg == nullptr) {
+            return -1;
+          }
+        }
+        if (PyErr_Occurred()) {
+          // Check to see how PyIter_Next() exited.
+          return -1;
+        }
+      } else {
+        if (ScopedPyObjectPtr(repeated_scalar_container::Extend(
+                reinterpret_cast<RepeatedScalarContainer*>(container.get()),
+                value)) == nullptr) {
+          return -1;
+        }
+      }
+    } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      ScopedPyObjectPtr message(GetFieldValue(self, descriptor));
+      if (message == nullptr) {
+        return -1;
+      }
+      CMessage* cmessage = reinterpret_cast<CMessage*>(message.get());
+      if (PyDict_Check(value)) {
+        // Make the message exist even if the dict is empty.
+        AssureWritable(cmessage);
+        if (InitAttributes(cmessage, nullptr, value) < 0) {
+          return -1;
+        }
+      } else {
+        ScopedPyObjectPtr merged(MergeFrom(cmessage, value));
+        if (merged == nullptr) {
+          return -1;
+        }
+      }
+    } else {
+      ScopedPyObjectPtr new_val;
+      if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        new_val.reset(GetIntegerEnumValue(*descriptor, value));
+        if (new_val == nullptr) {
+          return -1;
+        }
+        value = new_val.get();
+      }
+      if (SetFieldValue(self, descriptor, value) < 0) {
+        return -1;
+      }
+    }
+  }
+  return 0;
+}
+
+// Allocates an incomplete Python Message: the caller must fill self->message
+// and eventually self->parent.
+CMessage* NewEmptyMessage(CMessageClass* type) {
+  CMessage* self = reinterpret_cast<CMessage*>(
+      PyType_GenericAlloc(&type->super.ht_type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  self->message = nullptr;
+  self->parent = nullptr;
+  self->parent_field_descriptor = nullptr;
+  self->read_only = false;
+
+  self->composite_fields = nullptr;
+  self->child_submessages = nullptr;
+
+  self->unknown_field_set = nullptr;
+
+  return self;
+}
+
+// The __new__ method of Message classes.
+// Creates a new C++ message and takes ownership.
+static CMessage* NewCMessage(CMessageClass* type) {
+  // Retrieve the message descriptor and the default instance (=prototype).
+  const Descriptor* message_descriptor = type->message_descriptor;
+  if (message_descriptor == nullptr) {
+    // This would be very unexpected since the CMessageClass has already
+    // been checked.
+    PyErr_Format(PyExc_TypeError,
+                 "CMessageClass object '%s' has no descriptor.",
+                 Py_TYPE(type)->tp_name);
+    return nullptr;
+  }
+  const Message* prototype =
+      type->py_message_factory->message_factory->GetPrototype(
+          message_descriptor);
+  if (prototype == nullptr) {
+    PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
+    return nullptr;
+  }
+
+  CMessage* self = NewEmptyMessage(type);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  self->message = prototype->New(nullptr);  // Ensures no arena is used.
+  self->parent = nullptr;  // This message owns its data.
+  return self;
+}
+
+static PyObject* New(PyTypeObject* cls, PyObject* unused_args,
+                     PyObject* unused_kwargs) {
+  CMessageClass* type = CheckMessageClass(cls);
+  if (type == nullptr) {
+    return nullptr;
+  }
+  return reinterpret_cast<PyObject*>(NewCMessage(type));
+}
+
+// The __init__ method of Message classes.
+// It initializes fields from keywords passed to the constructor.
+static int Init(CMessage* self, PyObject* args, PyObject* kwargs) {
+  return InitAttributes(self, args, kwargs);
+}
+
+// ---------------------------------------------------------------------
+// Deallocating a CMessage
+
+static void Dealloc(CMessage* self) {
+  if (self->weakreflist) {
+    PyObject_ClearWeakRefs(reinterpret_cast<PyObject*>(self));
+  }
+  // At this point all dependent objects have been removed.
+  GOOGLE_DCHECK(!self->child_submessages || self->child_submessages->empty());
+  GOOGLE_DCHECK(!self->composite_fields || self->composite_fields->empty());
+  delete self->child_submessages;
+  delete self->composite_fields;
+  if (self->unknown_field_set) {
+    unknown_fields::Clear(
+        reinterpret_cast<PyUnknownFields*>(self->unknown_field_set));
+  }
+
+  CMessage* parent = self->parent;
+  if (!parent) {
+    // No parent, we own the message.
+    delete self->message;
+  } else if (parent->AsPyObject() == Py_None) {
+    // Message owned externally: Nothing to dealloc
+    Py_CLEAR(self->parent);
+  } else {
+    // Clear this message from its parent's map.
+    if (self->parent_field_descriptor->is_repeated()) {
+      if (parent->child_submessages)
+        parent->child_submessages->erase(self->message);
+    } else {
+      if (parent->composite_fields)
+        parent->composite_fields->erase(self->parent_field_descriptor);
+    }
+    Py_CLEAR(self->parent);
+  }
+  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+// ---------------------------------------------------------------------
+
+
+PyObject* IsInitialized(CMessage* self, PyObject* args) {
+  PyObject* errors = nullptr;
+  if (!PyArg_ParseTuple(args, "|O", &errors)) {
+    return nullptr;
+  }
+  if (self->message->IsInitialized()) {
+    Py_RETURN_TRUE;
+  }
+  if (errors != nullptr) {
+    ScopedPyObjectPtr initialization_errors(
+        FindInitializationErrors(self));
+    if (initialization_errors == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr extend_name(PyUnicode_FromString("extend"));
+    if (extend_name == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr result(PyObject_CallMethodObjArgs(
+        errors, extend_name.get(), initialization_errors.get(), nullptr));
+    if (result == nullptr) {
+      return nullptr;
+    }
+  }
+  Py_RETURN_FALSE;
+}
+
+int HasFieldByDescriptor(CMessage* self,
+                         const FieldDescriptor* field_descriptor) {
+  Message* message = self->message;
+  if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
+    return -1;
+  }
+  if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    PyErr_SetString(PyExc_KeyError,
+                    "Field is repeated. A singular method is required.");
+    return -1;
+  }
+  return message->GetReflection()->HasField(*message, field_descriptor);
+}
+
+const FieldDescriptor* FindFieldWithOneofs(const Message* message,
+                                           ConstStringParam field_name,
+                                           bool* in_oneof) {
+  *in_oneof = false;
+  const Descriptor* descriptor = message->GetDescriptor();
+  const FieldDescriptor* field_descriptor =
+      descriptor->FindFieldByName(field_name);
+  if (field_descriptor != nullptr) {
+    return field_descriptor;
+  }
+  const OneofDescriptor* oneof_desc =
+      descriptor->FindOneofByName(field_name);
+  if (oneof_desc != nullptr) {
+    *in_oneof = true;
+    return message->GetReflection()->GetOneofFieldDescriptor(*message,
+                                                             oneof_desc);
+  }
+  return nullptr;
+}
+
+bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
+  auto message_name = field_descriptor->containing_type()->name();
+  if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    PyErr_Format(PyExc_ValueError,
+                 "Protocol message %s has no singular \"%s\" field.",
+                 message_name.c_str(), field_descriptor->name().c_str());
+    return false;
+  }
+
+  if (!field_descriptor->has_presence()) {
+    PyErr_Format(PyExc_ValueError,
+                 "Can't test non-optional, non-submessage field \"%s.%s\" for "
+                 "presence in proto3.",
+                 message_name.c_str(), field_descriptor->name().c_str());
+    return false;
+  }
+
+  return true;
+}
+
+PyObject* HasField(CMessage* self, PyObject* arg) {
+  char* field_name;
+  Py_ssize_t size;
+  field_name = const_cast<char*>(PyUnicode_AsUTF8AndSize(arg, &size));
+  if (!field_name) {
+    return nullptr;
+  }
+
+  Message* message = self->message;
+  bool is_in_oneof;
+  const FieldDescriptor* field_descriptor =
+      FindFieldWithOneofs(message, StringParam(field_name, size), &is_in_oneof);
+  if (field_descriptor == nullptr) {
+    if (!is_in_oneof) {
+      PyErr_Format(PyExc_ValueError, "Protocol message %s has no field %s.",
+                   message->GetDescriptor()->name().c_str(), field_name);
+      return nullptr;
+    } else {
+      Py_RETURN_FALSE;
+    }
+  }
+
+  if (!CheckHasPresence(field_descriptor, is_in_oneof)) {
+    return nullptr;
+  }
+
+  if (message->GetReflection()->HasField(*message, field_descriptor)) {
+    Py_RETURN_TRUE;
+  }
+
+  Py_RETURN_FALSE;
+}
+
+PyObject* ClearExtension(CMessage* self, PyObject* extension) {
+  const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+  if (ClearFieldByDescriptor(self, descriptor) < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+PyObject* HasExtension(CMessage* self, PyObject* extension) {
+  const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+  int has_field = HasFieldByDescriptor(self, descriptor);
+  if (has_field < 0) {
+    return nullptr;
+  } else {
+    return PyBool_FromLong(has_field);
+  }
+}
+
+// ---------------------------------------------------------------------
+// Releasing messages
+//
+// The Python API's ClearField() and Clear() methods behave
+// differently than their C++ counterparts.  While the C++ versions
+// clears the children, the Python versions detaches the children,
+// without touching their content.  This impedance mismatch causes
+// some complexity in the implementation, which is captured in this
+// section.
+//
+// When one or multiple fields are cleared we need to:
+//
+// * Gather all child objects that need to be detached from the message.
+//   In composite_fields and child_submessages.
+//
+// * Create a new Python message of the same kind. Use SwapFields() to move
+//   data from the original message.
+//
+// * Change the parent of all child objects: update their strong reference
+//   to their parent, and move their presence in composite_fields and
+//   child_submessages.
+
+// ---------------------------------------------------------------------
+// Release a composite child of a CMessage
+
+static int InternalReparentFields(
+    CMessage* self, const std::vector<CMessage*>& messages_to_release,
+    const std::vector<ContainerBase*>& containers_to_release) {
+  if (messages_to_release.empty() && containers_to_release.empty()) {
+    return 0;
+  }
+
+  // Move all the passed sub_messages to another message.
+  CMessage* new_message = cmessage::NewEmptyMessage(self->GetMessageClass());
+  if (new_message == nullptr) {
+    return -1;
+  }
+  new_message->message = self->message->New(nullptr);
+  ScopedPyObjectPtr holder(reinterpret_cast<PyObject*>(new_message));
+  new_message->child_submessages = new CMessage::SubMessagesMap();
+  new_message->composite_fields = new CMessage::CompositeFieldsMap();
+  std::set<const FieldDescriptor*> fields_to_swap;
+
+  // In case this the removed fields are the last reference to a message, keep
+  // a reference.
+  Py_INCREF(self);
+
+  for (const auto& to_release : messages_to_release) {
+    fields_to_swap.insert(to_release->parent_field_descriptor);
+    // Reparent
+    Py_INCREF(new_message);
+    Py_DECREF(to_release->parent);
+    to_release->parent = new_message;
+    self->child_submessages->erase(to_release->message);
+    new_message->child_submessages->emplace(to_release->message, to_release);
+  }
+
+  for (const auto& to_release : containers_to_release) {
+    fields_to_swap.insert(to_release->parent_field_descriptor);
+    Py_INCREF(new_message);
+    Py_DECREF(to_release->parent);
+    to_release->parent = new_message;
+    self->composite_fields->erase(to_release->parent_field_descriptor);
+    new_message->composite_fields->emplace(to_release->parent_field_descriptor,
+                                           to_release);
+  }
+
+  if (self->message->GetArena() == new_message->message->GetArena()) {
+    MessageReflectionFriend::UnsafeShallowSwapFields(
+        self->message, new_message->message,
+        std::vector<const FieldDescriptor*>(fields_to_swap.begin(),
+                                            fields_to_swap.end()));
+  } else {
+    self->message->GetReflection()->SwapFields(
+        self->message, new_message->message,
+        std::vector<const FieldDescriptor*>(fields_to_swap.begin(),
+                                            fields_to_swap.end()));
+  }
+
+  // This might delete the Python message completely if all children were moved.
+  Py_DECREF(self);
+
+  return 0;
+}
+
+int InternalReleaseFieldByDescriptor(
+    CMessage* self,
+    const FieldDescriptor* field_descriptor) {
+  if (!field_descriptor->is_repeated() &&
+      field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Single scalars are not in any cache.
+    return 0;
+  }
+  std::vector<CMessage*> messages_to_release;
+  std::vector<ContainerBase*> containers_to_release;
+  if (self->child_submessages && field_descriptor->is_repeated() &&
+      field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    for (const auto& child_item : *self->child_submessages) {
+      if (child_item.second->parent_field_descriptor == field_descriptor) {
+        messages_to_release.push_back(child_item.second);
+      }
+    }
+  }
+  if (self->composite_fields) {
+    CMessage::CompositeFieldsMap::iterator it =
+        self->composite_fields->find(field_descriptor);
+    if (it != self->composite_fields->end()) {
+      containers_to_release.push_back(it->second);
+    }
+  }
+
+  return InternalReparentFields(self, messages_to_release,
+                                containers_to_release);
+}
+
+int ClearFieldByDescriptor(CMessage* self,
+                           const FieldDescriptor* field_descriptor) {
+  if (!CheckFieldBelongsToMessage(field_descriptor, self->message)) {
+    return -1;
+  }
+  if (InternalReleaseFieldByDescriptor(self, field_descriptor) < 0) {
+    return -1;
+  }
+  AssureWritable(self);
+  Message* message = self->message;
+  message->GetReflection()->ClearField(message, field_descriptor);
+  return 0;
+}
+
+PyObject* ClearField(CMessage* self, PyObject* arg) {
+  char* field_name;
+  Py_ssize_t field_size;
+  if (PyString_AsStringAndSize(arg, &field_name, &field_size) < 0) {
+    return nullptr;
+  }
+  AssureWritable(self);
+  bool is_in_oneof;
+  const FieldDescriptor* field_descriptor = FindFieldWithOneofs(
+      self->message, StringParam(field_name, field_size), &is_in_oneof);
+  if (field_descriptor == nullptr) {
+    if (is_in_oneof) {
+      // We gave the name of a oneof, and none of its fields are set.
+      Py_RETURN_NONE;
+    } else {
+      PyErr_Format(PyExc_ValueError,
+                   "Protocol message has no \"%s\" field.", field_name);
+      return nullptr;
+    }
+  }
+
+  if (ClearFieldByDescriptor(self, field_descriptor) < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+PyObject* Clear(CMessage* self) {
+  AssureWritable(self);
+  // Detach all current fields of this message
+  std::vector<CMessage*> messages_to_release;
+  std::vector<ContainerBase*> containers_to_release;
+  if (self->child_submessages) {
+    for (const auto& item : *self->child_submessages) {
+      messages_to_release.push_back(item.second);
+    }
+  }
+  if (self->composite_fields) {
+    for (const auto& item : *self->composite_fields) {
+      containers_to_release.push_back(item.second);
+    }
+  }
+  if (InternalReparentFields(self, messages_to_release, containers_to_release) <
+      0) {
+    return nullptr;
+  }
+  if (self->unknown_field_set) {
+    unknown_fields::Clear(
+        reinterpret_cast<PyUnknownFields*>(self->unknown_field_set));
+    self->unknown_field_set = nullptr;
+  }
+  self->message->Clear();
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+
+static std::string GetMessageName(CMessage* self) {
+  if (self->parent_field_descriptor != nullptr) {
+    return self->parent_field_descriptor->full_name();
+  } else {
+    return self->message->GetDescriptor()->full_name();
+  }
+}
+
+static PyObject* InternalSerializeToString(
+    CMessage* self, PyObject* args, PyObject* kwargs,
+    bool require_initialized) {
+  // Parse the "deterministic" kwarg; defaults to False.
+  static const char* kwlist[] = {"deterministic", nullptr};
+  PyObject* deterministic_obj = Py_None;
+  if (!PyArg_ParseTupleAndKeywords(
+          args, kwargs, "|O", const_cast<char**>(kwlist), &deterministic_obj)) {
+    return nullptr;
+  }
+  // Preemptively convert to a bool first, so we don't need to back out of
+  // allocating memory if this raises an exception.
+  // NOTE: This is unused later if deterministic == Py_None, but that's fine.
+  int deterministic = PyObject_IsTrue(deterministic_obj);
+  if (deterministic < 0) {
+    return nullptr;
+  }
+
+  if (require_initialized && !self->message->IsInitialized()) {
+    ScopedPyObjectPtr errors(FindInitializationErrors(self));
+    if (errors == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr comma(PyUnicode_FromString(","));
+    if (comma == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr joined(
+        PyObject_CallMethod(comma.get(), "join", "O", errors.get()));
+    if (joined == nullptr) {
+      return nullptr;
+    }
+
+    // TODO(haberman): this is a (hopefully temporary) hack.  The unit testing
+    // infrastructure reloads all pure-Python modules for every test, but not
+    // C++ modules (because that's generally impossible:
+    // http://bugs.python.org/issue1144263).  But if we cache EncodeError, we'll
+    // return the EncodeError from a previous load of the module, which won't
+    // match a user's attempt to catch EncodeError.  So we have to look it up
+    // again every time.
+    ScopedPyObjectPtr message_module(PyImport_ImportModule(
+        "google.protobuf.message"));
+    if (message_module.get() == nullptr) {
+      return nullptr;
+    }
+
+    ScopedPyObjectPtr encode_error(
+        PyObject_GetAttrString(message_module.get(), "EncodeError"));
+    if (encode_error.get() == nullptr) {
+      return nullptr;
+    }
+    PyErr_Format(encode_error.get(),
+                 "Message %s is missing required fields: %s",
+                 GetMessageName(self).c_str(), PyString_AsString(joined.get()));
+    return nullptr;
+  }
+
+  // Ok, arguments parsed and errors checked, now encode to a string
+  const size_t size = self->message->ByteSizeLong();
+  if (size == 0) {
+    return PyBytes_FromString("");
+  }
+
+  if (size > INT_MAX) {
+    PyErr_Format(PyExc_ValueError,
+                 "Message %s exceeds maximum protobuf "
+                 "size of 2GB: %zu",
+                 GetMessageName(self).c_str(), size);
+    return nullptr;
+  }
+
+  PyObject* result = PyBytes_FromStringAndSize(nullptr, size);
+  if (result == nullptr) {
+    return nullptr;
+  }
+  io::ArrayOutputStream out(PyBytes_AS_STRING(result), size);
+  io::CodedOutputStream coded_out(&out);
+  if (deterministic_obj != Py_None) {
+    coded_out.SetSerializationDeterministic(deterministic);
+  }
+  self->message->SerializeWithCachedSizes(&coded_out);
+  GOOGLE_CHECK(!coded_out.HadError());
+  return result;
+}
+
+static PyObject* SerializeToString(
+    CMessage* self, PyObject* args, PyObject* kwargs) {
+  return InternalSerializeToString(self, args, kwargs,
+                                   /*require_initialized=*/true);
+}
+
+static PyObject* SerializePartialToString(
+    CMessage* self, PyObject* args, PyObject* kwargs) {
+  return InternalSerializeToString(self, args, kwargs,
+                                   /*require_initialized=*/false);
+}
+
+// Formats proto fields for ascii dumps using python formatting functions where
+// appropriate.
+class PythonFieldValuePrinter : public TextFormat::FastFieldValuePrinter {
+ public:
+  // Python has some differences from C++ when printing floating point numbers.
+  //
+  // 1) Trailing .0 is always printed.
+  // 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.
+  void PrintFloat(float val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    PrintDouble(val, generator);
+  }
+  void PrintDouble(double val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    // 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(val));
+    if (!py_value.get()) {
+      return;
+    }
+
+    ScopedPyObjectPtr py_str(PyObject_Str(py_value.get()));
+    if (!py_str.get()) {
+      return;
+    }
+
+    generator->PrintString(PyString_AsString(py_str.get()));
+  }
+};
+
+static PyObject* ToStr(CMessage* self) {
+  TextFormat::Printer printer;
+  // Passes ownership
+  printer.SetDefaultFieldValuePrinter(new PythonFieldValuePrinter());
+  printer.SetHideUnknownFields(true);
+  std::string output;
+  if (!printer.PrintToString(*self->message, &output)) {
+    PyErr_SetString(PyExc_ValueError, "Unable to convert message to str");
+    return nullptr;
+  }
+  return PyUnicode_FromString(output.c_str());
+}
+
+PyObject* MergeFrom(CMessage* self, PyObject* arg) {
+  CMessage* other_message;
+  if (!PyObject_TypeCheck(arg, CMessage_Type)) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to MergeFrom() must be instance of same class: "
+                 "expected %s got %s.",
+                 self->message->GetDescriptor()->full_name().c_str(),
+                 Py_TYPE(arg)->tp_name);
+    return nullptr;
+  }
+
+  other_message = reinterpret_cast<CMessage*>(arg);
+  if (other_message->message->GetDescriptor() !=
+      self->message->GetDescriptor()) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to MergeFrom() must be instance of same class: "
+                 "expected %s got %s.",
+                 self->message->GetDescriptor()->full_name().c_str(),
+                 other_message->message->GetDescriptor()->full_name().c_str());
+    return nullptr;
+  }
+  AssureWritable(self);
+
+  self->message->MergeFrom(*other_message->message);
+  // Child message might be lazily created before MergeFrom. Make sure they
+  // are mutable at this point if child messages are really created.
+  if (FixupMessageAfterMerge(self) < 0) {
+    return nullptr;
+  }
+
+  Py_RETURN_NONE;
+}
+
+static PyObject* CopyFrom(CMessage* self, PyObject* arg) {
+  CMessage* other_message;
+  if (!PyObject_TypeCheck(arg, CMessage_Type)) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to CopyFrom() must be instance of same class: "
+                 "expected %s got %s.",
+                 self->message->GetDescriptor()->full_name().c_str(),
+                 Py_TYPE(arg)->tp_name);
+    return nullptr;
+  }
+
+  other_message = reinterpret_cast<CMessage*>(arg);
+
+  if (self == other_message) {
+    Py_RETURN_NONE;
+  }
+
+  if (other_message->message->GetDescriptor() !=
+      self->message->GetDescriptor()) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to CopyFrom() must be instance of same class: "
+                 "expected %s got %s.",
+                 self->message->GetDescriptor()->full_name().c_str(),
+                 other_message->message->GetDescriptor()->full_name().c_str());
+    return nullptr;
+  }
+
+  AssureWritable(self);
+
+  // CopyFrom on the message will not clean up self->composite_fields,
+  // which can leave us in an inconsistent state, so clear it out here.
+  (void)ScopedPyObjectPtr(Clear(self));
+
+  self->message->CopyFrom(*other_message->message);
+
+  Py_RETURN_NONE;
+}
+
+// Provide a method in the module to set allow_oversize_protos to a boolean
+// value. This method returns the newly value of allow_oversize_protos.
+PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
+  if (!arg || !PyBool_Check(arg)) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Argument to SetAllowOversizeProtos must be boolean");
+    return nullptr;
+  }
+  allow_oversize_protos = PyObject_IsTrue(arg);
+  if (allow_oversize_protos) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
+  Py_buffer data;
+  if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) < 0) {
+    return nullptr;
+  }
+
+  AssureWritable(self);
+
+  PyMessageFactory* factory = GetFactoryForMessage(self);
+  int depth = allow_oversize_protos
+                  ? INT_MAX
+                  : io::CodedInputStream::GetDefaultRecursionLimit();
+  const char* ptr;
+  internal::ParseContext ctx(
+      depth, false, &ptr,
+      StringPiece(static_cast<const char*>(data.buf), data.len));
+  PyBuffer_Release(&data);
+  ctx.data().pool = factory->pool->pool;
+  ctx.data().factory = factory->message_factory;
+
+  ptr = self->message->_InternalParse(ptr, &ctx);
+
+  // Child message might be lazily created before MergeFrom. Make sure they
+  // are mutable at this point if child messages are really created.
+  if (FixupMessageAfterMerge(self) < 0) {
+    return nullptr;
+  }
+
+  // Python makes distinction in error message, between a general parse failure
+  // and in-correct ending on a terminating tag. Hence we need to be a bit more
+  // explicit in our correctness checks.
+  if (ptr == nullptr) {
+    // Parse error.
+    PyErr_Format(
+        DecodeError_class, "Error parsing message with type '%s'",
+        self->GetMessageClass()->message_descriptor->full_name().c_str());
+    return nullptr;
+  }
+  if (ctx.BytesUntilLimit(ptr) < 0) {
+    // The parser overshot the limit.
+    PyErr_Format(
+        DecodeError_class,
+        "Error parsing message as the message exceeded the protobuf limit "
+        "with type '%s'",
+        self->GetMessageClass()->message_descriptor->full_name().c_str());
+    return nullptr;
+  }
+
+  // ctx has an explicit limit set (length of string_view), so we have to
+  // check we ended at that limit.
+  if (!ctx.EndedAtLimit()) {
+    // TODO(jieluo): Raise error and return NULL instead.
+    // b/27494216
+    PyErr_Warn(nullptr, "Unexpected end-group tag: Not all data was converted");
+    return PyLong_FromLong(data.len - ctx.BytesUntilLimit(ptr));
+  }
+  return PyLong_FromLong(data.len);
+}
+
+static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
+  if (ScopedPyObjectPtr(Clear(self)) == nullptr) {
+    return nullptr;
+  }
+  return MergeFromString(self, arg);
+}
+
+static PyObject* ByteSize(CMessage* self, PyObject* args) {
+  return PyLong_FromLong(self->message->ByteSizeLong());
+}
+
+PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle) {
+  const FieldDescriptor* descriptor =
+      GetExtensionDescriptor(extension_handle);
+  if (descriptor == nullptr) {
+    return nullptr;
+  }
+  if (!PyObject_TypeCheck(cls, CMessageClass_Type)) {
+    PyErr_Format(PyExc_TypeError, "Expected a message class, got %s",
+                 cls->ob_type->tp_name);
+    return nullptr;
+  }
+  CMessageClass *message_class = reinterpret_cast<CMessageClass*>(cls);
+  if (message_class == nullptr) {
+    return nullptr;
+  }
+  // If the extension was already registered, check that it is the same.
+  const FieldDescriptor* existing_extension =
+      message_class->py_message_factory->pool->pool->FindExtensionByNumber(
+          descriptor->containing_type(), descriptor->number());
+  if (existing_extension != nullptr && existing_extension != descriptor) {
+    PyErr_SetString(PyExc_ValueError, "Double registration of Extensions");
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* SetInParent(CMessage* self, PyObject* args) {
+  AssureWritable(self);
+  Py_RETURN_NONE;
+}
+
+static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char *name_data;
+  if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0) return nullptr;
+  const OneofDescriptor* oneof_desc =
+      self->message->GetDescriptor()->FindOneofByName(
+          StringParam(name_data, name_size));
+  if (oneof_desc == nullptr) {
+    PyErr_Format(PyExc_ValueError,
+                 "Protocol message has no oneof \"%s\" field.", name_data);
+    return nullptr;
+  }
+  const FieldDescriptor* field_in_oneof =
+      self->message->GetReflection()->GetOneofFieldDescriptor(
+          *self->message, oneof_desc);
+  if (field_in_oneof == nullptr) {
+    Py_RETURN_NONE;
+  } else {
+    const std::string& name = field_in_oneof->name();
+    return PyUnicode_FromStringAndSize(name.c_str(), name.size());
+  }
+}
+
+static PyObject* GetExtensionDict(CMessage* self, void *closure);
+
+static PyObject* ListFields(CMessage* self) {
+  std::vector<const FieldDescriptor*> fields;
+  self->message->GetReflection()->ListFields(*self->message, &fields);
+
+  // Normally, the list will be exactly the size of the fields.
+  ScopedPyObjectPtr all_fields(PyList_New(fields.size()));
+  if (all_fields == nullptr) {
+    return nullptr;
+  }
+
+  // When there are unknown extensions, the py list will *not* contain
+  // 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 (size_t i = 0; i < fields.size(); ++i) {
+    ScopedPyObjectPtr t(PyTuple_New(2));
+    if (t == nullptr) {
+      return nullptr;
+    }
+
+    if (fields[i]->is_extension()) {
+      ScopedPyObjectPtr extension_field(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
+      if (extension_field == nullptr) {
+        return nullptr;
+      }
+      // With C++ descriptors, the field can always be retrieved, but for
+      // unknown extensions which have not been imported in Python code, there
+      // is no message class and we cannot retrieve the value.
+      // TODO(amauryfa): consider building the class on the fly!
+      if (fields[i]->message_type() != nullptr &&
+          message_factory::GetMessageClass(GetFactoryForMessage(self),
+                                           fields[i]->message_type()) ==
+              nullptr) {
+        PyErr_Clear();
+        continue;
+      }
+      ScopedPyObjectPtr extensions(GetExtensionDict(self, nullptr));
+      if (extensions == nullptr) {
+        return nullptr;
+      }
+      // 'extension' reference later stolen by PyTuple_SET_ITEM.
+      PyObject* extension = PyObject_GetItem(
+          extensions.get(), extension_field.get());
+      if (extension == nullptr) {
+        return nullptr;
+      }
+      PyTuple_SET_ITEM(t.get(), 0, extension_field.release());
+      // Steals reference to 'extension'
+      PyTuple_SET_ITEM(t.get(), 1, extension);
+    } else {
+      // Normal field
+      ScopedPyObjectPtr field_descriptor(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
+      if (field_descriptor == nullptr) {
+        return nullptr;
+      }
+
+      PyObject* field_value = GetFieldValue(self, fields[i]);
+      if (field_value == nullptr) {
+        PyErr_SetString(PyExc_ValueError, fields[i]->name().c_str());
+        return nullptr;
+      }
+      PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release());
+      PyTuple_SET_ITEM(t.get(), 1, field_value);
+    }
+    PyList_SET_ITEM(all_fields.get(), actual_size, t.release());
+    ++actual_size;
+  }
+  if (static_cast<size_t>(actual_size) != fields.size() &&
+      (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), nullptr) <
+       0)) {
+    return nullptr;
+  }
+  return all_fields.release();
+}
+
+static PyObject* DiscardUnknownFields(CMessage* self) {
+  AssureWritable(self);
+  self->message->DiscardUnknownFields();
+  Py_RETURN_NONE;
+}
+
+PyObject* FindInitializationErrors(CMessage* self) {
+  Message* message = self->message;
+  std::vector<std::string> errors;
+  message->FindInitializationErrors(&errors);
+
+  PyObject* error_list = PyList_New(errors.size());
+  if (error_list == nullptr) {
+    return nullptr;
+  }
+  for (size_t i = 0; i < errors.size(); ++i) {
+    const std::string& error = errors[i];
+    PyObject* error_string =
+        PyUnicode_FromStringAndSize(error.c_str(), error.length());
+    if (error_string == nullptr) {
+      Py_DECREF(error_list);
+      return nullptr;
+    }
+    PyList_SET_ITEM(error_list, i, error_string);
+  }
+  return error_list;
+}
+
+static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) {
+  // 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;
+  } else {
+    // Otherwise, we have a CMessage whose message we can inspect.
+    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(const Message* message,
+                            const FieldDescriptor* field_descriptor) {
+  const Reflection* reflection = message->GetReflection();
+
+  if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
+    return nullptr;
+  }
+
+  PyObject* result = nullptr;
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      int32_t value = reflection->GetInt32(*message, field_descriptor);
+      result = PyLong_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      int64_t value = reflection->GetInt64(*message, field_descriptor);
+      result = PyLong_FromLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      uint32_t value = reflection->GetUInt32(*message, field_descriptor);
+      result = PyLong_FromSsize_t(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      uint64_t value = reflection->GetUInt64(*message, field_descriptor);
+      result = PyLong_FromUnsignedLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value = reflection->GetFloat(*message, field_descriptor);
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value = reflection->GetDouble(*message, field_descriptor);
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      bool value = reflection->GetBool(*message, field_descriptor);
+      result = PyBool_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      std::string scratch;
+      const std::string& value =
+          reflection->GetStringReference(*message, field_descriptor, &scratch);
+      result = ToStringObject(field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      const EnumValueDescriptor* enum_value =
+          message->GetReflection()->GetEnum(*message, field_descriptor);
+      result = PyLong_FromLong(enum_value->number());
+      break;
+    }
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Getting a value from a field of unknown type %d",
+          field_descriptor->cpp_type());
+  }
+
+  return result;
+}
+
+CMessage* InternalGetSubMessage(
+    CMessage* self, const FieldDescriptor* field_descriptor) {
+  const Reflection* reflection = self->message->GetReflection();
+  PyMessageFactory* factory = GetFactoryForMessage(self);
+
+  CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
+      factory, field_descriptor->message_type());
+  ScopedPyObjectPtr message_class_owner(
+      reinterpret_cast<PyObject*>(message_class));
+  if (message_class == nullptr) {
+    return nullptr;
+  }
+
+  CMessage* cmsg = cmessage::NewEmptyMessage(message_class);
+  if (cmsg == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(self);
+  cmsg->parent = self;
+  cmsg->parent_field_descriptor = field_descriptor;
+  if (reflection->HasField(*self->message, field_descriptor)) {
+    // Force triggering MutableMessage to set the lazy message 'Dirty'
+    if (MessageReflectionFriend::IsLazyField(reflection, *self->message,
+                                             field_descriptor)) {
+      Message* sub_message = reflection->MutableMessage(
+          self->message, field_descriptor, factory->message_factory);
+      cmsg->read_only = false;
+      cmsg->message = sub_message;
+      return cmsg;
+    }
+  } else {
+    cmsg->read_only = true;
+  }
+  const Message& sub_message = reflection->GetMessage(
+      *self->message, field_descriptor, factory->message_factory);
+  cmsg->message = const_cast<Message*>(&sub_message);
+  return cmsg;
+}
+
+int InternalSetNonOneofScalar(
+    Message* message,
+    const FieldDescriptor* field_descriptor,
+    PyObject* arg) {
+  const Reflection* reflection = message->GetReflection();
+
+  if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
+    return -1;
+  }
+
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(arg, value, -1);
+      reflection->SetInt32(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(arg, value, -1);
+      reflection->SetInt64(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(arg, value, -1);
+      reflection->SetUInt32(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(arg, value, -1);
+      reflection->SetUInt64(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
+      reflection->SetFloat(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
+      reflection->SetDouble(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(arg, value, -1);
+      reflection->SetBool(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      if (!CheckAndSetString(
+          arg, message, field_descriptor, reflection, false, -1)) {
+        return -1;
+      }
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      GOOGLE_CHECK_GET_INT32(arg, value, -1);
+      if (reflection->SupportsUnknownEnumValues()) {
+        reflection->SetEnumValue(message, field_descriptor, value);
+      } else {
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != nullptr) {
+          reflection->SetEnum(message, field_descriptor, enum_value);
+        } else {
+          PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
+          return -1;
+        }
+      }
+      break;
+    }
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Setting value to a field of unknown type %d",
+          field_descriptor->cpp_type());
+      return -1;
+  }
+
+  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), nullptr);
+  if (py_cmsg == nullptr) {
+    return nullptr;
+  }
+  CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
+
+  ScopedPyObjectPtr py_length(MergeFromString(cmsg, serialized));
+  if (py_length == nullptr) {
+    Py_DECREF(py_cmsg);
+    return nullptr;
+  }
+
+  return py_cmsg;
+}
+
+PyObject* DeepCopy(CMessage* self, PyObject* arg) {
+  PyObject* clone =
+      PyObject_CallObject(reinterpret_cast<PyObject*>(Py_TYPE(self)), nullptr);
+  if (clone == nullptr) {
+    return nullptr;
+  }
+  if (!PyObject_TypeCheck(clone, CMessage_Type)) {
+    Py_DECREF(clone);
+    return nullptr;
+  }
+  if (ScopedPyObjectPtr(MergeFrom(reinterpret_cast<CMessage*>(clone),
+                                  reinterpret_cast<PyObject*>(self))) ==
+      nullptr) {
+    Py_DECREF(clone);
+    return nullptr;
+  }
+  return clone;
+}
+
+PyObject* ToUnicode(CMessage* self) {
+  // Lazy import to prevent circular dependencies
+  ScopedPyObjectPtr text_format(
+      PyImport_ImportModule("google.protobuf.text_format"));
+  if (text_format == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr method_name(PyUnicode_FromString("MessageToString"));
+  if (method_name == nullptr) {
+    return nullptr;
+  }
+  Py_INCREF(Py_True);
+  ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(
+      text_format.get(), method_name.get(), self, Py_True, nullptr));
+  Py_DECREF(Py_True);
+  if (encoded == nullptr) {
+    return nullptr;
+  }
+  PyObject* decoded =
+      PyUnicode_FromEncodedObject(encoded.get(), "utf-8", nullptr);
+  if (decoded == nullptr) {
+    return nullptr;
+  }
+  return decoded;
+}
+
+// CMessage static methods:
+PyObject* _CheckCalledFromGeneratedFile(PyObject* unused,
+                                        PyObject* unused_arg) {
+  if (!_CalledFromGeneratedFile(1)) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Descriptors should not be created directly, "
+                    "but only retrieved from their parent.");
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* GetExtensionDict(CMessage* self, void *closure) {
+  // 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()) {
+    PyErr_SetNone(PyExc_AttributeError);
+    return nullptr;
+  }
+  if (!self->composite_fields) {
+    self->composite_fields = new CMessage::CompositeFieldsMap();
+  }
+  if (!self->composite_fields) {
+    return nullptr;
+  }
+  ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
+  return reinterpret_cast<PyObject*>(extension_dict);
+}
+
+static PyObject* GetUnknownFields(CMessage* self) {
+  if (self->unknown_field_set == nullptr) {
+    self->unknown_field_set = unknown_fields::NewPyUnknownFields(self);
+  } else {
+    Py_INCREF(self->unknown_field_set);
+  }
+  return self->unknown_field_set;
+}
+
+static PyObject* GetExtensionsByName(CMessage *self, void *closure) {
+  return message_meta::GetExtensionsByName(
+      reinterpret_cast<CMessageClass*>(Py_TYPE(self)), closure);
+}
+
+static PyObject* GetExtensionsByNumber(CMessage *self, void *closure) {
+  return message_meta::GetExtensionsByNumber(
+      reinterpret_cast<CMessageClass*>(Py_TYPE(self)), closure);
+}
+
+static PyGetSetDef Getters[] = {
+    {"Extensions", (getter)GetExtensionDict, nullptr, "Extension dict"},
+    {"_extensions_by_name", (getter)GetExtensionsByName, nullptr},
+    {"_extensions_by_number", (getter)GetExtensionsByNumber, nullptr},
+    {nullptr},
+};
+
+static PyMethodDef Methods[] = {
+    {"__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+     "Makes a deep copy of the class."},
+    {"__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
+     "Outputs a unicode representation of the message."},
+    {"ByteSize", (PyCFunction)ByteSize, METH_NOARGS,
+     "Returns the size of the message in bytes."},
+    {"Clear", (PyCFunction)Clear, METH_NOARGS, "Clears the message."},
+    {"ClearExtension", (PyCFunction)ClearExtension, METH_O,
+     "Clears a message field."},
+    {"ClearField", (PyCFunction)ClearField, METH_O, "Clears a message field."},
+    {"CopyFrom", (PyCFunction)CopyFrom, METH_O,
+     "Copies a protocol message into the current message."},
+    {"DiscardUnknownFields", (PyCFunction)DiscardUnknownFields, METH_NOARGS,
+     "Discards the unknown fields."},
+    {"FindInitializationErrors", (PyCFunction)FindInitializationErrors,
+     METH_NOARGS, "Finds unset required fields."},
+    {"FromString", (PyCFunction)FromString, METH_O | METH_CLASS,
+     "Creates new method instance from given serialized data."},
+    {"HasExtension", (PyCFunction)HasExtension, METH_O,
+     "Checks if a message field is set."},
+    {"HasField", (PyCFunction)HasField, METH_O,
+     "Checks if a message field is set."},
+    {"IsInitialized", (PyCFunction)IsInitialized, METH_VARARGS,
+     "Checks if all required fields of a protocol message are set."},
+    {"ListFields", (PyCFunction)ListFields, METH_NOARGS,
+     "Lists all set fields of a message."},
+    {"MergeFrom", (PyCFunction)MergeFrom, METH_O,
+     "Merges a protocol message into the current message."},
+    {"MergeFromString", (PyCFunction)MergeFromString, METH_O,
+     "Merges a serialized message into the current message."},
+    {"ParseFromString", (PyCFunction)ParseFromString, METH_O,
+     "Parses a serialized message into the current message."},
+    {"RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS,
+     "Registers an extension with the current message."},
+    {"SerializePartialToString", (PyCFunction)SerializePartialToString,
+     METH_VARARGS | METH_KEYWORDS,
+     "Serializes the message to a string, even if it isn't initialized."},
+    {"SerializeToString", (PyCFunction)SerializeToString,
+     METH_VARARGS | METH_KEYWORDS,
+     "Serializes the message to a string, only for initialized messages."},
+    {"SetInParent", (PyCFunction)SetInParent, METH_NOARGS,
+     "Sets the has bit of the given field in its parent message."},
+    {"UnknownFields", (PyCFunction)GetUnknownFields, METH_NOARGS,
+     "Parse unknown field set"},
+    {"WhichOneof", (PyCFunction)WhichOneof, METH_O,
+     "Returns the name of the field set inside a oneof, "
+     "or None if no field is set."},
+
+    // Static Methods.
+    {"_CheckCalledFromGeneratedFile",
+     (PyCFunction)_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC,
+     "Raises TypeError if the caller is not in a _pb2.py file."},
+    {nullptr, nullptr}};
+
+bool SetCompositeField(CMessage* self, const FieldDescriptor* field,
+                       ContainerBase* value) {
+  if (self->composite_fields == nullptr) {
+    self->composite_fields = new CMessage::CompositeFieldsMap();
+  }
+  (*self->composite_fields)[field] = value;
+  return true;
+}
+
+bool SetSubmessage(CMessage* self, CMessage* submessage) {
+  if (self->child_submessages == nullptr) {
+    self->child_submessages = new CMessage::SubMessagesMap();
+  }
+  (*self->child_submessages)[submessage->message] = submessage;
+  return true;
+}
+
+PyObject* GetAttr(PyObject* pself, PyObject* name) {
+  CMessage* self = reinterpret_cast<CMessage*>(pself);
+  PyObject* result = PyObject_GenericGetAttr(
+      reinterpret_cast<PyObject*>(self), name);
+  if (result != nullptr) {
+    return result;
+  }
+  if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+    return nullptr;
+  }
+
+  PyErr_Clear();
+  return message_meta::GetClassAttribute(
+      CheckMessageClass(Py_TYPE(self)), name);
+}
+
+PyObject* GetFieldValue(CMessage* self,
+                        const FieldDescriptor* field_descriptor) {
+  if (self->composite_fields) {
+    CMessage::CompositeFieldsMap::iterator it =
+        self->composite_fields->find(field_descriptor);
+    if (it != self->composite_fields->end()) {
+      ContainerBase* value = it->second;
+      Py_INCREF(value);
+      return value->AsPyObject();
+    }
+  }
+
+  if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
+    PyErr_Format(PyExc_TypeError,
+                 "descriptor to field '%s' doesn't apply to '%s' object",
+                 field_descriptor->full_name().c_str(),
+                 Py_TYPE(self)->tp_name);
+    return nullptr;
+  }
+
+  if (!field_descriptor->is_repeated() &&
+      field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    return InternalGetScalar(self->message, field_descriptor);
+  }
+
+  ContainerBase* py_container = nullptr;
+  if (field_descriptor->is_map()) {
+    const Descriptor* entry_type = field_descriptor->message_type();
+    const FieldDescriptor* value_type = entry_type->map_value();
+    if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      CMessageClass* value_class = message_factory::GetMessageClass(
+          GetFactoryForMessage(self), value_type->message_type());
+      if (value_class == nullptr) {
+        return nullptr;
+      }
+      py_container =
+          NewMessageMapContainer(self, field_descriptor, value_class);
+    } else {
+      py_container = NewScalarMapContainer(self, field_descriptor);
+    }
+  } else if (field_descriptor->is_repeated()) {
+    if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      CMessageClass* message_class = message_factory::GetMessageClass(
+          GetFactoryForMessage(self), field_descriptor->message_type());
+      if (message_class == nullptr) {
+        return nullptr;
+      }
+      py_container = repeated_composite_container::NewContainer(
+          self, field_descriptor, message_class);
+    } else {
+      py_container =
+          repeated_scalar_container::NewContainer(self, field_descriptor);
+    }
+  } else if (field_descriptor->cpp_type() ==
+             FieldDescriptor::CPPTYPE_MESSAGE) {
+    py_container = InternalGetSubMessage(self, field_descriptor);
+  } else {
+    PyErr_SetString(PyExc_SystemError, "Should never happen");
+  }
+
+  if (py_container == nullptr) {
+    return nullptr;
+  }
+  if (!SetCompositeField(self, field_descriptor, py_container)) {
+    Py_DECREF(py_container);
+    return nullptr;
+  }
+  return py_container->AsPyObject();
+}
+
+int SetFieldValue(CMessage* self, const FieldDescriptor* field_descriptor,
+                  PyObject* value) {
+  if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
+    PyErr_Format(PyExc_TypeError,
+                 "descriptor to field '%s' doesn't apply to '%s' object",
+                 field_descriptor->full_name().c_str(),
+                 Py_TYPE(self)->tp_name);
+    return -1;
+  } else if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    PyErr_Format(PyExc_AttributeError,
+                 "Assignment not allowed to repeated "
+                 "field \"%s\" in protocol message object.",
+                 field_descriptor->name().c_str());
+    return -1;
+  } else if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    PyErr_Format(PyExc_AttributeError,
+                 "Assignment not allowed to "
+                 "field \"%s\" in protocol message object.",
+                 field_descriptor->name().c_str());
+    return -1;
+  } else {
+    AssureWritable(self);
+    return InternalSetScalar(self, field_descriptor, value);
+  }
+}
+
+}  // namespace cmessage
+
+// All containers which are not messages:
+// - Make a new parent message
+// - Copy the field
+// - return the field.
+PyObject* ContainerBase::DeepCopy() {
+  CMessage* new_parent =
+      cmessage::NewEmptyMessage(this->parent->GetMessageClass());
+  new_parent->message = this->parent->message->New(nullptr);
+
+  // Copy the map field into the new message.
+  this->parent->message->GetReflection()->SwapFields(
+      this->parent->message, new_parent->message,
+      {this->parent_field_descriptor});
+  this->parent->message->MergeFrom(*new_parent->message);
+
+  PyObject* result =
+      cmessage::GetFieldValue(new_parent, this->parent_field_descriptor);
+  Py_DECREF(new_parent);
+  return result;
+}
+
+void ContainerBase::RemoveFromParentCache() {
+  CMessage* parent = this->parent;
+  if (parent) {
+    if (parent->composite_fields)
+      parent->composite_fields->erase(this->parent_field_descriptor);
+    Py_CLEAR(parent);
+  }
+}
+
+CMessage* CMessage::BuildSubMessageFromPointer(
+    const FieldDescriptor* field_descriptor, Message* sub_message,
+    CMessageClass* message_class) {
+  if (!this->child_submessages) {
+    this->child_submessages = new CMessage::SubMessagesMap();
+  }
+  CMessage* cmsg = FindPtrOrNull(
+      *this->child_submessages, sub_message);
+  if (cmsg) {
+    Py_INCREF(cmsg);
+  } else {
+    cmsg = cmessage::NewEmptyMessage(message_class);
+
+    if (cmsg == nullptr) {
+      return nullptr;
+    }
+    cmsg->message = sub_message;
+    Py_INCREF(this);
+    cmsg->parent = this;
+    cmsg->parent_field_descriptor = field_descriptor;
+    cmessage::SetSubmessage(this, cmsg);
+  }
+  return cmsg;
+}
+
+CMessage* CMessage::MaybeReleaseSubMessage(Message* sub_message) {
+  if (!this->child_submessages) {
+    return nullptr;
+  }
+  CMessage* released = FindPtrOrNull(
+      *this->child_submessages, sub_message);
+  if (!released) {
+    return nullptr;
+  }
+  // The target message will now own its content.
+  Py_CLEAR(released->parent);
+  released->parent_field_descriptor = nullptr;
+  released->read_only = false;
+  // Delete it from the cache.
+  this->child_submessages->erase(sub_message);
+  return released;
+}
+
+static CMessageClass _CMessage_Type = {{{
+    PyVarObject_HEAD_INIT(&_CMessageClass_Type, 0) FULL_MODULE_NAME
+    ".CMessage",                    // tp_name
+    sizeof(CMessage),               // tp_basicsize
+    0,                              //  tp_itemsize
+    (destructor)cmessage::Dealloc,  //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                      //  tp_getattr
+    nullptr,                      //  tp_setattr
+    nullptr,                      //  tp_compare
+    (reprfunc)cmessage::ToStr,    //  tp_repr
+    nullptr,                      //  tp_as_number
+    nullptr,                      //  tp_as_sequence
+    nullptr,                      //  tp_as_mapping
+    PyObject_HashNotImplemented,  //  tp_hash
+    nullptr,                      //  tp_call
+    (reprfunc)cmessage::ToStr,    //  tp_str
+    cmessage::GetAttr,            //  tp_getattro
+    nullptr,                      //  tp_setattro
+    nullptr,                      //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+        Py_TPFLAGS_HAVE_VERSION_TAG,     //  tp_flags
+    "A ProtocolMessage",                 //  tp_doc
+    nullptr,                             //  tp_traverse
+    nullptr,                             //  tp_clear
+    (richcmpfunc)cmessage::RichCompare,  //  tp_richcompare
+    offsetof(CMessage, weakreflist),     //  tp_weaklistoffset
+    nullptr,                             //  tp_iter
+    nullptr,                             //  tp_iternext
+    cmessage::Methods,                   //  tp_methods
+    nullptr,                             //  tp_members
+    cmessage::Getters,                   //  tp_getset
+    nullptr,                             //  tp_base
+    nullptr,                             //  tp_dict
+    nullptr,                             //  tp_descr_get
+    nullptr,                             //  tp_descr_set
+    0,                                   //  tp_dictoffset
+    (initproc)cmessage::Init,            //  tp_init
+    nullptr,                             //  tp_alloc
+    cmessage::New,                       //  tp_new
+}}};
+PyTypeObject* CMessage_Type = &_CMessage_Type.super.ht_type;
+
+// --- Exposing the C proto living inside Python proto to C code:
+
+const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
+Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);
+
+static const Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
+  const Message* message = PyMessage_GetMessagePointer(msg);
+  if (message == nullptr) {
+    PyErr_Clear();
+    return nullptr;
+  }
+  return message;
+}
+
+static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
+  Message* message = PyMessage_GetMutableMessagePointer(msg);
+  if (message == nullptr) {
+    PyErr_Clear();
+    return nullptr;
+  }
+  return message;
+}
+
+const Message* PyMessage_GetMessagePointer(PyObject* msg) {
+  if (!PyObject_TypeCheck(msg, CMessage_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a Message instance");
+    return nullptr;
+  }
+  CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
+  return cmsg->message;
+}
+
+Message* PyMessage_GetMutableMessagePointer(PyObject* msg) {
+  if (!PyObject_TypeCheck(msg, CMessage_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a Message instance");
+    return nullptr;
+  }
+  CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
+
+
+  if ((cmsg->composite_fields && !cmsg->composite_fields->empty()) ||
+      (cmsg->child_submessages && !cmsg->child_submessages->empty())) {
+    // There is currently no way of accurately syncing arbitrary changes to
+    // the underlying C++ message back to the CMessage (e.g. removed repeated
+    // composite containers). We only allow direct mutation of the underlying
+    // C++ message if there is no child data in the CMessage.
+    PyErr_SetString(PyExc_ValueError,
+                    "Cannot reliably get a mutable pointer "
+                    "to a message with extra references");
+    return nullptr;
+  }
+  cmessage::AssureWritable(cmsg);
+  return cmsg->message;
+}
+
+// Returns a new reference to the MessageClass to use for message creation.
+// - if a PyMessageFactory is passed, use it.
+// - Otherwise, if a PyDescriptorPool was created, use its factory.
+static CMessageClass* GetMessageClassFromDescriptor(
+    const Descriptor* descriptor, PyObject* py_message_factory) {
+  PyMessageFactory* factory = nullptr;
+  if (py_message_factory == nullptr) {
+    PyDescriptorPool* pool =
+        GetDescriptorPool_FromPool(descriptor->file()->pool());
+    if (pool == nullptr) {
+      PyErr_SetString(PyExc_TypeError,
+                      "Unknown descriptor pool; C++ users should call "
+                      "DescriptorPool_FromPool and keep it alive");
+      return nullptr;
+    }
+    factory = pool->py_message_factory;
+  } else if (PyObject_TypeCheck(py_message_factory, &PyMessageFactory_Type)) {
+    factory = reinterpret_cast<PyMessageFactory*>(py_message_factory);
+  } else {
+    PyErr_SetString(PyExc_TypeError, "Expected a MessageFactory");
+    return nullptr;
+  }
+
+  return message_factory::GetOrCreateMessageClass(factory, descriptor);
+}
+
+PyObject* PyMessage_New(const Descriptor* descriptor,
+                        PyObject* py_message_factory) {
+  CMessageClass* message_class =
+      GetMessageClassFromDescriptor(descriptor, py_message_factory);
+  if (message_class == nullptr) {
+    return nullptr;
+  }
+
+  CMessage* self = cmessage::NewCMessage(message_class);
+  Py_DECREF(message_class);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  return self->AsPyObject();
+}
+
+PyObject* PyMessage_NewMessageOwnedExternally(Message* message,
+                                              PyObject* py_message_factory) {
+  CMessageClass* message_class = GetMessageClassFromDescriptor(
+      message->GetDescriptor(), py_message_factory);
+  if (message_class == nullptr) {
+    return nullptr;
+  }
+
+  CMessage* self = cmessage::NewEmptyMessage(message_class);
+  Py_DECREF(message_class);
+  if (self == nullptr) {
+    return nullptr;
+  }
+  self->message = message;
+  Py_INCREF(Py_None);
+  self->parent = reinterpret_cast<CMessage*>(Py_None);
+  return self->AsPyObject();
+}
+
+void InitGlobals() {
+  // TODO(gps): Check all return values in this function for NULL and propagate
+  // the error (MemoryError) on up to result in an import failure.  These should
+  // also be freed and reset to NULL during finalization.
+  kDESCRIPTOR = PyUnicode_FromString("DESCRIPTOR");
+
+  PyObject* dummy_obj = PySet_New(nullptr);
+  kEmptyWeakref = PyWeakref_NewRef(dummy_obj, nullptr);
+  Py_DECREF(dummy_obj);
+}
+
+bool InitProto2MessageModule(PyObject *m) {
+  // Initialize types and globals in descriptor.cc
+  if (!InitDescriptor()) {
+    return false;
+  }
+
+  // Initialize types and globals in descriptor_pool.cc
+  if (!InitDescriptorPool()) {
+    return false;
+  }
+
+  // Initialize types and globals in message_factory.cc
+  if (!InitMessageFactory()) {
+    return false;
+  }
+
+  // Initialize constants defined in this file.
+  InitGlobals();
+
+  CMessageClass_Type->tp_base = &PyType_Type;
+  if (PyType_Ready(CMessageClass_Type) < 0) {
+    return false;
+  }
+  PyModule_AddObject(m, "MessageMeta",
+                     reinterpret_cast<PyObject*>(CMessageClass_Type));
+
+  if (PyType_Ready(CMessage_Type) < 0) {
+    return false;
+  }
+  if (PyType_Ready(CFieldProperty_Type) < 0) {
+    return false;
+  }
+
+  // DESCRIPTOR is set on each protocol buffer message class elsewhere, but set
+  // it here as well to document that subclasses need to set it.
+  PyDict_SetItem(CMessage_Type->tp_dict, kDESCRIPTOR, Py_None);
+  // Invalidate any cached data for the CMessage type.
+  // This call is necessary to correctly support Py_TPFLAGS_HAVE_VERSION_TAG,
+  // after we have modified CMessage_Type.tp_dict.
+  PyType_Modified(CMessage_Type);
+
+  PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(CMessage_Type));
+
+  // 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 MutableSequence.
+    ScopedPyObjectPtr collections(PyImport_ImportModule("collections.abc"));
+    if (collections == nullptr) {
+      return false;
+    }
+    ScopedPyObjectPtr mutable_sequence(
+        PyObject_GetAttrString(collections.get(), "MutableSequence"));
+    if (mutable_sequence == nullptr) {
+      return false;
+    }
+    if (ScopedPyObjectPtr(
+            PyObject_CallMethod(mutable_sequence.get(), "register", "O",
+                                &RepeatedScalarContainer_Type)) == nullptr) {
+      return false;
+    }
+    if (ScopedPyObjectPtr(
+            PyObject_CallMethod(mutable_sequence.get(), "register", "O",
+                                &RepeatedCompositeContainer_Type)) == nullptr) {
+      return false;
+    }
+  }
+
+  if (PyType_Ready(&PyUnknownFields_Type) < 0) {
+    return false;
+  }
+
+  if (PyType_Ready(&PyUnknownFieldSet_Type) < 0) {
+    return false;
+  }
+
+  PyModule_AddObject(m, "UnknownFieldSet",
+                     reinterpret_cast<PyObject*>(&PyUnknownFieldSet_Type));
+
+  if (PyType_Ready(&PyUnknownFieldRef_Type) < 0) {
+    return false;
+  }
+
+  if (PyType_Ready(&PyUnknownField_Type) < 0) {
+    return false;
+  }
+
+  // Initialize Map container types.
+  if (!InitMapContainers()) {
+    return false;
+  }
+  PyModule_AddObject(m, "ScalarMapContainer",
+                     reinterpret_cast<PyObject*>(ScalarMapContainer_Type));
+  PyModule_AddObject(m, "MessageMapContainer",
+                     reinterpret_cast<PyObject*>(MessageMapContainer_Type));
+  PyModule_AddObject(m, "MapIterator",
+                     reinterpret_cast<PyObject*>(&MapIterator_Type));
+
+  if (PyType_Ready(&ExtensionDict_Type) < 0) {
+    return false;
+  }
+  PyModule_AddObject(m, "ExtensionDict",
+                     reinterpret_cast<PyObject*>(&ExtensionDict_Type));
+  if (PyType_Ready(&ExtensionIterator_Type) < 0) {
+    return false;
+  }
+  PyModule_AddObject(m, "ExtensionIterator",
+                     reinterpret_cast<PyObject*>(&ExtensionIterator_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));
+  PyModule_AddObject(m, "Descriptor",
+                     reinterpret_cast<PyObject*>(&PyMessageDescriptor_Type));
+  PyModule_AddObject(m, "FieldDescriptor",
+                     reinterpret_cast<PyObject*>(&PyFieldDescriptor_Type));
+  PyModule_AddObject(m, "EnumDescriptor",
+                     reinterpret_cast<PyObject*>(&PyEnumDescriptor_Type));
+  PyModule_AddObject(m, "EnumValueDescriptor",
+                     reinterpret_cast<PyObject*>(&PyEnumValueDescriptor_Type));
+  PyModule_AddObject(m, "FileDescriptor",
+                     reinterpret_cast<PyObject*>(&PyFileDescriptor_Type));
+  PyModule_AddObject(m, "OneofDescriptor",
+                     reinterpret_cast<PyObject*>(&PyOneofDescriptor_Type));
+  PyModule_AddObject(m, "ServiceDescriptor",
+                     reinterpret_cast<PyObject*>(&PyServiceDescriptor_Type));
+  PyModule_AddObject(m, "MethodDescriptor",
+                     reinterpret_cast<PyObject*>(&PyMethodDescriptor_Type));
+
+  PyObject* enum_type_wrapper = PyImport_ImportModule(
+      "google.protobuf.internal.enum_type_wrapper");
+  if (enum_type_wrapper == nullptr) {
+    return false;
+  }
+  EnumTypeWrapper_class =
+      PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper");
+  Py_DECREF(enum_type_wrapper);
+
+  PyObject* message_module = PyImport_ImportModule(
+      "google.protobuf.message");
+  if (message_module == nullptr) {
+    return false;
+  }
+  EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError");
+  DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError");
+  PythonMessage_class = PyObject_GetAttrString(message_module, "Message");
+  Py_DECREF(message_module);
+
+  PyObject* pickle_module = PyImport_ImportModule("pickle");
+  if (pickle_module == nullptr) {
+    return false;
+  }
+  PickleError_class = PyObject_GetAttrString(pickle_module, "PickleError");
+  Py_DECREF(pickle_module);
+
+  // Override {Get,Mutable}CProtoInsidePyProto.
+  GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl;
+  MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl;
+
+  return true;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
new file mode 100644
index 0000000..b17daa5
--- /dev/null
+++ b/python/google/protobuf/pyext/message.h
@@ -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.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class Reflection;
+class FieldDescriptor;
+class Descriptor;
+class DescriptorPool;
+class MessageFactory;
+
+namespace python {
+
+struct ExtensionDict;
+struct PyMessageFactory;
+struct CMessageClass;
+
+// Most of the complexity of the Message class comes from the "Release"
+// behavior:
+//
+// When a field is cleared, it is only detached from its message. Existing
+// references to submessages, to repeated container etc. won't see any change,
+// as if the data was effectively managed by these containers.
+//
+// ExtensionDicts and UnknownFields containers do NOT follow this rule. They
+// don't store any data, and always refer to their parent message.
+
+struct ContainerBase {
+  PyObject_HEAD;
+
+  // Strong reference to a parent message object. For a CMessage there are three
+  // cases:
+  // - For a top-level message, this pointer is NULL.
+  // - For a sub-message, this points to the parent message.
+  // - For a message managed externally, this is a owned reference to Py_None.
+  //
+  // For all other types: repeated containers, maps, it always point to a
+  // valid parent CMessage.
+  struct CMessage* parent;
+
+  // If this object belongs to a parent message, describes which field it comes
+  // from.
+  // The pointer is owned by the DescriptorPool (which is kept alive
+  // through the message's Python class)
+  const FieldDescriptor* parent_field_descriptor;
+
+  PyObject* AsPyObject() { return reinterpret_cast<PyObject*>(this); }
+
+  // The Three methods below are only used by Repeated containers, and Maps.
+
+  // This implementation works for all containers which have a parent.
+  PyObject* DeepCopy();
+  // Delete this container object from its parent. Does not work for messages.
+  void RemoveFromParentCache();
+};
+
+typedef struct CMessage : public ContainerBase {
+  // Pointer to the C++ Message object for this CMessage.
+  // - If this object has no parent, we own this pointer.
+  // - If this object has a parent message, the parent owns this pointer.
+  Message* message;
+
+  // Indicates this submessage is pointing to a default instance of a message.
+  // Submessages are always first created as read only messages and are then
+  // made writable, at which point this field is set to false.
+  bool read_only;
+
+  // A mapping indexed by field, containing weak references to contained objects
+  // which need to implement the "Release" mechanism:
+  // direct submessages, RepeatedCompositeContainer, RepeatedScalarContainer
+  // and MapContainer.
+  typedef std::unordered_map<const FieldDescriptor*, ContainerBase*>
+      CompositeFieldsMap;
+  CompositeFieldsMap* composite_fields;
+
+  // A mapping containing weak references to indirect child messages, accessed
+  // through containers: repeated messages, and values of message maps.
+  // This avoid the creation of similar maps in each of those containers.
+  typedef std::unordered_map<const Message*, CMessage*> SubMessagesMap;
+  SubMessagesMap* child_submessages;
+
+  // A reference to PyUnknownFields.
+  PyObject* unknown_field_set;
+
+  // Implements the "weakref" protocol for this object.
+  PyObject* weakreflist;
+
+  // Return a *borrowed* reference to the message class.
+  CMessageClass* GetMessageClass() {
+    return reinterpret_cast<CMessageClass*>(Py_TYPE(this));
+  }
+
+  // For container containing messages, return a Python object for the given
+  // pointer to a message.
+  CMessage* BuildSubMessageFromPointer(const FieldDescriptor* field_descriptor,
+                                       Message* sub_message,
+                                       CMessageClass* message_class);
+  CMessage* MaybeReleaseSubMessage(Message* sub_message);
+} CMessage;
+
+// The (meta) type of all Messages classes.
+// It allows us to cache some C++ pointers in the class object itself, they are
+// faster to extract than from the type's dictionary.
+
+struct CMessageClass {
+  // This is how CPython subclasses C structures: the base structure must be
+  // the first member of the object.
+  PyHeapTypeObject super;
+
+  // C++ descriptor of this message.
+  const Descriptor* message_descriptor;
+
+  // Owned reference, used to keep the pointer above alive.
+  // This reference must stay alive until all message pointers are destructed.
+  PyObject* py_message_descriptor;
+
+  // The Python MessageFactory used to create the class. It is needed to resolve
+  // fields descriptors, including extensions fields; its C++ MessageFactory is
+  // used to instantiate submessages.
+  // This reference must stay alive until all message pointers are destructed.
+  PyMessageFactory* py_message_factory;
+
+  PyObject* AsPyObject() {
+    return reinterpret_cast<PyObject*>(this);
+  }
+};
+
+extern PyTypeObject* CMessageClass_Type;
+extern PyTypeObject* CMessage_Type;
+
+namespace cmessage {
+
+// Internal function to create a new empty Message Python object, but with empty
+// pointers to the C++ objects.
+// The caller must fill self->message, self->owner and eventually self->parent.
+CMessage* NewEmptyMessage(CMessageClass* type);
+
+// Retrieves the C++ descriptor of a Python Extension descriptor.
+// On error, return NULL with an exception set.
+const FieldDescriptor* GetExtensionDescriptor(PyObject* extension);
+
+// Initializes a new CMessage instance for a submessage. Only called once per
+// submessage as the result is cached in composite_fields.
+//
+// Corresponds to reflection api method GetMessage.
+CMessage* InternalGetSubMessage(
+    CMessage* self, const FieldDescriptor* field_descriptor);
+
+// Deletes a range of items in a repeated field (following a
+// removal in a RepeatedCompositeContainer).
+//
+// Corresponds to reflection api method RemoveLast.
+int DeleteRepeatedField(CMessage* self,
+                        const FieldDescriptor* field_descriptor,
+                        PyObject* slice);
+
+// Sets the specified scalar value to the message.
+int InternalSetScalar(CMessage* self,
+                      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(const Message* message,
+                            const FieldDescriptor* field_descriptor);
+
+bool SetCompositeField(CMessage* self, const FieldDescriptor* field,
+                       ContainerBase* value);
+
+bool SetSubmessage(CMessage* self, CMessage* submessage);
+
+// Clears the message, removing all contained data. Extension dictionary and
+// submessages are released first if there are remaining external references.
+//
+// Corresponds to message api method Clear.
+PyObject* Clear(CMessage* self);
+
+// Clears the data described by the given descriptor.
+// Returns -1 on error.
+//
+// Corresponds to reflection api method ClearField.
+int ClearFieldByDescriptor(CMessage* self, const FieldDescriptor* descriptor);
+
+// Checks if the message has the field described by the descriptor. Used for
+// extensions (which have no name).
+// Returns 1 if true, 0 if false, and -1 on error.
+//
+// Corresponds to reflection api method HasField
+int HasFieldByDescriptor(CMessage* self,
+                         const FieldDescriptor* field_descriptor);
+
+// Checks if the message has the named field.
+//
+// Corresponds to reflection api method HasField.
+PyObject* HasField(CMessage* self, PyObject* arg);
+
+// Initializes values of fields on a newly constructed message.
+// Note that positional arguments are disallowed: 'args' must be NULL or the
+// empty tuple.
+int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs);
+
+PyObject* MergeFrom(CMessage* self, PyObject* arg);
+
+// This method does not do anything beyond checking that no other extension
+// has been registered with the same field number on this class.
+PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle);
+
+// Get a field from a message.
+PyObject* GetFieldValue(CMessage* self,
+                        const FieldDescriptor* field_descriptor);
+// Sets the value of a scalar field in a message.
+// On error, return -1 with an extension set.
+int SetFieldValue(CMessage* self, const FieldDescriptor* field_descriptor,
+                  PyObject* value);
+
+PyObject* FindInitializationErrors(CMessage* self);
+
+int AssureWritable(CMessage* self);
+
+// Returns the message factory for the given message.
+// This is equivalent to message.MESSAGE_FACTORY
+//
+// The returned factory is suitable for finding fields and building submessages,
+// even in the case of extensions.
+// Returns a *borrowed* reference, and never fails because we pass a CMessage.
+PyMessageFactory* GetFactoryForMessage(CMessage* message);
+
+PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg);
+
+}  // namespace cmessage
+
+
+/* Is 64bit */
+#define IS_64BIT (SIZEOF_LONG == 8)
+
+#define FIELD_IS_REPEATED(field_descriptor) \
+  ((field_descriptor)->label() == FieldDescriptor::LABEL_REPEATED)
+
+#define GOOGLE_CHECK_GET_INT32(arg, value, err)  \
+  int32_t value;                          \
+  if (!CheckAndGetInteger(arg, &value)) { \
+    return err;                           \
+  }
+
+#define GOOGLE_CHECK_GET_INT64(arg, value, err)  \
+  int64_t value;                          \
+  if (!CheckAndGetInteger(arg, &value)) { \
+    return err;                           \
+  }
+
+#define GOOGLE_CHECK_GET_UINT32(arg, value, err) \
+  uint32_t value;                         \
+  if (!CheckAndGetInteger(arg, &value)) { \
+    return err;                           \
+  }
+
+#define GOOGLE_CHECK_GET_UINT64(arg, value, err) \
+  uint64_t value;                         \
+  if (!CheckAndGetInteger(arg, &value)) { \
+    return err;                           \
+  }
+
+#define GOOGLE_CHECK_GET_FLOAT(arg, value, err) \
+  float value;                           \
+  if (!CheckAndGetFloat(arg, &value)) {  \
+    return err;                          \
+  }
+
+#define GOOGLE_CHECK_GET_DOUBLE(arg, value, err) \
+  double value;                           \
+  if (!CheckAndGetDouble(arg, &value)) {  \
+    return err;                           \
+  }
+
+#define GOOGLE_CHECK_GET_BOOL(arg, value, err) \
+  bool value;                           \
+  if (!CheckAndGetBool(arg, &value)) {  \
+    return err;                         \
+  }
+
+#define FULL_MODULE_NAME "google.protobuf.pyext._message"
+
+void FormatTypeError(PyObject* arg, const char* expected_types);
+template<class T>
+bool CheckAndGetInteger(PyObject* arg, T* value);
+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,
+    const Reflection* reflection,
+    bool append,
+    int index);
+PyObject* ToStringObject(const FieldDescriptor* descriptor,
+                         const std::string& value);
+
+// Check if the passed field descriptor belongs to the given message.
+// If not, return false and set a Python exception (a KeyError)
+bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
+                                const Message* message);
+
+extern PyObject* PickleError_class;
+
+PyObject* PyMessage_New(const Descriptor* descriptor,
+                        PyObject* py_message_factory);
+const Message* PyMessage_GetMessagePointer(PyObject* msg);
+Message* PyMessage_GetMutableMessagePointer(PyObject* msg);
+PyObject* PyMessage_NewMessageOwnedExternally(Message* message,
+                                              PyObject* py_message_factory);
+
+bool InitProto2MessageModule(PyObject *m);
+
+// These are referenced by repeated_scalar_container, and must
+// be explicitly instantiated.
+extern template bool CheckAndGetInteger<int32>(PyObject*, int32*);
+extern template bool CheckAndGetInteger<int64>(PyObject*, int64*);
+extern template bool CheckAndGetInteger<uint32>(PyObject*, uint32*);
+extern template bool CheckAndGetInteger<uint64>(PyObject*, uint64*);
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__
diff --git a/python/google/protobuf/pyext/message_factory.cc b/python/google/protobuf/pyext/message_factory.cc
new file mode 100644
index 0000000..bc44dd4
--- /dev/null
+++ b/python/google/protobuf/pyext/message_factory.cc
@@ -0,0 +1,306 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <unordered_map>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace message_factory {
+
+PyMessageFactory* NewMessageFactory(PyTypeObject* type, PyDescriptorPool* pool) {
+  PyMessageFactory* factory = reinterpret_cast<PyMessageFactory*>(
+      PyType_GenericAlloc(type, 0));
+  if (factory == nullptr) {
+    return nullptr;
+  }
+
+  DynamicMessageFactory* message_factory = new DynamicMessageFactory();
+  // This option might be the default some day.
+  message_factory->SetDelegateToGeneratedFactory(true);
+  factory->message_factory = message_factory;
+
+  factory->pool = pool;
+  Py_INCREF(pool);
+
+  factory->classes_by_descriptor = new PyMessageFactory::ClassesByMessageMap();
+
+  return factory;
+}
+
+PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
+  static const char* kwlist[] = {"pool", nullptr};
+  PyObject* pool = nullptr;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
+                                   const_cast<char**>(kwlist), &pool)) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr owned_pool;
+  if (pool == nullptr || pool == Py_None) {
+    owned_pool.reset(PyObject_CallFunction(
+        reinterpret_cast<PyObject*>(&PyDescriptorPool_Type), nullptr));
+    if (owned_pool == nullptr) {
+      return nullptr;
+    }
+    pool = owned_pool.get();
+  } else {
+    if (!PyObject_TypeCheck(pool, &PyDescriptorPool_Type)) {
+      PyErr_Format(PyExc_TypeError, "Expected a DescriptorPool, got %s",
+                   pool->ob_type->tp_name);
+      return nullptr;
+    }
+  }
+
+  return reinterpret_cast<PyObject*>(
+      NewMessageFactory(type, reinterpret_cast<PyDescriptorPool*>(pool)));
+}
+
+static void Dealloc(PyObject* pself) {
+  PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
+
+  typedef PyMessageFactory::ClassesByMessageMap::iterator iterator;
+  for (iterator it = self->classes_by_descriptor->begin();
+       it != self->classes_by_descriptor->end(); ++it) {
+    Py_CLEAR(it->second);
+  }
+  delete self->classes_by_descriptor;
+  delete self->message_factory;
+  Py_CLEAR(self->pool);
+  Py_TYPE(self)->tp_free(pself);
+}
+
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
+  Py_VISIT(self->pool);
+  for (const auto& desc_and_class : *self->classes_by_descriptor) {
+    Py_VISIT(desc_and_class.second);
+  }
+  return 0;
+}
+
+static int GcClear(PyObject* pself) {
+  PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
+  // Here it's important to not clear self->pool, so that the C++ DescriptorPool
+  // is still alive when self->message_factory is destructed.
+  for (auto& desc_and_class : *self->classes_by_descriptor) {
+    Py_CLEAR(desc_and_class.second);
+  }
+
+  return 0;
+}
+
+// Add a message class to our database.
+int RegisterMessageClass(PyMessageFactory* self,
+                         const Descriptor* message_descriptor,
+                         CMessageClass* message_class) {
+  Py_INCREF(message_class);
+  typedef PyMessageFactory::ClassesByMessageMap::iterator iterator;
+  std::pair<iterator, bool> ret = self->classes_by_descriptor->insert(
+      std::make_pair(message_descriptor, message_class));
+  if (!ret.second) {
+    // Update case: DECREF the previous value.
+    Py_DECREF(ret.first->second);
+    ret.first->second = message_class;
+  }
+  return 0;
+}
+
+CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self,
+                                       const Descriptor* descriptor) {
+  // This is the same implementation as MessageFactory.GetPrototype().
+
+  // Do not create a MessageClass that already exists.
+  std::unordered_map<const Descriptor*, CMessageClass*>::iterator it =
+      self->classes_by_descriptor->find(descriptor);
+  if (it != self->classes_by_descriptor->end()) {
+    Py_INCREF(it->second);
+    return it->second;
+  }
+  ScopedPyObjectPtr py_descriptor(
+      PyMessageDescriptor_FromDescriptor(descriptor));
+  if (py_descriptor == nullptr) {
+    return nullptr;
+  }
+  // Create a new message class.
+  ScopedPyObjectPtr args(Py_BuildValue(
+      "s(){sOsOsO}", descriptor->name().c_str(),
+      "DESCRIPTOR", py_descriptor.get(),
+      "__module__", Py_None,
+      "message_factory", self));
+  if (args == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr message_class(PyObject_CallObject(
+      reinterpret_cast<PyObject*>(CMessageClass_Type), args.get()));
+  if (message_class == nullptr) {
+    return nullptr;
+  }
+  // Create messages class for the messages used by the fields, and registers
+  // all extensions for these messages during the recursion.
+  for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
+    const Descriptor* sub_descriptor =
+        descriptor->field(field_idx)->message_type();
+    // It is null if the field type is not a message.
+    if (sub_descriptor != nullptr) {
+      CMessageClass* result = GetOrCreateMessageClass(self, sub_descriptor);
+      if (result == nullptr) {
+        return nullptr;
+      }
+      Py_DECREF(result);
+    }
+  }
+
+  // Register extensions defined in this message.
+  for (int ext_idx = 0 ; ext_idx < descriptor->extension_count() ; ext_idx++) {
+    const FieldDescriptor* extension = descriptor->extension(ext_idx);
+    ScopedPyObjectPtr py_extended_class(
+        GetOrCreateMessageClass(self, extension->containing_type())
+            ->AsPyObject());
+    if (py_extended_class == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr py_extension(PyFieldDescriptor_FromDescriptor(extension));
+    if (py_extension == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr result(cmessage::RegisterExtension(
+        py_extended_class.get(), py_extension.get()));
+    if (result == nullptr) {
+      return nullptr;
+    }
+  }
+  return reinterpret_cast<CMessageClass*>(message_class.release());
+}
+
+// Retrieve the message class added to our database.
+CMessageClass* GetMessageClass(PyMessageFactory* self,
+                               const Descriptor* message_descriptor) {
+  typedef PyMessageFactory::ClassesByMessageMap::iterator iterator;
+  iterator ret = self->classes_by_descriptor->find(message_descriptor);
+  if (ret == self->classes_by_descriptor->end()) {
+    PyErr_Format(PyExc_TypeError, "No message class registered for '%s'",
+                 message_descriptor->full_name().c_str());
+    return nullptr;
+  } else {
+    return ret->second;
+  }
+}
+
+static PyMethodDef Methods[] = {
+    {nullptr},
+};
+
+static PyObject* GetPool(PyMessageFactory* self, void* closure) {
+  Py_INCREF(self->pool);
+  return reinterpret_cast<PyObject*>(self->pool);
+}
+
+static PyGetSetDef Getters[] = {
+    {"pool", (getter)GetPool, nullptr, "DescriptorPool"},
+    {nullptr},
+};
+
+}  // namespace message_factory
+
+PyTypeObject PyMessageFactory_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MessageFactory",         // tp_name
+    sizeof(PyMessageFactory),  // tp_basicsize
+    0,                         // tp_itemsize
+    message_factory::Dealloc,  // tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,  // tp_getattr
+    nullptr,  // tp_setattr
+    nullptr,  // tp_compare
+    nullptr,  // tp_repr
+    nullptr,  // tp_as_number
+    nullptr,  // tp_as_sequence
+    nullptr,  // tp_as_mapping
+    nullptr,  // tp_hash
+    nullptr,  // tp_call
+    nullptr,  // tp_str
+    nullptr,  // tp_getattro
+    nullptr,  // tp_setattro
+    nullptr,  // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "A static Message Factory",                                     // tp_doc
+    message_factory::GcTraverse,  // tp_traverse
+    message_factory::GcClear,     // tp_clear
+    nullptr,                      // tp_richcompare
+    0,                            // tp_weaklistoffset
+    nullptr,                      // tp_iter
+    nullptr,                      // tp_iternext
+    message_factory::Methods,     // tp_methods
+    nullptr,                      // tp_members
+    message_factory::Getters,     // tp_getset
+    nullptr,                      // tp_base
+    nullptr,                      // tp_dict
+    nullptr,                      // tp_descr_get
+    nullptr,                      // tp_descr_set
+    0,                            // tp_dictoffset
+    nullptr,                      // tp_init
+    nullptr,                      // tp_alloc
+    message_factory::New,         // tp_new
+    PyObject_GC_Del,              // tp_free
+};
+
+bool InitMessageFactory() {
+  if (PyType_Ready(&PyMessageFactory_Type) < 0) {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/message_factory.h b/python/google/protobuf/pyext/message_factory.h
new file mode 100644
index 0000000..7dfe425
--- /dev/null
+++ b/python/google/protobuf/pyext/message_factory.h
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_FACTORY_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_FACTORY_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <unordered_map>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+
+namespace google {
+namespace protobuf {
+class MessageFactory;
+
+namespace python {
+
+// The (meta) type of all Messages classes.
+struct CMessageClass;
+
+struct PyMessageFactory {
+  PyObject_HEAD
+
+  // 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 PyMessageFactory.
+  // The C++ one creates messages, when the Python one creates classes.
+  MessageFactory* message_factory;
+
+  // Owned reference to a Python DescriptorPool.
+  // This reference must stay until the message_factory is destructed.
+  PyDescriptorPool* pool;
+
+  // Make our own mapping to retrieve Python classes from C++ descriptors.
+  //
+  // Descriptor pointers stored here are owned by the DescriptorPool above.
+  // Python references to classes are owned by this PyDescriptorPool.
+  typedef std::unordered_map<const Descriptor*, CMessageClass*>
+      ClassesByMessageMap;
+  ClassesByMessageMap* classes_by_descriptor;
+};
+
+extern PyTypeObject PyMessageFactory_Type;
+
+namespace message_factory {
+
+// Creates a new MessageFactory instance.
+PyMessageFactory* NewMessageFactory(PyTypeObject* type, PyDescriptorPool* pool);
+
+// Registers a new Python class for the given message descriptor.
+// On error, returns -1 with a Python exception set.
+int RegisterMessageClass(PyMessageFactory* self,
+                         const Descriptor* message_descriptor,
+                         CMessageClass* message_class);
+// Retrieves the Python class registered with the given message descriptor, or
+// fail with a TypeError. Returns a *borrowed* reference.
+CMessageClass* GetMessageClass(PyMessageFactory* self,
+                               const Descriptor* message_descriptor);
+// Retrieves the Python class registered with the given message descriptor.
+// The class is created if not done yet. Returns a *new* reference.
+CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self,
+                                       const Descriptor* message_descriptor);
+}  // namespace message_factory
+
+// Initialize objects used by this module.
+// On error, returns false with a Python exception set.
+bool InitMessageFactory();
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_FACTORY_H__
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
new file mode 100644
index 0000000..2d3c1d2
--- /dev/null
+++ b/python/google/protobuf/pyext/message_module.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.
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/proto_api.h>
+
+namespace {
+
+// C++ API.  Clients get at this via proto_api.h
+struct ApiImplementation : google::protobuf::python::PyProto_API {
+  const google::protobuf::Message* GetMessagePointer(PyObject* msg) const override {
+    return google::protobuf::python::PyMessage_GetMessagePointer(msg);
+  }
+  google::protobuf::Message* GetMutableMessagePointer(PyObject* msg) const override {
+    return google::protobuf::python::PyMessage_GetMutableMessagePointer(msg);
+  }
+  const google::protobuf::Descriptor* MessageDescriptor_AsDescriptor(
+      PyObject* desc) const override {
+    return google::protobuf::python::PyMessageDescriptor_AsDescriptor(desc);
+  }
+  const google::protobuf::EnumDescriptor* EnumDescriptor_AsDescriptor(
+      PyObject* enum_desc) const override {
+    return google::protobuf::python::PyEnumDescriptor_AsDescriptor(enum_desc);
+  }
+
+  const google::protobuf::DescriptorPool* GetDefaultDescriptorPool() const override {
+    return google::protobuf::python::GetDefaultDescriptorPool()->pool;
+  }
+
+  google::protobuf::MessageFactory* GetDefaultMessageFactory() const override {
+    return google::protobuf::python::GetDefaultDescriptorPool()
+        ->py_message_factory->message_factory;
+  }
+  PyObject* NewMessage(const google::protobuf::Descriptor* descriptor,
+                       PyObject* py_message_factory) const override {
+    return google::protobuf::python::PyMessage_New(descriptor, py_message_factory);
+  }
+  PyObject* NewMessageOwnedExternally(
+      google::protobuf::Message* msg, PyObject* py_message_factory) const override {
+    return google::protobuf::python::PyMessage_NewMessageOwnedExternally(
+        msg, py_message_factory);
+  }
+  PyObject* DescriptorPool_FromPool(
+      const google::protobuf::DescriptorPool* pool) const override {
+    return google::protobuf::python::PyDescriptorPool_FromPool(pool);
+  }
+};
+
+}  // namespace
+
+static const char module_docstring[] =
+    "python-proto2 is a module that can be used to enhance proto2 Python API\n"
+    "performance.\n"
+    "\n"
+    "It provides access to the protocol buffers C++ reflection API that\n"
+    "implements the basic protocol buffer functions.";
+
+static PyMethodDef ModuleMethods[] = {
+    {"SetAllowOversizeProtos",
+     (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, METH_O,
+     "Enable/disable oversize proto parsing."},
+    // DO NOT USE: For migration and testing only.
+    {nullptr, nullptr}};
+
+static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
+                                     "_message",
+                                     module_docstring,
+                                     -1,
+                                     ModuleMethods, /* m_methods */
+                                     nullptr,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr};
+
+PyMODINIT_FUNC PyInit__message() {
+  PyObject* m;
+  m = PyModule_Create(&_module);
+  if (m == nullptr) {
+    return nullptr;
+  }
+
+  if (!google::protobuf::python::InitProto2MessageModule(m)) {
+    Py_DECREF(m);
+    return nullptr;
+  }
+
+  // Adds the C++ API
+  if (PyObject* api = PyCapsule_New(
+          new ApiImplementation(), google::protobuf::python::PyProtoAPICapsuleName(),
+          [](PyObject* o) {
+            delete (ApiImplementation*)PyCapsule_GetPointer(
+                o, google::protobuf::python::PyProtoAPICapsuleName());
+          })) {
+    PyModule_AddObject(m, "proto_API", api);
+  } else {
+    return nullptr;
+  }
+
+  return m;
+}
diff --git a/python/google/protobuf/pyext/proto2_api_test.proto b/python/google/protobuf/pyext/proto2_api_test.proto
new file mode 100644
index 0000000..1fd78e8
--- /dev/null
+++ b/python/google/protobuf/pyext/proto2_api_test.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+import "google/protobuf/internal/cpp/proto1_api_test.proto";
+
+message TestNestedProto1APIMessage {
+  optional int32 a = 1;
+  optional TestMessage.NestedMessage b = 2;
+}
diff --git a/python/google/protobuf/pyext/python.proto b/python/google/protobuf/pyext/python.proto
new file mode 100644
index 0000000..2e50df7
--- /dev/null
+++ b/python/google/protobuf/pyext/python.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: tibell@google.com (Johan Tibell)
+//
+// These message definitions are used to exercises known corner cases
+// in the C++ implementation of the Python API.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal;
+
+// 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;
+
+message TestAllTypes {
+  message NestedMessage {
+    optional int32 bb = 1;
+    optional ForeignMessage cc = 2;
+  }
+
+  repeated NestedMessage repeated_nested_message = 1;
+  optional NestedMessage optional_nested_message = 2;
+  optional int32 optional_int32 = 3;
+}
+
+message ForeignMessage {
+  optional int32 c = 1;
+  repeated int32 d = 2;
+}
+
+message TestAllExtensions {  // extension begin
+  extensions 1 to max;
+}  // extension end
+
+extend TestAllExtensions {  // extension begin
+  optional TestAllTypes.NestedMessage optional_nested_message_extension = 1;
+  repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 2;
+}  // extension end
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
new file mode 100644
index 0000000..0b63f82
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -0,0 +1,591 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/repeated_composite_container.h>
+
+#include <memory>
+
+#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/reflection.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace repeated_composite_container {
+
+// ---------------------------------------------------------------------
+// len()
+
+static Py_ssize_t Length(PyObject* pself) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  Message* message = self->parent->message;
+  return message->GetReflection()->FieldSize(*message,
+                                             self->parent_field_descriptor);
+}
+
+// ---------------------------------------------------------------------
+// add()
+
+PyObject* Add(RepeatedCompositeContainer* self, PyObject* args,
+              PyObject* kwargs) {
+  if (cmessage::AssureWritable(self->parent) == -1) return nullptr;
+  Message* message = self->parent->message;
+
+  Message* sub_message = message->GetReflection()->AddMessage(
+      message, self->parent_field_descriptor,
+      self->child_message_class->py_message_factory->message_factory);
+  CMessage* cmsg = self->parent->BuildSubMessageFromPointer(
+      self->parent_field_descriptor, sub_message, self->child_message_class);
+
+  if (cmessage::InitAttributes(cmsg, args, kwargs) < 0) {
+    message->GetReflection()->RemoveLast(message,
+                                         self->parent_field_descriptor);
+    Py_DECREF(cmsg);
+    return nullptr;
+  }
+
+  return cmsg->AsPyObject();
+}
+
+static PyObject* AddMethod(PyObject* self, PyObject* args, PyObject* kwargs) {
+  return Add(reinterpret_cast<RepeatedCompositeContainer*>(self), args, kwargs);
+}
+
+// ---------------------------------------------------------------------
+// append()
+
+static PyObject* AddMessage(RepeatedCompositeContainer* self, PyObject* value) {
+  cmessage::AssureWritable(self->parent);
+  PyObject* py_cmsg;
+  Message* message = self->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  py_cmsg = Add(self, nullptr, nullptr);
+  if (py_cmsg == nullptr) return nullptr;
+  CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
+  if (ScopedPyObjectPtr(cmessage::MergeFrom(cmsg, value)) == nullptr) {
+    reflection->RemoveLast(message, self->parent_field_descriptor);
+    Py_DECREF(cmsg);
+    return nullptr;
+  }
+  return py_cmsg;
+}
+
+static PyObject* AppendMethod(PyObject* pself, PyObject* value) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+  ScopedPyObjectPtr py_cmsg(AddMessage(self, value));
+  if (py_cmsg == nullptr) {
+    return nullptr;
+  }
+
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+// insert()
+static PyObject* Insert(PyObject* pself, PyObject* args) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  Py_ssize_t index;
+  PyObject* value;
+  if (!PyArg_ParseTuple(args, "nO", &index, &value)) {
+    return nullptr;
+  }
+
+  ScopedPyObjectPtr py_cmsg(AddMessage(self, value));
+  if (py_cmsg == nullptr) {
+    return nullptr;
+  }
+
+  // Swap the element to right position.
+  Message* message = self->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+  Py_ssize_t length = reflection->FieldSize(*message, field_descriptor) - 1;
+  Py_ssize_t end_index = index;
+  if (end_index < 0) end_index += length;
+  if (end_index < 0) end_index = 0;
+  for (Py_ssize_t i = length; i > end_index; i--) {
+    reflection->SwapElements(message, field_descriptor, i, i - 1);
+  }
+
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+// extend()
+
+PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) {
+  cmessage::AssureWritable(self->parent);
+  ScopedPyObjectPtr iter(PyObject_GetIter(value));
+  if (iter == nullptr) {
+    PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+    return nullptr;
+  }
+  ScopedPyObjectPtr next;
+  while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
+    if (!PyObject_TypeCheck(next.get(), CMessage_Type)) {
+      PyErr_SetString(PyExc_TypeError, "Not a cmessage");
+      return nullptr;
+    }
+    ScopedPyObjectPtr new_message(Add(self, nullptr, nullptr));
+    if (new_message == nullptr) {
+      return nullptr;
+    }
+    CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
+    if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next.get())) ==
+        nullptr) {
+      return nullptr;
+    }
+  }
+  if (PyErr_Occurred()) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* ExtendMethod(PyObject* self, PyObject* value) {
+  return Extend(reinterpret_cast<RepeatedCompositeContainer*>(self), value);
+}
+
+PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other) {
+  return Extend(self, other);
+}
+
+static PyObject* MergeFromMethod(PyObject* self, PyObject* other) {
+  return MergeFrom(reinterpret_cast<RepeatedCompositeContainer*>(self), other);
+}
+
+// This function does not check the bounds.
+static PyObject* GetItem(RepeatedCompositeContainer* self, Py_ssize_t index,
+                         Py_ssize_t length = -1) {
+  if (length == -1) {
+    Message* message = self->parent->message;
+    const Reflection* reflection = message->GetReflection();
+    length = reflection->FieldSize(*message, self->parent_field_descriptor);
+  }
+  if (index < 0 || index >= length) {
+    PyErr_Format(PyExc_IndexError, "list index (%zd) out of range", index);
+    return nullptr;
+  }
+  Message* message = self->parent->message;
+  Message* sub_message = message->GetReflection()->MutableRepeatedMessage(
+      message, self->parent_field_descriptor, index);
+  return self->parent
+      ->BuildSubMessageFromPointer(self->parent_field_descriptor, sub_message,
+                                   self->child_message_class)
+      ->AsPyObject();
+}
+
+PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* item) {
+  Message* message = self->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  Py_ssize_t length =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+
+  if (PyIndex_Check(item)) {
+    Py_ssize_t index;
+    index = PyNumber_AsSsize_t(item, PyExc_IndexError);
+    if (index == -1 && PyErr_Occurred()) return nullptr;
+    if (index < 0) index += length;
+    return GetItem(self, index, length);
+  } else if (PySlice_Check(item)) {
+    Py_ssize_t from, to, step, slicelength, cur, i;
+    PyObject* result;
+
+    if (PySlice_GetIndicesEx(item, length, &from, &to, &step, &slicelength) ==
+        -1) {
+      return nullptr;
+    }
+
+    if (slicelength <= 0) {
+      return PyList_New(0);
+    } else {
+      result = PyList_New(slicelength);
+      if (!result) return nullptr;
+
+      for (cur = from, i = 0; i < slicelength; cur += step, i++) {
+        PyList_SET_ITEM(result, i, GetItem(self, cur, length));
+      }
+
+      return result;
+    }
+  } else {
+    PyErr_Format(PyExc_TypeError, "indices must be integers, not %.200s",
+                 item->ob_type->tp_name);
+    return nullptr;
+  }
+}
+
+static PyObject* SubscriptMethod(PyObject* self, PyObject* slice) {
+  return Subscript(reinterpret_cast<RepeatedCompositeContainer*>(self), slice);
+}
+
+int AssignSubscript(RepeatedCompositeContainer* self, PyObject* slice,
+                    PyObject* value) {
+  if (value != nullptr) {
+    PyErr_SetString(PyExc_TypeError, "does not support assignment");
+    return -1;
+  }
+
+  return cmessage::DeleteRepeatedField(self->parent,
+                                       self->parent_field_descriptor, slice);
+}
+
+static int AssignSubscriptMethod(PyObject* self, PyObject* slice,
+                                 PyObject* value) {
+  return AssignSubscript(reinterpret_cast<RepeatedCompositeContainer*>(self),
+                         slice, value);
+}
+
+static PyObject* Remove(PyObject* pself, PyObject* value) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+  Py_ssize_t len = Length(reinterpret_cast<PyObject*>(self));
+
+  for (Py_ssize_t i = 0; i < len; i++) {
+    ScopedPyObjectPtr item(GetItem(self, i, len));
+    if (item == nullptr) {
+      return nullptr;
+    }
+    int result = PyObject_RichCompareBool(item.get(), value, Py_EQ);
+    if (result < 0) {
+      return nullptr;
+    }
+    if (result) {
+      ScopedPyObjectPtr py_index(PyLong_FromSsize_t(i));
+      if (AssignSubscript(self, py_index.get(), nullptr) < 0) {
+        return nullptr;
+      }
+      Py_RETURN_NONE;
+    }
+  }
+  PyErr_SetString(PyExc_ValueError, "Item to delete not in list");
+  return nullptr;
+}
+
+static PyObject* RichCompare(PyObject* pself, PyObject* other, int opid) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  if (!PyObject_TypeCheck(other, &RepeatedCompositeContainer_Type)) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Can only compare repeated composite fields "
+                    "against other repeated composite fields.");
+    return nullptr;
+  }
+  if (opid == Py_EQ || opid == Py_NE) {
+    // TODO(anuraag): Don't make new lists just for this...
+    ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+    if (full_slice == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
+    if (list == nullptr) {
+      return nullptr;
+    }
+    ScopedPyObjectPtr other_list(
+        Subscript(reinterpret_cast<RepeatedCompositeContainer*>(other),
+                  full_slice.get()));
+    if (other_list == nullptr) {
+      return nullptr;
+    }
+    return PyObject_RichCompare(list.get(), other_list.get(), opid);
+  } else {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+}
+
+static PyObject* ToStr(PyObject* pself) {
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  if (full_slice == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr list(Subscript(
+      reinterpret_cast<RepeatedCompositeContainer*>(pself), full_slice.get()));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  return PyObject_Repr(list.get());
+}
+
+// ---------------------------------------------------------------------
+// sort()
+
+static void ReorderAttached(RepeatedCompositeContainer* self,
+                            PyObject* child_list) {
+  Message* message = self->parent->message;
+  const Reflection* reflection = message->GetReflection();
+  const FieldDescriptor* descriptor = self->parent_field_descriptor;
+  const Py_ssize_t length = Length(reinterpret_cast<PyObject*>(self));
+
+  // We need to rearrange things to match python's sort order.
+  for (Py_ssize_t i = 0; i < length; ++i) {
+    reflection->UnsafeArenaReleaseLast(message, descriptor);
+  }
+  for (Py_ssize_t i = 0; i < length; ++i) {
+    Message* child_message =
+        reinterpret_cast<CMessage*>(PyList_GET_ITEM(child_list, i))->message;
+    reflection->UnsafeArenaAddAllocatedMessage(message, descriptor,
+                                               child_message);
+  }
+}
+
+// Returns 0 if successful; returns -1 and sets an exception if
+// unsuccessful.
+static int SortPythonMessages(RepeatedCompositeContainer* self, PyObject* args,
+                              PyObject* kwds) {
+  ScopedPyObjectPtr child_list(
+      PySequence_List(reinterpret_cast<PyObject*>(self)));
+  if (child_list == nullptr) {
+    return -1;
+  }
+  ScopedPyObjectPtr m(PyObject_GetAttrString(child_list.get(), "sort"));
+  if (m == nullptr) return -1;
+  if (ScopedPyObjectPtr(PyObject_Call(m.get(), args, kwds)) == nullptr)
+    return -1;
+  ReorderAttached(self, child_list.get());
+  return 0;
+}
+
+static PyObject* Sort(PyObject* pself, PyObject* args, PyObject* kwds) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  // Support the old sort_function argument for backwards
+  // compatibility.
+  if (kwds != nullptr) {
+    PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
+    if (sort_func != nullptr) {
+      // Must set before deleting as sort_func is a borrowed reference
+      // and kwds might be the only thing keeping it alive.
+      PyDict_SetItemString(kwds, "cmp", sort_func);
+      PyDict_DelItemString(kwds, "sort_function");
+    }
+  }
+
+  if (SortPythonMessages(self, args, kwds) < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+// reverse()
+
+// Returns 0 if successful; returns -1 and sets an exception if
+// unsuccessful.
+static int ReversePythonMessages(RepeatedCompositeContainer* self) {
+  ScopedPyObjectPtr child_list(
+      PySequence_List(reinterpret_cast<PyObject*>(self)));
+  if (child_list == nullptr) {
+    return -1;
+  }
+  if (ScopedPyObjectPtr(
+          PyObject_CallMethod(child_list.get(), "reverse", nullptr)) == nullptr)
+    return -1;
+  ReorderAttached(self, child_list.get());
+  return 0;
+}
+
+static PyObject* Reverse(PyObject* pself) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  if (ReversePythonMessages(self) < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+
+static PyObject* Item(PyObject* pself, Py_ssize_t index) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+  return GetItem(self, index);
+}
+
+static PyObject* Pop(PyObject* pself, PyObject* args) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  Py_ssize_t index = -1;
+  if (!PyArg_ParseTuple(args, "|n", &index)) {
+    return nullptr;
+  }
+  Py_ssize_t length = Length(pself);
+  if (index < 0) index += length;
+  PyObject* item = GetItem(self, index, length);
+  if (item == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index));
+  if (AssignSubscript(self, py_index.get(), nullptr) < 0) {
+    return nullptr;
+  }
+  return item;
+}
+
+PyObject* DeepCopy(PyObject* pself, PyObject* arg) {
+  return reinterpret_cast<RepeatedCompositeContainer*>(pself)->DeepCopy();
+}
+
+// The private constructor of RepeatedCompositeContainer objects.
+RepeatedCompositeContainer* NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor,
+    CMessageClass* child_message_class) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return nullptr;
+  }
+
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(
+          PyType_GenericAlloc(&RepeatedCompositeContainer_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  Py_INCREF(child_message_class);
+  self->child_message_class = child_message_class;
+  return self;
+}
+
+static void Dealloc(PyObject* pself) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+  self->RemoveFromParentCache();
+  Py_CLEAR(self->child_message_class);
+  Py_TYPE(self)->tp_free(pself);
+}
+
+static PySequenceMethods SqMethods = {
+    Length,  /* sq_length */
+    nullptr, /* sq_concat */
+    nullptr, /* sq_repeat */
+    Item     /* sq_item */
+};
+
+static PyMappingMethods MpMethods = {
+    Length,                /* mp_length */
+    SubscriptMethod,       /* mp_subscript */
+    AssignSubscriptMethod, /* mp_ass_subscript */
+};
+
+static PyMethodDef Methods[] = {
+    {"__deepcopy__", DeepCopy, METH_VARARGS, "Makes a deep copy of the class."},
+    {"add", reinterpret_cast<PyCFunction>(AddMethod),
+     METH_VARARGS | METH_KEYWORDS, "Adds an object to the repeated container."},
+    {"append", AppendMethod, METH_O,
+     "Appends a message to the end of the repeated container."},
+    {"insert", Insert, METH_VARARGS,
+     "Inserts a message before the specified index."},
+    {"extend", ExtendMethod, METH_O, "Adds objects to the repeated container."},
+    {"pop", Pop, METH_VARARGS,
+     "Removes an object from the repeated container and returns it."},
+    {"remove", Remove, METH_O,
+     "Removes an object from the repeated container."},
+    {"sort", reinterpret_cast<PyCFunction>(Sort), METH_VARARGS | METH_KEYWORDS,
+     "Sorts the repeated container."},
+    {"reverse", reinterpret_cast<PyCFunction>(Reverse), METH_NOARGS,
+     "Reverses elements order of the repeated container."},
+    {"MergeFrom", MergeFromMethod, METH_O,
+     "Adds objects to the repeated container."},
+    {nullptr, nullptr}};
+
+}  // namespace repeated_composite_container
+
+PyTypeObject RepeatedCompositeContainer_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".RepeatedCompositeContainer",          // tp_name
+    sizeof(RepeatedCompositeContainer),     // tp_basicsize
+    0,                                      //  tp_itemsize
+    repeated_composite_container::Dealloc,  //  tp_dealloc
+#if PY_VERSION_HEX >= 0x03080000
+    0,  //  tp_vectorcall_offset
+#else
+    nullptr,  //  tp_print
+#endif
+    nullptr,                                    //  tp_getattr
+    nullptr,                                    //  tp_setattr
+    nullptr,                                    //  tp_compare
+    repeated_composite_container::ToStr,        //  tp_repr
+    nullptr,                                    //  tp_as_number
+    &repeated_composite_container::SqMethods,   //  tp_as_sequence
+    &repeated_composite_container::MpMethods,   //  tp_as_mapping
+    PyObject_HashNotImplemented,                //  tp_hash
+    nullptr,                                    //  tp_call
+    nullptr,                                    //  tp_str
+    nullptr,                                    //  tp_getattro
+    nullptr,                                    //  tp_setattro
+    nullptr,                                    //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                         //  tp_flags
+    "A Repeated scalar container",              //  tp_doc
+    nullptr,                                    //  tp_traverse
+    nullptr,                                    //  tp_clear
+    repeated_composite_container::RichCompare,  //  tp_richcompare
+    0,                                          //  tp_weaklistoffset
+    nullptr,                                    //  tp_iter
+    nullptr,                                    //  tp_iternext
+    repeated_composite_container::Methods,      //  tp_methods
+    nullptr,                                    //  tp_members
+    nullptr,                                    //  tp_getset
+    nullptr,                                    //  tp_base
+    nullptr,                                    //  tp_dict
+    nullptr,                                    //  tp_descr_get
+    nullptr,                                    //  tp_descr_set
+    0,                                          //  tp_dictoffset
+    nullptr,                                    //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h
new file mode 100644
index 0000000..6fa6e17
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_composite_container.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+
+class FieldDescriptor;
+class Message;
+
+namespace python {
+
+struct CMessageClass;
+
+// A RepeatedCompositeContainer always has a parent message.
+// The parent message also caches reference to items of the container.
+typedef struct RepeatedCompositeContainer : public ContainerBase {
+  // The type used to create new child messages.
+  CMessageClass* child_message_class;
+} RepeatedCompositeContainer;
+
+extern PyTypeObject RepeatedCompositeContainer_Type;
+
+namespace repeated_composite_container {
+
+// Builds a RepeatedCompositeContainer object, from a parent message and a
+// field descriptor.
+RepeatedCompositeContainer* NewContainer(
+    CMessage* parent,
+    const FieldDescriptor* parent_field_descriptor,
+    CMessageClass *child_message_class);
+
+// Appends a new CMessage to the container and returns it.  The
+// CMessage is initialized using the content of kwargs.
+//
+// Returns a new reference if successful; returns NULL and sets an
+// exception if unsuccessful.
+PyObject* Add(RepeatedCompositeContainer* self,
+              PyObject* args,
+              PyObject* kwargs);
+
+// Appends all the CMessages in the input iterator to the container.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value);
+
+// Appends a new message to the container for each message in the
+// input iterator, merging each data element in. Equivalent to extend.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other);
+
+// Accesses messages in the container.
+//
+// Returns a new reference to the message for an integer parameter.
+// Returns a new reference to a list of messages for a slice.
+PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice);
+
+// Deletes items from the container (cannot be used for assignment).
+//
+// Returns 0 on success, -1 on failure.
+int AssignSubscript(RepeatedCompositeContainer* self,
+                    PyObject* slice,
+                    PyObject* value);
+}  // namespace repeated_composite_container
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
new file mode 100644
index 0000000..f4a8df2
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_scalar_container.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.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#include <google/protobuf/pyext/repeated_scalar_container.h>
+
+#include <cstdint>
+#include <memory>
+
+#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>
+
+#define PyString_AsString(ob) \
+  (PyUnicode_Check(ob) ? PyUnicode_AsUTF8(ob) : PyBytes_AsString(ob))
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace repeated_scalar_container {
+
+static int InternalAssignRepeatedField(RepeatedScalarContainer* self,
+                                       PyObject* list) {
+  Message* message = self->parent->message;
+  message->GetReflection()->ClearField(message, self->parent_field_descriptor);
+  for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) {
+    PyObject* value = PyList_GET_ITEM(list, i);
+    if (ScopedPyObjectPtr(Append(self, value)) == nullptr) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+static Py_ssize_t Len(PyObject* pself) {
+  RepeatedScalarContainer* self =
+      reinterpret_cast<RepeatedScalarContainer*>(pself);
+  Message* message = self->parent->message;
+  return message->GetReflection()->FieldSize(*message,
+                                             self->parent_field_descriptor);
+}
+
+static int AssignItem(PyObject* pself, Py_ssize_t index, PyObject* arg) {
+  RepeatedScalarContainer* self =
+      reinterpret_cast<RepeatedScalarContainer*>(pself);
+
+  cmessage::AssureWritable(self->parent);
+  Message* message = self->parent->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+
+  const Reflection* reflection = message->GetReflection();
+  int field_size = reflection->FieldSize(*message, field_descriptor);
+  if (index < 0) {
+    index = field_size + index;
+  }
+  if (index < 0 || index >= field_size) {
+    PyErr_Format(PyExc_IndexError, "list assignment index (%d) out of range",
+                 static_cast<int>(index));
+    return -1;
+  }
+
+  if (arg == nullptr) {
+    ScopedPyObjectPtr py_index(PyLong_FromLong(index));
+    return cmessage::DeleteRepeatedField(self->parent, field_descriptor,
+                                         py_index.get());
+  }
+
+  if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) {
+    PyErr_SetString(PyExc_TypeError, "Value must be scalar");
+    return -1;
+  }
+
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(arg, value, -1);
+      reflection->SetRepeatedInt32(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(arg, value, -1);
+      reflection->SetRepeatedInt64(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(arg, value, -1);
+      reflection->SetRepeatedUInt32(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(arg, value, -1);
+      reflection->SetRepeatedUInt64(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
+      reflection->SetRepeatedFloat(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
+      reflection->SetRepeatedDouble(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(arg, value, -1);
+      reflection->SetRepeatedBool(message, field_descriptor, index, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      if (!CheckAndSetString(arg, message, field_descriptor, reflection, false,
+                             index)) {
+        return -1;
+      }
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      GOOGLE_CHECK_GET_INT32(arg, value, -1);
+      if (reflection->SupportsUnknownEnumValues()) {
+        reflection->SetRepeatedEnumValue(message, field_descriptor, index,
+                                         value);
+      } else {
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != nullptr) {
+          reflection->SetRepeatedEnum(message, field_descriptor, index,
+                                      enum_value);
+        } else {
+          ScopedPyObjectPtr s(PyObject_Str(arg));
+          if (s != nullptr) {
+            PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
+                         PyString_AsString(s.get()));
+          }
+          return -1;
+        }
+      }
+      break;
+    }
+    default:
+      PyErr_Format(PyExc_SystemError,
+                   "Adding value to a field of unknown type %d",
+                   field_descriptor->cpp_type());
+      return -1;
+  }
+  return 0;
+}
+
+static PyObject* Item(PyObject* pself, Py_ssize_t index) {
+  RepeatedScalarContainer* self =
+      reinterpret_cast<RepeatedScalarContainer*>(pself);
+
+  Message* message = self->parent->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+  const Reflection* reflection = message->GetReflection();
+
+  int field_size = reflection->FieldSize(*message, field_descriptor);
+  if (index < 0) {
+    index = field_size + index;
+  }
+  if (index < 0 || index >= field_size) {
+    PyErr_Format(PyExc_IndexError, "list index (%zd) out of range", index);
+    return nullptr;
+  }
+
+  PyObject* result = nullptr;
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      int32_t value =
+          reflection->GetRepeatedInt32(*message, field_descriptor, index);
+      result = PyLong_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      int64_t value =
+          reflection->GetRepeatedInt64(*message, field_descriptor, index);
+      result = PyLong_FromLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      uint32_t value =
+          reflection->GetRepeatedUInt32(*message, field_descriptor, index);
+      result = PyLong_FromLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      uint64_t value =
+          reflection->GetRepeatedUInt64(*message, field_descriptor, index);
+      result = PyLong_FromUnsignedLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value =
+          reflection->GetRepeatedFloat(*message, field_descriptor, index);
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value =
+          reflection->GetRepeatedDouble(*message, field_descriptor, index);
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      bool value =
+          reflection->GetRepeatedBool(*message, field_descriptor, index);
+      result = PyBool_FromLong(value ? 1 : 0);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      const EnumValueDescriptor* enum_value =
+          message->GetReflection()->GetRepeatedEnum(*message, field_descriptor,
+                                                    index);
+      result = PyLong_FromLong(enum_value->number());
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      std::string scratch;
+      const std::string& value = reflection->GetRepeatedStringReference(
+          *message, field_descriptor, index, &scratch);
+      result = ToStringObject(field_descriptor, value);
+      break;
+    }
+    default:
+      PyErr_Format(PyExc_SystemError,
+                   "Getting value from a repeated field of unknown type %d",
+                   field_descriptor->cpp_type());
+  }
+
+  return result;
+}
+
+static PyObject* Subscript(PyObject* pself, PyObject* slice) {
+  Py_ssize_t from;
+  Py_ssize_t to;
+  Py_ssize_t step;
+  Py_ssize_t length;
+  Py_ssize_t slicelength;
+  bool return_list = false;
+  if (PyLong_Check(slice)) {
+    from = to = PyLong_AsLong(slice);
+  } else if (PyIndex_Check(slice)) {
+    from = to = PyNumber_AsSsize_t(slice, PyExc_ValueError);
+    if (from == -1 && PyErr_Occurred()) {
+      return nullptr;
+    }
+  } else if (PySlice_Check(slice)) {
+    length = Len(pself);
+    if (PySlice_GetIndicesEx(slice, length, &from, &to, &step, &slicelength) ==
+        -1) {
+      return nullptr;
+    }
+    return_list = true;
+  } else {
+    PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+    return nullptr;
+  }
+
+  if (!return_list) {
+    return Item(pself, from);
+  }
+
+  PyObject* list = PyList_New(0);
+  if (list == nullptr) {
+    return nullptr;
+  }
+  if (from <= to) {
+    if (step < 0) {
+      return list;
+    }
+    for (Py_ssize_t index = from; index < to; index += step) {
+      if (index < 0 || index >= length) {
+        break;
+      }
+      ScopedPyObjectPtr s(Item(pself, index));
+      PyList_Append(list, s.get());
+    }
+  } else {
+    if (step > 0) {
+      return list;
+    }
+    for (Py_ssize_t index = from; index > to; index += step) {
+      if (index < 0 || index >= length) {
+        break;
+      }
+      ScopedPyObjectPtr s(Item(pself, index));
+      PyList_Append(list, s.get());
+    }
+  }
+  return list;
+}
+
+PyObject* Append(RepeatedScalarContainer* self, PyObject* item) {
+  cmessage::AssureWritable(self->parent);
+  Message* message = self->parent->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+
+  const Reflection* reflection = message->GetReflection();
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(item, value, nullptr);
+      reflection->AddInt32(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(item, value, nullptr);
+      reflection->AddInt64(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(item, value, nullptr);
+      reflection->AddUInt32(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(item, value, nullptr);
+      reflection->AddUInt64(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      GOOGLE_CHECK_GET_FLOAT(item, value, nullptr);
+      reflection->AddFloat(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      GOOGLE_CHECK_GET_DOUBLE(item, value, nullptr);
+      reflection->AddDouble(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(item, value, nullptr);
+      reflection->AddBool(message, field_descriptor, value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      if (!CheckAndSetString(item, message, field_descriptor, reflection, true,
+                             -1)) {
+        return nullptr;
+      }
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      GOOGLE_CHECK_GET_INT32(item, value, nullptr);
+      if (reflection->SupportsUnknownEnumValues()) {
+        reflection->AddEnumValue(message, field_descriptor, value);
+      } else {
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != nullptr) {
+          reflection->AddEnum(message, field_descriptor, enum_value);
+        } else {
+          ScopedPyObjectPtr s(PyObject_Str(item));
+          if (s != nullptr) {
+            PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
+                         PyString_AsString(s.get()));
+          }
+          return nullptr;
+        }
+      }
+      break;
+    }
+    default:
+      PyErr_Format(PyExc_SystemError,
+                   "Adding value to a field of unknown type %d",
+                   field_descriptor->cpp_type());
+      return nullptr;
+  }
+
+  Py_RETURN_NONE;
+}
+
+static PyObject* AppendMethod(PyObject* self, PyObject* item) {
+  return Append(reinterpret_cast<RepeatedScalarContainer*>(self), item);
+}
+
+static int AssSubscript(PyObject* pself, PyObject* slice, PyObject* value) {
+  RepeatedScalarContainer* self =
+      reinterpret_cast<RepeatedScalarContainer*>(pself);
+
+  Py_ssize_t from;
+  Py_ssize_t to;
+  Py_ssize_t step;
+  Py_ssize_t length;
+  Py_ssize_t slicelength;
+  bool create_list = false;
+
+  cmessage::AssureWritable(self->parent);
+  Message* message = self->parent->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+
+  if (PyLong_Check(slice)) {
+    from = to = PyLong_AsLong(slice);
+  } else if (PySlice_Check(slice)) {
+    const Reflection* reflection = message->GetReflection();
+    length = reflection->FieldSize(*message, field_descriptor);
+    if (PySlice_GetIndicesEx(slice, length, &from, &to, &step, &slicelength) ==
+        -1) {
+      return -1;
+    }
+    create_list = true;
+  } else {
+    PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+    return -1;
+  }
+
+  if (value == nullptr) {
+    return cmessage::DeleteRepeatedField(self->parent, field_descriptor, slice);
+  }
+
+  if (!create_list) {
+    return AssignItem(pself, from, value);
+  }
+
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  if (full_slice == nullptr) {
+    return -1;
+  }
+  ScopedPyObjectPtr new_list(Subscript(pself, full_slice.get()));
+  if (new_list == nullptr) {
+    return -1;
+  }
+  if (PySequence_SetSlice(new_list.get(), from, to, value) < 0) {
+    return -1;
+  }
+
+  return InternalAssignRepeatedField(self, new_list.get());
+}
+
+PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
+  cmessage::AssureWritable(self->parent);
+
+  // TODO(ptucker): Deprecate this behavior. b/18413862
+  if (value == Py_None) {
+    Py_RETURN_NONE;
+  }
+  if ((Py_TYPE(value)->tp_as_sequence == nullptr) && PyObject_Not(value)) {
+    Py_RETURN_NONE;
+  }
+
+  ScopedPyObjectPtr iter(PyObject_GetIter(value));
+  if (iter == nullptr) {
+    PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+    return nullptr;
+  }
+  ScopedPyObjectPtr next;
+  while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
+    if (ScopedPyObjectPtr(Append(self, next.get())) == nullptr) {
+      return nullptr;
+    }
+  }
+  if (PyErr_Occurred()) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* Insert(PyObject* pself, PyObject* args) {
+  RepeatedScalarContainer* self =
+      reinterpret_cast<RepeatedScalarContainer*>(pself);
+
+  Py_ssize_t index;
+  PyObject* value;
+  if (!PyArg_ParseTuple(args, "lO", &index, &value)) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  ScopedPyObjectPtr new_list(Subscript(pself, full_slice.get()));
+  if (PyList_Insert(new_list.get(), index, value) < 0) {
+    return nullptr;
+  }
+  int ret = InternalAssignRepeatedField(self, new_list.get());
+  if (ret < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* Remove(PyObject* pself, PyObject* value) {
+  Py_ssize_t match_index = -1;
+  for (Py_ssize_t i = 0; i < Len(pself); ++i) {
+    ScopedPyObjectPtr elem(Item(pself, i));
+    if (PyObject_RichCompareBool(elem.get(), value, Py_EQ)) {
+      match_index = i;
+      break;
+    }
+  }
+  if (match_index == -1) {
+    PyErr_SetString(PyExc_ValueError, "remove(x): x not in container");
+    return nullptr;
+  }
+  if (AssignItem(pself, match_index, nullptr) < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* ExtendMethod(PyObject* self, PyObject* value) {
+  return Extend(reinterpret_cast<RepeatedScalarContainer*>(self), value);
+}
+
+static PyObject* RichCompare(PyObject* pself, PyObject* other, int opid) {
+  if (opid != Py_EQ && opid != Py_NE) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  // Copy the contents of this repeated scalar container, and other if it is
+  // also a repeated scalar container, into Python lists so we can delegate
+  // to the list's compare method.
+
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  if (full_slice == nullptr) {
+    return nullptr;
+  }
+
+  ScopedPyObjectPtr other_list_deleter;
+  if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) {
+    other_list_deleter.reset(Subscript(other, full_slice.get()));
+    other = other_list_deleter.get();
+  }
+
+  ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  return PyObject_RichCompare(list.get(), other, opid);
+}
+
+PyObject* Reduce(PyObject* unused_self, PyObject* unused_other) {
+  PyErr_Format(PickleError_class,
+               "can't pickle repeated message fields, convert to list first");
+  return nullptr;
+}
+
+static PyObject* Sort(PyObject* pself, PyObject* args, PyObject* kwds) {
+  // Support the old sort_function argument for backwards
+  // compatibility.
+  if (kwds != nullptr) {
+    PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
+    if (sort_func != nullptr) {
+      // Must set before deleting as sort_func is a borrowed reference
+      // and kwds might be the only thing keeping it alive.
+      if (PyDict_SetItemString(kwds, "cmp", sort_func) == -1) return nullptr;
+      if (PyDict_DelItemString(kwds, "sort_function") == -1) return nullptr;
+    }
+  }
+
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  if (full_slice == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr m(PyObject_GetAttrString(list.get(), "sort"));
+  if (m == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr res(PyObject_Call(m.get(), args, kwds));
+  if (res == nullptr) {
+    return nullptr;
+  }
+  int ret = InternalAssignRepeatedField(
+      reinterpret_cast<RepeatedScalarContainer*>(pself), list.get());
+  if (ret < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* Reverse(PyObject* pself) {
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  if (full_slice == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr res(PyObject_CallMethod(list.get(), "reverse", nullptr));
+  if (res == nullptr) {
+    return nullptr;
+  }
+  int ret = InternalAssignRepeatedField(
+      reinterpret_cast<RepeatedScalarContainer*>(pself), list.get());
+  if (ret < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* Pop(PyObject* pself, PyObject* args) {
+  Py_ssize_t index = -1;
+  if (!PyArg_ParseTuple(args, "|n", &index)) {
+    return nullptr;
+  }
+  PyObject* item = Item(pself, index);
+  if (item == nullptr) {
+    PyErr_Format(PyExc_IndexError, "list index (%zd) out of range", index);
+    return nullptr;
+  }
+  if (AssignItem(pself, index, nullptr) < 0) {
+    return nullptr;
+  }
+  return item;
+}
+
+static PyObject* ToStr(PyObject* pself) {
+  ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
+  if (full_slice == nullptr) {
+    return nullptr;
+  }
+  ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
+  if (list == nullptr) {
+    return nullptr;
+  }
+  return PyObject_Repr(list.get());
+}
+
+static PyObject* MergeFrom(PyObject* pself, PyObject* arg) {
+  return Extend(reinterpret_cast<RepeatedScalarContainer*>(pself), arg);
+}
+
+// The private constructor of RepeatedScalarContainer objects.
+RepeatedScalarContainer* NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return nullptr;
+  }
+
+  RepeatedScalarContainer* self = reinterpret_cast<RepeatedScalarContainer*>(
+      PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+
+  return self;
+}
+
+PyObject* DeepCopy(PyObject* pself, PyObject* arg) {
+  return reinterpret_cast<RepeatedScalarContainer*>(pself)->DeepCopy();
+}
+
+static void Dealloc(PyObject* pself) {
+  reinterpret_cast<RepeatedScalarContainer*>(pself)->RemoveFromParentCache();
+  Py_TYPE(pself)->tp_free(pself);
+}
+
+static PySequenceMethods SqMethods = {
+    Len,       /* sq_length */
+    nullptr,   /* sq_concat */
+    nullptr,   /* sq_repeat */
+    Item,      /* sq_item */
+    nullptr,   /* sq_slice */
+    AssignItem /* sq_ass_item */
+};
+
+static PyMappingMethods MpMethods = {
+    Len,          /* mp_length */
+    Subscript,    /* mp_subscript */
+    AssSubscript, /* mp_ass_subscript */
+};
+
+static PyMethodDef Methods[] = {
+    {"__deepcopy__", DeepCopy, METH_VARARGS, "Makes a deep copy of the class."},
+    {"__reduce__", Reduce, METH_NOARGS,
+     "Outputs picklable representation of the repeated field."},
+    {"append", AppendMethod, METH_O,
+     "Appends an object to the repeated container."},
+    {"extend", ExtendMethod, METH_O,
+     "Appends objects to the repeated container."},
+    {"insert", Insert, METH_VARARGS,
+     "Inserts an object at the specified position in the container."},
+    {"pop", Pop, METH_VARARGS,
+     "Removes an object from the repeated container and returns it."},
+    {"remove", Remove, METH_O,
+     "Removes an object from the repeated container."},
+    {"sort", reinterpret_cast<PyCFunction>(Sort), METH_VARARGS | METH_KEYWORDS,
+     "Sorts the repeated container."},
+    {"reverse", reinterpret_cast<PyCFunction>(Reverse), METH_NOARGS,
+     "Reverses elements order of the repeated container."},
+    {"MergeFrom", static_cast<PyCFunction>(MergeFrom), METH_O,
+     "Merges a repeated container into the current container."},
+    {nullptr, nullptr}};
+
+}  // namespace repeated_scalar_container
+
+PyTypeObject RepeatedScalarContainer_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".RepeatedScalarContainer",              // tp_name
+    sizeof(RepeatedScalarContainer),         // tp_basicsize
+    0,                                       //  tp_itemsize
+    repeated_scalar_container::Dealloc,      //  tp_dealloc
+#if PY_VERSION_HEX >= 0x03080000
+    0,                                       //  tp_vectorcall_offset
+#else
+    nullptr,                                 //  tp_print
+#endif
+    nullptr,                                 //  tp_getattr
+    nullptr,                                 //  tp_setattr
+    nullptr,                                 //  tp_compare
+    repeated_scalar_container::ToStr,        //  tp_repr
+    nullptr,                                 //  tp_as_number
+    &repeated_scalar_container::SqMethods,   //  tp_as_sequence
+    &repeated_scalar_container::MpMethods,   //  tp_as_mapping
+    PyObject_HashNotImplemented,             //  tp_hash
+    nullptr,                                 //  tp_call
+    nullptr,                                 //  tp_str
+    nullptr,                                 //  tp_getattro
+    nullptr,                                 //  tp_setattro
+    nullptr,                                 //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                      //  tp_flags
+    "A Repeated scalar container",           //  tp_doc
+    nullptr,                                 //  tp_traverse
+    nullptr,                                 //  tp_clear
+    repeated_scalar_container::RichCompare,  //  tp_richcompare
+    0,                                       //  tp_weaklistoffset
+    nullptr,                                 //  tp_iter
+    nullptr,                                 //  tp_iternext
+    repeated_scalar_container::Methods,      //  tp_methods
+    nullptr,                                 //  tp_members
+    nullptr,                                 //  tp_getset
+    nullptr,                                 //  tp_base
+    nullptr,                                 //  tp_dict
+    nullptr,                                 //  tp_descr_get
+    nullptr,                                 //  tp_descr_set
+    0,                                       //  tp_dictoffset
+    nullptr,                                 //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h
new file mode 100644
index 0000000..67423ab
--- /dev/null
+++ b/python/google/protobuf/pyext/repeated_scalar_container.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: anuraag@google.com (Anuraag Agrawal)
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+typedef struct RepeatedScalarContainer : public ContainerBase {
+} RepeatedScalarContainer;
+
+extern PyTypeObject RepeatedScalarContainer_Type;
+
+namespace repeated_scalar_container {
+
+// Builds a RepeatedScalarContainer object, from a parent message and a
+// field descriptor.
+extern RepeatedScalarContainer* NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
+
+// Appends the scalar 'item' to the end of the container 'self'.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* Append(RepeatedScalarContainer* self, PyObject* item);
+
+// Appends all the elements in the input iterator to the container.
+//
+// Returns None if successful; returns NULL and sets an exception if
+// unsuccessful.
+PyObject* Extend(RepeatedScalarContainer* self, PyObject* value);
+
+}  // namespace repeated_scalar_container
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/safe_numerics.h b/python/google/protobuf/pyext/safe_numerics.h
new file mode 100644
index 0000000..93ae640
--- /dev/null
+++ b/python/google/protobuf/pyext/safe_numerics.h
@@ -0,0 +1,164 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__
+// Copied from chromium with only changes to the namespace.
+
+#include <limits>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+template <bool SameSize, bool DestLarger,
+          bool DestIsSigned, bool SourceIsSigned>
+struct IsValidNumericCastImpl;
+
+#define BASE_NUMERIC_CAST_CASE_SPECIALIZATION(A, B, C, D, Code) \
+template <> struct IsValidNumericCastImpl<A, B, C, D> { \
+  template <class Source, class DestBounds> static inline bool Test( \
+      Source source, DestBounds min, DestBounds max) { \
+    return Code; \
+  } \
+}
+
+#define BASE_NUMERIC_CAST_CASE_SAME_SIZE(DestSigned, SourceSigned, Code) \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      true, true, DestSigned, SourceSigned, Code); \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      true, false, DestSigned, SourceSigned, Code)
+
+#define BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(DestSigned, SourceSigned, Code) \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      false, false, DestSigned, SourceSigned, Code); \
+
+#define BASE_NUMERIC_CAST_CASE_DEST_LARGER(DestSigned, SourceSigned, Code) \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      false, true, DestSigned, SourceSigned, Code); \
+
+// The three top level cases are:
+// - Same size
+// - Source larger
+// - Dest larger
+// And for each of those three cases, we handle the 4 different possibilities
+// of signed and unsigned. This gives 12 cases to handle, which we enumerate
+// below.
+//
+// The last argument in each of the macros is the actual comparison code. It
+// has three arguments available, source (the value), and min/max which are
+// the ranges of the destination.
+
+
+// These are the cases where both types have the same size.
+
+// Both signed.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, true, true);
+// Both unsigned.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, false, true);
+// Dest unsigned, Source signed.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, true, source >= 0);
+// Dest signed, Source unsigned.
+// This cast is OK because Dest's max must be less than Source's.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, false,
+                                 source <= static_cast<Source>(max));
+
+
+// These are the cases where Source is larger.
+
+// Both unsigned.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, false, source <= max);
+// Both signed.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, true,
+                                     source >= min && source <= max);
+// Dest is unsigned, Source is signed.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, true,
+                                     source >= 0 && source <= max);
+// Dest is signed, Source is unsigned.
+// This cast is OK because Dest's max must be less than Source's.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, false,
+                                     source <= static_cast<Source>(max));
+
+
+// These are the cases where Dest is larger.
+
+// Both unsigned.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, false, true);
+// Both signed.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, true, true);
+// Dest is unsigned, Source is signed.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, true, source >= 0);
+// Dest is signed, Source is unsigned.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, false, true);
+
+#undef BASE_NUMERIC_CAST_CASE_SPECIALIZATION
+#undef BASE_NUMERIC_CAST_CASE_SAME_SIZE
+#undef BASE_NUMERIC_CAST_CASE_SOURCE_LARGER
+#undef BASE_NUMERIC_CAST_CASE_DEST_LARGER
+
+
+// The main test for whether the conversion will under or overflow.
+template <class Dest, class Source>
+inline bool IsValidNumericCast(Source source) {
+  typedef std::numeric_limits<Source> SourceLimits;
+  typedef std::numeric_limits<Dest> DestLimits;
+  static_assert(SourceLimits::is_specialized, "argument must be numeric");
+  static_assert(SourceLimits::is_integer, "argument must be integral");
+  static_assert(DestLimits::is_specialized, "result must be numeric");
+  static_assert(DestLimits::is_integer, "result must be integral");
+
+  return IsValidNumericCastImpl<
+      sizeof(Dest) == sizeof(Source),
+      (sizeof(Dest) > sizeof(Source)),
+      DestLimits::is_signed,
+      SourceLimits::is_signed>::Test(
+          source,
+          DestLimits::min(),
+          DestLimits::max());
+}
+
+// checked_numeric_cast<> is analogous to static_cast<> for numeric types,
+// except that it CHECKs that the specified numeric conversion will not
+// overflow or underflow. Floating point arguments are not currently allowed
+// (this is static_asserted), though this could be supported if necessary.
+template <class Dest, class Source>
+inline Dest checked_numeric_cast(Source source) {
+  GOOGLE_CHECK(IsValidNumericCast<Dest>(source));
+  return static_cast<Dest>(source);
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__
diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
new file mode 100644
index 0000000..ad3fa94
--- /dev/null
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -0,0 +1,101 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: tibell@google.com (Johan Tibell)
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
+
+#include <google/protobuf/stubs/common.h>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Owns a python object and decrements the reference count on destruction.
+// This class is not threadsafe.
+template <typename PyObjectStruct>
+class ScopedPythonPtr {
+ public:
+  // Takes the ownership of the specified object to ScopedPythonPtr.
+  // The reference count of the specified py_object is not incremented.
+  explicit ScopedPythonPtr(PyObjectStruct* py_object = nullptr)
+      : ptr_(py_object) {}
+
+  // If a PyObject is owned, decrement its reference count.
+  ~ScopedPythonPtr() { Py_XDECREF(ptr_); }
+
+  // Deletes the current owned object, if any.
+  // Then takes ownership of a new object without incrementing the reference
+  // count.
+  // This function must be called with a reference that you own.
+  //   this->reset(this->get()) is wrong!
+  //   this->reset(this->release()) is OK.
+  PyObjectStruct* reset(PyObjectStruct* p = nullptr) {
+    Py_XDECREF(ptr_);
+    ptr_ = p;
+    return ptr_;
+  }
+
+  // Releases ownership of the object without decrementing the reference count.
+  // The caller now owns the returned reference.
+  PyObjectStruct* release() {
+    PyObject* p = ptr_;
+    ptr_ = nullptr;
+    return p;
+  }
+
+  PyObjectStruct* get() const { return ptr_; }
+
+  PyObject* as_pyobject() const { return reinterpret_cast<PyObject*>(ptr_); }
+
+  // Increments the reference count of the current object.
+  // Should not be called when no object is held.
+  void inc() const { Py_INCREF(ptr_); }
+
+  // True when a ScopedPyObjectPtr and a raw pointer refer to the same object.
+  // Comparison operators are non reflexive.
+  bool operator==(const PyObjectStruct* p) const { return ptr_ == p; }
+  bool operator!=(const PyObjectStruct* p) const { return ptr_ != p; }
+
+ private:
+  PyObjectStruct* ptr_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ScopedPythonPtr);
+};
+
+typedef ScopedPythonPtr<PyObject> ScopedPyObjectPtr;
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
diff --git a/python/google/protobuf/pyext/unknown_field_set.cc b/python/google/protobuf/pyext/unknown_field_set.cc
new file mode 100644
index 0000000..42f9bbc
--- /dev/null
+++ b/python/google/protobuf/pyext/unknown_field_set.cc
@@ -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.
+
+#include <google/protobuf/pyext/unknown_field_set.h>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <memory>
+#include <set>
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace unknown_field_set {
+
+static Py_ssize_t Len(PyObject* pself) {
+  PyUnknownFieldSet* self = reinterpret_cast<PyUnknownFieldSet*>(pself);
+  if (self->fields == nullptr) {
+    PyErr_Format(PyExc_ValueError, "UnknownFieldSet does not exist. ");
+    return -1;
+  }
+  return self->fields->field_count();
+}
+
+PyObject* NewPyUnknownField(PyUnknownFieldSet* parent, Py_ssize_t index);
+
+static PyObject* Item(PyObject* pself, Py_ssize_t index) {
+  PyUnknownFieldSet* self = reinterpret_cast<PyUnknownFieldSet*>(pself);
+  if (self->fields == nullptr) {
+    PyErr_Format(PyExc_ValueError, "UnknownFieldSet does not exist. ");
+    return nullptr;
+  }
+  Py_ssize_t total_size = self->fields->field_count();
+  if (index < 0) {
+    index = total_size + index;
+  }
+  if (index < 0 || index >= total_size) {
+    PyErr_Format(PyExc_IndexError, "index (%zd) out of range", index);
+    return nullptr;
+  }
+  return unknown_field_set::NewPyUnknownField(self, index);
+}
+
+PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
+  if (args == nullptr || PyTuple_Size(args) != 1) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Must provide a message to create UnknownFieldSet");
+    return nullptr;
+  }
+
+  PyObject* c_message;
+  if (!PyArg_ParseTuple(args, "O", &c_message)) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Must provide a message to create UnknownFieldSet");
+    return nullptr;
+  }
+
+  if (!PyObject_TypeCheck(c_message, CMessage_Type)) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to UnknownFieldSet() must be a message "
+                 "got %s.",
+                 Py_TYPE(c_message)->tp_name);
+    return nullptr;
+  }
+
+  PyUnknownFieldSet* self = reinterpret_cast<PyUnknownFieldSet*>(
+      PyType_GenericAlloc(&PyUnknownFieldSet_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  // Top UnknownFieldSet should set parent nullptr.
+  self->parent = nullptr;
+
+  // Copy c_message's UnknownFieldSet.
+  Message* message = reinterpret_cast<CMessage*>(c_message)->message;
+  const Reflection* reflection = message->GetReflection();
+  self->fields = new google::protobuf::UnknownFieldSet;
+  self->fields->MergeFrom(reflection->GetUnknownFields(*message));
+  return reinterpret_cast<PyObject*>(self);
+}
+
+PyObject* NewPyUnknownField(PyUnknownFieldSet* parent, Py_ssize_t index) {
+  PyUnknownField* self = reinterpret_cast<PyUnknownField*>(
+      PyType_GenericAlloc(&PyUnknownField_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->index = index;
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static void Dealloc(PyObject* pself) {
+  PyUnknownFieldSet* self = reinterpret_cast<PyUnknownFieldSet*>(pself);
+  if (self->parent == nullptr) {
+    delete self->fields;
+  } else {
+    Py_CLEAR(self->parent);
+  }
+  auto* py_type = Py_TYPE(pself);
+  self->~PyUnknownFieldSet();
+  py_type->tp_free(pself);
+}
+
+static PySequenceMethods SqMethods = {
+    Len,     /* sq_length */
+    nullptr, /* sq_concat */
+    nullptr, /* sq_repeat */
+    Item,    /* sq_item */
+    nullptr, /* sq_slice */
+    nullptr, /* sq_ass_item */
+};
+
+}  // namespace unknown_field_set
+
+PyTypeObject PyUnknownFieldSet_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".PyUnknownFieldSet",        // tp_name
+    sizeof(PyUnknownFieldSet),   // tp_basicsize
+    0,                           //  tp_itemsize
+    unknown_field_set::Dealloc,  //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                        //  tp_getattr
+    nullptr,                        //  tp_setattr
+    nullptr,                        //  tp_compare
+    nullptr,                        //  tp_repr
+    nullptr,                        //  tp_as_number
+    &unknown_field_set::SqMethods,  //  tp_as_sequence
+    nullptr,                        //  tp_as_mapping
+    PyObject_HashNotImplemented,    //  tp_hash
+    nullptr,                        //  tp_call
+    nullptr,                        //  tp_str
+    nullptr,                        //  tp_getattro
+    nullptr,                        //  tp_setattro
+    nullptr,                        //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,             //  tp_flags
+    "unknown field set",            //  tp_doc
+    nullptr,                        //  tp_traverse
+    nullptr,                        //  tp_clear
+    nullptr,                        //  tp_richcompare
+    0,                              //  tp_weaklistoffset
+    nullptr,                        //  tp_iter
+    nullptr,                        //  tp_iternext
+    nullptr,                        //  tp_methods
+    nullptr,                        //  tp_members
+    nullptr,                        //  tp_getset
+    nullptr,                        //  tp_base
+    nullptr,                        //  tp_dict
+    nullptr,                        //  tp_descr_get
+    nullptr,                        //  tp_descr_set
+    0,                              //  tp_dictoffset
+    nullptr,                        //  tp_init
+    nullptr,                        //  tp_alloc
+    unknown_field_set::New,         //  tp_new
+};
+
+namespace unknown_field {
+static PyObject* PyUnknownFieldSet_FromUnknownFieldSet(
+    PyUnknownFieldSet* parent, const UnknownFieldSet& fields) {
+  PyUnknownFieldSet* self = reinterpret_cast<PyUnknownFieldSet*>(
+      PyType_GenericAlloc(&PyUnknownFieldSet_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->fields = const_cast<UnknownFieldSet*>(&fields);
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+const UnknownField* GetUnknownField(PyUnknownField* self) {
+  const UnknownFieldSet* fields = self->parent->fields;
+  if (fields == nullptr) {
+    PyErr_Format(PyExc_ValueError, "UnknownField does not exist. ");
+    return nullptr;
+  }
+  Py_ssize_t total_size = fields->field_count();
+  if (self->index >= total_size) {
+    PyErr_Format(PyExc_ValueError, "UnknownField does not exist. ");
+    return nullptr;
+  }
+  return &fields->field(self->index);
+}
+
+static PyObject* GetFieldNumber(PyUnknownField* self, void* closure) {
+  const UnknownField* unknown_field = GetUnknownField(self);
+  if (unknown_field == nullptr) {
+    return nullptr;
+  }
+  return PyLong_FromLong(unknown_field->number());
+}
+
+using internal::WireFormatLite;
+static PyObject* GetWireType(PyUnknownField* self, void* closure) {
+  const UnknownField* unknown_field = GetUnknownField(self);
+  if (unknown_field == nullptr) {
+    return nullptr;
+  }
+
+  // Assign a default value to suppress may-uninitialized warnings (errors
+  // when built in some places).
+  WireFormatLite::WireType wire_type = WireFormatLite::WIRETYPE_VARINT;
+  switch (unknown_field->type()) {
+    case UnknownField::TYPE_VARINT:
+      wire_type = WireFormatLite::WIRETYPE_VARINT;
+      break;
+    case UnknownField::TYPE_FIXED32:
+      wire_type = WireFormatLite::WIRETYPE_FIXED32;
+      break;
+    case UnknownField::TYPE_FIXED64:
+      wire_type = WireFormatLite::WIRETYPE_FIXED64;
+      break;
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      wire_type = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+      break;
+    case UnknownField::TYPE_GROUP:
+      wire_type = WireFormatLite::WIRETYPE_START_GROUP;
+      break;
+  }
+  return PyLong_FromLong(wire_type);
+}
+
+static PyObject* GetData(PyUnknownField* self, void* closure) {
+  const UnknownField* field = GetUnknownField(self);
+  if (field == nullptr) {
+    return nullptr;
+  }
+  PyObject* data = nullptr;
+  switch (field->type()) {
+    case UnknownField::TYPE_VARINT:
+      data = PyLong_FromUnsignedLongLong(field->varint());
+      break;
+    case UnknownField::TYPE_FIXED32:
+      data = PyLong_FromUnsignedLong(field->fixed32());
+      break;
+    case UnknownField::TYPE_FIXED64:
+      data = PyLong_FromUnsignedLongLong(field->fixed64());
+      break;
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      data = PyBytes_FromStringAndSize(field->length_delimited().data(),
+                                       field->GetLengthDelimitedSize());
+      break;
+    case UnknownField::TYPE_GROUP:
+      data =
+          PyUnknownFieldSet_FromUnknownFieldSet(self->parent, field->group());
+      break;
+  }
+  return data;
+}
+
+static void Dealloc(PyObject* pself) {
+  PyUnknownField* self = reinterpret_cast<PyUnknownField*>(pself);
+  Py_CLEAR(self->parent);
+}
+
+static PyGetSetDef Getters[] = {
+    {"field_number", (getter)GetFieldNumber, nullptr},
+    {"wire_type", (getter)GetWireType, nullptr},
+    {"data", (getter)GetData, nullptr},
+    {nullptr},
+};
+
+}  // namespace unknown_field
+
+PyTypeObject PyUnknownField_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".PyUnknownField",       // tp_name
+    sizeof(PyUnknownField),  //  tp_basicsize
+    0,                       //  tp_itemsize
+    unknown_field::Dealloc,  //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                      //  tp_getattr
+    nullptr,                      //  tp_setattr
+    nullptr,                      //  tp_compare
+    nullptr,                      //  tp_repr
+    nullptr,                      //  tp_as_number
+    nullptr,                      //  tp_as_sequence
+    nullptr,                      //  tp_as_mapping
+    PyObject_HashNotImplemented,  //  tp_hash
+    nullptr,                      //  tp_call
+    nullptr,                      //  tp_str
+    nullptr,                      //  tp_getattro
+    nullptr,                      //  tp_setattro
+    nullptr,                      //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,           //  tp_flags
+    "unknown field",              //  tp_doc
+    nullptr,                      //  tp_traverse
+    nullptr,                      //  tp_clear
+    nullptr,                      //  tp_richcompare
+    0,                            //  tp_weaklistoffset
+    nullptr,                      //  tp_iter
+    nullptr,                      //  tp_iternext
+    nullptr,                      //  tp_methods
+    nullptr,                      //  tp_members
+    unknown_field::Getters,       //  tp_getset
+    nullptr,                      //  tp_base
+    nullptr,                      //  tp_dict
+    nullptr,                      //  tp_descr_get
+    nullptr,                      //  tp_descr_set
+    0,                            //  tp_dictoffset
+    nullptr,                      //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/unknown_field_set.h b/python/google/protobuf/pyext/unknown_field_set.h
new file mode 100644
index 0000000..3fa764d
--- /dev/null
+++ b/python/google/protobuf/pyext/unknown_field_set.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_PYTHON_CPP_UNKNOWN_FIELD_SET_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_UNKNOWN_FIELD_SET_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <memory>
+#include <set>
+
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+
+class UnknownField;
+class UnknownFieldSet;
+
+namespace python {
+struct CMessage;
+
+struct PyUnknownFieldSet {
+  PyObject_HEAD;
+  // If parent is nullptr, it is a top UnknownFieldSet.
+  PyUnknownFieldSet* parent;
+
+  // Top UnknownFieldSet owns fields pointer. Sub UnknownFieldSet
+  // does not own fields pointer.
+  UnknownFieldSet* fields;
+};
+
+struct PyUnknownField {
+  PyObject_HEAD;
+  // Every Python PyUnknownField holds a reference to its parent
+  // PyUnknownFieldSet in order to keep it alive.
+  PyUnknownFieldSet* parent;
+
+  // The UnknownField index in UnknownFieldSet.
+  Py_ssize_t index;
+};
+
+extern PyTypeObject PyUnknownFieldSet_Type;
+extern PyTypeObject PyUnknownField_Type;
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_UNKNOWN_FIELD_SET_H__
diff --git a/python/google/protobuf/pyext/unknown_fields.cc b/python/google/protobuf/pyext/unknown_fields.cc
new file mode 100644
index 0000000..dcd63b2
--- /dev/null
+++ b/python/google/protobuf/pyext/unknown_fields.cc
@@ -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.
+
+#include <google/protobuf/pyext/unknown_fields.h>
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <set>
+#include <memory>
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+namespace unknown_fields {
+
+static Py_ssize_t Len(PyObject* pself) {
+  PyUnknownFields* self =
+      reinterpret_cast<PyUnknownFields*>(pself);
+  if (self->fields == nullptr) {
+    PyErr_Format(PyExc_ValueError,
+                 "UnknownFields does not exist. "
+                 "The parent message might be cleared.");
+    return -1;
+  }
+  return self->fields->field_count();
+}
+
+void Clear(PyUnknownFields* self) {
+  for (std::set<PyUnknownFields*>::iterator it =
+           self->sub_unknown_fields.begin();
+       it != self->sub_unknown_fields.end(); it++) {
+    Clear(*it);
+  }
+  self->fields = nullptr;
+  self->sub_unknown_fields.clear();
+}
+
+PyObject* NewPyUnknownFieldRef(PyUnknownFields* parent,
+                               Py_ssize_t index);
+
+static PyObject* Item(PyObject* pself, Py_ssize_t index) {
+  PyUnknownFields* self =
+      reinterpret_cast<PyUnknownFields*>(pself);
+  if (self->fields == nullptr) {
+    PyErr_Format(PyExc_ValueError,
+                 "UnknownFields does not exist. "
+                 "The parent message might be cleared.");
+    return nullptr;
+  }
+  Py_ssize_t total_size = self->fields->field_count();
+  if (index < 0) {
+    index = total_size + index;
+  }
+  if (index < 0 || index >= total_size) {
+    PyErr_Format(PyExc_IndexError,
+                 "index (%zd) out of range",
+                 index);
+    return nullptr;
+  }
+
+  return unknown_fields::NewPyUnknownFieldRef(self, index);
+}
+
+PyObject* NewPyUnknownFields(CMessage* c_message) {
+  PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
+      PyType_GenericAlloc(&PyUnknownFields_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+  // Call "placement new" to initialize PyUnknownFields.
+  new (self) PyUnknownFields;
+
+  Py_INCREF(c_message);
+  self->parent = reinterpret_cast<PyObject*>(c_message);
+  Message* message = c_message->message;
+  const Reflection* reflection = message->GetReflection();
+  self->fields = &reflection->GetUnknownFields(*message);
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+PyObject* NewPyUnknownFieldRef(PyUnknownFields* parent,
+                               Py_ssize_t index) {
+  PyUnknownFieldRef* self = reinterpret_cast<PyUnknownFieldRef*>(
+      PyType_GenericAlloc(&PyUnknownFieldRef_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+
+  Py_INCREF(parent);
+  self->parent = parent;
+  self->index = index;
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static void Dealloc(PyObject* pself) {
+  PyUnknownFields* self =
+      reinterpret_cast<PyUnknownFields*>(pself);
+  if (PyObject_TypeCheck(self->parent, &PyUnknownFields_Type)) {
+    reinterpret_cast<PyUnknownFields*>(
+        self->parent)->sub_unknown_fields.erase(self);
+  } else {
+    reinterpret_cast<CMessage*>(self->parent)->unknown_field_set = nullptr;
+  }
+  Py_CLEAR(self->parent);
+  auto* py_type = Py_TYPE(pself);
+  self->~PyUnknownFields();
+  py_type->tp_free(pself);
+}
+
+static PySequenceMethods SqMethods = {
+    Len,     /* sq_length */
+    nullptr, /* sq_concat */
+    nullptr, /* sq_repeat */
+    Item,    /* sq_item */
+    nullptr, /* sq_slice */
+    nullptr, /* sq_ass_item */
+};
+
+}  // namespace unknown_fields
+
+PyTypeObject PyUnknownFields_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".PyUnknownFields",       // tp_name
+    sizeof(PyUnknownFields),  // tp_basicsize
+    0,                        //  tp_itemsize
+    unknown_fields::Dealloc,  //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                      //  tp_getattr
+    nullptr,                      //  tp_setattr
+    nullptr,                      //  tp_compare
+    nullptr,                      //  tp_repr
+    nullptr,                      //  tp_as_number
+    &unknown_fields::SqMethods,   //  tp_as_sequence
+    nullptr,                      //  tp_as_mapping
+    PyObject_HashNotImplemented,  //  tp_hash
+    nullptr,                      //  tp_call
+    nullptr,                      //  tp_str
+    nullptr,                      //  tp_getattro
+    nullptr,                      //  tp_setattro
+    nullptr,                      //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,           //  tp_flags
+    "unknown field set",          //  tp_doc
+    nullptr,                      //  tp_traverse
+    nullptr,                      //  tp_clear
+    nullptr,                      //  tp_richcompare
+    0,                            //  tp_weaklistoffset
+    nullptr,                      //  tp_iter
+    nullptr,                      //  tp_iternext
+    nullptr,                      //  tp_methods
+    nullptr,                      //  tp_members
+    nullptr,                      //  tp_getset
+    nullptr,                      //  tp_base
+    nullptr,                      //  tp_dict
+    nullptr,                      //  tp_descr_get
+    nullptr,                      //  tp_descr_set
+    0,                            //  tp_dictoffset
+    nullptr,                      //  tp_init
+};
+
+namespace unknown_field {
+static PyObject* PyUnknownFields_FromUnknownFieldSet(
+    PyUnknownFields* parent, const UnknownFieldSet& fields) {
+  PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
+      PyType_GenericAlloc(&PyUnknownFields_Type, 0));
+  if (self == nullptr) {
+    return nullptr;
+  }
+  // Call "placement new" to initialize PyUnknownFields.
+  new (self) PyUnknownFields;
+
+  Py_INCREF(parent);
+  self->parent = reinterpret_cast<PyObject*>(parent);
+  self->fields = &fields;
+  parent->sub_unknown_fields.emplace(self);
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+const UnknownField* GetUnknownField(PyUnknownFieldRef* self) {
+  const UnknownFieldSet* fields = self->parent->fields;
+  if (fields == nullptr) {
+    PyErr_Format(PyExc_ValueError,
+                 "UnknownField does not exist. "
+                 "The parent message might be cleared.");
+    return nullptr;
+  }
+  Py_ssize_t total_size = fields->field_count();
+  if (self->index >= total_size) {
+    PyErr_Format(PyExc_ValueError,
+                 "UnknownField does not exist. "
+                 "The parent message might be cleared.");
+    return nullptr;
+  }
+  return &fields->field(self->index);
+}
+
+static PyObject* GetFieldNumber(PyUnknownFieldRef* self, void *closure) {
+  const UnknownField* unknown_field = GetUnknownField(self);
+  if (unknown_field == nullptr) {
+    return nullptr;
+  }
+  return PyLong_FromLong(unknown_field->number());
+}
+
+using internal::WireFormatLite;
+static PyObject* GetWireType(PyUnknownFieldRef* self, void *closure) {
+  const UnknownField* unknown_field = GetUnknownField(self);
+  if (unknown_field == nullptr) {
+    return nullptr;
+  }
+
+  // Assign a default value to suppress may-uninitialized warnings (errors
+  // when built in some places).
+  WireFormatLite::WireType wire_type = WireFormatLite::WIRETYPE_VARINT;
+  switch (unknown_field->type()) {
+    case UnknownField::TYPE_VARINT:
+      wire_type = WireFormatLite::WIRETYPE_VARINT;
+      break;
+    case UnknownField::TYPE_FIXED32:
+      wire_type = WireFormatLite::WIRETYPE_FIXED32;
+      break;
+    case UnknownField::TYPE_FIXED64:
+      wire_type = WireFormatLite::WIRETYPE_FIXED64;
+      break;
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      wire_type = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+      break;
+    case UnknownField::TYPE_GROUP:
+      wire_type = WireFormatLite::WIRETYPE_START_GROUP;
+      break;
+  }
+  return PyLong_FromLong(wire_type);
+}
+
+static PyObject* GetData(PyUnknownFieldRef* self, void *closure) {
+  const UnknownField* field = GetUnknownField(self);
+  if (field == nullptr) {
+    return nullptr;
+  }
+  PyObject* data = nullptr;
+  switch (field->type()) {
+    case UnknownField::TYPE_VARINT:
+      data = PyLong_FromUnsignedLongLong(field->varint());
+      break;
+    case UnknownField::TYPE_FIXED32:
+      data = PyLong_FromUnsignedLong(field->fixed32());
+      break;
+    case UnknownField::TYPE_FIXED64:
+      data = PyLong_FromUnsignedLongLong(field->fixed64());
+      break;
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      data = PyBytes_FromStringAndSize(field->length_delimited().data(),
+                                       field->GetLengthDelimitedSize());
+      break;
+    case UnknownField::TYPE_GROUP:
+      data = PyUnknownFields_FromUnknownFieldSet(
+          self->parent, field->group());
+      break;
+  }
+  return data;
+}
+
+static void Dealloc(PyObject* pself) {
+  PyUnknownFieldRef* self =
+      reinterpret_cast<PyUnknownFieldRef*>(pself);
+  Py_CLEAR(self->parent);
+}
+
+static PyGetSetDef Getters[] = {
+    {"field_number", (getter)GetFieldNumber, nullptr},
+    {"wire_type", (getter)GetWireType, nullptr},
+    {"data", (getter)GetData, nullptr},
+    {nullptr},
+};
+
+}  // namespace unknown_field
+
+PyTypeObject PyUnknownFieldRef_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".PyUnknownFieldRef",       // tp_name
+    sizeof(PyUnknownFieldRef),  //  tp_basicsize
+    0,                          //  tp_itemsize
+    unknown_field::Dealloc,     //  tp_dealloc
+#if PY_VERSION_HEX < 0x03080000
+    nullptr,  // tp_print
+#else
+    0,  // tp_vectorcall_offset
+#endif
+    nullptr,                      //  tp_getattr
+    nullptr,                      //  tp_setattr
+    nullptr,                      //  tp_compare
+    nullptr,                      //  tp_repr
+    nullptr,                      //  tp_as_number
+    nullptr,                      //  tp_as_sequence
+    nullptr,                      //  tp_as_mapping
+    PyObject_HashNotImplemented,  //  tp_hash
+    nullptr,                      //  tp_call
+    nullptr,                      //  tp_str
+    nullptr,                      //  tp_getattro
+    nullptr,                      //  tp_setattro
+    nullptr,                      //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,           //  tp_flags
+    "unknown field",              //  tp_doc
+    nullptr,                      //  tp_traverse
+    nullptr,                      //  tp_clear
+    nullptr,                      //  tp_richcompare
+    0,                            //  tp_weaklistoffset
+    nullptr,                      //  tp_iter
+    nullptr,                      //  tp_iternext
+    nullptr,                      //  tp_methods
+    nullptr,                      //  tp_members
+    unknown_field::Getters,       //  tp_getset
+    nullptr,                      //  tp_base
+    nullptr,                      //  tp_dict
+    nullptr,                      //  tp_descr_get
+    nullptr,                      //  tp_descr_set
+    0,                            //  tp_dictoffset
+    nullptr,                      //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/unknown_fields.h b/python/google/protobuf/pyext/unknown_fields.h
new file mode 100644
index 0000000..e7b0b35
--- /dev/null
+++ b/python/google/protobuf/pyext/unknown_fields.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_PYTHON_CPP_UNKNOWN_FIELDS_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_UNKNOWN_FIELDS_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#include <memory>
+#include <set>
+
+#include <google/protobuf/pyext/message.h>
+
+namespace google {
+namespace protobuf {
+
+class UnknownField;
+class UnknownFieldSet;
+
+namespace python {
+struct CMessage;
+
+typedef struct PyUnknownFields {
+  PyObject_HEAD;
+  // Strong pointer to the parent CMessage or PyUnknownFields.
+  // The top PyUnknownFields holds a reference to its parent CMessage
+  // object before release.
+  // Sub PyUnknownFields holds reference to parent PyUnknownFields.
+  PyObject* parent;
+
+  // Pointer to the C++ UnknownFieldSet.
+  // PyUnknownFields does not own this pointer.
+  const UnknownFieldSet* fields;
+
+  // Weak references to child unknown fields.
+  std::set<PyUnknownFields*> sub_unknown_fields;
+} PyUnknownFields;
+
+typedef struct PyUnknownFieldRef {
+  PyObject_HEAD;
+  // Every Python PyUnknownFieldRef holds a reference to its parent
+  // PyUnknownFields in order to keep it alive.
+  PyUnknownFields* parent;
+
+  // The UnknownField index in UnknownFields.
+  Py_ssize_t index;
+} UknownFieldRef;
+
+extern PyTypeObject PyUnknownFields_Type;
+extern PyTypeObject PyUnknownFieldRef_Type;
+
+namespace unknown_fields {
+
+// Builds an PyUnknownFields for a specific message.
+PyObject* NewPyUnknownFields(CMessage *parent);
+void Clear(PyUnknownFields* self);
+
+}  // namespace unknown_fields
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_UNKNOWN_FIELDS_H__
diff --git a/python/google/protobuf/python_protobuf.h b/python/google/protobuf/python_protobuf.h
new file mode 100644
index 0000000..4fcf065
--- /dev/null
+++ b/python/google/protobuf/python_protobuf.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.
+
+// Author: qrczak@google.com (Marcin Kowalczyk)
+//
+// This module exposes the C proto inside the given Python proto, in
+// case the Python proto is implemented with a C proto.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__
+#define GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace python {
+
+// Return the pointer to the C proto inside the given Python proto,
+// or NULL when this is not a Python proto implemented with a C proto.
+const Message* GetCProtoInsidePyProto(PyObject* msg);
+Message* MutableCProtoInsidePyProto(PyObject* msg);
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__
diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py
new file mode 100644
index 0000000..81e1885
--- /dev/null
+++ b/python/google/protobuf/reflection.py
@@ -0,0 +1,95 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This code is meant to work on Python 2.4 and above only.
+
+"""Contains a metaclass and helper functions used to create
+protocol message classes from Descriptor objects at runtime.
+
+Recall that a metaclass is the "type" of a class.
+(A class is to a metaclass what an instance is to a class.)
+
+In this case, we use the GeneratedProtocolMessageType metaclass
+to inject all the useful functionality into the classes
+output by the protocol compiler at compile-time.
+
+The upshot of all this is that the real implementation
+details for ALL pure-Python protocol buffers are *here in
+this file*.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+
+from google.protobuf import message_factory
+from google.protobuf import symbol_database
+
+# The type of all Message classes.
+# Part of the public interface, but normally only used by message factories.
+GeneratedProtocolMessageType = message_factory._GENERATED_PROTOCOL_MESSAGE_TYPE
+
+MESSAGE_CLASS_CACHE = {}
+
+
+# Deprecated. Please NEVER use reflection.ParseMessage().
+def ParseMessage(descriptor, byte_str):
+  """Generate a new Message instance from this Descriptor and a byte string.
+
+  DEPRECATED: ParseMessage is deprecated because it is using MakeClass().
+  Please use MessageFactory.GetPrototype() instead.
+
+  Args:
+    descriptor: Protobuf Descriptor object
+    byte_str: Serialized protocol buffer byte string
+
+  Returns:
+    Newly created protobuf Message object.
+  """
+  result_class = MakeClass(descriptor)
+  new_msg = result_class()
+  new_msg.ParseFromString(byte_str)
+  return new_msg
+
+
+# Deprecated. Please NEVER use reflection.MakeClass().
+def MakeClass(descriptor):
+  """Construct a class object for a protobuf described by descriptor.
+
+  DEPRECATED: use MessageFactory.GetPrototype() instead.
+
+  Args:
+    descriptor: A descriptor.Descriptor object describing the protobuf.
+  Returns:
+    The Message class object described by the descriptor.
+  """
+  # Original implementation leads to duplicate message classes, which won't play
+  # well with extensions. Message factory info is also missing.
+  # Redirect to message_factory.
+  return symbol_database.Default().GetPrototype(descriptor)
diff --git a/python/google/protobuf/service.py b/python/google/protobuf/service.py
new file mode 100644
index 0000000..5625246
--- /dev/null
+++ b/python/google/protobuf/service.py
@@ -0,0 +1,228 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""DEPRECATED:  Declares the RPC service interfaces.
+
+This module declares the abstract interfaces underlying proto2 RPC
+services.  These are intended to be independent of any particular RPC
+implementation, so that proto2 services can be used on top of a variety
+of implementations.  Starting with version 2.3.0, RPC implementations should
+not try to build on these, but should instead provide code generator plugins
+which generate code specific to the particular RPC implementation.  This way
+the generated code can be more appropriate for the implementation in use
+and can avoid unnecessary layers of indirection.
+"""
+
+__author__ = 'petar@google.com (Petar Petrov)'
+
+
+class RpcException(Exception):
+  """Exception raised on failed blocking RPC method call."""
+  pass
+
+
+class Service(object):
+
+  """Abstract base interface for protocol-buffer-based RPC services.
+
+  Services themselves are abstract classes (implemented either by servers or as
+  stubs), but they subclass this base interface. The methods of this
+  interface can be used to call the methods of the service without knowing
+  its exact type at compile time (analogous to the Message interface).
+  """
+
+  def GetDescriptor():
+    """Retrieves this service's descriptor."""
+    raise NotImplementedError
+
+  def CallMethod(self, method_descriptor, rpc_controller,
+                 request, done):
+    """Calls a method of the service specified by method_descriptor.
+
+    If "done" is None then the call is blocking and the response
+    message will be returned directly.  Otherwise the call is asynchronous
+    and "done" will later be called with the response value.
+
+    In the blocking case, RpcException will be raised on error.
+
+    Preconditions:
+
+    * method_descriptor.service == GetDescriptor
+    * request is of the exact same classes as returned by
+      GetRequestClass(method).
+    * After the call has started, the request must not be modified.
+    * "rpc_controller" is of the correct type for the RPC implementation being
+      used by this Service.  For stubs, the "correct type" depends on the
+      RpcChannel which the stub is using.
+
+    Postconditions:
+
+    * "done" will be called when the method is complete.  This may be
+      before CallMethod() returns or it may be at some point in the future.
+    * If the RPC failed, the response value passed to "done" will be None.
+      Further details about the failure can be found by querying the
+      RpcController.
+    """
+    raise NotImplementedError
+
+  def GetRequestClass(self, method_descriptor):
+    """Returns the class of the request message for the specified method.
+
+    CallMethod() requires that the request is of a particular subclass of
+    Message. GetRequestClass() gets the default instance of this required
+    type.
+
+    Example:
+      method = service.GetDescriptor().FindMethodByName("Foo")
+      request = stub.GetRequestClass(method)()
+      request.ParseFromString(input)
+      service.CallMethod(method, request, callback)
+    """
+    raise NotImplementedError
+
+  def GetResponseClass(self, method_descriptor):
+    """Returns the class of the response message for the specified method.
+
+    This method isn't really needed, as the RpcChannel's CallMethod constructs
+    the response protocol message. It's provided anyway in case it is useful
+    for the caller to know the response type in advance.
+    """
+    raise NotImplementedError
+
+
+class RpcController(object):
+
+  """An RpcController mediates a single method call.
+
+  The primary purpose of the controller is to provide a way to manipulate
+  settings specific to the RPC implementation and to find out about RPC-level
+  errors. The methods provided by the RpcController interface are intended
+  to be a "least common denominator" set of features which we expect all
+  implementations to support.  Specific implementations may provide more
+  advanced features (e.g. deadline propagation).
+  """
+
+  # Client-side methods below
+
+  def Reset(self):
+    """Resets the RpcController to its initial state.
+
+    After the RpcController has been reset, it may be reused in
+    a new call. Must not be called while an RPC is in progress.
+    """
+    raise NotImplementedError
+
+  def Failed(self):
+    """Returns true if the call failed.
+
+    After a call has finished, returns true if the call failed.  The possible
+    reasons for failure depend on the RPC implementation.  Failed() must not
+    be called before a call has finished.  If Failed() returns true, the
+    contents of the response message are undefined.
+    """
+    raise NotImplementedError
+
+  def ErrorText(self):
+    """If Failed is true, returns a human-readable description of the error."""
+    raise NotImplementedError
+
+  def StartCancel(self):
+    """Initiate cancellation.
+
+    Advises the RPC system that the caller desires that the RPC call be
+    canceled.  The RPC system may cancel it immediately, may wait awhile and
+    then cancel it, or may not even cancel the call at all.  If the call is
+    canceled, the "done" callback will still be called and the RpcController
+    will indicate that the call failed at that time.
+    """
+    raise NotImplementedError
+
+  # Server-side methods below
+
+  def SetFailed(self, reason):
+    """Sets a failure reason.
+
+    Causes Failed() to return true on the client side.  "reason" will be
+    incorporated into the message returned by ErrorText().  If you find
+    you need to return machine-readable information about failures, you
+    should incorporate it into your response protocol buffer and should
+    NOT call SetFailed().
+    """
+    raise NotImplementedError
+
+  def IsCanceled(self):
+    """Checks if the client cancelled the RPC.
+
+    If true, indicates that the client canceled the RPC, so the server may
+    as well give up on replying to it.  The server should still call the
+    final "done" callback.
+    """
+    raise NotImplementedError
+
+  def NotifyOnCancel(self, callback):
+    """Sets a callback to invoke on cancel.
+
+    Asks that the given callback be called when the RPC is canceled.  The
+    callback will always be called exactly once.  If the RPC completes without
+    being canceled, the callback will be called after completion.  If the RPC
+    has already been canceled when NotifyOnCancel() is called, the callback
+    will be called immediately.
+
+    NotifyOnCancel() must be called no more than once per request.
+    """
+    raise NotImplementedError
+
+
+class RpcChannel(object):
+
+  """Abstract interface for an RPC channel.
+
+  An RpcChannel represents a communication line to a service which can be used
+  to call that service's methods.  The service may be running on another
+  machine. Normally, you should not use an RpcChannel directly, but instead
+  construct a stub {@link Service} wrapping it.  Example:
+
+  Example:
+    RpcChannel channel = rpcImpl.Channel("remotehost.example.com:1234")
+    RpcController controller = rpcImpl.Controller()
+    MyService service = MyService_Stub(channel)
+    service.MyMethod(controller, request, callback)
+  """
+
+  def CallMethod(self, method_descriptor, rpc_controller,
+                 request, response_class, done):
+    """Calls the method identified by the descriptor.
+
+    Call the given method of the remote service.  The signature of this
+    procedure looks the same as Service.CallMethod(), but the requirements
+    are less strict in one important way:  the request object doesn't have to
+    be of any specific class as long as its descriptor is method.input_type.
+    """
+    raise NotImplementedError
diff --git a/python/google/protobuf/service_reflection.py b/python/google/protobuf/service_reflection.py
new file mode 100644
index 0000000..f82ab71
--- /dev/null
+++ b/python/google/protobuf/service_reflection.py
@@ -0,0 +1,295 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 metaclasses used to create protocol service and service stub
+classes from ServiceDescriptor objects at runtime.
+
+The GeneratedServiceType and GeneratedServiceStubType metaclasses are used to
+inject all useful functionality into the classes output by the protocol
+compiler at compile-time.
+"""
+
+__author__ = 'petar@google.com (Petar Petrov)'
+
+
+class GeneratedServiceType(type):
+
+  """Metaclass for service classes created at runtime from ServiceDescriptors.
+
+  Implementations for all methods described in the Service class are added here
+  by this class. We also create properties to allow getting/setting all fields
+  in the protocol message.
+
+  The protocol compiler currently uses this metaclass to create protocol service
+  classes at runtime. Clients can also manually create their own classes at
+  runtime, as in this example::
+
+    mydescriptor = ServiceDescriptor(.....)
+    class MyProtoService(service.Service):
+      __metaclass__ = GeneratedServiceType
+      DESCRIPTOR = mydescriptor
+    myservice_instance = MyProtoService()
+    # ...
+  """
+
+  _DESCRIPTOR_KEY = 'DESCRIPTOR'
+
+  def __init__(cls, name, bases, dictionary):
+    """Creates a message service class.
+
+    Args:
+      name: Name of the class (ignored, but required by the metaclass
+        protocol).
+      bases: Base classes of the class being constructed.
+      dictionary: The class dictionary of the class being constructed.
+        dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object
+        describing this protocol service type.
+    """
+    # Don't do anything if this class doesn't have a descriptor. This happens
+    # when a service class is subclassed.
+    if GeneratedServiceType._DESCRIPTOR_KEY not in dictionary:
+      return
+
+    descriptor = dictionary[GeneratedServiceType._DESCRIPTOR_KEY]
+    service_builder = _ServiceBuilder(descriptor)
+    service_builder.BuildService(cls)
+    cls.DESCRIPTOR = descriptor
+
+
+class GeneratedServiceStubType(GeneratedServiceType):
+
+  """Metaclass for service stubs created at runtime from ServiceDescriptors.
+
+  This class has similar responsibilities as GeneratedServiceType, except that
+  it creates the service stub classes.
+  """
+
+  _DESCRIPTOR_KEY = 'DESCRIPTOR'
+
+  def __init__(cls, name, bases, dictionary):
+    """Creates a message service stub class.
+
+    Args:
+      name: Name of the class (ignored, here).
+      bases: Base classes of the class being constructed.
+      dictionary: The class dictionary of the class being constructed.
+        dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object
+        describing this protocol service type.
+    """
+    super(GeneratedServiceStubType, cls).__init__(name, bases, dictionary)
+    # Don't do anything if this class doesn't have a descriptor. This happens
+    # when a service stub is subclassed.
+    if GeneratedServiceStubType._DESCRIPTOR_KEY not in dictionary:
+      return
+
+    descriptor = dictionary[GeneratedServiceStubType._DESCRIPTOR_KEY]
+    service_stub_builder = _ServiceStubBuilder(descriptor)
+    service_stub_builder.BuildServiceStub(cls)
+
+
+class _ServiceBuilder(object):
+
+  """This class constructs a protocol service class using a service descriptor.
+
+  Given a service descriptor, this class constructs a class that represents
+  the specified service descriptor. One service builder instance constructs
+  exactly one service class. That means all instances of that class share the
+  same builder.
+  """
+
+  def __init__(self, service_descriptor):
+    """Initializes an instance of the service class builder.
+
+    Args:
+      service_descriptor: ServiceDescriptor to use when constructing the
+        service class.
+    """
+    self.descriptor = service_descriptor
+
+  def BuildService(builder, cls):
+    """Constructs the service class.
+
+    Args:
+      cls: The class that will be constructed.
+    """
+
+    # CallMethod needs to operate with an instance of the Service class. This
+    # internal wrapper function exists only to be able to pass the service
+    # instance to the method that does the real CallMethod work.
+    # Making sure to use exact argument names from the abstract interface in
+    # service.py to match the type signature
+    def _WrapCallMethod(self, method_descriptor, rpc_controller, request, done):
+      return builder._CallMethod(self, method_descriptor, rpc_controller,
+                                 request, done)
+
+    def _WrapGetRequestClass(self, method_descriptor):
+      return builder._GetRequestClass(method_descriptor)
+
+    def _WrapGetResponseClass(self, method_descriptor):
+      return builder._GetResponseClass(method_descriptor)
+
+    builder.cls = cls
+    cls.CallMethod = _WrapCallMethod
+    cls.GetDescriptor = staticmethod(lambda: builder.descriptor)
+    cls.GetDescriptor.__doc__ = 'Returns the service descriptor.'
+    cls.GetRequestClass = _WrapGetRequestClass
+    cls.GetResponseClass = _WrapGetResponseClass
+    for method in builder.descriptor.methods:
+      setattr(cls, method.name, builder._GenerateNonImplementedMethod(method))
+
+  def _CallMethod(self, srvc, method_descriptor,
+                  rpc_controller, request, callback):
+    """Calls the method described by a given method descriptor.
+
+    Args:
+      srvc: Instance of the service for which this method is called.
+      method_descriptor: Descriptor that represent the method to call.
+      rpc_controller: RPC controller to use for this method's execution.
+      request: Request protocol message.
+      callback: A callback to invoke after the method has completed.
+    """
+    if method_descriptor.containing_service != self.descriptor:
+      raise RuntimeError(
+          'CallMethod() given method descriptor for wrong service type.')
+    method = getattr(srvc, method_descriptor.name)
+    return method(rpc_controller, request, callback)
+
+  def _GetRequestClass(self, method_descriptor):
+    """Returns the class of the request protocol message.
+
+    Args:
+      method_descriptor: Descriptor of the method for which to return the
+        request protocol message class.
+
+    Returns:
+      A class that represents the input protocol message of the specified
+      method.
+    """
+    if method_descriptor.containing_service != self.descriptor:
+      raise RuntimeError(
+          'GetRequestClass() given method descriptor for wrong service type.')
+    return method_descriptor.input_type._concrete_class
+
+  def _GetResponseClass(self, method_descriptor):
+    """Returns the class of the response protocol message.
+
+    Args:
+      method_descriptor: Descriptor of the method for which to return the
+        response protocol message class.
+
+    Returns:
+      A class that represents the output protocol message of the specified
+      method.
+    """
+    if method_descriptor.containing_service != self.descriptor:
+      raise RuntimeError(
+          'GetResponseClass() given method descriptor for wrong service type.')
+    return method_descriptor.output_type._concrete_class
+
+  def _GenerateNonImplementedMethod(self, method):
+    """Generates and returns a method that can be set for a service methods.
+
+    Args:
+      method: Descriptor of the service method for which a method is to be
+        generated.
+
+    Returns:
+      A method that can be added to the service class.
+    """
+    return lambda inst, rpc_controller, request, callback: (
+        self._NonImplementedMethod(method.name, rpc_controller, callback))
+
+  def _NonImplementedMethod(self, method_name, rpc_controller, callback):
+    """The body of all methods in the generated service class.
+
+    Args:
+      method_name: Name of the method being executed.
+      rpc_controller: RPC controller used to execute this method.
+      callback: A callback which will be invoked when the method finishes.
+    """
+    rpc_controller.SetFailed('Method %s not implemented.' % method_name)
+    callback(None)
+
+
+class _ServiceStubBuilder(object):
+
+  """Constructs a protocol service stub class using a service descriptor.
+
+  Given a service descriptor, this class constructs a suitable stub class.
+  A stub is just a type-safe wrapper around an RpcChannel which emulates a
+  local implementation of the service.
+
+  One service stub builder instance constructs exactly one class. It means all
+  instances of that class share the same service stub builder.
+  """
+
+  def __init__(self, service_descriptor):
+    """Initializes an instance of the service stub class builder.
+
+    Args:
+      service_descriptor: ServiceDescriptor to use when constructing the
+        stub class.
+    """
+    self.descriptor = service_descriptor
+
+  def BuildServiceStub(self, cls):
+    """Constructs the stub class.
+
+    Args:
+      cls: The class that will be constructed.
+    """
+
+    def _ServiceStubInit(stub, rpc_channel):
+      stub.rpc_channel = rpc_channel
+    self.cls = cls
+    cls.__init__ = _ServiceStubInit
+    for method in self.descriptor.methods:
+      setattr(cls, method.name, self._GenerateStubMethod(method))
+
+  def _GenerateStubMethod(self, method):
+    return (lambda inst, rpc_controller, request, callback=None:
+        self._StubMethod(inst, method, rpc_controller, request, callback))
+
+  def _StubMethod(self, stub, method_descriptor,
+                  rpc_controller, request, callback):
+    """The body of all service methods in the generated stub class.
+
+    Args:
+      stub: Stub instance.
+      method_descriptor: Descriptor of the invoked method.
+      rpc_controller: Rpc controller to execute the method.
+      request: Request protocol message.
+      callback: A callback to execute when the method finishes.
+    Returns:
+      Response message (in case of blocking call).
+    """
+    return stub.rpc_channel.CallMethod(
+        method_descriptor, rpc_controller, request,
+        method_descriptor.output_type._concrete_class, callback)
diff --git a/python/google/protobuf/source_context_pb2.py b/python/google/protobuf/source_context_pb2.py
new file mode 100644
index 0000000..cfcd9e4
--- /dev/null
+++ b/python/google/protobuf/source_context_pb2.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/source_context.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/source_context.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\022SourceContextProtoP\001Z6google.golang.org/protobuf/types/known/sourcecontextpb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n$google/protobuf/source_context.proto\x12\x0fgoogle.protobuf\"\"\n\rSourceContext\x12\x11\n\tfile_name\x18\x01 \x01(\tB\x8a\x01\n\x13\x63om.google.protobufB\x12SourceContextProtoP\x01Z6google.golang.org/protobuf/types/known/sourcecontextpb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_SOURCECONTEXT = _descriptor.Descriptor(
+  name='SourceContext',
+  full_name='google.protobuf.SourceContext',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='file_name', full_name='google.protobuf.SourceContext.file_name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=57,
+  serialized_end=91,
+)
+
+DESCRIPTOR.message_types_by_name['SourceContext'] = _SOURCECONTEXT
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+SourceContext = _reflection.GeneratedProtocolMessageType('SourceContext', (_message.Message,), {
+  'DESCRIPTOR' : _SOURCECONTEXT,
+  '__module__' : 'google.protobuf.source_context_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.SourceContext)
+  })
+_sym_db.RegisterMessage(SourceContext)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/struct_pb2.py b/python/google/protobuf/struct_pb2.py
new file mode 100644
index 0000000..efc8fac
--- /dev/null
+++ b/python/google/protobuf/struct_pb2.py
@@ -0,0 +1,287 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/struct.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/struct.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\013StructProtoP\001Z/google.golang.org/protobuf/types/known/structpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1cgoogle/protobuf/struct.proto\x12\x0fgoogle.protobuf\"\x84\x01\n\x06Struct\x12\x33\n\x06\x66ields\x18\x01 \x03(\x0b\x32#.google.protobuf.Struct.FieldsEntry\x1a\x45\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value:\x02\x38\x01\"\xea\x01\n\x05Value\x12\x30\n\nnull_value\x18\x01 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x12\x16\n\x0cnumber_value\x18\x02 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x03 \x01(\tH\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12/\n\x0cstruct_value\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x12\x30\n\nlist_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x42\x06\n\x04kind\"3\n\tListValue\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value*\x1b\n\tNullValue\x12\x0e\n\nNULL_VALUE\x10\x00\x42\x7f\n\x13\x63om.google.protobufB\x0bStructProtoP\x01Z/google.golang.org/protobuf/types/known/structpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+_NULLVALUE = _descriptor.EnumDescriptor(
+  name='NullValue',
+  full_name='google.protobuf.NullValue',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='NULL_VALUE', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=474,
+  serialized_end=501,
+)
+_sym_db.RegisterEnumDescriptor(_NULLVALUE)
+
+NullValue = enum_type_wrapper.EnumTypeWrapper(_NULLVALUE)
+NULL_VALUE = 0
+
+
+
+_STRUCT_FIELDSENTRY = _descriptor.Descriptor(
+  name='FieldsEntry',
+  full_name='google.protobuf.Struct.FieldsEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='google.protobuf.Struct.FieldsEntry.key', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.Struct.FieldsEntry.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=113,
+  serialized_end=182,
+)
+
+_STRUCT = _descriptor.Descriptor(
+  name='Struct',
+  full_name='google.protobuf.Struct',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='fields', full_name='google.protobuf.Struct.fields', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[_STRUCT_FIELDSENTRY, ],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=50,
+  serialized_end=182,
+)
+
+
+_VALUE = _descriptor.Descriptor(
+  name='Value',
+  full_name='google.protobuf.Value',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='null_value', full_name='google.protobuf.Value.null_value', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='number_value', full_name='google.protobuf.Value.number_value', index=1,
+      number=2, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='string_value', full_name='google.protobuf.Value.string_value', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='bool_value', full_name='google.protobuf.Value.bool_value', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='struct_value', full_name='google.protobuf.Value.struct_value', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='list_value', full_name='google.protobuf.Value.list_value', index=5,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='kind', full_name='google.protobuf.Value.kind',
+      index=0, containing_type=None,
+      create_key=_descriptor._internal_create_key,
+    fields=[]),
+  ],
+  serialized_start=185,
+  serialized_end=419,
+)
+
+
+_LISTVALUE = _descriptor.Descriptor(
+  name='ListValue',
+  full_name='google.protobuf.ListValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='values', full_name='google.protobuf.ListValue.values', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=421,
+  serialized_end=472,
+)
+
+_STRUCT_FIELDSENTRY.fields_by_name['value'].message_type = _VALUE
+_STRUCT_FIELDSENTRY.containing_type = _STRUCT
+_STRUCT.fields_by_name['fields'].message_type = _STRUCT_FIELDSENTRY
+_VALUE.fields_by_name['null_value'].enum_type = _NULLVALUE
+_VALUE.fields_by_name['struct_value'].message_type = _STRUCT
+_VALUE.fields_by_name['list_value'].message_type = _LISTVALUE
+_VALUE.oneofs_by_name['kind'].fields.append(
+  _VALUE.fields_by_name['null_value'])
+_VALUE.fields_by_name['null_value'].containing_oneof = _VALUE.oneofs_by_name['kind']
+_VALUE.oneofs_by_name['kind'].fields.append(
+  _VALUE.fields_by_name['number_value'])
+_VALUE.fields_by_name['number_value'].containing_oneof = _VALUE.oneofs_by_name['kind']
+_VALUE.oneofs_by_name['kind'].fields.append(
+  _VALUE.fields_by_name['string_value'])
+_VALUE.fields_by_name['string_value'].containing_oneof = _VALUE.oneofs_by_name['kind']
+_VALUE.oneofs_by_name['kind'].fields.append(
+  _VALUE.fields_by_name['bool_value'])
+_VALUE.fields_by_name['bool_value'].containing_oneof = _VALUE.oneofs_by_name['kind']
+_VALUE.oneofs_by_name['kind'].fields.append(
+  _VALUE.fields_by_name['struct_value'])
+_VALUE.fields_by_name['struct_value'].containing_oneof = _VALUE.oneofs_by_name['kind']
+_VALUE.oneofs_by_name['kind'].fields.append(
+  _VALUE.fields_by_name['list_value'])
+_VALUE.fields_by_name['list_value'].containing_oneof = _VALUE.oneofs_by_name['kind']
+_LISTVALUE.fields_by_name['values'].message_type = _VALUE
+DESCRIPTOR.message_types_by_name['Struct'] = _STRUCT
+DESCRIPTOR.message_types_by_name['Value'] = _VALUE
+DESCRIPTOR.message_types_by_name['ListValue'] = _LISTVALUE
+DESCRIPTOR.enum_types_by_name['NullValue'] = _NULLVALUE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Struct = _reflection.GeneratedProtocolMessageType('Struct', (_message.Message,), {
+
+  'FieldsEntry' : _reflection.GeneratedProtocolMessageType('FieldsEntry', (_message.Message,), {
+    'DESCRIPTOR' : _STRUCT_FIELDSENTRY,
+    '__module__' : 'google.protobuf.struct_pb2'
+    # @@protoc_insertion_point(class_scope:google.protobuf.Struct.FieldsEntry)
+    })
+  ,
+  'DESCRIPTOR' : _STRUCT,
+  '__module__' : 'google.protobuf.struct_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Struct)
+  })
+_sym_db.RegisterMessage(Struct)
+_sym_db.RegisterMessage(Struct.FieldsEntry)
+
+Value = _reflection.GeneratedProtocolMessageType('Value', (_message.Message,), {
+  'DESCRIPTOR' : _VALUE,
+  '__module__' : 'google.protobuf.struct_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Value)
+  })
+_sym_db.RegisterMessage(Value)
+
+ListValue = _reflection.GeneratedProtocolMessageType('ListValue', (_message.Message,), {
+  'DESCRIPTOR' : _LISTVALUE,
+  '__module__' : 'google.protobuf.struct_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.ListValue)
+  })
+_sym_db.RegisterMessage(ListValue)
+
+
+DESCRIPTOR._options = None
+_STRUCT_FIELDSENTRY._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/symbol_database.py b/python/google/protobuf/symbol_database.py
new file mode 100644
index 0000000..fdcf8cf
--- /dev/null
+++ b/python/google/protobuf/symbol_database.py
@@ -0,0 +1,194 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""A database of Python protocol buffer generated symbols.
+
+SymbolDatabase is the MessageFactory for messages generated at compile time,
+and makes it easy to create new instances of a registered type, given only the
+type's protocol buffer symbol name.
+
+Example usage::
+
+  db = symbol_database.SymbolDatabase()
+
+  # Register symbols of interest, from one or multiple files.
+  db.RegisterFileDescriptor(my_proto_pb2.DESCRIPTOR)
+  db.RegisterMessage(my_proto_pb2.MyMessage)
+  db.RegisterEnumDescriptor(my_proto_pb2.MyEnum.DESCRIPTOR)
+
+  # The database can be used as a MessageFactory, to generate types based on
+  # their name:
+  types = db.GetMessages(['my_proto.proto'])
+  my_message_instance = types['MyMessage']()
+
+  # The database's underlying descriptor pool can be queried, so it's not
+  # necessary to know a type's filename to be able to generate it:
+  filename = db.pool.FindFileContainingSymbol('MyMessage')
+  my_message_instance = db.GetMessages([filename])['MyMessage']()
+
+  # This functionality is also provided directly via a convenience method:
+  my_message_instance = db.GetSymbol('MyMessage')()
+"""
+
+
+from google.protobuf.internal import api_implementation
+from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
+
+
+class SymbolDatabase(message_factory.MessageFactory):
+  """A database of Python generated symbols."""
+
+  def RegisterMessage(self, message):
+    """Registers the given message type in the local database.
+
+    Calls to GetSymbol() and GetMessages() will return messages registered here.
+
+    Args:
+      message: A :class:`google.protobuf.message.Message` subclass (or
+        instance); its descriptor will be registered.
+
+    Returns:
+      The provided message.
+    """
+
+    desc = message.DESCRIPTOR
+    self._classes[desc] = message
+    self.RegisterMessageDescriptor(desc)
+    return message
+
+  def RegisterMessageDescriptor(self, message_descriptor):
+    """Registers the given message descriptor in the local database.
+
+    Args:
+      message_descriptor (Descriptor): the message descriptor to add.
+    """
+    if api_implementation.Type() == 'python':
+      # pylint: disable=protected-access
+      self.pool._AddDescriptor(message_descriptor)
+
+  def RegisterEnumDescriptor(self, enum_descriptor):
+    """Registers the given enum descriptor in the local database.
+
+    Args:
+      enum_descriptor (EnumDescriptor): The enum descriptor to register.
+
+    Returns:
+      EnumDescriptor: The provided descriptor.
+    """
+    if api_implementation.Type() == 'python':
+      # pylint: disable=protected-access
+      self.pool._AddEnumDescriptor(enum_descriptor)
+    return enum_descriptor
+
+  def RegisterServiceDescriptor(self, service_descriptor):
+    """Registers the given service descriptor in the local database.
+
+    Args:
+      service_descriptor (ServiceDescriptor): the service descriptor to
+        register.
+    """
+    if api_implementation.Type() == 'python':
+      # pylint: disable=protected-access
+      self.pool._AddServiceDescriptor(service_descriptor)
+
+  def RegisterFileDescriptor(self, file_descriptor):
+    """Registers the given file descriptor in the local database.
+
+    Args:
+      file_descriptor (FileDescriptor): The file descriptor to register.
+    """
+    if api_implementation.Type() == 'python':
+      # pylint: disable=protected-access
+      self.pool._InternalAddFileDescriptor(file_descriptor)
+
+  def GetSymbol(self, symbol):
+    """Tries to find a symbol in the local database.
+
+    Currently, this method only returns message.Message instances, however, if
+    may be extended in future to support other symbol types.
+
+    Args:
+      symbol (str): a protocol buffer symbol.
+
+    Returns:
+      A Python class corresponding to the symbol.
+
+    Raises:
+      KeyError: if the symbol could not be found.
+    """
+
+    return self._classes[self.pool.FindMessageTypeByName(symbol)]
+
+  def GetMessages(self, files):
+    # TODO(amauryfa): Fix the differences with MessageFactory.
+    """Gets all registered messages from a specified file.
+
+    Only messages already created and registered will be returned; (this is the
+    case for imported _pb2 modules)
+    But unlike MessageFactory, this version also returns already defined nested
+    messages, but does not register any message extensions.
+
+    Args:
+      files (list[str]): The file names to extract messages from.
+
+    Returns:
+      A dictionary mapping proto names to the message classes.
+
+    Raises:
+      KeyError: if a file could not be found.
+    """
+
+    def _GetAllMessages(desc):
+      """Walk a message Descriptor and recursively yields all message names."""
+      yield desc
+      for msg_desc in desc.nested_types:
+        for nested_desc in _GetAllMessages(msg_desc):
+          yield nested_desc
+
+    result = {}
+    for file_name in files:
+      file_desc = self.pool.FindFileByName(file_name)
+      for msg_desc in file_desc.message_types_by_name.values():
+        for desc in _GetAllMessages(msg_desc):
+          try:
+            result[desc.full_name] = self._classes[desc]
+          except KeyError:
+            # This descriptor has no registered class, skip it.
+            pass
+    return result
+
+
+_DEFAULT = SymbolDatabase(pool=descriptor_pool.Default())
+
+
+def Default():
+  """Returns the default SymbolDatabase."""
+  return _DEFAULT
diff --git a/python/google/protobuf/text_encoding.py b/python/google/protobuf/text_encoding.py
new file mode 100644
index 0000000..759cf11
--- /dev/null
+++ b/python/google/protobuf/text_encoding.py
@@ -0,0 +1,110 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Encoding related utilities."""
+import re
+
+_cescape_chr_to_symbol_map = {}
+_cescape_chr_to_symbol_map[9] = r'\t'  # optional escape
+_cescape_chr_to_symbol_map[10] = r'\n'  # optional escape
+_cescape_chr_to_symbol_map[13] = r'\r'  # optional escape
+_cescape_chr_to_symbol_map[34] = r'\"'  # necessary escape
+_cescape_chr_to_symbol_map[39] = r"\'"  # optional escape
+_cescape_chr_to_symbol_map[92] = r'\\'  # necessary escape
+
+# Lookup table for unicode
+_cescape_unicode_to_str = [chr(i) for i in range(0, 256)]
+for byte, string in _cescape_chr_to_symbol_map.items():
+  _cescape_unicode_to_str[byte] = string
+
+# Lookup table for non-utf8, with necessary escapes at (o >= 127 or o < 32)
+_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)])
+for byte, string in _cescape_chr_to_symbol_map.items():
+  _cescape_byte_to_str[byte] = string
+del byte, string
+
+
+def CEscape(text, as_utf8):
+  # type: (...) -> str
+  """Escape a bytes string for use in an text protocol buffer.
+
+  Args:
+    text: A byte string to be escaped.
+    as_utf8: Specifies if result may contain non-ASCII characters.
+        In Python 3 this allows unescaped non-ASCII Unicode characters.
+        In Python 2 the return value will be valid UTF-8 rather than only ASCII.
+  Returns:
+    Escaped string (str).
+  """
+  # Python's text.encode() 'string_escape' or 'unicode_escape' codecs do not
+  # satisfy our needs; they encodes unprintable characters using two-digit hex
+  # escapes whereas our C++ unescaping function allows hex escapes to be any
+  # length.  So, "\0011".encode('string_escape') ends up being "\\x011", which
+  # will be decoded in C++ as a single-character string with char code 0x11.
+  text_is_unicode = isinstance(text, str)
+  if as_utf8 and text_is_unicode:
+    # We're already unicode, no processing beyond control char escapes.
+    return text.translate(_cescape_chr_to_symbol_map)
+  ord_ = ord if text_is_unicode else lambda x: x  # bytes iterate as ints.
+  if as_utf8:
+    return ''.join(_cescape_unicode_to_str[ord_(c)] for c in text)
+  return ''.join(_cescape_byte_to_str[ord_(c)] for c in text)
+
+
+_CUNESCAPE_HEX = re.compile(r'(\\+)x([0-9a-fA-F])(?![0-9a-fA-F])')
+
+
+def CUnescape(text):
+  # type: (str) -> bytes
+  """Unescape a text string with C-style escape sequences to UTF-8 bytes.
+
+  Args:
+    text: The data to parse in a str.
+  Returns:
+    A byte string.
+  """
+
+  def ReplaceHex(m):
+    # Only replace the match if the number of leading back slashes is odd. i.e.
+    # the slash itself is not escaped.
+    if len(m.group(1)) & 1:
+      return m.group(1) + 'x0' + m.group(2)
+    return m.group(0)
+
+  # This is required because the 'string_escape' encoding doesn't
+  # allow single-digit hex escapes (like '\xf').
+  result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
+
+  return (result.encode('utf-8')  # Make it bytes to allow decode.
+          .decode('unicode_escape')
+          # Make it bytes again to return the proper type.
+          .encode('raw_unicode_escape'))
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
new file mode 100644
index 0000000..a6d8bcf
--- /dev/null
+++ b/python/google/protobuf/text_format.py
@@ -0,0 +1,1842 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 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)'
+
+# TODO(b/129989314) Import thread contention leads to test failures.
+import encodings.raw_unicode_escape  # pylint: disable=unused-import
+import encodings.unicode_escape  # pylint: disable=unused-import
+import io
+import math
+import re
+
+from google.protobuf.internal import decoder
+from google.protobuf.internal import type_checkers
+from google.protobuf import descriptor
+from google.protobuf import text_encoding
+from google.protobuf import unknown_fields
+
+# pylint: disable=g-import-not-at-top
+__all__ = ['MessageToString', 'Parse', 'PrintMessage', 'PrintField',
+           'PrintFieldValue', 'Merge', 'MessageToBytes']
+
+_INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),
+                     type_checkers.Int32ValueChecker(),
+                     type_checkers.Uint64ValueChecker(),
+                     type_checkers.Int64ValueChecker())
+_FLOAT_INFINITY = re.compile('-?inf(?:inity)?f?$', re.IGNORECASE)
+_FLOAT_NAN = re.compile('nanf?$', re.IGNORECASE)
+_QUOTES = frozenset(("'", '"'))
+_ANY_FULL_TYPE_NAME = 'google.protobuf.Any'
+
+
+class Error(Exception):
+  """Top-level module error for text_format."""
+
+
+class ParseError(Error):
+  """Thrown in case of text parsing or tokenizing error."""
+
+  def __init__(self, message=None, line=None, column=None):
+    if message is not None and line is not None:
+      loc = str(line)
+      if column is not None:
+        loc += ':{0}'.format(column)
+      message = '{0} : {1}'.format(loc, message)
+    if message is not None:
+      super(ParseError, self).__init__(message)
+    else:
+      super(ParseError, self).__init__()
+    self._line = line
+    self._column = column
+
+  def GetLine(self):
+    return self._line
+
+  def GetColumn(self):
+    return self._column
+
+
+class TextWriter(object):
+
+  def __init__(self, as_utf8):
+    self._writer = io.StringIO()
+
+  def write(self, val):
+    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,
+    use_short_repeated_primitives=False,
+    pointy_brackets=False,
+    use_index_order=False,
+    float_format=None,
+    double_format=None,
+    use_field_number=False,
+    descriptor_pool=None,
+    indent=0,
+    message_formatter=None,
+    print_unknown_fields=False,
+    force_colon=False):
+  # type: (...) -> str
+  """Convert protobuf message to text format.
+
+  Double values can be formatted compactly with 15 digits of
+  precision (which is the most that IEEE 754 "double" can guarantee)
+  using double_format='.15g'. To ensure that converting to text and back to a
+  proto will result in an identical value, double_format='.17g' should be used.
+
+  Args:
+    message: The protocol buffers message.
+    as_utf8: Return unescaped Unicode for non-ASCII characters.
+    as_one_line: Don't introduce newlines between fields.
+    use_short_repeated_primitives: Use short repeated format for primitives.
+    pointy_brackets: If True, use angle brackets instead of curly braces for
+      nesting.
+    use_index_order: If True, fields of a proto message will be printed using
+      the order defined in source code instead of the field number, extensions
+      will be printed at the end of the message and their relative order is
+      determined by the extension number. By default, use the field number
+      order.
+    float_format (str): If set, use this to specify float field formatting
+      (per the "Format Specification Mini-Language"); otherwise, shortest float
+      that has same value in wire will be printed. Also affect double field
+      if double_format is not set but float_format is set.
+    double_format (str): If set, use this to specify double field formatting
+      (per the "Format Specification Mini-Language"); if it is not set but
+      float_format is set, use float_format. Otherwise, use ``str()``
+    use_field_number: If True, print field numbers instead of names.
+    descriptor_pool (DescriptorPool): Descriptor pool used to resolve Any types.
+    indent (int): The initial indent level, in terms of spaces, for pretty
+      print.
+    message_formatter (function(message, indent, as_one_line) -> unicode|None):
+      Custom formatter for selected sub-messages (usually based on message
+      type). Use to pretty print parts of the protobuf for easier diffing.
+    print_unknown_fields: If True, unknown fields will be printed.
+    force_colon: If set, a colon will be added after the field name even if the
+      field is a proto message.
+
+  Returns:
+    str: A string of the text formatted protocol buffer message.
+  """
+  out = TextWriter(as_utf8)
+  printer = _Printer(
+      out,
+      indent,
+      as_utf8,
+      as_one_line,
+      use_short_repeated_primitives,
+      pointy_brackets,
+      use_index_order,
+      float_format,
+      double_format,
+      use_field_number,
+      descriptor_pool,
+      message_formatter,
+      print_unknown_fields=print_unknown_fields,
+      force_colon=force_colon)
+  printer.PrintMessage(message)
+  result = out.getvalue()
+  out.close()
+  if as_one_line:
+    return result.rstrip()
+  return result
+
+
+def MessageToBytes(message, **kwargs):
+  # type: (...) -> bytes
+  """Convert protobuf message to encoded text format.  See MessageToString."""
+  text = MessageToString(message, **kwargs)
+  if isinstance(text, bytes):
+    return text
+  codec = 'utf-8' if kwargs.get('as_utf8') else 'ascii'
+  return text.encode(codec)
+
+
+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,
+                 use_short_repeated_primitives=False,
+                 pointy_brackets=False,
+                 use_index_order=False,
+                 float_format=None,
+                 double_format=None,
+                 use_field_number=False,
+                 descriptor_pool=None,
+                 message_formatter=None,
+                 print_unknown_fields=False,
+                 force_colon=False):
+  """Convert the message to text format and write it to the out stream.
+
+  Args:
+    message: The Message object to convert to text format.
+    out: A file handle to write the message to.
+    indent: The initial indent level for pretty print.
+    as_utf8: Return unescaped Unicode for non-ASCII characters.
+    as_one_line: Don't introduce newlines between fields.
+    use_short_repeated_primitives: Use short repeated format for primitives.
+    pointy_brackets: If True, use angle brackets instead of curly braces for
+      nesting.
+    use_index_order: If True, print fields of a proto message using the order
+      defined in source code instead of the field number. By default, use the
+      field number order.
+    float_format: If set, use this to specify float field formatting
+      (per the "Format Specification Mini-Language"); otherwise, shortest
+      float that has same value in wire will be printed. Also affect double
+      field if double_format is not set but float_format is set.
+    double_format: If set, use this to specify double field formatting
+      (per the "Format Specification Mini-Language"); if it is not set but
+      float_format is set, use float_format. Otherwise, str() is used.
+    use_field_number: If True, print field numbers instead of names.
+    descriptor_pool: A DescriptorPool used to resolve Any types.
+    message_formatter: A function(message, indent, as_one_line): unicode|None
+      to custom format selected sub-messages (usually based on message type).
+      Use to pretty print parts of the protobuf for easier diffing.
+    print_unknown_fields: If True, unknown fields will be printed.
+    force_colon: If set, a colon will be added after the field name even if
+      the field is a proto message.
+  """
+  printer = _Printer(
+      out=out, indent=indent, as_utf8=as_utf8,
+      as_one_line=as_one_line,
+      use_short_repeated_primitives=use_short_repeated_primitives,
+      pointy_brackets=pointy_brackets,
+      use_index_order=use_index_order,
+      float_format=float_format,
+      double_format=double_format,
+      use_field_number=use_field_number,
+      descriptor_pool=descriptor_pool,
+      message_formatter=message_formatter,
+      print_unknown_fields=print_unknown_fields,
+      force_colon=force_colon)
+  printer.PrintMessage(message)
+
+
+def PrintField(field,
+               value,
+               out,
+               indent=0,
+               as_utf8=False,
+               as_one_line=False,
+               use_short_repeated_primitives=False,
+               pointy_brackets=False,
+               use_index_order=False,
+               float_format=None,
+               double_format=None,
+               message_formatter=None,
+               print_unknown_fields=False,
+               force_colon=False):
+  """Print a single field name/value pair."""
+  printer = _Printer(out, indent, as_utf8, as_one_line,
+                     use_short_repeated_primitives, pointy_brackets,
+                     use_index_order, float_format, double_format,
+                     message_formatter=message_formatter,
+                     print_unknown_fields=print_unknown_fields,
+                     force_colon=force_colon)
+  printer.PrintField(field, value)
+
+
+def PrintFieldValue(field,
+                    value,
+                    out,
+                    indent=0,
+                    as_utf8=False,
+                    as_one_line=False,
+                    use_short_repeated_primitives=False,
+                    pointy_brackets=False,
+                    use_index_order=False,
+                    float_format=None,
+                    double_format=None,
+                    message_formatter=None,
+                    print_unknown_fields=False,
+                    force_colon=False):
+  """Print a single field value (not including name)."""
+  printer = _Printer(out, indent, as_utf8, as_one_line,
+                     use_short_repeated_primitives, pointy_brackets,
+                     use_index_order, float_format, double_format,
+                     message_formatter=message_formatter,
+                     print_unknown_fields=print_unknown_fields,
+                     force_colon=force_colon)
+  printer.PrintFieldValue(field, value)
+
+
+def _BuildMessageFromTypeName(type_name, descriptor_pool):
+  """Returns a protobuf message instance.
+
+  Args:
+    type_name: Fully-qualified protobuf  message type name string.
+    descriptor_pool: DescriptorPool instance.
+
+  Returns:
+    A Message instance of type matching type_name, or None if the a Descriptor
+    wasn't found matching type_name.
+  """
+  # pylint: disable=g-import-not-at-top
+  if descriptor_pool is None:
+    from google.protobuf import descriptor_pool as pool_mod
+    descriptor_pool = pool_mod.Default()
+  from google.protobuf import symbol_database
+  database = symbol_database.Default()
+  try:
+    message_descriptor = descriptor_pool.FindMessageTypeByName(type_name)
+  except KeyError:
+    return None
+  message_type = database.GetPrototype(message_descriptor)
+  return message_type()
+
+
+# These values must match WireType enum in google/protobuf/wire_format.h.
+WIRETYPE_LENGTH_DELIMITED = 2
+WIRETYPE_START_GROUP = 3
+
+
+class _Printer(object):
+  """Text format printer for protocol message."""
+
+  def __init__(
+      self,
+      out,
+      indent=0,
+      as_utf8=False,
+      as_one_line=False,
+      use_short_repeated_primitives=False,
+      pointy_brackets=False,
+      use_index_order=False,
+      float_format=None,
+      double_format=None,
+      use_field_number=False,
+      descriptor_pool=None,
+      message_formatter=None,
+      print_unknown_fields=False,
+      force_colon=False):
+    """Initialize the Printer.
+
+    Double values can be formatted compactly with 15 digits of precision
+    (which is the most that IEEE 754 "double" can guarantee) using
+    double_format='.15g'. To ensure that converting to text and back to a proto
+    will result in an identical value, double_format='.17g' should be used.
+
+    Args:
+      out: To record the text format result.
+      indent: The initial indent level for pretty print.
+      as_utf8: Return unescaped Unicode for non-ASCII characters.
+      as_one_line: Don't introduce newlines between fields.
+      use_short_repeated_primitives: Use short repeated format for primitives.
+      pointy_brackets: If True, use angle brackets instead of curly braces for
+        nesting.
+      use_index_order: If True, print fields of a proto message using the order
+        defined in source code instead of the field number. By default, use the
+        field number order.
+      float_format: If set, use this to specify float field formatting
+        (per the "Format Specification Mini-Language"); otherwise, shortest
+        float that has same value in wire will be printed. Also affect double
+        field if double_format is not set but float_format is set.
+      double_format: If set, use this to specify double field formatting
+        (per the "Format Specification Mini-Language"); if it is not set but
+        float_format is set, use float_format. Otherwise, str() is used.
+      use_field_number: If True, print field numbers instead of names.
+      descriptor_pool: A DescriptorPool used to resolve Any types.
+      message_formatter: A function(message, indent, as_one_line): unicode|None
+        to custom format selected sub-messages (usually based on message type).
+        Use to pretty print parts of the protobuf for easier diffing.
+      print_unknown_fields: If True, unknown fields will be printed.
+      force_colon: If set, a colon will be added after the field name even if
+        the field is a proto message.
+    """
+    self.out = out
+    self.indent = indent
+    self.as_utf8 = as_utf8
+    self.as_one_line = as_one_line
+    self.use_short_repeated_primitives = use_short_repeated_primitives
+    self.pointy_brackets = pointy_brackets
+    self.use_index_order = use_index_order
+    self.float_format = float_format
+    if double_format is not None:
+      self.double_format = double_format
+    else:
+      self.double_format = float_format
+    self.use_field_number = use_field_number
+    self.descriptor_pool = descriptor_pool
+    self.message_formatter = message_formatter
+    self.print_unknown_fields = print_unknown_fields
+    self.force_colon = force_colon
+
+  def _TryPrintAsAnyMessage(self, message):
+    """Serializes if message is a google.protobuf.Any field."""
+    if '/' not in message.type_url:
+      return False
+    packed_message = _BuildMessageFromTypeName(message.TypeName(),
+                                               self.descriptor_pool)
+    if packed_message:
+      packed_message.MergeFromString(message.value)
+      colon = ':' if self.force_colon else ''
+      self.out.write('%s[%s]%s ' % (self.indent * ' ', message.type_url, colon))
+      self._PrintMessageFieldValue(packed_message)
+      self.out.write(' ' if self.as_one_line else '\n')
+      return True
+    else:
+      return False
+
+  def _TryCustomFormatMessage(self, message):
+    formatted = self.message_formatter(message, self.indent, self.as_one_line)
+    if formatted is None:
+      return False
+
+    out = self.out
+    out.write(' ' * self.indent)
+    out.write(formatted)
+    out.write(' ' if self.as_one_line else '\n')
+    return True
+
+  def PrintMessage(self, message):
+    """Convert protobuf message to text format.
+
+    Args:
+      message: The protocol buffers message.
+    """
+    if self.message_formatter and self._TryCustomFormatMessage(message):
+      return
+    if (message.DESCRIPTOR.full_name == _ANY_FULL_TYPE_NAME and
+        self._TryPrintAsAnyMessage(message)):
+      return
+    fields = message.ListFields()
+    if self.use_index_order:
+      fields.sort(
+          key=lambda x: x[0].number if x[0].is_extension else x[0].index)
+    for field, value in fields:
+      if _IsMapEntry(field):
+        for key in sorted(value):
+          # This is slow for maps with submessage entries 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 = value.GetEntryClass()(key=key, value=value[key])
+          self.PrintField(field, entry_submsg)
+      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        if (self.use_short_repeated_primitives
+            and field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE
+            and field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_STRING):
+          self._PrintShortRepeatedPrimitivesValue(field, value)
+        else:
+          for element in value:
+            self.PrintField(field, element)
+      else:
+        self.PrintField(field, value)
+
+    if self.print_unknown_fields:
+      self._PrintUnknownFields(unknown_fields.UnknownFieldSet(message))
+
+  def _PrintUnknownFields(self, unknown_field_set):
+    """Print unknown fields."""
+    out = self.out
+    for field in unknown_field_set:
+      out.write(' ' * self.indent)
+      out.write(str(field.field_number))
+      if field.wire_type == WIRETYPE_START_GROUP:
+        if self.as_one_line:
+          out.write(' { ')
+        else:
+          out.write(' {\n')
+          self.indent += 2
+
+        self._PrintUnknownFields(field.data)
+
+        if self.as_one_line:
+          out.write('} ')
+        else:
+          self.indent -= 2
+          out.write(' ' * self.indent + '}\n')
+      elif field.wire_type == WIRETYPE_LENGTH_DELIMITED:
+        try:
+          # If this field is parseable as a Message, it is probably
+          # an embedded message.
+          # pylint: disable=protected-access
+          (embedded_unknown_message, pos) = decoder._DecodeUnknownFieldSet(
+              memoryview(field.data), 0, len(field.data))
+        except Exception:    # pylint: disable=broad-except
+          pos = 0
+
+        if pos == len(field.data):
+          if self.as_one_line:
+            out.write(' { ')
+          else:
+            out.write(' {\n')
+            self.indent += 2
+
+          self._PrintUnknownFields(embedded_unknown_message)
+
+          if self.as_one_line:
+            out.write('} ')
+          else:
+            self.indent -= 2
+            out.write(' ' * self.indent + '}\n')
+        else:
+          # A string or bytes field. self.as_utf8 may not work.
+          out.write(': \"')
+          out.write(text_encoding.CEscape(field.data, False))
+          out.write('\" ' if self.as_one_line else '\"\n')
+      else:
+        # varint, fixed32, fixed64
+        out.write(': ')
+        out.write(str(field.data))
+        out.write(' ' if self.as_one_line else '\n')
+
+  def _PrintFieldName(self, field):
+    """Print field name."""
+    out = self.out
+    out.write(' ' * self.indent)
+    if self.use_field_number:
+      out.write(str(field.number))
+    else:
+      if field.is_extension:
+        out.write('[')
+        if (field.containing_type.GetOptions().message_set_wire_format and
+            field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+            field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
+          out.write(field.message_type.full_name)
+        else:
+          out.write(field.full_name)
+        out.write(']')
+      elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
+        # For groups, use the capitalized name.
+        out.write(field.message_type.name)
+      else:
+          out.write(field.name)
+
+    if (self.force_colon or
+        field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE):
+      # The colon is optional in this case, but our cross-language golden files
+      # don't include it. Here, the colon is only included if force_colon is
+      # set to True
+      out.write(':')
+
+  def PrintField(self, field, value):
+    """Print a single field name/value pair."""
+    self._PrintFieldName(field)
+    self.out.write(' ')
+    self.PrintFieldValue(field, value)
+    self.out.write(' ' if self.as_one_line else '\n')
+
+  def _PrintShortRepeatedPrimitivesValue(self, field, value):
+    """"Prints short repeated primitives value."""
+    # Note: this is called only when value has at least one element.
+    self._PrintFieldName(field)
+    self.out.write(' [')
+    for i in range(len(value) - 1):
+      self.PrintFieldValue(field, value[i])
+      self.out.write(', ')
+    self.PrintFieldValue(field, value[-1])
+    self.out.write(']')
+    self.out.write(' ' if self.as_one_line else '\n')
+
+  def _PrintMessageFieldValue(self, value):
+    if self.pointy_brackets:
+      openb = '<'
+      closeb = '>'
+    else:
+      openb = '{'
+      closeb = '}'
+
+    if self.as_one_line:
+      self.out.write('%s ' % openb)
+      self.PrintMessage(value)
+      self.out.write(closeb)
+    else:
+      self.out.write('%s\n' % openb)
+      self.indent += 2
+      self.PrintMessage(value)
+      self.indent -= 2
+      self.out.write(' ' * self.indent + closeb)
+
+  def PrintFieldValue(self, field, value):
+    """Print a single field value (not including name).
+
+    For repeated fields, the value should be a single element.
+
+    Args:
+      field: The descriptor of the field to be printed.
+      value: The value of the field.
+    """
+    out = self.out
+    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      self._PrintMessageFieldValue(value)
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+      enum_value = field.enum_type.values_by_number.get(value, None)
+      if enum_value is not None:
+        out.write(enum_value.name)
+      else:
+        out.write(str(value))
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+      out.write('\"')
+      if isinstance(value, str) and not self.as_utf8:
+        out_value = value.encode('utf-8')
+      else:
+        out_value = value
+      if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+        # We always need to escape all binary data in TYPE_BYTES fields.
+        out_as_utf8 = False
+      else:
+        out_as_utf8 = self.as_utf8
+      out.write(text_encoding.CEscape(out_value, out_as_utf8))
+      out.write('\"')
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+      if value:
+        out.write('true')
+      else:
+        out.write('false')
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT:
+      if self.float_format is not None:
+        out.write('{1:{0}}'.format(self.float_format, value))
+      else:
+        if math.isnan(value):
+          out.write(str(value))
+        else:
+          out.write(str(type_checkers.ToShortestFloat(value)))
+    elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_DOUBLE and
+          self.double_format is not None):
+      out.write('{1:{0}}'.format(self.double_format, value))
+    else:
+      out.write(str(value))
+
+
+def Parse(text,
+          message,
+          allow_unknown_extension=False,
+          allow_field_number=False,
+          descriptor_pool=None,
+          allow_unknown_field=False):
+  """Parses a text representation of a protocol message into a message.
+
+  NOTE: for historical reasons this function does not clear the input
+  message. This is different from what the binary msg.ParseFrom(...) does.
+  If text contains a field already set in message, the value is appended if the
+  field is repeated. Otherwise, an error is raised.
+
+  Example::
+
+    a = MyProto()
+    a.repeated_field.append('test')
+    b = MyProto()
+
+    # Repeated fields are combined
+    text_format.Parse(repr(a), b)
+    text_format.Parse(repr(a), b) # repeated_field contains ["test", "test"]
+
+    # Non-repeated fields cannot be overwritten
+    a.singular_field = 1
+    b.singular_field = 2
+    text_format.Parse(repr(a), b) # ParseError
+
+    # Binary version:
+    b.ParseFromString(a.SerializeToString()) # repeated_field is now "test"
+
+  Caller is responsible for clearing the message as needed.
+
+  Args:
+    text (str): Message text representation.
+    message (Message): A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
+    descriptor_pool (DescriptorPool): Descriptor pool used to resolve Any types.
+    allow_unknown_field: if True, skip over unknown field and keep
+      parsing. Avoid to use this option if possible. It may hide some
+      errors (e.g. spelling error on field name)
+
+  Returns:
+    Message: The same message passed as argument.
+
+  Raises:
+    ParseError: On text parsing problems.
+  """
+  return ParseLines(text.split(b'\n' if isinstance(text, bytes) else u'\n'),
+                    message,
+                    allow_unknown_extension,
+                    allow_field_number,
+                    descriptor_pool=descriptor_pool,
+                    allow_unknown_field=allow_unknown_field)
+
+
+def Merge(text,
+          message,
+          allow_unknown_extension=False,
+          allow_field_number=False,
+          descriptor_pool=None,
+          allow_unknown_field=False):
+  """Parses a 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. This means any non-repeated, top-level fields specified in text
+  replace those in the message.
+
+  Args:
+    text (str): Message text representation.
+    message (Message): A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
+    descriptor_pool (DescriptorPool): Descriptor pool used to resolve Any types.
+    allow_unknown_field: if True, skip over unknown field and keep
+      parsing. Avoid to use this option if possible. It may hide some
+      errors (e.g. spelling error on field name)
+
+  Returns:
+    Message: The same message passed as argument.
+
+  Raises:
+    ParseError: On text parsing problems.
+  """
+  return MergeLines(
+      text.split(b'\n' if isinstance(text, bytes) else u'\n'),
+      message,
+      allow_unknown_extension,
+      allow_field_number,
+      descriptor_pool=descriptor_pool,
+      allow_unknown_field=allow_unknown_field)
+
+
+def ParseLines(lines,
+               message,
+               allow_unknown_extension=False,
+               allow_field_number=False,
+               descriptor_pool=None,
+               allow_unknown_field=False):
+  """Parses a text representation of a protocol message into a message.
+
+  See Parse() for caveats.
+
+  Args:
+    lines: An iterable of lines of a message's text representation.
+    message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
+    descriptor_pool: A DescriptorPool used to resolve Any types.
+    allow_unknown_field: if True, skip over unknown field and keep
+      parsing. Avoid to use this option if possible. It may hide some
+      errors (e.g. spelling error on field name)
+
+  Returns:
+    The same message passed as argument.
+
+  Raises:
+    ParseError: On text parsing problems.
+  """
+  parser = _Parser(allow_unknown_extension,
+                   allow_field_number,
+                   descriptor_pool=descriptor_pool,
+                   allow_unknown_field=allow_unknown_field)
+  return parser.ParseLines(lines, message)
+
+
+def MergeLines(lines,
+               message,
+               allow_unknown_extension=False,
+               allow_field_number=False,
+               descriptor_pool=None,
+               allow_unknown_field=False):
+  """Parses a text representation of a protocol message into a message.
+
+  See Merge() for more details.
+
+  Args:
+    lines: An iterable of lines of a message's text representation.
+    message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
+    descriptor_pool: A DescriptorPool used to resolve Any types.
+    allow_unknown_field: if True, skip over unknown field and keep
+      parsing. Avoid to use this option if possible. It may hide some
+      errors (e.g. spelling error on field name)
+
+  Returns:
+    The same message passed as argument.
+
+  Raises:
+    ParseError: On text parsing problems.
+  """
+  parser = _Parser(allow_unknown_extension,
+                   allow_field_number,
+                   descriptor_pool=descriptor_pool,
+                   allow_unknown_field=allow_unknown_field)
+  return parser.MergeLines(lines, message)
+
+
+class _Parser(object):
+  """Text format parser for protocol message."""
+
+  def __init__(self,
+               allow_unknown_extension=False,
+               allow_field_number=False,
+               descriptor_pool=None,
+               allow_unknown_field=False):
+    self.allow_unknown_extension = allow_unknown_extension
+    self.allow_field_number = allow_field_number
+    self.descriptor_pool = descriptor_pool
+    self.allow_unknown_field = allow_unknown_field
+
+  def ParseLines(self, lines, message):
+    """Parses a text representation of a protocol message into a message."""
+    self._allow_multiple_scalars = False
+    self._ParseOrMerge(lines, message)
+    return message
+
+  def MergeLines(self, lines, message):
+    """Merges a text representation of a protocol message into a message."""
+    self._allow_multiple_scalars = True
+    self._ParseOrMerge(lines, message)
+    return message
+
+  def _ParseOrMerge(self, lines, message):
+    """Converts a text representation of a protocol message into a message.
+
+    Args:
+      lines: Lines of a message's text representation.
+      message: A protocol buffer message to merge into.
+
+    Raises:
+      ParseError: On text parsing problems.
+    """
+    # Tokenize expects native str lines.
+    str_lines = (
+        line if isinstance(line, str) else line.decode('utf-8')
+        for line in lines)
+    tokenizer = Tokenizer(str_lines)
+    while not tokenizer.AtEnd():
+      self._MergeField(tokenizer, message)
+
+  def _MergeField(self, tokenizer, message):
+    """Merges a single protocol message field into a message.
+
+    Args:
+      tokenizer: A tokenizer to parse the field name and values.
+      message: A protocol message to record the data.
+
+    Raises:
+      ParseError: In case of text parsing problems.
+    """
+    message_descriptor = message.DESCRIPTOR
+    if (message_descriptor.full_name == _ANY_FULL_TYPE_NAME and
+        tokenizer.TryConsume('[')):
+      type_url_prefix, packed_type_name = self._ConsumeAnyTypeUrl(tokenizer)
+      tokenizer.Consume(']')
+      tokenizer.TryConsume(':')
+      if tokenizer.TryConsume('<'):
+        expanded_any_end_token = '>'
+      else:
+        tokenizer.Consume('{')
+        expanded_any_end_token = '}'
+      expanded_any_sub_message = _BuildMessageFromTypeName(packed_type_name,
+                                                           self.descriptor_pool)
+      # Direct comparison with None is used instead of implicit bool conversion
+      # to avoid false positives with falsy initial values, e.g. for
+      # google.protobuf.ListValue.
+      if expanded_any_sub_message is None:
+        raise ParseError('Type %s not found in descriptor pool' %
+                         packed_type_name)
+      while not tokenizer.TryConsume(expanded_any_end_token):
+        if tokenizer.AtEnd():
+          raise tokenizer.ParseErrorPreviousToken('Expected "%s".' %
+                                                  (expanded_any_end_token,))
+        self._MergeField(tokenizer, expanded_any_sub_message)
+      deterministic = False
+
+      message.Pack(expanded_any_sub_message,
+                   type_url_prefix=type_url_prefix,
+                   deterministic=deterministic)
+      return
+
+    if tokenizer.TryConsume('['):
+      name = [tokenizer.ConsumeIdentifier()]
+      while tokenizer.TryConsume('.'):
+        name.append(tokenizer.ConsumeIdentifier())
+      name = '.'.join(name)
+
+      if not message_descriptor.is_extendable:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Message type "%s" does not have extensions.' %
+            message_descriptor.full_name)
+      # pylint: disable=protected-access
+      field = message.Extensions._FindExtensionByName(name)
+      # pylint: enable=protected-access
+
+
+      if not field:
+        if self.allow_unknown_extension:
+          field = None
+        else:
+          raise tokenizer.ParseErrorPreviousToken(
+              'Extension "%s" not registered. '
+              'Did you import the _pb2 module which defines it? '
+              'If you are trying to place the extension in the MessageSet '
+              'field of another message that is in an Any or MessageSet field, '
+              'that message\'s _pb2 module must be imported as well' % 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.ConsumeIdentifierOrNumber()
+      if self.allow_field_number and name.isdigit():
+        number = ParseInteger(name, True, True)
+        field = message_descriptor.fields_by_number.get(number, None)
+        if not field and message_descriptor.is_extendable:
+          field = message.Extensions._FindExtensionByNumber(number)
+      else:
+        field = message_descriptor.fields_by_name.get(name, None)
+
+        # Group names are expected to be capitalized as they appear in the
+        # .proto file, which actually matches their type names, not their field
+        # names.
+        if not field:
+          field = message_descriptor.fields_by_name.get(name.lower(), None)
+          if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
+            field = None
+
+        if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
+            field.message_type.name != name):
+          field = None
+
+      if not field and not self.allow_unknown_field:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Message type "%s" has no field named "%s".' %
+            (message_descriptor.full_name, name))
+
+    if field:
+      if not self._allow_multiple_scalars and field.containing_oneof:
+        # Check if there's a different field set in this oneof.
+        # Note that we ignore the case if the same field was set before, and we
+        # apply _allow_multiple_scalars to non-scalar fields as well.
+        which_oneof = message.WhichOneof(field.containing_oneof.name)
+        if which_oneof is not None and which_oneof != field.name:
+          raise tokenizer.ParseErrorPreviousToken(
+              'Field "%s" is specified along with field "%s", another member '
+              'of oneof "%s" for message type "%s".' %
+              (field.name, which_oneof, field.containing_oneof.name,
+               message_descriptor.full_name))
+
+      if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        tokenizer.TryConsume(':')
+        merger = self._MergeMessageField
+      else:
+        tokenizer.Consume(':')
+        merger = self._MergeScalarField
+
+      if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and
+          tokenizer.TryConsume('[')):
+        # Short repeated format, e.g. "foo: [1, 2, 3]"
+        if not tokenizer.TryConsume(']'):
+          while True:
+            merger(tokenizer, message, field)
+            if tokenizer.TryConsume(']'):
+              break
+            tokenizer.Consume(',')
+
+      else:
+        merger(tokenizer, message, field)
+
+    else:  # Proto field is unknown.
+      assert (self.allow_unknown_extension or self.allow_unknown_field)
+      _SkipFieldContents(tokenizer)
+
+    # For historical reasons, fields may optionally be separated by commas or
+    # semicolons.
+    if not tokenizer.TryConsume(','):
+      tokenizer.TryConsume(';')
+
+
+  def _ConsumeAnyTypeUrl(self, tokenizer):
+    """Consumes a google.protobuf.Any type URL and returns the type name."""
+    # Consume "type.googleapis.com/".
+    prefix = [tokenizer.ConsumeIdentifier()]
+    tokenizer.Consume('.')
+    prefix.append(tokenizer.ConsumeIdentifier())
+    tokenizer.Consume('.')
+    prefix.append(tokenizer.ConsumeIdentifier())
+    tokenizer.Consume('/')
+    # Consume the fully-qualified type name.
+    name = [tokenizer.ConsumeIdentifier()]
+    while tokenizer.TryConsume('.'):
+      name.append(tokenizer.ConsumeIdentifier())
+    return '.'.join(prefix), '.'.join(name)
+
+  def _MergeMessageField(self, tokenizer, message, field):
+    """Merges a single scalar field into a message.
+
+    Args:
+      tokenizer: A tokenizer to parse the field value.
+      message: The message of which field is a member.
+      field: The descriptor of the field to be merged.
+
+    Raises:
+      ParseError: In case of text parsing problems.
+    """
+    is_map_entry = _IsMapEntry(field)
+
+    if tokenizer.TryConsume('<'):
+      end_token = '>'
+    else:
+      tokenizer.Consume('{')
+      end_token = '}'
+
+    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+      if field.is_extension:
+        sub_message = message.Extensions[field].add()
+      elif is_map_entry:
+        sub_message = getattr(message, field.name).GetEntryClass()()
+      else:
+        sub_message = getattr(message, field.name).add()
+    else:
+      if field.is_extension:
+        if (not self._allow_multiple_scalars and
+            message.HasExtension(field)):
+          raise tokenizer.ParseErrorPreviousToken(
+              'Message type "%s" should not have multiple "%s" extensions.' %
+              (message.DESCRIPTOR.full_name, field.full_name))
+        sub_message = message.Extensions[field]
+      else:
+        # Also apply _allow_multiple_scalars to message field.
+        # TODO(jieluo): Change to _allow_singular_overwrites.
+        if (not self._allow_multiple_scalars and
+            message.HasField(field.name)):
+          raise tokenizer.ParseErrorPreviousToken(
+              'Message type "%s" should not have multiple "%s" fields.' %
+              (message.DESCRIPTOR.full_name, field.name))
+        sub_message = getattr(message, field.name)
+      sub_message.SetInParent()
+
+    while not tokenizer.TryConsume(end_token):
+      if tokenizer.AtEnd():
+        raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,))
+      self._MergeField(tokenizer, sub_message)
+
+    if is_map_entry:
+      value_cpptype = field.message_type.fields_by_name['value'].cpp_type
+      if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        value = getattr(message, field.name)[sub_message.key]
+        value.CopyFrom(sub_message.value)
+      else:
+        getattr(message, field.name)[sub_message.key] = sub_message.value
+
+  @staticmethod
+  def _IsProto3Syntax(message):
+    message_descriptor = message.DESCRIPTOR
+    return (hasattr(message_descriptor, 'syntax') and
+            message_descriptor.syntax == 'proto3')
+
+  def _MergeScalarField(self, tokenizer, message, field):
+    """Merges a single scalar field into a message.
+
+    Args:
+      tokenizer: A tokenizer to parse the field value.
+      message: A protocol message to record the data.
+      field: The descriptor of the field to be merged.
+
+    Raises:
+      ParseError: In case of text parsing problems.
+      RuntimeError: On runtime errors.
+    """
+    _ = self.allow_unknown_extension
+    value = None
+
+    if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
+                      descriptor.FieldDescriptor.TYPE_SINT32,
+                      descriptor.FieldDescriptor.TYPE_SFIXED32):
+      value = _ConsumeInt32(tokenizer)
+    elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
+                        descriptor.FieldDescriptor.TYPE_SINT64,
+                        descriptor.FieldDescriptor.TYPE_SFIXED64):
+      value = _ConsumeInt64(tokenizer)
+    elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
+                        descriptor.FieldDescriptor.TYPE_FIXED32):
+      value = _ConsumeUint32(tokenizer)
+    elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
+                        descriptor.FieldDescriptor.TYPE_FIXED64):
+      value = _ConsumeUint64(tokenizer)
+    elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
+                        descriptor.FieldDescriptor.TYPE_DOUBLE):
+      value = tokenizer.ConsumeFloat()
+    elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
+      value = tokenizer.ConsumeBool()
+    elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
+      value = tokenizer.ConsumeString()
+    elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+      value = tokenizer.ConsumeByteString()
+    elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
+      value = tokenizer.ConsumeEnum(field)
+    else:
+      raise RuntimeError('Unknown field type %d' % field.type)
+
+    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+      if field.is_extension:
+        message.Extensions[field].append(value)
+      else:
+        getattr(message, field.name).append(value)
+    else:
+      if field.is_extension:
+        if (not self._allow_multiple_scalars and
+            not self._IsProto3Syntax(message) and
+            message.HasExtension(field)):
+          raise tokenizer.ParseErrorPreviousToken(
+              'Message type "%s" should not have multiple "%s" extensions.' %
+              (message.DESCRIPTOR.full_name, field.full_name))
+        else:
+          message.Extensions[field] = value
+      else:
+        duplicate_error = False
+        if not self._allow_multiple_scalars:
+          if self._IsProto3Syntax(message):
+            # Proto3 doesn't represent presence so we try best effort to check
+            # multiple scalars by compare to default values.
+            duplicate_error = bool(getattr(message, field.name))
+          else:
+            duplicate_error = message.HasField(field.name)
+
+        if duplicate_error:
+          raise tokenizer.ParseErrorPreviousToken(
+              'Message type "%s" should not have multiple "%s" fields.' %
+              (message.DESCRIPTOR.full_name, field.name))
+        else:
+          setattr(message, field.name, value)
+
+
+def _SkipFieldContents(tokenizer):
+  """Skips over contents (value or message) of a field.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+  # Try to guess the type of this field.
+  # If this field is not a message, there should be a ":" between the
+  # field name and the field value and also the field value should not
+  # start with "{" or "<" which indicates the beginning of a message body.
+  # If there is no ":" or there is a "{" or "<" after ":", this field has
+  # to be a message or the input is ill-formed.
+  if tokenizer.TryConsume(
+      ':') and not tokenizer.LookingAt('{') and not tokenizer.LookingAt('<'):
+    if tokenizer.LookingAt('['):
+      _SkipRepeatedFieldValue(tokenizer)
+    else:
+      _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.ConsumeIdentifierOrNumber()
+
+  _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/bytes tokens can come in multiple adjacent string literals.
+  # If we can consume one, consume as many as we can.
+  if tokenizer.TryConsumeByteString():
+    while tokenizer.TryConsumeByteString():
+      pass
+    return
+
+  if (not tokenizer.TryConsumeIdentifier() and
+      not _TryConsumeInt64(tokenizer) and not _TryConsumeUint64(tokenizer) and
+      not tokenizer.TryConsumeFloat()):
+    raise ParseError('Invalid field value: ' + tokenizer.token)
+
+
+def _SkipRepeatedFieldValue(tokenizer):
+  """Skips over a repeated field value.
+
+  Args:
+    tokenizer: A tokenizer to parse the field value.
+  """
+  tokenizer.Consume('[')
+  if not tokenizer.LookingAt(']'):
+    _SkipFieldValue(tokenizer)
+    while tokenizer.TryConsume(','):
+      _SkipFieldValue(tokenizer)
+  tokenizer.Consume(']')
+
+
+class Tokenizer(object):
+  """Protocol buffer text representation tokenizer.
+
+  This class handles the lower level string parsing by splitting it into
+  meaningful tokens.
+
+  It was directly ported from the Java protocol buffer API.
+  """
+
+  _WHITESPACE = re.compile(r'\s+')
+  _COMMENT = re.compile(r'(\s*#.*$)', re.MULTILINE)
+  _WHITESPACE_OR_COMMENT = re.compile(r'(\s|(#.*$))+', re.MULTILINE)
+  _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
+      # Avoid backtracking! https://stackoverflow.com/a/844267
+      r'{qt}[^{qt}\n\\]*((\\.)+[^{qt}\n\\]*)*({qt}|\\?$)'.format(qt=mark)
+      for mark in _QUOTES
+  ]))
+
+  _IDENTIFIER = re.compile(r'[^\d\W]\w*')
+  _IDENTIFIER_OR_NUMBER = re.compile(r'\w+')
+
+  def __init__(self, lines, skip_comments=True):
+    self._position = 0
+    self._line = -1
+    self._column = 0
+    self._token_start = None
+    self.token = ''
+    self._lines = iter(lines)
+    self._current_line = ''
+    self._previous_line = 0
+    self._previous_column = 0
+    self._more_lines = True
+    self._skip_comments = skip_comments
+    self._whitespace_pattern = (skip_comments and self._WHITESPACE_OR_COMMENT
+                                or self._WHITESPACE)
+    self._SkipWhitespace()
+    self.NextToken()
+
+  def LookingAt(self, token):
+    return self.token == token
+
+  def AtEnd(self):
+    """Checks the end of the text was reached.
+
+    Returns:
+      True iff the end was reached.
+    """
+    return not self.token
+
+  def _PopLine(self):
+    while len(self._current_line) <= self._column:
+      try:
+        self._current_line = next(self._lines)
+      except StopIteration:
+        self._current_line = ''
+        self._more_lines = False
+        return
+      else:
+        self._line += 1
+        self._column = 0
+
+  def _SkipWhitespace(self):
+    while True:
+      self._PopLine()
+      match = self._whitespace_pattern.match(self._current_line, self._column)
+      if not match:
+        break
+      length = len(match.group(0))
+      self._column += length
+
+  def TryConsume(self, token):
+    """Tries to consume a given piece of text.
+
+    Args:
+      token: Text to consume.
+
+    Returns:
+      True iff the text was consumed.
+    """
+    if self.token == token:
+      self.NextToken()
+      return True
+    return False
+
+  def Consume(self, token):
+    """Consumes a piece of text.
+
+    Args:
+      token: Text to consume.
+
+    Raises:
+      ParseError: If the text couldn't be consumed.
+    """
+    if not self.TryConsume(token):
+      raise self.ParseError('Expected "%s".' % token)
+
+  def ConsumeComment(self):
+    result = self.token
+    if not self._COMMENT.match(result):
+      raise self.ParseError('Expected comment.')
+    self.NextToken()
+    return result
+
+  def ConsumeCommentOrTrailingComment(self):
+    """Consumes a comment, returns a 2-tuple (trailing bool, comment str)."""
+
+    # Tokenizer initializes _previous_line and _previous_column to 0. As the
+    # tokenizer starts, it looks like there is a previous token on the line.
+    just_started = self._line == 0 and self._column == 0
+
+    before_parsing = self._previous_line
+    comment = self.ConsumeComment()
+
+    # A trailing comment is a comment on the same line than the previous token.
+    trailing = (self._previous_line == before_parsing
+                and not just_started)
+
+    return trailing, comment
+
+  def TryConsumeIdentifier(self):
+    try:
+      self.ConsumeIdentifier()
+      return True
+    except ParseError:
+      return False
+
+  def ConsumeIdentifier(self):
+    """Consumes protocol message field identifier.
+
+    Returns:
+      Identifier string.
+
+    Raises:
+      ParseError: If an identifier couldn't be consumed.
+    """
+    result = self.token
+    if not self._IDENTIFIER.match(result):
+      raise self.ParseError('Expected identifier.')
+    self.NextToken()
+    return result
+
+  def TryConsumeIdentifierOrNumber(self):
+    try:
+      self.ConsumeIdentifierOrNumber()
+      return True
+    except ParseError:
+      return False
+
+  def ConsumeIdentifierOrNumber(self):
+    """Consumes protocol message field identifier.
+
+    Returns:
+      Identifier string.
+
+    Raises:
+      ParseError: If an identifier couldn't be consumed.
+    """
+    result = self.token
+    if not self._IDENTIFIER_OR_NUMBER.match(result):
+      raise self.ParseError('Expected identifier or number, got %s.' % result)
+    self.NextToken()
+    return result
+
+  def TryConsumeInteger(self):
+    try:
+      self.ConsumeInteger()
+      return True
+    except ParseError:
+      return False
+
+  def ConsumeInteger(self):
+    """Consumes an integer number.
+
+    Returns:
+      The integer parsed.
+
+    Raises:
+      ParseError: If an integer couldn't be consumed.
+    """
+    try:
+      result = _ParseAbstractInteger(self.token)
+    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.
+
+    Returns:
+      The number parsed.
+
+    Raises:
+      ParseError: If a floating point number couldn't be consumed.
+    """
+    try:
+      result = ParseFloat(self.token)
+    except ValueError as e:
+      raise self.ParseError(str(e))
+    self.NextToken()
+    return result
+
+  def ConsumeBool(self):
+    """Consumes a boolean value.
+
+    Returns:
+      The bool parsed.
+
+    Raises:
+      ParseError: If a boolean value couldn't be consumed.
+    """
+    try:
+      result = ParseBool(self.token)
+    except ValueError as e:
+      raise self.ParseError(str(e))
+    self.NextToken()
+    return result
+
+  def TryConsumeByteString(self):
+    try:
+      self.ConsumeByteString()
+      return True
+    except ParseError:
+      return False
+
+  def ConsumeString(self):
+    """Consumes a string value.
+
+    Returns:
+      The string parsed.
+
+    Raises:
+      ParseError: If a string value couldn't be consumed.
+    """
+    the_bytes = self.ConsumeByteString()
+    try:
+      return str(the_bytes, 'utf-8')
+    except UnicodeDecodeError as e:
+      raise self._StringParseError(e)
+
+  def ConsumeByteString(self):
+    """Consumes a byte array value.
+
+    Returns:
+      The array parsed (as a string).
+
+    Raises:
+      ParseError: If a byte array value couldn't be consumed.
+    """
+    the_list = [self._ConsumeSingleByteString()]
+    while self.token and self.token[0] in _QUOTES:
+      the_list.append(self._ConsumeSingleByteString())
+    return b''.join(the_list)
+
+  def _ConsumeSingleByteString(self):
+    """Consume one token of a string literal.
+
+    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 _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: %r' % (text,))
+
+    try:
+      result = text_encoding.CUnescape(text[1:-1])
+    except ValueError as e:
+      raise self.ParseError(str(e))
+    self.NextToken()
+    return result
+
+  def ConsumeEnum(self, field):
+    try:
+      result = ParseEnum(field, self.token)
+    except ValueError as e:
+      raise self.ParseError(str(e))
+    self.NextToken()
+    return result
+
+  def ParseErrorPreviousToken(self, message):
+    """Creates and *returns* a ParseError for the previously read token.
+
+    Args:
+      message: A message to set for the exception.
+
+    Returns:
+      A ParseError instance.
+    """
+    return ParseError(message, self._previous_line + 1,
+                      self._previous_column + 1)
+
+  def ParseError(self, message):
+    """Creates and *returns* a ParseError for the current token."""
+    return ParseError('\'' + self._current_line + '\': ' + message,
+                      self._line + 1, self._column + 1)
+
+  def _StringParseError(self, e):
+    return self.ParseError('Couldn\'t parse string: ' + str(e))
+
+  def NextToken(self):
+    """Reads the next meaningful token."""
+    self._previous_line = self._line
+    self._previous_column = self._column
+
+    self._column += len(self.token)
+    self._SkipWhitespace()
+
+    if not self._more_lines:
+      self.token = ''
+      return
+
+    match = self._TOKEN.match(self._current_line, self._column)
+    if not match and not self._skip_comments:
+      match = self._COMMENT.match(self._current_line, self._column)
+    if match:
+      token = match.group(0)
+      self.token = token
+    else:
+      self.token = self._current_line[self._column]
+
+# Aliased so it can still be accessed by current visibility violators.
+# TODO(dbarnett): Migrate violators to textformat_tokenizer.
+_Tokenizer = Tokenizer  # pylint: disable=invalid-name
+
+
+def _ConsumeInt32(tokenizer):
+  """Consumes a signed 32bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If a signed 32bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=True, is_long=False)
+
+
+def _ConsumeUint32(tokenizer):
+  """Consumes an unsigned 32bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If an unsigned 32bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=False, is_long=False)
+
+
+def _TryConsumeInt64(tokenizer):
+  try:
+    _ConsumeInt64(tokenizer)
+    return True
+  except ParseError:
+    return False
+
+
+def _ConsumeInt64(tokenizer):
+  """Consumes a signed 32bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If a signed 32bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=True, is_long=True)
+
+
+def _TryConsumeUint64(tokenizer):
+  try:
+    _ConsumeUint64(tokenizer)
+    return True
+  except ParseError:
+    return False
+
+
+def _ConsumeUint64(tokenizer):
+  """Consumes an unsigned 64bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If an unsigned 64bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=False, is_long=True)
+
+
+def _ConsumeInteger(tokenizer, is_signed=False, is_long=False):
+  """Consumes an integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+    is_signed: True if a signed integer must be parsed.
+    is_long: True if a long integer must be parsed.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If an integer with given characteristics couldn't be consumed.
+  """
+  try:
+    result = ParseInteger(tokenizer.token, is_signed=is_signed, is_long=is_long)
+  except ValueError as e:
+    raise tokenizer.ParseError(str(e))
+  tokenizer.NextToken()
+  return result
+
+
+def ParseInteger(text, is_signed=False, is_long=False):
+  """Parses an integer.
+
+  Args:
+    text: The text to parse.
+    is_signed: True if a signed integer must be parsed.
+    is_long: True if a long integer must be parsed.
+
+  Returns:
+    The integer value.
+
+  Raises:
+    ValueError: Thrown Iff the text is not a valid integer.
+  """
+  # Do the actual parsing. Exception handling is propagated to caller.
+  result = _ParseAbstractInteger(text)
+
+  # Check if the integer is sane. Exceptions handled by callers.
+  checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
+  checker.CheckValue(result)
+  return result
+
+
+def _ParseAbstractInteger(text):
+  """Parses an integer without checking size/signedness.
+
+  Args:
+    text: The text to parse.
+
+  Returns:
+    The integer value.
+
+  Raises:
+    ValueError: Thrown Iff the text is not a valid integer.
+  """
+  # Do the actual parsing. Exception handling is propagated to caller.
+  orig_text = text
+  c_octal_match = re.match(r'(-?)0(\d+)$', text)
+  if c_octal_match:
+    # Python 3 no longer supports 0755 octal syntax without the 'o', so
+    # we always use the '0o' prefix for multi-digit numbers starting with 0.
+    text = c_octal_match.group(1) + '0o' + c_octal_match.group(2)
+  try:
+    return int(text, 0)
+  except ValueError:
+    raise ValueError('Couldn\'t parse integer: %s' % orig_text)
+
+
+def ParseFloat(text):
+  """Parse a floating point number.
+
+  Args:
+    text: Text to parse.
+
+  Returns:
+    The number parsed.
+
+  Raises:
+    ValueError: If a floating point number couldn't be parsed.
+  """
+  try:
+    # Assume Python compatible syntax.
+    return float(text)
+  except ValueError:
+    # Check alternative spellings.
+    if _FLOAT_INFINITY.match(text):
+      if text[0] == '-':
+        return float('-inf')
+      else:
+        return float('inf')
+    elif _FLOAT_NAN.match(text):
+      return float('nan')
+    else:
+      # assume '1.0f' format
+      try:
+        return float(text.rstrip('f'))
+      except ValueError:
+        raise ValueError('Couldn\'t parse float: %s' % text)
+
+
+def ParseBool(text):
+  """Parse a boolean value.
+
+  Args:
+    text: Text to parse.
+
+  Returns:
+    Boolean values parsed
+
+  Raises:
+    ValueError: If text is not a valid boolean.
+  """
+  if text in ('true', 't', '1', 'True'):
+    return True
+  elif text in ('false', 'f', '0', 'False'):
+    return False
+  else:
+    raise ValueError('Expected "true" or "false".')
+
+
+def ParseEnum(field, value):
+  """Parse an enum value.
+
+  The value can be specified by a number (the enum value), or by
+  a string literal (the enum name).
+
+  Args:
+    field: Enum field descriptor.
+    value: String value.
+
+  Returns:
+    Enum value number.
+
+  Raises:
+    ValueError: If the enum value could not be parsed.
+  """
+  enum_descriptor = field.enum_type
+  try:
+    number = int(value, 0)
+  except ValueError:
+    # Identifier.
+    enum_value = enum_descriptor.values_by_name.get(value, None)
+    if enum_value is None:
+      raise ValueError('Enum type "%s" has no value named %s.' %
+                       (enum_descriptor.full_name, value))
+  else:
+    # Numeric value.
+    if hasattr(field.file, 'syntax'):
+      # Attribute is checked for compatibility.
+      if field.file.syntax == 'proto3':
+        # Proto3 accept numeric unknown enums.
+        return number
+    enum_value = enum_descriptor.values_by_number.get(number, None)
+    if enum_value is None:
+      raise ValueError('Enum type "%s" has no value with number %d.' %
+                       (enum_descriptor.full_name, number))
+  return enum_value.number
diff --git a/python/google/protobuf/timestamp_pb2.py b/python/google/protobuf/timestamp_pb2.py
new file mode 100644
index 0000000..6fb22d2
--- /dev/null
+++ b/python/google/protobuf/timestamp_pb2.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/timestamp.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/timestamp.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\016TimestampProtoP\001Z2google.golang.org/protobuf/types/known/timestamppb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1fgoogle/protobuf/timestamp.proto\x12\x0fgoogle.protobuf\"+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x85\x01\n\x13\x63om.google.protobufB\x0eTimestampProtoP\x01Z2google.golang.org/protobuf/types/known/timestamppb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_TIMESTAMP = _descriptor.Descriptor(
+  name='Timestamp',
+  full_name='google.protobuf.Timestamp',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='seconds', full_name='google.protobuf.Timestamp.seconds', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='nanos', full_name='google.protobuf.Timestamp.nanos', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=52,
+  serialized_end=95,
+)
+
+DESCRIPTOR.message_types_by_name['Timestamp'] = _TIMESTAMP
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Timestamp = _reflection.GeneratedProtocolMessageType('Timestamp', (_message.Message,), {
+  'DESCRIPTOR' : _TIMESTAMP,
+  '__module__' : 'google.protobuf.timestamp_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Timestamp)
+  })
+_sym_db.RegisterMessage(Timestamp)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/type_pb2.py b/python/google/protobuf/type_pb2.py
new file mode 100644
index 0000000..bec1a1e
--- /dev/null
+++ b/python/google/protobuf/type_pb2.py
@@ -0,0 +1,573 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/type.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
+from google.protobuf import source_context_pb2 as google_dot_protobuf_dot_source__context__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/type.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\tTypeProtoP\001Z-google.golang.org/protobuf/types/known/typepb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1agoogle/protobuf/type.proto\x12\x0fgoogle.protobuf\x1a\x19google/protobuf/any.proto\x1a$google/protobuf/source_context.proto\"\xd7\x01\n\x04Type\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Field\x12\x0e\n\x06oneofs\x18\x03 \x03(\t\x12(\n\x07options\x18\x04 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x06 \x01(\x0e\x32\x17.google.protobuf.Syntax\"\xd5\x05\n\x05\x46ield\x12)\n\x04kind\x18\x01 \x01(\x0e\x32\x1b.google.protobuf.Field.Kind\x12\x37\n\x0b\x63\x61rdinality\x18\x02 \x01(\x0e\x32\".google.protobuf.Field.Cardinality\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x10\n\x08type_url\x18\x06 \x01(\t\x12\x13\n\x0boneof_index\x18\x07 \x01(\x05\x12\x0e\n\x06packed\x18\x08 \x01(\x08\x12(\n\x07options\x18\t \x03(\x0b\x32\x17.google.protobuf.Option\x12\x11\n\tjson_name\x18\n \x01(\t\x12\x15\n\rdefault_value\x18\x0b \x01(\t\"\xc8\x02\n\x04Kind\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"t\n\x0b\x43\x61rdinality\x12\x17\n\x13\x43\x41RDINALITY_UNKNOWN\x10\x00\x12\x18\n\x14\x43\x41RDINALITY_OPTIONAL\x10\x01\x12\x18\n\x14\x43\x41RDINALITY_REQUIRED\x10\x02\x12\x18\n\x14\x43\x41RDINALITY_REPEATED\x10\x03\"\xce\x01\n\x04\x45num\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\tenumvalue\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.EnumValue\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x05 \x01(\x0e\x32\x17.google.protobuf.Syntax\"S\n\tEnumValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\";\n\x06Option\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any*.\n\x06Syntax\x12\x11\n\rSYNTAX_PROTO2\x10\x00\x12\x11\n\rSYNTAX_PROTO3\x10\x01\x42{\n\x13\x63om.google.protobufB\tTypeProtoP\x01Z-google.golang.org/protobuf/types/known/typepb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+  ,
+  dependencies=[google_dot_protobuf_dot_any__pb2.DESCRIPTOR,google_dot_protobuf_dot_source__context__pb2.DESCRIPTOR,])
+
+_SYNTAX = _descriptor.EnumDescriptor(
+  name='Syntax',
+  full_name='google.protobuf.Syntax',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='SYNTAX_PROTO2', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='SYNTAX_PROTO3', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1413,
+  serialized_end=1459,
+)
+_sym_db.RegisterEnumDescriptor(_SYNTAX)
+
+Syntax = enum_type_wrapper.EnumTypeWrapper(_SYNTAX)
+SYNTAX_PROTO2 = 0
+SYNTAX_PROTO3 = 1
+
+
+_FIELD_KIND = _descriptor.EnumDescriptor(
+  name='Kind',
+  full_name='google.protobuf.Field.Kind',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_DOUBLE', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_FLOAT', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_INT64', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_UINT64', index=4, number=4,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_INT32', index=5, number=5,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_FIXED64', index=6, number=6,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_FIXED32', index=7, number=7,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_BOOL', index=8, number=8,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_STRING', index=9, number=9,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_GROUP', index=10, number=10,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_MESSAGE', index=11, number=11,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_BYTES', index=12, number=12,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_UINT32', index=13, number=13,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_ENUM', index=14, number=14,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SFIXED32', index=15, number=15,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SFIXED64', index=16, number=16,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SINT32', index=17, number=17,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TYPE_SINT64', index=18, number=18,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=610,
+  serialized_end=938,
+)
+_sym_db.RegisterEnumDescriptor(_FIELD_KIND)
+
+_FIELD_CARDINALITY = _descriptor.EnumDescriptor(
+  name='Cardinality',
+  full_name='google.protobuf.Field.Cardinality',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='CARDINALITY_UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CARDINALITY_OPTIONAL', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CARDINALITY_REQUIRED', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='CARDINALITY_REPEATED', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=940,
+  serialized_end=1056,
+)
+_sym_db.RegisterEnumDescriptor(_FIELD_CARDINALITY)
+
+
+_TYPE = _descriptor.Descriptor(
+  name='Type',
+  full_name='google.protobuf.Type',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Type.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='fields', full_name='google.protobuf.Type.fields', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='oneofs', full_name='google.protobuf.Type.oneofs', index=2,
+      number=3, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.Type.options', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_context', full_name='google.protobuf.Type.source_context', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='syntax', full_name='google.protobuf.Type.syntax', index=5,
+      number=6, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=113,
+  serialized_end=328,
+)
+
+
+_FIELD = _descriptor.Descriptor(
+  name='Field',
+  full_name='google.protobuf.Field',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='kind', full_name='google.protobuf.Field.kind', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cardinality', full_name='google.protobuf.Field.cardinality', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='number', full_name='google.protobuf.Field.number', index=2,
+      number=3, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Field.name', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='type_url', full_name='google.protobuf.Field.type_url', index=4,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='oneof_index', full_name='google.protobuf.Field.oneof_index', index=5,
+      number=7, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='packed', full_name='google.protobuf.Field.packed', index=6,
+      number=8, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.Field.options', index=7,
+      number=9, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='json_name', full_name='google.protobuf.Field.json_name', index=8,
+      number=10, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='default_value', full_name='google.protobuf.Field.default_value', index=9,
+      number=11, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _FIELD_KIND,
+    _FIELD_CARDINALITY,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=331,
+  serialized_end=1056,
+)
+
+
+_ENUM = _descriptor.Descriptor(
+  name='Enum',
+  full_name='google.protobuf.Enum',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Enum.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='enumvalue', full_name='google.protobuf.Enum.enumvalue', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.Enum.options', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='source_context', full_name='google.protobuf.Enum.source_context', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='syntax', full_name='google.protobuf.Enum.syntax', index=4,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1059,
+  serialized_end=1265,
+)
+
+
+_ENUMVALUE = _descriptor.Descriptor(
+  name='EnumValue',
+  full_name='google.protobuf.EnumValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.EnumValue.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='number', full_name='google.protobuf.EnumValue.number', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='options', full_name='google.protobuf.EnumValue.options', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1267,
+  serialized_end=1350,
+)
+
+
+_OPTION = _descriptor.Descriptor(
+  name='Option',
+  full_name='google.protobuf.Option',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='google.protobuf.Option.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.Option.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1352,
+  serialized_end=1411,
+)
+
+_TYPE.fields_by_name['fields'].message_type = _FIELD
+_TYPE.fields_by_name['options'].message_type = _OPTION
+_TYPE.fields_by_name['source_context'].message_type = google_dot_protobuf_dot_source__context__pb2._SOURCECONTEXT
+_TYPE.fields_by_name['syntax'].enum_type = _SYNTAX
+_FIELD.fields_by_name['kind'].enum_type = _FIELD_KIND
+_FIELD.fields_by_name['cardinality'].enum_type = _FIELD_CARDINALITY
+_FIELD.fields_by_name['options'].message_type = _OPTION
+_FIELD_KIND.containing_type = _FIELD
+_FIELD_CARDINALITY.containing_type = _FIELD
+_ENUM.fields_by_name['enumvalue'].message_type = _ENUMVALUE
+_ENUM.fields_by_name['options'].message_type = _OPTION
+_ENUM.fields_by_name['source_context'].message_type = google_dot_protobuf_dot_source__context__pb2._SOURCECONTEXT
+_ENUM.fields_by_name['syntax'].enum_type = _SYNTAX
+_ENUMVALUE.fields_by_name['options'].message_type = _OPTION
+_OPTION.fields_by_name['value'].message_type = google_dot_protobuf_dot_any__pb2._ANY
+DESCRIPTOR.message_types_by_name['Type'] = _TYPE
+DESCRIPTOR.message_types_by_name['Field'] = _FIELD
+DESCRIPTOR.message_types_by_name['Enum'] = _ENUM
+DESCRIPTOR.message_types_by_name['EnumValue'] = _ENUMVALUE
+DESCRIPTOR.message_types_by_name['Option'] = _OPTION
+DESCRIPTOR.enum_types_by_name['Syntax'] = _SYNTAX
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Type = _reflection.GeneratedProtocolMessageType('Type', (_message.Message,), {
+  'DESCRIPTOR' : _TYPE,
+  '__module__' : 'google.protobuf.type_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Type)
+  })
+_sym_db.RegisterMessage(Type)
+
+Field = _reflection.GeneratedProtocolMessageType('Field', (_message.Message,), {
+  'DESCRIPTOR' : _FIELD,
+  '__module__' : 'google.protobuf.type_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Field)
+  })
+_sym_db.RegisterMessage(Field)
+
+Enum = _reflection.GeneratedProtocolMessageType('Enum', (_message.Message,), {
+  'DESCRIPTOR' : _ENUM,
+  '__module__' : 'google.protobuf.type_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Enum)
+  })
+_sym_db.RegisterMessage(Enum)
+
+EnumValue = _reflection.GeneratedProtocolMessageType('EnumValue', (_message.Message,), {
+  'DESCRIPTOR' : _ENUMVALUE,
+  '__module__' : 'google.protobuf.type_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.EnumValue)
+  })
+_sym_db.RegisterMessage(EnumValue)
+
+Option = _reflection.GeneratedProtocolMessageType('Option', (_message.Message,), {
+  'DESCRIPTOR' : _OPTION,
+  '__module__' : 'google.protobuf.type_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Option)
+  })
+_sym_db.RegisterMessage(Option)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/google/protobuf/unknown_fields.py b/python/google/protobuf/unknown_fields.py
new file mode 100644
index 0000000..3bd8286
--- /dev/null
+++ b/python/google/protobuf/unknown_fields.py
@@ -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.
+
+"""Contains Unknown Fields APIs.
+
+Simple usage example:
+  unknown_field_set = UnknownFieldSet(message)
+  for unknown_field in unknown_field_set:
+    wire_type = unknown_field.wire_type
+    field_number = unknown_field.field_number
+    data = unknown_field.data
+"""
+
+
+from google.protobuf.internal import api_implementation
+
+if api_implementation._c_module is not None:  # pylint: disable=protected-access
+  UnknownFieldSet = api_implementation._c_module.UnknownFieldSet  # pylint: disable=protected-access
+else:
+  from google.protobuf.internal import decoder  # pylint: disable=g-import-not-at-top
+  from google.protobuf.internal import wire_format  # pylint: disable=g-import-not-at-top
+
+  class UnknownField:
+    """A parsed unknown field."""
+
+    # Disallows assignment to other attributes.
+    __slots__ = ['_field_number', '_wire_type', '_data']
+
+    def __init__(self, field_number, wire_type, data):
+      self._field_number = field_number
+      self._wire_type = wire_type
+      self._data = data
+      return
+
+    @property
+    def field_number(self):
+      return self._field_number
+
+    @property
+    def wire_type(self):
+      return self._wire_type
+
+    @property
+    def data(self):
+      return self._data
+
+  class UnknownFieldSet:
+    """UnknownField container."""
+
+    # Disallows assignment to other attributes.
+    __slots__ = ['_values']
+
+    def __init__(self, msg):
+
+      def InternalAdd(field_number, wire_type, data):
+        unknown_field = UnknownField(field_number, wire_type, data)
+        self._values.append(unknown_field)
+
+      self._values = []
+      msg_des = msg.DESCRIPTOR
+      # pylint: disable=protected-access
+      unknown_fields = msg._unknown_fields
+      if (msg_des.has_options and
+          msg_des.GetOptions().message_set_wire_format):
+        local_decoder = decoder.UnknownMessageSetItemDecoder()
+        for _, buffer in unknown_fields:
+          (field_number, data) = local_decoder(memoryview(buffer))
+          InternalAdd(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED, data)
+      else:
+        for tag_bytes, buffer in unknown_fields:
+          # pylint: disable=protected-access
+          (tag, _) = decoder._DecodeVarint(tag_bytes, 0)
+          field_number, wire_type = wire_format.UnpackTag(tag)
+          if field_number == 0:
+            raise RuntimeError('Field number 0 is illegal.')
+          (data, _) = decoder._DecodeUnknownField(
+              memoryview(buffer), 0, wire_type)
+          InternalAdd(field_number, wire_type, data)
+
+    def __getitem__(self, index):
+      size = len(self._values)
+      if index < 0:
+        index += size
+      if index < 0 or index >= size:
+        raise IndexError('index %d out of range'.index)
+
+      return self._values[index]
+
+    def __len__(self):
+      return len(self._values)
+
+    def __iter__(self):
+      return iter(self._values)
diff --git a/python/google/protobuf/util/__init__.py b/python/google/protobuf/util/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/google/protobuf/util/__init__.py
diff --git a/python/google/protobuf/wrappers_pb2.py b/python/google/protobuf/wrappers_pb2.py
new file mode 100644
index 0000000..6e5e2bc
--- /dev/null
+++ b/python/google/protobuf/wrappers_pb2.py
@@ -0,0 +1,391 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/protobuf/wrappers.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='google/protobuf/wrappers.proto',
+  package='google.protobuf',
+  syntax='proto3',
+  serialized_options=b'\n\023com.google.protobufB\rWrappersProtoP\001Z1google.golang.org/protobuf/types/known/wrapperspb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x1egoogle/protobuf/wrappers.proto\x12\x0fgoogle.protobuf\"\x1c\n\x0b\x44oubleValue\x12\r\n\x05value\x18\x01 \x01(\x01\"\x1b\n\nFloatValue\x12\r\n\x05value\x18\x01 \x01(\x02\"\x1b\n\nInt64Value\x12\r\n\x05value\x18\x01 \x01(\x03\"\x1c\n\x0bUInt64Value\x12\r\n\x05value\x18\x01 \x01(\x04\"\x1b\n\nInt32Value\x12\r\n\x05value\x18\x01 \x01(\x05\"\x1c\n\x0bUInt32Value\x12\r\n\x05value\x18\x01 \x01(\r\"\x1a\n\tBoolValue\x12\r\n\x05value\x18\x01 \x01(\x08\"\x1c\n\x0bStringValue\x12\r\n\x05value\x18\x01 \x01(\t\"\x1b\n\nBytesValue\x12\r\n\x05value\x18\x01 \x01(\x0c\x42\x83\x01\n\x13\x63om.google.protobufB\rWrappersProtoP\x01Z1google.golang.org/protobuf/types/known/wrapperspb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3'
+)
+
+
+
+
+_DOUBLEVALUE = _descriptor.Descriptor(
+  name='DoubleValue',
+  full_name='google.protobuf.DoubleValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.DoubleValue.value', index=0,
+      number=1, type=1, cpp_type=5, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=51,
+  serialized_end=79,
+)
+
+
+_FLOATVALUE = _descriptor.Descriptor(
+  name='FloatValue',
+  full_name='google.protobuf.FloatValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.FloatValue.value', index=0,
+      number=1, type=2, cpp_type=6, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=81,
+  serialized_end=108,
+)
+
+
+_INT64VALUE = _descriptor.Descriptor(
+  name='Int64Value',
+  full_name='google.protobuf.Int64Value',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.Int64Value.value', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=110,
+  serialized_end=137,
+)
+
+
+_UINT64VALUE = _descriptor.Descriptor(
+  name='UInt64Value',
+  full_name='google.protobuf.UInt64Value',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.UInt64Value.value', index=0,
+      number=1, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=139,
+  serialized_end=167,
+)
+
+
+_INT32VALUE = _descriptor.Descriptor(
+  name='Int32Value',
+  full_name='google.protobuf.Int32Value',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.Int32Value.value', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=169,
+  serialized_end=196,
+)
+
+
+_UINT32VALUE = _descriptor.Descriptor(
+  name='UInt32Value',
+  full_name='google.protobuf.UInt32Value',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.UInt32Value.value', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=198,
+  serialized_end=226,
+)
+
+
+_BOOLVALUE = _descriptor.Descriptor(
+  name='BoolValue',
+  full_name='google.protobuf.BoolValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.BoolValue.value', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=228,
+  serialized_end=254,
+)
+
+
+_STRINGVALUE = _descriptor.Descriptor(
+  name='StringValue',
+  full_name='google.protobuf.StringValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.StringValue.value', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=256,
+  serialized_end=284,
+)
+
+
+_BYTESVALUE = _descriptor.Descriptor(
+  name='BytesValue',
+  full_name='google.protobuf.BytesValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='google.protobuf.BytesValue.value', index=0,
+      number=1, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=286,
+  serialized_end=313,
+)
+
+DESCRIPTOR.message_types_by_name['DoubleValue'] = _DOUBLEVALUE
+DESCRIPTOR.message_types_by_name['FloatValue'] = _FLOATVALUE
+DESCRIPTOR.message_types_by_name['Int64Value'] = _INT64VALUE
+DESCRIPTOR.message_types_by_name['UInt64Value'] = _UINT64VALUE
+DESCRIPTOR.message_types_by_name['Int32Value'] = _INT32VALUE
+DESCRIPTOR.message_types_by_name['UInt32Value'] = _UINT32VALUE
+DESCRIPTOR.message_types_by_name['BoolValue'] = _BOOLVALUE
+DESCRIPTOR.message_types_by_name['StringValue'] = _STRINGVALUE
+DESCRIPTOR.message_types_by_name['BytesValue'] = _BYTESVALUE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+DoubleValue = _reflection.GeneratedProtocolMessageType('DoubleValue', (_message.Message,), {
+  'DESCRIPTOR' : _DOUBLEVALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.DoubleValue)
+  })
+_sym_db.RegisterMessage(DoubleValue)
+
+FloatValue = _reflection.GeneratedProtocolMessageType('FloatValue', (_message.Message,), {
+  'DESCRIPTOR' : _FLOATVALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.FloatValue)
+  })
+_sym_db.RegisterMessage(FloatValue)
+
+Int64Value = _reflection.GeneratedProtocolMessageType('Int64Value', (_message.Message,), {
+  'DESCRIPTOR' : _INT64VALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Int64Value)
+  })
+_sym_db.RegisterMessage(Int64Value)
+
+UInt64Value = _reflection.GeneratedProtocolMessageType('UInt64Value', (_message.Message,), {
+  'DESCRIPTOR' : _UINT64VALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.UInt64Value)
+  })
+_sym_db.RegisterMessage(UInt64Value)
+
+Int32Value = _reflection.GeneratedProtocolMessageType('Int32Value', (_message.Message,), {
+  'DESCRIPTOR' : _INT32VALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.Int32Value)
+  })
+_sym_db.RegisterMessage(Int32Value)
+
+UInt32Value = _reflection.GeneratedProtocolMessageType('UInt32Value', (_message.Message,), {
+  'DESCRIPTOR' : _UINT32VALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.UInt32Value)
+  })
+_sym_db.RegisterMessage(UInt32Value)
+
+BoolValue = _reflection.GeneratedProtocolMessageType('BoolValue', (_message.Message,), {
+  'DESCRIPTOR' : _BOOLVALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.BoolValue)
+  })
+_sym_db.RegisterMessage(BoolValue)
+
+StringValue = _reflection.GeneratedProtocolMessageType('StringValue', (_message.Message,), {
+  'DESCRIPTOR' : _STRINGVALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.StringValue)
+  })
+_sym_db.RegisterMessage(StringValue)
+
+BytesValue = _reflection.GeneratedProtocolMessageType('BytesValue', (_message.Message,), {
+  'DESCRIPTOR' : _BYTESVALUE,
+  '__module__' : 'google.protobuf.wrappers_pb2'
+  # @@protoc_insertion_point(class_scope:google.protobuf.BytesValue)
+  })
+_sym_db.RegisterMessage(BytesValue)
+
+
+DESCRIPTOR._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/python/mox.py b/python/mox.py
new file mode 100755
index 0000000..9dd8ac7
--- /dev/null
+++ b/python/mox.py
@@ -0,0 +1,1401 @@
+#!/usr/bin/python2.4
+#
+# Copyright 2008 Google Inc.
+#
+# 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.
+
+# This file is used for testing.  The original is at:
+#   http://code.google.com/p/pymox/
+
+"""Mox, an object-mocking framework for Python.
+
+Mox works in the record-replay-verify paradigm.  When you first create
+a mock object, it is in record mode.  You then programmatically set
+the expected behavior of the mock object (what methods are to be
+called on it, with what parameters, what they should return, and in
+what order).
+
+Once you have set up the expected mock behavior, you put it in replay
+mode.  Now the mock responds to method calls just as you told it to.
+If an unexpected method (or an expected method with unexpected
+parameters) is called, then an exception will be raised.
+
+Once you are done interacting with the mock, you need to verify that
+all the expected interactions occurred.  (Maybe your code exited
+prematurely without calling some cleanup method!)  The verify phase
+ensures that every expected method was called; otherwise, an exception
+will be raised.
+
+Suggested usage / workflow:
+
+  # Create Mox factory
+  my_mox = Mox()
+
+  # Create a mock data access object
+  mock_dao = my_mox.CreateMock(DAOClass)
+
+  # Set up expected behavior
+  mock_dao.RetrievePersonWithIdentifier('1').AndReturn(person)
+  mock_dao.DeletePerson(person)
+
+  # Put mocks in replay mode
+  my_mox.ReplayAll()
+
+  # Inject mock object and run test
+  controller.SetDao(mock_dao)
+  controller.DeletePersonById('1')
+
+  # Verify all methods were called as expected
+  my_mox.VerifyAll()
+"""
+
+from collections import deque
+import re
+import types
+import unittest
+
+import stubout
+
+class Error(AssertionError):
+  """Base exception for this module."""
+
+  pass
+
+
+class ExpectedMethodCallsError(Error):
+  """Raised when Verify() is called before all expected methods have been called
+  """
+
+  def __init__(self, expected_methods):
+    """Init exception.
+
+    Args:
+      # expected_methods: A sequence of MockMethod objects that should have been
+      #   called.
+      expected_methods: [MockMethod]
+
+    Raises:
+      ValueError: if expected_methods contains no methods.
+    """
+
+    if not expected_methods:
+      raise ValueError("There must be at least one expected method")
+    Error.__init__(self)
+    self._expected_methods = expected_methods
+
+  def __str__(self):
+    calls = "\n".join(["%3d.  %s" % (i, m)
+                       for i, m in enumerate(self._expected_methods)])
+    return "Verify: Expected methods never called:\n%s" % (calls,)
+
+
+class UnexpectedMethodCallError(Error):
+  """Raised when an unexpected method is called.
+
+  This can occur if a method is called with incorrect parameters, or out of the
+  specified order.
+  """
+
+  def __init__(self, unexpected_method, expected):
+    """Init exception.
+
+    Args:
+      # unexpected_method: MockMethod that was called but was not at the head of
+      #   the expected_method queue.
+      # expected: MockMethod or UnorderedGroup the method should have
+      #   been in.
+      unexpected_method: MockMethod
+      expected: MockMethod or UnorderedGroup
+    """
+
+    Error.__init__(self)
+    self._unexpected_method = unexpected_method
+    self._expected = expected
+
+  def __str__(self):
+    return "Unexpected method call: %s.  Expecting: %s" % \
+      (self._unexpected_method, self._expected)
+
+
+class UnknownMethodCallError(Error):
+  """Raised if an unknown method is requested of the mock object."""
+
+  def __init__(self, unknown_method_name):
+    """Init exception.
+
+    Args:
+      # unknown_method_name: Method call that is not part of the mocked class's
+      #   public interface.
+      unknown_method_name: str
+    """
+
+    Error.__init__(self)
+    self._unknown_method_name = unknown_method_name
+
+  def __str__(self):
+    return "Method called is not a member of the object: %s" % \
+      self._unknown_method_name
+
+
+class Mox(object):
+  """Mox: a factory for creating mock objects."""
+
+  # A list of types that should be stubbed out with MockObjects (as
+  # opposed to MockAnythings).
+  _USE_MOCK_OBJECT = [types.ClassType, types.InstanceType, types.ModuleType,
+                      types.ObjectType, types.TypeType]
+
+  def __init__(self):
+    """Initialize a new Mox."""
+
+    self._mock_objects = []
+    self.stubs = stubout.StubOutForTesting()
+
+  def CreateMock(self, class_to_mock):
+    """Create a new mock object.
+
+    Args:
+      # class_to_mock: the class to be mocked
+      class_to_mock: class
+
+    Returns:
+      MockObject that can be used as the class_to_mock would be.
+    """
+
+    new_mock = MockObject(class_to_mock)
+    self._mock_objects.append(new_mock)
+    return new_mock
+
+  def CreateMockAnything(self):
+    """Create a mock that will accept any method calls.
+
+    This does not enforce an interface.
+    """
+
+    new_mock = MockAnything()
+    self._mock_objects.append(new_mock)
+    return new_mock
+
+  def ReplayAll(self):
+    """Set all mock objects to replay mode."""
+
+    for mock_obj in self._mock_objects:
+      mock_obj._Replay()
+
+
+  def VerifyAll(self):
+    """Call verify on all mock objects created."""
+
+    for mock_obj in self._mock_objects:
+      mock_obj._Verify()
+
+  def ResetAll(self):
+    """Call reset on all mock objects.  This does not unset stubs."""
+
+    for mock_obj in self._mock_objects:
+      mock_obj._Reset()
+
+  def StubOutWithMock(self, obj, attr_name, use_mock_anything=False):
+    """Replace a method, attribute, etc. with a Mock.
+
+    This will replace a class or module with a MockObject, and everything else
+    (method, function, etc) with a MockAnything.  This can be overridden to
+    always use a MockAnything by setting use_mock_anything to True.
+
+    Args:
+      obj: A Python object (class, module, instance, callable).
+      attr_name: str.  The name of the attribute to replace with a mock.
+      use_mock_anything: bool. True if a MockAnything should be used regardless
+        of the type of attribute.
+    """
+
+    attr_to_replace = getattr(obj, attr_name)
+    if type(attr_to_replace) in self._USE_MOCK_OBJECT and not use_mock_anything:
+      stub = self.CreateMock(attr_to_replace)
+    else:
+      stub = self.CreateMockAnything()
+
+    self.stubs.Set(obj, attr_name, stub)
+
+  def UnsetStubs(self):
+    """Restore stubs to their original state."""
+
+    self.stubs.UnsetAll()
+
+def Replay(*args):
+  """Put mocks into Replay mode.
+
+  Args:
+    # args is any number of mocks to put into replay mode.
+  """
+
+  for mock in args:
+    mock._Replay()
+
+
+def Verify(*args):
+  """Verify mocks.
+
+  Args:
+    # args is any number of mocks to be verified.
+  """
+
+  for mock in args:
+    mock._Verify()
+
+
+def Reset(*args):
+  """Reset mocks.
+
+  Args:
+    # args is any number of mocks to be reset.
+  """
+
+  for mock in args:
+    mock._Reset()
+
+
+class MockAnything:
+  """A mock that can be used to mock anything.
+
+  This is helpful for mocking classes that do not provide a public interface.
+  """
+
+  def __init__(self):
+    """ """
+    self._Reset()
+
+  def __getattr__(self, method_name):
+    """Intercept method calls on this object.
+
+     A new MockMethod is returned that is aware of the MockAnything's
+     state (record or replay).  The call will be recorded or replayed
+     by the MockMethod's __call__.
+
+    Args:
+      # method name: the name of the method being called.
+      method_name: str
+
+    Returns:
+      A new MockMethod aware of MockAnything's state (record or replay).
+    """
+
+    return self._CreateMockMethod(method_name)
+
+  def _CreateMockMethod(self, method_name):
+    """Create a new mock method call and return it.
+
+    Args:
+      # method name: the name of the method being called.
+      method_name: str
+
+    Returns:
+      A new MockMethod aware of MockAnything's state (record or replay).
+    """
+
+    return MockMethod(method_name, self._expected_calls_queue,
+                      self._replay_mode)
+
+  def __nonzero__(self):
+    """Return 1 for nonzero so the mock can be used as a conditional."""
+
+    return 1
+
+  def __eq__(self, rhs):
+    """Provide custom logic to compare objects."""
+
+    return (isinstance(rhs, MockAnything) and
+            self._replay_mode == rhs._replay_mode and
+            self._expected_calls_queue == rhs._expected_calls_queue)
+
+  def __ne__(self, rhs):
+    """Provide custom logic to compare objects."""
+
+    return not self == rhs
+
+  def _Replay(self):
+    """Start replaying expected method calls."""
+
+    self._replay_mode = True
+
+  def _Verify(self):
+    """Verify that all of the expected calls have been made.
+
+    Raises:
+      ExpectedMethodCallsError: if there are still more method calls in the
+        expected queue.
+    """
+
+    # If the list of expected calls is not empty, raise an exception
+    if self._expected_calls_queue:
+      # The last MultipleTimesGroup is not popped from the queue.
+      if (len(self._expected_calls_queue) == 1 and
+          isinstance(self._expected_calls_queue[0], MultipleTimesGroup) and
+          self._expected_calls_queue[0].IsSatisfied()):
+        pass
+      else:
+        raise ExpectedMethodCallsError(self._expected_calls_queue)
+
+  def _Reset(self):
+    """Reset the state of this mock to record mode with an empty queue."""
+
+    # Maintain a list of method calls we are expecting
+    self._expected_calls_queue = deque()
+
+    # Make sure we are in setup mode, not replay mode
+    self._replay_mode = False
+
+
+class MockObject(MockAnything, object):
+  """A mock object that simulates the public/protected interface of a class."""
+
+  def __init__(self, class_to_mock):
+    """Initialize a mock object.
+
+    This determines the methods and properties of the class and stores them.
+
+    Args:
+      # class_to_mock: class to be mocked
+      class_to_mock: class
+    """
+
+    # This is used to hack around the mixin/inheritance of MockAnything, which
+    # is not a proper object (it can be anything. :-)
+    MockAnything.__dict__['__init__'](self)
+
+    # Get a list of all the public and special methods we should mock.
+    self._known_methods = set()
+    self._known_vars = set()
+    self._class_to_mock = class_to_mock
+    for method in dir(class_to_mock):
+      if callable(getattr(class_to_mock, method)):
+        self._known_methods.add(method)
+      else:
+        self._known_vars.add(method)
+
+  def __getattr__(self, name):
+    """Intercept attribute request on this object.
+
+    If the attribute is a public class variable, it will be returned and not
+    recorded as a call.
+
+    If the attribute is not a variable, it is handled like a method
+    call. The method name is checked against the set of mockable
+    methods, and a new MockMethod is returned that is aware of the
+    MockObject's state (record or replay).  The call will be recorded
+    or replayed by the MockMethod's __call__.
+
+    Args:
+      # name: the name of the attribute being requested.
+      name: str
+
+    Returns:
+      Either a class variable or a new MockMethod that is aware of the state
+      of the mock (record or replay).
+
+    Raises:
+      UnknownMethodCallError if the MockObject does not mock the requested
+          method.
+    """
+
+    if name in self._known_vars:
+      return getattr(self._class_to_mock, name)
+
+    if name in self._known_methods:
+      return self._CreateMockMethod(name)
+
+    raise UnknownMethodCallError(name)
+
+  def __eq__(self, rhs):
+    """Provide custom logic to compare objects."""
+
+    return (isinstance(rhs, MockObject) and
+            self._class_to_mock == rhs._class_to_mock and
+            self._replay_mode == rhs._replay_mode and
+            self._expected_calls_queue == rhs._expected_calls_queue)
+
+  def __setitem__(self, key, value):
+    """Provide custom logic for mocking classes that support item assignment.
+
+    Args:
+      key: Key to set the value for.
+      value: Value to set.
+
+    Returns:
+      Expected return value in replay mode.  A MockMethod object for the
+      __setitem__ method that has already been called if not in replay mode.
+
+    Raises:
+      TypeError if the underlying class does not support item assignment.
+      UnexpectedMethodCallError if the object does not expect the call to
+        __setitem__.
+
+    """
+    setitem = self._class_to_mock.__dict__.get('__setitem__', None)
+
+    # Verify the class supports item assignment.
+    if setitem is None:
+      raise TypeError('object does not support item assignment')
+
+    # If we are in replay mode then simply call the mock __setitem__ method.
+    if self._replay_mode:
+      return MockMethod('__setitem__', self._expected_calls_queue,
+                        self._replay_mode)(key, value)
+
+
+    # Otherwise, create a mock method __setitem__.
+    return self._CreateMockMethod('__setitem__')(key, value)
+
+  def __getitem__(self, key):
+    """Provide custom logic for mocking classes that are subscriptable.
+
+    Args:
+      key: Key to return the value for.
+
+    Returns:
+      Expected return value in replay mode.  A MockMethod object for the
+      __getitem__ method that has already been called if not in replay mode.
+
+    Raises:
+      TypeError if the underlying class is not subscriptable.
+      UnexpectedMethodCallError if the object does not expect the call to
+        __setitem__.
+
+    """
+    getitem = self._class_to_mock.__dict__.get('__getitem__', None)
+
+    # Verify the class supports item assignment.
+    if getitem is None:
+      raise TypeError('unsubscriptable object')
+
+    # If we are in replay mode then simply call the mock __getitem__ method.
+    if self._replay_mode:
+      return MockMethod('__getitem__', self._expected_calls_queue,
+                        self._replay_mode)(key)
+
+
+    # Otherwise, create a mock method __getitem__.
+    return self._CreateMockMethod('__getitem__')(key)
+
+  def __call__(self, *params, **named_params):
+    """Provide custom logic for mocking classes that are callable."""
+
+    # Verify the class we are mocking is callable
+    callable = self._class_to_mock.__dict__.get('__call__', None)
+    if callable is None:
+      raise TypeError('Not callable')
+
+    # Because the call is happening directly on this object instead of a method,
+    # the call on the mock method is made right here
+    mock_method = self._CreateMockMethod('__call__')
+    return mock_method(*params, **named_params)
+
+  @property
+  def __class__(self):
+    """Return the class that is being mocked."""
+
+    return self._class_to_mock
+
+
+class MockMethod(object):
+  """Callable mock method.
+
+  A MockMethod should act exactly like the method it mocks, accepting parameters
+  and returning a value, or throwing an exception (as specified).  When this
+  method is called, it can optionally verify whether the called method (name and
+  signature) matches the expected method.
+  """
+
+  def __init__(self, method_name, call_queue, replay_mode):
+    """Construct a new mock method.
+
+    Args:
+      # method_name: the name of the method
+      # call_queue: deque of calls, verify this call against the head, or add
+      #     this call to the queue.
+      # replay_mode: False if we are recording, True if we are verifying calls
+      #     against the call queue.
+      method_name: str
+      call_queue: list or deque
+      replay_mode: bool
+    """
+
+    self._name = method_name
+    self._call_queue = call_queue
+    if not isinstance(call_queue, deque):
+      self._call_queue = deque(self._call_queue)
+    self._replay_mode = replay_mode
+
+    self._params = None
+    self._named_params = None
+    self._return_value = None
+    self._exception = None
+    self._side_effects = None
+
+  def __call__(self, *params, **named_params):
+    """Log parameters and return the specified return value.
+
+    If the Mock(Anything/Object) associated with this call is in record mode,
+    this MockMethod will be pushed onto the expected call queue.  If the mock
+    is in replay mode, this will pop a MockMethod off the top of the queue and
+    verify this call is equal to the expected call.
+
+    Raises:
+      UnexpectedMethodCall if this call is supposed to match an expected method
+        call and it does not.
+    """
+
+    self._params = params
+    self._named_params = named_params
+
+    if not self._replay_mode:
+      self._call_queue.append(self)
+      return self
+
+    expected_method = self._VerifyMethodCall()
+
+    if expected_method._side_effects:
+      expected_method._side_effects(*params, **named_params)
+
+    if expected_method._exception:
+      raise expected_method._exception
+
+    return expected_method._return_value
+
+  def __getattr__(self, name):
+    """Raise an AttributeError with a helpful message."""
+
+    raise AttributeError('MockMethod has no attribute "%s". '
+        'Did you remember to put your mocks in replay mode?' % name)
+
+  def _PopNextMethod(self):
+    """Pop the next method from our call queue."""
+    try:
+      return self._call_queue.popleft()
+    except IndexError:
+      raise UnexpectedMethodCallError(self, None)
+
+  def _VerifyMethodCall(self):
+    """Verify the called method is expected.
+
+    This can be an ordered method, or part of an unordered set.
+
+    Returns:
+      The expected mock method.
+
+    Raises:
+      UnexpectedMethodCall if the method called was not expected.
+    """
+
+    expected = self._PopNextMethod()
+
+    # Loop here, because we might have a MethodGroup followed by another
+    # group.
+    while isinstance(expected, MethodGroup):
+      expected, method = expected.MethodCalled(self)
+      if method is not None:
+        return method
+
+    # This is a mock method, so just check equality.
+    if expected != self:
+      raise UnexpectedMethodCallError(self, expected)
+
+    return expected
+
+  def __str__(self):
+    params = ', '.join(
+        [repr(p) for p in self._params or []] +
+        ['%s=%r' % x for x in sorted((self._named_params or {}).items())])
+    desc = "%s(%s) -> %r" % (self._name, params, self._return_value)
+    return desc
+
+  def __eq__(self, rhs):
+    """Test whether this MockMethod is equivalent to another MockMethod.
+
+    Args:
+      # rhs: the right hand side of the test
+      rhs: MockMethod
+    """
+
+    return (isinstance(rhs, MockMethod) and
+            self._name == rhs._name and
+            self._params == rhs._params and
+            self._named_params == rhs._named_params)
+
+  def __ne__(self, rhs):
+    """Test whether this MockMethod is not equivalent to another MockMethod.
+
+    Args:
+      # rhs: the right hand side of the test
+      rhs: MockMethod
+    """
+
+    return not self == rhs
+
+  def GetPossibleGroup(self):
+    """Returns a possible group from the end of the call queue or None if no
+    other methods are on the stack.
+    """
+
+    # Remove this method from the tail of the queue so we can add it to a group.
+    this_method = self._call_queue.pop()
+    assert this_method == self
+
+    # Determine if the tail of the queue is a group, or just a regular ordered
+    # mock method.
+    group = None
+    try:
+      group = self._call_queue[-1]
+    except IndexError:
+      pass
+
+    return group
+
+  def _CheckAndCreateNewGroup(self, group_name, group_class):
+    """Checks if the last method (a possible group) is an instance of our
+    group_class. Adds the current method to this group or creates a new one.
+
+    Args:
+
+      group_name: the name of the group.
+      group_class: the class used to create instance of this new group
+    """
+    group = self.GetPossibleGroup()
+
+    # If this is a group, and it is the correct group, add the method.
+    if isinstance(group, group_class) and group.group_name() == group_name:
+      group.AddMethod(self)
+      return self
+
+    # Create a new group and add the method.
+    new_group = group_class(group_name)
+    new_group.AddMethod(self)
+    self._call_queue.append(new_group)
+    return self
+
+  def InAnyOrder(self, group_name="default"):
+    """Move this method into a group of unordered calls.
+
+    A group of unordered calls must be defined together, and must be executed
+    in full before the next expected method can be called.  There can be
+    multiple groups that are expected serially, if they are given
+    different group names.  The same group name can be reused if there is a
+    standard method call, or a group with a different name, spliced between
+    usages.
+
+    Args:
+      group_name: the name of the unordered group.
+
+    Returns:
+      self
+    """
+    return self._CheckAndCreateNewGroup(group_name, UnorderedGroup)
+
+  def MultipleTimes(self, group_name="default"):
+    """Move this method into group of calls which may be called multiple times.
+
+    A group of repeating calls must be defined together, and must be executed in
+    full before the next expected method can be called.
+
+    Args:
+      group_name: the name of the unordered group.
+
+    Returns:
+      self
+    """
+    return self._CheckAndCreateNewGroup(group_name, MultipleTimesGroup)
+
+  def AndReturn(self, return_value):
+    """Set the value to return when this method is called.
+
+    Args:
+      # return_value can be anything.
+    """
+
+    self._return_value = return_value
+    return return_value
+
+  def AndRaise(self, exception):
+    """Set the exception to raise when this method is called.
+
+    Args:
+      # exception: the exception to raise when this method is called.
+      exception: Exception
+    """
+
+    self._exception = exception
+
+  def WithSideEffects(self, side_effects):
+    """Set the side effects that are simulated when this method is called.
+
+    Args:
+      side_effects: A callable which modifies the parameters or other relevant
+        state which a given test case depends on.
+
+    Returns:
+      Self for chaining with AndReturn and AndRaise.
+    """
+    self._side_effects = side_effects
+    return self
+
+class Comparator:
+  """Base class for all Mox comparators.
+
+  A Comparator can be used as a parameter to a mocked method when the exact
+  value is not known.  For example, the code you are testing might build up a
+  long SQL string that is passed to your mock DAO. You're only interested that
+  the IN clause contains the proper primary keys, so you can set your mock
+  up as follows:
+
+  mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result)
+
+  Now whatever query is passed in must contain the string 'IN (1, 2, 4, 5)'.
+
+  A Comparator may replace one or more parameters, for example:
+  # return at most 10 rows
+  mock_dao.RunQuery(StrContains('SELECT'), 10)
+
+  or
+
+  # Return some non-deterministic number of rows
+  mock_dao.RunQuery(StrContains('SELECT'), IsA(int))
+  """
+
+  def equals(self, rhs):
+    """Special equals method that all comparators must implement.
+
+    Args:
+      rhs: any python object
+    """
+
+    raise NotImplementedError('method must be implemented by a subclass.')
+
+  def __eq__(self, rhs):
+    return self.equals(rhs)
+
+  def __ne__(self, rhs):
+    return not self.equals(rhs)
+
+
+class IsA(Comparator):
+  """This class wraps a basic Python type or class.  It is used to verify
+  that a parameter is of the given type or class.
+
+  Example:
+  mock_dao.Connect(IsA(DbConnectInfo))
+  """
+
+  def __init__(self, class_name):
+    """Initialize IsA
+
+    Args:
+      class_name: basic python type or a class
+    """
+
+    self._class_name = class_name
+
+  def equals(self, rhs):
+    """Check to see if the RHS is an instance of class_name.
+
+    Args:
+      # rhs: the right hand side of the test
+      rhs: object
+
+    Returns:
+      bool
+    """
+
+    try:
+      return isinstance(rhs, self._class_name)
+    except TypeError:
+      # Check raw types if there was a type error.  This is helpful for
+      # things like cStringIO.StringIO.
+      return type(rhs) == type(self._class_name)
+
+  def __repr__(self):
+    return str(self._class_name)
+
+class IsAlmost(Comparator):
+  """Comparison class used to check whether a parameter is nearly equal
+  to a given value.  Generally useful for floating point numbers.
+
+  Example mock_dao.SetTimeout((IsAlmost(3.9)))
+  """
+
+  def __init__(self, float_value, places=7):
+    """Initialize IsAlmost.
+
+    Args:
+      float_value: The value for making the comparison.
+      places: The number of decimal places to round to.
+    """
+
+    self._float_value = float_value
+    self._places = places
+
+  def equals(self, rhs):
+    """Check to see if RHS is almost equal to float_value
+
+    Args:
+      rhs: the value to compare to float_value
+
+    Returns:
+      bool
+    """
+
+    try:
+      return round(rhs-self._float_value, self._places) == 0
+    except TypeError:
+      # This is probably because either float_value or rhs is not a number.
+      return False
+
+  def __repr__(self):
+    return str(self._float_value)
+
+class StrContains(Comparator):
+  """Comparison class used to check whether a substring exists in a
+  string parameter.  This can be useful in mocking a database with SQL
+  passed in as a string parameter, for example.
+
+  Example:
+  mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result)
+  """
+
+  def __init__(self, search_string):
+    """Initialize.
+
+    Args:
+      # search_string: the string you are searching for
+      search_string: str
+    """
+
+    self._search_string = search_string
+
+  def equals(self, rhs):
+    """Check to see if the search_string is contained in the rhs string.
+
+    Args:
+      # rhs: the right hand side of the test
+      rhs: object
+
+    Returns:
+      bool
+    """
+
+    try:
+      return rhs.find(self._search_string) > -1
+    except Exception:
+      return False
+
+  def __repr__(self):
+    return '<str containing \'%s\'>' % self._search_string
+
+
+class Regex(Comparator):
+  """Checks if a string matches a regular expression.
+
+  This uses a given regular expression to determine equality.
+  """
+
+  def __init__(self, pattern, flags=0):
+    """Initialize.
+
+    Args:
+      # pattern is the regular expression to search for
+      pattern: str
+      # flags passed to re.compile function as the second argument
+      flags: int
+    """
+
+    self.regex = re.compile(pattern, flags=flags)
+
+  def equals(self, rhs):
+    """Check to see if rhs matches regular expression pattern.
+
+    Returns:
+      bool
+    """
+
+    return self.regex.search(rhs) is not None
+
+  def __repr__(self):
+    s = '<regular expression \'%s\'' % self.regex.pattern
+    if self.regex.flags:
+      s += ', flags=%d' % self.regex.flags
+    s += '>'
+    return s
+
+
+class In(Comparator):
+  """Checks whether an item (or key) is in a list (or dict) parameter.
+
+  Example:
+  mock_dao.GetUsersInfo(In('expectedUserName')).AndReturn(mock_result)
+  """
+
+  def __init__(self, key):
+    """Initialize.
+
+    Args:
+      # key is any thing that could be in a list or a key in a dict
+    """
+
+    self._key = key
+
+  def equals(self, rhs):
+    """Check to see whether key is in rhs.
+
+    Args:
+      rhs: dict
+
+    Returns:
+      bool
+    """
+
+    return self._key in rhs
+
+  def __repr__(self):
+    return '<sequence or map containing \'%s\'>' % self._key
+
+
+class ContainsKeyValue(Comparator):
+  """Checks whether a key/value pair is in a dict parameter.
+
+  Example:
+  mock_dao.UpdateUsers(ContainsKeyValue('stevepm', stevepm_user_info))
+  """
+
+  def __init__(self, key, value):
+    """Initialize.
+
+    Args:
+      # key: a key in a dict
+      # value: the corresponding value
+    """
+
+    self._key = key
+    self._value = value
+
+  def equals(self, rhs):
+    """Check whether the given key/value pair is in the rhs dict.
+
+    Returns:
+      bool
+    """
+
+    try:
+      return rhs[self._key] == self._value
+    except Exception:
+      return False
+
+  def __repr__(self):
+    return '<map containing the entry \'%s: %s\'>' % (self._key, self._value)
+
+
+class SameElementsAs(Comparator):
+  """Checks whether iterables contain the same elements (ignoring order).
+
+  Example:
+  mock_dao.ProcessUsers(SameElementsAs('stevepm', 'salomaki'))
+  """
+
+  def __init__(self, expected_seq):
+    """Initialize.
+
+    Args:
+      expected_seq: a sequence
+    """
+
+    self._expected_seq = expected_seq
+
+  def equals(self, actual_seq):
+    """Check to see whether actual_seq has same elements as expected_seq.
+
+    Args:
+      actual_seq: sequence
+
+    Returns:
+      bool
+    """
+
+    try:
+      expected = dict([(element, None) for element in self._expected_seq])
+      actual = dict([(element, None) for element in actual_seq])
+    except TypeError:
+      # Fall back to slower list-compare if any of the objects are unhashable.
+      expected = list(self._expected_seq)
+      actual = list(actual_seq)
+      expected.sort()
+      actual.sort()
+    return expected == actual
+
+  def __repr__(self):
+    return '<sequence with same elements as \'%s\'>' % self._expected_seq
+
+
+class And(Comparator):
+  """Evaluates one or more Comparators on RHS and returns an AND of the results.
+  """
+
+  def __init__(self, *args):
+    """Initialize.
+
+    Args:
+      *args: One or more Comparator
+    """
+
+    self._comparators = args
+
+  def equals(self, rhs):
+    """Checks whether all Comparators are equal to rhs.
+
+    Args:
+      # rhs: can be anything
+
+    Returns:
+      bool
+    """
+
+    for comparator in self._comparators:
+      if not comparator.equals(rhs):
+        return False
+
+    return True
+
+  def __repr__(self):
+    return '<AND %s>' % str(self._comparators)
+
+
+class Or(Comparator):
+  """Evaluates one or more Comparators on RHS and returns an OR of the results.
+  """
+
+  def __init__(self, *args):
+    """Initialize.
+
+    Args:
+      *args: One or more Mox comparators
+    """
+
+    self._comparators = args
+
+  def equals(self, rhs):
+    """Checks whether any Comparator is equal to rhs.
+
+    Args:
+      # rhs: can be anything
+
+    Returns:
+      bool
+    """
+
+    for comparator in self._comparators:
+      if comparator.equals(rhs):
+        return True
+
+    return False
+
+  def __repr__(self):
+    return '<OR %s>' % str(self._comparators)
+
+
+class Func(Comparator):
+  """Call a function that should verify the parameter passed in is correct.
+
+  You may need the ability to perform more advanced operations on the parameter
+  in order to validate it.  You can use this to have a callable validate any
+  parameter. The callable should return either True or False.
+
+
+  Example:
+
+  def myParamValidator(param):
+    # Advanced logic here
+    return True
+
+  mock_dao.DoSomething(Func(myParamValidator), true)
+  """
+
+  def __init__(self, func):
+    """Initialize.
+
+    Args:
+      func: callable that takes one parameter and returns a bool
+    """
+
+    self._func = func
+
+  def equals(self, rhs):
+    """Test whether rhs passes the function test.
+
+    rhs is passed into func.
+
+    Args:
+      rhs: any python object
+
+    Returns:
+      the result of func(rhs)
+    """
+
+    return self._func(rhs)
+
+  def __repr__(self):
+    return str(self._func)
+
+
+class IgnoreArg(Comparator):
+  """Ignore an argument.
+
+  This can be used when we don't care about an argument of a method call.
+
+  Example:
+  # Check if CastMagic is called with 3 as first arg and 'disappear' as third.
+  mymock.CastMagic(3, IgnoreArg(), 'disappear')
+  """
+
+  def equals(self, unused_rhs):
+    """Ignores arguments and returns True.
+
+    Args:
+      unused_rhs: any python object
+
+    Returns:
+      always returns True
+    """
+
+    return True
+
+  def __repr__(self):
+    return '<IgnoreArg>'
+
+
+class MethodGroup(object):
+  """Base class containing common behaviour for MethodGroups."""
+
+  def __init__(self, group_name):
+    self._group_name = group_name
+
+  def group_name(self):
+    return self._group_name
+
+  def __str__(self):
+    return '<%s "%s">' % (self.__class__.__name__, self._group_name)
+
+  def AddMethod(self, mock_method):
+    raise NotImplementedError
+
+  def MethodCalled(self, mock_method):
+    raise NotImplementedError
+
+  def IsSatisfied(self):
+    raise NotImplementedError
+
+class UnorderedGroup(MethodGroup):
+  """UnorderedGroup holds a set of method calls that may occur in any order.
+
+  This construct is helpful for non-deterministic events, such as iterating
+  over the keys of a dict.
+  """
+
+  def __init__(self, group_name):
+    super(UnorderedGroup, self).__init__(group_name)
+    self._methods = []
+
+  def AddMethod(self, mock_method):
+    """Add a method to this group.
+
+    Args:
+      mock_method: A mock method to be added to this group.
+    """
+
+    self._methods.append(mock_method)
+
+  def MethodCalled(self, mock_method):
+    """Remove a method call from the group.
+
+    If the method is not in the set, an UnexpectedMethodCallError will be
+    raised.
+
+    Args:
+      mock_method: a mock method that should be equal to a method in the group.
+
+    Returns:
+      The mock method from the group
+
+    Raises:
+      UnexpectedMethodCallError if the mock_method was not in the group.
+    """
+
+    # Check to see if this method exists, and if so, remove it from the set
+    # and return it.
+    for method in self._methods:
+      if method == mock_method:
+        # Remove the called mock_method instead of the method in the group.
+        # The called method will match any comparators when equality is checked
+        # during removal.  The method in the group could pass a comparator to
+        # another comparator during the equality check.
+        self._methods.remove(mock_method)
+
+        # If this group is not empty, put it back at the head of the queue.
+        if not self.IsSatisfied():
+          mock_method._call_queue.appendleft(self)
+
+        return self, method
+
+    raise UnexpectedMethodCallError(mock_method, self)
+
+  def IsSatisfied(self):
+    """Return True if there are not any methods in this group."""
+
+    return len(self._methods) == 0
+
+
+class MultipleTimesGroup(MethodGroup):
+  """MultipleTimesGroup holds methods that may be called any number of times.
+
+  Note: Each method must be called at least once.
+
+  This is helpful, if you don't know or care how many times a method is called.
+  """
+
+  def __init__(self, group_name):
+    super(MultipleTimesGroup, self).__init__(group_name)
+    self._methods = set()
+    self._methods_called = set()
+
+  def AddMethod(self, mock_method):
+    """Add a method to this group.
+
+    Args:
+      mock_method: A mock method to be added to this group.
+    """
+
+    self._methods.add(mock_method)
+
+  def MethodCalled(self, mock_method):
+    """Remove a method call from the group.
+
+    If the method is not in the set, an UnexpectedMethodCallError will be
+    raised.
+
+    Args:
+      mock_method: a mock method that should be equal to a method in the group.
+
+    Returns:
+      The mock method from the group
+
+    Raises:
+      UnexpectedMethodCallError if the mock_method was not in the group.
+    """
+
+    # Check to see if this method exists, and if so add it to the set of
+    # called methods.
+
+    for method in self._methods:
+      if method == mock_method:
+        self._methods_called.add(mock_method)
+        # Always put this group back on top of the queue, because we don't know
+        # when we are done.
+        mock_method._call_queue.appendleft(self)
+        return self, method
+
+    if self.IsSatisfied():
+      next_method = mock_method._PopNextMethod();
+      return next_method, None
+    else:
+      raise UnexpectedMethodCallError(mock_method, self)
+
+  def IsSatisfied(self):
+    """Return True if all methods in this group are called at least once."""
+    # NOTE(psycho): We can't use the simple set difference here because we want
+    # to match different parameters which are considered the same e.g. IsA(str)
+    # and some string. This solution is O(n^2) but n should be small.
+    tmp = self._methods.copy()
+    for called in self._methods_called:
+      for expected in tmp:
+        if called == expected:
+          tmp.remove(expected)
+          if not tmp:
+            return True
+          break
+    return False
+
+
+class MoxMetaTestBase(type):
+  """Metaclass to add mox cleanup and verification to every test.
+
+  As the mox unit testing class is being constructed (MoxTestBase or a
+  subclass), this metaclass will modify all test functions to call the
+  CleanUpMox method of the test class after they finish. This means that
+  unstubbing and verifying will happen for every test with no additional code,
+  and any failures will result in test failures as opposed to errors.
+  """
+
+  def __init__(cls, name, bases, d):
+    type.__init__(cls, name, bases, d)
+
+    # also get all the attributes from the base classes to account
+    # for a case when test class is not the immediate child of MoxTestBase
+    for base in bases:
+      for attr_name in dir(base):
+        d[attr_name] = getattr(base, attr_name)
+
+    for func_name, func in d.items():
+      if func_name.startswith('test') and callable(func):
+        setattr(cls, func_name, MoxMetaTestBase.CleanUpTest(cls, func))
+
+  @staticmethod
+  def CleanUpTest(cls, func):
+    """Adds Mox cleanup code to any MoxTestBase method.
+
+    Always unsets stubs after a test. Will verify all mocks for tests that
+    otherwise pass.
+
+    Args:
+      cls: MoxTestBase or subclass; the class whose test method we are altering.
+      func: method; the method of the MoxTestBase test class we wish to alter.
+
+    Returns:
+      The modified method.
+    """
+    def new_method(self, *args, **kwargs):
+      mox_obj = getattr(self, 'mox', None)
+      cleanup_mox = False
+      if mox_obj and isinstance(mox_obj, Mox):
+        cleanup_mox = True
+      try:
+        func(self, *args, **kwargs)
+      finally:
+        if cleanup_mox:
+          mox_obj.UnsetStubs()
+      if cleanup_mox:
+        mox_obj.VerifyAll()
+    new_method.__name__ = func.__name__
+    new_method.__doc__ = func.__doc__
+    new_method.__module__ = func.__module__
+    return new_method
+
+
+class MoxTestBase(unittest.TestCase):
+  """Convenience test class to make stubbing easier.
+
+  Sets up a "mox" attribute which is an instance of Mox - any mox tests will
+  want this. Also automatically unsets any stubs and verifies that all mock
+  methods have been called at the end of each test, eliminating boilerplate
+  code.
+  """
+
+  __metaclass__ = MoxMetaTestBase
+
+  def setUp(self):
+    self.mox = Mox()
diff --git a/python/release.sh b/python/release.sh
new file mode 100755
index 0000000..87fcf8c
--- /dev/null
+++ b/python/release.sh
@@ -0,0 +1,137 @@
+#!/bin/bash
+
+set -ex
+
+function get_source_version() {
+  grep "__version__ = '.*'" python/google/protobuf/__init__.py | sed -r "s/__version__ = '(.*)'/\1/"
+}
+
+function run_install_test() {
+  local VERSION=$1
+  local PYTHON=$2
+  local PYPI=$3
+
+  virtualenv -p `which $PYTHON` test-venv
+
+  # Intentionally put a broken protoc in the path to make sure installation
+  # doesn't require protoc installed.
+  touch test-venv/bin/protoc
+  chmod +x test-venv/bin/protoc
+
+  source test-venv/bin/activate
+  (pip install -i ${PYPI} protobuf==${VERSION} --no-cache-dir) || (retry_pip_install ${PYPI} ${VERSION})
+  deactivate
+  rm -fr test-venv
+}
+
+function retry_pip_install() {
+  local PYPI=$1
+  local VERSION=$2
+  
+  read -p "pip install failed, possibly due to delay between upload and availability on pip. Retry? [y/n]" -r
+  echo
+  if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+    exit 1
+  fi
+
+  (pip install -i ${PYPI} protobuf==${VERSION} --no-cache-dir) || (retry_pip_install ${PYPI} ${VERSION})
+}
+
+
+[ $# -lt 1 ] && {
+  echo "Usage: $0 VERSION ["
+  echo ""
+  echo "Examples:"
+  echo "  Test 3.3.0 release using version number 3.3.0.dev1:"
+  echo "    $0 3.0.0 dev1"
+  echo "  Actually release 3.3.0 to PyPI:"
+  echo "    $0 3.3.0"
+  exit 1
+}
+VERSION=$1
+DEV=$2
+
+# Make sure we are in a protobuf source tree.
+[ -f "python/google/protobuf/__init__.py" ] || {
+  echo "This script must be ran under root of protobuf source tree."
+  exit 1
+}
+
+# Make sure all files are world-readable.
+find python -type d -exec chmod a+r,a+x {} +
+find python -type f -exec chmod a+r {} +
+umask 0022
+
+# Check that the supplied version number matches what's inside the source code.
+SOURCE_VERSION=`get_source_version`
+
+[ "${VERSION}" == "${SOURCE_VERSION}" -o "${VERSION}.${DEV}" == "${SOURCE_VERSION}" ] || {
+  echo "Version number specified on the command line ${VERSION} doesn't match"
+  echo "the actual version number in the source code: ${SOURCE_VERSION}"
+  exit 1
+}
+
+TESTING_ONLY=1
+TESTING_VERSION=${VERSION}.${DEV}
+if [ -z "${DEV}" ]; then
+  read -p "You are releasing ${VERSION} to PyPI. Are you sure? [y/n]" -r
+  echo
+  if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+    exit 1
+  fi
+  TESTING_ONLY=0
+  TESTING_VERSION=${VERSION}
+else
+  # Use dev version number for testing.
+  sed -i -r "s/__version__ = '.*'/__version__ = '${VERSION}.${DEV}'/" python/google/protobuf/__init__.py
+fi
+
+# Copy LICENSE
+cp LICENSE python/LICENSE
+
+cd python
+
+# Run tests locally.
+python3 setup.py build
+python3 setup.py test
+
+# Deploy source package to testing PyPI
+python3 setup.py sdist
+twine upload --skip-existing -r testpypi -u protobuf-wheel-test dist/*
+
+# Sleep to allow time for distribution to be available on pip.
+sleep 5m
+
+# Test locally.
+run_install_test ${TESTING_VERSION} python3 https://test.pypi.org/simple
+
+# Deploy egg/wheel packages to testing PyPI and test again.
+python3 setup.py clean build bdist_wheel
+twine upload --skip-existing -r testpypi -u protobuf-wheel-test dist/*
+sleep 5m
+run_install_test ${TESTING_VERSION} python3 https://test.pypi.org/simple
+
+echo "All install tests have passed using testing PyPI."
+
+if [ $TESTING_ONLY -eq 0 ]; then
+  read -p "Publish to PyPI? [y/n]" -r
+  echo
+  if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+    exit 1
+  fi
+  echo "Publishing to PyPI..."
+  # Be sure to run build before sdist, because otherwise sdist will not include
+  # well-known types.
+  python3 setup.py clean build sdist
+  twine upload --skip-existing -u protobuf-packages dist/*
+  # Be sure to run clean before bdist_xxx, because otherwise bdist_xxx will
+  # include files you may not want in the package. E.g., if you have built
+  # and tested with --cpp_implemenation, bdist_xxx will include the _message.so
+  # file even when you no longer pass the --cpp_implemenation flag. See:
+  #   https://github.com/protocolbuffers/protobuf/issues/3042
+  python3 setup.py clean build bdist_wheel
+  twine upload --skip-existing -u protobuf-packages dist/*
+else
+  # Set the version number back (i.e., remove dev suffix).
+  sed -i -r "s/__version__ = '.*'/__version__ = '${VERSION}'/" google/protobuf/__init__.py
+fi
diff --git a/python/setup.cfg b/python/setup.cfg
new file mode 100644
index 0000000..2a9acf1
--- /dev/null
+++ b/python/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1
diff --git a/python/setup.py b/python/setup.py
new file mode 100755
index 0000000..cbb9a59
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,358 @@
+#! /usr/bin/env python
+#
+# See README for usage instructions.
+
+# pylint:disable=missing-module-docstring
+# pylint:disable=g-bad-import-order
+from distutils import util
+import fnmatch
+import glob
+import os
+import pkg_resources
+import re
+import subprocess
+import sys
+import sysconfig
+
+# pylint:disable=g-importing-member
+# pylint:disable=g-multiple-import
+
+# We must use setuptools, not distutils, because we need to use the
+# namespace_packages option for the "google" package.
+from setuptools import setup, Extension, find_packages
+
+from distutils.command.build_ext import build_ext as _build_ext
+from distutils.command.build_py import build_py as _build_py
+from distutils.command.clean import clean as _clean
+from distutils.spawn import find_executable
+
+# Find the Protocol Compiler.
+if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
+  protoc = os.environ['PROTOC']
+elif os.path.exists('../src/protoc'):
+  protoc = '../src/protoc'
+elif os.path.exists('../src/protoc.exe'):
+  protoc = '../src/protoc.exe'
+elif os.path.exists('../vsprojects/Debug/protoc.exe'):
+  protoc = '../vsprojects/Debug/protoc.exe'
+elif os.path.exists('../vsprojects/Release/protoc.exe'):
+  protoc = '../vsprojects/Release/protoc.exe'
+else:
+  protoc = find_executable('protoc')
+
+
+def GetVersion():
+  """Reads and returns the version from google/protobuf/__init__.py.
+
+  Do not import google.protobuf.__init__ directly, because an installed
+  protobuf library may be loaded instead.
+
+  Returns:
+      The version.
+  """
+
+  with open(os.path.join('google', 'protobuf', '__init__.py')) as version_file:
+    exec(version_file.read(), globals())  # pylint:disable=exec-used
+    return __version__  # pylint:disable=undefined-variable
+
+
+def GenProto(source, require=True):
+  """Generates a _pb2.py from the given .proto file.
+
+  Does nothing if the output already exists and is newer than the input.
+
+  Args:
+      source: the .proto file path.
+      require: if True, exit immediately when a path is not found.
+  """
+
+  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)
+
+    if not os.path.exists(source):
+      sys.stderr.write("Can't find required file: %s\n" % source)
+      sys.exit(-1)
+
+    if protoc is None:
+      sys.stderr.write(
+          'protoc is not installed nor found in ../src.  Please compile it '
+          'or install the binary package.\n')
+      sys.exit(-1)
+
+    protoc_command = [protoc, '-I../src', '-I.', '--python_out=.', source]
+    if subprocess.call(protoc_command) != 0:
+      sys.exit(-1)
+
+
+def GenerateUnittestProtos():
+  """Generates protobuf code for unittests."""
+  GenProto('../src/google/protobuf/any_test.proto', False)
+  GenProto('../src/google/protobuf/map_proto2_unittest.proto', False)
+  GenProto('../src/google/protobuf/map_unittest.proto', False)
+  GenProto('../src/google/protobuf/test_messages_proto3.proto', False)
+  GenProto('../src/google/protobuf/test_messages_proto2.proto', False)
+  GenProto('../src/google/protobuf/unittest_arena.proto', False)
+  GenProto('../src/google/protobuf/unittest.proto', False)
+  GenProto('../src/google/protobuf/unittest_custom_options.proto', False)
+  GenProto('../src/google/protobuf/unittest_import.proto', False)
+  GenProto('../src/google/protobuf/unittest_import_public.proto', False)
+  GenProto('../src/google/protobuf/unittest_mset.proto', False)
+  GenProto('../src/google/protobuf/unittest_mset_wire_format.proto', False)
+  GenProto('../src/google/protobuf/unittest_no_generic_services.proto', False)
+  GenProto('../src/google/protobuf/unittest_proto3_arena.proto', False)
+  GenProto('../src/google/protobuf/util/json_format.proto', False)
+  GenProto('../src/google/protobuf/util/json_format_proto3.proto', False)
+  GenProto('google/protobuf/internal/any_test.proto', False)
+  GenProto('google/protobuf/internal/descriptor_pool_test1.proto', False)
+  GenProto('google/protobuf/internal/descriptor_pool_test2.proto', False)
+  GenProto('google/protobuf/internal/factory_test1.proto', False)
+  GenProto('google/protobuf/internal/factory_test2.proto', False)
+  GenProto('google/protobuf/internal/file_options_test.proto', False)
+  GenProto('google/protobuf/internal/import_test_package/import_public.proto',
+           False)
+  GenProto(
+      'google/protobuf/internal/import_test_package/import_public_nested.proto',
+      False)
+  GenProto('google/protobuf/internal/import_test_package/inner.proto', False)
+  GenProto('google/protobuf/internal/import_test_package/outer.proto', False)
+  GenProto('google/protobuf/internal/missing_enum_values.proto', False)
+  GenProto('google/protobuf/internal/message_set_extensions.proto', False)
+  GenProto('google/protobuf/internal/more_extensions.proto', False)
+  GenProto('google/protobuf/internal/more_extensions_dynamic.proto', False)
+  GenProto('google/protobuf/internal/more_messages.proto', False)
+  GenProto('google/protobuf/internal/no_package.proto', False)
+  GenProto('google/protobuf/internal/packed_field_test.proto', False)
+  GenProto('google/protobuf/internal/test_bad_identifiers.proto', False)
+  GenProto('google/protobuf/internal/test_proto3_optional.proto', False)
+  GenProto('google/protobuf/pyext/python.proto', False)
+
+
+class CleanCmd(_clean):
+  """Custom clean command for building the protobuf extension."""
+
+  def run(self):
+    # Delete generated files in the code tree.
+    for (dirpath, unused_dirnames, filenames) in os.walk('.'):
+      for filename in filenames:
+        filepath = os.path.join(dirpath, filename)
+        if (filepath.endswith('_pb2.py') or filepath.endswith('.pyc') or
+            filepath.endswith('.so') or filepath.endswith('.o')):
+          os.remove(filepath)
+    # _clean is an old-style class, so super() doesn't work.
+    _clean.run(self)
+
+
+class BuildPyCmd(_build_py):
+  """Custom build_py command for building the protobuf runtime."""
+
+  def run(self):
+    # Generate necessary .proto file if it doesn't exist.
+    GenProto('../src/google/protobuf/descriptor.proto')
+    GenProto('../src/google/protobuf/compiler/plugin.proto')
+    GenProto('../src/google/protobuf/any.proto')
+    GenProto('../src/google/protobuf/api.proto')
+    GenProto('../src/google/protobuf/duration.proto')
+    GenProto('../src/google/protobuf/empty.proto')
+    GenProto('../src/google/protobuf/field_mask.proto')
+    GenProto('../src/google/protobuf/source_context.proto')
+    GenProto('../src/google/protobuf/struct.proto')
+    GenProto('../src/google/protobuf/timestamp.proto')
+    GenProto('../src/google/protobuf/type.proto')
+    GenProto('../src/google/protobuf/wrappers.proto')
+    GenerateUnittestProtos()
+
+    # _build_py is an old-style class, so super() doesn't work.
+    _build_py.run(self)
+
+  def find_package_modules(self, package, package_dir):
+    exclude = (
+        '*test*',
+        'google/protobuf/internal/*_pb2.py',
+        'google/protobuf/internal/_parameterized.py',
+        'google/protobuf/pyext/python_pb2.py',
+    )
+    modules = _build_py.find_package_modules(self, package, package_dir)
+    return [(pkg, mod, fil) for (pkg, mod, fil) in modules
+            if not any(fnmatch.fnmatchcase(fil, pat=pat) for pat in exclude)]
+
+
+class BuildExtCmd(_build_ext):
+  """Command class for building the protobuf Python extension."""
+
+  def get_ext_filename(self, ext_name):
+    # since python3.5, python extensions' shared libraries use a suffix that
+    # corresponds to the value of sysconfig.get_config_var('EXT_SUFFIX') and
+    # contains info about the architecture the library targets.  E.g. on x64
+    # linux the suffix is ".cpython-XYZ-x86_64-linux-gnu.so" When
+    # crosscompiling python wheels, we need to be able to override this
+    # suffix so that the resulting file name matches the target architecture
+    # and we end up with a well-formed wheel.
+    filename = _build_ext.get_ext_filename(self, ext_name)
+    orig_ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
+    new_ext_suffix = os.getenv('PROTOCOL_BUFFERS_OVERRIDE_EXT_SUFFIX')
+    if new_ext_suffix and filename.endswith(orig_ext_suffix):
+      filename = filename[:-len(orig_ext_suffix)] + new_ext_suffix
+    return filename
+
+
+class TestConformanceCmd(_build_py):
+  target = 'test_python'
+
+  def run(self):
+    # 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' % (TestConformanceCmd.target)
+    subprocess.check_call(cmd, shell=True)
+
+
+def GetOptionFromArgv(option_str):
+  if option_str in sys.argv:
+    sys.argv.remove(option_str)
+    return True
+  return False
+
+
+if __name__ == '__main__':
+  ext_module_list = []
+  warnings_as_errors = '--warnings_as_errors'
+  if GetOptionFromArgv('--cpp_implementation'):
+    # Link libprotobuf.a and libprotobuf-lite.a statically with the
+    # extension. Note that those libraries have to be compiled with
+    # -fPIC for this to work.
+    compile_static_ext = GetOptionFromArgv('--compile_static_extension')
+    libraries = ['protobuf']
+    extra_objects = None
+    if compile_static_ext:
+      libraries = None
+      extra_objects = ['../src/.libs/libprotobuf.a',
+                       '../src/.libs/libprotobuf-lite.a']
+    TestConformanceCmd.target = 'test_python_cpp'
+
+    extra_compile_args = []
+
+    message_extra_link_args = None
+    api_implementation_link_args = None
+    if 'darwin' in sys.platform:
+      if sys.version_info[0] == 2:
+        message_init_symbol = 'init_message'
+        api_implementation_init_symbol = 'init_api_implementation'
+      else:
+        message_init_symbol = 'PyInit__message'
+        api_implementation_init_symbol = 'PyInit__api_implementation'
+      message_extra_link_args = [
+          '-Wl,-exported_symbol,_%s' % message_init_symbol
+      ]
+      api_implementation_link_args = [
+          '-Wl,-exported_symbol,_%s' % api_implementation_init_symbol
+      ]
+
+    if sys.platform != 'win32':
+      extra_compile_args.append('-Wno-write-strings')
+      extra_compile_args.append('-Wno-invalid-offsetof')
+      extra_compile_args.append('-Wno-sign-compare')
+      extra_compile_args.append('-Wno-unused-variable')
+      extra_compile_args.append('-std=c++11')
+
+    if sys.platform == 'darwin':
+      extra_compile_args.append('-Wno-shorten-64-to-32')
+      extra_compile_args.append('-Wno-deprecated-register')
+
+    # https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
+    # C++ projects must now migrate to libc++ and are recommended to set a
+    # deployment target of macOS 10.9 or later, or iOS 7 or later.
+    if sys.platform == 'darwin':
+      mac_target = str(sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET'))
+      if mac_target and (pkg_resources.parse_version(mac_target) <
+                         pkg_resources.parse_version('10.9.0')):
+        os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.9'
+        os.environ['_PYTHON_HOST_PLATFORM'] = re.sub(
+            r'macosx-[0-9]+\.[0-9]+-(.+)', r'macosx-10.9-\1',
+            util.get_platform())
+
+    # https://github.com/Theano/Theano/issues/4926
+    if sys.platform == 'win32':
+      extra_compile_args.append('-D_hypot=hypot')
+
+    # https://github.com/tpaviot/pythonocc-core/issues/48
+    if sys.platform == 'win32' and  '64 bit' in sys.version:
+      extra_compile_args.append('-DMS_WIN64')
+
+    # MSVS default is dymanic
+    if sys.platform == 'win32':
+      extra_compile_args.append('/MT')
+
+    if 'clang' in os.popen('$CC --version 2> /dev/null').read():
+      extra_compile_args.append('-Wno-shorten-64-to-32')
+
+    if warnings_as_errors in sys.argv:
+      extra_compile_args.append('-Werror')
+      sys.argv.remove(warnings_as_errors)
+
+    # C++ implementation extension
+    ext_module_list.extend([
+        Extension(
+            'google.protobuf.pyext._message',
+            glob.glob('google/protobuf/pyext/*.cc'),
+            include_dirs=['.', '../src'],
+            libraries=libraries,
+            extra_objects=extra_objects,
+            extra_link_args=message_extra_link_args,
+            library_dirs=['../src/.libs'],
+            extra_compile_args=extra_compile_args,
+        ),
+        Extension(
+            'google.protobuf.internal._api_implementation',
+            glob.glob('google/protobuf/internal/api_implementation.cc'),
+            extra_compile_args=(extra_compile_args +
+                                ['-DPYTHON_PROTO2_CPP_IMPL_V2']),
+            extra_link_args=api_implementation_link_args,
+        ),
+    ])
+    os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
+
+  # Keep this list of dependencies in sync with tox.ini.
+  install_requires = []
+
+  setup(
+      name='protobuf',
+      version=GetVersion(),
+      description='Protocol Buffers',
+      download_url='https://github.com/protocolbuffers/protobuf/releases',
+      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='BSD-3-Clause',
+      classifiers=[
+          'Programming Language :: Python',
+          'Programming Language :: Python :: 3',
+          'Programming Language :: Python :: 3.7',
+          'Programming Language :: Python :: 3.8',
+          'Programming Language :: Python :: 3.9',
+          'Programming Language :: Python :: 3.10',
+      ],
+      namespace_packages=['google'],
+      packages=find_packages(
+          exclude=[
+              'import_test_package',
+              'protobuf_distutils',
+          ],),
+      test_suite='google.protobuf.internal',
+      cmdclass={
+          'clean': CleanCmd,
+          'build_py': BuildPyCmd,
+          'build_ext': BuildExtCmd,
+          'test_conformance': TestConformanceCmd,
+      },
+      install_requires=install_requires,
+      ext_modules=ext_module_list,
+      python_requires='>=3.7',
+  )
diff --git a/python/stubout.py b/python/stubout.py
new file mode 100755
index 0000000..ba39104
--- /dev/null
+++ b/python/stubout.py
@@ -0,0 +1,143 @@
+#!/usr/bin/python2.4
+#
+# Copyright 2008 Google Inc.
+#
+# 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.
+
+# This file is used for testing.  The original is at:
+#   http://code.google.com/p/pymox/
+
+import inspect
+
+
+class StubOutForTesting:
+  """Sample Usage:
+     You want os.path.exists() to always return true during testing.
+
+     stubs = StubOutForTesting()
+     stubs.Set(os.path, 'exists', lambda x: 1)
+       ...
+     stubs.UnsetAll()
+
+     The above changes os.path.exists into a lambda that returns 1.  Once
+     the ... part of the code finishes, the UnsetAll() looks up the old value
+     of os.path.exists and restores it.
+
+  """
+  def __init__(self):
+    self.cache = []
+    self.stubs = []
+
+  def __del__(self):
+    self.SmartUnsetAll()
+    self.UnsetAll()
+
+  def SmartSet(self, obj, attr_name, new_attr):
+    """Replace obj.attr_name with new_attr. This method is smart and works
+       at the module, class, and instance level while preserving proper
+       inheritance. It will not stub out C types however unless that has been
+       explicitly allowed by the type.
+
+       This method supports the case where attr_name is a staticmethod or a
+       classmethod of obj.
+
+       Notes:
+      - If obj is an instance, then it is its class that will actually be
+        stubbed. Note that the method Set() does not do that: if obj is
+        an instance, it (and not its class) will be stubbed.
+      - The stubbing is using the builtin getattr and setattr. So, the __get__
+        and __set__ will be called when stubbing (TODO: A better idea would
+        probably be to manipulate obj.__dict__ instead of getattr() and
+        setattr()).
+
+       Raises AttributeError if the attribute cannot be found.
+    """
+    if (inspect.ismodule(obj) or
+        (not inspect.isclass(obj) and obj.__dict__.has_key(attr_name))):
+      orig_obj = obj
+      orig_attr = getattr(obj, attr_name)
+
+    else:
+      if not inspect.isclass(obj):
+        mro = list(inspect.getmro(obj.__class__))
+      else:
+        mro = list(inspect.getmro(obj))
+
+      mro.reverse()
+
+      orig_attr = None
+
+      for cls in mro:
+        try:
+          orig_obj = cls
+          orig_attr = getattr(obj, attr_name)
+        except AttributeError:
+          continue
+
+    if orig_attr is None:
+      raise AttributeError("Attribute not found.")
+
+    # Calling getattr() on a staticmethod transforms it to a 'normal' function.
+    # We need to ensure that we put it back as a staticmethod.
+    old_attribute = obj.__dict__.get(attr_name)
+    if old_attribute is not None and isinstance(old_attribute, staticmethod):
+      orig_attr = staticmethod(orig_attr)
+
+    self.stubs.append((orig_obj, attr_name, orig_attr))
+    setattr(orig_obj, attr_name, new_attr)
+
+  def SmartUnsetAll(self):
+    """Reverses all the SmartSet() calls, restoring things to their original
+    definition.  Its okay to call SmartUnsetAll() repeatedly, as later calls
+    have no effect if no SmartSet() calls have been made.
+
+    """
+    self.stubs.reverse()
+
+    for args in self.stubs:
+      setattr(*args)
+
+    self.stubs = []
+
+  def Set(self, parent, child_name, new_child):
+    """Replace child_name's old definition with new_child, in the context
+    of the given parent.  The parent could be a module when the child is a
+    function at module scope.  Or the parent could be a class when a class'
+    method is being replaced.  The named child is set to new_child, while
+    the prior definition is saved away for later, when UnsetAll() is called.
+
+    This method supports the case where child_name is a staticmethod or a
+    classmethod of parent.
+    """
+    old_child = getattr(parent, child_name)
+
+    old_attribute = parent.__dict__.get(child_name)
+    if old_attribute is not None and isinstance(old_attribute, staticmethod):
+      old_child = staticmethod(old_child)
+
+    self.cache.append((parent, old_child, child_name))
+    setattr(parent, child_name, new_child)
+
+  def UnsetAll(self):
+    """Reverses all the Set() calls, restoring things to their original
+    definition.  Its okay to call UnsetAll() repeatedly, as later calls have
+    no effect if no Set() calls have been made.
+
+    """
+    # Undo calls to Set() in reverse order, in case Set() was called on the
+    # same arguments repeatedly (want the original call to be last one undone)
+    self.cache.reverse()
+
+    for (parent, old_child, child_name) in self.cache:
+      setattr(parent, child_name, old_child)
+    self.cache = []
diff --git a/python/tox.ini b/python/tox.ini
new file mode 100644
index 0000000..b923a4a
--- /dev/null
+++ b/python/tox.ini
@@ -0,0 +1,21 @@
+[tox]
+envlist =
+    py{37,38,39,310}-{cpp,python}
+
+[testenv]
+usedevelop=true
+passenv =
+    CC KOKORO_BUILD_ID KOKORO_BUILD_NUMBER
+setenv =
+    cpp: LD_LIBRARY_PATH={toxinidir}/../src/.libs
+    cpp: DYLD_LIBRARY_PATH={toxinidir}/../src/.libs
+    cpp: PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+    python: PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
+commands =
+    python setup.py -q build_py
+    python: python setup.py -q build
+    py{37,38,39,310}-cpp: python setup.py -q build --cpp_implementation --warnings_as_errors --compile_static_extension
+    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
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..f7f091f
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,12 @@
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+https://developers.google.com/protocol-buffers/
+This package contains a precompiled binary version of the protocol buffer
+compiler (protoc). This binary is intended for users who want to use Protocol
+Buffers in languages other than C++ but do not want to compile protoc
+themselves. To install, simply place this binary somewhere in your PATH.
+If you intend to use the included well known types then don't forget to
+copy the contents of the 'include' directory somewhere as well, for example
+into '/usr/local/include/'.
+Please refer to our official github site for more installation instructions:
+  https://github.com/protocolbuffers/protobuf
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..7a612db
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,918 @@
+## Process this file with automake to produce Makefile.in
+
+if HAVE_ZLIB
+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
+
+PROTOBUF_VERSION = 32:9:0
+
+if GCC
+# Turn on all warnings except for sign comparison (we ignore sign comparison
+# in Google so our code base have tons of such warnings).
+NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wno-sign-compare
+else
+NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF)
+endif
+
+AM_CXXFLAGS = $(NO_OPT_CXXFLAGS) $(PROTOBUF_OPT_FLAG)
+
+AM_LDFLAGS = $(PTHREAD_CFLAGS) ${LIBLOG_LIBS}
+
+# If I say "dist_include_DATA", automake complains that $(includedir) is not
+# a "legitimate" directory for DATA.  Screw you, automake.
+protodir = $(includedir)
+
+# If you are adding new files here, also remember to change the build files for
+# all other languages, //protoc-artifacts/build-zip.sh and run
+# //update_file_list.sh for bazel.
+nobase_dist_proto_DATA =                \
+  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
+
+# Not sure why these don't get cleaned automatically.
+clean-local:
+	rm -f *.loT
+
+CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
+             testzip.jar testzip.list testzip.proto testzip.zip \
+             no_warning_test.cc
+
+MAINTAINERCLEANFILES =   \
+  Makefile.in
+
+nobase_include_HEADERS =                                         \
+  google/protobuf/any.h                                          \
+  google/protobuf/any.pb.h                                       \
+  google/protobuf/api.pb.h                                       \
+  google/protobuf/arena.h                                        \
+  google/protobuf/arena_impl.h                                   \
+  google/protobuf/arenastring.h                                  \
+  google/protobuf/arenaz_sampler.h                               \
+  google/protobuf/compiler/code_generator.h                      \
+  google/protobuf/compiler/command_line_interface.h              \
+  google/protobuf/compiler/cpp/cpp_generator.h                   \
+  google/protobuf/compiler/cpp/file.h                            \
+  google/protobuf/compiler/cpp/generator.h                       \
+  google/protobuf/compiler/cpp/helpers.h                         \
+  google/protobuf/compiler/cpp/names.h                           \
+  google/protobuf/compiler/csharp/csharp_doc_comment.h           \
+  google/protobuf/compiler/csharp/csharp_generator.h             \
+  google/protobuf/compiler/csharp/csharp_names.h                 \
+  google/protobuf/compiler/csharp/csharp_options.h               \
+  google/protobuf/compiler/importer.h                            \
+  google/protobuf/compiler/java/generator.h                      \
+  google/protobuf/compiler/java/java_generator.h                 \
+  google/protobuf/compiler/java/kotlin_generator.h               \
+  google/protobuf/compiler/java/names.h                          \
+  google/protobuf/compiler/objectivec/objectivec_generator.h     \
+  google/protobuf/compiler/objectivec/objectivec_helpers.h       \
+  google/protobuf/compiler/parser.h                              \
+  google/protobuf/compiler/php/php_generator.h                   \
+  google/protobuf/compiler/plugin.h                              \
+  google/protobuf/compiler/plugin.pb.h                           \
+  google/protobuf/compiler/python/generator.h                    \
+  google/protobuf/compiler/python/pyi_generator.h                \
+  google/protobuf/compiler/python/python_generator.h             \
+  google/protobuf/compiler/ruby/ruby_generator.h                 \
+  google/protobuf/descriptor.h                                   \
+  google/protobuf/descriptor.pb.h                                \
+  google/protobuf/descriptor_database.h                          \
+  google/protobuf/duration.pb.h                                  \
+  google/protobuf/dynamic_message.h                              \
+  google/protobuf/empty.pb.h                                     \
+  google/protobuf/endian.h                                       \
+  google/protobuf/explicitly_constructed.h                       \
+  google/protobuf/extension_set.h                                \
+  google/protobuf/extension_set_inl.h                            \
+  google/protobuf/field_access_listener.h                        \
+  google/protobuf/field_mask.pb.h                                \
+  google/protobuf/generated_enum_reflection.h                    \
+  google/protobuf/generated_enum_util.h                          \
+  google/protobuf/generated_message_bases.h                      \
+  google/protobuf/generated_message_reflection.h                 \
+  google/protobuf/generated_message_tctable_decl.h               \
+  google/protobuf/generated_message_tctable_impl.h               \
+  google/protobuf/generated_message_util.h                       \
+  google/protobuf/has_bits.h                                     \
+  google/protobuf/implicit_weak_message.h                        \
+  google/protobuf/inlined_string_field.h                         \
+  google/protobuf/io/coded_stream.h                              \
+  $(GZHEADERS)                                                   \
+  google/protobuf/io/io_win32.h                                  \
+  google/protobuf/io/printer.h                                   \
+  google/protobuf/io/strtod.h                                    \
+  google/protobuf/io/tokenizer.h                                 \
+  google/protobuf/io/zero_copy_stream.h                          \
+  google/protobuf/io/zero_copy_stream_impl.h                     \
+  google/protobuf/io/zero_copy_stream_impl_lite.h                \
+  google/protobuf/map.h                                          \
+  google/protobuf/map_entry.h                                    \
+  google/protobuf/map_entry_lite.h                               \
+  google/protobuf/map_field.h                                    \
+  google/protobuf/map_field_inl.h                                \
+  google/protobuf/map_field_lite.h                               \
+  google/protobuf/map_type_handler.h                             \
+  google/protobuf/message.h                                      \
+  google/protobuf/message_lite.h                                 \
+  google/protobuf/metadata.h                                     \
+  google/protobuf/metadata_lite.h                                \
+  google/protobuf/parse_context.h                                \
+  google/protobuf/port.h                                         \
+  google/protobuf/port_def.inc                                   \
+  google/protobuf/port_undef.inc                                 \
+  google/protobuf/reflection.h                                   \
+  google/protobuf/reflection_internal.h                          \
+  google/protobuf/reflection_ops.h                               \
+  google/protobuf/repeated_field.h                               \
+  google/protobuf/repeated_ptr_field.h                           \
+  google/protobuf/service.h                                      \
+  google/protobuf/source_context.pb.h                            \
+  google/protobuf/struct.pb.h                                    \
+  google/protobuf/stubs/bytestream.h                             \
+  google/protobuf/stubs/callback.h                               \
+  google/protobuf/stubs/casts.h                                  \
+  google/protobuf/stubs/common.h                                 \
+  google/protobuf/stubs/hash.h                                   \
+  google/protobuf/stubs/logging.h                                \
+  google/protobuf/stubs/macros.h                                 \
+  google/protobuf/stubs/map_util.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/status.h                                 \
+  google/protobuf/stubs/stl_util.h                               \
+  google/protobuf/stubs/stringpiece.h                            \
+  google/protobuf/stubs/strutil.h                                \
+  google/protobuf/stubs/template_util.h                          \
+  google/protobuf/text_format.h                                  \
+  google/protobuf/timestamp.pb.h                                 \
+  google/protobuf/type.pb.h                                      \
+  google/protobuf/unknown_field_set.h                            \
+  google/protobuf/util/delimited_message_util.h                  \
+  google/protobuf/util/field_comparator.h                        \
+  google/protobuf/util/field_mask_util.h                         \
+  google/protobuf/util/json_util.h                               \
+  google/protobuf/util/message_differencer.h                     \
+  google/protobuf/util/time_util.h                               \
+  google/protobuf/util/type_resolver.h                           \
+  google/protobuf/util/type_resolver_util.h                      \
+  google/protobuf/wire_format.h                                  \
+  google/protobuf/wire_format_lite.h                             \
+  google/protobuf/wrappers.pb.h
+
+lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
+
+libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS) $(LIBATOMIC_LIBS)
+libprotobuf_lite_la_LDFLAGS = -version-info $(PROTOBUF_VERSION) -export-dynamic -no-undefined
+if HAVE_LD_VERSION_SCRIPT
+libprotobuf_lite_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotobuf-lite.map
+EXTRA_libprotobuf_lite_la_DEPENDENCIES = libprotobuf-lite.map
+endif
+libprotobuf_lite_la_SOURCES =                                  \
+  google/protobuf/any_lite.cc                                  \
+  google/protobuf/arena.cc                                     \
+  google/protobuf/arenastring.cc                               \
+  google/protobuf/arenaz_sampler.cc                            \
+  google/protobuf/extension_set.cc                             \
+  google/protobuf/generated_enum_util.cc                       \
+  google/protobuf/generated_message_tctable_lite.cc            \
+  google/protobuf/generated_message_util.cc                    \
+  google/protobuf/implicit_weak_message.cc                     \
+  google/protobuf/inlined_string_field.cc                      \
+  google/protobuf/io/coded_stream.cc                           \
+  google/protobuf/io/io_win32.cc                               \
+  google/protobuf/io/strtod.cc                                 \
+  google/protobuf/io/zero_copy_stream.cc                       \
+  google/protobuf/io/zero_copy_stream_impl.cc                  \
+  google/protobuf/io/zero_copy_stream_impl_lite.cc             \
+  google/protobuf/map.cc                                       \
+  google/protobuf/message_lite.cc                              \
+  google/protobuf/parse_context.cc                             \
+  google/protobuf/repeated_field.cc                            \
+  google/protobuf/repeated_ptr_field.cc                        \
+  google/protobuf/string_member_robber.h                       \
+  google/protobuf/stubs/bytestream.cc                          \
+  google/protobuf/stubs/common.cc                              \
+  google/protobuf/stubs/int128.cc                              \
+  google/protobuf/stubs/int128.h                               \
+  google/protobuf/stubs/mathutil.h                             \
+  google/protobuf/stubs/status.cc                              \
+  google/protobuf/stubs/status_macros.h                        \
+  google/protobuf/stubs/statusor.cc                            \
+  google/protobuf/stubs/statusor.h                             \
+  google/protobuf/stubs/stringpiece.cc                         \
+  google/protobuf/stubs/stringprintf.cc                        \
+  google/protobuf/stubs/stringprintf.h                         \
+  google/protobuf/stubs/structurally_valid.cc                  \
+  google/protobuf/stubs/strutil.cc                             \
+  google/protobuf/stubs/time.cc                                \
+  google/protobuf/stubs/time.h                                 \
+  google/protobuf/wire_format_lite.cc
+
+libprotobuf_la_LIBADD = $(PTHREAD_LIBS) $(LIBATOMIC_LIBS)
+libprotobuf_la_LDFLAGS = -version-info $(PROTOBUF_VERSION) -export-dynamic -no-undefined
+if HAVE_LD_VERSION_SCRIPT
+libprotobuf_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotobuf.map
+EXTRA_libprotobuf_la_DEPENDENCIES = libprotobuf.map
+endif
+libprotobuf_la_SOURCES =                                       \
+  $(libprotobuf_lite_la_SOURCES)                               \
+  google/protobuf/any.cc                                       \
+  google/protobuf/any.pb.cc                                    \
+  google/protobuf/api.pb.cc                                    \
+  google/protobuf/compiler/importer.cc                         \
+  google/protobuf/compiler/parser.cc                           \
+  google/protobuf/descriptor.cc                                \
+  google/protobuf/descriptor.pb.cc                             \
+  google/protobuf/descriptor_database.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_bases.cc                   \
+  google/protobuf/generated_message_reflection.cc              \
+  google/protobuf/generated_message_tctable_full.cc            \
+  google/protobuf/io/gzip_stream.cc                            \
+  google/protobuf/io/printer.cc                                \
+  google/protobuf/io/tokenizer.cc                              \
+  google/protobuf/map_field.cc                                 \
+  google/protobuf/message.cc                                   \
+  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/util/delimited_message_util.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/proto_writer.cc                \
+  google/protobuf/util/internal/proto_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/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.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                   \
+  google/protobuf/wire_format.cc                               \
+  google/protobuf/wrappers.pb.cc
+
+nodist_libprotobuf_la_SOURCES = $(nodist_libprotobuf_lite_la_SOURCES)
+
+libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
+libprotoc_la_LDFLAGS = -version-info $(PROTOBUF_VERSION) -export-dynamic -no-undefined
+if HAVE_LD_VERSION_SCRIPT
+libprotoc_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotoc.map
+EXTRA_libprotoc_la_DEPENDENCIES = libprotoc.map
+endif
+libprotoc_la_SOURCES =                                         \
+  google/protobuf/compiler/code_generator.cc                   \
+  google/protobuf/compiler/command_line_interface.cc           \
+  google/protobuf/compiler/cpp/enum.cc                         \
+  google/protobuf/compiler/cpp/enum.h                          \
+  google/protobuf/compiler/cpp/enum_field.cc                   \
+  google/protobuf/compiler/cpp/enum_field.h                    \
+  google/protobuf/compiler/cpp/extension.cc                    \
+  google/protobuf/compiler/cpp/extension.h                     \
+  google/protobuf/compiler/cpp/field.cc                        \
+  google/protobuf/compiler/cpp/field.h                         \
+  google/protobuf/compiler/cpp/file.cc                         \
+  google/protobuf/compiler/cpp/generator.cc                    \
+  google/protobuf/compiler/cpp/helpers.cc                      \
+  google/protobuf/compiler/cpp/map_field.cc                    \
+  google/protobuf/compiler/cpp/map_field.h                     \
+  google/protobuf/compiler/cpp/message.cc                      \
+  google/protobuf/compiler/cpp/message.h                       \
+  google/protobuf/compiler/cpp/message_field.cc                \
+  google/protobuf/compiler/cpp/message_field.h                 \
+  google/protobuf/compiler/cpp/message_layout_helper.h         \
+  google/protobuf/compiler/cpp/options.h                       \
+  google/protobuf/compiler/cpp/padding_optimizer.cc            \
+  google/protobuf/compiler/cpp/padding_optimizer.h             \
+  google/protobuf/compiler/cpp/parse_function_generator.cc     \
+  google/protobuf/compiler/cpp/parse_function_generator.h      \
+  google/protobuf/compiler/cpp/primitive_field.cc              \
+  google/protobuf/compiler/cpp/primitive_field.h               \
+  google/protobuf/compiler/cpp/service.cc                      \
+  google/protobuf/compiler/cpp/service.h                       \
+  google/protobuf/compiler/cpp/string_field.cc                 \
+  google/protobuf/compiler/cpp/string_field.h                  \
+  google/protobuf/compiler/csharp/csharp_doc_comment.cc        \
+  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       \
+  google/protobuf/compiler/java/context.cc                     \
+  google/protobuf/compiler/java/context.h                      \
+  google/protobuf/compiler/java/doc_comment.cc                 \
+  google/protobuf/compiler/java/doc_comment.h                  \
+  google/protobuf/compiler/java/enum.cc                        \
+  google/protobuf/compiler/java/enum.h                         \
+  google/protobuf/compiler/java/enum_field.cc                  \
+  google/protobuf/compiler/java/enum_field.h                   \
+  google/protobuf/compiler/java/enum_field_lite.cc             \
+  google/protobuf/compiler/java/enum_field_lite.h              \
+  google/protobuf/compiler/java/enum_lite.cc                   \
+  google/protobuf/compiler/java/enum_lite.h                    \
+  google/protobuf/compiler/java/extension.cc                   \
+  google/protobuf/compiler/java/extension.h                    \
+  google/protobuf/compiler/java/extension_lite.cc              \
+  google/protobuf/compiler/java/extension_lite.h               \
+  google/protobuf/compiler/java/field.cc                       \
+  google/protobuf/compiler/java/field.h                        \
+  google/protobuf/compiler/java/file.cc                        \
+  google/protobuf/compiler/java/file.h                         \
+  google/protobuf/compiler/java/generator.cc                   \
+  google/protobuf/compiler/java/generator_factory.cc           \
+  google/protobuf/compiler/java/generator_factory.h            \
+  google/protobuf/compiler/java/helpers.cc                     \
+  google/protobuf/compiler/java/helpers.h                      \
+  google/protobuf/compiler/java/kotlin_generator.cc            \
+  google/protobuf/compiler/java/map_field.cc                   \
+  google/protobuf/compiler/java/map_field.h                    \
+  google/protobuf/compiler/java/map_field_lite.cc              \
+  google/protobuf/compiler/java/map_field_lite.h               \
+  google/protobuf/compiler/java/message.cc                     \
+  google/protobuf/compiler/java/message.h                      \
+  google/protobuf/compiler/java/message_builder.cc             \
+  google/protobuf/compiler/java/message_builder.h              \
+  google/protobuf/compiler/java/message_builder_lite.cc        \
+  google/protobuf/compiler/java/message_builder_lite.h         \
+  google/protobuf/compiler/java/message_field.cc               \
+  google/protobuf/compiler/java/message_field.h                \
+  google/protobuf/compiler/java/message_field_lite.cc          \
+  google/protobuf/compiler/java/message_field_lite.h           \
+  google/protobuf/compiler/java/message_lite.cc                \
+  google/protobuf/compiler/java/message_lite.h                 \
+  google/protobuf/compiler/java/name_resolver.cc               \
+  google/protobuf/compiler/java/name_resolver.h                \
+  google/protobuf/compiler/java/options.h                      \
+  google/protobuf/compiler/java/primitive_field.cc             \
+  google/protobuf/compiler/java/primitive_field.h              \
+  google/protobuf/compiler/java/primitive_field_lite.cc        \
+  google/protobuf/compiler/java/primitive_field_lite.h         \
+  google/protobuf/compiler/java/service.cc                     \
+  google/protobuf/compiler/java/service.h                      \
+  google/protobuf/compiler/java/shared_code_generator.cc       \
+  google/protobuf/compiler/java/shared_code_generator.h        \
+  google/protobuf/compiler/java/string_field.cc                \
+  google/protobuf/compiler/java/string_field.h                 \
+  google/protobuf/compiler/java/string_field_lite.cc           \
+  google/protobuf/compiler/java/string_field_lite.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_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_nsobject_methods.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/php/php_generator.cc                \
+  google/protobuf/compiler/plugin.cc                           \
+  google/protobuf/compiler/plugin.pb.cc                        \
+  google/protobuf/compiler/python/generator.cc                 \
+  google/protobuf/compiler/python/helpers.cc                   \
+  google/protobuf/compiler/python/helpers.h                    \
+  google/protobuf/compiler/python/pyi_generator.cc             \
+  google/protobuf/compiler/ruby/ruby_generator.cc              \
+  google/protobuf/compiler/scc.h                               \
+  google/protobuf/compiler/subprocess.cc                       \
+  google/protobuf/compiler/subprocess.h                        \
+  google/protobuf/compiler/zip_writer.cc                       \
+  google/protobuf/compiler/zip_writer.h
+
+bin_PROGRAMS = protoc
+protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
+protoc_SOURCES = google/protobuf/compiler/main.cc
+
+# Tests ==============================================================
+
+protoc_inputs =                                                   \
+  google/protobuf/any_test.proto                                  \
+  google/protobuf/compiler/cpp/test_bad_identifiers.proto         \
+  google/protobuf/compiler/cpp/test_large_enum_value.proto        \
+  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_enormous_descriptor.proto              \
+  google/protobuf/unittest_import.proto                           \
+  google/protobuf/unittest_import_lite.proto                      \
+  google/protobuf/unittest_import_public.proto                    \
+  google/protobuf/unittest_import_public_lite.proto               \
+  google/protobuf/unittest_lazy_dependencies.proto                \
+  google/protobuf/unittest_lazy_dependencies_custom_option.proto  \
+  google/protobuf/unittest_lazy_dependencies_enum.proto           \
+  google/protobuf/unittest_lite.proto                             \
+  google/protobuf/unittest_lite_imports_nonlite.proto             \
+  google/protobuf/unittest_mset.proto                             \
+  google/protobuf/unittest_mset_wire_format.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.proto                           \
+  google/protobuf/unittest_proto3_arena.proto                     \
+  google/protobuf/unittest_proto3_arena_lite.proto                \
+  google/protobuf/unittest_proto3_lite.proto                      \
+  google/protobuf/unittest_proto3_optional.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/proto3.proto             \
+  google/protobuf/util/internal/testdata/struct.proto             \
+  google/protobuf/util/internal/testdata/timestamp_duration.proto \
+  google/protobuf/util/internal/testdata/wrappers.proto           \
+  google/protobuf/util/json_format.proto                          \
+  google/protobuf/util/json_format_proto3.proto                   \
+  google/protobuf/util/message_differencer_unittest.proto
+
+EXTRA_DIST =                                                   \
+  $(protoc_inputs)                                             \
+  README.md                                                    \
+  google/protobuf/compiler/package_info.h                      \
+  google/protobuf/compiler/ruby/ruby_generated_code.proto      \
+  google/protobuf/compiler/ruby/ruby_generated_code_pb.rb      \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb \
+  google/protobuf/compiler/zip_output_unittest.sh              \
+  google/protobuf/io/gzip_stream.h                             \
+  google/protobuf/io/gzip_stream_unittest.sh                   \
+  google/protobuf/io/package_info.h                            \
+  google/protobuf/package_info.h                               \
+  google/protobuf/test_messages_proto2.proto                   \
+  google/protobuf/test_messages_proto3.proto                   \
+  google/protobuf/testdata/bad_utf8_string                     \
+  google/protobuf/testdata/golden_message                      \
+  google/protobuf/testdata/golden_message_maps                 \
+  google/protobuf/testdata/golden_message_oneof_implemented    \
+  google/protobuf/testdata/golden_message_proto3               \
+  google/protobuf/testdata/golden_packed_fields_message        \
+  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 \
+  google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt \
+  google/protobuf/testdata/text_format_unittest_extensions_data.txt \
+  google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt \
+  google/protobuf/util/package_info.h                          \
+  libprotobuf-lite.map                                         \
+  libprotobuf.map                                              \
+  libprotoc.map                                                \
+  solaris/libstdc++.la                                        
+
+protoc_lite_outputs =                                          \
+  google/protobuf/map_lite_unittest.pb.cc                      \
+  google/protobuf/map_lite_unittest.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             \
+  google/protobuf/unittest_lite.pb.cc                          \
+  google/protobuf/unittest_lite.pb.h
+
+protoc_outputs =                                                  \
+  $(protoc_lite_outputs)                                          \
+  google/protobuf/any_test.pb.cc                                  \
+  google/protobuf/any_test.pb.h                                   \
+  google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc         \
+  google/protobuf/compiler/cpp/test_bad_identifiers.pb.h          \
+  google/protobuf/compiler/cpp/test_large_enum_value.pb.cc        \
+  google/protobuf/compiler/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.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_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_lazy_dependencies.pb.cc                \
+  google/protobuf/unittest_lazy_dependencies.pb.h                 \
+  google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc  \
+  google/protobuf/unittest_lazy_dependencies_custom_option.pb.h   \
+  google/protobuf/unittest_lazy_dependencies_enum.pb.cc           \
+  google/protobuf/unittest_lazy_dependencies_enum.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_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.pb.cc                           \
+  google/protobuf/unittest_proto3.pb.h                            \
+  google/protobuf/unittest_proto3_arena.pb.cc                     \
+  google/protobuf/unittest_proto3_arena.pb.h                      \
+  google/protobuf/unittest_proto3_arena_lite.pb.cc                \
+  google/protobuf/unittest_proto3_arena_lite.pb.h                 \
+  google/protobuf/unittest_proto3_lite.pb.cc                      \
+  google/protobuf/unittest_proto3_lite.pb.h                       \
+  google/protobuf/unittest_proto3_optional.pb.cc                  \
+  google/protobuf/unittest_proto3_optional.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/proto3.pb.cc             \
+  google/protobuf/util/internal/testdata/proto3.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/internal/testdata/wrappers.pb.cc           \
+  google/protobuf/util/internal/testdata/wrappers.pb.h            \
+  google/protobuf/util/json_format.pb.cc                          \
+  google/protobuf/util/json_format.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
+
+if USE_EXTERNAL_PROTOC
+
+unittest_proto_middleman: $(protoc_inputs)
+	$(PROTOC) -I$(srcdir) --cpp_out=. $^
+	touch unittest_proto_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.
+unittest_proto_middleman: protoc$(EXEEXT) $(protoc_inputs)
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd $(protoc_inputs) --experimental_allow_proto3_optional )
+	touch unittest_proto_middleman
+
+endif
+
+$(protoc_outputs): unittest_proto_middleman
+
+COMMON_TEST_SOURCES =                                          \
+  $(COMMON_LITE_TEST_SOURCES)                                  \
+  google/protobuf/compiler/cpp/unittest.h                      \
+  google/protobuf/map_test_util.h                              \
+  google/protobuf/map_test_util.inc                            \
+  google/protobuf/reflection_tester.cc                         \
+  google/protobuf/reflection_tester.h                          \
+  google/protobuf/test_util.cc                                 \
+  google/protobuf/test_util.h                                  \
+  google/protobuf/test_util.inc                                \
+  google/protobuf/test_util2.h                                 \
+  google/protobuf/testing/file.cc                              \
+  google/protobuf/testing/file.h                               \
+  google/protobuf/testing/googletest.cc                        \
+  google/protobuf/testing/googletest.h
+
+GOOGLETEST_BUILD_DIR=../third_party/googletest/googletest
+GOOGLEMOCK_BUILD_DIR=../third_party/googletest/googlemock
+GOOGLETEST_SRC_DIR=$(srcdir)/../third_party/googletest/googletest
+GOOGLEMOCK_SRC_DIR=$(srcdir)/../third_party/googletest/googlemock
+check_PROGRAMS = protoc protobuf-test protobuf-lazy-descriptor-test \
+                 protobuf-lite-test test_plugin protobuf-lite-arena-test \
+                 no-warning-test $(GZCHECKPROGRAMS)
+protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
+                      $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la     \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la     \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_test_CPPFLAGS = -I$(GOOGLETEST_SRC_DIR)/include \
+                         -I$(GOOGLEMOCK_SRC_DIR)/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 =                                        \
+  $(COMMON_TEST_SOURCES)                                       \
+  google/protobuf/any_test.cc                                  \
+  google/protobuf/arena_unittest.cc                            \
+  google/protobuf/arenastring_unittest.cc                      \
+  google/protobuf/arenaz_sampler_test.cc                       \
+  google/protobuf/compiler/annotation_test_util.cc             \
+  google/protobuf/compiler/annotation_test_util.h              \
+  google/protobuf/compiler/command_line_interface_unittest.cc  \
+  google/protobuf/compiler/cpp/bootstrap_unittest.cc           \
+  google/protobuf/compiler/cpp/message_size_unittest.cc        \
+  google/protobuf/compiler/cpp/metadata_test.cc                \
+  google/protobuf/compiler/cpp/move_unittest.cc                \
+  google/protobuf/compiler/cpp/plugin_unittest.cc              \
+  google/protobuf/compiler/cpp/unittest.cc                     \
+  google/protobuf/compiler/cpp/unittest.inc                    \
+  google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc \
+  google/protobuf/compiler/csharp/csharp_generator_unittest.cc \
+  google/protobuf/compiler/importer_unittest.cc                \
+  google/protobuf/compiler/java/doc_comment_unittest.cc        \
+  google/protobuf/compiler/java/plugin_unittest.cc             \
+  google/protobuf/compiler/mock_code_generator.cc              \
+  google/protobuf/compiler/mock_code_generator.h               \
+  google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc \
+  google/protobuf/compiler/parser_unittest.cc                  \
+  google/protobuf/compiler/python/plugin_unittest.cc           \
+  google/protobuf/compiler/ruby/ruby_generator_unittest.cc     \
+  google/protobuf/descriptor_database_unittest.cc              \
+  google/protobuf/descriptor_unittest.cc                       \
+  google/protobuf/drop_unknown_fields_test.cc                  \
+  google/protobuf/dynamic_message_unittest.cc                  \
+  google/protobuf/extension_set_unittest.cc                    \
+  google/protobuf/generated_message_reflection_unittest.cc     \
+  google/protobuf/generated_message_tctable_lite_test.cc       \
+  google/protobuf/inlined_string_field_unittest.cc             \
+  google/protobuf/io/coded_stream_unittest.cc                  \
+  google/protobuf/io/io_win32_unittest.cc                      \
+  google/protobuf/io/printer_unittest.cc                       \
+  google/protobuf/io/tokenizer_unittest.cc                     \
+  google/protobuf/io/zero_copy_stream_unittest.cc              \
+  google/protobuf/map_field_test.cc                            \
+  google/protobuf/map_test.cc                                  \
+  google/protobuf/map_test.inc                                 \
+  google/protobuf/message_unittest.cc                          \
+  google/protobuf/message_unittest.inc                         \
+  google/protobuf/no_field_presence_test.cc                    \
+  google/protobuf/preserve_unknown_enum_test.cc                \
+  google/protobuf/proto3_arena_lite_unittest.cc                \
+  google/protobuf/proto3_arena_unittest.cc                     \
+  google/protobuf/proto3_lite_unittest.cc                      \
+  google/protobuf/proto3_lite_unittest.inc                     \
+  google/protobuf/reflection_ops_unittest.cc                   \
+  google/protobuf/repeated_field_reflection_unittest.cc        \
+  google/protobuf/repeated_field_unittest.cc                   \
+  google/protobuf/stubs/bytestream_unittest.cc                 \
+  google/protobuf/stubs/common_unittest.cc                     \
+  google/protobuf/stubs/int128_unittest.cc                     \
+  google/protobuf/stubs/status_test.cc                         \
+  google/protobuf/stubs/statusor_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/text_format_unittest.cc                      \
+  google/protobuf/unknown_field_set_unittest.cc                \
+  google/protobuf/util/delimited_message_util_test.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              \
+  google/protobuf/well_known_types_unittest.cc                 \
+  google/protobuf/wire_format_unittest.cc                      \
+  google/protobuf/wire_format_unittest.inc
+
+nodist_protobuf_test_SOURCES = $(protoc_outputs)
+$(am_protobuf_test_OBJECTS): unittest_proto_middleman
+
+# Run cpp_unittest again with PROTOBUF_TEST_NO_DESCRIPTORS defined.
+protobuf_lazy_descriptor_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la \
+                      libprotoc.la                                   \
+                      $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_lazy_descriptor_test_CPPFLAGS = -I$(GOOGLEMOCK_SRC_DIR)/include \
+                                         -I$(GOOGLETEST_SRC_DIR)/include \
+                                         -DPROTOBUF_TEST_NO_DESCRIPTORS
+protobuf_lazy_descriptor_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
+protobuf_lazy_descriptor_test_SOURCES =                        \
+  google/protobuf/compiler/cpp/unittest.cc                     \
+  $(COMMON_TEST_SOURCES)
+nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs)
+$(am_protobuf_lazy_descriptor_test_OBJECTS): unittest_proto_middleman
+
+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/map_test_util_impl.h                                 \
+  google/protobuf/test_util_lite.cc                                    \
+  google/protobuf/test_util_lite.h
+
+# Build lite_unittest separately, since it doesn't use gtest. It can't
+# depend on gtest because our internal version of gtest depend on proto
+# full runtime and we want to make sure this test builds without full
+# runtime.
+protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la     \
+                           $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la \
+                           $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la \
+                           $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_lite_test_CPPFLAGS= -I$(GOOGLEMOCK_SRC_DIR)/include \
+                             -I$(GOOGLETEST_SRC_DIR)/include
+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)
+$(am_protobuf_lite_test_OBJECTS): unittest_proto_middleman
+
+# 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 \
+                      $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_lite_arena_test_CPPFLAGS = -I$(GOOGLEMOCK_SRC_DIR)/include  \
+                                    -I$(GOOGLETEST_SRC_DIR)/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)
+$(am_protobuf_lite_arena_test_OBJECTS): unittest_proto_middleman
+
+# Test plugin binary.
+test_plugin_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
+                    $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la
+test_plugin_CPPFLAGS = -I$(GOOGLETEST_SRC_DIR)/include
+test_plugin_SOURCES =                                          \
+  google/protobuf/compiler/mock_code_generator.cc              \
+  google/protobuf/compiler/test_plugin.cc                      \
+  google/protobuf/testing/file.cc                              \
+  google/protobuf/testing/file.h
+
+if HAVE_ZLIB
+zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
+zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc
+
+zcgunzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
+zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc
+endif
+
+# This test target is to ensure all our public header files and generated
+# code is free from warnings. We have to be more pedantic about these
+# files because they are compiled by users with different compiler flags.
+no_warning_test.cc:
+	echo "// Generated from Makefile.am" > no_warning_test.cc
+	for FILE in $(nobase_include_HEADERS); do \
+		case $$FILE in *.inc) continue;; esac; \
+		echo "#include <$${FILE}>" >> no_warning_test.cc; \
+	done
+	echo "int main(int, char**) { return 0; }" >> no_warning_test.cc
+
+no_warning_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
+no_warning_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) \
+                           -Wall -Wextra -Werror -Wno-unused-parameter
+nodist_no_warning_test_SOURCES = no_warning_test.cc $(protoc_outputs)
+
+TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test \
+        google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS)     \
+        protobuf-lite-arena-test no-warning-test
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..e8b1427
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,9522 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HAVE_LD_VERSION_SCRIPT_TRUE@am__append_1 = -Wl,--version-script=$(srcdir)/libprotobuf-lite.map
+@HAVE_LD_VERSION_SCRIPT_TRUE@am__append_2 = -Wl,--version-script=$(srcdir)/libprotobuf.map
+@HAVE_LD_VERSION_SCRIPT_TRUE@am__append_3 = -Wl,--version-script=$(srcdir)/libprotoc.map
+bin_PROGRAMS = protoc$(EXEEXT)
+check_PROGRAMS = protoc$(EXEEXT) protobuf-test$(EXEEXT) \
+	protobuf-lazy-descriptor-test$(EXEEXT) \
+	protobuf-lite-test$(EXEEXT) test_plugin$(EXEEXT) \
+	protobuf-lite-arena-test$(EXEEXT) no-warning-test$(EXEEXT) \
+	$(am__EXEEXT_1)
+TESTS = protobuf-test$(EXEEXT) protobuf-lazy-descriptor-test$(EXEEXT) \
+	protobuf-lite-test$(EXEEXT) \
+	google/protobuf/compiler/zip_output_unittest.sh \
+	$(am__EXEEXT_2) protobuf-lite-arena-test$(EXEEXT) \
+	no-warning-test$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ac_system_extensions.m4 \
+	$(top_srcdir)/m4/acx_check_suncc.m4 \
+	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+	$(top_srcdir)/m4/ax_prog_cxx_for_build.m4 \
+	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/stl_hash.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(nobase_dist_proto_DATA) \
+	$(am__nobase_include_HEADERS_DIST) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \
+	"$(DESTDIR)$(protodir)" "$(DESTDIR)$(includedir)"
+@HAVE_ZLIB_TRUE@am__EXEEXT_1 = zcgzip$(EXEEXT) zcgunzip$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libprotobuf_lite_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_libprotobuf_lite_la_OBJECTS = google/protobuf/any_lite.lo \
+	google/protobuf/arena.lo google/protobuf/arenastring.lo \
+	google/protobuf/arenaz_sampler.lo \
+	google/protobuf/extension_set.lo \
+	google/protobuf/generated_enum_util.lo \
+	google/protobuf/generated_message_tctable_lite.lo \
+	google/protobuf/generated_message_util.lo \
+	google/protobuf/implicit_weak_message.lo \
+	google/protobuf/inlined_string_field.lo \
+	google/protobuf/io/coded_stream.lo \
+	google/protobuf/io/io_win32.lo google/protobuf/io/strtod.lo \
+	google/protobuf/io/zero_copy_stream.lo \
+	google/protobuf/io/zero_copy_stream_impl.lo \
+	google/protobuf/io/zero_copy_stream_impl_lite.lo \
+	google/protobuf/map.lo google/protobuf/message_lite.lo \
+	google/protobuf/parse_context.lo \
+	google/protobuf/repeated_field.lo \
+	google/protobuf/repeated_ptr_field.lo \
+	google/protobuf/stubs/bytestream.lo \
+	google/protobuf/stubs/common.lo \
+	google/protobuf/stubs/int128.lo \
+	google/protobuf/stubs/status.lo \
+	google/protobuf/stubs/statusor.lo \
+	google/protobuf/stubs/stringpiece.lo \
+	google/protobuf/stubs/stringprintf.lo \
+	google/protobuf/stubs/structurally_valid.lo \
+	google/protobuf/stubs/strutil.lo google/protobuf/stubs/time.lo \
+	google/protobuf/wire_format_lite.lo
+libprotobuf_lite_la_OBJECTS = $(am_libprotobuf_lite_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libprotobuf_lite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(AM_CXXFLAGS) $(CXXFLAGS) $(libprotobuf_lite_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+libprotobuf_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
+am__objects_1 = google/protobuf/any_lite.lo google/protobuf/arena.lo \
+	google/protobuf/arenastring.lo \
+	google/protobuf/arenaz_sampler.lo \
+	google/protobuf/extension_set.lo \
+	google/protobuf/generated_enum_util.lo \
+	google/protobuf/generated_message_tctable_lite.lo \
+	google/protobuf/generated_message_util.lo \
+	google/protobuf/implicit_weak_message.lo \
+	google/protobuf/inlined_string_field.lo \
+	google/protobuf/io/coded_stream.lo \
+	google/protobuf/io/io_win32.lo google/protobuf/io/strtod.lo \
+	google/protobuf/io/zero_copy_stream.lo \
+	google/protobuf/io/zero_copy_stream_impl.lo \
+	google/protobuf/io/zero_copy_stream_impl_lite.lo \
+	google/protobuf/map.lo google/protobuf/message_lite.lo \
+	google/protobuf/parse_context.lo \
+	google/protobuf/repeated_field.lo \
+	google/protobuf/repeated_ptr_field.lo \
+	google/protobuf/stubs/bytestream.lo \
+	google/protobuf/stubs/common.lo \
+	google/protobuf/stubs/int128.lo \
+	google/protobuf/stubs/status.lo \
+	google/protobuf/stubs/statusor.lo \
+	google/protobuf/stubs/stringpiece.lo \
+	google/protobuf/stubs/stringprintf.lo \
+	google/protobuf/stubs/structurally_valid.lo \
+	google/protobuf/stubs/strutil.lo google/protobuf/stubs/time.lo \
+	google/protobuf/wire_format_lite.lo
+am_libprotobuf_la_OBJECTS = $(am__objects_1) google/protobuf/any.lo \
+	google/protobuf/any.pb.lo google/protobuf/api.pb.lo \
+	google/protobuf/compiler/importer.lo \
+	google/protobuf/compiler/parser.lo \
+	google/protobuf/descriptor.lo google/protobuf/descriptor.pb.lo \
+	google/protobuf/descriptor_database.lo \
+	google/protobuf/duration.pb.lo \
+	google/protobuf/dynamic_message.lo google/protobuf/empty.pb.lo \
+	google/protobuf/extension_set_heavy.lo \
+	google/protobuf/field_mask.pb.lo \
+	google/protobuf/generated_message_bases.lo \
+	google/protobuf/generated_message_reflection.lo \
+	google/protobuf/generated_message_tctable_full.lo \
+	google/protobuf/io/gzip_stream.lo \
+	google/protobuf/io/printer.lo google/protobuf/io/tokenizer.lo \
+	google/protobuf/map_field.lo google/protobuf/message.lo \
+	google/protobuf/reflection_ops.lo google/protobuf/service.lo \
+	google/protobuf/source_context.pb.lo \
+	google/protobuf/struct.pb.lo \
+	google/protobuf/stubs/substitute.lo \
+	google/protobuf/text_format.lo google/protobuf/timestamp.pb.lo \
+	google/protobuf/type.pb.lo \
+	google/protobuf/unknown_field_set.lo \
+	google/protobuf/util/delimited_message_util.lo \
+	google/protobuf/util/field_comparator.lo \
+	google/protobuf/util/field_mask_util.lo \
+	google/protobuf/util/internal/datapiece.lo \
+	google/protobuf/util/internal/default_value_objectwriter.lo \
+	google/protobuf/util/internal/error_listener.lo \
+	google/protobuf/util/internal/field_mask_utility.lo \
+	google/protobuf/util/internal/json_escaping.lo \
+	google/protobuf/util/internal/json_objectwriter.lo \
+	google/protobuf/util/internal/json_stream_parser.lo \
+	google/protobuf/util/internal/object_writer.lo \
+	google/protobuf/util/internal/proto_writer.lo \
+	google/protobuf/util/internal/protostream_objectsource.lo \
+	google/protobuf/util/internal/protostream_objectwriter.lo \
+	google/protobuf/util/internal/type_info.lo \
+	google/protobuf/util/internal/utility.lo \
+	google/protobuf/util/json_util.lo \
+	google/protobuf/util/message_differencer.lo \
+	google/protobuf/util/time_util.lo \
+	google/protobuf/util/type_resolver_util.lo \
+	google/protobuf/wire_format.lo google/protobuf/wrappers.pb.lo
+nodist_libprotobuf_la_OBJECTS =
+libprotobuf_la_OBJECTS = $(am_libprotobuf_la_OBJECTS) \
+	$(nodist_libprotobuf_la_OBJECTS)
+libprotobuf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(AM_CXXFLAGS) $(CXXFLAGS) $(libprotobuf_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+libprotoc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la
+am_libprotoc_la_OBJECTS = google/protobuf/compiler/code_generator.lo \
+	google/protobuf/compiler/command_line_interface.lo \
+	google/protobuf/compiler/cpp/enum.lo \
+	google/protobuf/compiler/cpp/enum_field.lo \
+	google/protobuf/compiler/cpp/extension.lo \
+	google/protobuf/compiler/cpp/field.lo \
+	google/protobuf/compiler/cpp/file.lo \
+	google/protobuf/compiler/cpp/generator.lo \
+	google/protobuf/compiler/cpp/helpers.lo \
+	google/protobuf/compiler/cpp/map_field.lo \
+	google/protobuf/compiler/cpp/message.lo \
+	google/protobuf/compiler/cpp/message_field.lo \
+	google/protobuf/compiler/cpp/padding_optimizer.lo \
+	google/protobuf/compiler/cpp/parse_function_generator.lo \
+	google/protobuf/compiler/cpp/primitive_field.lo \
+	google/protobuf/compiler/cpp/service.lo \
+	google/protobuf/compiler/cpp/string_field.lo \
+	google/protobuf/compiler/csharp/csharp_doc_comment.lo \
+	google/protobuf/compiler/csharp/csharp_enum.lo \
+	google/protobuf/compiler/csharp/csharp_enum_field.lo \
+	google/protobuf/compiler/csharp/csharp_field_base.lo \
+	google/protobuf/compiler/csharp/csharp_generator.lo \
+	google/protobuf/compiler/csharp/csharp_helpers.lo \
+	google/protobuf/compiler/csharp/csharp_map_field.lo \
+	google/protobuf/compiler/csharp/csharp_message.lo \
+	google/protobuf/compiler/csharp/csharp_message_field.lo \
+	google/protobuf/compiler/csharp/csharp_primitive_field.lo \
+	google/protobuf/compiler/csharp/csharp_reflection_class.lo \
+	google/protobuf/compiler/csharp/csharp_repeated_enum_field.lo \
+	google/protobuf/compiler/csharp/csharp_repeated_message_field.lo \
+	google/protobuf/compiler/csharp/csharp_repeated_primitive_field.lo \
+	google/protobuf/compiler/csharp/csharp_source_generator_base.lo \
+	google/protobuf/compiler/csharp/csharp_wrapper_field.lo \
+	google/protobuf/compiler/java/context.lo \
+	google/protobuf/compiler/java/doc_comment.lo \
+	google/protobuf/compiler/java/enum.lo \
+	google/protobuf/compiler/java/enum_field.lo \
+	google/protobuf/compiler/java/enum_field_lite.lo \
+	google/protobuf/compiler/java/enum_lite.lo \
+	google/protobuf/compiler/java/extension.lo \
+	google/protobuf/compiler/java/extension_lite.lo \
+	google/protobuf/compiler/java/field.lo \
+	google/protobuf/compiler/java/file.lo \
+	google/protobuf/compiler/java/generator.lo \
+	google/protobuf/compiler/java/generator_factory.lo \
+	google/protobuf/compiler/java/helpers.lo \
+	google/protobuf/compiler/java/kotlin_generator.lo \
+	google/protobuf/compiler/java/map_field.lo \
+	google/protobuf/compiler/java/map_field_lite.lo \
+	google/protobuf/compiler/java/message.lo \
+	google/protobuf/compiler/java/message_builder.lo \
+	google/protobuf/compiler/java/message_builder_lite.lo \
+	google/protobuf/compiler/java/message_field.lo \
+	google/protobuf/compiler/java/message_field_lite.lo \
+	google/protobuf/compiler/java/message_lite.lo \
+	google/protobuf/compiler/java/name_resolver.lo \
+	google/protobuf/compiler/java/primitive_field.lo \
+	google/protobuf/compiler/java/primitive_field_lite.lo \
+	google/protobuf/compiler/java/service.lo \
+	google/protobuf/compiler/java/shared_code_generator.lo \
+	google/protobuf/compiler/java/string_field.lo \
+	google/protobuf/compiler/java/string_field_lite.lo \
+	google/protobuf/compiler/objectivec/objectivec_enum.lo \
+	google/protobuf/compiler/objectivec/objectivec_enum_field.lo \
+	google/protobuf/compiler/objectivec/objectivec_extension.lo \
+	google/protobuf/compiler/objectivec/objectivec_field.lo \
+	google/protobuf/compiler/objectivec/objectivec_file.lo \
+	google/protobuf/compiler/objectivec/objectivec_generator.lo \
+	google/protobuf/compiler/objectivec/objectivec_helpers.lo \
+	google/protobuf/compiler/objectivec/objectivec_map_field.lo \
+	google/protobuf/compiler/objectivec/objectivec_message.lo \
+	google/protobuf/compiler/objectivec/objectivec_message_field.lo \
+	google/protobuf/compiler/objectivec/objectivec_oneof.lo \
+	google/protobuf/compiler/objectivec/objectivec_primitive_field.lo \
+	google/protobuf/compiler/php/php_generator.lo \
+	google/protobuf/compiler/plugin.lo \
+	google/protobuf/compiler/plugin.pb.lo \
+	google/protobuf/compiler/python/generator.lo \
+	google/protobuf/compiler/python/helpers.lo \
+	google/protobuf/compiler/python/pyi_generator.lo \
+	google/protobuf/compiler/ruby/ruby_generator.lo \
+	google/protobuf/compiler/subprocess.lo \
+	google/protobuf/compiler/zip_writer.lo
+libprotoc_la_OBJECTS = $(am_libprotoc_la_OBJECTS)
+libprotoc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libprotoc_la_LDFLAGS) $(LDFLAGS) -o $@
+am__objects_2 = google/protobuf/no_warning_test-map_lite_unittest.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_import_lite.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_import_public_lite.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_lite.pb.$(OBJEXT)
+am__objects_3 = $(am__objects_2) \
+	google/protobuf/no_warning_test-any_test.pb.$(OBJEXT) \
+	google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.$(OBJEXT) \
+	google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-map_proto2_unittest.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-map_unittest.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_arena.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_custom_options.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_empty.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_import.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_import_public.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_mset.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_mset_wire_format.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_no_field_presence.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_no_generic_services.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_optimize_for.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_proto3.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_proto3_arena.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_proto3_lite.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_proto3_optional.pb.$(OBJEXT) \
+	google/protobuf/no_warning_test-unittest_well_known_types.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-anys.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-books.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-maps.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-struct.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.$(OBJEXT) \
+	google/protobuf/util/no_warning_test-json_format.pb.$(OBJEXT) \
+	google/protobuf/util/no_warning_test-json_format_proto3.pb.$(OBJEXT) \
+	google/protobuf/util/no_warning_test-message_differencer_unittest.pb.$(OBJEXT)
+nodist_no_warning_test_OBJECTS =  \
+	no_warning_test-no_warning_test.$(OBJEXT) $(am__objects_3)
+no_warning_test_OBJECTS = $(nodist_no_warning_test_OBJECTS)
+no_warning_test_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
+	libprotoc.la
+no_warning_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(no_warning_test_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+am__objects_4 = google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.$(OBJEXT)
+am__objects_5 = $(am__objects_4) \
+	google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-test_util.$(OBJEXT) \
+	google/protobuf/testing/protobuf_lazy_descriptor_test-file.$(OBJEXT) \
+	google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.$(OBJEXT)
+am_protobuf_lazy_descriptor_test_OBJECTS = google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.$(OBJEXT) \
+	$(am__objects_5)
+am__objects_6 = google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.$(OBJEXT)
+am__objects_7 = $(am__objects_6) \
+	google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.$(OBJEXT) \
+	google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.$(OBJEXT) \
+	google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.$(OBJEXT) \
+	google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.$(OBJEXT)
+nodist_protobuf_lazy_descriptor_test_OBJECTS = $(am__objects_7)
+protobuf_lazy_descriptor_test_OBJECTS =  \
+	$(am_protobuf_lazy_descriptor_test_OBJECTS) \
+	$(nodist_protobuf_lazy_descriptor_test_OBJECTS)
+protobuf_lazy_descriptor_test_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	libprotobuf.la libprotoc.la \
+	$(GOOGLETEST_BUILD_DIR)/lib/libgtest.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_lazy_descriptor_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+am__objects_8 = google/protobuf/protobuf_lite_arena_test-arena_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_lite_arena_test-map_lite_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_lite_arena_test-test_util_lite.$(OBJEXT)
+am_protobuf_lite_arena_test_OBJECTS = google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.$(OBJEXT) \
+	$(am__objects_8)
+am__objects_9 = google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.$(OBJEXT)
+nodist_protobuf_lite_arena_test_OBJECTS = $(am__objects_9)
+protobuf_lite_arena_test_OBJECTS =  \
+	$(am_protobuf_lite_arena_test_OBJECTS) \
+	$(nodist_protobuf_lite_arena_test_OBJECTS)
+protobuf_lite_arena_test_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	libprotobuf-lite.la $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_lite_arena_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+am__objects_10 =  \
+	google/protobuf/protobuf_lite_test-arena_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_lite_test-map_lite_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_lite_test-test_util_lite.$(OBJEXT)
+am_protobuf_lite_test_OBJECTS =  \
+	google/protobuf/protobuf_lite_test-lite_unittest.$(OBJEXT) \
+	$(am__objects_10)
+am__objects_11 = google/protobuf/protobuf_lite_test-map_lite_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lite_test-unittest_import_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_lite_test-unittest_lite.pb.$(OBJEXT)
+nodist_protobuf_lite_test_OBJECTS = $(am__objects_11)
+protobuf_lite_test_OBJECTS = $(am_protobuf_lite_test_OBJECTS) \
+	$(nodist_protobuf_lite_test_OBJECTS)
+protobuf_lite_test_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	libprotobuf-lite.la $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_lite_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+am__objects_12 =  \
+	google/protobuf/protobuf_test-arena_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_test-map_lite_test_util.$(OBJEXT) \
+	google/protobuf/protobuf_test-test_util_lite.$(OBJEXT)
+am__objects_13 = $(am__objects_12) \
+	google/protobuf/protobuf_test-reflection_tester.$(OBJEXT) \
+	google/protobuf/protobuf_test-test_util.$(OBJEXT) \
+	google/protobuf/testing/protobuf_test-file.$(OBJEXT) \
+	google/protobuf/testing/protobuf_test-googletest.$(OBJEXT)
+am_protobuf_test_OBJECTS = $(am__objects_13) \
+	google/protobuf/protobuf_test-any_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-arena_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-arenastring_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-arenaz_sampler_test.$(OBJEXT) \
+	google/protobuf/compiler/protobuf_test-annotation_test_util.$(OBJEXT) \
+	google/protobuf/compiler/protobuf_test-command_line_interface_unittest.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-metadata_test.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-move_unittest.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-unittest.$(OBJEXT) \
+	google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.$(OBJEXT) \
+	google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.$(OBJEXT) \
+	google/protobuf/compiler/protobuf_test-importer_unittest.$(OBJEXT) \
+	google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.$(OBJEXT) \
+	google/protobuf/compiler/java/protobuf_test-plugin_unittest.$(OBJEXT) \
+	google/protobuf/compiler/protobuf_test-mock_code_generator.$(OBJEXT) \
+	google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.$(OBJEXT) \
+	google/protobuf/compiler/protobuf_test-parser_unittest.$(OBJEXT) \
+	google/protobuf/compiler/python/protobuf_test-plugin_unittest.$(OBJEXT) \
+	google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-descriptor_database_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-descriptor_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-drop_unknown_fields_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-dynamic_message_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-extension_set_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-generated_message_reflection_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-generated_message_tctable_lite_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-inlined_string_field_unittest.$(OBJEXT) \
+	google/protobuf/io/protobuf_test-coded_stream_unittest.$(OBJEXT) \
+	google/protobuf/io/protobuf_test-io_win32_unittest.$(OBJEXT) \
+	google/protobuf/io/protobuf_test-printer_unittest.$(OBJEXT) \
+	google/protobuf/io/protobuf_test-tokenizer_unittest.$(OBJEXT) \
+	google/protobuf/io/protobuf_test-zero_copy_stream_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-map_field_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-map_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-message_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-no_field_presence_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-preserve_unknown_enum_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-proto3_arena_lite_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-proto3_arena_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-proto3_lite_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-reflection_ops_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-repeated_field_reflection_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-repeated_field_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-bytestream_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-common_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-int128_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-status_test.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-statusor_test.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-stringpiece_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-stringprintf_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-structurally_valid_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-strutil_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-template_util_unittest.$(OBJEXT) \
+	google/protobuf/stubs/protobuf_test-time_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-text_format_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-unknown_field_set_unittest.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-delimited_message_util_test.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-field_comparator_test.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-field_mask_util_test.$(OBJEXT) \
+	google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.$(OBJEXT) \
+	google/protobuf/util/internal/protobuf_test-json_objectwriter_test.$(OBJEXT) \
+	google/protobuf/util/internal/protobuf_test-json_stream_parser_test.$(OBJEXT) \
+	google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.$(OBJEXT) \
+	google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.$(OBJEXT) \
+	google/protobuf/util/internal/protobuf_test-type_info_test_helper.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-json_util_test.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-message_differencer_unittest.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-time_util_test.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-type_resolver_util_test.$(OBJEXT) \
+	google/protobuf/protobuf_test-well_known_types_unittest.$(OBJEXT) \
+	google/protobuf/protobuf_test-wire_format_unittest.$(OBJEXT)
+am__objects_14 =  \
+	google/protobuf/protobuf_test-map_lite_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_import_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_import_public_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_lite.pb.$(OBJEXT)
+am__objects_15 = $(am__objects_14) \
+	google/protobuf/protobuf_test-any_test.pb.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.$(OBJEXT) \
+	google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-map_proto2_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-map_unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_arena.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_custom_options.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_empty.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_import.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_import_public.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_mset.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_mset_wire_format.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_no_field_presence.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_no_generic_services.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_optimize_for.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_proto3.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_proto3_arena.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_proto3_lite.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_proto3_optional.pb.$(OBJEXT) \
+	google/protobuf/protobuf_test-unittest_well_known_types.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-anys.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-books.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-maps.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-struct.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.$(OBJEXT) \
+	google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-json_format.pb.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-json_format_proto3.pb.$(OBJEXT) \
+	google/protobuf/util/protobuf_test-message_differencer_unittest.pb.$(OBJEXT)
+nodist_protobuf_test_OBJECTS = $(am__objects_15)
+protobuf_test_OBJECTS = $(am_protobuf_test_OBJECTS) \
+	$(nodist_protobuf_test_OBJECTS)
+protobuf_test_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
+	libprotoc.la $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la \
+	$(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+protobuf_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(protobuf_test_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+	-o $@
+am_protoc_OBJECTS = google/protobuf/compiler/main.$(OBJEXT)
+protoc_OBJECTS = $(am_protoc_OBJECTS)
+protoc_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
+	libprotoc.la
+am_test_plugin_OBJECTS = google/protobuf/compiler/test_plugin-mock_code_generator.$(OBJEXT) \
+	google/protobuf/compiler/test_plugin-test_plugin.$(OBJEXT) \
+	google/protobuf/testing/test_plugin-file.$(OBJEXT)
+test_plugin_OBJECTS = $(am_test_plugin_OBJECTS)
+test_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
+	libprotoc.la $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la
+am__zcgunzip_SOURCES_DIST = google/protobuf/testing/zcgunzip.cc
+@HAVE_ZLIB_TRUE@am_zcgunzip_OBJECTS =  \
+@HAVE_ZLIB_TRUE@	google/protobuf/testing/zcgunzip.$(OBJEXT)
+zcgunzip_OBJECTS = $(am_zcgunzip_OBJECTS)
+@HAVE_ZLIB_TRUE@zcgunzip_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_ZLIB_TRUE@	libprotobuf.la
+am__zcgzip_SOURCES_DIST = google/protobuf/testing/zcgzip.cc
+@HAVE_ZLIB_TRUE@am_zcgzip_OBJECTS =  \
+@HAVE_ZLIB_TRUE@	google/protobuf/testing/zcgzip.$(OBJEXT)
+zcgzip_OBJECTS = $(am_zcgzip_OBJECTS)
+@HAVE_ZLIB_TRUE@zcgzip_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_ZLIB_TRUE@	libprotobuf.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/no_warning_test-no_warning_test.Po \
+	google/protobuf/$(DEPDIR)/any.Plo \
+	google/protobuf/$(DEPDIR)/any.pb.Plo \
+	google/protobuf/$(DEPDIR)/any_lite.Plo \
+	google/protobuf/$(DEPDIR)/api.pb.Plo \
+	google/protobuf/$(DEPDIR)/arena.Plo \
+	google/protobuf/$(DEPDIR)/arenastring.Plo \
+	google/protobuf/$(DEPDIR)/arenaz_sampler.Plo \
+	google/protobuf/$(DEPDIR)/descriptor.Plo \
+	google/protobuf/$(DEPDIR)/descriptor.pb.Plo \
+	google/protobuf/$(DEPDIR)/descriptor_database.Plo \
+	google/protobuf/$(DEPDIR)/duration.pb.Plo \
+	google/protobuf/$(DEPDIR)/dynamic_message.Plo \
+	google/protobuf/$(DEPDIR)/empty.pb.Plo \
+	google/protobuf/$(DEPDIR)/extension_set.Plo \
+	google/protobuf/$(DEPDIR)/extension_set_heavy.Plo \
+	google/protobuf/$(DEPDIR)/field_mask.pb.Plo \
+	google/protobuf/$(DEPDIR)/generated_enum_util.Plo \
+	google/protobuf/$(DEPDIR)/generated_message_bases.Plo \
+	google/protobuf/$(DEPDIR)/generated_message_reflection.Plo \
+	google/protobuf/$(DEPDIR)/generated_message_tctable_full.Plo \
+	google/protobuf/$(DEPDIR)/generated_message_tctable_lite.Plo \
+	google/protobuf/$(DEPDIR)/generated_message_util.Plo \
+	google/protobuf/$(DEPDIR)/implicit_weak_message.Plo \
+	google/protobuf/$(DEPDIR)/inlined_string_field.Plo \
+	google/protobuf/$(DEPDIR)/map.Plo \
+	google/protobuf/$(DEPDIR)/map_field.Plo \
+	google/protobuf/$(DEPDIR)/message.Plo \
+	google/protobuf/$(DEPDIR)/message_lite.Plo \
+	google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Po \
+	google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Po \
+	google/protobuf/$(DEPDIR)/parse_context.Plo \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-any_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-map_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Po \
+	google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po \
+	google/protobuf/$(DEPDIR)/reflection_ops.Plo \
+	google/protobuf/$(DEPDIR)/repeated_field.Plo \
+	google/protobuf/$(DEPDIR)/repeated_ptr_field.Plo \
+	google/protobuf/$(DEPDIR)/service.Plo \
+	google/protobuf/$(DEPDIR)/source_context.pb.Plo \
+	google/protobuf/$(DEPDIR)/struct.pb.Plo \
+	google/protobuf/$(DEPDIR)/text_format.Plo \
+	google/protobuf/$(DEPDIR)/timestamp.pb.Plo \
+	google/protobuf/$(DEPDIR)/type.pb.Plo \
+	google/protobuf/$(DEPDIR)/unknown_field_set.Plo \
+	google/protobuf/$(DEPDIR)/wire_format.Plo \
+	google/protobuf/$(DEPDIR)/wire_format_lite.Plo \
+	google/protobuf/$(DEPDIR)/wrappers.pb.Plo \
+	google/protobuf/compiler/$(DEPDIR)/code_generator.Plo \
+	google/protobuf/compiler/$(DEPDIR)/command_line_interface.Plo \
+	google/protobuf/compiler/$(DEPDIR)/importer.Plo \
+	google/protobuf/compiler/$(DEPDIR)/main.Po \
+	google/protobuf/compiler/$(DEPDIR)/parser.Plo \
+	google/protobuf/compiler/$(DEPDIR)/plugin.Plo \
+	google/protobuf/compiler/$(DEPDIR)/plugin.pb.Plo \
+	google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Po \
+	google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po \
+	google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po \
+	google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po \
+	google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po \
+	google/protobuf/compiler/$(DEPDIR)/subprocess.Plo \
+	google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po \
+	google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po \
+	google/protobuf/compiler/$(DEPDIR)/zip_writer.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/enum.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/enum_field.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/extension.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/field.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/file.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/generator.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/helpers.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/map_field.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/message.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/message_field.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/padding_optimizer.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/parse_function_generator.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/primitive_field.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Po \
+	google/protobuf/compiler/cpp/$(DEPDIR)/service.Plo \
+	google/protobuf/compiler/cpp/$(DEPDIR)/string_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_doc_comment.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_field_base.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_generator.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_helpers.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_map_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_primitive_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_reflection_class.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_enum_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_message_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_primitive_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_source_generator_base.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/csharp_wrapper_field.Plo \
+	google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Po \
+	google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Po \
+	google/protobuf/compiler/java/$(DEPDIR)/context.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/doc_comment.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/enum.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/enum_field.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/enum_field_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/enum_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/extension.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/extension_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/field.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/file.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/generator.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/generator_factory.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/helpers.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/kotlin_generator.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/map_field.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/map_field_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/message.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/message_builder.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/message_builder_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/message_field.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/message_field_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/message_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/name_resolver.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/primitive_field.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/primitive_field_lite.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Po \
+	google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Po \
+	google/protobuf/compiler/java/$(DEPDIR)/service.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/shared_code_generator.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/string_field.Plo \
+	google/protobuf/compiler/java/$(DEPDIR)/string_field_lite.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum_field.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_extension.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_field.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_file.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_generator.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_helpers.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_map_field.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message_field.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_oneof.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_primitive_field.Plo \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Po \
+	google/protobuf/compiler/php/$(DEPDIR)/php_generator.Plo \
+	google/protobuf/compiler/python/$(DEPDIR)/generator.Plo \
+	google/protobuf/compiler/python/$(DEPDIR)/helpers.Plo \
+	google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Po \
+	google/protobuf/compiler/python/$(DEPDIR)/pyi_generator.Plo \
+	google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Po \
+	google/protobuf/compiler/ruby/$(DEPDIR)/ruby_generator.Plo \
+	google/protobuf/io/$(DEPDIR)/coded_stream.Plo \
+	google/protobuf/io/$(DEPDIR)/gzip_stream.Plo \
+	google/protobuf/io/$(DEPDIR)/io_win32.Plo \
+	google/protobuf/io/$(DEPDIR)/printer.Plo \
+	google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po \
+	google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Po \
+	google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po \
+	google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po \
+	google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po \
+	google/protobuf/io/$(DEPDIR)/strtod.Plo \
+	google/protobuf/io/$(DEPDIR)/tokenizer.Plo \
+	google/protobuf/io/$(DEPDIR)/zero_copy_stream.Plo \
+	google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl.Plo \
+	google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl_lite.Plo \
+	google/protobuf/stubs/$(DEPDIR)/bytestream.Plo \
+	google/protobuf/stubs/$(DEPDIR)/common.Plo \
+	google/protobuf/stubs/$(DEPDIR)/int128.Plo \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po \
+	google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Po \
+	google/protobuf/stubs/$(DEPDIR)/status.Plo \
+	google/protobuf/stubs/$(DEPDIR)/statusor.Plo \
+	google/protobuf/stubs/$(DEPDIR)/stringpiece.Plo \
+	google/protobuf/stubs/$(DEPDIR)/stringprintf.Plo \
+	google/protobuf/stubs/$(DEPDIR)/structurally_valid.Plo \
+	google/protobuf/stubs/$(DEPDIR)/strutil.Plo \
+	google/protobuf/stubs/$(DEPDIR)/substitute.Plo \
+	google/protobuf/stubs/$(DEPDIR)/time.Plo \
+	google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po \
+	google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po \
+	google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po \
+	google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po \
+	google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po \
+	google/protobuf/testing/$(DEPDIR)/zcgunzip.Po \
+	google/protobuf/testing/$(DEPDIR)/zcgzip.Po \
+	google/protobuf/util/$(DEPDIR)/delimited_message_util.Plo \
+	google/protobuf/util/$(DEPDIR)/field_comparator.Plo \
+	google/protobuf/util/$(DEPDIR)/field_mask_util.Plo \
+	google/protobuf/util/$(DEPDIR)/json_util.Plo \
+	google/protobuf/util/$(DEPDIR)/message_differencer.Plo \
+	google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Po \
+	google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Po \
+	google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Po \
+	google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Po \
+	google/protobuf/util/$(DEPDIR)/time_util.Plo \
+	google/protobuf/util/$(DEPDIR)/type_resolver_util.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/datapiece.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/default_value_objectwriter.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/error_listener.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/field_mask_utility.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/json_escaping.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/json_objectwriter.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/json_stream_parser.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/object_writer.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/proto_writer.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Po \
+	google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Po \
+	google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Po \
+	google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Po \
+	google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Po \
+	google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Po \
+	google/protobuf/util/internal/$(DEPDIR)/protostream_objectsource.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/protostream_objectwriter.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/type_info.Plo \
+	google/protobuf/util/internal/$(DEPDIR)/utility.Plo \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Po \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libprotobuf_lite_la_SOURCES) $(libprotobuf_la_SOURCES) \
+	$(nodist_libprotobuf_la_SOURCES) $(libprotoc_la_SOURCES) \
+	$(nodist_no_warning_test_SOURCES) \
+	$(protobuf_lazy_descriptor_test_SOURCES) \
+	$(nodist_protobuf_lazy_descriptor_test_SOURCES) \
+	$(protobuf_lite_arena_test_SOURCES) \
+	$(nodist_protobuf_lite_arena_test_SOURCES) \
+	$(protobuf_lite_test_SOURCES) \
+	$(nodist_protobuf_lite_test_SOURCES) $(protobuf_test_SOURCES) \
+	$(nodist_protobuf_test_SOURCES) $(protoc_SOURCES) \
+	$(test_plugin_SOURCES) $(zcgunzip_SOURCES) $(zcgzip_SOURCES)
+DIST_SOURCES = $(libprotobuf_lite_la_SOURCES) \
+	$(libprotobuf_la_SOURCES) $(libprotoc_la_SOURCES) \
+	$(protobuf_lazy_descriptor_test_SOURCES) \
+	$(protobuf_lite_arena_test_SOURCES) \
+	$(protobuf_lite_test_SOURCES) $(protobuf_test_SOURCES) \
+	$(protoc_SOURCES) $(test_plugin_SOURCES) \
+	$(am__zcgunzip_SOURCES_DIST) $(am__zcgzip_SOURCES_DIST)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+DATA = $(nobase_dist_proto_DATA)
+am__nobase_include_HEADERS_DIST = google/protobuf/any.h \
+	google/protobuf/any.pb.h google/protobuf/api.pb.h \
+	google/protobuf/arena.h google/protobuf/arena_impl.h \
+	google/protobuf/arenastring.h google/protobuf/arenaz_sampler.h \
+	google/protobuf/compiler/code_generator.h \
+	google/protobuf/compiler/command_line_interface.h \
+	google/protobuf/compiler/cpp/cpp_generator.h \
+	google/protobuf/compiler/cpp/file.h \
+	google/protobuf/compiler/cpp/generator.h \
+	google/protobuf/compiler/cpp/helpers.h \
+	google/protobuf/compiler/cpp/names.h \
+	google/protobuf/compiler/csharp/csharp_doc_comment.h \
+	google/protobuf/compiler/csharp/csharp_generator.h \
+	google/protobuf/compiler/csharp/csharp_names.h \
+	google/protobuf/compiler/csharp/csharp_options.h \
+	google/protobuf/compiler/importer.h \
+	google/protobuf/compiler/java/generator.h \
+	google/protobuf/compiler/java/java_generator.h \
+	google/protobuf/compiler/java/kotlin_generator.h \
+	google/protobuf/compiler/java/names.h \
+	google/protobuf/compiler/objectivec/objectivec_generator.h \
+	google/protobuf/compiler/objectivec/objectivec_helpers.h \
+	google/protobuf/compiler/parser.h \
+	google/protobuf/compiler/php/php_generator.h \
+	google/protobuf/compiler/plugin.h \
+	google/protobuf/compiler/plugin.pb.h \
+	google/protobuf/compiler/python/generator.h \
+	google/protobuf/compiler/python/pyi_generator.h \
+	google/protobuf/compiler/python/python_generator.h \
+	google/protobuf/compiler/ruby/ruby_generator.h \
+	google/protobuf/descriptor.h google/protobuf/descriptor.pb.h \
+	google/protobuf/descriptor_database.h \
+	google/protobuf/duration.pb.h \
+	google/protobuf/dynamic_message.h google/protobuf/empty.pb.h \
+	google/protobuf/endian.h \
+	google/protobuf/explicitly_constructed.h \
+	google/protobuf/extension_set.h \
+	google/protobuf/extension_set_inl.h \
+	google/protobuf/field_access_listener.h \
+	google/protobuf/field_mask.pb.h \
+	google/protobuf/generated_enum_reflection.h \
+	google/protobuf/generated_enum_util.h \
+	google/protobuf/generated_message_bases.h \
+	google/protobuf/generated_message_reflection.h \
+	google/protobuf/generated_message_tctable_decl.h \
+	google/protobuf/generated_message_tctable_impl.h \
+	google/protobuf/generated_message_util.h \
+	google/protobuf/has_bits.h \
+	google/protobuf/implicit_weak_message.h \
+	google/protobuf/inlined_string_field.h \
+	google/protobuf/io/coded_stream.h \
+	google/protobuf/io/gzip_stream.h google/protobuf/io/io_win32.h \
+	google/protobuf/io/printer.h google/protobuf/io/strtod.h \
+	google/protobuf/io/tokenizer.h \
+	google/protobuf/io/zero_copy_stream.h \
+	google/protobuf/io/zero_copy_stream_impl.h \
+	google/protobuf/io/zero_copy_stream_impl_lite.h \
+	google/protobuf/map.h google/protobuf/map_entry.h \
+	google/protobuf/map_entry_lite.h google/protobuf/map_field.h \
+	google/protobuf/map_field_inl.h \
+	google/protobuf/map_field_lite.h \
+	google/protobuf/map_type_handler.h google/protobuf/message.h \
+	google/protobuf/message_lite.h google/protobuf/metadata.h \
+	google/protobuf/metadata_lite.h \
+	google/protobuf/parse_context.h google/protobuf/port.h \
+	google/protobuf/port_def.inc google/protobuf/port_undef.inc \
+	google/protobuf/reflection.h \
+	google/protobuf/reflection_internal.h \
+	google/protobuf/reflection_ops.h \
+	google/protobuf/repeated_field.h \
+	google/protobuf/repeated_ptr_field.h google/protobuf/service.h \
+	google/protobuf/source_context.pb.h \
+	google/protobuf/struct.pb.h google/protobuf/stubs/bytestream.h \
+	google/protobuf/stubs/callback.h google/protobuf/stubs/casts.h \
+	google/protobuf/stubs/common.h google/protobuf/stubs/hash.h \
+	google/protobuf/stubs/logging.h google/protobuf/stubs/macros.h \
+	google/protobuf/stubs/map_util.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/status.h \
+	google/protobuf/stubs/stl_util.h \
+	google/protobuf/stubs/stringpiece.h \
+	google/protobuf/stubs/strutil.h \
+	google/protobuf/stubs/template_util.h \
+	google/protobuf/text_format.h google/protobuf/timestamp.pb.h \
+	google/protobuf/type.pb.h google/protobuf/unknown_field_set.h \
+	google/protobuf/util/delimited_message_util.h \
+	google/protobuf/util/field_comparator.h \
+	google/protobuf/util/field_mask_util.h \
+	google/protobuf/util/json_util.h \
+	google/protobuf/util/message_differencer.h \
+	google/protobuf/util/time_util.h \
+	google/protobuf/util/type_resolver.h \
+	google/protobuf/util/type_resolver_util.h \
+	google/protobuf/wire_format.h \
+	google/protobuf/wire_format_lite.h \
+	google/protobuf/wrappers.pb.h
+HEADERS = $(nobase_include_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+@HAVE_ZLIB_TRUE@am__EXEEXT_2 =  \
+@HAVE_ZLIB_TRUE@	google/protobuf/io/gzip_stream_unittest.sh
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+	$(top_srcdir)/test-driver README.md
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXCPPFLAGS_FOR_BUILD = @CXXCPPFLAGS_FOR_BUILD@
+CXXCPP_FOR_BUILD = @CXXCPP_FOR_BUILD@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@
+CXX_FOR_BUILD = @CXX_FOR_BUILD@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DIST_LANG = @DIST_LANG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+ISAINFO = @ISAINFO@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBATOMIC_LIBS = @LIBATOMIC_LIBS@
+LIBLOG_LIBS = @LIBLOG_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POW_LIB = @POW_LIB@
+PROTOBUF_OPT_FLAG = @PROTOBUF_OPT_FLAG@
+PROTOC = @PROTOC@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_CXX_FOR_BUILD = @ac_ct_CXX_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@HAVE_ZLIB_FALSE@GZCHECKPROGRAMS = 
+@HAVE_ZLIB_TRUE@GZCHECKPROGRAMS = zcgzip zcgunzip
+@HAVE_ZLIB_FALSE@GZHEADERS = 
+@HAVE_ZLIB_TRUE@GZHEADERS = google/protobuf/io/gzip_stream.h
+@HAVE_ZLIB_FALSE@GZTESTS = 
+@HAVE_ZLIB_TRUE@GZTESTS = google/protobuf/io/gzip_stream_unittest.sh
+@HAVE_ZLIB_FALSE@ZLIB_DEF = 
+@HAVE_ZLIB_TRUE@ZLIB_DEF = -DHAVE_ZLIB=1
+@HAVE_PTHREAD_FALSE@PTHREAD_DEF = 
+@HAVE_PTHREAD_TRUE@PTHREAD_DEF = -DHAVE_PTHREAD=1
+PROTOBUF_VERSION = 32:9:0
+@GCC_FALSE@NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF)
+
+# Turn on all warnings except for sign comparison (we ignore sign comparison
+# in Google so our code base have tons of such warnings).
+@GCC_TRUE@NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wno-sign-compare
+AM_CXXFLAGS = $(NO_OPT_CXXFLAGS) $(PROTOBUF_OPT_FLAG)
+AM_LDFLAGS = $(PTHREAD_CFLAGS) ${LIBLOG_LIBS}
+
+# If I say "dist_include_DATA", automake complains that $(includedir) is not
+# a "legitimate" directory for DATA.  Screw you, automake.
+protodir = $(includedir)
+
+# If you are adding new files here, also remember to change the build files for
+# all other languages, //protoc-artifacts/build-zip.sh and run
+# //update_file_list.sh for bazel.
+nobase_dist_proto_DATA = \
+  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
+
+CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
+             testzip.jar testzip.list testzip.proto testzip.zip \
+             no_warning_test.cc
+
+MAINTAINERCLEANFILES = \
+  Makefile.in
+
+nobase_include_HEADERS = \
+  google/protobuf/any.h                                          \
+  google/protobuf/any.pb.h                                       \
+  google/protobuf/api.pb.h                                       \
+  google/protobuf/arena.h                                        \
+  google/protobuf/arena_impl.h                                   \
+  google/protobuf/arenastring.h                                  \
+  google/protobuf/arenaz_sampler.h                               \
+  google/protobuf/compiler/code_generator.h                      \
+  google/protobuf/compiler/command_line_interface.h              \
+  google/protobuf/compiler/cpp/cpp_generator.h                   \
+  google/protobuf/compiler/cpp/file.h                            \
+  google/protobuf/compiler/cpp/generator.h                       \
+  google/protobuf/compiler/cpp/helpers.h                         \
+  google/protobuf/compiler/cpp/names.h                           \
+  google/protobuf/compiler/csharp/csharp_doc_comment.h           \
+  google/protobuf/compiler/csharp/csharp_generator.h             \
+  google/protobuf/compiler/csharp/csharp_names.h                 \
+  google/protobuf/compiler/csharp/csharp_options.h               \
+  google/protobuf/compiler/importer.h                            \
+  google/protobuf/compiler/java/generator.h                      \
+  google/protobuf/compiler/java/java_generator.h                 \
+  google/protobuf/compiler/java/kotlin_generator.h               \
+  google/protobuf/compiler/java/names.h                          \
+  google/protobuf/compiler/objectivec/objectivec_generator.h     \
+  google/protobuf/compiler/objectivec/objectivec_helpers.h       \
+  google/protobuf/compiler/parser.h                              \
+  google/protobuf/compiler/php/php_generator.h                   \
+  google/protobuf/compiler/plugin.h                              \
+  google/protobuf/compiler/plugin.pb.h                           \
+  google/protobuf/compiler/python/generator.h                    \
+  google/protobuf/compiler/python/pyi_generator.h                \
+  google/protobuf/compiler/python/python_generator.h             \
+  google/protobuf/compiler/ruby/ruby_generator.h                 \
+  google/protobuf/descriptor.h                                   \
+  google/protobuf/descriptor.pb.h                                \
+  google/protobuf/descriptor_database.h                          \
+  google/protobuf/duration.pb.h                                  \
+  google/protobuf/dynamic_message.h                              \
+  google/protobuf/empty.pb.h                                     \
+  google/protobuf/endian.h                                       \
+  google/protobuf/explicitly_constructed.h                       \
+  google/protobuf/extension_set.h                                \
+  google/protobuf/extension_set_inl.h                            \
+  google/protobuf/field_access_listener.h                        \
+  google/protobuf/field_mask.pb.h                                \
+  google/protobuf/generated_enum_reflection.h                    \
+  google/protobuf/generated_enum_util.h                          \
+  google/protobuf/generated_message_bases.h                      \
+  google/protobuf/generated_message_reflection.h                 \
+  google/protobuf/generated_message_tctable_decl.h               \
+  google/protobuf/generated_message_tctable_impl.h               \
+  google/protobuf/generated_message_util.h                       \
+  google/protobuf/has_bits.h                                     \
+  google/protobuf/implicit_weak_message.h                        \
+  google/protobuf/inlined_string_field.h                         \
+  google/protobuf/io/coded_stream.h                              \
+  $(GZHEADERS)                                                   \
+  google/protobuf/io/io_win32.h                                  \
+  google/protobuf/io/printer.h                                   \
+  google/protobuf/io/strtod.h                                    \
+  google/protobuf/io/tokenizer.h                                 \
+  google/protobuf/io/zero_copy_stream.h                          \
+  google/protobuf/io/zero_copy_stream_impl.h                     \
+  google/protobuf/io/zero_copy_stream_impl_lite.h                \
+  google/protobuf/map.h                                          \
+  google/protobuf/map_entry.h                                    \
+  google/protobuf/map_entry_lite.h                               \
+  google/protobuf/map_field.h                                    \
+  google/protobuf/map_field_inl.h                                \
+  google/protobuf/map_field_lite.h                               \
+  google/protobuf/map_type_handler.h                             \
+  google/protobuf/message.h                                      \
+  google/protobuf/message_lite.h                                 \
+  google/protobuf/metadata.h                                     \
+  google/protobuf/metadata_lite.h                                \
+  google/protobuf/parse_context.h                                \
+  google/protobuf/port.h                                         \
+  google/protobuf/port_def.inc                                   \
+  google/protobuf/port_undef.inc                                 \
+  google/protobuf/reflection.h                                   \
+  google/protobuf/reflection_internal.h                          \
+  google/protobuf/reflection_ops.h                               \
+  google/protobuf/repeated_field.h                               \
+  google/protobuf/repeated_ptr_field.h                           \
+  google/protobuf/service.h                                      \
+  google/protobuf/source_context.pb.h                            \
+  google/protobuf/struct.pb.h                                    \
+  google/protobuf/stubs/bytestream.h                             \
+  google/protobuf/stubs/callback.h                               \
+  google/protobuf/stubs/casts.h                                  \
+  google/protobuf/stubs/common.h                                 \
+  google/protobuf/stubs/hash.h                                   \
+  google/protobuf/stubs/logging.h                                \
+  google/protobuf/stubs/macros.h                                 \
+  google/protobuf/stubs/map_util.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/status.h                                 \
+  google/protobuf/stubs/stl_util.h                               \
+  google/protobuf/stubs/stringpiece.h                            \
+  google/protobuf/stubs/strutil.h                                \
+  google/protobuf/stubs/template_util.h                          \
+  google/protobuf/text_format.h                                  \
+  google/protobuf/timestamp.pb.h                                 \
+  google/protobuf/type.pb.h                                      \
+  google/protobuf/unknown_field_set.h                            \
+  google/protobuf/util/delimited_message_util.h                  \
+  google/protobuf/util/field_comparator.h                        \
+  google/protobuf/util/field_mask_util.h                         \
+  google/protobuf/util/json_util.h                               \
+  google/protobuf/util/message_differencer.h                     \
+  google/protobuf/util/time_util.h                               \
+  google/protobuf/util/type_resolver.h                           \
+  google/protobuf/util/type_resolver_util.h                      \
+  google/protobuf/wire_format.h                                  \
+  google/protobuf/wire_format_lite.h                             \
+  google/protobuf/wrappers.pb.h
+
+lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
+libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS) $(LIBATOMIC_LIBS)
+libprotobuf_lite_la_LDFLAGS = -version-info $(PROTOBUF_VERSION) \
+	-export-dynamic -no-undefined $(am__append_1)
+@HAVE_LD_VERSION_SCRIPT_TRUE@EXTRA_libprotobuf_lite_la_DEPENDENCIES = libprotobuf-lite.map
+libprotobuf_lite_la_SOURCES = \
+  google/protobuf/any_lite.cc                                  \
+  google/protobuf/arena.cc                                     \
+  google/protobuf/arenastring.cc                               \
+  google/protobuf/arenaz_sampler.cc                            \
+  google/protobuf/extension_set.cc                             \
+  google/protobuf/generated_enum_util.cc                       \
+  google/protobuf/generated_message_tctable_lite.cc            \
+  google/protobuf/generated_message_util.cc                    \
+  google/protobuf/implicit_weak_message.cc                     \
+  google/protobuf/inlined_string_field.cc                      \
+  google/protobuf/io/coded_stream.cc                           \
+  google/protobuf/io/io_win32.cc                               \
+  google/protobuf/io/strtod.cc                                 \
+  google/protobuf/io/zero_copy_stream.cc                       \
+  google/protobuf/io/zero_copy_stream_impl.cc                  \
+  google/protobuf/io/zero_copy_stream_impl_lite.cc             \
+  google/protobuf/map.cc                                       \
+  google/protobuf/message_lite.cc                              \
+  google/protobuf/parse_context.cc                             \
+  google/protobuf/repeated_field.cc                            \
+  google/protobuf/repeated_ptr_field.cc                        \
+  google/protobuf/string_member_robber.h                       \
+  google/protobuf/stubs/bytestream.cc                          \
+  google/protobuf/stubs/common.cc                              \
+  google/protobuf/stubs/int128.cc                              \
+  google/protobuf/stubs/int128.h                               \
+  google/protobuf/stubs/mathutil.h                             \
+  google/protobuf/stubs/status.cc                              \
+  google/protobuf/stubs/status_macros.h                        \
+  google/protobuf/stubs/statusor.cc                            \
+  google/protobuf/stubs/statusor.h                             \
+  google/protobuf/stubs/stringpiece.cc                         \
+  google/protobuf/stubs/stringprintf.cc                        \
+  google/protobuf/stubs/stringprintf.h                         \
+  google/protobuf/stubs/structurally_valid.cc                  \
+  google/protobuf/stubs/strutil.cc                             \
+  google/protobuf/stubs/time.cc                                \
+  google/protobuf/stubs/time.h                                 \
+  google/protobuf/wire_format_lite.cc
+
+libprotobuf_la_LIBADD = $(PTHREAD_LIBS) $(LIBATOMIC_LIBS)
+libprotobuf_la_LDFLAGS = -version-info $(PROTOBUF_VERSION) \
+	-export-dynamic -no-undefined $(am__append_2)
+@HAVE_LD_VERSION_SCRIPT_TRUE@EXTRA_libprotobuf_la_DEPENDENCIES = libprotobuf.map
+libprotobuf_la_SOURCES = \
+  $(libprotobuf_lite_la_SOURCES)                               \
+  google/protobuf/any.cc                                       \
+  google/protobuf/any.pb.cc                                    \
+  google/protobuf/api.pb.cc                                    \
+  google/protobuf/compiler/importer.cc                         \
+  google/protobuf/compiler/parser.cc                           \
+  google/protobuf/descriptor.cc                                \
+  google/protobuf/descriptor.pb.cc                             \
+  google/protobuf/descriptor_database.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_bases.cc                   \
+  google/protobuf/generated_message_reflection.cc              \
+  google/protobuf/generated_message_tctable_full.cc            \
+  google/protobuf/io/gzip_stream.cc                            \
+  google/protobuf/io/printer.cc                                \
+  google/protobuf/io/tokenizer.cc                              \
+  google/protobuf/map_field.cc                                 \
+  google/protobuf/message.cc                                   \
+  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/util/delimited_message_util.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/proto_writer.cc                \
+  google/protobuf/util/internal/proto_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/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.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                   \
+  google/protobuf/wire_format.cc                               \
+  google/protobuf/wrappers.pb.cc
+
+nodist_libprotobuf_la_SOURCES = $(nodist_libprotobuf_lite_la_SOURCES)
+libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
+libprotoc_la_LDFLAGS = -version-info $(PROTOBUF_VERSION) \
+	-export-dynamic -no-undefined $(am__append_3)
+@HAVE_LD_VERSION_SCRIPT_TRUE@EXTRA_libprotoc_la_DEPENDENCIES = libprotoc.map
+libprotoc_la_SOURCES = \
+  google/protobuf/compiler/code_generator.cc                   \
+  google/protobuf/compiler/command_line_interface.cc           \
+  google/protobuf/compiler/cpp/enum.cc                         \
+  google/protobuf/compiler/cpp/enum.h                          \
+  google/protobuf/compiler/cpp/enum_field.cc                   \
+  google/protobuf/compiler/cpp/enum_field.h                    \
+  google/protobuf/compiler/cpp/extension.cc                    \
+  google/protobuf/compiler/cpp/extension.h                     \
+  google/protobuf/compiler/cpp/field.cc                        \
+  google/protobuf/compiler/cpp/field.h                         \
+  google/protobuf/compiler/cpp/file.cc                         \
+  google/protobuf/compiler/cpp/generator.cc                    \
+  google/protobuf/compiler/cpp/helpers.cc                      \
+  google/protobuf/compiler/cpp/map_field.cc                    \
+  google/protobuf/compiler/cpp/map_field.h                     \
+  google/protobuf/compiler/cpp/message.cc                      \
+  google/protobuf/compiler/cpp/message.h                       \
+  google/protobuf/compiler/cpp/message_field.cc                \
+  google/protobuf/compiler/cpp/message_field.h                 \
+  google/protobuf/compiler/cpp/message_layout_helper.h         \
+  google/protobuf/compiler/cpp/options.h                       \
+  google/protobuf/compiler/cpp/padding_optimizer.cc            \
+  google/protobuf/compiler/cpp/padding_optimizer.h             \
+  google/protobuf/compiler/cpp/parse_function_generator.cc     \
+  google/protobuf/compiler/cpp/parse_function_generator.h      \
+  google/protobuf/compiler/cpp/primitive_field.cc              \
+  google/protobuf/compiler/cpp/primitive_field.h               \
+  google/protobuf/compiler/cpp/service.cc                      \
+  google/protobuf/compiler/cpp/service.h                       \
+  google/protobuf/compiler/cpp/string_field.cc                 \
+  google/protobuf/compiler/cpp/string_field.h                  \
+  google/protobuf/compiler/csharp/csharp_doc_comment.cc        \
+  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       \
+  google/protobuf/compiler/java/context.cc                     \
+  google/protobuf/compiler/java/context.h                      \
+  google/protobuf/compiler/java/doc_comment.cc                 \
+  google/protobuf/compiler/java/doc_comment.h                  \
+  google/protobuf/compiler/java/enum.cc                        \
+  google/protobuf/compiler/java/enum.h                         \
+  google/protobuf/compiler/java/enum_field.cc                  \
+  google/protobuf/compiler/java/enum_field.h                   \
+  google/protobuf/compiler/java/enum_field_lite.cc             \
+  google/protobuf/compiler/java/enum_field_lite.h              \
+  google/protobuf/compiler/java/enum_lite.cc                   \
+  google/protobuf/compiler/java/enum_lite.h                    \
+  google/protobuf/compiler/java/extension.cc                   \
+  google/protobuf/compiler/java/extension.h                    \
+  google/protobuf/compiler/java/extension_lite.cc              \
+  google/protobuf/compiler/java/extension_lite.h               \
+  google/protobuf/compiler/java/field.cc                       \
+  google/protobuf/compiler/java/field.h                        \
+  google/protobuf/compiler/java/file.cc                        \
+  google/protobuf/compiler/java/file.h                         \
+  google/protobuf/compiler/java/generator.cc                   \
+  google/protobuf/compiler/java/generator_factory.cc           \
+  google/protobuf/compiler/java/generator_factory.h            \
+  google/protobuf/compiler/java/helpers.cc                     \
+  google/protobuf/compiler/java/helpers.h                      \
+  google/protobuf/compiler/java/kotlin_generator.cc            \
+  google/protobuf/compiler/java/map_field.cc                   \
+  google/protobuf/compiler/java/map_field.h                    \
+  google/protobuf/compiler/java/map_field_lite.cc              \
+  google/protobuf/compiler/java/map_field_lite.h               \
+  google/protobuf/compiler/java/message.cc                     \
+  google/protobuf/compiler/java/message.h                      \
+  google/protobuf/compiler/java/message_builder.cc             \
+  google/protobuf/compiler/java/message_builder.h              \
+  google/protobuf/compiler/java/message_builder_lite.cc        \
+  google/protobuf/compiler/java/message_builder_lite.h         \
+  google/protobuf/compiler/java/message_field.cc               \
+  google/protobuf/compiler/java/message_field.h                \
+  google/protobuf/compiler/java/message_field_lite.cc          \
+  google/protobuf/compiler/java/message_field_lite.h           \
+  google/protobuf/compiler/java/message_lite.cc                \
+  google/protobuf/compiler/java/message_lite.h                 \
+  google/protobuf/compiler/java/name_resolver.cc               \
+  google/protobuf/compiler/java/name_resolver.h                \
+  google/protobuf/compiler/java/options.h                      \
+  google/protobuf/compiler/java/primitive_field.cc             \
+  google/protobuf/compiler/java/primitive_field.h              \
+  google/protobuf/compiler/java/primitive_field_lite.cc        \
+  google/protobuf/compiler/java/primitive_field_lite.h         \
+  google/protobuf/compiler/java/service.cc                     \
+  google/protobuf/compiler/java/service.h                      \
+  google/protobuf/compiler/java/shared_code_generator.cc       \
+  google/protobuf/compiler/java/shared_code_generator.h        \
+  google/protobuf/compiler/java/string_field.cc                \
+  google/protobuf/compiler/java/string_field.h                 \
+  google/protobuf/compiler/java/string_field_lite.cc           \
+  google/protobuf/compiler/java/string_field_lite.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_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_nsobject_methods.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/php/php_generator.cc                \
+  google/protobuf/compiler/plugin.cc                           \
+  google/protobuf/compiler/plugin.pb.cc                        \
+  google/protobuf/compiler/python/generator.cc                 \
+  google/protobuf/compiler/python/helpers.cc                   \
+  google/protobuf/compiler/python/helpers.h                    \
+  google/protobuf/compiler/python/pyi_generator.cc             \
+  google/protobuf/compiler/ruby/ruby_generator.cc              \
+  google/protobuf/compiler/scc.h                               \
+  google/protobuf/compiler/subprocess.cc                       \
+  google/protobuf/compiler/subprocess.h                        \
+  google/protobuf/compiler/zip_writer.cc                       \
+  google/protobuf/compiler/zip_writer.h
+
+protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
+protoc_SOURCES = google/protobuf/compiler/main.cc
+
+# Tests ==============================================================
+protoc_inputs = \
+  google/protobuf/any_test.proto                                  \
+  google/protobuf/compiler/cpp/test_bad_identifiers.proto         \
+  google/protobuf/compiler/cpp/test_large_enum_value.proto        \
+  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_enormous_descriptor.proto              \
+  google/protobuf/unittest_import.proto                           \
+  google/protobuf/unittest_import_lite.proto                      \
+  google/protobuf/unittest_import_public.proto                    \
+  google/protobuf/unittest_import_public_lite.proto               \
+  google/protobuf/unittest_lazy_dependencies.proto                \
+  google/protobuf/unittest_lazy_dependencies_custom_option.proto  \
+  google/protobuf/unittest_lazy_dependencies_enum.proto           \
+  google/protobuf/unittest_lite.proto                             \
+  google/protobuf/unittest_lite_imports_nonlite.proto             \
+  google/protobuf/unittest_mset.proto                             \
+  google/protobuf/unittest_mset_wire_format.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.proto                           \
+  google/protobuf/unittest_proto3_arena.proto                     \
+  google/protobuf/unittest_proto3_arena_lite.proto                \
+  google/protobuf/unittest_proto3_lite.proto                      \
+  google/protobuf/unittest_proto3_optional.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/proto3.proto             \
+  google/protobuf/util/internal/testdata/struct.proto             \
+  google/protobuf/util/internal/testdata/timestamp_duration.proto \
+  google/protobuf/util/internal/testdata/wrappers.proto           \
+  google/protobuf/util/json_format.proto                          \
+  google/protobuf/util/json_format_proto3.proto                   \
+  google/protobuf/util/message_differencer_unittest.proto
+
+EXTRA_DIST = \
+  $(protoc_inputs)                                             \
+  README.md                                                    \
+  google/protobuf/compiler/package_info.h                      \
+  google/protobuf/compiler/ruby/ruby_generated_code.proto      \
+  google/protobuf/compiler/ruby/ruby_generated_code_pb.rb      \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto \
+  google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto \
+  google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb \
+  google/protobuf/compiler/zip_output_unittest.sh              \
+  google/protobuf/io/gzip_stream.h                             \
+  google/protobuf/io/gzip_stream_unittest.sh                   \
+  google/protobuf/io/package_info.h                            \
+  google/protobuf/package_info.h                               \
+  google/protobuf/test_messages_proto2.proto                   \
+  google/protobuf/test_messages_proto3.proto                   \
+  google/protobuf/testdata/bad_utf8_string                     \
+  google/protobuf/testdata/golden_message                      \
+  google/protobuf/testdata/golden_message_maps                 \
+  google/protobuf/testdata/golden_message_oneof_implemented    \
+  google/protobuf/testdata/golden_message_proto3               \
+  google/protobuf/testdata/golden_packed_fields_message        \
+  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 \
+  google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt \
+  google/protobuf/testdata/text_format_unittest_extensions_data.txt \
+  google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt \
+  google/protobuf/util/package_info.h                          \
+  libprotobuf-lite.map                                         \
+  libprotobuf.map                                              \
+  libprotoc.map                                                \
+  solaris/libstdc++.la                                        
+
+protoc_lite_outputs = \
+  google/protobuf/map_lite_unittest.pb.cc                      \
+  google/protobuf/map_lite_unittest.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             \
+  google/protobuf/unittest_lite.pb.cc                          \
+  google/protobuf/unittest_lite.pb.h
+
+protoc_outputs = \
+  $(protoc_lite_outputs)                                          \
+  google/protobuf/any_test.pb.cc                                  \
+  google/protobuf/any_test.pb.h                                   \
+  google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc         \
+  google/protobuf/compiler/cpp/test_bad_identifiers.pb.h          \
+  google/protobuf/compiler/cpp/test_large_enum_value.pb.cc        \
+  google/protobuf/compiler/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.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_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_lazy_dependencies.pb.cc                \
+  google/protobuf/unittest_lazy_dependencies.pb.h                 \
+  google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc  \
+  google/protobuf/unittest_lazy_dependencies_custom_option.pb.h   \
+  google/protobuf/unittest_lazy_dependencies_enum.pb.cc           \
+  google/protobuf/unittest_lazy_dependencies_enum.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_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.pb.cc                           \
+  google/protobuf/unittest_proto3.pb.h                            \
+  google/protobuf/unittest_proto3_arena.pb.cc                     \
+  google/protobuf/unittest_proto3_arena.pb.h                      \
+  google/protobuf/unittest_proto3_arena_lite.pb.cc                \
+  google/protobuf/unittest_proto3_arena_lite.pb.h                 \
+  google/protobuf/unittest_proto3_lite.pb.cc                      \
+  google/protobuf/unittest_proto3_lite.pb.h                       \
+  google/protobuf/unittest_proto3_optional.pb.cc                  \
+  google/protobuf/unittest_proto3_optional.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/proto3.pb.cc             \
+  google/protobuf/util/internal/testdata/proto3.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/internal/testdata/wrappers.pb.cc           \
+  google/protobuf/util/internal/testdata/wrappers.pb.h            \
+  google/protobuf/util/json_format.pb.cc                          \
+  google/protobuf/util/json_format.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
+
+COMMON_TEST_SOURCES = \
+  $(COMMON_LITE_TEST_SOURCES)                                  \
+  google/protobuf/compiler/cpp/unittest.h                      \
+  google/protobuf/map_test_util.h                              \
+  google/protobuf/map_test_util.inc                            \
+  google/protobuf/reflection_tester.cc                         \
+  google/protobuf/reflection_tester.h                          \
+  google/protobuf/test_util.cc                                 \
+  google/protobuf/test_util.h                                  \
+  google/protobuf/test_util.inc                                \
+  google/protobuf/test_util2.h                                 \
+  google/protobuf/testing/file.cc                              \
+  google/protobuf/testing/file.h                               \
+  google/protobuf/testing/googletest.cc                        \
+  google/protobuf/testing/googletest.h
+
+GOOGLETEST_BUILD_DIR = ../third_party/googletest/googletest
+GOOGLEMOCK_BUILD_DIR = ../third_party/googletest/googlemock
+GOOGLETEST_SRC_DIR = $(srcdir)/../third_party/googletest/googletest
+GOOGLEMOCK_SRC_DIR = $(srcdir)/../third_party/googletest/googlemock
+protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
+                      $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la     \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la     \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+
+protobuf_test_CPPFLAGS = -I$(GOOGLETEST_SRC_DIR)/include \
+                         -I$(GOOGLEMOCK_SRC_DIR)/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 = \
+  $(COMMON_TEST_SOURCES)                                       \
+  google/protobuf/any_test.cc                                  \
+  google/protobuf/arena_unittest.cc                            \
+  google/protobuf/arenastring_unittest.cc                      \
+  google/protobuf/arenaz_sampler_test.cc                       \
+  google/protobuf/compiler/annotation_test_util.cc             \
+  google/protobuf/compiler/annotation_test_util.h              \
+  google/protobuf/compiler/command_line_interface_unittest.cc  \
+  google/protobuf/compiler/cpp/bootstrap_unittest.cc           \
+  google/protobuf/compiler/cpp/message_size_unittest.cc        \
+  google/protobuf/compiler/cpp/metadata_test.cc                \
+  google/protobuf/compiler/cpp/move_unittest.cc                \
+  google/protobuf/compiler/cpp/plugin_unittest.cc              \
+  google/protobuf/compiler/cpp/unittest.cc                     \
+  google/protobuf/compiler/cpp/unittest.inc                    \
+  google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc \
+  google/protobuf/compiler/csharp/csharp_generator_unittest.cc \
+  google/protobuf/compiler/importer_unittest.cc                \
+  google/protobuf/compiler/java/doc_comment_unittest.cc        \
+  google/protobuf/compiler/java/plugin_unittest.cc             \
+  google/protobuf/compiler/mock_code_generator.cc              \
+  google/protobuf/compiler/mock_code_generator.h               \
+  google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc \
+  google/protobuf/compiler/parser_unittest.cc                  \
+  google/protobuf/compiler/python/plugin_unittest.cc           \
+  google/protobuf/compiler/ruby/ruby_generator_unittest.cc     \
+  google/protobuf/descriptor_database_unittest.cc              \
+  google/protobuf/descriptor_unittest.cc                       \
+  google/protobuf/drop_unknown_fields_test.cc                  \
+  google/protobuf/dynamic_message_unittest.cc                  \
+  google/protobuf/extension_set_unittest.cc                    \
+  google/protobuf/generated_message_reflection_unittest.cc     \
+  google/protobuf/generated_message_tctable_lite_test.cc       \
+  google/protobuf/inlined_string_field_unittest.cc             \
+  google/protobuf/io/coded_stream_unittest.cc                  \
+  google/protobuf/io/io_win32_unittest.cc                      \
+  google/protobuf/io/printer_unittest.cc                       \
+  google/protobuf/io/tokenizer_unittest.cc                     \
+  google/protobuf/io/zero_copy_stream_unittest.cc              \
+  google/protobuf/map_field_test.cc                            \
+  google/protobuf/map_test.cc                                  \
+  google/protobuf/map_test.inc                                 \
+  google/protobuf/message_unittest.cc                          \
+  google/protobuf/message_unittest.inc                         \
+  google/protobuf/no_field_presence_test.cc                    \
+  google/protobuf/preserve_unknown_enum_test.cc                \
+  google/protobuf/proto3_arena_lite_unittest.cc                \
+  google/protobuf/proto3_arena_unittest.cc                     \
+  google/protobuf/proto3_lite_unittest.cc                      \
+  google/protobuf/proto3_lite_unittest.inc                     \
+  google/protobuf/reflection_ops_unittest.cc                   \
+  google/protobuf/repeated_field_reflection_unittest.cc        \
+  google/protobuf/repeated_field_unittest.cc                   \
+  google/protobuf/stubs/bytestream_unittest.cc                 \
+  google/protobuf/stubs/common_unittest.cc                     \
+  google/protobuf/stubs/int128_unittest.cc                     \
+  google/protobuf/stubs/status_test.cc                         \
+  google/protobuf/stubs/statusor_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/text_format_unittest.cc                      \
+  google/protobuf/unknown_field_set_unittest.cc                \
+  google/protobuf/util/delimited_message_util_test.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              \
+  google/protobuf/well_known_types_unittest.cc                 \
+  google/protobuf/wire_format_unittest.cc                      \
+  google/protobuf/wire_format_unittest.inc
+
+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                                   \
+                      $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+
+protobuf_lazy_descriptor_test_CPPFLAGS = -I$(GOOGLEMOCK_SRC_DIR)/include \
+                                         -I$(GOOGLETEST_SRC_DIR)/include \
+                                         -DPROTOBUF_TEST_NO_DESCRIPTORS
+
+protobuf_lazy_descriptor_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
+protobuf_lazy_descriptor_test_SOURCES = \
+  google/protobuf/compiler/cpp/unittest.cc                     \
+  $(COMMON_TEST_SOURCES)
+
+nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs)
+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/map_test_util_impl.h                                 \
+  google/protobuf/test_util_lite.cc                                    \
+  google/protobuf/test_util_lite.h
+
+
+# Build lite_unittest separately, since it doesn't use gtest. It can't
+# depend on gtest because our internal version of gtest depend on proto
+# full runtime and we want to make sure this test builds without full
+# runtime.
+protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la     \
+                           $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la \
+                           $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la \
+                           $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+
+protobuf_lite_test_CPPFLAGS = -I$(GOOGLEMOCK_SRC_DIR)/include \
+                             -I$(GOOGLETEST_SRC_DIR)/include
+
+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 \
+                      $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock.la        \
+                      $(GOOGLEMOCK_BUILD_DIR)/lib/libgmock_main.la
+
+protobuf_lite_arena_test_CPPFLAGS = -I$(GOOGLEMOCK_SRC_DIR)/include  \
+                                    -I$(GOOGLETEST_SRC_DIR)/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 \
+                    $(GOOGLETEST_BUILD_DIR)/lib/libgtest.la
+
+test_plugin_CPPFLAGS = -I$(GOOGLETEST_SRC_DIR)/include
+test_plugin_SOURCES = \
+  google/protobuf/compiler/mock_code_generator.cc              \
+  google/protobuf/compiler/test_plugin.cc                      \
+  google/protobuf/testing/file.cc                              \
+  google/protobuf/testing/file.h
+
+@HAVE_ZLIB_TRUE@zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
+@HAVE_ZLIB_TRUE@zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc
+@HAVE_ZLIB_TRUE@zcgunzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
+@HAVE_ZLIB_TRUE@zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc
+no_warning_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
+no_warning_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) \
+                           -Wall -Wextra -Werror -Wno-unused-parameter
+
+nodist_no_warning_test_SOURCES = no_warning_test.cc $(protoc_outputs)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+	fi; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p \
+	 || test -f $$p1 \
+	  ; then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' \
+	    -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' \
+	`; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+google/protobuf/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf
+	@: > google/protobuf/$(am__dirstamp)
+google/protobuf/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/$(DEPDIR)
+	@: > google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/any_lite.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/arena.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/arenastring.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/arenaz_sampler.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/extension_set.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/generated_enum_util.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/generated_message_tctable_lite.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/generated_message_util.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/implicit_weak_message.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/inlined_string_field.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/io
+	@: > google/protobuf/io/$(am__dirstamp)
+google/protobuf/io/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/io/$(DEPDIR)
+	@: > google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/coded_stream.lo:  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/io_win32.lo: google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/strtod.lo: google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/zero_copy_stream.lo:  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/zero_copy_stream_impl.lo:  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/zero_copy_stream_impl_lite.lo:  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/map.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/message_lite.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/parse_context.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/repeated_field.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/repeated_ptr_field.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/stubs
+	@: > google/protobuf/stubs/$(am__dirstamp)
+google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/stubs/$(DEPDIR)
+	@: > google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/bytestream.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/common.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/int128.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/status.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/statusor.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/stringpiece.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/stringprintf.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/structurally_valid.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/strutil.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/time.lo: google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/wire_format_lite.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+
+libprotobuf-lite.la: $(libprotobuf_lite_la_OBJECTS) $(libprotobuf_lite_la_DEPENDENCIES) $(EXTRA_libprotobuf_lite_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(libprotobuf_lite_la_LINK) -rpath $(libdir) $(libprotobuf_lite_la_OBJECTS) $(libprotobuf_lite_la_LIBADD) $(LIBS)
+google/protobuf/any.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/any.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/api.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler
+	@: > google/protobuf/compiler/$(am__dirstamp)
+google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/$(DEPDIR)
+	@: > google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/importer.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/parser.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/descriptor.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/descriptor.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/descriptor_database.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/duration.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/dynamic_message.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/empty.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/extension_set_heavy.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/field_mask.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/generated_message_bases.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/generated_message_reflection.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/generated_message_tctable_full.lo:  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/gzip_stream.lo: google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/printer.lo: google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/tokenizer.lo: google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/map_field.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/message.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/reflection_ops.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/service.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/source_context.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/struct.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/substitute.lo:  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/text_format.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/timestamp.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/type.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/unknown_field_set.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/util
+	@: > google/protobuf/util/$(am__dirstamp)
+google/protobuf/util/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/util/$(DEPDIR)
+	@: > google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/delimited_message_util.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/field_comparator.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/field_mask_util.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/util/internal
+	@: > google/protobuf/util/internal/$(am__dirstamp)
+google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/util/internal/$(DEPDIR)
+	@: > google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/datapiece.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/default_value_objectwriter.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/error_listener.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/field_mask_utility.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/json_escaping.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/json_objectwriter.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/json_stream_parser.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/object_writer.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/proto_writer.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protostream_objectsource.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protostream_objectwriter.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/type_info.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/utility.lo:  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/json_util.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/message_differencer.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/time_util.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/type_resolver_util.lo:  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/wire_format.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/wrappers.pb.lo: google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+
+libprotobuf.la: $(libprotobuf_la_OBJECTS) $(libprotobuf_la_DEPENDENCIES) $(EXTRA_libprotobuf_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(libprotobuf_la_LINK) -rpath $(libdir) $(libprotobuf_la_OBJECTS) $(libprotobuf_la_LIBADD) $(LIBS)
+google/protobuf/compiler/code_generator.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/command_line_interface.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/cpp
+	@: > google/protobuf/compiler/cpp/$(am__dirstamp)
+google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/cpp/$(DEPDIR)
+	@: > google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/enum.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/enum_field.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/extension.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/field.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/file.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/generator.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/helpers.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/map_field.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/message.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/message_field.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/padding_optimizer.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/parse_function_generator.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/primitive_field.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/service.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/string_field.lo:  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/csharp
+	@: > google/protobuf/compiler/csharp/$(am__dirstamp)
+google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/csharp/$(DEPDIR)
+	@: > google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_doc_comment.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_enum.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_enum_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_field_base.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_generator.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_helpers.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_map_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_message.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_message_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_primitive_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_reflection_class.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_repeated_enum_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_repeated_message_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_repeated_primitive_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_source_generator_base.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/csharp_wrapper_field.lo:  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/java
+	@: > google/protobuf/compiler/java/$(am__dirstamp)
+google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/java/$(DEPDIR)
+	@: > google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/context.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/doc_comment.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/enum.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/enum_field.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/enum_field_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/enum_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/extension.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/extension_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/field.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/file.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/generator.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/generator_factory.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/helpers.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/kotlin_generator.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/map_field.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/map_field_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/message.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/message_builder.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/message_builder_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/message_field.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/message_field_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/message_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/name_resolver.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/primitive_field.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/primitive_field_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/service.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/shared_code_generator.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/string_field.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/string_field_lite.lo:  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/objectivec
+	@: > google/protobuf/compiler/objectivec/$(am__dirstamp)
+google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/objectivec/$(DEPDIR)
+	@: > google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_enum.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_enum_field.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_extension.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_field.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_file.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_generator.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_helpers.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_map_field.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_message.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_message_field.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_oneof.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/objectivec_primitive_field.lo:  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/php/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/php
+	@: > google/protobuf/compiler/php/$(am__dirstamp)
+google/protobuf/compiler/php/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/php/$(DEPDIR)
+	@: > google/protobuf/compiler/php/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/php/php_generator.lo:  \
+	google/protobuf/compiler/php/$(am__dirstamp) \
+	google/protobuf/compiler/php/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/plugin.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/plugin.pb.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/python/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/python
+	@: > google/protobuf/compiler/python/$(am__dirstamp)
+google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/python/$(DEPDIR)
+	@: > google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/python/generator.lo:  \
+	google/protobuf/compiler/python/$(am__dirstamp) \
+	google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/python/helpers.lo:  \
+	google/protobuf/compiler/python/$(am__dirstamp) \
+	google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/python/pyi_generator.lo:  \
+	google/protobuf/compiler/python/$(am__dirstamp) \
+	google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/ruby/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/ruby
+	@: > google/protobuf/compiler/ruby/$(am__dirstamp)
+google/protobuf/compiler/ruby/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/compiler/ruby/$(DEPDIR)
+	@: > google/protobuf/compiler/ruby/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/ruby/ruby_generator.lo:  \
+	google/protobuf/compiler/ruby/$(am__dirstamp) \
+	google/protobuf/compiler/ruby/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/subprocess.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/zip_writer.lo:  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+
+libprotoc.la: $(libprotoc_la_OBJECTS) $(libprotoc_la_DEPENDENCIES) $(EXTRA_libprotoc_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(libprotoc_la_LINK) -rpath $(libdir) $(libprotoc_la_OBJECTS) $(libprotoc_la_LIBADD) $(LIBS)
+google/protobuf/no_warning_test-map_lite_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_import_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_import_public_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-any_test.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-map_proto2_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-map_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_arena.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_custom_options.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_empty.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_import.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_import_public.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_mset.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_mset_wire_format.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_no_field_presence.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_no_generic_services.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_optimize_for.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_proto3.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_proto3_arena.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_proto3_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_proto3_optional.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/no_warning_test-unittest_well_known_types.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/util/internal/testdata
+	@: > google/protobuf/util/internal/testdata/$(am__dirstamp)
+google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/util/internal/testdata/$(DEPDIR)
+	@: > google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-anys.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-books.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-maps.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-struct.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/no_warning_test-json_format.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/no_warning_test-json_format_proto3.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/no_warning_test-message_differencer_unittest.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+
+no-warning-test$(EXEEXT): $(no_warning_test_OBJECTS) $(no_warning_test_DEPENDENCIES) $(EXTRA_no_warning_test_DEPENDENCIES) 
+	@rm -f no-warning-test$(EXEEXT)
+	$(AM_V_CXXLD)$(no_warning_test_LINK) $(no_warning_test_OBJECTS) $(no_warning_test_LDADD) $(LIBS)
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/testing/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/testing
+	@: > google/protobuf/testing/$(am__dirstamp)
+google/protobuf/testing/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) google/protobuf/testing/$(DEPDIR)
+	@: > google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/testing/protobuf_lazy_descriptor_test-file.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+
+protobuf-lazy-descriptor-test$(EXEEXT): $(protobuf_lazy_descriptor_test_OBJECTS) $(protobuf_lazy_descriptor_test_DEPENDENCIES) $(EXTRA_protobuf_lazy_descriptor_test_DEPENDENCIES) 
+	@rm -f protobuf-lazy-descriptor-test$(EXEEXT)
+	$(AM_V_CXXLD)$(protobuf_lazy_descriptor_test_LINK) $(protobuf_lazy_descriptor_test_OBJECTS) $(protobuf_lazy_descriptor_test_LDADD) $(LIBS)
+google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-arena_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-map_lite_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-test_util_lite.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+
+protobuf-lite-arena-test$(EXEEXT): $(protobuf_lite_arena_test_OBJECTS) $(protobuf_lite_arena_test_DEPENDENCIES) $(EXTRA_protobuf_lite_arena_test_DEPENDENCIES) 
+	@rm -f protobuf-lite-arena-test$(EXEEXT)
+	$(AM_V_CXXLD)$(protobuf_lite_arena_test_LINK) $(protobuf_lite_arena_test_OBJECTS) $(protobuf_lite_arena_test_LDADD) $(LIBS)
+google/protobuf/protobuf_lite_test-lite_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-arena_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-map_lite_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-test_util_lite.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-map_lite_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-unittest_import_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_lite_test-unittest_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+
+protobuf-lite-test$(EXEEXT): $(protobuf_lite_test_OBJECTS) $(protobuf_lite_test_DEPENDENCIES) $(EXTRA_protobuf_lite_test_DEPENDENCIES) 
+	@rm -f protobuf-lite-test$(EXEEXT)
+	$(AM_V_CXXLD)$(protobuf_lite_test_LINK) $(protobuf_lite_test_OBJECTS) $(protobuf_lite_test_LDADD) $(LIBS)
+google/protobuf/protobuf_test-arena_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-map_lite_test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-test_util_lite.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-reflection_tester.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-test_util.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/testing/protobuf_test-file.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/testing/protobuf_test-googletest.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-any_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-arena_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-arenastring_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-arenaz_sampler_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/protobuf_test-annotation_test_util.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/protobuf_test-command_line_interface_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-metadata_test.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-move_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-unittest.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/csharp/$(am__dirstamp) \
+	google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/protobuf_test-importer_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/java/protobuf_test-plugin_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/java/$(am__dirstamp) \
+	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/protobuf_test-mock_code_generator.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/objectivec/$(am__dirstamp) \
+	google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/protobuf_test-parser_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/python/protobuf_test-plugin_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/python/$(am__dirstamp) \
+	google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.$(OBJEXT):  \
+	google/protobuf/compiler/ruby/$(am__dirstamp) \
+	google/protobuf/compiler/ruby/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-descriptor_database_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-descriptor_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-drop_unknown_fields_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-dynamic_message_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-extension_set_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-generated_message_reflection_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-generated_message_tctable_lite_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-inlined_string_field_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/protobuf_test-coded_stream_unittest.$(OBJEXT):  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/protobuf_test-io_win32_unittest.$(OBJEXT):  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/protobuf_test-printer_unittest.$(OBJEXT):  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/protobuf_test-tokenizer_unittest.$(OBJEXT):  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/io/protobuf_test-zero_copy_stream_unittest.$(OBJEXT):  \
+	google/protobuf/io/$(am__dirstamp) \
+	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-map_field_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-map_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-message_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-no_field_presence_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-preserve_unknown_enum_test.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-proto3_arena_lite_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-proto3_arena_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-proto3_lite_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-reflection_ops_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-repeated_field_reflection_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-repeated_field_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-bytestream_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-common_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-int128_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-status_test.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-statusor_test.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-stringpiece_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-stringprintf_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-structurally_valid_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-strutil_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-template_util_unittest.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/stubs/protobuf_test-time_test.$(OBJEXT):  \
+	google/protobuf/stubs/$(am__dirstamp) \
+	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-text_format_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unknown_field_set_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-delimited_message_util_test.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-field_comparator_test.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-field_mask_util_test.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.$(OBJEXT):  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protobuf_test-json_objectwriter_test.$(OBJEXT):  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protobuf_test-json_stream_parser_test.$(OBJEXT):  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.$(OBJEXT):  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.$(OBJEXT):  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/protobuf_test-type_info_test_helper.$(OBJEXT):  \
+	google/protobuf/util/internal/$(am__dirstamp) \
+	google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-json_util_test.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-message_differencer_unittest.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-time_util_test.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-type_resolver_util_test.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-well_known_types_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-wire_format_unittest.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-map_lite_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_import_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_import_public_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-any_test.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.$(OBJEXT):  \
+	google/protobuf/compiler/cpp/$(am__dirstamp) \
+	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-map_proto2_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-map_unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_arena.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_custom_options.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_empty.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_import.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_import_public.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_mset.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_mset_wire_format.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_no_field_presence.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_no_generic_services.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_optimize_for.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_proto3.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_proto3_arena.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_proto3_lite.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_proto3_optional.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/protobuf_test-unittest_well_known_types.pb.$(OBJEXT):  \
+	google/protobuf/$(am__dirstamp) \
+	google/protobuf/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-anys.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-books.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-maps.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-struct.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.$(OBJEXT):  \
+	google/protobuf/util/internal/testdata/$(am__dirstamp) \
+	google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-json_format.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-json_format_proto3.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/util/protobuf_test-message_differencer_unittest.pb.$(OBJEXT):  \
+	google/protobuf/util/$(am__dirstamp) \
+	google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+
+protobuf-test$(EXEEXT): $(protobuf_test_OBJECTS) $(protobuf_test_DEPENDENCIES) $(EXTRA_protobuf_test_DEPENDENCIES) 
+	@rm -f protobuf-test$(EXEEXT)
+	$(AM_V_CXXLD)$(protobuf_test_LINK) $(protobuf_test_OBJECTS) $(protobuf_test_LDADD) $(LIBS)
+google/protobuf/compiler/main.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+
+protoc$(EXEEXT): $(protoc_OBJECTS) $(protoc_DEPENDENCIES) $(EXTRA_protoc_DEPENDENCIES) 
+	@rm -f protoc$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(protoc_OBJECTS) $(protoc_LDADD) $(LIBS)
+google/protobuf/compiler/test_plugin-mock_code_generator.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/compiler/test_plugin-test_plugin.$(OBJEXT):  \
+	google/protobuf/compiler/$(am__dirstamp) \
+	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+google/protobuf/testing/test_plugin-file.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+
+test_plugin$(EXEEXT): $(test_plugin_OBJECTS) $(test_plugin_DEPENDENCIES) $(EXTRA_test_plugin_DEPENDENCIES) 
+	@rm -f test_plugin$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(test_plugin_OBJECTS) $(test_plugin_LDADD) $(LIBS)
+google/protobuf/testing/zcgunzip.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+
+zcgunzip$(EXEEXT): $(zcgunzip_OBJECTS) $(zcgunzip_DEPENDENCIES) $(EXTRA_zcgunzip_DEPENDENCIES) 
+	@rm -f zcgunzip$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(zcgunzip_OBJECTS) $(zcgunzip_LDADD) $(LIBS)
+google/protobuf/testing/zcgzip.$(OBJEXT):  \
+	google/protobuf/testing/$(am__dirstamp) \
+	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+
+zcgzip$(EXEEXT): $(zcgzip_OBJECTS) $(zcgzip_DEPENDENCIES) $(EXTRA_zcgzip_DEPENDENCIES) 
+	@rm -f zcgzip$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(zcgzip_OBJECTS) $(zcgzip_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f google/protobuf/*.$(OBJEXT)
+	-rm -f google/protobuf/*.lo
+	-rm -f google/protobuf/compiler/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/*.lo
+	-rm -f google/protobuf/compiler/cpp/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/cpp/*.lo
+	-rm -f google/protobuf/compiler/csharp/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/csharp/*.lo
+	-rm -f google/protobuf/compiler/java/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/java/*.lo
+	-rm -f google/protobuf/compiler/objectivec/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/objectivec/*.lo
+	-rm -f google/protobuf/compiler/php/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/php/*.lo
+	-rm -f google/protobuf/compiler/python/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/python/*.lo
+	-rm -f google/protobuf/compiler/ruby/*.$(OBJEXT)
+	-rm -f google/protobuf/compiler/ruby/*.lo
+	-rm -f google/protobuf/io/*.$(OBJEXT)
+	-rm -f google/protobuf/io/*.lo
+	-rm -f google/protobuf/stubs/*.$(OBJEXT)
+	-rm -f google/protobuf/stubs/*.lo
+	-rm -f google/protobuf/testing/*.$(OBJEXT)
+	-rm -f google/protobuf/util/*.$(OBJEXT)
+	-rm -f google/protobuf/util/*.lo
+	-rm -f google/protobuf/util/internal/*.$(OBJEXT)
+	-rm -f google/protobuf/util/internal/*.lo
+	-rm -f google/protobuf/util/internal/testdata/*.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/no_warning_test-no_warning_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/any.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/any.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/any_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/api.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/arena.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/arenastring.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/arenaz_sampler.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/descriptor.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/descriptor.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/descriptor_database.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/duration.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/dynamic_message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/empty.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/extension_set.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/extension_set_heavy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/field_mask.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_enum_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_bases.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_reflection.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_tctable_full.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_tctable_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/implicit_weak_message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/inlined_string_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/map.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/map_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/message_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/parse_context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-any_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-map_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/reflection_ops.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/repeated_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/repeated_ptr_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/service.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/source_context.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/struct.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/text_format.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/timestamp.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/type.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/unknown_field_set.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/wire_format.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/wire_format_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/wrappers.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/code_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/command_line_interface.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/importer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/plugin.pb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/subprocess.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/zip_writer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/enum.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/enum_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/extension.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/helpers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/map_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/message_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/padding_optimizer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/parse_function_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/primitive_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/service.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/string_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_doc_comment.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_field_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_helpers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_map_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_primitive_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_reflection_class.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_enum_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_message_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_primitive_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_source_generator_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/csharp_wrapper_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/doc_comment.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/enum.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/enum_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/enum_field_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/enum_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/extension.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/extension_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/generator_factory.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/helpers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/kotlin_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/map_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/map_field_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/message_builder.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/message_builder_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/message_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/message_field_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/message_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/name_resolver.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/primitive_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/primitive_field_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/service.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/shared_code_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/string_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/string_field_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_extension.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_helpers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_map_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_oneof.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_primitive_field.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/php/$(DEPDIR)/php_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/python/$(DEPDIR)/generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/python/$(DEPDIR)/helpers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/python/$(DEPDIR)/pyi_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/ruby/$(DEPDIR)/ruby_generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/coded_stream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/gzip_stream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/io_win32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/printer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/strtod.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/tokenizer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/zero_copy_stream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl_lite.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/bytestream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/int128.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/status.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/statusor.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/stringpiece.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/stringprintf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/structurally_valid.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/strutil.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/substitute.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/time.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/zcgunzip.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/zcgzip.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/delimited_message_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/field_comparator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/field_mask_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/json_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/message_differencer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/time_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/$(DEPDIR)/type_resolver_util.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/datapiece.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/default_value_objectwriter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/error_listener.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/field_mask_utility.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/json_escaping.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/json_objectwriter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/json_stream_parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/object_writer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/proto_writer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protostream_objectsource.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/protostream_objectwriter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/type_info.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/$(DEPDIR)/utility.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+	@$(MKDIR_P) $(@D)
+	@echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cc.o:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+no_warning_test-no_warning_test.o: no_warning_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT no_warning_test-no_warning_test.o -MD -MP -MF $(DEPDIR)/no_warning_test-no_warning_test.Tpo -c -o no_warning_test-no_warning_test.o `test -f 'no_warning_test.cc' || echo '$(srcdir)/'`no_warning_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/no_warning_test-no_warning_test.Tpo $(DEPDIR)/no_warning_test-no_warning_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='no_warning_test.cc' object='no_warning_test-no_warning_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o no_warning_test-no_warning_test.o `test -f 'no_warning_test.cc' || echo '$(srcdir)/'`no_warning_test.cc
+
+no_warning_test-no_warning_test.obj: no_warning_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT no_warning_test-no_warning_test.obj -MD -MP -MF $(DEPDIR)/no_warning_test-no_warning_test.Tpo -c -o no_warning_test-no_warning_test.obj `if test -f 'no_warning_test.cc'; then $(CYGPATH_W) 'no_warning_test.cc'; else $(CYGPATH_W) '$(srcdir)/no_warning_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/no_warning_test-no_warning_test.Tpo $(DEPDIR)/no_warning_test-no_warning_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='no_warning_test.cc' object='no_warning_test-no_warning_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o no_warning_test-no_warning_test.obj `if test -f 'no_warning_test.cc'; then $(CYGPATH_W) 'no_warning_test.cc'; else $(CYGPATH_W) '$(srcdir)/no_warning_test.cc'; fi`
+
+google/protobuf/no_warning_test-map_lite_unittest.pb.o: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-map_lite_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/no_warning_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/no_warning_test-map_lite_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+
+google/protobuf/no_warning_test-map_lite_unittest.pb.obj: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-map_lite_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/no_warning_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/no_warning_test-map_lite_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+
+google/protobuf/no_warning_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+
+google/protobuf/no_warning_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+
+google/protobuf/no_warning_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+
+google/protobuf/no_warning_test-any_test.pb.o: google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-any_test.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Tpo -c -o google/protobuf/no_warning_test-any_test.pb.o `test -f 'google/protobuf/any_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.pb.cc' object='google/protobuf/no_warning_test-any_test.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-any_test.pb.o `test -f 'google/protobuf/any_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/any_test.pb.cc
+
+google/protobuf/no_warning_test-any_test.pb.obj: google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-any_test.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Tpo -c -o google/protobuf/no_warning_test-any_test.pb.obj `if test -f 'google/protobuf/any_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.pb.cc' object='google/protobuf/no_warning_test-any_test.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-any_test.pb.obj `if test -f 'google/protobuf/any_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.o: google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+
+google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.obj: google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/no_warning_test-test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.o: google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Tpo -c -o google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.o `test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' object='google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.o `test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+
+google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.obj: google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Tpo -c -o google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' object='google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/no_warning_test-test_large_enum_value.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; fi`
+
+google/protobuf/no_warning_test-map_proto2_unittest.pb.o: google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-map_proto2_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Tpo -c -o google/protobuf/no_warning_test-map_proto2_unittest.pb.o `test -f 'google/protobuf/map_proto2_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_proto2_unittest.pb.cc' object='google/protobuf/no_warning_test-map_proto2_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-map_proto2_unittest.pb.o `test -f 'google/protobuf/map_proto2_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_proto2_unittest.pb.cc
+
+google/protobuf/no_warning_test-map_proto2_unittest.pb.obj: google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-map_proto2_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Tpo -c -o google/protobuf/no_warning_test-map_proto2_unittest.pb.obj `if test -f 'google/protobuf/map_proto2_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_proto2_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_proto2_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_proto2_unittest.pb.cc' object='google/protobuf/no_warning_test-map_proto2_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-map_proto2_unittest.pb.obj `if test -f 'google/protobuf/map_proto2_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_proto2_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_proto2_unittest.pb.cc'; fi`
+
+google/protobuf/no_warning_test-map_unittest.pb.o: google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-map_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Tpo -c -o google/protobuf/no_warning_test-map_unittest.pb.o `test -f 'google/protobuf/map_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_unittest.pb.cc' object='google/protobuf/no_warning_test-map_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-map_unittest.pb.o `test -f 'google/protobuf/map_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_unittest.pb.cc
+
+google/protobuf/no_warning_test-map_unittest.pb.obj: google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-map_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Tpo -c -o google/protobuf/no_warning_test-map_unittest.pb.obj `if test -f 'google/protobuf/map_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_unittest.pb.cc' object='google/protobuf/no_warning_test-map_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-map_unittest.pb.obj `if test -f 'google/protobuf/map_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_unittest.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest.pb.o: google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Tpo -c -o google/protobuf/no_warning_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/no_warning_test-unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
+
+google/protobuf/no_warning_test-unittest.pb.obj: google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Tpo -c -o google/protobuf/no_warning_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/no_warning_test-unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_arena.pb.o: google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_arena.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_arena.pb.o `test -f 'google/protobuf/unittest_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_arena.pb.cc' object='google/protobuf/no_warning_test-unittest_arena.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_arena.pb.o `test -f 'google/protobuf/unittest_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_arena.pb.cc
+
+google/protobuf/no_warning_test-unittest_arena.pb.obj: google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_arena.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_arena.pb.obj `if test -f 'google/protobuf/unittest_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_arena.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_arena.pb.cc' object='google/protobuf/no_warning_test-unittest_arena.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_arena.pb.obj `if test -f 'google/protobuf/unittest_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_arena.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_custom_options.pb.o: google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_custom_options.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/no_warning_test-unittest_custom_options.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
+
+google/protobuf/no_warning_test-unittest_custom_options.pb.obj: google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_custom_options.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/no_warning_test-unittest_custom_options.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.o: google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.o `test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_drop_unknown_fields.pb.cc' object='google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.o `test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_drop_unknown_fields.pb.cc
+
+google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.obj: google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.obj `if test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_drop_unknown_fields.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_drop_unknown_fields.pb.cc' object='google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_drop_unknown_fields.pb.obj `if test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_drop_unknown_fields.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.o: google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
+
+google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.obj: google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_empty.pb.o: google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_empty.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/no_warning_test-unittest_empty.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
+
+google/protobuf/no_warning_test-unittest_empty.pb.obj: google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_empty.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/no_warning_test-unittest_empty.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.o: google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.o `test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_enormous_descriptor.pb.cc' object='google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.o `test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_enormous_descriptor.pb.cc
+
+google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.obj: google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.obj `if test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_enormous_descriptor.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_enormous_descriptor.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_enormous_descriptor.pb.cc' object='google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_enormous_descriptor.pb.obj `if test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_enormous_descriptor.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_enormous_descriptor.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_import.pb.o: google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/no_warning_test-unittest_import.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
+
+google/protobuf/no_warning_test-unittest_import.pb.obj: google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/no_warning_test-unittest_import.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_import_public.pb.o: google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import_public.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/no_warning_test-unittest_import_public.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
+
+google/protobuf/no_warning_test-unittest_import_public.pb.obj: google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_import_public.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/no_warning_test-unittest_import_public.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.o: google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies.pb.cc' object='google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies.pb.cc
+
+google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.obj: google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies.pb.cc' object='google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.o: google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' object='google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+
+google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.obj: google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' object='google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_custom_option.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.o: google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_enum.pb.cc' object='google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+
+google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.obj: google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_enum.pb.cc' object='google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lazy_dependencies_enum.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.o: google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
+
+google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.obj: google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_mset.pb.o: google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_mset.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/no_warning_test-unittest_mset.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
+
+google/protobuf/no_warning_test-unittest_mset.pb.obj: google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_mset.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/no_warning_test-unittest_mset.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_mset_wire_format.pb.o: google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_mset_wire_format.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_mset_wire_format.pb.o `test -f 'google/protobuf/unittest_mset_wire_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset_wire_format.pb.cc' object='google/protobuf/no_warning_test-unittest_mset_wire_format.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_mset_wire_format.pb.o `test -f 'google/protobuf/unittest_mset_wire_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset_wire_format.pb.cc
+
+google/protobuf/no_warning_test-unittest_mset_wire_format.pb.obj: google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_mset_wire_format.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_mset_wire_format.pb.obj `if test -f 'google/protobuf/unittest_mset_wire_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset_wire_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset_wire_format.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset_wire_format.pb.cc' object='google/protobuf/no_warning_test-unittest_mset_wire_format.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_mset_wire_format.pb.obj `if test -f 'google/protobuf/unittest_mset_wire_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset_wire_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset_wire_format.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_no_field_presence.pb.o: google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_no_field_presence.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_no_field_presence.pb.o `test -f 'google/protobuf/unittest_no_field_presence.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_field_presence.pb.cc' object='google/protobuf/no_warning_test-unittest_no_field_presence.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_no_field_presence.pb.o `test -f 'google/protobuf/unittest_no_field_presence.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_field_presence.pb.cc
+
+google/protobuf/no_warning_test-unittest_no_field_presence.pb.obj: google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_no_field_presence.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_no_field_presence.pb.obj `if test -f 'google/protobuf/unittest_no_field_presence.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_field_presence.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_field_presence.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_field_presence.pb.cc' object='google/protobuf/no_warning_test-unittest_no_field_presence.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_no_field_presence.pb.obj `if test -f 'google/protobuf/unittest_no_field_presence.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_field_presence.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_field_presence.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_no_generic_services.pb.o: google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_no_generic_services.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/no_warning_test-unittest_no_generic_services.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
+
+google/protobuf/no_warning_test-unittest_no_generic_services.pb.obj: google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_no_generic_services.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/no_warning_test-unittest_no_generic_services.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_optimize_for.pb.o: google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/no_warning_test-unittest_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
+
+google/protobuf/no_warning_test-unittest_optimize_for.pb.obj: google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/no_warning_test-unittest_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.o: google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum.pb.cc' object='google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum.pb.cc
+
+google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.obj: google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum.pb.cc' object='google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.o: google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum2.pb.cc' object='google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+
+google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.obj: google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum2.pb.cc' object='google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_preserve_unknown_enum2.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_proto3.pb.o: google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3.pb.o `test -f 'google/protobuf/unittest_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3.pb.o `test -f 'google/protobuf/unittest_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3.pb.cc
+
+google/protobuf/no_warning_test-unittest_proto3.pb.obj: google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3.pb.obj `if test -f 'google/protobuf/unittest_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3.pb.obj `if test -f 'google/protobuf/unittest_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_proto3_arena.pb.o: google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_arena.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_arena.pb.o `test -f 'google/protobuf/unittest_proto3_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_arena.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_arena.pb.o `test -f 'google/protobuf/unittest_proto3_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena.pb.cc
+
+google/protobuf/no_warning_test-unittest_proto3_arena.pb.obj: google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_arena.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_arena.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_arena.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_arena.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.o: google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.o `test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.o `test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena_lite.pb.cc
+
+google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.obj: google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_arena_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena_lite.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_proto3_lite.pb.o: google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_lite.pb.o `test -f 'google/protobuf/unittest_proto3_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_lite.pb.o `test -f 'google/protobuf/unittest_proto3_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_lite.pb.cc
+
+google/protobuf/no_warning_test-unittest_proto3_lite.pb.obj: google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_lite.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_lite.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_proto3_optional.pb.o: google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_optional.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_optional.pb.o `test -f 'google/protobuf/unittest_proto3_optional.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_optional.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_optional.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_optional.pb.o `test -f 'google/protobuf/unittest_proto3_optional.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_optional.pb.cc
+
+google/protobuf/no_warning_test-unittest_proto3_optional.pb.obj: google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_proto3_optional.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_proto3_optional.pb.obj `if test -f 'google/protobuf/unittest_proto3_optional.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_optional.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_optional.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_optional.pb.cc' object='google/protobuf/no_warning_test-unittest_proto3_optional.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_proto3_optional.pb.obj `if test -f 'google/protobuf/unittest_proto3_optional.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_optional.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_optional.pb.cc'; fi`
+
+google/protobuf/no_warning_test-unittest_well_known_types.pb.o: google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_well_known_types.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_well_known_types.pb.o `test -f 'google/protobuf/unittest_well_known_types.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_well_known_types.pb.cc' object='google/protobuf/no_warning_test-unittest_well_known_types.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_well_known_types.pb.o `test -f 'google/protobuf/unittest_well_known_types.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_well_known_types.pb.cc
+
+google/protobuf/no_warning_test-unittest_well_known_types.pb.obj: google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/no_warning_test-unittest_well_known_types.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Tpo -c -o google/protobuf/no_warning_test-unittest_well_known_types.pb.obj `if test -f 'google/protobuf/unittest_well_known_types.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_well_known_types.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_well_known_types.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Tpo google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_well_known_types.pb.cc' object='google/protobuf/no_warning_test-unittest_well_known_types.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/no_warning_test-unittest_well_known_types.pb.obj `if test -f 'google/protobuf/unittest_well_known_types.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_well_known_types.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_well_known_types.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-anys.pb.o: google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-anys.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-anys.pb.o `test -f 'google/protobuf/util/internal/testdata/anys.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/anys.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-anys.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-anys.pb.o `test -f 'google/protobuf/util/internal/testdata/anys.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/anys.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-anys.pb.obj: google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-anys.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-anys.pb.obj `if test -f 'google/protobuf/util/internal/testdata/anys.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/anys.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/anys.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/anys.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-anys.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-anys.pb.obj `if test -f 'google/protobuf/util/internal/testdata/anys.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/anys.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/anys.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-books.pb.o: google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-books.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-books.pb.o `test -f 'google/protobuf/util/internal/testdata/books.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/books.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-books.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-books.pb.o `test -f 'google/protobuf/util/internal/testdata/books.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/books.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-books.pb.obj: google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-books.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-books.pb.obj `if test -f 'google/protobuf/util/internal/testdata/books.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/books.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/books.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/books.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-books.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-books.pb.obj `if test -f 'google/protobuf/util/internal/testdata/books.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/books.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/books.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.o: google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.obj: google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.o: google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value_test.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value_test.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.obj: google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value_test.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value_test.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-default_value_test.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value_test.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.o: google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.o `test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/field_mask.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.o `test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/field_mask.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.obj: google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.obj `if test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/field_mask.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/field_mask.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-field_mask.pb.obj `if test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/field_mask.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-maps.pb.o: google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-maps.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-maps.pb.o `test -f 'google/protobuf/util/internal/testdata/maps.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/maps.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-maps.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-maps.pb.o `test -f 'google/protobuf/util/internal/testdata/maps.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/maps.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-maps.pb.obj: google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-maps.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-maps.pb.obj `if test -f 'google/protobuf/util/internal/testdata/maps.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/maps.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/maps.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/maps.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-maps.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-maps.pb.obj `if test -f 'google/protobuf/util/internal/testdata/maps.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/maps.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/maps.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.o: google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.o `test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/oneofs.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.o `test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/oneofs.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.obj: google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.obj `if test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/oneofs.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/oneofs.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-oneofs.pb.obj `if test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/oneofs.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.o: google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.o `test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/proto3.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.o `test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/proto3.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.obj: google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.obj `if test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/proto3.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-proto3.pb.obj `if test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/proto3.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-struct.pb.o: google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-struct.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-struct.pb.o `test -f 'google/protobuf/util/internal/testdata/struct.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/struct.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-struct.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-struct.pb.o `test -f 'google/protobuf/util/internal/testdata/struct.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/struct.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-struct.pb.obj: google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-struct.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-struct.pb.obj `if test -f 'google/protobuf/util/internal/testdata/struct.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/struct.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/struct.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/struct.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-struct.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-struct.pb.obj `if test -f 'google/protobuf/util/internal/testdata/struct.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/struct.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/struct.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.o: google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.o `test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.o `test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.obj: google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.obj `if test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-timestamp_duration.pb.obj `if test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.o: google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.o `test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/wrappers.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.o `test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/wrappers.pb.cc
+
+google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.obj: google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Tpo -c -o google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.obj `if test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/wrappers.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/wrappers.pb.cc' object='google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/no_warning_test-wrappers.pb.obj `if test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/wrappers.pb.cc'; fi`
+
+google/protobuf/util/no_warning_test-json_format.pb.o: google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/no_warning_test-json_format.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Tpo -c -o google/protobuf/util/no_warning_test-json_format.pb.o `test -f 'google/protobuf/util/json_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Tpo google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format.pb.cc' object='google/protobuf/util/no_warning_test-json_format.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/no_warning_test-json_format.pb.o `test -f 'google/protobuf/util/json_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format.pb.cc
+
+google/protobuf/util/no_warning_test-json_format.pb.obj: google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/no_warning_test-json_format.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Tpo -c -o google/protobuf/util/no_warning_test-json_format.pb.obj `if test -f 'google/protobuf/util/json_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Tpo google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format.pb.cc' object='google/protobuf/util/no_warning_test-json_format.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/no_warning_test-json_format.pb.obj `if test -f 'google/protobuf/util/json_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format.pb.cc'; fi`
+
+google/protobuf/util/no_warning_test-json_format_proto3.pb.o: google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/no_warning_test-json_format_proto3.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Tpo -c -o google/protobuf/util/no_warning_test-json_format_proto3.pb.o `test -f 'google/protobuf/util/json_format_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Tpo google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format_proto3.pb.cc' object='google/protobuf/util/no_warning_test-json_format_proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/no_warning_test-json_format_proto3.pb.o `test -f 'google/protobuf/util/json_format_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format_proto3.pb.cc
+
+google/protobuf/util/no_warning_test-json_format_proto3.pb.obj: google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/no_warning_test-json_format_proto3.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Tpo -c -o google/protobuf/util/no_warning_test-json_format_proto3.pb.obj `if test -f 'google/protobuf/util/json_format_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format_proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Tpo google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format_proto3.pb.cc' object='google/protobuf/util/no_warning_test-json_format_proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/no_warning_test-json_format_proto3.pb.obj `if test -f 'google/protobuf/util/json_format_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format_proto3.pb.cc'; fi`
+
+google/protobuf/util/no_warning_test-message_differencer_unittest.pb.o: google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/no_warning_test-message_differencer_unittest.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Tpo -c -o google/protobuf/util/no_warning_test-message_differencer_unittest.pb.o `test -f 'google/protobuf/util/message_differencer_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Tpo google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.pb.cc' object='google/protobuf/util/no_warning_test-message_differencer_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/no_warning_test-message_differencer_unittest.pb.o `test -f 'google/protobuf/util/message_differencer_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.pb.cc
+
+google/protobuf/util/no_warning_test-message_differencer_unittest.pb.obj: google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/no_warning_test-message_differencer_unittest.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Tpo -c -o google/protobuf/util/no_warning_test-message_differencer_unittest.pb.obj `if test -f 'google/protobuf/util/message_differencer_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Tpo google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.pb.cc' object='google/protobuf/util/no_warning_test-message_differencer_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(no_warning_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/no_warning_test-message_differencer_unittest.pb.obj `if test -f 'google/protobuf/util/message_differencer_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.o: google/protobuf/compiler/cpp/unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.o `test -f 'google/protobuf/compiler/cpp/unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/unittest.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.o `test -f 'google/protobuf/compiler/cpp/unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/unittest.cc
+
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.obj: google/protobuf/compiler/cpp/unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.obj `if test -f 'google/protobuf/compiler/cpp/unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/unittest.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-unittest.obj `if test -f 'google/protobuf/compiler/cpp/unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/unittest.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.o: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.obj: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.o: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.obj: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.o: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.obj: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.o: google/protobuf/reflection_tester.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.o `test -f 'google/protobuf/reflection_tester.cc' || echo '$(srcdir)/'`google/protobuf/reflection_tester.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_tester.cc' object='google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.o `test -f 'google/protobuf/reflection_tester.cc' || echo '$(srcdir)/'`google/protobuf/reflection_tester.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.obj: google/protobuf/reflection_tester.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.obj `if test -f 'google/protobuf/reflection_tester.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_tester.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_tester.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_tester.cc' object='google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-reflection_tester.obj `if test -f 'google/protobuf/reflection_tester.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_tester.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_tester.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-test_util.o: google/protobuf/test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-test_util.obj: google/protobuf/test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
+
+google/protobuf/testing/protobuf_lazy_descriptor_test-file.o: google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-file.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-file.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
+
+google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj: google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
+
+google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o: google/protobuf/testing/googletest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
+
+google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj: google/protobuf/testing/googletest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.o: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.obj: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.o: google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.o `test -f 'google/protobuf/any_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.o `test -f 'google/protobuf/any_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/any_test.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.obj: google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.obj `if test -f 'google/protobuf/any_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-any_test.pb.obj `if test -f 'google/protobuf/any_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.o: google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.obj: google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.o: google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.o `test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.o `test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+
+google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.obj: google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-test_large_enum_value.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.o: google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.o `test -f 'google/protobuf/map_proto2_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_proto2_unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.o `test -f 'google/protobuf/map_proto2_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_proto2_unittest.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.obj: google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.obj `if test -f 'google/protobuf/map_proto2_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_proto2_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_proto2_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_proto2_unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.obj `if test -f 'google/protobuf/map_proto2_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_proto2_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_proto2_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.o: google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.o `test -f 'google/protobuf/map_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.o `test -f 'google/protobuf/map_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_unittest.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.obj: google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.obj `if test -f 'google/protobuf/map_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-map_unittest.pb.obj `if test -f 'google/protobuf/map_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o: google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj: google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.o: google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.o `test -f 'google/protobuf/unittest_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_arena.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.o `test -f 'google/protobuf/unittest_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_arena.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.obj: google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.obj `if test -f 'google/protobuf/unittest_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_arena.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_arena.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_arena.pb.obj `if test -f 'google/protobuf/unittest_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_arena.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o: google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj: google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.o: google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.o `test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_drop_unknown_fields.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.o `test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_drop_unknown_fields.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.obj: google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.obj `if test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_drop_unknown_fields.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_drop_unknown_fields.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.obj `if test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_drop_unknown_fields.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o: google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj: google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o: google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj: google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.o: google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.o `test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_enormous_descriptor.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.o `test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_enormous_descriptor.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.obj: google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.obj `if test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_enormous_descriptor.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_enormous_descriptor.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_enormous_descriptor.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.obj `if test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_enormous_descriptor.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_enormous_descriptor.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o: google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj: google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o: google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj: google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.o: google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.obj: google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.o: google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.obj: google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.o: google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_enum.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.obj: google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_enum.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o: google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj: google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o: google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj: google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.o: google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.o `test -f 'google/protobuf/unittest_mset_wire_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset_wire_format.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.o `test -f 'google/protobuf/unittest_mset_wire_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset_wire_format.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.obj: google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.obj `if test -f 'google/protobuf/unittest_mset_wire_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset_wire_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset_wire_format.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset_wire_format.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.obj `if test -f 'google/protobuf/unittest_mset_wire_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset_wire_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset_wire_format.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.o: google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.o `test -f 'google/protobuf/unittest_no_field_presence.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_field_presence.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.o `test -f 'google/protobuf/unittest_no_field_presence.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_field_presence.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.obj: google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.obj `if test -f 'google/protobuf/unittest_no_field_presence.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_field_presence.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_field_presence.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_field_presence.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.obj `if test -f 'google/protobuf/unittest_no_field_presence.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_field_presence.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_field_presence.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o: google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj: google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o: google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj: google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.o: google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.obj: google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.o: google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum2.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.obj: google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum2.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.o: google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.o `test -f 'google/protobuf/unittest_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.o `test -f 'google/protobuf/unittest_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.obj: google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.obj `if test -f 'google/protobuf/unittest_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3.pb.obj `if test -f 'google/protobuf/unittest_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.o: google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.o `test -f 'google/protobuf/unittest_proto3_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.o `test -f 'google/protobuf/unittest_proto3_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.obj: google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.o: google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.o `test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.o `test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena_lite.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.obj: google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.o: google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.o `test -f 'google/protobuf/unittest_proto3_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.o `test -f 'google/protobuf/unittest_proto3_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_lite.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.obj: google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.o: google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.o `test -f 'google/protobuf/unittest_proto3_optional.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_optional.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.o `test -f 'google/protobuf/unittest_proto3_optional.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_optional.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.obj: google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.obj `if test -f 'google/protobuf/unittest_proto3_optional.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_optional.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_optional.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_optional.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.obj `if test -f 'google/protobuf/unittest_proto3_optional.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_optional.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_optional.pb.cc'; fi`
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.o: google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.o `test -f 'google/protobuf/unittest_well_known_types.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_well_known_types.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.o `test -f 'google/protobuf/unittest_well_known_types.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_well_known_types.pb.cc
+
+google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.obj: google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.obj `if test -f 'google/protobuf/unittest_well_known_types.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_well_known_types.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_well_known_types.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_well_known_types.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.obj `if test -f 'google/protobuf/unittest_well_known_types.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_well_known_types.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_well_known_types.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.o: google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.o `test -f 'google/protobuf/util/internal/testdata/anys.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/anys.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.o `test -f 'google/protobuf/util/internal/testdata/anys.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/anys.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.obj: google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.obj `if test -f 'google/protobuf/util/internal/testdata/anys.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/anys.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/anys.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/anys.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-anys.pb.obj `if test -f 'google/protobuf/util/internal/testdata/anys.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/anys.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/anys.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.o: google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.o `test -f 'google/protobuf/util/internal/testdata/books.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/books.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.o `test -f 'google/protobuf/util/internal/testdata/books.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/books.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.obj: google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.obj `if test -f 'google/protobuf/util/internal/testdata/books.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/books.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/books.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/books.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-books.pb.obj `if test -f 'google/protobuf/util/internal/testdata/books.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/books.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/books.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.o: google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.obj: google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.o: google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value_test.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value_test.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.obj: google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value_test.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value_test.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-default_value_test.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value_test.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.o: google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.o `test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/field_mask.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.o `test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/field_mask.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.obj: google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.obj `if test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/field_mask.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/field_mask.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-field_mask.pb.obj `if test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/field_mask.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.o: google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.o `test -f 'google/protobuf/util/internal/testdata/maps.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/maps.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.o `test -f 'google/protobuf/util/internal/testdata/maps.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/maps.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.obj: google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.obj `if test -f 'google/protobuf/util/internal/testdata/maps.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/maps.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/maps.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/maps.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-maps.pb.obj `if test -f 'google/protobuf/util/internal/testdata/maps.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/maps.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/maps.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.o: google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.o `test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/oneofs.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.o `test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/oneofs.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.obj: google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.obj `if test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/oneofs.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/oneofs.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-oneofs.pb.obj `if test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/oneofs.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.o: google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.o `test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/proto3.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.o `test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/proto3.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.obj: google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.obj `if test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/proto3.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-proto3.pb.obj `if test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/proto3.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.o: google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.o `test -f 'google/protobuf/util/internal/testdata/struct.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/struct.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.o `test -f 'google/protobuf/util/internal/testdata/struct.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/struct.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.obj: google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.obj `if test -f 'google/protobuf/util/internal/testdata/struct.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/struct.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/struct.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/struct.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-struct.pb.obj `if test -f 'google/protobuf/util/internal/testdata/struct.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/struct.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/struct.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.o: google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.o `test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.o `test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.obj: google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.obj `if test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-timestamp_duration.pb.obj `if test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.o: google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.o `test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/wrappers.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.o `test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/wrappers.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.obj: google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.obj `if test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/wrappers.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/wrappers.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_lazy_descriptor_test-wrappers.pb.obj `if test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/wrappers.pb.cc'; fi`
+
+google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.o: google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Tpo -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.o `test -f 'google/protobuf/util/json_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format.pb.cc' object='google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.o `test -f 'google/protobuf/util/json_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format.pb.cc
+
+google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.obj: google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Tpo -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.obj `if test -f 'google/protobuf/util/json_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format.pb.cc' object='google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format.pb.obj `if test -f 'google/protobuf/util/json_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format.pb.cc'; fi`
+
+google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.o: google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Tpo -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.o `test -f 'google/protobuf/util/json_format_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format_proto3.pb.cc' object='google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.o `test -f 'google/protobuf/util/json_format_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format_proto3.pb.cc
+
+google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.obj: google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Tpo -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.obj `if test -f 'google/protobuf/util/json_format_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format_proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format_proto3.pb.cc' object='google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_lazy_descriptor_test-json_format_proto3.pb.obj `if test -f 'google/protobuf/util/json_format_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format_proto3.pb.cc'; fi`
+
+google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.o: google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Tpo -c -o google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.o `test -f 'google/protobuf/util/message_differencer_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.pb.cc' object='google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.o `test -f 'google/protobuf/util/message_differencer_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.pb.cc
+
+google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.obj: google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Tpo -c -o google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.obj `if test -f 'google/protobuf/util/message_differencer_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.pb.cc' object='google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.obj `if test -f 'google/protobuf/util/message_differencer_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.o: google/protobuf/lite_arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Tpo -c -o google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.o `test -f 'google/protobuf/lite_arena_unittest.cc' || echo '$(srcdir)/'`google/protobuf/lite_arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/lite_arena_unittest.cc' object='google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.o `test -f 'google/protobuf/lite_arena_unittest.cc' || echo '$(srcdir)/'`google/protobuf/lite_arena_unittest.cc
+
+google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.obj: google/protobuf/lite_arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Tpo -c -o google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.obj `if test -f 'google/protobuf/lite_arena_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/lite_arena_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/lite_arena_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/lite_arena_unittest.cc' object='google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-lite_arena_unittest.obj `if test -f 'google/protobuf/lite_arena_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/lite_arena_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/lite_arena_unittest.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-arena_test_util.o: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-arena_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_lite_arena_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_lite_arena_test-arena_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+
+google/protobuf/protobuf_lite_arena_test-arena_test_util.obj: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-arena_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_lite_arena_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_lite_arena_test-arena_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-map_lite_test_util.o: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-map_lite_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_lite_arena_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_lite_arena_test-map_lite_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+
+google/protobuf/protobuf_lite_arena_test-map_lite_test_util.obj: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-map_lite_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_lite_arena_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_lite_arena_test-map_lite_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-test_util_lite.o: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-test_util_lite.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lite_arena_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lite_arena_test-test_util_lite.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+
+google/protobuf/protobuf_lite_arena_test-test_util_lite.obj: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-test_util_lite.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lite_arena_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lite_arena_test-test_util_lite.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.o: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+
+google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.obj: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+
+google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+
+google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+
+google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_arena_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_arena_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_arena_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_test-lite_unittest.o: google/protobuf/lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-lite_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo -c -o google/protobuf/protobuf_lite_test-lite_unittest.o `test -f 'google/protobuf/lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/lite_unittest.cc' object='google/protobuf/protobuf_lite_test-lite_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-lite_unittest.o `test -f 'google/protobuf/lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/lite_unittest.cc
+
+google/protobuf/protobuf_lite_test-lite_unittest.obj: google/protobuf/lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-lite_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo -c -o google/protobuf/protobuf_lite_test-lite_unittest.obj `if test -f 'google/protobuf/lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/lite_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/lite_unittest.cc' object='google/protobuf/protobuf_lite_test-lite_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-lite_unittest.obj `if test -f 'google/protobuf/lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/lite_unittest.cc'; fi`
+
+google/protobuf/protobuf_lite_test-arena_test_util.o: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-arena_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_lite_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_lite_test-arena_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+
+google/protobuf/protobuf_lite_test-arena_test_util.obj: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-arena_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_lite_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_lite_test-arena_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+
+google/protobuf/protobuf_lite_test-map_lite_test_util.o: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-map_lite_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_lite_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_lite_test-map_lite_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+
+google/protobuf/protobuf_lite_test-map_lite_test_util.obj: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-map_lite_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_lite_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_lite_test-map_lite_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+
+google/protobuf/protobuf_lite_test-test_util_lite.o: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-test_util_lite.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lite_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lite_test-test_util_lite.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+
+google/protobuf/protobuf_lite_test-test_util_lite.obj: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-test_util_lite.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lite_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lite_test-test_util_lite.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+
+google/protobuf/protobuf_lite_test-map_lite_unittest.pb.o: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-map_lite_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_lite_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_lite_test-map_lite_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+
+google/protobuf/protobuf_lite_test-map_lite_unittest.pb.obj: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-map_lite_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_lite_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_lite_test-map_lite_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+
+google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+
+google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_lite_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+
+google/protobuf/protobuf_lite_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lite_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-arena_test_util.o: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arena_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_test-arena_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arena_test_util.o `test -f 'google/protobuf/arena_test_util.cc' || echo '$(srcdir)/'`google/protobuf/arena_test_util.cc
+
+google/protobuf/protobuf_test-arena_test_util.obj: google/protobuf/arena_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arena_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Tpo -c -o google/protobuf/protobuf_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_test_util.cc' object='google/protobuf/protobuf_test-arena_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arena_test_util.obj `if test -f 'google/protobuf/arena_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/arena_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_test_util.cc'; fi`
+
+google/protobuf/protobuf_test-map_lite_test_util.o: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_lite_test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_test-map_lite_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_lite_test_util.o `test -f 'google/protobuf/map_lite_test_util.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_test_util.cc
+
+google/protobuf/protobuf_test-map_lite_test_util.obj: google/protobuf/map_lite_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_lite_test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Tpo -c -o google/protobuf/protobuf_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_test_util.cc' object='google/protobuf/protobuf_test-map_lite_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_lite_test_util.obj `if test -f 'google/protobuf/map_lite_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_test_util.cc'; fi`
+
+google/protobuf/protobuf_test-test_util_lite.o: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-test_util_lite.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_test-test_util_lite.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
+
+google/protobuf/protobuf_test-test_util_lite.obj: google/protobuf/test_util_lite.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-test_util_lite.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_test-test_util_lite.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
+
+google/protobuf/protobuf_test-reflection_tester.o: google/protobuf/reflection_tester.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-reflection_tester.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Tpo -c -o google/protobuf/protobuf_test-reflection_tester.o `test -f 'google/protobuf/reflection_tester.cc' || echo '$(srcdir)/'`google/protobuf/reflection_tester.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Tpo google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_tester.cc' object='google/protobuf/protobuf_test-reflection_tester.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-reflection_tester.o `test -f 'google/protobuf/reflection_tester.cc' || echo '$(srcdir)/'`google/protobuf/reflection_tester.cc
+
+google/protobuf/protobuf_test-reflection_tester.obj: google/protobuf/reflection_tester.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-reflection_tester.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Tpo -c -o google/protobuf/protobuf_test-reflection_tester.obj `if test -f 'google/protobuf/reflection_tester.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_tester.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_tester.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Tpo google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_tester.cc' object='google/protobuf/protobuf_test-reflection_tester.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-reflection_tester.obj `if test -f 'google/protobuf/reflection_tester.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_tester.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_tester.cc'; fi`
+
+google/protobuf/protobuf_test-test_util.o: google/protobuf/test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo -c -o google/protobuf/protobuf_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_test-test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
+
+google/protobuf/protobuf_test-test_util.obj: google/protobuf/test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo -c -o google/protobuf/protobuf_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_test-test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
+
+google/protobuf/testing/protobuf_test-file.o: google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-file.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo -c -o google/protobuf/testing/protobuf_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_test-file.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
+
+google/protobuf/testing/protobuf_test-file.obj: google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-file.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo -c -o google/protobuf/testing/protobuf_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_test-file.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
+
+google/protobuf/testing/protobuf_test-googletest.o: google/protobuf/testing/googletest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-googletest.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_test-googletest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
+
+google/protobuf/testing/protobuf_test-googletest.obj: google/protobuf/testing/googletest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-googletest.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_test-googletest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
+
+google/protobuf/protobuf_test-any_test.o: google/protobuf/any_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-any_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-any_test.Tpo -c -o google/protobuf/protobuf_test-any_test.o `test -f 'google/protobuf/any_test.cc' || echo '$(srcdir)/'`google/protobuf/any_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-any_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-any_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.cc' object='google/protobuf/protobuf_test-any_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-any_test.o `test -f 'google/protobuf/any_test.cc' || echo '$(srcdir)/'`google/protobuf/any_test.cc
+
+google/protobuf/protobuf_test-any_test.obj: google/protobuf/any_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-any_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-any_test.Tpo -c -o google/protobuf/protobuf_test-any_test.obj `if test -f 'google/protobuf/any_test.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-any_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-any_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.cc' object='google/protobuf/protobuf_test-any_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-any_test.obj `if test -f 'google/protobuf/any_test.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.cc'; fi`
+
+google/protobuf/protobuf_test-arena_unittest.o: google/protobuf/arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arena_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Tpo -c -o google/protobuf/protobuf_test-arena_unittest.o `test -f 'google/protobuf/arena_unittest.cc' || echo '$(srcdir)/'`google/protobuf/arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_unittest.cc' object='google/protobuf/protobuf_test-arena_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arena_unittest.o `test -f 'google/protobuf/arena_unittest.cc' || echo '$(srcdir)/'`google/protobuf/arena_unittest.cc
+
+google/protobuf/protobuf_test-arena_unittest.obj: google/protobuf/arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arena_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Tpo -c -o google/protobuf/protobuf_test-arena_unittest.obj `if test -f 'google/protobuf/arena_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/arena_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arena_unittest.cc' object='google/protobuf/protobuf_test-arena_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arena_unittest.obj `if test -f 'google/protobuf/arena_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/arena_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arena_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-arenastring_unittest.o: google/protobuf/arenastring_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arenastring_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Tpo -c -o google/protobuf/protobuf_test-arenastring_unittest.o `test -f 'google/protobuf/arenastring_unittest.cc' || echo '$(srcdir)/'`google/protobuf/arenastring_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arenastring_unittest.cc' object='google/protobuf/protobuf_test-arenastring_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arenastring_unittest.o `test -f 'google/protobuf/arenastring_unittest.cc' || echo '$(srcdir)/'`google/protobuf/arenastring_unittest.cc
+
+google/protobuf/protobuf_test-arenastring_unittest.obj: google/protobuf/arenastring_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arenastring_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Tpo -c -o google/protobuf/protobuf_test-arenastring_unittest.obj `if test -f 'google/protobuf/arenastring_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/arenastring_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arenastring_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arenastring_unittest.cc' object='google/protobuf/protobuf_test-arenastring_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arenastring_unittest.obj `if test -f 'google/protobuf/arenastring_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/arenastring_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arenastring_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-arenaz_sampler_test.o: google/protobuf/arenaz_sampler_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arenaz_sampler_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Tpo -c -o google/protobuf/protobuf_test-arenaz_sampler_test.o `test -f 'google/protobuf/arenaz_sampler_test.cc' || echo '$(srcdir)/'`google/protobuf/arenaz_sampler_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arenaz_sampler_test.cc' object='google/protobuf/protobuf_test-arenaz_sampler_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arenaz_sampler_test.o `test -f 'google/protobuf/arenaz_sampler_test.cc' || echo '$(srcdir)/'`google/protobuf/arenaz_sampler_test.cc
+
+google/protobuf/protobuf_test-arenaz_sampler_test.obj: google/protobuf/arenaz_sampler_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-arenaz_sampler_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Tpo -c -o google/protobuf/protobuf_test-arenaz_sampler_test.obj `if test -f 'google/protobuf/arenaz_sampler_test.cc'; then $(CYGPATH_W) 'google/protobuf/arenaz_sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arenaz_sampler_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/arenaz_sampler_test.cc' object='google/protobuf/protobuf_test-arenaz_sampler_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-arenaz_sampler_test.obj `if test -f 'google/protobuf/arenaz_sampler_test.cc'; then $(CYGPATH_W) 'google/protobuf/arenaz_sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/arenaz_sampler_test.cc'; fi`
+
+google/protobuf/compiler/protobuf_test-annotation_test_util.o: google/protobuf/compiler/annotation_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-annotation_test_util.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Tpo -c -o google/protobuf/compiler/protobuf_test-annotation_test_util.o `test -f 'google/protobuf/compiler/annotation_test_util.cc' || echo '$(srcdir)/'`google/protobuf/compiler/annotation_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/annotation_test_util.cc' object='google/protobuf/compiler/protobuf_test-annotation_test_util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-annotation_test_util.o `test -f 'google/protobuf/compiler/annotation_test_util.cc' || echo '$(srcdir)/'`google/protobuf/compiler/annotation_test_util.cc
+
+google/protobuf/compiler/protobuf_test-annotation_test_util.obj: google/protobuf/compiler/annotation_test_util.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-annotation_test_util.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Tpo -c -o google/protobuf/compiler/protobuf_test-annotation_test_util.obj `if test -f 'google/protobuf/compiler/annotation_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/annotation_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/annotation_test_util.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/annotation_test_util.cc' object='google/protobuf/compiler/protobuf_test-annotation_test_util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-annotation_test_util.obj `if test -f 'google/protobuf/compiler/annotation_test_util.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/annotation_test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/annotation_test_util.cc'; fi`
+
+google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o: google/protobuf/compiler/command_line_interface_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o `test -f 'google/protobuf/compiler/command_line_interface_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/command_line_interface_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/command_line_interface_unittest.cc' object='google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o `test -f 'google/protobuf/compiler/command_line_interface_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/command_line_interface_unittest.cc
+
+google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj: google/protobuf/compiler/command_line_interface_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj `if test -f 'google/protobuf/compiler/command_line_interface_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/command_line_interface_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/command_line_interface_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/command_line_interface_unittest.cc' object='google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj `if test -f 'google/protobuf/compiler/command_line_interface_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/command_line_interface_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/command_line_interface_unittest.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.o: google/protobuf/compiler/cpp/bootstrap_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.o `test -f 'google/protobuf/compiler/cpp/bootstrap_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/bootstrap_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/bootstrap_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.o `test -f 'google/protobuf/compiler/cpp/bootstrap_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/bootstrap_unittest.cc
+
+google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.obj: google/protobuf/compiler/cpp/bootstrap_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.obj `if test -f 'google/protobuf/compiler/cpp/bootstrap_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/bootstrap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/bootstrap_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/bootstrap_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-bootstrap_unittest.obj `if test -f 'google/protobuf/compiler/cpp/bootstrap_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/bootstrap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/bootstrap_unittest.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.o: google/protobuf/compiler/cpp/message_size_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.o `test -f 'google/protobuf/compiler/cpp/message_size_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/message_size_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/message_size_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.o `test -f 'google/protobuf/compiler/cpp/message_size_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/message_size_unittest.cc
+
+google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.obj: google/protobuf/compiler/cpp/message_size_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.obj `if test -f 'google/protobuf/compiler/cpp/message_size_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/message_size_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/message_size_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/message_size_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-message_size_unittest.obj `if test -f 'google/protobuf/compiler/cpp/message_size_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/message_size_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/message_size_unittest.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-metadata_test.o: google/protobuf/compiler/cpp/metadata_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-metadata_test.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-metadata_test.o `test -f 'google/protobuf/compiler/cpp/metadata_test.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/metadata_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/metadata_test.cc' object='google/protobuf/compiler/cpp/protobuf_test-metadata_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-metadata_test.o `test -f 'google/protobuf/compiler/cpp/metadata_test.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/metadata_test.cc
+
+google/protobuf/compiler/cpp/protobuf_test-metadata_test.obj: google/protobuf/compiler/cpp/metadata_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-metadata_test.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-metadata_test.obj `if test -f 'google/protobuf/compiler/cpp/metadata_test.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/metadata_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/metadata_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/metadata_test.cc' object='google/protobuf/compiler/cpp/protobuf_test-metadata_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-metadata_test.obj `if test -f 'google/protobuf/compiler/cpp/metadata_test.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/metadata_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/metadata_test.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-move_unittest.o: google/protobuf/compiler/cpp/move_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-move_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-move_unittest.o `test -f 'google/protobuf/compiler/cpp/move_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/move_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/move_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-move_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-move_unittest.o `test -f 'google/protobuf/compiler/cpp/move_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/move_unittest.cc
+
+google/protobuf/compiler/cpp/protobuf_test-move_unittest.obj: google/protobuf/compiler/cpp/move_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-move_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-move_unittest.obj `if test -f 'google/protobuf/compiler/cpp/move_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/move_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/move_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/move_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-move_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-move_unittest.obj `if test -f 'google/protobuf/compiler/cpp/move_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/move_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/move_unittest.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.o: google/protobuf/compiler/cpp/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.o `test -f 'google/protobuf/compiler/cpp/plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/plugin_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.o `test -f 'google/protobuf/compiler/cpp/plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/plugin_unittest.cc
+
+google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.obj: google/protobuf/compiler/cpp/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.obj `if test -f 'google/protobuf/compiler/cpp/plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/plugin_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/plugin_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-plugin_unittest.obj `if test -f 'google/protobuf/compiler/cpp/plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/plugin_unittest.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-unittest.o: google/protobuf/compiler/cpp/unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-unittest.o `test -f 'google/protobuf/compiler/cpp/unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-unittest.o `test -f 'google/protobuf/compiler/cpp/unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/unittest.cc
+
+google/protobuf/compiler/cpp/protobuf_test-unittest.obj: google/protobuf/compiler/cpp/unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-unittest.obj `if test -f 'google/protobuf/compiler/cpp/unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-unittest.obj `if test -f 'google/protobuf/compiler/cpp/unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/unittest.cc'; fi`
+
+google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.o: google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.o -MD -MP -MF google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Tpo -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.o `test -f 'google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Tpo google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc' object='google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.o `test -f 'google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
+
+google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.obj: google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.obj -MD -MP -MF google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Tpo -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.obj `if test -f 'google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Tpo google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc' object='google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_bootstrap_unittest.obj `if test -f 'google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc'; fi`
+
+google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.o: google/protobuf/compiler/csharp/csharp_generator_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.o -MD -MP -MF google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Tpo -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.o `test -f 'google/protobuf/compiler/csharp/csharp_generator_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/csharp/csharp_generator_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Tpo google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/csharp/csharp_generator_unittest.cc' object='google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.o `test -f 'google/protobuf/compiler/csharp/csharp_generator_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/csharp/csharp_generator_unittest.cc
+
+google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.obj: google/protobuf/compiler/csharp/csharp_generator_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.obj -MD -MP -MF google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Tpo -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.obj `if test -f 'google/protobuf/compiler/csharp/csharp_generator_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/csharp/csharp_generator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/csharp/csharp_generator_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Tpo google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/csharp/csharp_generator_unittest.cc' object='google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/csharp/protobuf_test-csharp_generator_unittest.obj `if test -f 'google/protobuf/compiler/csharp/csharp_generator_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/csharp/csharp_generator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/csharp/csharp_generator_unittest.cc'; fi`
+
+google/protobuf/compiler/protobuf_test-importer_unittest.o: google/protobuf/compiler/importer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-importer_unittest.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-importer_unittest.o `test -f 'google/protobuf/compiler/importer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/importer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/importer_unittest.cc' object='google/protobuf/compiler/protobuf_test-importer_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-importer_unittest.o `test -f 'google/protobuf/compiler/importer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/importer_unittest.cc
+
+google/protobuf/compiler/protobuf_test-importer_unittest.obj: google/protobuf/compiler/importer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-importer_unittest.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-importer_unittest.obj `if test -f 'google/protobuf/compiler/importer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/importer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/importer_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/importer_unittest.cc' object='google/protobuf/compiler/protobuf_test-importer_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-importer_unittest.obj `if test -f 'google/protobuf/compiler/importer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/importer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/importer_unittest.cc'; fi`
+
+google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.o: google/protobuf/compiler/java/doc_comment_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.o -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.o `test -f 'google/protobuf/compiler/java/doc_comment_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/doc_comment_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/doc_comment_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.o `test -f 'google/protobuf/compiler/java/doc_comment_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/doc_comment_unittest.cc
+
+google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.obj: google/protobuf/compiler/java/doc_comment_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.obj -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.obj `if test -f 'google/protobuf/compiler/java/doc_comment_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/doc_comment_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/doc_comment_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/doc_comment_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-doc_comment_unittest.obj `if test -f 'google/protobuf/compiler/java/doc_comment_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/doc_comment_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/doc_comment_unittest.cc'; fi`
+
+google/protobuf/compiler/java/protobuf_test-plugin_unittest.o: google/protobuf/compiler/java/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-plugin_unittest.o -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-plugin_unittest.o `test -f 'google/protobuf/compiler/java/plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/plugin_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-plugin_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-plugin_unittest.o `test -f 'google/protobuf/compiler/java/plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/plugin_unittest.cc
+
+google/protobuf/compiler/java/protobuf_test-plugin_unittest.obj: google/protobuf/compiler/java/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-plugin_unittest.obj -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-plugin_unittest.obj `if test -f 'google/protobuf/compiler/java/plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/plugin_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/plugin_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-plugin_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-plugin_unittest.obj `if test -f 'google/protobuf/compiler/java/plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/plugin_unittest.cc'; fi`
+
+google/protobuf/compiler/protobuf_test-mock_code_generator.o: google/protobuf/compiler/mock_code_generator.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-mock_code_generator.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/protobuf_test-mock_code_generator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
+
+google/protobuf/compiler/protobuf_test-mock_code_generator.obj: google/protobuf/compiler/mock_code_generator.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-mock_code_generator.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/protobuf_test-mock_code_generator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
+
+google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.o: google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.o -MD -MP -MF google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Tpo -c -o google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.o `test -f 'google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Tpo google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc' object='google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.o `test -f 'google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
+
+google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.obj: google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.obj -MD -MP -MF google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Tpo -c -o google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.obj `if test -f 'google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Tpo google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc' object='google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/objectivec/protobuf_test-objectivec_helpers_unittest.obj `if test -f 'google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc'; fi`
+
+google/protobuf/compiler/protobuf_test-parser_unittest.o: google/protobuf/compiler/parser_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-parser_unittest.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-parser_unittest.o `test -f 'google/protobuf/compiler/parser_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/parser_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/parser_unittest.cc' object='google/protobuf/compiler/protobuf_test-parser_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-parser_unittest.o `test -f 'google/protobuf/compiler/parser_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/parser_unittest.cc
+
+google/protobuf/compiler/protobuf_test-parser_unittest.obj: google/protobuf/compiler/parser_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-parser_unittest.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-parser_unittest.obj `if test -f 'google/protobuf/compiler/parser_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/parser_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/parser_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/parser_unittest.cc' object='google/protobuf/compiler/protobuf_test-parser_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-parser_unittest.obj `if test -f 'google/protobuf/compiler/parser_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/parser_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/parser_unittest.cc'; fi`
+
+google/protobuf/compiler/python/protobuf_test-plugin_unittest.o: google/protobuf/compiler/python/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/python/protobuf_test-plugin_unittest.o -MD -MP -MF google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo -c -o google/protobuf/compiler/python/protobuf_test-plugin_unittest.o `test -f 'google/protobuf/compiler/python/plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/python/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/python/plugin_unittest.cc' object='google/protobuf/compiler/python/protobuf_test-plugin_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/python/protobuf_test-plugin_unittest.o `test -f 'google/protobuf/compiler/python/plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/python/plugin_unittest.cc
+
+google/protobuf/compiler/python/protobuf_test-plugin_unittest.obj: google/protobuf/compiler/python/plugin_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/python/protobuf_test-plugin_unittest.obj -MD -MP -MF google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo -c -o google/protobuf/compiler/python/protobuf_test-plugin_unittest.obj `if test -f 'google/protobuf/compiler/python/plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/python/plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/python/plugin_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Tpo google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/python/plugin_unittest.cc' object='google/protobuf/compiler/python/protobuf_test-plugin_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/python/protobuf_test-plugin_unittest.obj `if test -f 'google/protobuf/compiler/python/plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/python/plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/python/plugin_unittest.cc'; fi`
+
+google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.o: google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.o -MD -MP -MF google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Tpo -c -o google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.o `test -f 'google/protobuf/compiler/ruby/ruby_generator_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Tpo google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/ruby/ruby_generator_unittest.cc' object='google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.o `test -f 'google/protobuf/compiler/ruby/ruby_generator_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+
+google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.obj: google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.obj -MD -MP -MF google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Tpo -c -o google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.obj `if test -f 'google/protobuf/compiler/ruby/ruby_generator_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/ruby/ruby_generator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/ruby/ruby_generator_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Tpo google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/ruby/ruby_generator_unittest.cc' object='google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/ruby/protobuf_test-ruby_generator_unittest.obj `if test -f 'google/protobuf/compiler/ruby/ruby_generator_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/ruby/ruby_generator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/ruby/ruby_generator_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-descriptor_database_unittest.o: google/protobuf/descriptor_database_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_database_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_database_unittest.o `test -f 'google/protobuf/descriptor_database_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_database_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_database_unittest.cc' object='google/protobuf/protobuf_test-descriptor_database_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_database_unittest.o `test -f 'google/protobuf/descriptor_database_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_database_unittest.cc
+
+google/protobuf/protobuf_test-descriptor_database_unittest.obj: google/protobuf/descriptor_database_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_database_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_database_unittest.obj `if test -f 'google/protobuf/descriptor_database_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_database_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_database_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_database_unittest.cc' object='google/protobuf/protobuf_test-descriptor_database_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_database_unittest.obj `if test -f 'google/protobuf/descriptor_database_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_database_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_database_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-descriptor_unittest.o: google/protobuf/descriptor_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_unittest.o `test -f 'google/protobuf/descriptor_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_unittest.cc' object='google/protobuf/protobuf_test-descriptor_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_unittest.o `test -f 'google/protobuf/descriptor_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_unittest.cc
+
+google/protobuf/protobuf_test-descriptor_unittest.obj: google/protobuf/descriptor_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_unittest.obj `if test -f 'google/protobuf/descriptor_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_unittest.cc' object='google/protobuf/protobuf_test-descriptor_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_unittest.obj `if test -f 'google/protobuf/descriptor_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-drop_unknown_fields_test.o: google/protobuf/drop_unknown_fields_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-drop_unknown_fields_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Tpo -c -o google/protobuf/protobuf_test-drop_unknown_fields_test.o `test -f 'google/protobuf/drop_unknown_fields_test.cc' || echo '$(srcdir)/'`google/protobuf/drop_unknown_fields_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/drop_unknown_fields_test.cc' object='google/protobuf/protobuf_test-drop_unknown_fields_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-drop_unknown_fields_test.o `test -f 'google/protobuf/drop_unknown_fields_test.cc' || echo '$(srcdir)/'`google/protobuf/drop_unknown_fields_test.cc
+
+google/protobuf/protobuf_test-drop_unknown_fields_test.obj: google/protobuf/drop_unknown_fields_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-drop_unknown_fields_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Tpo -c -o google/protobuf/protobuf_test-drop_unknown_fields_test.obj `if test -f 'google/protobuf/drop_unknown_fields_test.cc'; then $(CYGPATH_W) 'google/protobuf/drop_unknown_fields_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/drop_unknown_fields_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/drop_unknown_fields_test.cc' object='google/protobuf/protobuf_test-drop_unknown_fields_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-drop_unknown_fields_test.obj `if test -f 'google/protobuf/drop_unknown_fields_test.cc'; then $(CYGPATH_W) 'google/protobuf/drop_unknown_fields_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/drop_unknown_fields_test.cc'; fi`
+
+google/protobuf/protobuf_test-dynamic_message_unittest.o: google/protobuf/dynamic_message_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-dynamic_message_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo -c -o google/protobuf/protobuf_test-dynamic_message_unittest.o `test -f 'google/protobuf/dynamic_message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/dynamic_message_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/dynamic_message_unittest.cc' object='google/protobuf/protobuf_test-dynamic_message_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-dynamic_message_unittest.o `test -f 'google/protobuf/dynamic_message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/dynamic_message_unittest.cc
+
+google/protobuf/protobuf_test-dynamic_message_unittest.obj: google/protobuf/dynamic_message_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-dynamic_message_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo -c -o google/protobuf/protobuf_test-dynamic_message_unittest.obj `if test -f 'google/protobuf/dynamic_message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/dynamic_message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/dynamic_message_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/dynamic_message_unittest.cc' object='google/protobuf/protobuf_test-dynamic_message_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-dynamic_message_unittest.obj `if test -f 'google/protobuf/dynamic_message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/dynamic_message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/dynamic_message_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-extension_set_unittest.o: google/protobuf/extension_set_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-extension_set_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo -c -o google/protobuf/protobuf_test-extension_set_unittest.o `test -f 'google/protobuf/extension_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/extension_set_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/extension_set_unittest.cc' object='google/protobuf/protobuf_test-extension_set_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-extension_set_unittest.o `test -f 'google/protobuf/extension_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/extension_set_unittest.cc
+
+google/protobuf/protobuf_test-extension_set_unittest.obj: google/protobuf/extension_set_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-extension_set_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo -c -o google/protobuf/protobuf_test-extension_set_unittest.obj `if test -f 'google/protobuf/extension_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/extension_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/extension_set_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/extension_set_unittest.cc' object='google/protobuf/protobuf_test-extension_set_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-extension_set_unittest.obj `if test -f 'google/protobuf/extension_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/extension_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/extension_set_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-generated_message_reflection_unittest.o: google/protobuf/generated_message_reflection_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-generated_message_reflection_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.o `test -f 'google/protobuf/generated_message_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/generated_message_reflection_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/generated_message_reflection_unittest.cc' object='google/protobuf/protobuf_test-generated_message_reflection_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.o `test -f 'google/protobuf/generated_message_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/generated_message_reflection_unittest.cc
+
+google/protobuf/protobuf_test-generated_message_reflection_unittest.obj: google/protobuf/generated_message_reflection_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-generated_message_reflection_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.obj `if test -f 'google/protobuf/generated_message_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/generated_message_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/generated_message_reflection_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/generated_message_reflection_unittest.cc' object='google/protobuf/protobuf_test-generated_message_reflection_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.obj `if test -f 'google/protobuf/generated_message_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/generated_message_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/generated_message_reflection_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-generated_message_tctable_lite_test.o: google/protobuf/generated_message_tctable_lite_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-generated_message_tctable_lite_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Tpo -c -o google/protobuf/protobuf_test-generated_message_tctable_lite_test.o `test -f 'google/protobuf/generated_message_tctable_lite_test.cc' || echo '$(srcdir)/'`google/protobuf/generated_message_tctable_lite_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/generated_message_tctable_lite_test.cc' object='google/protobuf/protobuf_test-generated_message_tctable_lite_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-generated_message_tctable_lite_test.o `test -f 'google/protobuf/generated_message_tctable_lite_test.cc' || echo '$(srcdir)/'`google/protobuf/generated_message_tctable_lite_test.cc
+
+google/protobuf/protobuf_test-generated_message_tctable_lite_test.obj: google/protobuf/generated_message_tctable_lite_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-generated_message_tctable_lite_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Tpo -c -o google/protobuf/protobuf_test-generated_message_tctable_lite_test.obj `if test -f 'google/protobuf/generated_message_tctable_lite_test.cc'; then $(CYGPATH_W) 'google/protobuf/generated_message_tctable_lite_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/generated_message_tctable_lite_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/generated_message_tctable_lite_test.cc' object='google/protobuf/protobuf_test-generated_message_tctable_lite_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-generated_message_tctable_lite_test.obj `if test -f 'google/protobuf/generated_message_tctable_lite_test.cc'; then $(CYGPATH_W) 'google/protobuf/generated_message_tctable_lite_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/generated_message_tctable_lite_test.cc'; fi`
+
+google/protobuf/protobuf_test-inlined_string_field_unittest.o: google/protobuf/inlined_string_field_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-inlined_string_field_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Tpo -c -o google/protobuf/protobuf_test-inlined_string_field_unittest.o `test -f 'google/protobuf/inlined_string_field_unittest.cc' || echo '$(srcdir)/'`google/protobuf/inlined_string_field_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/inlined_string_field_unittest.cc' object='google/protobuf/protobuf_test-inlined_string_field_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-inlined_string_field_unittest.o `test -f 'google/protobuf/inlined_string_field_unittest.cc' || echo '$(srcdir)/'`google/protobuf/inlined_string_field_unittest.cc
+
+google/protobuf/protobuf_test-inlined_string_field_unittest.obj: google/protobuf/inlined_string_field_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-inlined_string_field_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Tpo -c -o google/protobuf/protobuf_test-inlined_string_field_unittest.obj `if test -f 'google/protobuf/inlined_string_field_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/inlined_string_field_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/inlined_string_field_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/inlined_string_field_unittest.cc' object='google/protobuf/protobuf_test-inlined_string_field_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-inlined_string_field_unittest.obj `if test -f 'google/protobuf/inlined_string_field_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/inlined_string_field_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/inlined_string_field_unittest.cc'; fi`
+
+google/protobuf/io/protobuf_test-coded_stream_unittest.o: google/protobuf/io/coded_stream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-coded_stream_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.o `test -f 'google/protobuf/io/coded_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/coded_stream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/coded_stream_unittest.cc' object='google/protobuf/io/protobuf_test-coded_stream_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.o `test -f 'google/protobuf/io/coded_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/coded_stream_unittest.cc
+
+google/protobuf/io/protobuf_test-coded_stream_unittest.obj: google/protobuf/io/coded_stream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-coded_stream_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.obj `if test -f 'google/protobuf/io/coded_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/coded_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/coded_stream_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/coded_stream_unittest.cc' object='google/protobuf/io/protobuf_test-coded_stream_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.obj `if test -f 'google/protobuf/io/coded_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/coded_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/coded_stream_unittest.cc'; fi`
+
+google/protobuf/io/protobuf_test-io_win32_unittest.o: google/protobuf/io/io_win32_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-io_win32_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Tpo -c -o google/protobuf/io/protobuf_test-io_win32_unittest.o `test -f 'google/protobuf/io/io_win32_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/io_win32_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/io_win32_unittest.cc' object='google/protobuf/io/protobuf_test-io_win32_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-io_win32_unittest.o `test -f 'google/protobuf/io/io_win32_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/io_win32_unittest.cc
+
+google/protobuf/io/protobuf_test-io_win32_unittest.obj: google/protobuf/io/io_win32_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-io_win32_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Tpo -c -o google/protobuf/io/protobuf_test-io_win32_unittest.obj `if test -f 'google/protobuf/io/io_win32_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/io_win32_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/io_win32_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/io_win32_unittest.cc' object='google/protobuf/io/protobuf_test-io_win32_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-io_win32_unittest.obj `if test -f 'google/protobuf/io/io_win32_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/io_win32_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/io_win32_unittest.cc'; fi`
+
+google/protobuf/io/protobuf_test-printer_unittest.o: google/protobuf/io/printer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-printer_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-printer_unittest.o `test -f 'google/protobuf/io/printer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/printer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/printer_unittest.cc' object='google/protobuf/io/protobuf_test-printer_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-printer_unittest.o `test -f 'google/protobuf/io/printer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/printer_unittest.cc
+
+google/protobuf/io/protobuf_test-printer_unittest.obj: google/protobuf/io/printer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-printer_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-printer_unittest.obj `if test -f 'google/protobuf/io/printer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/printer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/printer_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/printer_unittest.cc' object='google/protobuf/io/protobuf_test-printer_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-printer_unittest.obj `if test -f 'google/protobuf/io/printer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/printer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/printer_unittest.cc'; fi`
+
+google/protobuf/io/protobuf_test-tokenizer_unittest.o: google/protobuf/io/tokenizer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-tokenizer_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.o `test -f 'google/protobuf/io/tokenizer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/tokenizer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/tokenizer_unittest.cc' object='google/protobuf/io/protobuf_test-tokenizer_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.o `test -f 'google/protobuf/io/tokenizer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/tokenizer_unittest.cc
+
+google/protobuf/io/protobuf_test-tokenizer_unittest.obj: google/protobuf/io/tokenizer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-tokenizer_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.obj `if test -f 'google/protobuf/io/tokenizer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/tokenizer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/tokenizer_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/tokenizer_unittest.cc' object='google/protobuf/io/protobuf_test-tokenizer_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.obj `if test -f 'google/protobuf/io/tokenizer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/tokenizer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/tokenizer_unittest.cc'; fi`
+
+google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o: google/protobuf/io/zero_copy_stream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o `test -f 'google/protobuf/io/zero_copy_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/zero_copy_stream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/zero_copy_stream_unittest.cc' object='google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o `test -f 'google/protobuf/io/zero_copy_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/zero_copy_stream_unittest.cc
+
+google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj: google/protobuf/io/zero_copy_stream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj `if test -f 'google/protobuf/io/zero_copy_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/zero_copy_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/zero_copy_stream_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/zero_copy_stream_unittest.cc' object='google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj `if test -f 'google/protobuf/io/zero_copy_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/zero_copy_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/zero_copy_stream_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-map_field_test.o: google/protobuf/map_field_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_field_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Tpo -c -o google/protobuf/protobuf_test-map_field_test.o `test -f 'google/protobuf/map_field_test.cc' || echo '$(srcdir)/'`google/protobuf/map_field_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_field_test.cc' object='google/protobuf/protobuf_test-map_field_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_field_test.o `test -f 'google/protobuf/map_field_test.cc' || echo '$(srcdir)/'`google/protobuf/map_field_test.cc
+
+google/protobuf/protobuf_test-map_field_test.obj: google/protobuf/map_field_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_field_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Tpo -c -o google/protobuf/protobuf_test-map_field_test.obj `if test -f 'google/protobuf/map_field_test.cc'; then $(CYGPATH_W) 'google/protobuf/map_field_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_field_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_field_test.cc' object='google/protobuf/protobuf_test-map_field_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_field_test.obj `if test -f 'google/protobuf/map_field_test.cc'; then $(CYGPATH_W) 'google/protobuf/map_field_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_field_test.cc'; fi`
+
+google/protobuf/protobuf_test-map_test.o: google/protobuf/map_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_test.Tpo -c -o google/protobuf/protobuf_test-map_test.o `test -f 'google/protobuf/map_test.cc' || echo '$(srcdir)/'`google/protobuf/map_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_test.cc' object='google/protobuf/protobuf_test-map_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_test.o `test -f 'google/protobuf/map_test.cc' || echo '$(srcdir)/'`google/protobuf/map_test.cc
+
+google/protobuf/protobuf_test-map_test.obj: google/protobuf/map_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_test.Tpo -c -o google/protobuf/protobuf_test-map_test.obj `if test -f 'google/protobuf/map_test.cc'; then $(CYGPATH_W) 'google/protobuf/map_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_test.cc' object='google/protobuf/protobuf_test-map_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_test.obj `if test -f 'google/protobuf/map_test.cc'; then $(CYGPATH_W) 'google/protobuf/map_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_test.cc'; fi`
+
+google/protobuf/protobuf_test-message_unittest.o: google/protobuf/message_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-message_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo -c -o google/protobuf/protobuf_test-message_unittest.o `test -f 'google/protobuf/message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/message_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/message_unittest.cc' object='google/protobuf/protobuf_test-message_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-message_unittest.o `test -f 'google/protobuf/message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/message_unittest.cc
+
+google/protobuf/protobuf_test-message_unittest.obj: google/protobuf/message_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-message_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo -c -o google/protobuf/protobuf_test-message_unittest.obj `if test -f 'google/protobuf/message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/message_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/message_unittest.cc' object='google/protobuf/protobuf_test-message_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-message_unittest.obj `if test -f 'google/protobuf/message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/message_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-no_field_presence_test.o: google/protobuf/no_field_presence_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-no_field_presence_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Tpo -c -o google/protobuf/protobuf_test-no_field_presence_test.o `test -f 'google/protobuf/no_field_presence_test.cc' || echo '$(srcdir)/'`google/protobuf/no_field_presence_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/no_field_presence_test.cc' object='google/protobuf/protobuf_test-no_field_presence_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-no_field_presence_test.o `test -f 'google/protobuf/no_field_presence_test.cc' || echo '$(srcdir)/'`google/protobuf/no_field_presence_test.cc
+
+google/protobuf/protobuf_test-no_field_presence_test.obj: google/protobuf/no_field_presence_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-no_field_presence_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Tpo -c -o google/protobuf/protobuf_test-no_field_presence_test.obj `if test -f 'google/protobuf/no_field_presence_test.cc'; then $(CYGPATH_W) 'google/protobuf/no_field_presence_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/no_field_presence_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/no_field_presence_test.cc' object='google/protobuf/protobuf_test-no_field_presence_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-no_field_presence_test.obj `if test -f 'google/protobuf/no_field_presence_test.cc'; then $(CYGPATH_W) 'google/protobuf/no_field_presence_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/no_field_presence_test.cc'; fi`
+
+google/protobuf/protobuf_test-preserve_unknown_enum_test.o: google/protobuf/preserve_unknown_enum_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-preserve_unknown_enum_test.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Tpo -c -o google/protobuf/protobuf_test-preserve_unknown_enum_test.o `test -f 'google/protobuf/preserve_unknown_enum_test.cc' || echo '$(srcdir)/'`google/protobuf/preserve_unknown_enum_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/preserve_unknown_enum_test.cc' object='google/protobuf/protobuf_test-preserve_unknown_enum_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-preserve_unknown_enum_test.o `test -f 'google/protobuf/preserve_unknown_enum_test.cc' || echo '$(srcdir)/'`google/protobuf/preserve_unknown_enum_test.cc
+
+google/protobuf/protobuf_test-preserve_unknown_enum_test.obj: google/protobuf/preserve_unknown_enum_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-preserve_unknown_enum_test.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Tpo -c -o google/protobuf/protobuf_test-preserve_unknown_enum_test.obj `if test -f 'google/protobuf/preserve_unknown_enum_test.cc'; then $(CYGPATH_W) 'google/protobuf/preserve_unknown_enum_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/preserve_unknown_enum_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Tpo google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/preserve_unknown_enum_test.cc' object='google/protobuf/protobuf_test-preserve_unknown_enum_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-preserve_unknown_enum_test.obj `if test -f 'google/protobuf/preserve_unknown_enum_test.cc'; then $(CYGPATH_W) 'google/protobuf/preserve_unknown_enum_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/preserve_unknown_enum_test.cc'; fi`
+
+google/protobuf/protobuf_test-proto3_arena_lite_unittest.o: google/protobuf/proto3_arena_lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-proto3_arena_lite_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Tpo -c -o google/protobuf/protobuf_test-proto3_arena_lite_unittest.o `test -f 'google/protobuf/proto3_arena_lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/proto3_arena_lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/proto3_arena_lite_unittest.cc' object='google/protobuf/protobuf_test-proto3_arena_lite_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-proto3_arena_lite_unittest.o `test -f 'google/protobuf/proto3_arena_lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/proto3_arena_lite_unittest.cc
+
+google/protobuf/protobuf_test-proto3_arena_lite_unittest.obj: google/protobuf/proto3_arena_lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-proto3_arena_lite_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Tpo -c -o google/protobuf/protobuf_test-proto3_arena_lite_unittest.obj `if test -f 'google/protobuf/proto3_arena_lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/proto3_arena_lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/proto3_arena_lite_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/proto3_arena_lite_unittest.cc' object='google/protobuf/protobuf_test-proto3_arena_lite_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-proto3_arena_lite_unittest.obj `if test -f 'google/protobuf/proto3_arena_lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/proto3_arena_lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/proto3_arena_lite_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-proto3_arena_unittest.o: google/protobuf/proto3_arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-proto3_arena_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Tpo -c -o google/protobuf/protobuf_test-proto3_arena_unittest.o `test -f 'google/protobuf/proto3_arena_unittest.cc' || echo '$(srcdir)/'`google/protobuf/proto3_arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/proto3_arena_unittest.cc' object='google/protobuf/protobuf_test-proto3_arena_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-proto3_arena_unittest.o `test -f 'google/protobuf/proto3_arena_unittest.cc' || echo '$(srcdir)/'`google/protobuf/proto3_arena_unittest.cc
+
+google/protobuf/protobuf_test-proto3_arena_unittest.obj: google/protobuf/proto3_arena_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-proto3_arena_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Tpo -c -o google/protobuf/protobuf_test-proto3_arena_unittest.obj `if test -f 'google/protobuf/proto3_arena_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/proto3_arena_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/proto3_arena_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/proto3_arena_unittest.cc' object='google/protobuf/protobuf_test-proto3_arena_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-proto3_arena_unittest.obj `if test -f 'google/protobuf/proto3_arena_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/proto3_arena_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/proto3_arena_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-proto3_lite_unittest.o: google/protobuf/proto3_lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-proto3_lite_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Tpo -c -o google/protobuf/protobuf_test-proto3_lite_unittest.o `test -f 'google/protobuf/proto3_lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/proto3_lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/proto3_lite_unittest.cc' object='google/protobuf/protobuf_test-proto3_lite_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-proto3_lite_unittest.o `test -f 'google/protobuf/proto3_lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/proto3_lite_unittest.cc
+
+google/protobuf/protobuf_test-proto3_lite_unittest.obj: google/protobuf/proto3_lite_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-proto3_lite_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Tpo -c -o google/protobuf/protobuf_test-proto3_lite_unittest.obj `if test -f 'google/protobuf/proto3_lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/proto3_lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/proto3_lite_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/proto3_lite_unittest.cc' object='google/protobuf/protobuf_test-proto3_lite_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-proto3_lite_unittest.obj `if test -f 'google/protobuf/proto3_lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/proto3_lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/proto3_lite_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-reflection_ops_unittest.o: google/protobuf/reflection_ops_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-reflection_ops_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo -c -o google/protobuf/protobuf_test-reflection_ops_unittest.o `test -f 'google/protobuf/reflection_ops_unittest.cc' || echo '$(srcdir)/'`google/protobuf/reflection_ops_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_ops_unittest.cc' object='google/protobuf/protobuf_test-reflection_ops_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-reflection_ops_unittest.o `test -f 'google/protobuf/reflection_ops_unittest.cc' || echo '$(srcdir)/'`google/protobuf/reflection_ops_unittest.cc
+
+google/protobuf/protobuf_test-reflection_ops_unittest.obj: google/protobuf/reflection_ops_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-reflection_ops_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo -c -o google/protobuf/protobuf_test-reflection_ops_unittest.obj `if test -f 'google/protobuf/reflection_ops_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_ops_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_ops_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_ops_unittest.cc' object='google/protobuf/protobuf_test-reflection_ops_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-reflection_ops_unittest.obj `if test -f 'google/protobuf/reflection_ops_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_ops_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_ops_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-repeated_field_reflection_unittest.o: google/protobuf/repeated_field_reflection_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_reflection_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.o `test -f 'google/protobuf/repeated_field_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_reflection_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_reflection_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_reflection_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.o `test -f 'google/protobuf/repeated_field_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_reflection_unittest.cc
+
+google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj: google/protobuf/repeated_field_reflection_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj `if test -f 'google/protobuf/repeated_field_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_reflection_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_reflection_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj `if test -f 'google/protobuf/repeated_field_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_reflection_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-repeated_field_unittest.o: google/protobuf/repeated_field_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_unittest.o `test -f 'google/protobuf/repeated_field_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_unittest.o `test -f 'google/protobuf/repeated_field_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_unittest.cc
+
+google/protobuf/protobuf_test-repeated_field_unittest.obj: google/protobuf/repeated_field_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_unittest.obj `if test -f 'google/protobuf/repeated_field_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_unittest.obj `if test -f 'google/protobuf/repeated_field_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-bytestream_unittest.o: google/protobuf/stubs/bytestream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-bytestream_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-bytestream_unittest.o `test -f 'google/protobuf/stubs/bytestream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/bytestream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/bytestream_unittest.cc' object='google/protobuf/stubs/protobuf_test-bytestream_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-bytestream_unittest.o `test -f 'google/protobuf/stubs/bytestream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/bytestream_unittest.cc
+
+google/protobuf/stubs/protobuf_test-bytestream_unittest.obj: google/protobuf/stubs/bytestream_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-bytestream_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-bytestream_unittest.obj `if test -f 'google/protobuf/stubs/bytestream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/bytestream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/bytestream_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/bytestream_unittest.cc' object='google/protobuf/stubs/protobuf_test-bytestream_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-bytestream_unittest.obj `if test -f 'google/protobuf/stubs/bytestream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/bytestream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/bytestream_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-common_unittest.o: google/protobuf/stubs/common_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-common_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-common_unittest.o `test -f 'google/protobuf/stubs/common_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/common_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/common_unittest.cc' object='google/protobuf/stubs/protobuf_test-common_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-common_unittest.o `test -f 'google/protobuf/stubs/common_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/common_unittest.cc
+
+google/protobuf/stubs/protobuf_test-common_unittest.obj: google/protobuf/stubs/common_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-common_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-common_unittest.obj `if test -f 'google/protobuf/stubs/common_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/common_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/common_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/common_unittest.cc' object='google/protobuf/stubs/protobuf_test-common_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-common_unittest.obj `if test -f 'google/protobuf/stubs/common_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/common_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/common_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-int128_unittest.o: google/protobuf/stubs/int128_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-int128_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-int128_unittest.o `test -f 'google/protobuf/stubs/int128_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/int128_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/int128_unittest.cc' object='google/protobuf/stubs/protobuf_test-int128_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-int128_unittest.o `test -f 'google/protobuf/stubs/int128_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/int128_unittest.cc
+
+google/protobuf/stubs/protobuf_test-int128_unittest.obj: google/protobuf/stubs/int128_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-int128_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-int128_unittest.obj `if test -f 'google/protobuf/stubs/int128_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/int128_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/int128_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/int128_unittest.cc' object='google/protobuf/stubs/protobuf_test-int128_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-int128_unittest.obj `if test -f 'google/protobuf/stubs/int128_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/int128_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/int128_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-status_test.o: google/protobuf/stubs/status_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-status_test.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Tpo -c -o google/protobuf/stubs/protobuf_test-status_test.o `test -f 'google/protobuf/stubs/status_test.cc' || echo '$(srcdir)/'`google/protobuf/stubs/status_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/status_test.cc' object='google/protobuf/stubs/protobuf_test-status_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-status_test.o `test -f 'google/protobuf/stubs/status_test.cc' || echo '$(srcdir)/'`google/protobuf/stubs/status_test.cc
+
+google/protobuf/stubs/protobuf_test-status_test.obj: google/protobuf/stubs/status_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-status_test.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Tpo -c -o google/protobuf/stubs/protobuf_test-status_test.obj `if test -f 'google/protobuf/stubs/status_test.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/status_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/status_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/status_test.cc' object='google/protobuf/stubs/protobuf_test-status_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-status_test.obj `if test -f 'google/protobuf/stubs/status_test.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/status_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/status_test.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-statusor_test.o: google/protobuf/stubs/statusor_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-statusor_test.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Tpo -c -o google/protobuf/stubs/protobuf_test-statusor_test.o `test -f 'google/protobuf/stubs/statusor_test.cc' || echo '$(srcdir)/'`google/protobuf/stubs/statusor_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/statusor_test.cc' object='google/protobuf/stubs/protobuf_test-statusor_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-statusor_test.o `test -f 'google/protobuf/stubs/statusor_test.cc' || echo '$(srcdir)/'`google/protobuf/stubs/statusor_test.cc
+
+google/protobuf/stubs/protobuf_test-statusor_test.obj: google/protobuf/stubs/statusor_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-statusor_test.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Tpo -c -o google/protobuf/stubs/protobuf_test-statusor_test.obj `if test -f 'google/protobuf/stubs/statusor_test.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/statusor_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/statusor_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/statusor_test.cc' object='google/protobuf/stubs/protobuf_test-statusor_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-statusor_test.obj `if test -f 'google/protobuf/stubs/statusor_test.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/statusor_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/statusor_test.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-stringpiece_unittest.o: google/protobuf/stubs/stringpiece_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-stringpiece_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-stringpiece_unittest.o `test -f 'google/protobuf/stubs/stringpiece_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/stringpiece_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/stringpiece_unittest.cc' object='google/protobuf/stubs/protobuf_test-stringpiece_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-stringpiece_unittest.o `test -f 'google/protobuf/stubs/stringpiece_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/stringpiece_unittest.cc
+
+google/protobuf/stubs/protobuf_test-stringpiece_unittest.obj: google/protobuf/stubs/stringpiece_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-stringpiece_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-stringpiece_unittest.obj `if test -f 'google/protobuf/stubs/stringpiece_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/stringpiece_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/stringpiece_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/stringpiece_unittest.cc' object='google/protobuf/stubs/protobuf_test-stringpiece_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-stringpiece_unittest.obj `if test -f 'google/protobuf/stubs/stringpiece_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/stringpiece_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/stringpiece_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-stringprintf_unittest.o: google/protobuf/stubs/stringprintf_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-stringprintf_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.o `test -f 'google/protobuf/stubs/stringprintf_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/stringprintf_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/stringprintf_unittest.cc' object='google/protobuf/stubs/protobuf_test-stringprintf_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.o `test -f 'google/protobuf/stubs/stringprintf_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/stringprintf_unittest.cc
+
+google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj: google/protobuf/stubs/stringprintf_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj `if test -f 'google/protobuf/stubs/stringprintf_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/stringprintf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/stringprintf_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/stringprintf_unittest.cc' object='google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj `if test -f 'google/protobuf/stubs/stringprintf_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/stringprintf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/stringprintf_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o: google/protobuf/stubs/structurally_valid_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o `test -f 'google/protobuf/stubs/structurally_valid_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/structurally_valid_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/structurally_valid_unittest.cc' object='google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o `test -f 'google/protobuf/stubs/structurally_valid_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/structurally_valid_unittest.cc
+
+google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj: google/protobuf/stubs/structurally_valid_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj `if test -f 'google/protobuf/stubs/structurally_valid_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/structurally_valid_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/structurally_valid_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/structurally_valid_unittest.cc' object='google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj `if test -f 'google/protobuf/stubs/structurally_valid_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/structurally_valid_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/structurally_valid_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-strutil_unittest.o: google/protobuf/stubs/strutil_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-strutil_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.o `test -f 'google/protobuf/stubs/strutil_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/strutil_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/strutil_unittest.cc' object='google/protobuf/stubs/protobuf_test-strutil_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.o `test -f 'google/protobuf/stubs/strutil_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/strutil_unittest.cc
+
+google/protobuf/stubs/protobuf_test-strutil_unittest.obj: google/protobuf/stubs/strutil_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-strutil_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.obj `if test -f 'google/protobuf/stubs/strutil_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/strutil_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/strutil_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/strutil_unittest.cc' object='google/protobuf/stubs/protobuf_test-strutil_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.obj `if test -f 'google/protobuf/stubs/strutil_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/strutil_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/strutil_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-template_util_unittest.o: google/protobuf/stubs/template_util_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-template_util_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.o `test -f 'google/protobuf/stubs/template_util_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/template_util_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/template_util_unittest.cc' object='google/protobuf/stubs/protobuf_test-template_util_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.o `test -f 'google/protobuf/stubs/template_util_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/template_util_unittest.cc
+
+google/protobuf/stubs/protobuf_test-template_util_unittest.obj: google/protobuf/stubs/template_util_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-template_util_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.obj `if test -f 'google/protobuf/stubs/template_util_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/template_util_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/template_util_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/template_util_unittest.cc' object='google/protobuf/stubs/protobuf_test-template_util_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.obj `if test -f 'google/protobuf/stubs/template_util_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/template_util_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/template_util_unittest.cc'; fi`
+
+google/protobuf/stubs/protobuf_test-time_test.o: google/protobuf/stubs/time_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-time_test.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Tpo -c -o google/protobuf/stubs/protobuf_test-time_test.o `test -f 'google/protobuf/stubs/time_test.cc' || echo '$(srcdir)/'`google/protobuf/stubs/time_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/time_test.cc' object='google/protobuf/stubs/protobuf_test-time_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-time_test.o `test -f 'google/protobuf/stubs/time_test.cc' || echo '$(srcdir)/'`google/protobuf/stubs/time_test.cc
+
+google/protobuf/stubs/protobuf_test-time_test.obj: google/protobuf/stubs/time_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-time_test.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Tpo -c -o google/protobuf/stubs/protobuf_test-time_test.obj `if test -f 'google/protobuf/stubs/time_test.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/time_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/time_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/time_test.cc' object='google/protobuf/stubs/protobuf_test-time_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-time_test.obj `if test -f 'google/protobuf/stubs/time_test.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/time_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/time_test.cc'; fi`
+
+google/protobuf/protobuf_test-text_format_unittest.o: google/protobuf/text_format_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-text_format_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo -c -o google/protobuf/protobuf_test-text_format_unittest.o `test -f 'google/protobuf/text_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/text_format_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/text_format_unittest.cc' object='google/protobuf/protobuf_test-text_format_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-text_format_unittest.o `test -f 'google/protobuf/text_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/text_format_unittest.cc
+
+google/protobuf/protobuf_test-text_format_unittest.obj: google/protobuf/text_format_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-text_format_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo -c -o google/protobuf/protobuf_test-text_format_unittest.obj `if test -f 'google/protobuf/text_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/text_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/text_format_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/text_format_unittest.cc' object='google/protobuf/protobuf_test-text_format_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-text_format_unittest.obj `if test -f 'google/protobuf/text_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/text_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/text_format_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-unknown_field_set_unittest.o: google/protobuf/unknown_field_set_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unknown_field_set_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.o `test -f 'google/protobuf/unknown_field_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/unknown_field_set_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unknown_field_set_unittest.cc' object='google/protobuf/protobuf_test-unknown_field_set_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.o `test -f 'google/protobuf/unknown_field_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/unknown_field_set_unittest.cc
+
+google/protobuf/protobuf_test-unknown_field_set_unittest.obj: google/protobuf/unknown_field_set_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unknown_field_set_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.obj `if test -f 'google/protobuf/unknown_field_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/unknown_field_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unknown_field_set_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unknown_field_set_unittest.cc' object='google/protobuf/protobuf_test-unknown_field_set_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.obj `if test -f 'google/protobuf/unknown_field_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/unknown_field_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unknown_field_set_unittest.cc'; fi`
+
+google/protobuf/util/protobuf_test-delimited_message_util_test.o: google/protobuf/util/delimited_message_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-delimited_message_util_test.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Tpo -c -o google/protobuf/util/protobuf_test-delimited_message_util_test.o `test -f 'google/protobuf/util/delimited_message_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/delimited_message_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/delimited_message_util_test.cc' object='google/protobuf/util/protobuf_test-delimited_message_util_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-delimited_message_util_test.o `test -f 'google/protobuf/util/delimited_message_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/delimited_message_util_test.cc
+
+google/protobuf/util/protobuf_test-delimited_message_util_test.obj: google/protobuf/util/delimited_message_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-delimited_message_util_test.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Tpo -c -o google/protobuf/util/protobuf_test-delimited_message_util_test.obj `if test -f 'google/protobuf/util/delimited_message_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/delimited_message_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/delimited_message_util_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/delimited_message_util_test.cc' object='google/protobuf/util/protobuf_test-delimited_message_util_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-delimited_message_util_test.obj `if test -f 'google/protobuf/util/delimited_message_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/delimited_message_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/delimited_message_util_test.cc'; fi`
+
+google/protobuf/util/protobuf_test-field_comparator_test.o: google/protobuf/util/field_comparator_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-field_comparator_test.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Tpo -c -o google/protobuf/util/protobuf_test-field_comparator_test.o `test -f 'google/protobuf/util/field_comparator_test.cc' || echo '$(srcdir)/'`google/protobuf/util/field_comparator_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/field_comparator_test.cc' object='google/protobuf/util/protobuf_test-field_comparator_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-field_comparator_test.o `test -f 'google/protobuf/util/field_comparator_test.cc' || echo '$(srcdir)/'`google/protobuf/util/field_comparator_test.cc
+
+google/protobuf/util/protobuf_test-field_comparator_test.obj: google/protobuf/util/field_comparator_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-field_comparator_test.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Tpo -c -o google/protobuf/util/protobuf_test-field_comparator_test.obj `if test -f 'google/protobuf/util/field_comparator_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/field_comparator_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/field_comparator_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/field_comparator_test.cc' object='google/protobuf/util/protobuf_test-field_comparator_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-field_comparator_test.obj `if test -f 'google/protobuf/util/field_comparator_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/field_comparator_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/field_comparator_test.cc'; fi`
+
+google/protobuf/util/protobuf_test-field_mask_util_test.o: google/protobuf/util/field_mask_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-field_mask_util_test.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Tpo -c -o google/protobuf/util/protobuf_test-field_mask_util_test.o `test -f 'google/protobuf/util/field_mask_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/field_mask_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/field_mask_util_test.cc' object='google/protobuf/util/protobuf_test-field_mask_util_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-field_mask_util_test.o `test -f 'google/protobuf/util/field_mask_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/field_mask_util_test.cc
+
+google/protobuf/util/protobuf_test-field_mask_util_test.obj: google/protobuf/util/field_mask_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-field_mask_util_test.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Tpo -c -o google/protobuf/util/protobuf_test-field_mask_util_test.obj `if test -f 'google/protobuf/util/field_mask_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/field_mask_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/field_mask_util_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/field_mask_util_test.cc' object='google/protobuf/util/protobuf_test-field_mask_util_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-field_mask_util_test.obj `if test -f 'google/protobuf/util/field_mask_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/field_mask_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/field_mask_util_test.cc'; fi`
+
+google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.o: google/protobuf/util/internal/default_value_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.o -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.o `test -f 'google/protobuf/util/internal/default_value_objectwriter_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/default_value_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/default_value_objectwriter_test.cc' object='google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.o `test -f 'google/protobuf/util/internal/default_value_objectwriter_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/default_value_objectwriter_test.cc
+
+google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.obj: google/protobuf/util/internal/default_value_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.obj -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.obj `if test -f 'google/protobuf/util/internal/default_value_objectwriter_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/default_value_objectwriter_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/default_value_objectwriter_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/default_value_objectwriter_test.cc' object='google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-default_value_objectwriter_test.obj `if test -f 'google/protobuf/util/internal/default_value_objectwriter_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/default_value_objectwriter_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/default_value_objectwriter_test.cc'; fi`
+
+google/protobuf/util/internal/protobuf_test-json_objectwriter_test.o: google/protobuf/util/internal/json_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-json_objectwriter_test.o -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-json_objectwriter_test.o `test -f 'google/protobuf/util/internal/json_objectwriter_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/json_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/json_objectwriter_test.cc' object='google/protobuf/util/internal/protobuf_test-json_objectwriter_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-json_objectwriter_test.o `test -f 'google/protobuf/util/internal/json_objectwriter_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/json_objectwriter_test.cc
+
+google/protobuf/util/internal/protobuf_test-json_objectwriter_test.obj: google/protobuf/util/internal/json_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-json_objectwriter_test.obj -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-json_objectwriter_test.obj `if test -f 'google/protobuf/util/internal/json_objectwriter_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/json_objectwriter_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/json_objectwriter_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/json_objectwriter_test.cc' object='google/protobuf/util/internal/protobuf_test-json_objectwriter_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-json_objectwriter_test.obj `if test -f 'google/protobuf/util/internal/json_objectwriter_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/json_objectwriter_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/json_objectwriter_test.cc'; fi`
+
+google/protobuf/util/internal/protobuf_test-json_stream_parser_test.o: google/protobuf/util/internal/json_stream_parser_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-json_stream_parser_test.o -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-json_stream_parser_test.o `test -f 'google/protobuf/util/internal/json_stream_parser_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/json_stream_parser_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/json_stream_parser_test.cc' object='google/protobuf/util/internal/protobuf_test-json_stream_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-json_stream_parser_test.o `test -f 'google/protobuf/util/internal/json_stream_parser_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/json_stream_parser_test.cc
+
+google/protobuf/util/internal/protobuf_test-json_stream_parser_test.obj: google/protobuf/util/internal/json_stream_parser_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-json_stream_parser_test.obj -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-json_stream_parser_test.obj `if test -f 'google/protobuf/util/internal/json_stream_parser_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/json_stream_parser_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/json_stream_parser_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/json_stream_parser_test.cc' object='google/protobuf/util/internal/protobuf_test-json_stream_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-json_stream_parser_test.obj `if test -f 'google/protobuf/util/internal/json_stream_parser_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/json_stream_parser_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/json_stream_parser_test.cc'; fi`
+
+google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.o: google/protobuf/util/internal/protostream_objectsource_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.o -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.o `test -f 'google/protobuf/util/internal/protostream_objectsource_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/protostream_objectsource_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/protostream_objectsource_test.cc' object='google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.o `test -f 'google/protobuf/util/internal/protostream_objectsource_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/protostream_objectsource_test.cc
+
+google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.obj: google/protobuf/util/internal/protostream_objectsource_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.obj -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.obj `if test -f 'google/protobuf/util/internal/protostream_objectsource_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/protostream_objectsource_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/protostream_objectsource_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/protostream_objectsource_test.cc' object='google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-protostream_objectsource_test.obj `if test -f 'google/protobuf/util/internal/protostream_objectsource_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/protostream_objectsource_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/protostream_objectsource_test.cc'; fi`
+
+google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.o: google/protobuf/util/internal/protostream_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.o -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.o `test -f 'google/protobuf/util/internal/protostream_objectwriter_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/protostream_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/protostream_objectwriter_test.cc' object='google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.o `test -f 'google/protobuf/util/internal/protostream_objectwriter_test.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/protostream_objectwriter_test.cc
+
+google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.obj: google/protobuf/util/internal/protostream_objectwriter_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.obj -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Tpo -c -o google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.obj `if test -f 'google/protobuf/util/internal/protostream_objectwriter_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/protostream_objectwriter_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/protostream_objectwriter_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/protostream_objectwriter_test.cc' object='google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-protostream_objectwriter_test.obj `if test -f 'google/protobuf/util/internal/protostream_objectwriter_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/protostream_objectwriter_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/protostream_objectwriter_test.cc'; fi`
+
+google/protobuf/util/internal/protobuf_test-type_info_test_helper.o: google/protobuf/util/internal/type_info_test_helper.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-type_info_test_helper.o -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Tpo -c -o google/protobuf/util/internal/protobuf_test-type_info_test_helper.o `test -f 'google/protobuf/util/internal/type_info_test_helper.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/type_info_test_helper.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/type_info_test_helper.cc' object='google/protobuf/util/internal/protobuf_test-type_info_test_helper.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-type_info_test_helper.o `test -f 'google/protobuf/util/internal/type_info_test_helper.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/type_info_test_helper.cc
+
+google/protobuf/util/internal/protobuf_test-type_info_test_helper.obj: google/protobuf/util/internal/type_info_test_helper.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/protobuf_test-type_info_test_helper.obj -MD -MP -MF google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Tpo -c -o google/protobuf/util/internal/protobuf_test-type_info_test_helper.obj `if test -f 'google/protobuf/util/internal/type_info_test_helper.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/type_info_test_helper.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/type_info_test_helper.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Tpo google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/type_info_test_helper.cc' object='google/protobuf/util/internal/protobuf_test-type_info_test_helper.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/protobuf_test-type_info_test_helper.obj `if test -f 'google/protobuf/util/internal/type_info_test_helper.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/type_info_test_helper.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/type_info_test_helper.cc'; fi`
+
+google/protobuf/util/protobuf_test-json_util_test.o: google/protobuf/util/json_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-json_util_test.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Tpo -c -o google/protobuf/util/protobuf_test-json_util_test.o `test -f 'google/protobuf/util/json_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/json_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_util_test.cc' object='google/protobuf/util/protobuf_test-json_util_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-json_util_test.o `test -f 'google/protobuf/util/json_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/json_util_test.cc
+
+google/protobuf/util/protobuf_test-json_util_test.obj: google/protobuf/util/json_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-json_util_test.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Tpo -c -o google/protobuf/util/protobuf_test-json_util_test.obj `if test -f 'google/protobuf/util/json_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_util_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_util_test.cc' object='google/protobuf/util/protobuf_test-json_util_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-json_util_test.obj `if test -f 'google/protobuf/util/json_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_util_test.cc'; fi`
+
+google/protobuf/util/protobuf_test-message_differencer_unittest.o: google/protobuf/util/message_differencer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-message_differencer_unittest.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Tpo -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.o `test -f 'google/protobuf/util/message_differencer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.cc' object='google/protobuf/util/protobuf_test-message_differencer_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.o `test -f 'google/protobuf/util/message_differencer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.cc
+
+google/protobuf/util/protobuf_test-message_differencer_unittest.obj: google/protobuf/util/message_differencer_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-message_differencer_unittest.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Tpo -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.obj `if test -f 'google/protobuf/util/message_differencer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.cc' object='google/protobuf/util/protobuf_test-message_differencer_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.obj `if test -f 'google/protobuf/util/message_differencer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.cc'; fi`
+
+google/protobuf/util/protobuf_test-time_util_test.o: google/protobuf/util/time_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-time_util_test.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Tpo -c -o google/protobuf/util/protobuf_test-time_util_test.o `test -f 'google/protobuf/util/time_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/time_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/time_util_test.cc' object='google/protobuf/util/protobuf_test-time_util_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-time_util_test.o `test -f 'google/protobuf/util/time_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/time_util_test.cc
+
+google/protobuf/util/protobuf_test-time_util_test.obj: google/protobuf/util/time_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-time_util_test.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Tpo -c -o google/protobuf/util/protobuf_test-time_util_test.obj `if test -f 'google/protobuf/util/time_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/time_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/time_util_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/time_util_test.cc' object='google/protobuf/util/protobuf_test-time_util_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-time_util_test.obj `if test -f 'google/protobuf/util/time_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/time_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/time_util_test.cc'; fi`
+
+google/protobuf/util/protobuf_test-type_resolver_util_test.o: google/protobuf/util/type_resolver_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-type_resolver_util_test.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Tpo -c -o google/protobuf/util/protobuf_test-type_resolver_util_test.o `test -f 'google/protobuf/util/type_resolver_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/type_resolver_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/type_resolver_util_test.cc' object='google/protobuf/util/protobuf_test-type_resolver_util_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-type_resolver_util_test.o `test -f 'google/protobuf/util/type_resolver_util_test.cc' || echo '$(srcdir)/'`google/protobuf/util/type_resolver_util_test.cc
+
+google/protobuf/util/protobuf_test-type_resolver_util_test.obj: google/protobuf/util/type_resolver_util_test.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-type_resolver_util_test.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Tpo -c -o google/protobuf/util/protobuf_test-type_resolver_util_test.obj `if test -f 'google/protobuf/util/type_resolver_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/type_resolver_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/type_resolver_util_test.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/type_resolver_util_test.cc' object='google/protobuf/util/protobuf_test-type_resolver_util_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-type_resolver_util_test.obj `if test -f 'google/protobuf/util/type_resolver_util_test.cc'; then $(CYGPATH_W) 'google/protobuf/util/type_resolver_util_test.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/type_resolver_util_test.cc'; fi`
+
+google/protobuf/protobuf_test-well_known_types_unittest.o: google/protobuf/well_known_types_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-well_known_types_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Tpo -c -o google/protobuf/protobuf_test-well_known_types_unittest.o `test -f 'google/protobuf/well_known_types_unittest.cc' || echo '$(srcdir)/'`google/protobuf/well_known_types_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/well_known_types_unittest.cc' object='google/protobuf/protobuf_test-well_known_types_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-well_known_types_unittest.o `test -f 'google/protobuf/well_known_types_unittest.cc' || echo '$(srcdir)/'`google/protobuf/well_known_types_unittest.cc
+
+google/protobuf/protobuf_test-well_known_types_unittest.obj: google/protobuf/well_known_types_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-well_known_types_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Tpo -c -o google/protobuf/protobuf_test-well_known_types_unittest.obj `if test -f 'google/protobuf/well_known_types_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/well_known_types_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/well_known_types_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/well_known_types_unittest.cc' object='google/protobuf/protobuf_test-well_known_types_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-well_known_types_unittest.obj `if test -f 'google/protobuf/well_known_types_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/well_known_types_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/well_known_types_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-wire_format_unittest.o: google/protobuf/wire_format_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-wire_format_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo -c -o google/protobuf/protobuf_test-wire_format_unittest.o `test -f 'google/protobuf/wire_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/wire_format_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/wire_format_unittest.cc' object='google/protobuf/protobuf_test-wire_format_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-wire_format_unittest.o `test -f 'google/protobuf/wire_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/wire_format_unittest.cc
+
+google/protobuf/protobuf_test-wire_format_unittest.obj: google/protobuf/wire_format_unittest.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-wire_format_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo -c -o google/protobuf/protobuf_test-wire_format_unittest.obj `if test -f 'google/protobuf/wire_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/wire_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/wire_format_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/wire_format_unittest.cc' object='google/protobuf/protobuf_test-wire_format_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-wire_format_unittest.obj `if test -f 'google/protobuf/wire_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/wire_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/wire_format_unittest.cc'; fi`
+
+google/protobuf/protobuf_test-map_lite_unittest.pb.o: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_lite_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_test-map_lite_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_lite_unittest.pb.o `test -f 'google/protobuf/map_lite_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_lite_unittest.pb.cc
+
+google/protobuf/protobuf_test-map_lite_unittest.pb.obj: google/protobuf/map_lite_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_lite_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Tpo -c -o google/protobuf/protobuf_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_lite_unittest.pb.cc' object='google/protobuf/protobuf_test-map_lite_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_lite_unittest.pb.obj `if test -f 'google/protobuf/map_lite_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_lite_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_lite_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
+
+google/protobuf/protobuf_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
+
+google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
+
+google/protobuf/protobuf_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-any_test.pb.o: google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-any_test.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Tpo -c -o google/protobuf/protobuf_test-any_test.pb.o `test -f 'google/protobuf/any_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.pb.cc' object='google/protobuf/protobuf_test-any_test.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-any_test.pb.o `test -f 'google/protobuf/any_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/any_test.pb.cc
+
+google/protobuf/protobuf_test-any_test.pb.obj: google/protobuf/any_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-any_test.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Tpo -c -o google/protobuf/protobuf_test-any_test.pb.obj `if test -f 'google/protobuf/any_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/any_test.pb.cc' object='google/protobuf/protobuf_test-any_test.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-any_test.pb.obj `if test -f 'google/protobuf/any_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/any_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/any_test.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.o: google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+
+google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.obj: google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_bad_identifiers.pb.cc'; fi`
+
+google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.o: google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.o `test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' object='google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.o `test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+
+google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.obj: google/protobuf/compiler/cpp/test_large_enum_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/test_large_enum_value.pb.cc' object='google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-test_large_enum_value.pb.obj `if test -f 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/test_large_enum_value.pb.cc'; fi`
+
+google/protobuf/protobuf_test-map_proto2_unittest.pb.o: google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_proto2_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Tpo -c -o google/protobuf/protobuf_test-map_proto2_unittest.pb.o `test -f 'google/protobuf/map_proto2_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_proto2_unittest.pb.cc' object='google/protobuf/protobuf_test-map_proto2_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_proto2_unittest.pb.o `test -f 'google/protobuf/map_proto2_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_proto2_unittest.pb.cc
+
+google/protobuf/protobuf_test-map_proto2_unittest.pb.obj: google/protobuf/map_proto2_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_proto2_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Tpo -c -o google/protobuf/protobuf_test-map_proto2_unittest.pb.obj `if test -f 'google/protobuf/map_proto2_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_proto2_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_proto2_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_proto2_unittest.pb.cc' object='google/protobuf/protobuf_test-map_proto2_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_proto2_unittest.pb.obj `if test -f 'google/protobuf/map_proto2_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_proto2_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_proto2_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_test-map_unittest.pb.o: google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Tpo -c -o google/protobuf/protobuf_test-map_unittest.pb.o `test -f 'google/protobuf/map_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_unittest.pb.cc' object='google/protobuf/protobuf_test-map_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_unittest.pb.o `test -f 'google/protobuf/map_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/map_unittest.pb.cc
+
+google/protobuf/protobuf_test-map_unittest.pb.obj: google/protobuf/map_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-map_unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Tpo -c -o google/protobuf/protobuf_test-map_unittest.pb.obj `if test -f 'google/protobuf/map_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/map_unittest.pb.cc' object='google/protobuf/protobuf_test-map_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-map_unittest.pb.obj `if test -f 'google/protobuf/map_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/map_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/map_unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest.pb.o: google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_test-unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
+
+google/protobuf/protobuf_test-unittest.pb.obj: google/protobuf/unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_test-unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_arena.pb.o: google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_arena.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_arena.pb.o `test -f 'google/protobuf/unittest_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_arena.pb.cc' object='google/protobuf/protobuf_test-unittest_arena.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_arena.pb.o `test -f 'google/protobuf/unittest_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_arena.pb.cc
+
+google/protobuf/protobuf_test-unittest_arena.pb.obj: google/protobuf/unittest_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_arena.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_arena.pb.obj `if test -f 'google/protobuf/unittest_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_arena.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_arena.pb.cc' object='google/protobuf/protobuf_test-unittest_arena.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_arena.pb.obj `if test -f 'google/protobuf/unittest_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_arena.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_custom_options.pb.o: google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_custom_options.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_test-unittest_custom_options.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
+
+google/protobuf/protobuf_test-unittest_custom_options.pb.obj: google/protobuf/unittest_custom_options.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_custom_options.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_test-unittest_custom_options.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.o: google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.o `test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_drop_unknown_fields.pb.cc' object='google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.o `test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_drop_unknown_fields.pb.cc
+
+google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.obj: google/protobuf/unittest_drop_unknown_fields.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.obj `if test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_drop_unknown_fields.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_drop_unknown_fields.pb.cc' object='google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_drop_unknown_fields.pb.obj `if test -f 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_drop_unknown_fields.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_drop_unknown_fields.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o: google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
+
+google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj: google/protobuf/unittest_embed_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_empty.pb.o: google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_empty.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_test-unittest_empty.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
+
+google/protobuf/protobuf_test-unittest_empty.pb.obj: google/protobuf/unittest_empty.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_empty.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_test-unittest_empty.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.o: google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.o `test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_enormous_descriptor.pb.cc' object='google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.o `test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_enormous_descriptor.pb.cc
+
+google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.obj: google/protobuf/unittest_enormous_descriptor.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.obj `if test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_enormous_descriptor.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_enormous_descriptor.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_enormous_descriptor.pb.cc' object='google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_enormous_descriptor.pb.obj `if test -f 'google/protobuf/unittest_enormous_descriptor.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_enormous_descriptor.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_enormous_descriptor.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_import.pb.o: google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_test-unittest_import.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
+
+google/protobuf/protobuf_test-unittest_import.pb.obj: google/protobuf/unittest_import.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_test-unittest_import.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_import_public.pb.o: google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
+
+google/protobuf/protobuf_test-unittest_import_public.pb.obj: google/protobuf/unittest_import_public.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.o: google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies.pb.cc' object='google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies.pb.cc
+
+google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.obj: google/protobuf/unittest_lazy_dependencies.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies.pb.cc' object='google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.o: google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' object='google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+
+google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.obj: google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc' object='google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_custom_option.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_custom_option.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.o: google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_enum.pb.cc' object='google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.o `test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+
+google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.obj: google/protobuf/unittest_lazy_dependencies_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lazy_dependencies_enum.pb.cc' object='google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lazy_dependencies_enum.pb.obj `if test -f 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lazy_dependencies_enum.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o: google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
+
+google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj: google/protobuf/unittest_lite_imports_nonlite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_mset.pb.o: google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_mset.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_test-unittest_mset.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
+
+google/protobuf/protobuf_test-unittest_mset.pb.obj: google/protobuf/unittest_mset.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_mset.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_test-unittest_mset.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_mset_wire_format.pb.o: google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_mset_wire_format.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_mset_wire_format.pb.o `test -f 'google/protobuf/unittest_mset_wire_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset_wire_format.pb.cc' object='google/protobuf/protobuf_test-unittest_mset_wire_format.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_mset_wire_format.pb.o `test -f 'google/protobuf/unittest_mset_wire_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset_wire_format.pb.cc
+
+google/protobuf/protobuf_test-unittest_mset_wire_format.pb.obj: google/protobuf/unittest_mset_wire_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_mset_wire_format.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_mset_wire_format.pb.obj `if test -f 'google/protobuf/unittest_mset_wire_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset_wire_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset_wire_format.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset_wire_format.pb.cc' object='google/protobuf/protobuf_test-unittest_mset_wire_format.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_mset_wire_format.pb.obj `if test -f 'google/protobuf/unittest_mset_wire_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset_wire_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset_wire_format.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_no_field_presence.pb.o: google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_no_field_presence.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_no_field_presence.pb.o `test -f 'google/protobuf/unittest_no_field_presence.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_field_presence.pb.cc' object='google/protobuf/protobuf_test-unittest_no_field_presence.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_no_field_presence.pb.o `test -f 'google/protobuf/unittest_no_field_presence.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_field_presence.pb.cc
+
+google/protobuf/protobuf_test-unittest_no_field_presence.pb.obj: google/protobuf/unittest_no_field_presence.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_no_field_presence.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_no_field_presence.pb.obj `if test -f 'google/protobuf/unittest_no_field_presence.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_field_presence.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_field_presence.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_field_presence.pb.cc' object='google/protobuf/protobuf_test-unittest_no_field_presence.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_no_field_presence.pb.obj `if test -f 'google/protobuf/unittest_no_field_presence.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_field_presence.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_field_presence.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_no_generic_services.pb.o: google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_no_generic_services.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_test-unittest_no_generic_services.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
+
+google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj: google/protobuf/unittest_no_generic_services.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_optimize_for.pb.o: google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
+
+google/protobuf/protobuf_test-unittest_optimize_for.pb.obj: google/protobuf/unittest_optimize_for.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.o: google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum.pb.cc' object='google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum.pb.cc
+
+google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.obj: google/protobuf/unittest_preserve_unknown_enum.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum.pb.cc' object='google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.o: google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum2.pb.cc' object='google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.o `test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+
+google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.obj: google/protobuf/unittest_preserve_unknown_enum2.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_preserve_unknown_enum2.pb.cc' object='google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_preserve_unknown_enum2.pb.obj `if test -f 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_preserve_unknown_enum2.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_proto3.pb.o: google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3.pb.o `test -f 'google/protobuf/unittest_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3.pb.o `test -f 'google/protobuf/unittest_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3.pb.cc
+
+google/protobuf/protobuf_test-unittest_proto3.pb.obj: google/protobuf/unittest_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3.pb.obj `if test -f 'google/protobuf/unittest_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3.pb.obj `if test -f 'google/protobuf/unittest_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_proto3_arena.pb.o: google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_arena.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_arena.pb.o `test -f 'google/protobuf/unittest_proto3_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_arena.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_arena.pb.o `test -f 'google/protobuf/unittest_proto3_arena.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena.pb.cc
+
+google/protobuf/protobuf_test-unittest_proto3_arena.pb.obj: google/protobuf/unittest_proto3_arena.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_arena.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_arena.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_arena.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_arena.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.o: google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.o `test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.o `test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_arena_lite.pb.cc
+
+google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.obj: google/protobuf/unittest_proto3_arena_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_arena_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_arena_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_arena_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_arena_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_proto3_lite.pb.o: google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_lite.pb.o `test -f 'google/protobuf/unittest_proto3_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_lite.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_lite.pb.o `test -f 'google/protobuf/unittest_proto3_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_lite.pb.cc
+
+google/protobuf/protobuf_test-unittest_proto3_lite.pb.obj: google/protobuf/unittest_proto3_lite.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_lite.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_lite.pb.obj `if test -f 'google/protobuf/unittest_proto3_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_lite.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_proto3_optional.pb.o: google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_optional.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_optional.pb.o `test -f 'google/protobuf/unittest_proto3_optional.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_optional.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_optional.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_optional.pb.o `test -f 'google/protobuf/unittest_proto3_optional.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_proto3_optional.pb.cc
+
+google/protobuf/protobuf_test-unittest_proto3_optional.pb.obj: google/protobuf/unittest_proto3_optional.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_proto3_optional.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_proto3_optional.pb.obj `if test -f 'google/protobuf/unittest_proto3_optional.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_optional.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_optional.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_proto3_optional.pb.cc' object='google/protobuf/protobuf_test-unittest_proto3_optional.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_proto3_optional.pb.obj `if test -f 'google/protobuf/unittest_proto3_optional.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_proto3_optional.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_proto3_optional.pb.cc'; fi`
+
+google/protobuf/protobuf_test-unittest_well_known_types.pb.o: google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_well_known_types.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_well_known_types.pb.o `test -f 'google/protobuf/unittest_well_known_types.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_well_known_types.pb.cc' object='google/protobuf/protobuf_test-unittest_well_known_types.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_well_known_types.pb.o `test -f 'google/protobuf/unittest_well_known_types.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_well_known_types.pb.cc
+
+google/protobuf/protobuf_test-unittest_well_known_types.pb.obj: google/protobuf/unittest_well_known_types.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_well_known_types.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_well_known_types.pb.obj `if test -f 'google/protobuf/unittest_well_known_types.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_well_known_types.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_well_known_types.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_well_known_types.pb.cc' object='google/protobuf/protobuf_test-unittest_well_known_types.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_well_known_types.pb.obj `if test -f 'google/protobuf/unittest_well_known_types.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_well_known_types.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_well_known_types.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-anys.pb.o: google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-anys.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-anys.pb.o `test -f 'google/protobuf/util/internal/testdata/anys.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/anys.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-anys.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-anys.pb.o `test -f 'google/protobuf/util/internal/testdata/anys.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/anys.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-anys.pb.obj: google/protobuf/util/internal/testdata/anys.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-anys.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-anys.pb.obj `if test -f 'google/protobuf/util/internal/testdata/anys.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/anys.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/anys.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/anys.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-anys.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-anys.pb.obj `if test -f 'google/protobuf/util/internal/testdata/anys.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/anys.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/anys.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-books.pb.o: google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-books.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-books.pb.o `test -f 'google/protobuf/util/internal/testdata/books.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/books.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-books.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-books.pb.o `test -f 'google/protobuf/util/internal/testdata/books.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/books.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-books.pb.obj: google/protobuf/util/internal/testdata/books.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-books.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-books.pb.obj `if test -f 'google/protobuf/util/internal/testdata/books.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/books.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/books.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/books.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-books.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-books.pb.obj `if test -f 'google/protobuf/util/internal/testdata/books.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/books.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/books.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.o: google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.obj: google/protobuf/util/internal/testdata/default_value.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.o: google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value_test.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.o `test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/default_value_test.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.obj: google/protobuf/util/internal/testdata/default_value_test.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value_test.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/default_value_test.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-default_value_test.pb.obj `if test -f 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/default_value_test.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/default_value_test.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.o: google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.o `test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/field_mask.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.o `test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/field_mask.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.obj: google/protobuf/util/internal/testdata/field_mask.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.obj `if test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/field_mask.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/field_mask.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-field_mask.pb.obj `if test -f 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/field_mask.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/field_mask.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-maps.pb.o: google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-maps.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-maps.pb.o `test -f 'google/protobuf/util/internal/testdata/maps.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/maps.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-maps.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-maps.pb.o `test -f 'google/protobuf/util/internal/testdata/maps.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/maps.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-maps.pb.obj: google/protobuf/util/internal/testdata/maps.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-maps.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-maps.pb.obj `if test -f 'google/protobuf/util/internal/testdata/maps.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/maps.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/maps.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/maps.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-maps.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-maps.pb.obj `if test -f 'google/protobuf/util/internal/testdata/maps.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/maps.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/maps.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.o: google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.o `test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/oneofs.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.o `test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/oneofs.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.obj: google/protobuf/util/internal/testdata/oneofs.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.obj `if test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/oneofs.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/oneofs.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-oneofs.pb.obj `if test -f 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/oneofs.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/oneofs.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.o: google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.o `test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/proto3.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.o `test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/proto3.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.obj: google/protobuf/util/internal/testdata/proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.obj `if test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/proto3.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-proto3.pb.obj `if test -f 'google/protobuf/util/internal/testdata/proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/proto3.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-struct.pb.o: google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-struct.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-struct.pb.o `test -f 'google/protobuf/util/internal/testdata/struct.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/struct.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-struct.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-struct.pb.o `test -f 'google/protobuf/util/internal/testdata/struct.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/struct.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-struct.pb.obj: google/protobuf/util/internal/testdata/struct.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-struct.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-struct.pb.obj `if test -f 'google/protobuf/util/internal/testdata/struct.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/struct.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/struct.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/struct.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-struct.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-struct.pb.obj `if test -f 'google/protobuf/util/internal/testdata/struct.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/struct.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/struct.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.o: google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.o `test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.o `test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.obj: google/protobuf/util/internal/testdata/timestamp_duration.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.obj `if test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/timestamp_duration.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-timestamp_duration.pb.obj `if test -f 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/timestamp_duration.pb.cc'; fi`
+
+google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.o: google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.o -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.o `test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/wrappers.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.o `test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/internal/testdata/wrappers.pb.cc
+
+google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.obj: google/protobuf/util/internal/testdata/wrappers.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.obj -MD -MP -MF google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Tpo -c -o google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.obj `if test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/wrappers.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Tpo google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/internal/testdata/wrappers.pb.cc' object='google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/internal/testdata/protobuf_test-wrappers.pb.obj `if test -f 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/internal/testdata/wrappers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/internal/testdata/wrappers.pb.cc'; fi`
+
+google/protobuf/util/protobuf_test-json_format.pb.o: google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-json_format.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Tpo -c -o google/protobuf/util/protobuf_test-json_format.pb.o `test -f 'google/protobuf/util/json_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format.pb.cc' object='google/protobuf/util/protobuf_test-json_format.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-json_format.pb.o `test -f 'google/protobuf/util/json_format.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format.pb.cc
+
+google/protobuf/util/protobuf_test-json_format.pb.obj: google/protobuf/util/json_format.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-json_format.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Tpo -c -o google/protobuf/util/protobuf_test-json_format.pb.obj `if test -f 'google/protobuf/util/json_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format.pb.cc' object='google/protobuf/util/protobuf_test-json_format.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-json_format.pb.obj `if test -f 'google/protobuf/util/json_format.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format.pb.cc'; fi`
+
+google/protobuf/util/protobuf_test-json_format_proto3.pb.o: google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-json_format_proto3.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Tpo -c -o google/protobuf/util/protobuf_test-json_format_proto3.pb.o `test -f 'google/protobuf/util/json_format_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format_proto3.pb.cc' object='google/protobuf/util/protobuf_test-json_format_proto3.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-json_format_proto3.pb.o `test -f 'google/protobuf/util/json_format_proto3.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/json_format_proto3.pb.cc
+
+google/protobuf/util/protobuf_test-json_format_proto3.pb.obj: google/protobuf/util/json_format_proto3.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-json_format_proto3.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Tpo -c -o google/protobuf/util/protobuf_test-json_format_proto3.pb.obj `if test -f 'google/protobuf/util/json_format_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format_proto3.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/json_format_proto3.pb.cc' object='google/protobuf/util/protobuf_test-json_format_proto3.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-json_format_proto3.pb.obj `if test -f 'google/protobuf/util/json_format_proto3.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/json_format_proto3.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/json_format_proto3.pb.cc'; fi`
+
+google/protobuf/util/protobuf_test-message_differencer_unittest.pb.o: google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-message_differencer_unittest.pb.o -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Tpo -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.pb.o `test -f 'google/protobuf/util/message_differencer_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.pb.cc' object='google/protobuf/util/protobuf_test-message_differencer_unittest.pb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.pb.o `test -f 'google/protobuf/util/message_differencer_unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/util/message_differencer_unittest.pb.cc
+
+google/protobuf/util/protobuf_test-message_differencer_unittest.pb.obj: google/protobuf/util/message_differencer_unittest.pb.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/util/protobuf_test-message_differencer_unittest.pb.obj -MD -MP -MF google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Tpo -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.pb.obj `if test -f 'google/protobuf/util/message_differencer_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.pb.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Tpo google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/util/message_differencer_unittest.pb.cc' object='google/protobuf/util/protobuf_test-message_differencer_unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/util/protobuf_test-message_differencer_unittest.pb.obj `if test -f 'google/protobuf/util/message_differencer_unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/util/message_differencer_unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/util/message_differencer_unittest.pb.cc'; fi`
+
+google/protobuf/compiler/test_plugin-mock_code_generator.o: google/protobuf/compiler/mock_code_generator.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-mock_code_generator.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo -c -o google/protobuf/compiler/test_plugin-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/test_plugin-mock_code_generator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
+
+google/protobuf/compiler/test_plugin-mock_code_generator.obj: google/protobuf/compiler/mock_code_generator.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-mock_code_generator.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo -c -o google/protobuf/compiler/test_plugin-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/test_plugin-mock_code_generator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
+
+google/protobuf/compiler/test_plugin-test_plugin.o: google/protobuf/compiler/test_plugin.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-test_plugin.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo -c -o google/protobuf/compiler/test_plugin-test_plugin.o `test -f 'google/protobuf/compiler/test_plugin.cc' || echo '$(srcdir)/'`google/protobuf/compiler/test_plugin.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/test_plugin.cc' object='google/protobuf/compiler/test_plugin-test_plugin.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-test_plugin.o `test -f 'google/protobuf/compiler/test_plugin.cc' || echo '$(srcdir)/'`google/protobuf/compiler/test_plugin.cc
+
+google/protobuf/compiler/test_plugin-test_plugin.obj: google/protobuf/compiler/test_plugin.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-test_plugin.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo -c -o google/protobuf/compiler/test_plugin-test_plugin.obj `if test -f 'google/protobuf/compiler/test_plugin.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/test_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/test_plugin.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/test_plugin.cc' object='google/protobuf/compiler/test_plugin-test_plugin.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-test_plugin.obj `if test -f 'google/protobuf/compiler/test_plugin.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/test_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/test_plugin.cc'; fi`
+
+google/protobuf/testing/test_plugin-file.o: google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/test_plugin-file.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo -c -o google/protobuf/testing/test_plugin-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/test_plugin-file.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/test_plugin-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
+
+google/protobuf/testing/test_plugin-file.obj: google/protobuf/testing/file.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/test_plugin-file.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo -c -o google/protobuf/testing/test_plugin-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/test_plugin-file.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/test_plugin-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf google/protobuf/.libs google/protobuf/_libs
+	-rm -rf google/protobuf/compiler/.libs google/protobuf/compiler/_libs
+	-rm -rf google/protobuf/compiler/cpp/.libs google/protobuf/compiler/cpp/_libs
+	-rm -rf google/protobuf/compiler/csharp/.libs google/protobuf/compiler/csharp/_libs
+	-rm -rf google/protobuf/compiler/java/.libs google/protobuf/compiler/java/_libs
+	-rm -rf google/protobuf/compiler/objectivec/.libs google/protobuf/compiler/objectivec/_libs
+	-rm -rf google/protobuf/compiler/php/.libs google/protobuf/compiler/php/_libs
+	-rm -rf google/protobuf/compiler/python/.libs google/protobuf/compiler/python/_libs
+	-rm -rf google/protobuf/compiler/ruby/.libs google/protobuf/compiler/ruby/_libs
+	-rm -rf google/protobuf/io/.libs google/protobuf/io/_libs
+	-rm -rf google/protobuf/stubs/.libs google/protobuf/stubs/_libs
+	-rm -rf google/protobuf/util/.libs google/protobuf/util/_libs
+	-rm -rf google/protobuf/util/internal/.libs google/protobuf/util/internal/_libs
+install-nobase_dist_protoDATA: $(nobase_dist_proto_DATA)
+	@$(NORMAL_INSTALL)
+	@list='$(nobase_dist_proto_DATA)'; test -n "$(protodir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(protodir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(protodir)" || exit 1; \
+	fi; \
+	$(am__nobase_list) | while read dir files; do \
+	  xfiles=; for file in $$files; do \
+	    if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+	    else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+	  test -z "$$xfiles" || { \
+	    test "x$$dir" = x. || { \
+	      echo " $(MKDIR_P) '$(DESTDIR)$(protodir)/$$dir'"; \
+	      $(MKDIR_P) "$(DESTDIR)$(protodir)/$$dir"; }; \
+	    echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(protodir)/$$dir'"; \
+	    $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(protodir)/$$dir" || exit $$?; }; \
+	done
+
+uninstall-nobase_dist_protoDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(nobase_dist_proto_DATA)'; test -n "$(protodir)" || list=; \
+	$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+	dir='$(DESTDIR)$(protodir)'; $(am__uninstall_files_from_dir)
+install-nobase_includeHEADERS: $(nobase_include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+	fi; \
+	$(am__nobase_list) | while read dir files; do \
+	  xfiles=; for file in $$files; do \
+	    if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+	    else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+	  test -z "$$xfiles" || { \
+	    test "x$$dir" = x. || { \
+	      echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \
+	      $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \
+	    echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \
+	    $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \
+	done
+
+uninstall-nobase_includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \
+	$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+protobuf-test.log: protobuf-test$(EXEEXT)
+	@p='protobuf-test$(EXEEXT)'; \
+	b='protobuf-test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+protobuf-lazy-descriptor-test.log: protobuf-lazy-descriptor-test$(EXEEXT)
+	@p='protobuf-lazy-descriptor-test$(EXEEXT)'; \
+	b='protobuf-lazy-descriptor-test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+protobuf-lite-test.log: protobuf-lite-test$(EXEEXT)
+	@p='protobuf-lite-test$(EXEEXT)'; \
+	b='protobuf-lite-test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+google/protobuf/compiler/zip_output_unittest.sh.log: google/protobuf/compiler/zip_output_unittest.sh
+	@p='google/protobuf/compiler/zip_output_unittest.sh'; \
+	b='google/protobuf/compiler/zip_output_unittest.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+google/protobuf/io/gzip_stream_unittest.sh.log: google/protobuf/io/gzip_stream_unittest.sh
+	@p='google/protobuf/io/gzip_stream_unittest.sh'; \
+	b='google/protobuf/io/gzip_stream_unittest.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+protobuf-lite-arena-test.log: protobuf-lite-arena-test$(EXEEXT)
+	@p='protobuf-lite-arena-test$(EXEEXT)'; \
+	b='protobuf-lite-arena-test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+no-warning-test.log: no-warning-test$(EXEEXT)
+	@p='no-warning-test$(EXEEXT)'; \
+	b='no-warning-test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(DATA) $(HEADERS)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+install-checkPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(protodir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f google/protobuf/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/cpp/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/csharp/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/java/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/objectivec/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/php/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/php/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/python/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/ruby/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/compiler/ruby/$(am__dirstamp)
+	-rm -f google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/io/$(am__dirstamp)
+	-rm -f google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/stubs/$(am__dirstamp)
+	-rm -f google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/testing/$(am__dirstamp)
+	-rm -f google/protobuf/util/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/util/$(am__dirstamp)
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/util/internal/$(am__dirstamp)
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/$(am__dirstamp)
+	-rm -f google/protobuf/util/internal/testdata/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+	clean-libLTLIBRARIES clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+		-rm -f ./$(DEPDIR)/no_warning_test-no_warning_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/any.Plo
+	-rm -f google/protobuf/$(DEPDIR)/any.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/any_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/api.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/arena.Plo
+	-rm -f google/protobuf/$(DEPDIR)/arenastring.Plo
+	-rm -f google/protobuf/$(DEPDIR)/arenaz_sampler.Plo
+	-rm -f google/protobuf/$(DEPDIR)/descriptor.Plo
+	-rm -f google/protobuf/$(DEPDIR)/descriptor.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/descriptor_database.Plo
+	-rm -f google/protobuf/$(DEPDIR)/duration.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/dynamic_message.Plo
+	-rm -f google/protobuf/$(DEPDIR)/empty.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/extension_set.Plo
+	-rm -f google/protobuf/$(DEPDIR)/extension_set_heavy.Plo
+	-rm -f google/protobuf/$(DEPDIR)/field_mask.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_enum_util.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_bases.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_reflection.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_tctable_full.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_tctable_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_util.Plo
+	-rm -f google/protobuf/$(DEPDIR)/implicit_weak_message.Plo
+	-rm -f google/protobuf/$(DEPDIR)/inlined_string_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/map.Plo
+	-rm -f google/protobuf/$(DEPDIR)/map_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/message.Plo
+	-rm -f google/protobuf/$(DEPDIR)/message_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/parse_context.Plo
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-any_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/reflection_ops.Plo
+	-rm -f google/protobuf/$(DEPDIR)/repeated_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/repeated_ptr_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/service.Plo
+	-rm -f google/protobuf/$(DEPDIR)/source_context.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/struct.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/text_format.Plo
+	-rm -f google/protobuf/$(DEPDIR)/timestamp.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/type.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/unknown_field_set.Plo
+	-rm -f google/protobuf/$(DEPDIR)/wire_format.Plo
+	-rm -f google/protobuf/$(DEPDIR)/wire_format_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/wrappers.pb.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/code_generator.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/command_line_interface.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/importer.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/main.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/parser.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/plugin.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/plugin.pb.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/subprocess.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/zip_writer.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/enum.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/enum_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/extension.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/file.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/generator.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/helpers.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/map_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/message.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/message_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/padding_optimizer.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/parse_function_generator.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/primitive_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/service.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/string_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_doc_comment.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_field_base.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_generator.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_helpers.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_map_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_primitive_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_reflection_class.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_enum_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_message_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_primitive_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_source_generator_base.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_wrapper_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Po
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Po
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/context.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/doc_comment.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/extension.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/extension_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/file.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/generator.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/generator_factory.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/helpers.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/kotlin_generator.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/map_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/map_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_builder.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_builder_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/name_resolver.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/primitive_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/primitive_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Po
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/service.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/shared_code_generator.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/string_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/string_field_lite.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_extension.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_file.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_generator.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_helpers.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_map_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_oneof.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_primitive_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Po
+	-rm -f google/protobuf/compiler/php/$(DEPDIR)/php_generator.Plo
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/generator.Plo
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/helpers.Plo
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/pyi_generator.Plo
+	-rm -f google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Po
+	-rm -f google/protobuf/compiler/ruby/$(DEPDIR)/ruby_generator.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/coded_stream.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/gzip_stream.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/io_win32.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/printer.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/strtod.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/tokenizer.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/zero_copy_stream.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl_lite.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/bytestream.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/common.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/int128.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/status.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/statusor.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/stringpiece.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/stringprintf.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/structurally_valid.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/strutil.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/substitute.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/time.Plo
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/zcgunzip.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/zcgzip.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/delimited_message_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/field_comparator.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/field_mask_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/json_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/message_differencer.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/time_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/type_resolver_util.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/datapiece.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/default_value_objectwriter.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/error_listener.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/field_mask_utility.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/json_escaping.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/json_objectwriter.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/json_stream_parser.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/object_writer.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/proto_writer.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protostream_objectsource.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protostream_objectwriter.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/type_info.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/utility.Plo
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Po
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_dist_protoDATA \
+	install-nobase_includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+		-rm -f ./$(DEPDIR)/no_warning_test-no_warning_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/any.Plo
+	-rm -f google/protobuf/$(DEPDIR)/any.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/any_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/api.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/arena.Plo
+	-rm -f google/protobuf/$(DEPDIR)/arenastring.Plo
+	-rm -f google/protobuf/$(DEPDIR)/arenaz_sampler.Plo
+	-rm -f google/protobuf/$(DEPDIR)/descriptor.Plo
+	-rm -f google/protobuf/$(DEPDIR)/descriptor.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/descriptor_database.Plo
+	-rm -f google/protobuf/$(DEPDIR)/duration.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/dynamic_message.Plo
+	-rm -f google/protobuf/$(DEPDIR)/empty.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/extension_set.Plo
+	-rm -f google/protobuf/$(DEPDIR)/extension_set_heavy.Plo
+	-rm -f google/protobuf/$(DEPDIR)/field_mask.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_enum_util.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_bases.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_reflection.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_tctable_full.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_tctable_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/generated_message_util.Plo
+	-rm -f google/protobuf/$(DEPDIR)/implicit_weak_message.Plo
+	-rm -f google/protobuf/$(DEPDIR)/inlined_string_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/map.Plo
+	-rm -f google/protobuf/$(DEPDIR)/map_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/message.Plo
+	-rm -f google/protobuf/$(DEPDIR)/message_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-any_test.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-map_proto2_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-map_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_custom_options.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_drop_unknown_fields.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_embed_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_empty.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_enormous_descriptor.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_custom_option.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lazy_dependencies_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_lite_imports_nonlite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_mset_wire_format.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_field_presence.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_no_generic_services.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_preserve_unknown_enum2.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_arena_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_proto3_optional.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/no_warning_test-unittest_well_known_types.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/parse_context.Plo
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-any_test.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_proto2_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-map_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-reflection_tester.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_drop_unknown_fields.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_enormous_descriptor.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_custom_option.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lazy_dependencies_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset_wire_format.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_field_presence.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_preserve_unknown_enum2.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_arena_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_proto3_optional.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_well_known_types.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-lite_arena_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_arena_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-any_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-any_test.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arena_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arena_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arenastring_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-arenaz_sampler_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-drop_unknown_fields_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-generated_message_tctable_lite_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-inlined_string_field_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_field_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_lite_test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_lite_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_proto2_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-map_unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-no_field_presence_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-preserve_unknown_enum_test.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_lite_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-proto3_arena_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-proto3_lite_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-reflection_tester.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-test_util_lite.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_drop_unknown_fields.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_enormous_descriptor.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_custom_option.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lazy_dependencies_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset_wire_format.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_field_presence.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_preserve_unknown_enum2.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_arena_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_lite.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_proto3_optional.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unittest_well_known_types.pb.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-well_known_types_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po
+	-rm -f google/protobuf/$(DEPDIR)/reflection_ops.Plo
+	-rm -f google/protobuf/$(DEPDIR)/repeated_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/repeated_ptr_field.Plo
+	-rm -f google/protobuf/$(DEPDIR)/service.Plo
+	-rm -f google/protobuf/$(DEPDIR)/source_context.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/struct.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/text_format.Plo
+	-rm -f google/protobuf/$(DEPDIR)/timestamp.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/type.pb.Plo
+	-rm -f google/protobuf/$(DEPDIR)/unknown_field_set.Plo
+	-rm -f google/protobuf/$(DEPDIR)/wire_format.Plo
+	-rm -f google/protobuf/$(DEPDIR)/wire_format_lite.Plo
+	-rm -f google/protobuf/$(DEPDIR)/wrappers.pb.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/code_generator.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/command_line_interface.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/importer.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/main.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/parser.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/plugin.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/plugin.pb.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-annotation_test_util.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/subprocess.Plo
+	-rm -f google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po
+	-rm -f google/protobuf/compiler/$(DEPDIR)/zip_writer.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/enum.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/enum_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/extension.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/file.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/generator.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/helpers.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/map_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/message.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/message_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_bad_identifiers.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/no_warning_test-test_large_enum_value.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/padding_optimizer.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/parse_function_generator.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/primitive_field.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_bad_identifiers.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-test_large_enum_value.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-bootstrap_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-message_size_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-metadata_test.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-move_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_bad_identifiers.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-test_large_enum_value.pb.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-unittest.Po
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/service.Plo
+	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/string_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_doc_comment.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_enum_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_field_base.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_generator.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_helpers.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_map_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_message_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_primitive_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_reflection_class.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_enum_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_message_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_repeated_primitive_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_source_generator_base.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/csharp_wrapper_field.Plo
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_bootstrap_unittest.Po
+	-rm -f google/protobuf/compiler/csharp/$(DEPDIR)/protobuf_test-csharp_generator_unittest.Po
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/context.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/doc_comment.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/enum_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/extension.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/extension_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/file.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/generator.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/generator_factory.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/helpers.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/kotlin_generator.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/map_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/map_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_builder.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_builder_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/message_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/name_resolver.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/primitive_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/primitive_field_lite.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-doc_comment_unittest.Po
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/service.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/shared_code_generator.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/string_field.Plo
+	-rm -f google/protobuf/compiler/java/$(DEPDIR)/string_field_lite.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_enum_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_extension.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_file.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_generator.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_helpers.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_map_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_message_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_oneof.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/objectivec_primitive_field.Plo
+	-rm -f google/protobuf/compiler/objectivec/$(DEPDIR)/protobuf_test-objectivec_helpers_unittest.Po
+	-rm -f google/protobuf/compiler/php/$(DEPDIR)/php_generator.Plo
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/generator.Plo
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/helpers.Plo
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-plugin_unittest.Po
+	-rm -f google/protobuf/compiler/python/$(DEPDIR)/pyi_generator.Plo
+	-rm -f google/protobuf/compiler/ruby/$(DEPDIR)/protobuf_test-ruby_generator_unittest.Po
+	-rm -f google/protobuf/compiler/ruby/$(DEPDIR)/ruby_generator.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/coded_stream.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/gzip_stream.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/io_win32.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/printer.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-io_win32_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po
+	-rm -f google/protobuf/io/$(DEPDIR)/strtod.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/tokenizer.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/zero_copy_stream.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl.Plo
+	-rm -f google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl_lite.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/bytestream.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/common.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/int128.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-bytestream_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-int128_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-status_test.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-statusor_test.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringpiece_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/protobuf_test-time_test.Po
+	-rm -f google/protobuf/stubs/$(DEPDIR)/status.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/statusor.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/stringpiece.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/stringprintf.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/structurally_valid.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/strutil.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/substitute.Plo
+	-rm -f google/protobuf/stubs/$(DEPDIR)/time.Plo
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/zcgunzip.Po
+	-rm -f google/protobuf/testing/$(DEPDIR)/zcgzip.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/delimited_message_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/field_comparator.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/field_mask_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/json_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/message_differencer.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/no_warning_test-json_format.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/no_warning_test-json_format_proto3.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/no_warning_test-message_differencer_unittest.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-json_format_proto3.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_lazy_descriptor_test-message_differencer_unittest.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-delimited_message_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-field_comparator_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-field_mask_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-json_format.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-json_format_proto3.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-json_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-message_differencer_unittest.pb.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-time_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/protobuf_test-type_resolver_util_test.Po
+	-rm -f google/protobuf/util/$(DEPDIR)/time_util.Plo
+	-rm -f google/protobuf/util/$(DEPDIR)/type_resolver_util.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/datapiece.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/default_value_objectwriter.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/error_listener.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/field_mask_utility.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/json_escaping.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/json_objectwriter.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/json_stream_parser.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/object_writer.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/proto_writer.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-default_value_objectwriter_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_objectwriter_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-json_stream_parser_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectsource_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-protostream_objectwriter_test.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protobuf_test-type_info_test_helper.Po
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protostream_objectsource.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/protostream_objectwriter.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/type_info.Plo
+	-rm -f google/protobuf/util/internal/$(DEPDIR)/utility.Plo
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-anys.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-books.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-default_value_test.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-field_mask.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-maps.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-oneofs.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-proto3.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-struct.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-timestamp_duration.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/no_warning_test-wrappers.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-anys.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-books.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-default_value_test.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-field_mask.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-maps.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-oneofs.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-proto3.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-struct.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-timestamp_duration.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_lazy_descriptor_test-wrappers.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-anys.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-books.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-default_value_test.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-field_mask.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-maps.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-oneofs.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-proto3.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-struct.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-timestamp_duration.pb.Po
+	-rm -f google/protobuf/util/internal/testdata/$(DEPDIR)/protobuf_test-wrappers.pb.Po
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+	uninstall-nobase_dist_protoDATA \
+	uninstall-nobase_includeHEADERS
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+	check-am clean clean-binPROGRAMS clean-checkPROGRAMS \
+	clean-generic clean-libLTLIBRARIES clean-libtool clean-local \
+	cscopelist-am ctags ctags-am distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-binPROGRAMS install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am \
+	install-libLTLIBRARIES install-man \
+	install-nobase_dist_protoDATA install-nobase_includeHEADERS \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am recheck tags tags-am uninstall \
+	uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+	uninstall-nobase_dist_protoDATA \
+	uninstall-nobase_includeHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Not sure why these don't get cleaned automatically.
+clean-local:
+	rm -f *.loT
+
+@USE_EXTERNAL_PROTOC_TRUE@unittest_proto_middleman: $(protoc_inputs)
+@USE_EXTERNAL_PROTOC_TRUE@	$(PROTOC) -I$(srcdir) --cpp_out=. $^
+@USE_EXTERNAL_PROTOC_TRUE@	touch unittest_proto_middleman
+
+# We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
+# relative to srcdir, which may not be the same as the current directory when
+# building out-of-tree.
+@USE_EXTERNAL_PROTOC_FALSE@unittest_proto_middleman: protoc$(EXEEXT) $(protoc_inputs)
+@USE_EXTERNAL_PROTOC_FALSE@	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd $(protoc_inputs) --experimental_allow_proto3_optional )
+@USE_EXTERNAL_PROTOC_FALSE@	touch unittest_proto_middleman
+
+$(protoc_outputs): unittest_proto_middleman
+$(am_protobuf_test_OBJECTS): unittest_proto_middleman
+$(am_protobuf_lazy_descriptor_test_OBJECTS): unittest_proto_middleman
+$(am_protobuf_lite_test_OBJECTS): unittest_proto_middleman
+$(am_protobuf_lite_arena_test_OBJECTS): unittest_proto_middleman
+
+# This test target is to ensure all our public header files and generated
+# code is free from warnings. We have to be more pedantic about these
+# files because they are compiled by users with different compiler flags.
+no_warning_test.cc:
+	echo "// Generated from Makefile.am" > no_warning_test.cc
+	for FILE in $(nobase_include_HEADERS); do \
+		case $$FILE in *.inc) continue;; esac; \
+		echo "#include <$${FILE}>" >> no_warning_test.cc; \
+	done
+	echo "int main(int, char**) { return 0; }" >> no_warning_test.cc
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..cf843d7
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,234 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+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
+  * make
+  * g++
+  * unzip
+
+On Ubuntu/Debian, you can install them with:
+
+    sudo apt-get install autoconf automake libtool curl make g++ unzip
+
+On other platforms, please use the corresponding package managing tool to
+install them before proceeding.
+
+To get the source, download one of the release .tar.gz or .zip packages in the
+release page:
+
+    https://github.com/protocolbuffers/protobuf/releases/latest
+
+For example: if you only need C++, download `protobuf-cpp-[VERSION].tar.gz`; if
+you need C++ and Java, download `protobuf-java-[VERSION].tar.gz` (every package
+contains C++ source already); if you need C++ and multiple other languages,
+download `protobuf-all-[VERSION].tar.gz`.
+
+You can also get the source by "git clone" our git repository. Make sure you
+have also cloned the submodules and generated the configure script (skip this
+if you are using a release .tar.gz or .zip package):
+
+    git clone https://github.com/protocolbuffers/protobuf.git
+    cd protobuf
+    git submodule update --init --recursive
+    ./autogen.sh
+
+To build and install the C++ Protocol Buffer runtime and the Protocol
+Buffer compiler (protoc) execute the following:
+
+
+     ./configure
+     make -j$(nproc) # $(nproc) ensures it uses all cores for compilation
+     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
+
+Alternative for Homebrew users:
+
+    brew 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/protocolbuffers/protobuf/releases/latest
+
+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.
+
+Protobuf and its dependencies can be installed directly by using `vcpkg`:
+
+    >vcpkg install protobuf protobuf:x64-windows
+
+If zlib support is desired, you'll also need to install the zlib feature:
+
+    >vcpkg install protobuf[zlib] protobuf[zlib]:x64-windows
+
+See https://github.com/Microsoft/vcpkg for more information.
+
+To build from source using Microsoft Visual C++, see [cmake/README.md](../cmake/README.md).
+
+To build from source using Cygwin or MinGW, follow the Unix installation
+instructions, above.
+
+Binary Compatibility Warning
+----------------------------
+
+Due to the nature of C++, it is unlikely that any two versions of the
+Protocol Buffers C++ runtime libraries will have compatible ABIs.
+That is, if you linked an executable against an older version of
+libprotobuf, it is unlikely to work with a newer version without
+re-compiling.  This problem, when it occurs, will normally be detected
+immediately on startup of your app.  Still, you may want to consider
+using static linkage.  You can configure this package to install
+static libraries only using:
+
+    ./configure --disable-shared
+
+Usage
+-----
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+https://developers.google.com/protocol-buffers/
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
new file mode 100644
index 0000000..346fa19
--- /dev/null
+++ b/src/google/protobuf/any.cc
@@ -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.
+
+#include <google/protobuf/any.h>
+
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+bool AnyMetadata::PackFrom(Arena* arena, const Message& message) {
+  return PackFrom(arena, message, kTypeGoogleApisComPrefix);
+}
+
+bool AnyMetadata::PackFrom(Arena* arena, const Message& message,
+                           StringPiece type_url_prefix) {
+  type_url_->Set(
+      GetTypeUrl(message.GetDescriptor()->full_name(), type_url_prefix), arena);
+  return message.SerializeToString(value_->Mutable(arena));
+}
+
+bool AnyMetadata::UnpackTo(Message* message) const {
+  if (!InternalIs(message->GetDescriptor()->full_name())) {
+    return false;
+  }
+  return message->ParseFromString(value_->Get());
+}
+
+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 != nullptr &&
+          (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
+          *value_field != nullptr &&
+          (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
new file mode 100644
index 0000000..92ea2bb
--- /dev/null
+++ b/src/google/protobuf/any.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.
+
+#ifndef GOOGLE_PROTOBUF_ANY_H__
+#define GOOGLE_PROTOBUF_ANY_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class FieldDescriptor;
+class Message;
+
+namespace internal {
+
+extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
+extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
+extern const char kTypeGoogleProdComPrefix[];  // "type.googleprod.com/".
+
+std::string GetTypeUrl(StringPiece message_name,
+                       StringPiece type_url_prefix);
+
+// Helper class used to implement google::protobuf::Any.
+class PROTOBUF_EXPORT AnyMetadata {
+  typedef ArenaStringPtr UrlType;
+  typedef ArenaStringPtr ValueType;
+ public:
+  // AnyMetadata does not take ownership of "type_url" and "value".
+  constexpr AnyMetadata(UrlType* type_url, ValueType* value)
+      : type_url_(type_url), value_(value) {}
+
+  // Packs a message using the default type URL prefix: "type.googleapis.com".
+  // The resulted type URL will be "type.googleapis.com/<message_full_name>".
+  // Returns false if serializing the message failed.
+  template <typename T>
+  bool PackFrom(Arena* arena, const T& message) {
+    return InternalPackFrom(arena, message, kTypeGoogleApisComPrefix,
+                            T::FullMessageName());
+  }
+
+  bool PackFrom(Arena* arena, const Message& message);
+
+  // Packs a message using the given type URL prefix. The type URL will be
+  // constructed by concatenating the message type's full name to the prefix
+  // with an optional "/" separator if the prefix doesn't already end with "/".
+  // For example, both PackFrom(message, "type.googleapis.com") and
+  // PackFrom(message, "type.googleapis.com/") yield the same result type
+  // URL: "type.googleapis.com/<message_full_name>".
+  // Returns false if serializing the message failed.
+  template <typename T>
+  bool PackFrom(Arena* arena, const T& message,
+                StringPiece type_url_prefix) {
+    return InternalPackFrom(arena, message, type_url_prefix,
+                            T::FullMessageName());
+  }
+
+  bool PackFrom(Arena* arena, const Message& message,
+                StringPiece type_url_prefix);
+
+  // Unpacks the payload into the given message. Returns false if the message's
+  // type doesn't match the type specified in the type URL (i.e., the full
+  // name after the last "/" of the type URL doesn't match the message's actual
+  // full name) or parsing the payload has failed.
+  template <typename T>
+  bool UnpackTo(T* message) const {
+    return InternalUnpackTo(T::FullMessageName(), message);
+  }
+
+  bool UnpackTo(Message* message) const;
+
+  // Checks whether the type specified in the type URL matches the given type.
+  // A type is considered matching if its full name matches the full name after
+  // the last "/" in the type URL.
+  template <typename T>
+  bool Is() const {
+    return InternalIs(T::FullMessageName());
+  }
+
+ private:
+  bool InternalPackFrom(Arena* arena, const MessageLite& message,
+                        StringPiece type_url_prefix,
+                        StringPiece type_name);
+  bool InternalUnpackTo(StringPiece type_name,
+                        MessageLite* message) const;
+  bool InternalIs(StringPiece type_name) const;
+
+  UrlType* type_url_;
+  ValueType* value_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
+};
+
+// 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 the type_url does not have a "/"
+// in the type url separating the full type name.
+//
+// NOTE: this function is available publicly as a static method on the
+// generated message type: google::protobuf::Any::ParseAnyTypeUrl()
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* full_type_name);
+
+// Get the proto type name and prefix from Any::type_url value. For example,
+// passing "type.googleapis.com/rpc.QueryOrigin" will return
+// "type.googleapis.com/" in *url_prefix and "rpc.QueryOrigin" in
+// *full_type_name. Returns false if the type_url does not have a "/" in the
+// type url separating the full type name.
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* url_prefix,
+                     std::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
+
+#include <google/protobuf/port_undef.inc>
+
+#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..c02f9eb
--- /dev/null
+++ b/src/google/protobuf/any.pb.cc
@@ -0,0 +1,368 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#include <google/protobuf/any.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+#if defined(__llvm__)
+  #pragma clang diagnostic push
+  #pragma clang diagnostic ignored "-Wuninitialized"
+#endif  // __llvm__
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Any::Any(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}} {}
+struct AnyDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR AnyDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~AnyDefaultTypeInternal() {}
+  union {
+    Any _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 AnyDefaultTypeInternal _Any_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fany_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _impl_.type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _impl_.value_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Any)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Any_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\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(\014Bv\n\023com.google.protobufB\010AnyProtoP\001Z"
+  ",google.golang.org/protobuf/types/known/"
+  "anypb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownT"
+  "ypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fany_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
+    false, false, 212, descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
+    "google/protobuf/any.proto",
+    &descriptor_table_google_2fprotobuf_2fany_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fany_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fany_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fany_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fany_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fany_2eproto(&descriptor_table_google_2fprotobuf_2fany_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+bool Any::GetAnyFieldDescriptors(
+    const ::PROTOBUF_NAMESPACE_ID::Message& message,
+    const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
+    const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field) {
+  return ::_pbi::GetAnyFieldDescriptors(
+      message, type_url_field, value_field);
+}
+bool Any::ParseAnyTypeUrl(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,
+    std::string* full_type_name) {
+  return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);
+}
+
+class Any::_Internal {
+ public:
+};
+
+Any::Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Any)
+}
+Any::Any(const Any& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Any* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.type_url_){}
+    , decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_type_url().empty()) {
+    _this->_impl_.type_url_.Set(from._internal_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_value().empty()) {
+    _this->_impl_.value_.Set(from._internal_value(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
+}
+
+inline void Any::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.type_url_){}
+    , decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}
+  };
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Any::~Any() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Any)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Any::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.type_url_.Destroy();
+  _impl_.value_.Destroy();
+  _impl_._any_metadata_.~AnyMetadata();
+}
+
+void Any::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Any::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.type_url_.ClearToEmpty();
+  _impl_.value_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Any::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string type_url = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Any.type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bytes value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Any::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string type_url = 1;
+  if (!this->_internal_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Any.type_url");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_type_url(), target);
+  }
+
+  // bytes value = 2;
+  if (!this->_internal_value().empty()) {
+    target = stream->WriteBytesMaybeAliased(
+        2, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
+  return target;
+}
+
+size_t Any::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string type_url = 1;
+  if (!this->_internal_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_type_url());
+  }
+
+  // bytes value = 2;
+  if (!this->_internal_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
+        this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Any::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Any::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Any::GetClassData() const { return &_class_data_; }
+
+
+void Any::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Any*>(&to_msg);
+  auto& from = static_cast<const Any&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_type_url().empty()) {
+    _this->_internal_set_type_url(from._internal_type_url());
+  }
+  if (!from._internal_value().empty()) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Any::CopyFrom(const Any& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Any::IsInitialized() const {
+  return true;
+}
+
+void Any::InternalSwap(Any* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.type_url_, lhs_arena,
+      &other->_impl_.type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.value_, lhs_arena,
+      &other->_impl_.value_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Any::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fany_2eproto_getter, &descriptor_table_google_2fprotobuf_2fany_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fany_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Any*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Any >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Any >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#if defined(__llvm__)
+  #pragma clang diagnostic pop
+#endif  // __llvm__
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
new file mode 100644
index 0000000..982e9cf
--- /dev/null
+++ b/src/google/protobuf/any.pb.h
@@ -0,0 +1,384 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fany_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fany_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Any;
+struct AnyDefaultTypeInternal;
+PROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Any* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Any>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Any final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
+ public:
+  inline Any() : Any(nullptr) {}
+  ~Any() override;
+  explicit PROTOBUF_CONSTEXPR Any(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Any(const Any& from);
+  Any(Any&& from) noexcept
+    : Any() {
+    *this = ::std::move(from);
+  }
+
+  inline Any& operator=(const Any& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Any& operator=(Any&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Any& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Any* internal_default_instance() {
+    return reinterpret_cast<const Any*>(
+               &_Any_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  // implements Any -----------------------------------------------
+
+  bool PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message& message) {
+    GOOGLE_DCHECK_NE(&message, this);
+    return _impl_._any_metadata_.PackFrom(GetArena(), message);
+  }
+  bool PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message& message,
+                ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url_prefix) {
+    GOOGLE_DCHECK_NE(&message, this);
+    return _impl_._any_metadata_.PackFrom(GetArena(), message, type_url_prefix);
+  }
+  bool UnpackTo(::PROTOBUF_NAMESPACE_ID::Message* message) const {
+    return _impl_._any_metadata_.UnpackTo(message);
+  }
+  static bool GetAnyFieldDescriptors(
+      const ::PROTOBUF_NAMESPACE_ID::Message& message,
+      const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
+      const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field);
+  template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
+  bool PackFrom(const T& message) {
+    return _impl_._any_metadata_.PackFrom<T>(GetArena(), message);
+  }
+  template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
+  bool PackFrom(const T& message,
+                ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url_prefix) {
+    return _impl_._any_metadata_.PackFrom<T>(GetArena(), message, type_url_prefix);}
+  template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
+  bool UnpackTo(T* message) const {
+    return _impl_._any_metadata_.UnpackTo<T>(message);
+  }
+  template<typename T> bool Is() const {
+    return _impl_._any_metadata_.Is<T>();
+  }
+  static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,
+                              std::string* full_type_name);
+  friend void swap(Any& a, Any& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Any* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Any* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Any* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Any>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Any& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Any& from) {
+    Any::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Any* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Any";
+  }
+  protected:
+  explicit Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kTypeUrlFieldNumber = 1,
+    kValueFieldNumber = 2,
+  };
+  // string type_url = 1;
+  void clear_type_url();
+  const std::string& type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_type_url();
+  PROTOBUF_NODISCARD std::string* release_type_url();
+  void set_allocated_type_url(std::string* type_url);
+  private:
+  const std::string& _internal_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_url(const std::string& value);
+  std::string* _internal_mutable_type_url();
+  public:
+
+  // bytes value = 2;
+  void clear_value();
+  const std::string& value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_value();
+  PROTOBUF_NODISCARD std::string* release_value();
+  void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Any)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_url_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata _any_metadata_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fany_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Any
+
+// string type_url = 1;
+inline void Any::clear_type_url() {
+  _impl_.type_url_.ClearToEmpty();
+}
+inline const std::string& Any::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
+  return _internal_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Any::set_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
+}
+inline std::string* Any::mutable_type_url() {
+  std::string* _s = _internal_mutable_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
+  return _s;
+}
+inline const std::string& Any::_internal_type_url() const {
+  return _impl_.type_url_.Get();
+}
+inline void Any::_internal_set_type_url(const std::string& value) {
+  
+  _impl_.type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Any::_internal_mutable_type_url() {
+  
+  return _impl_.type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Any::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
+  return _impl_.type_url_.Release();
+}
+inline void Any::set_allocated_type_url(std::string* type_url) {
+  if (type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.type_url_.SetAllocated(type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_url_.IsDefault()) {
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
+}
+
+// bytes value = 2;
+inline void Any::clear_value() {
+  _impl_.value_.ClearToEmpty();
+}
+inline const std::string& Any::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
+  return _internal_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Any::set_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.value)
+}
+inline std::string* Any::mutable_value() {
+  std::string* _s = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
+  return _s;
+}
+inline const std::string& Any::_internal_value() const {
+  return _impl_.value_.Get();
+}
+inline void Any::_internal_set_value(const std::string& value) {
+  
+  _impl_.value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Any::_internal_mutable_value() {
+  
+  return _impl_.value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Any::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.value)
+  return _impl_.value_.Release();
+}
+inline void Any::set_allocated_value(std::string* value) {
+  if (value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.value_.SetAllocated(value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.value_.IsDefault()) {
+    _impl_.value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
new file mode 100644
index 0000000..e2c2042
--- /dev/null
+++ b/src/google/protobuf/any.proto
@@ -0,0 +1,158 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "google.golang.org/protobuf/types/known/anypb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// `Any` contains an arbitrary serialized protocol buffer message along with a
+// URL that describes the type of the serialized message.
+//
+// Protobuf library provides support to pack/unpack Any values in the form
+// of utility functions or additional generated methods of the Any type.
+//
+// Example 1: Pack and unpack a message in C++.
+//
+//     Foo foo = ...;
+//     Any any;
+//     any.PackFrom(foo);
+//     ...
+//     if (any.UnpackTo(&foo)) {
+//       ...
+//     }
+//
+// Example 2: Pack and unpack a message in Java.
+//
+//     Foo foo = ...;
+//     Any any = Any.pack(foo);
+//     ...
+//     if (any.is(Foo.class)) {
+//       foo = any.unpack(Foo.class);
+//     }
+//
+// Example 3: Pack and unpack a message in Python.
+//
+//     foo = Foo(...)
+//     any = Any()
+//     any.Pack(foo)
+//     ...
+//     if any.Is(Foo.DESCRIPTOR):
+//       any.Unpack(foo)
+//       ...
+//
+// Example 4: Pack and unpack a message in Go
+//
+//      foo := &pb.Foo{...}
+//      any, err := anypb.New(foo)
+//      if err != nil {
+//        ...
+//      }
+//      ...
+//      foo := &pb.Foo{}
+//      if err := any.UnmarshalTo(foo); err != nil {
+//        ...
+//      }
+//
+// The pack methods provided by protobuf library will by default use
+// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+// methods only use the fully qualified type name after the last '/'
+// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+// name "y.z".
+//
+//
+// JSON
+//
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+//     package google.profile;
+//     message Person {
+//       string first_name = 1;
+//       string last_name = 2;
+//     }
+//
+//     {
+//       "@type": "type.googleapis.com/google.profile.Person",
+//       "firstName": <string>,
+//       "lastName": <string>
+//     }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
+//
+//     {
+//       "@type": "type.googleapis.com/google.protobuf.Duration",
+//       "value": "1.212s"
+//     }
+//
+message Any {
+  // A URL/resource name that uniquely identifies the type of the serialized
+  // protocol buffer message. This string must contain at least
+  // one "/" character. The last segment of the URL's path must represent
+  // the fully qualified name of the type (as in
+  // `path/google.protobuf.Duration`). The name should be in a canonical form
+  // (e.g., leading "." is not accepted).
+  //
+  // In practice, teams usually precompile into the binary all types that they
+  // expect it to use in the context of Any. However, for URLs which use the
+  // scheme `http`, `https`, or no scheme, one can optionally set up a type
+  // server that maps type URLs to message definitions as follows:
+  //
+  // * If no scheme is provided, `https` is assumed.
+  // * 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.)
+  //
+  // Note: this functionality is not currently available in the official
+  // protobuf release, and it is not used for type URLs beginning with
+  // type.googleapis.com.
+  //
+  // Schemes other than `http`, `https` (or the empty scheme) might be
+  // used with implementation specific semantics.
+  //
+  string type_url = 1;
+
+  // Must be a valid serialized protocol buffer of the above specified type.
+  bytes value = 2;
+}
diff --git a/src/google/protobuf/any_lite.cc b/src/google/protobuf/any_lite.cc
new file mode 100644
index 0000000..f283a31
--- /dev/null
+++ b/src/google/protobuf/any_lite.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 <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+std::string GetTypeUrl(StringPiece message_name,
+                       StringPiece type_url_prefix) {
+  if (!type_url_prefix.empty() &&
+      type_url_prefix[type_url_prefix.size() - 1] == '/') {
+    return StrCat(type_url_prefix, message_name);
+  } else {
+    return StrCat(type_url_prefix, "/", message_name);
+  }
+}
+
+const char kAnyFullTypeName[] = "google.protobuf.Any";
+const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
+
+bool AnyMetadata::InternalPackFrom(Arena* arena, const MessageLite& message,
+                                   StringPiece type_url_prefix,
+                                   StringPiece type_name) {
+  type_url_->Set(GetTypeUrl(type_name, type_url_prefix), arena);
+  return message.SerializeToString(value_->Mutable(arena));
+}
+
+bool AnyMetadata::InternalUnpackTo(StringPiece type_name,
+                                   MessageLite* message) const {
+  if (!InternalIs(type_name)) {
+    return false;
+  }
+  return message->ParseFromString(value_->Get());
+}
+
+bool AnyMetadata::InternalIs(StringPiece type_name) const {
+  StringPiece type_url = type_url_->Get();
+  return type_url.size() >= type_name.size() + 1 &&
+         type_url[type_url.size() - type_name.size() - 1] == '/' &&
+         HasSuffixString(type_url, type_name);
+}
+
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* url_prefix,
+                     std::string* full_type_name) {
+  size_t pos = type_url.find_last_of('/');
+  if (pos == std::string::npos || pos + 1 == type_url.size()) {
+    return false;
+  }
+  if (url_prefix) {
+    *url_prefix = std::string(type_url.substr(0, pos + 1));
+  }
+  *full_type_name = std::string(type_url.substr(pos + 1));
+  return true;
+}
+
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* full_type_name) {
+  return ParseAnyTypeUrl(type_url, nullptr, full_type_name);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/any_test.cc b/src/google/protobuf/any_test.cc
new file mode 100644
index 0000000..a82afb2
--- /dev/null
+++ b/src/google/protobuf/any_test.cc
@@ -0,0 +1,194 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/any_test.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <gtest/gtest.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(AnyMetadataTest, ConstInit) {
+  PROTOBUF_CONSTINIT static internal::AnyMetadata metadata(nullptr, nullptr);
+  (void)metadata;
+}
+
+TEST(AnyTest, TestPackAndUnpack) {
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  protobuf_unittest::TestAny message;
+  ASSERT_TRUE(message.mutable_any_value()->PackFrom(submessage));
+
+  std::string data = message.SerializeAsString();
+
+  ASSERT_TRUE(message.ParseFromString(data));
+  EXPECT_TRUE(message.has_any_value());
+  submessage.Clear();
+  ASSERT_TRUE(message.any_value().UnpackTo(&submessage));
+  EXPECT_EQ(12345, submessage.int32_value());
+}
+
+TEST(AnyTest, TestPackFromSerializationExceedsSizeLimit) {
+  protobuf_unittest::TestAny submessage;
+  submessage.mutable_text()->resize(INT_MAX, 'a');
+  protobuf_unittest::TestAny message;
+  EXPECT_FALSE(message.mutable_any_value()->PackFrom(submessage));
+}
+
+TEST(AnyTest, TestUnpackWithTypeMismatch) {
+  protobuf_unittest::TestAny payload;
+  payload.set_int32_value(13);
+  google::protobuf::Any any;
+  any.PackFrom(payload);
+
+  // Attempt to unpack into the wrong type.
+  protobuf_unittest::TestAllTypes dest;
+  EXPECT_FALSE(any.UnpackTo(&dest));
+}
+
+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);
+
+  std::string data = message.SerializeAsString();
+
+  ASSERT_TRUE(message.ParseFromString(data));
+  EXPECT_TRUE(message.has_any_value());
+  any.Clear();
+  submessage.Clear();
+  ASSERT_TRUE(message.any_value().UnpackTo(&any));
+  ASSERT_TRUE(any.UnpackTo(&submessage));
+  EXPECT_EQ(12345, submessage.int32_value());
+}
+
+TEST(AnyTest, TestPackWithCustomTypeUrl) {
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  google::protobuf::Any any;
+  // Pack with a custom type URL prefix.
+  any.PackFrom(submessage, "type.myservice.com");
+  EXPECT_EQ("type.myservice.com/protobuf_unittest.TestAny", any.type_url());
+  // Pack with a custom type URL prefix ending with '/'.
+  any.PackFrom(submessage, "type.myservice.com/");
+  EXPECT_EQ("type.myservice.com/protobuf_unittest.TestAny", any.type_url());
+  // Pack with an empty type URL prefix.
+  any.PackFrom(submessage, "");
+  EXPECT_EQ("/protobuf_unittest.TestAny", any.type_url());
+
+  // Test unpacking the type.
+  submessage.Clear();
+  EXPECT_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>());
+
+  any.set_type_url("/protobuf_unittest.TestAny");
+  EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
+  // The type URL must contain at least one "/".
+  any.set_type_url("protobuf_unittest.TestAny");
+  EXPECT_FALSE(any.Is<protobuf_unittest::TestAny>());
+  // The type name after the slash must be fully qualified.
+  any.set_type_url("/TestAny");
+  EXPECT_FALSE(any.Is<protobuf_unittest::TestAny>());
+}
+
+TEST(AnyTest, MoveConstructor) {
+  protobuf_unittest::TestAny payload;
+  payload.set_int32_value(12345);
+
+  google::protobuf::Any src;
+  src.PackFrom(payload);
+
+  const char* type_url = src.type_url().data();
+
+  google::protobuf::Any dst(std::move(src));
+  EXPECT_EQ(type_url, dst.type_url().data());
+  payload.Clear();
+  ASSERT_TRUE(dst.UnpackTo(&payload));
+  EXPECT_EQ(12345, payload.int32_value());
+}
+
+TEST(AnyTest, MoveAssignment) {
+  protobuf_unittest::TestAny payload;
+  payload.set_int32_value(12345);
+
+  google::protobuf::Any src;
+  src.PackFrom(payload);
+
+  const char* type_url = src.type_url().data();
+
+  google::protobuf::Any dst;
+  dst = std::move(src);
+  EXPECT_EQ(type_url, dst.type_url().data());
+  payload.Clear();
+  ASSERT_TRUE(dst.UnpackTo(&payload));
+  EXPECT_EQ(12345, payload.int32_value());
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+#ifndef NDEBUG
+TEST(AnyTest, PackSelfDeath) {
+  google::protobuf::Any any;
+  EXPECT_DEATH(any.PackFrom(any), "&message");
+  EXPECT_DEATH(any.PackFrom(any, ""), "&message");
+}
+#endif  // !NDEBUG
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/any_test.proto b/src/google/protobuf/any_test.proto
new file mode 100644
index 0000000..256035b
--- /dev/null
+++ b/src/google/protobuf/any_test.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 = "proto3";
+
+package protobuf_unittest;
+
+import "google/protobuf/any.proto";
+
+option java_outer_classname = "TestAnyProto";
+
+message TestAny {
+  int32 int32_value = 1;
+  google.protobuf.Any any_value = 2;
+  repeated google.protobuf.Any repeated_any_value = 3;
+  string text = 4;
+}
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
new file mode 100644
index 0000000..24b6049
--- /dev/null
+++ b/src/google/protobuf/api.pb.cc
@@ -0,0 +1,1309 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#include <google/protobuf/api.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Api::Api(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.methods_)*/{}
+  , /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.mixins_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.version_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.source_context_)*/nullptr
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct ApiDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ApiDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ApiDefaultTypeInternal() {}
+  union {
+    Api _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ApiDefaultTypeInternal _Api_default_instance_;
+PROTOBUF_CONSTEXPR Method::Method(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.request_type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.response_type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.request_streaming_)*/false
+  , /*decltype(_impl_.response_streaming_)*/false
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct MethodDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MethodDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MethodDefaultTypeInternal() {}
+  union {
+    Method _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodDefaultTypeInternal _Method_default_instance_;
+PROTOBUF_CONSTEXPR Mixin::Mixin(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.root_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct MixinDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MixinDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MixinDefaultTypeInternal() {}
+  union {
+    Mixin _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MixinDefaultTypeInternal _Mixin_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fapi_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.methods_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.version_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.source_context_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.mixins_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.request_type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.request_streaming_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.response_type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.response_streaming_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, _impl_.root_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Api)},
+  { 13, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Method)},
+  { 26, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Mixin)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Api_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Method_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Mixin_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\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(\tBv\n\023com.google.pr"
+  "otobufB\010ApiProtoP\001Z,google.golang.org/pr"
+  "otobuf/types/known/apipb\242\002\003GPB\252\002\036Google."
+  "Protobuf.WellKnownTypesb\006proto3"
+  ;
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2fapi_2eproto_deps[2] = {
+  &::descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto,
+  &::descriptor_table_google_2fprotobuf_2ftype_2eproto,
+};
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fapi_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
+    false, false, 751, descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
+    "google/protobuf/api.proto",
+    &descriptor_table_google_2fprotobuf_2fapi_2eproto_once, descriptor_table_google_2fprotobuf_2fapi_2eproto_deps, 2, 3,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fapi_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fapi_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fapi_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fapi_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fapi_2eproto(&descriptor_table_google_2fprotobuf_2fapi_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Api::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context(const Api* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::SourceContext&
+Api::_Internal::source_context(const Api* msg) {
+  return *msg->_impl_.source_context_;
+}
+void Api::clear_options() {
+  _impl_.options_.Clear();
+}
+void Api::clear_source_context() {
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+}
+Api::Api(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Api)
+}
+Api::Api(const Api& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Api* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.methods_){from._impl_.methods_}
+    , decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.mixins_){from._impl_.mixins_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.version_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.version_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.version_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_version().empty()) {
+    _this->_impl_.version_.Set(from._internal_version(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
+  }
+  _this->_impl_.syntax_ = from._impl_.syntax_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Api)
+}
+
+inline void Api::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.methods_){arena}
+    , decltype(_impl_.options_){arena}
+    , decltype(_impl_.mixins_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.version_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.version_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.version_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Api::~Api() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Api)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Api::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.methods_.~RepeatedPtrField();
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.mixins_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  _impl_.version_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.source_context_;
+}
+
+void Api::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Api::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Api)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.methods_.Clear();
+  _impl_.options_.Clear();
+  _impl_.mixins_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.version_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+  _impl_.syntax_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Api::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Api.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Method methods = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_methods(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // string version = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_version();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Api.version"));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.SourceContext source_context = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Mixin mixins = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_mixins(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Api::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.Method methods = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_methods_size()); i < n; i++) {
+    const auto& repfield = this->_internal_methods(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // string version = 4;
+  if (!this->_internal_version().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_version().data(), static_cast<int>(this->_internal_version().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.version");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_version(), target);
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(5, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_mixins_size()); i < n; i++) {
+    const auto& repfield = this->_internal_mixins(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      7, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Api)
+  return target;
+}
+
+size_t Api::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Api)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Method methods = 2;
+  total_size += 1UL * this->_internal_methods_size();
+  for (const auto& msg : this->_impl_.methods_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  total_size += 1UL * this->_internal_mixins_size();
+  for (const auto& msg : this->_impl_.mixins_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string version = 4;
+  if (!this->_internal_version().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_version());
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.source_context_);
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Api::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Api::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Api::GetClassData() const { return &_class_data_; }
+
+
+void Api::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Api*>(&to_msg);
+  auto& from = static_cast<const Api&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Api)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.methods_.MergeFrom(from._impl_.methods_);
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  _this->_impl_.mixins_.MergeFrom(from._impl_.mixins_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_version().empty()) {
+    _this->_internal_set_version(from._internal_version());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
+        from._internal_source_context());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Api::CopyFrom(const Api& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Api)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Api::IsInitialized() const {
+  return true;
+}
+
+void Api::InternalSwap(Api* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.methods_.InternalSwap(&other->_impl_.methods_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  _impl_.mixins_.InternalSwap(&other->_impl_.mixins_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.version_, lhs_arena,
+      &other->_impl_.version_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Api, _impl_.syntax_)
+      + sizeof(Api::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Api, _impl_.source_context_)>(
+          reinterpret_cast<char*>(&_impl_.source_context_),
+          reinterpret_cast<char*>(&other->_impl_.source_context_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Api::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fapi_2eproto[0]);
+}
+
+// ===================================================================
+
+class Method::_Internal {
+ public:
+};
+
+void Method::clear_options() {
+  _impl_.options_.Clear();
+}
+Method::Method(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Method)
+}
+Method::Method(const Method& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Method* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.request_type_url_){}
+    , decltype(_impl_.response_type_url_){}
+    , decltype(_impl_.request_streaming_){}
+    , decltype(_impl_.response_streaming_){}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.request_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.request_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_request_type_url().empty()) {
+    _this->_impl_.request_type_url_.Set(from._internal_request_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.response_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.response_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_response_type_url().empty()) {
+    _this->_impl_.response_type_url_.Set(from._internal_response_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.request_streaming_, &from._impl_.request_streaming_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.syntax_) -
+    reinterpret_cast<char*>(&_impl_.request_streaming_)) + sizeof(_impl_.syntax_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Method)
+}
+
+inline void Method::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.request_type_url_){}
+    , decltype(_impl_.response_type_url_){}
+    , decltype(_impl_.request_streaming_){false}
+    , decltype(_impl_.response_streaming_){false}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.request_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.request_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.response_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.response_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Method::~Method() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Method)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Method::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  _impl_.request_type_url_.Destroy();
+  _impl_.response_type_url_.Destroy();
+}
+
+void Method::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Method::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Method)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.request_type_url_.ClearToEmpty();
+  _impl_.response_type_url_.ClearToEmpty();
+  ::memset(&_impl_.request_streaming_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.syntax_) -
+      reinterpret_cast<char*>(&_impl_.request_streaming_)) + sizeof(_impl_.syntax_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Method::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string request_type_url = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_request_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.request_type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bool request_streaming = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _impl_.request_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // string response_type_url = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_response_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.response_type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bool response_streaming = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _impl_.response_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Method::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // string request_type_url = 2;
+  if (!this->_internal_request_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_request_type_url().data(), static_cast<int>(this->_internal_request_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.request_type_url");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_request_type_url(), target);
+  }
+
+  // bool request_streaming = 3;
+  if (this->_internal_request_streaming() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_request_streaming(), target);
+  }
+
+  // string response_type_url = 4;
+  if (!this->_internal_response_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_response_type_url().data(), static_cast<int>(this->_internal_response_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.response_type_url");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_response_type_url(), target);
+  }
+
+  // bool response_streaming = 5;
+  if (this->_internal_response_streaming() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_response_streaming(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      7, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Method)
+  return target;
+}
+
+size_t Method::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Method)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Option options = 6;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string request_type_url = 2;
+  if (!this->_internal_request_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_request_type_url());
+  }
+
+  // string response_type_url = 4;
+  if (!this->_internal_response_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_response_type_url());
+  }
+
+  // bool request_streaming = 3;
+  if (this->_internal_request_streaming() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // bool response_streaming = 5;
+  if (this->_internal_response_streaming() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Method::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Method::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Method::GetClassData() const { return &_class_data_; }
+
+
+void Method::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Method*>(&to_msg);
+  auto& from = static_cast<const Method&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Method)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_request_type_url().empty()) {
+    _this->_internal_set_request_type_url(from._internal_request_type_url());
+  }
+  if (!from._internal_response_type_url().empty()) {
+    _this->_internal_set_response_type_url(from._internal_response_type_url());
+  }
+  if (from._internal_request_streaming() != 0) {
+    _this->_internal_set_request_streaming(from._internal_request_streaming());
+  }
+  if (from._internal_response_streaming() != 0) {
+    _this->_internal_set_response_streaming(from._internal_response_streaming());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Method::CopyFrom(const Method& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Method)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Method::IsInitialized() const {
+  return true;
+}
+
+void Method::InternalSwap(Method* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.request_type_url_, lhs_arena,
+      &other->_impl_.request_type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.response_type_url_, lhs_arena,
+      &other->_impl_.response_type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Method, _impl_.syntax_)
+      + sizeof(Method::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Method, _impl_.request_streaming_)>(
+          reinterpret_cast<char*>(&_impl_.request_streaming_),
+          reinterpret_cast<char*>(&other->_impl_.request_streaming_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Method::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fapi_2eproto[1]);
+}
+
+// ===================================================================
+
+class Mixin::_Internal {
+ public:
+};
+
+Mixin::Mixin(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Mixin)
+}
+Mixin::Mixin(const Mixin& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Mixin* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.root_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.root_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.root_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_root().empty()) {
+    _this->_impl_.root_.Set(from._internal_root(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Mixin)
+}
+
+inline void Mixin::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.root_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.root_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.root_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Mixin::~Mixin() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Mixin)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Mixin::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.root_.Destroy();
+}
+
+void Mixin::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Mixin::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.name_.ClearToEmpty();
+  _impl_.root_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Mixin::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Mixin.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string root = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_root();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Mixin.root"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Mixin::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // string root = 2;
+  if (!this->_internal_root().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_root().data(), static_cast<int>(this->_internal_root().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.root");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_root(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Mixin)
+  return target;
+}
+
+size_t Mixin::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Mixin)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string root = 2;
+  if (!this->_internal_root().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_root());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Mixin::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Mixin::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Mixin::GetClassData() const { return &_class_data_; }
+
+
+void Mixin::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Mixin*>(&to_msg);
+  auto& from = static_cast<const Mixin&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Mixin)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_root().empty()) {
+    _this->_internal_set_root(from._internal_root());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Mixin::CopyFrom(const Mixin& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Mixin)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Mixin::IsInitialized() const {
+  return true;
+}
+
+void Mixin::InternalSwap(Mixin* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.root_, lhs_arena,
+      &other->_impl_.root_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Mixin::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fapi_2eproto[2]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Api*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Api >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Api >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Method*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Method >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Method >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Mixin*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Mixin >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Mixin >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
new file mode 100644
index 0000000..3e746de
--- /dev/null
+++ b/src/google/protobuf/api.pb.h
@@ -0,0 +1,1437 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fapi_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fapi_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/source_context.pb.h>
+#include <google/protobuf/type.pb.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fapi_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fapi_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Api;
+struct ApiDefaultTypeInternal;
+PROTOBUF_EXPORT extern ApiDefaultTypeInternal _Api_default_instance_;
+class Method;
+struct MethodDefaultTypeInternal;
+PROTOBUF_EXPORT extern MethodDefaultTypeInternal _Method_default_instance_;
+class Mixin;
+struct MixinDefaultTypeInternal;
+PROTOBUF_EXPORT extern MixinDefaultTypeInternal _Mixin_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Api* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Api>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Method* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Method>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Mixin* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Mixin>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Api final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Api) */ {
+ public:
+  inline Api() : Api(nullptr) {}
+  ~Api() override;
+  explicit PROTOBUF_CONSTEXPR Api(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Api(const Api& from);
+  Api(Api&& from) noexcept
+    : Api() {
+    *this = ::std::move(from);
+  }
+
+  inline Api& operator=(const Api& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Api& operator=(Api&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Api& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Api* internal_default_instance() {
+    return reinterpret_cast<const Api*>(
+               &_Api_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Api& a, Api& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Api* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Api* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Api* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Api>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Api& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Api& from) {
+    Api::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Api* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Api";
+  }
+  protected:
+  explicit Api(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kMethodsFieldNumber = 2,
+    kOptionsFieldNumber = 3,
+    kMixinsFieldNumber = 6,
+    kNameFieldNumber = 1,
+    kVersionFieldNumber = 4,
+    kSourceContextFieldNumber = 5,
+    kSyntaxFieldNumber = 7,
+  };
+  // repeated .google.protobuf.Method methods = 2;
+  int methods_size() const;
+  private:
+  int _internal_methods_size() const;
+  public:
+  void clear_methods();
+  ::PROTOBUF_NAMESPACE_ID::Method* mutable_methods(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >*
+      mutable_methods();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Method& _internal_methods(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Method* _internal_add_methods();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Method& methods(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Method* add_methods();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >&
+      methods() const;
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  int mixins_size() const;
+  private:
+  int _internal_mixins_size() const;
+  public:
+  void clear_mixins();
+  ::PROTOBUF_NAMESPACE_ID::Mixin* mutable_mixins(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >*
+      mutable_mixins();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Mixin& _internal_mixins(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Mixin* _internal_add_mixins();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Mixin& mixins(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Mixin* add_mixins();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >&
+      mixins() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string version = 4;
+  void clear_version();
+  const std::string& version() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_version(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_version();
+  PROTOBUF_NODISCARD std::string* release_version();
+  void set_allocated_version(std::string* version);
+  private:
+  const std::string& _internal_version() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_version(const std::string& value);
+  std::string* _internal_mutable_version();
+  public:
+
+  // .google.protobuf.SourceContext source_context = 5;
+  bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
+  void clear_source_context();
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
+  void set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& _internal_source_context() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _internal_mutable_source_context();
+  public:
+  void unsafe_arena_set_allocated_source_context(
+      ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* unsafe_arena_release_source_context();
+
+  // .google.protobuf.Syntax syntax = 7;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Api)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method > methods_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin > mixins_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr version_;
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fapi_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Method final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Method) */ {
+ public:
+  inline Method() : Method(nullptr) {}
+  ~Method() override;
+  explicit PROTOBUF_CONSTEXPR Method(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Method(const Method& from);
+  Method(Method&& from) noexcept
+    : Method() {
+    *this = ::std::move(from);
+  }
+
+  inline Method& operator=(const Method& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Method& operator=(Method&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Method& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Method* internal_default_instance() {
+    return reinterpret_cast<const Method*>(
+               &_Method_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(Method& a, Method& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Method* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Method* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Method* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Method>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Method& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Method& from) {
+    Method::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Method* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Method";
+  }
+  protected:
+  explicit Method(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 6,
+    kNameFieldNumber = 1,
+    kRequestTypeUrlFieldNumber = 2,
+    kResponseTypeUrlFieldNumber = 4,
+    kRequestStreamingFieldNumber = 3,
+    kResponseStreamingFieldNumber = 5,
+    kSyntaxFieldNumber = 7,
+  };
+  // repeated .google.protobuf.Option options = 6;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string request_type_url = 2;
+  void clear_request_type_url();
+  const std::string& request_type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_request_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_request_type_url();
+  PROTOBUF_NODISCARD std::string* release_request_type_url();
+  void set_allocated_request_type_url(std::string* request_type_url);
+  private:
+  const std::string& _internal_request_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_request_type_url(const std::string& value);
+  std::string* _internal_mutable_request_type_url();
+  public:
+
+  // string response_type_url = 4;
+  void clear_response_type_url();
+  const std::string& response_type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_response_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_response_type_url();
+  PROTOBUF_NODISCARD std::string* release_response_type_url();
+  void set_allocated_response_type_url(std::string* response_type_url);
+  private:
+  const std::string& _internal_response_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_response_type_url(const std::string& value);
+  std::string* _internal_mutable_response_type_url();
+  public:
+
+  // bool request_streaming = 3;
+  void clear_request_streaming();
+  bool request_streaming() const;
+  void set_request_streaming(bool value);
+  private:
+  bool _internal_request_streaming() const;
+  void _internal_set_request_streaming(bool value);
+  public:
+
+  // bool response_streaming = 5;
+  void clear_response_streaming();
+  bool response_streaming() const;
+  void set_response_streaming(bool value);
+  private:
+  bool _internal_response_streaming() const;
+  void _internal_set_response_streaming(bool value);
+  public:
+
+  // .google.protobuf.Syntax syntax = 7;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Method)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr request_type_url_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr response_type_url_;
+    bool request_streaming_;
+    bool response_streaming_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fapi_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Mixin final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Mixin) */ {
+ public:
+  inline Mixin() : Mixin(nullptr) {}
+  ~Mixin() override;
+  explicit PROTOBUF_CONSTEXPR Mixin(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Mixin(const Mixin& from);
+  Mixin(Mixin&& from) noexcept
+    : Mixin() {
+    *this = ::std::move(from);
+  }
+
+  inline Mixin& operator=(const Mixin& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Mixin& operator=(Mixin&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Mixin& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Mixin* internal_default_instance() {
+    return reinterpret_cast<const Mixin*>(
+               &_Mixin_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Mixin& a, Mixin& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Mixin* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Mixin* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Mixin* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Mixin>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Mixin& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Mixin& from) {
+    Mixin::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Mixin* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Mixin";
+  }
+  protected:
+  explicit Mixin(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kRootFieldNumber = 2,
+  };
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string root = 2;
+  void clear_root();
+  const std::string& root() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_root(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_root();
+  PROTOBUF_NODISCARD std::string* release_root();
+  void set_allocated_root(std::string* root);
+  private:
+  const std::string& _internal_root() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_root(const std::string& value);
+  std::string* _internal_mutable_root();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Mixin)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr root_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fapi_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Api
+
+// string name = 1;
+inline void Api::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Api::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Api::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.name)
+}
+inline std::string* Api::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.name)
+  return _s;
+}
+inline const std::string& Api::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Api::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Api::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Api::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.name)
+  return _impl_.name_.Release();
+}
+inline void Api::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.name)
+}
+
+// repeated .google.protobuf.Method methods = 2;
+inline int Api::_internal_methods_size() const {
+  return _impl_.methods_.size();
+}
+inline int Api::methods_size() const {
+  return _internal_methods_size();
+}
+inline void Api::clear_methods() {
+  _impl_.methods_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Method* Api::mutable_methods(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods)
+  return _impl_.methods_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >*
+Api::mutable_methods() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods)
+  return &_impl_.methods_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Method& Api::_internal_methods(int index) const {
+  return _impl_.methods_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Method& Api::methods(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.methods)
+  return _internal_methods(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Method* Api::_internal_add_methods() {
+  return _impl_.methods_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Method* Api::add_methods() {
+  ::PROTOBUF_NAMESPACE_ID::Method* _add = _internal_add_methods();
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.methods)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >&
+Api::methods() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.methods)
+  return _impl_.methods_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int Api::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Api::options_size() const {
+  return _internal_options_size();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Api::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Api::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Api::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Api::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Api::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Api::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Api::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.options)
+  return _impl_.options_;
+}
+
+// string version = 4;
+inline void Api::clear_version() {
+  _impl_.version_.ClearToEmpty();
+}
+inline const std::string& Api::version() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.version)
+  return _internal_version();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Api::set_version(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.version_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.version)
+}
+inline std::string* Api::mutable_version() {
+  std::string* _s = _internal_mutable_version();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.version)
+  return _s;
+}
+inline const std::string& Api::_internal_version() const {
+  return _impl_.version_.Get();
+}
+inline void Api::_internal_set_version(const std::string& value) {
+  
+  _impl_.version_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Api::_internal_mutable_version() {
+  
+  return _impl_.version_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Api::release_version() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.version)
+  return _impl_.version_.Release();
+}
+inline void Api::set_allocated_version(std::string* version) {
+  if (version != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.version_.SetAllocated(version, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.version_.IsDefault()) {
+    _impl_.version_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.version)
+}
+
+// .google.protobuf.SourceContext source_context = 5;
+inline bool Api::_internal_has_source_context() const {
+  return this != internal_default_instance() && _impl_.source_context_ != nullptr;
+}
+inline bool Api::has_source_context() const {
+  return _internal_has_source_context();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Api::_internal_source_context() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext* p = _impl_.source_context_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceContext&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Api::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.source_context)
+  return _internal_source_context();
+}
+inline void Api::unsafe_arena_set_allocated_source_context(
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  _impl_.source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Api.source_context)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::release_source_context() {
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::unsafe_arena_release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context)
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::_internal_mutable_source_context() {
+  
+  if (_impl_.source_context_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(GetArenaForAllocation());
+    _impl_.source_context_ = p;
+  }
+  return _impl_.source_context_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::mutable_source_context() {
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _msg = _internal_mutable_source_context();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context)
+  return _msg;
+}
+inline void Api::set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  if (source_context) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(source_context));
+    if (message_arena != submessage_arena) {
+      source_context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_context, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.source_context_ = source_context;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.source_context)
+}
+
+// repeated .google.protobuf.Mixin mixins = 6;
+inline int Api::_internal_mixins_size() const {
+  return _impl_.mixins_.size();
+}
+inline int Api::mixins_size() const {
+  return _internal_mixins_size();
+}
+inline void Api::clear_mixins() {
+  _impl_.mixins_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Mixin* Api::mutable_mixins(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins)
+  return _impl_.mixins_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >*
+Api::mutable_mixins() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins)
+  return &_impl_.mixins_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Mixin& Api::_internal_mixins(int index) const {
+  return _impl_.mixins_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Mixin& Api::mixins(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins)
+  return _internal_mixins(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Mixin* Api::_internal_add_mixins() {
+  return _impl_.mixins_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Mixin* Api::add_mixins() {
+  ::PROTOBUF_NAMESPACE_ID::Mixin* _add = _internal_add_mixins();
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >&
+Api::mixins() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins)
+  return _impl_.mixins_;
+}
+
+// .google.protobuf.Syntax syntax = 7;
+inline void Api::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Api::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Api::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.syntax)
+  return _internal_syntax();
+}
+inline void Api::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Api::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Method
+
+// string name = 1;
+inline void Method::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Method::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Method::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.name)
+}
+inline std::string* Method::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.name)
+  return _s;
+}
+inline const std::string& Method::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Method::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Method::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Method::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.name)
+  return _impl_.name_.Release();
+}
+inline void Method::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.name)
+}
+
+// string request_type_url = 2;
+inline void Method::clear_request_type_url() {
+  _impl_.request_type_url_.ClearToEmpty();
+}
+inline const std::string& Method::request_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_type_url)
+  return _internal_request_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Method::set_request_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.request_type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_type_url)
+}
+inline std::string* Method::mutable_request_type_url() {
+  std::string* _s = _internal_mutable_request_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.request_type_url)
+  return _s;
+}
+inline const std::string& Method::_internal_request_type_url() const {
+  return _impl_.request_type_url_.Get();
+}
+inline void Method::_internal_set_request_type_url(const std::string& value) {
+  
+  _impl_.request_type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Method::_internal_mutable_request_type_url() {
+  
+  return _impl_.request_type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Method::release_request_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url)
+  return _impl_.request_type_url_.Release();
+}
+inline void Method::set_allocated_request_type_url(std::string* request_type_url) {
+  if (request_type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.request_type_url_.SetAllocated(request_type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.request_type_url_.IsDefault()) {
+    _impl_.request_type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.request_type_url)
+}
+
+// bool request_streaming = 3;
+inline void Method::clear_request_streaming() {
+  _impl_.request_streaming_ = false;
+}
+inline bool Method::_internal_request_streaming() const {
+  return _impl_.request_streaming_;
+}
+inline bool Method::request_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_streaming)
+  return _internal_request_streaming();
+}
+inline void Method::_internal_set_request_streaming(bool value) {
+  
+  _impl_.request_streaming_ = value;
+}
+inline void Method::set_request_streaming(bool value) {
+  _internal_set_request_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_streaming)
+}
+
+// string response_type_url = 4;
+inline void Method::clear_response_type_url() {
+  _impl_.response_type_url_.ClearToEmpty();
+}
+inline const std::string& Method::response_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_type_url)
+  return _internal_response_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Method::set_response_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.response_type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_type_url)
+}
+inline std::string* Method::mutable_response_type_url() {
+  std::string* _s = _internal_mutable_response_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.response_type_url)
+  return _s;
+}
+inline const std::string& Method::_internal_response_type_url() const {
+  return _impl_.response_type_url_.Get();
+}
+inline void Method::_internal_set_response_type_url(const std::string& value) {
+  
+  _impl_.response_type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Method::_internal_mutable_response_type_url() {
+  
+  return _impl_.response_type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Method::release_response_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url)
+  return _impl_.response_type_url_.Release();
+}
+inline void Method::set_allocated_response_type_url(std::string* response_type_url) {
+  if (response_type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.response_type_url_.SetAllocated(response_type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.response_type_url_.IsDefault()) {
+    _impl_.response_type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.response_type_url)
+}
+
+// bool response_streaming = 5;
+inline void Method::clear_response_streaming() {
+  _impl_.response_streaming_ = false;
+}
+inline bool Method::_internal_response_streaming() const {
+  return _impl_.response_streaming_;
+}
+inline bool Method::response_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_streaming)
+  return _internal_response_streaming();
+}
+inline void Method::_internal_set_response_streaming(bool value) {
+  
+  _impl_.response_streaming_ = value;
+}
+inline void Method::set_response_streaming(bool value) {
+  _internal_set_response_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_streaming)
+}
+
+// repeated .google.protobuf.Option options = 6;
+inline int Method::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Method::options_size() const {
+  return _internal_options_size();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Method::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Method::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Method::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Method::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Method::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Method::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Method.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Method::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Method.options)
+  return _impl_.options_;
+}
+
+// .google.protobuf.Syntax syntax = 7;
+inline void Method::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Method::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Method::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.syntax)
+  return _internal_syntax();
+}
+inline void Method::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Method::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Mixin
+
+// string name = 1;
+inline void Mixin::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Mixin::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Mixin::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name)
+}
+inline std::string* Mixin::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name)
+  return _s;
+}
+inline const std::string& Mixin::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Mixin::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Mixin::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Mixin::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name)
+  return _impl_.name_.Release();
+}
+inline void Mixin::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name)
+}
+
+// string root = 2;
+inline void Mixin::clear_root() {
+  _impl_.root_.ClearToEmpty();
+}
+inline const std::string& Mixin::root() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
+  return _internal_root();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Mixin::set_root(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.root_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root)
+}
+inline std::string* Mixin::mutable_root() {
+  std::string* _s = _internal_mutable_root();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root)
+  return _s;
+}
+inline const std::string& Mixin::_internal_root() const {
+  return _impl_.root_.Get();
+}
+inline void Mixin::_internal_set_root(const std::string& value) {
+  
+  _impl_.root_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Mixin::_internal_mutable_root() {
+  
+  return _impl_.root_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Mixin::release_root() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root)
+  return _impl_.root_.Release();
+}
+inline void Mixin::set_allocated_root(std::string* root) {
+  if (root != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.root_.SetAllocated(root, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.root_.IsDefault()) {
+    _impl_.root_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fapi_2eproto
diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto
new file mode 100644
index 0000000..3d598fc
--- /dev/null
+++ b/src/google/protobuf/api.proto
@@ -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.
+
+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 objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/apipb";
+
+// Api is a light-weight descriptor for an API Interface.
+//
+// Interfaces are also described as "protocol buffer services" in some contexts,
+// such as by the "service" keyword in a .proto file, but they are different
+// from API Services, which represent a concrete implementation of an interface
+// as opposed to simply a description of methods and bindings. They are also
+// sometimes simply referred to as "APIs" in other contexts, such as the name of
+// this message itself. See https://cloud.google.com/apis/design/glossary for
+// detailed terminology.
+message Api {
+  // The fully qualified name of this interface, including package name
+  // followed by the interface's simple name.
+  string name = 1;
+
+  // The methods of this interface, in unspecified order.
+  repeated Method methods = 2;
+
+  // Any metadata attached to the interface.
+  repeated Option options = 3;
+
+  // A version string for this interface. 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
+  // interface, 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, non-GA interfaces.
+  //
+  //
+  string version = 4;
+
+  // Source context for the protocol buffer service represented by this
+  // message.
+  SourceContext source_context = 5;
+
+  // Included interfaces. See [Mixin][].
+  repeated Mixin mixins = 6;
+
+  // The source syntax of the service.
+  Syntax syntax = 7;
+}
+
+// Method represents a method of an API interface.
+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 Interface to be included in this interface. The including
+// interface must redeclare all the methods from the included interface, 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 interface 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 inheriting
+// 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 interface which is included.
+  string name = 1;
+
+  // If non-empty specifies a path under which inherited HTTP paths
+  // are rooted.
+  string root = 2;
+}
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
new file mode 100644
index 0000000..6ba508a
--- /dev/null
+++ b/src/google/protobuf/arena.cc
@@ -0,0 +1,537 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arena.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <typeinfo>
+
+#include <google/protobuf/arena_impl.h>
+#include <google/protobuf/arenaz_sampler.h>
+#include <google/protobuf/port.h>
+
+#include <google/protobuf/stubs/mutex.h>
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif  // ADDRESS_SANITIZER
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+static SerialArena::Memory AllocateMemory(const AllocationPolicy* policy_ptr,
+                                          size_t last_size, size_t min_bytes) {
+  AllocationPolicy policy;  // default policy
+  if (policy_ptr) policy = *policy_ptr;
+  size_t size;
+  if (last_size != 0) {
+    // Double the current block size, up to a limit.
+    auto max_size = policy.max_block_size;
+    size = std::min(2 * last_size, max_size);
+  } else {
+    size = policy.start_block_size;
+  }
+  // Verify that min_bytes + kBlockHeaderSize won't overflow.
+  GOOGLE_CHECK_LE(min_bytes,
+           std::numeric_limits<size_t>::max() - SerialArena::kBlockHeaderSize);
+  size = std::max(size, SerialArena::kBlockHeaderSize + min_bytes);
+
+  void* mem;
+  if (policy.block_alloc == nullptr) {
+    mem = ::operator new(size);
+  } else {
+    mem = policy.block_alloc(size);
+  }
+  return {mem, size};
+}
+
+class GetDeallocator {
+ public:
+  GetDeallocator(const AllocationPolicy* policy, size_t* space_allocated)
+      : dealloc_(policy ? policy->block_dealloc : nullptr),
+        space_allocated_(space_allocated) {}
+
+  void operator()(SerialArena::Memory mem) const {
+#ifdef ADDRESS_SANITIZER
+    // This memory was provided by the underlying allocator as unpoisoned,
+    // so return it in an unpoisoned state.
+    ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
+#endif  // ADDRESS_SANITIZER
+    if (dealloc_) {
+      dealloc_(mem.ptr, mem.size);
+    } else {
+      internal::SizedDelete(mem.ptr, mem.size);
+    }
+    *space_allocated_ += mem.size;
+  }
+
+ private:
+  void (*dealloc_)(void*, size_t);
+  size_t* space_allocated_;
+};
+
+SerialArena::SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats)
+    : space_allocated_(b->size) {
+  owner_ = owner;
+  head_ = b;
+  ptr_ = b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize);
+  limit_ = b->Pointer(b->size & static_cast<size_t>(-8));
+  arena_stats_ = stats;
+}
+
+SerialArena* SerialArena::New(Memory mem, void* owner,
+                              ThreadSafeArenaStats* stats) {
+  GOOGLE_DCHECK_LE(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize, mem.size);
+  ThreadSafeArenaStats::RecordAllocateStats(
+      stats, /*requested=*/mem.size, /*allocated=*/mem.size, /*wasted=*/0);
+  auto b = new (mem.ptr) Block{nullptr, mem.size};
+  return new (b->Pointer(kBlockHeaderSize)) SerialArena(b, owner, stats);
+}
+
+template <typename Deallocator>
+SerialArena::Memory SerialArena::Free(Deallocator deallocator) {
+  Block* b = head_;
+  Memory mem = {b, b->size};
+  while (b->next) {
+    b = b->next;  // We must first advance before deleting this block
+    deallocator(mem);
+    mem = {b, b->size};
+  }
+  return mem;
+}
+
+PROTOBUF_NOINLINE
+std::pair<void*, SerialArena::CleanupNode*>
+SerialArena::AllocateAlignedWithCleanupFallback(
+    size_t n, const AllocationPolicy* policy) {
+  AllocateNewBlock(n + kCleanupSize, policy);
+  return AllocateFromExistingWithCleanupFallback(n);
+}
+
+PROTOBUF_NOINLINE
+void* SerialArena::AllocateAlignedFallback(size_t n,
+                                           const AllocationPolicy* policy) {
+  AllocateNewBlock(n, policy);
+  return AllocateFromExisting(n);
+}
+
+void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) {
+  // Sync limit to block
+  head_->start = reinterpret_cast<CleanupNode*>(limit_);
+
+  // Record how much used in this block.
+  size_t used = ptr_ - head_->Pointer(kBlockHeaderSize);
+  size_t wasted = head_->size - used;
+  space_used_ += used;
+
+  // TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a
+  // win. In preliminary testing showed increased memory savings as expected,
+  // but with a CPU regression. The regression might have been an artifact of
+  // the microbenchmark.
+
+  auto mem = AllocateMemory(policy, head_->size, n);
+  // We don't want to emit an expensive RMW instruction that requires
+  // exclusive access to a cacheline. Hence we write it in terms of a
+  // regular add.
+  auto relaxed = std::memory_order_relaxed;
+  space_allocated_.store(space_allocated_.load(relaxed) + mem.size, relaxed);
+  ThreadSafeArenaStats::RecordAllocateStats(arena_stats_, /*requested=*/n,
+                                            /*allocated=*/mem.size, wasted);
+  head_ = new (mem.ptr) Block{head_, mem.size};
+  ptr_ = head_->Pointer(kBlockHeaderSize);
+  limit_ = head_->Pointer(head_->size);
+
+#ifdef ADDRESS_SANITIZER
+  ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_);
+#endif  // ADDRESS_SANITIZER
+}
+
+uint64_t SerialArena::SpaceUsed() const {
+  uint64_t space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
+  space_used += space_used_;
+  // Remove the overhead of the SerialArena itself.
+  space_used -= ThreadSafeArena::kSerialArenaSize;
+  return space_used;
+}
+
+void SerialArena::CleanupList() {
+  Block* b = head_;
+  b->start = reinterpret_cast<CleanupNode*>(limit_);
+  do {
+    auto* limit = reinterpret_cast<CleanupNode*>(
+        b->Pointer(b->size & static_cast<size_t>(-8)));
+    auto it = b->start;
+    auto num = limit - it;
+    if (num > 0) {
+      for (; it < limit; it++) {
+        it->cleanup(it->elem);
+      }
+    }
+    b = b->next;
+  } while (b);
+}
+
+
+ThreadSafeArena::CacheAlignedLifecycleIdGenerator
+    ThreadSafeArena::lifecycle_id_generator_;
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
+  static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
+      new internal::ThreadLocalStorage<ThreadCache>();
+  return *thread_cache_->Get();
+}
+#elif defined(PROTOBUF_USE_DLLS)
+ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
+  static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_ = {
+      0, static_cast<LifecycleIdAtomic>(-1), nullptr};
+  return thread_cache_;
+}
+#else
+PROTOBUF_THREAD_LOCAL ThreadSafeArena::ThreadCache
+    ThreadSafeArena::thread_cache_ = {0, static_cast<LifecycleIdAtomic>(-1),
+                                      nullptr};
+#endif
+
+void ThreadSafeArena::InitializeFrom(void* mem, size_t size) {
+  GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
+  GOOGLE_DCHECK(!AllocPolicy());  // Reset should call InitializeWithPolicy instead.
+  Init();
+
+  // Ignore initial block if it is too small.
+  if (mem != nullptr && size >= kBlockHeaderSize + kSerialArenaSize) {
+    alloc_policy_.set_is_user_owned_initial_block(true);
+    SetInitialBlock(mem, size);
+  }
+}
+
+void ThreadSafeArena::InitializeWithPolicy(void* mem, size_t size,
+                                           AllocationPolicy policy) {
+#ifndef NDEBUG
+  const uint64_t old_alloc_policy = alloc_policy_.get_raw();
+  // If there was a policy (e.g., in Reset()), make sure flags were preserved.
+#define GOOGLE_DCHECK_POLICY_FLAGS_() \
+  if (old_alloc_policy > 3)    \
+    GOOGLE_CHECK_EQ(old_alloc_policy & 3, alloc_policy_.get_raw() & 3)
+#else
+#define GOOGLE_DCHECK_POLICY_FLAGS_()
+#endif  // NDEBUG
+
+  if (policy.IsDefault()) {
+    // Legacy code doesn't use the API above, but provides the initial block
+    // through ArenaOptions. I suspect most do not touch the allocation
+    // policy parameters.
+    InitializeFrom(mem, size);
+    GOOGLE_DCHECK_POLICY_FLAGS_();
+    return;
+  }
+  GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
+  Init();
+
+  // Ignore initial block if it is too small. We include an optional
+  // AllocationPolicy in this check, so that this can be allocated on the
+  // first block.
+  constexpr size_t kAPSize = internal::AlignUpTo8(sizeof(AllocationPolicy));
+  constexpr size_t kMinimumSize = kBlockHeaderSize + kSerialArenaSize + kAPSize;
+
+  // The value for alloc_policy_ stores whether or not allocations should be
+  // recorded.
+  alloc_policy_.set_should_record_allocs(
+      policy.metrics_collector != nullptr &&
+      policy.metrics_collector->RecordAllocs());
+  // Make sure we have an initial block to store the AllocationPolicy.
+  if (mem != nullptr && size >= kMinimumSize) {
+    alloc_policy_.set_is_user_owned_initial_block(true);
+  } else {
+    auto tmp = AllocateMemory(&policy, 0, kMinimumSize);
+    mem = tmp.ptr;
+    size = tmp.size;
+  }
+  SetInitialBlock(mem, size);
+
+  auto sa = threads_.load(std::memory_order_relaxed);
+  // We ensured enough space so this cannot fail.
+  void* p;
+  if (!sa || !sa->MaybeAllocateAligned(kAPSize, &p)) {
+    GOOGLE_LOG(FATAL) << "MaybeAllocateAligned cannot fail here.";
+    return;
+  }
+  new (p) AllocationPolicy{policy};
+  // Low bits store flags, so they mustn't be overwritten.
+  GOOGLE_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(p) & 3);
+  alloc_policy_.set_policy(reinterpret_cast<AllocationPolicy*>(p));
+  GOOGLE_DCHECK_POLICY_FLAGS_();
+
+#undef GOOGLE_DCHECK_POLICY_FLAGS_
+}
+
+void ThreadSafeArena::Init() {
+#ifndef NDEBUG
+  const bool was_message_owned = IsMessageOwned();
+#endif  // NDEBUG
+  ThreadCache& tc = thread_cache();
+  auto id = tc.next_lifecycle_id;
+  // We increment lifecycle_id's by multiples of two so we can use bit 0 as
+  // a tag.
+  constexpr uint64_t kDelta = 2;
+  constexpr uint64_t kInc = ThreadCache::kPerThreadIds * kDelta;
+  if (PROTOBUF_PREDICT_FALSE((id & (kInc - 1)) == 0)) {
+    constexpr auto relaxed = std::memory_order_relaxed;
+    // On platforms that don't support uint64_t atomics we can certainly not
+    // afford to increment by large intervals and expect uniqueness due to
+    // wrapping, hence we only add by 1.
+    id = lifecycle_id_generator_.id.fetch_add(1, relaxed) * kInc;
+  }
+  tc.next_lifecycle_id = id + kDelta;
+  // Message ownership is stored in tag_and_id_, and is set in the constructor.
+  // This flag bit must be preserved, even across calls to Reset().
+  tag_and_id_ = id | (tag_and_id_ & kMessageOwnedArena);
+  hint_.store(nullptr, std::memory_order_relaxed);
+  threads_.store(nullptr, std::memory_order_relaxed);
+#ifndef NDEBUG
+  GOOGLE_CHECK_EQ(was_message_owned, IsMessageOwned());
+#endif  // NDEBUG
+  arena_stats_ = Sample();
+}
+
+void ThreadSafeArena::SetInitialBlock(void* mem, size_t size) {
+  SerialArena* serial = SerialArena::New({mem, size}, &thread_cache(),
+                                         arena_stats_.MutableStats());
+  serial->set_next(NULL);
+  threads_.store(serial, std::memory_order_relaxed);
+  CacheSerialArena(serial);
+}
+
+ThreadSafeArena::~ThreadSafeArena() {
+  // Have to do this in a first pass, because some of the destructors might
+  // refer to memory in other blocks.
+  CleanupList();
+
+  size_t space_allocated = 0;
+  auto mem = Free(&space_allocated);
+
+  // Policy is about to get deleted.
+  auto* p = alloc_policy_.get();
+  ArenaMetricsCollector* collector = p ? p->metrics_collector : nullptr;
+
+  if (alloc_policy_.is_user_owned_initial_block()) {
+#ifdef ADDRESS_SANITIZER
+    // Unpoison the initial block, now that it's going back to the user.
+    ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
+#endif  // ADDRESS_SANITIZER
+    space_allocated += mem.size;
+  } else {
+    GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
+  }
+
+  if (collector) collector->OnDestroy(space_allocated);
+}
+
+SerialArena::Memory ThreadSafeArena::Free(size_t* space_allocated) {
+  SerialArena::Memory mem = {nullptr, 0};
+  auto deallocator = GetDeallocator(alloc_policy_.get(), space_allocated);
+  PerSerialArena([deallocator, &mem](SerialArena* a) {
+    if (mem.ptr) deallocator(mem);
+    mem = a->Free(deallocator);
+  });
+  return mem;
+}
+
+uint64_t ThreadSafeArena::Reset() {
+  // Have to do this in a first pass, because some of the destructors might
+  // refer to memory in other blocks.
+  CleanupList();
+
+  // Discard all blocks except the special block (if present).
+  size_t space_allocated = 0;
+  auto mem = Free(&space_allocated);
+  arena_stats_.RecordReset();
+
+  AllocationPolicy* policy = alloc_policy_.get();
+  if (policy) {
+    auto saved_policy = *policy;
+    if (alloc_policy_.is_user_owned_initial_block()) {
+      space_allocated += mem.size;
+    } else {
+      GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
+      mem.ptr = nullptr;
+      mem.size = 0;
+    }
+    ArenaMetricsCollector* collector = saved_policy.metrics_collector;
+    if (collector) collector->OnReset(space_allocated);
+    InitializeWithPolicy(mem.ptr, mem.size, saved_policy);
+  } else {
+    GOOGLE_DCHECK(!alloc_policy_.should_record_allocs());
+    // Nullptr policy
+    if (alloc_policy_.is_user_owned_initial_block()) {
+      space_allocated += mem.size;
+      InitializeFrom(mem.ptr, mem.size);
+    } else {
+      GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
+      Init();
+    }
+  }
+
+  return space_allocated;
+}
+
+std::pair<void*, SerialArena::CleanupNode*>
+ThreadSafeArena::AllocateAlignedWithCleanup(size_t n,
+                                            const std::type_info* type) {
+  SerialArena* arena;
+  if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
+                            GetSerialArenaFast(&arena))) {
+    return arena->AllocateAlignedWithCleanup(n, alloc_policy_.get());
+  } else {
+    return AllocateAlignedWithCleanupFallback(n, type);
+  }
+}
+
+void ThreadSafeArena::AddCleanup(void* elem, void (*cleanup)(void*)) {
+  SerialArena* arena;
+  if (PROTOBUF_PREDICT_FALSE(!GetSerialArenaFast(&arena))) {
+    arena = GetSerialArenaFallback(&thread_cache());
+  }
+  arena->AddCleanup(elem, cleanup, AllocPolicy());
+}
+
+PROTOBUF_NOINLINE
+void* ThreadSafeArena::AllocateAlignedFallback(size_t n,
+                                               const std::type_info* type) {
+  if (alloc_policy_.should_record_allocs()) {
+    alloc_policy_.RecordAlloc(type, n);
+    SerialArena* arena;
+    if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+      return arena->AllocateAligned(n, alloc_policy_.get());
+    }
+  }
+  return GetSerialArenaFallback(&thread_cache())
+      ->AllocateAligned(n, alloc_policy_.get());
+}
+
+PROTOBUF_NOINLINE
+std::pair<void*, SerialArena::CleanupNode*>
+ThreadSafeArena::AllocateAlignedWithCleanupFallback(
+    size_t n, const std::type_info* type) {
+  if (alloc_policy_.should_record_allocs()) {
+    alloc_policy_.RecordAlloc(type, n);
+    SerialArena* arena;
+    if (GetSerialArenaFast(&arena)) {
+      return arena->AllocateAlignedWithCleanup(n, alloc_policy_.get());
+    }
+  }
+  return GetSerialArenaFallback(&thread_cache())
+      ->AllocateAlignedWithCleanup(n, alloc_policy_.get());
+}
+
+uint64_t ThreadSafeArena::SpaceAllocated() const {
+  SerialArena* serial = threads_.load(std::memory_order_acquire);
+  uint64_t res = 0;
+  for (; serial; serial = serial->next()) {
+    res += serial->SpaceAllocated();
+  }
+  return res;
+}
+
+uint64_t ThreadSafeArena::SpaceUsed() const {
+  SerialArena* serial = threads_.load(std::memory_order_acquire);
+  uint64_t space_used = 0;
+  for (; serial; serial = serial->next()) {
+    space_used += serial->SpaceUsed();
+  }
+  return space_used - (alloc_policy_.get() ? sizeof(AllocationPolicy) : 0);
+}
+
+void ThreadSafeArena::CleanupList() {
+  PerSerialArena([](SerialArena* a) { a->CleanupList(); });
+}
+
+PROTOBUF_NOINLINE
+SerialArena* ThreadSafeArena::GetSerialArenaFallback(void* me) {
+  // Look for this SerialArena in our linked list.
+  SerialArena* serial = threads_.load(std::memory_order_acquire);
+  for (; serial; serial = serial->next()) {
+    if (serial->owner() == me) {
+      break;
+    }
+  }
+
+  if (!serial) {
+    // This thread doesn't have any SerialArena, which also means it doesn't
+    // have any blocks yet.  So we'll allocate its first block now.
+    serial = SerialArena::New(
+        AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), me,
+        arena_stats_.MutableStats());
+
+    SerialArena* head = threads_.load(std::memory_order_relaxed);
+    do {
+      serial->set_next(head);
+    } while (!threads_.compare_exchange_weak(
+        head, serial, std::memory_order_release, std::memory_order_relaxed));
+  }
+
+  CacheSerialArena(serial);
+  return serial;
+}
+
+}  // namespace internal
+
+PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedNoHook(size_t n) {
+  return impl_.AllocateAligned(n, nullptr);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedWithHook(size_t n, const std::type_info* type) {
+  return impl_.AllocateAligned(n, type);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedWithHookForArray(size_t n,
+                                             const std::type_info* type) {
+  return impl_.AllocateAligned<internal::AllocationClient::kArray>(n, type);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
+std::pair<void*, internal::SerialArena::CleanupNode*>
+Arena::AllocateAlignedWithCleanup(size_t n, const std::type_info* type) {
+  return impl_.AllocateAlignedWithCleanup(n, type);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
new file mode 100644
index 0000000..3b5f16c
--- /dev/null
+++ b/src/google/protobuf/arena.h
@@ -0,0 +1,851 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 an Arena allocator for better allocation performance.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_H__
+#define GOOGLE_PROTOBUF_ARENA_H__
+
+
+#include <limits>
+#include <type_traits>
+#include <utility>
+#if defined(_MSC_VER) && !defined(_LIBCPP_STD_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 <type_traits>
+#include <google/protobuf/arena_impl.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+struct ArenaOptions;  // defined below
+class Arena;    // defined below
+class Message;  // defined in message.h
+class MessageLite;
+template <typename Key, typename T>
+class Map;
+
+namespace arena_metrics {
+
+void EnableArenaMetrics(ArenaOptions* options);
+
+}  // namespace arena_metrics
+
+namespace TestUtil {
+class ReflectionTester;  // defined in test_util.h
+}  // namespace TestUtil
+
+namespace internal {
+
+struct ArenaTestPeer;        // defined in arena_test_util.h
+class InternalMetadata;      // defined in metadata_lite.h
+class LazyField;             // defined in lazy_field.h
+class EpsCopyInputStream;    // defined in parse_context.h
+class RepeatedPtrFieldBase;  // defined in repeated_ptr_field.h
+
+template <typename Type>
+class GenericTypeHandler;  // defined in repeated_field.h
+
+inline PROTOBUF_ALWAYS_INLINE
+void* AlignTo(void* ptr, size_t align) {
+  return reinterpret_cast<void*>(
+      (reinterpret_cast<uintptr_t>(ptr) + align - 1) & (~align + 1));
+}
+
+// Templated cleanup methods.
+template <typename T>
+void arena_destruct_object(void* object) {
+  reinterpret_cast<T*>(object)->~T();
+}
+
+template <bool destructor_skippable, typename T>
+struct ObjectDestructor {
+  constexpr static void (*destructor)(void*) = &arena_destruct_object<T>;
+};
+
+template <typename T>
+struct ObjectDestructor<true, T> {
+  constexpr static void (*destructor)(void*) = nullptr;
+};
+
+template <typename T>
+void arena_delete_object(void* object) {
+  delete reinterpret_cast<T*>(object);
+}
+}  // namespace internal
+
+// ArenaOptions provides optional additional parameters to arena construction
+// that control its block-allocation behavior.
+struct ArenaOptions {
+  // This defines the size of the first block requested from the system malloc.
+  // Subsequent block sizes will increase in a geometric series up to a maximum.
+  size_t start_block_size;
+
+  // This defines the maximum block size requested from system malloc (unless an
+  // individual arena allocation request occurs with a size larger than this
+  // maximum). Requested block sizes increase up to this value, then remain
+  // here.
+  size_t max_block_size;
+
+  // An initial block of memory for the arena to use, or NULL for none. If
+  // provided, the block must live at least as long as the arena itself. The
+  // creator of the Arena retains ownership of the block after the Arena is
+  // destroyed.
+  char* initial_block;
+
+  // The size of the initial block, if provided.
+  size_t initial_block_size;
+
+  // A function pointer to an alloc method that returns memory blocks of size
+  // requested. By default, it contains a ptr to the malloc function.
+  //
+  // NOTE: block_alloc and dealloc functions are expected to behave like
+  // malloc and free, including Asan poisoning.
+  void* (*block_alloc)(size_t);
+  // A function pointer to a dealloc method that takes ownership of the blocks
+  // from the arena. By default, it contains a ptr to a wrapper function that
+  // calls free.
+  void (*block_dealloc)(void*, size_t);
+
+  ArenaOptions()
+      : start_block_size(internal::AllocationPolicy::kDefaultStartBlockSize),
+        max_block_size(internal::AllocationPolicy::kDefaultMaxBlockSize),
+        initial_block(NULL),
+        initial_block_size(0),
+        block_alloc(nullptr),
+        block_dealloc(nullptr),
+        make_metrics_collector(nullptr) {}
+
+ private:
+  // If make_metrics_collector is not nullptr, it will be called at Arena init
+  // time. It may return a pointer to a collector instance that will be notified
+  // of interesting events related to the arena.
+  internal::ArenaMetricsCollector* (*make_metrics_collector)();
+
+  internal::ArenaMetricsCollector* MetricsCollector() const {
+    return make_metrics_collector ? (*make_metrics_collector)() : nullptr;
+  }
+
+  internal::AllocationPolicy AllocationPolicy() const {
+    internal::AllocationPolicy res;
+    res.start_block_size = start_block_size;
+    res.max_block_size = max_block_size;
+    res.block_alloc = block_alloc;
+    res.block_dealloc = block_dealloc;
+    res.metrics_collector = MetricsCollector();
+    return res;
+  }
+
+  friend void arena_metrics::EnableArenaMetrics(ArenaOptions*);
+
+  friend class Arena;
+  friend class ArenaOptionsTestFriend;
+};
+
+// Support for non-RTTI environments. (The metrics hooks API uses type
+// information.)
+#if PROTOBUF_RTTI
+#define RTTI_TYPE_ID(type) (&typeid(type))
+#else
+#define RTTI_TYPE_ID(type) (NULL)
+#endif
+
+// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
+// with new/delete, and improves performance by aggregating allocations into
+// larger blocks and freeing allocations all at once. Protocol messages are
+// allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
+// are automatically freed when the arena is destroyed.
+//
+// This is a thread-safe implementation: multiple threads may allocate from the
+// arena concurrently. Destruction is not thread-safe and the destructing
+// thread must synchronize with users of the arena first.
+//
+// An arena provides two allocation interfaces: CreateMessage<T>, which works
+// for arena-enabled proto2 message types as well as other types that satisfy
+// the appropriate protocol (described below), and Create<T>, which works for
+// any arbitrary type T. CreateMessage<T> is better when the type T supports it,
+// because this interface (i) passes the arena pointer to the created object so
+// that its sub-objects and internal allocations can use the arena too, and (ii)
+// elides the object's destructor call when possible. Create<T> does not place
+// any special requirements on the type T, and will invoke the object's
+// destructor when the arena is destroyed.
+//
+// The arena message allocation protocol, required by
+// CreateMessage<T>(Arena* arena, Args&&... args), is as follows:
+//
+// - The type T must have (at least) two constructors: a constructor callable
+//   with `args` (without `arena`), called when a T is allocated on the heap;
+//   and a constructor callable with `Arena* arena, Args&&... args`, 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
+//   (`args`-only) 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.
+//
+// This protocol is implemented by all arena-enabled proto2 message classes as
+// well as protobuf container types like RepeatedPtrField and Map. The protocol
+// is internal to protobuf and is not guaranteed to be stable. Non-proto types
+// should not rely on this protocol.
+class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
+ public:
+  // Default constructor with sensible default options, tuned for average
+  // use-cases.
+  inline Arena() : impl_() {}
+
+  // Construct an arena with default options, except for the supplied
+  // initial block. It is more efficient to use this constructor
+  // instead of passing ArenaOptions if the only configuration needed
+  // by the caller is supplying an initial block.
+  inline Arena(char* initial_block, size_t initial_block_size)
+      : impl_(initial_block, initial_block_size) {}
+
+  // Arena constructor taking custom options. See ArenaOptions above for
+  // descriptions of the options available.
+  explicit Arena(const ArenaOptions& options)
+      : impl_(options.initial_block, options.initial_block_size,
+              options.AllocationPolicy()) {}
+
+  // Block overhead.  Use this as a guide for how much to over-allocate the
+  // initial block if you want an allocation of size N to fit inside it.
+  //
+  // WARNING: if you allocate multiple objects, it is difficult to guarantee
+  // that a series of allocations will fit in the initial block, especially if
+  // Arena changes its alignment guarantees in the future!
+  static const size_t kBlockOverhead =
+      internal::ThreadSafeArena::kBlockHeaderSize +
+      internal::ThreadSafeArena::kSerialArenaSize;
+
+  inline ~Arena() {}
+
+  // TODO(protobuf-team): Fix callers to use constructor and delete this method.
+  void Init(const ArenaOptions&) {}
+
+  // API to create proto2 message objects on the arena. If the arena passed in
+  // is NULL, then a heap allocated object is returned. Type T must be a message
+  // defined in a .proto file with cc_enable_arenas set to true, otherwise a
+  // compilation error will occur.
+  //
+  // RepeatedField and RepeatedPtrField may also be instantiated directly on an
+  // arena with this method.
+  //
+  // This function also accepts any type T that satisfies the arena message
+  // allocation protocol, documented above.
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateMessage(Arena* arena, Args&&... args) {
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+    // We must delegate to CreateMaybeMessage() and NOT CreateMessageInternal()
+    // because protobuf generated classes specialize CreateMaybeMessage() and we
+    // need to use that specialization for code size reasons.
+    return Arena::CreateMaybeMessage<T>(arena, static_cast<Args&&>(args)...);
+  }
+
+  // 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, typename... Args>
+  PROTOBUF_NDEBUG_INLINE static T* Create(Arena* arena, Args&&... args) {
+    return CreateInternal<T>(arena, std::is_convertible<T*, MessageLite*>(),
+                             static_cast<Args&&>(args)...);
+  }
+
+  // Allocates memory with the specific size and alignment.
+  void* AllocateAligned(size_t size, size_t align = 8) {
+    if (align <= 8) {
+      return AllocateAlignedNoHook(internal::AlignUpTo8(size));
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(AllocateAlignedNoHook(size + align - 8), align);
+    }
+  }
+
+  // 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>
+  PROTOBUF_NDEBUG_INLINE static T* CreateArray(Arena* arena,
+                                               size_t num_elements) {
+    static_assert(std::is_trivial<T>::value,
+                  "CreateArray requires a trivially constructible type");
+    static_assert(std::is_trivially_destructible<T>::value,
+                  "CreateArray requires a trivially destructible type");
+    GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
+    if (arena == NULL) {
+      return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
+    } else {
+      return arena->CreateInternalRawArray<T>(num_elements);
+    }
+  }
+
+  // The following are routines are for monitoring. They will approximate the
+  // total sum allocated and used memory, but the exact value is an
+  // implementation deal. For instance allocated space depends on growth
+  // policies. Do not use these in unit tests.
+  // Returns the total space allocated by the arena, which is the sum of the
+  // sizes of the underlying blocks.
+  uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); }
+  // Returns the total space used by the arena. Similar to SpaceAllocated but
+  // does not include free space and block overhead. The total space returned
+  // may not include space used by other threads executing concurrently with
+  // the call to this method.
+  uint64_t SpaceUsed() const { return impl_.SpaceUsed(); }
+
+  // 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_t Reset() { return impl_.Reset(); }
+
+  // Adds |object| to a list of heap-allocated objects to be freed with |delete|
+  // when the arena is destroyed or reset.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void Own(T* object) {
+    OwnInternal(object, std::is_convertible<T*, MessageLite*>());
+  }
+
+  // Adds |object| to a list of objects whose destructors will be manually
+  // called when the arena is destroyed or reset. This differs from Own() in
+  // that it does not free the underlying memory with |delete|; hence, it is
+  // normally only used for objects that are placement-newed into
+  // arena-allocated memory.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) {
+    if (object != NULL) {
+      impl_.AddCleanup(object, &internal::arena_destruct_object<T>);
+    }
+  }
+
+  // Adds a custom member function on an object to the list of destructors that
+  // will be manually called when the arena is destroyed or reset. This differs
+  // from OwnDestructor() in that any member function may be specified, not only
+  // the class destructor.
+  PROTOBUF_ALWAYS_INLINE void OwnCustomDestructor(void* object,
+                                                  void (*destruct)(void*)) {
+    impl_.AddCleanup(object, destruct);
+  }
+
+  // Retrieves the arena associated with |value| if |value| is an arena-capable
+  // message, or NULL otherwise. If possible, the call resolves at compile time.
+  // Note that we can often devirtualize calls to `value->GetArena()` so usually
+  // calling this method is unnecessary.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) {
+    return GetArenaInternal(value);
+  }
+
+  template <typename T>
+  class InternalHelper {
+   private:
+    // Provides access to protected GetOwningArena to generated messages.
+    static Arena* GetOwningArena(const T* p) { return p->GetOwningArena(); }
+
+    static void InternalSwap(T* a, T* b) { a->InternalSwap(b); }
+
+    static Arena* GetArenaForAllocationInternal(
+        const T* p, std::true_type /*is_derived_from<MessageLite>*/) {
+      return p->GetArenaForAllocation();
+    }
+
+    static Arena* GetArenaForAllocationInternal(
+        const T* p, std::false_type /*is_derived_from<MessageLite>*/) {
+      return GetArenaForAllocationForNonMessage(
+          p, typename is_arena_constructable::type());
+    }
+
+    static Arena* GetArenaForAllocationForNonMessage(
+        const T* p, std::true_type /*is_arena_constructible*/) {
+      return p->GetArena();
+    }
+
+    static Arena* GetArenaForAllocationForNonMessage(
+        const T* p, std::false_type /*is_arena_constructible*/) {
+      return GetArenaForAllocationForNonMessageNonArenaConstructible(
+          p, typename has_get_arena::type());
+    }
+
+    static Arena* GetArenaForAllocationForNonMessageNonArenaConstructible(
+        const T* p, std::true_type /*has_get_arena*/) {
+      return p->GetArena();
+    }
+
+    static Arena* GetArenaForAllocationForNonMessageNonArenaConstructible(
+        const T* /* p */, std::false_type /*has_get_arena*/) {
+      return nullptr;
+    }
+
+    template <typename U>
+    static char DestructorSkippable(const typename U::DestructorSkippable_*);
+    template <typename U>
+    static double DestructorSkippable(...);
+
+    typedef std::integral_constant<
+        bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
+                      sizeof(char) ||
+                  std::is_trivially_destructible<T>::value>
+        is_destructor_skippable;
+
+    template <typename U>
+    static char ArenaConstructable(
+        const typename U::InternalArenaConstructable_*);
+    template <typename U>
+    static double ArenaConstructable(...);
+
+    typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
+                                             static_cast<const T*>(0))) ==
+                                             sizeof(char)>
+        is_arena_constructable;
+
+    template <typename U,
+              typename std::enable_if<
+                  std::is_same<Arena*, decltype(std::declval<const U>()
+                                                    .GetArena())>::value,
+                  int>::type = 0>
+    static char HasGetArena(decltype(&U::GetArena));
+    template <typename U>
+    static double HasGetArena(...);
+
+    typedef std::integral_constant<bool, sizeof(HasGetArena<T>(nullptr)) ==
+                                             sizeof(char)>
+        has_get_arena;
+
+    template <typename... Args>
+    static T* Construct(void* ptr, Args&&... args) {
+      return new (ptr) T(static_cast<Args&&>(args)...);
+    }
+
+    static inline PROTOBUF_ALWAYS_INLINE T* New() {
+      return new T(nullptr);
+    }
+
+    static Arena* GetArena(const T* p) { return p->GetArena(); }
+
+    friend class Arena;
+    friend class TestUtil::ReflectionTester;
+  };
+
+  // Provides access to protected GetOwningArena to generated messages.  For
+  // internal use only.
+  template <typename T>
+  static Arena* InternalGetOwningArena(const T* p) {
+    return InternalHelper<T>::GetOwningArena(p);
+  }
+
+  // Provides access to protected GetArenaForAllocation to generated messages.
+  // For internal use only.
+  template <typename T>
+  static Arena* InternalGetArenaForAllocation(const T* p) {
+    return InternalHelper<T>::GetArenaForAllocationInternal(
+        p, std::is_convertible<T*, MessageLite*>());
+  }
+
+  // Creates message-owned arena.  For internal use only.
+  static Arena* InternalCreateMessageOwnedArena() {
+    return new Arena(internal::MessageOwned{});
+  }
+
+  // Checks whether this arena is message-owned.  For internal use only.
+  bool InternalIsMessageOwnedArena() { return IsMessageOwned(); }
+
+  // Helper typetraits 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.
+  //
+  // is_destructor_skippable<T>::value is true if the message type T has told
+  // the arena that it is safe to skip the destructor, 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 : InternalHelper<T>::is_arena_constructable {};
+  template <typename T>
+  struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
+  };
+
+ private:
+  internal::ThreadSafeArena impl_;
+
+  template <typename T>
+  struct has_get_arena : InternalHelper<T>::has_get_arena {};
+
+  // Constructor solely used by message-owned arena.
+  inline Arena(internal::MessageOwned) : impl_(internal::MessageOwned{}) {}
+
+  // Checks whether this arena is message-owned.
+  PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
+    return impl_.IsMessageOwned();
+  }
+
+  void ReturnArrayMemory(void* p, size_t size) {
+    impl_.ReturnArrayMemory(p, size);
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena,
+                                                         Args&&... args) {
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+    if (arena == NULL) {
+      return new T(nullptr, static_cast<Args&&>(args)...);
+    } else {
+      return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...);
+    }
+  }
+
+  // This specialization for no arguments is necessary, because its behavior is
+  // slightly different.  When the arena pointer is nullptr, it calls T()
+  // instead of T(nullptr).
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena) {
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+    if (arena == NULL) {
+      // Generated arena constructor T(Arena*) is protected. Call via
+      // InternalHelper.
+      return InternalHelper<T>::New();
+    } else {
+      return arena->DoCreateMessage<T>();
+    }
+  }
+
+  // Allocate and also optionally call collector with the allocated type info
+  // when allocation recording is enabled.
+  PROTOBUF_NDEBUG_INLINE void* AllocateInternal(size_t size, size_t align,
+                                                void (*destructor)(void*),
+                                                const std::type_info* type) {
+    // Monitor allocation if needed.
+    if (destructor == nullptr) {
+      return AllocateAlignedWithHook(size, align, type);
+    } else {
+      if (align <= 8) {
+        auto res = AllocateAlignedWithCleanup(internal::AlignUpTo8(size), type);
+        res.second->elem = res.first;
+        res.second->cleanup = destructor;
+        return res.first;
+      } else {
+        auto res = AllocateAlignedWithCleanup(size + align - 8, type);
+        auto ptr = internal::AlignTo(res.first, align);
+        res.second->elem = ptr;
+        res.second->cleanup = destructor;
+        return ptr;
+      }
+    }
+  }
+
+  // CreateMessage<T> requires that T supports arenas, but this private method
+  // works whether or not T supports arenas. These are not exposed to user code
+  // as it can cause confusing API usages, and end up having double free in
+  // user code. These are used only internally from LazyField and Repeated
+  // fields, since they are designed to work in all mode combinations.
+  template <typename Msg, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static Msg* DoCreateMaybeMessage(Arena* arena,
+                                                          std::true_type,
+                                                          Args&&... args) {
+    return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* DoCreateMaybeMessage(Arena* arena,
+                                                        std::false_type,
+                                                        Args&&... args) {
+    return Create<T>(arena, std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateMaybeMessage(Arena* arena,
+                                                      Args&&... args) {
+    return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
+                                   std::forward<Args>(args)...);
+  }
+
+  // Just allocate the required size for the given type assuming the
+  // type has a trivial constructor.
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE T* CreateInternalRawArray(size_t num_elements) {
+    GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
+    // We count on compiler to realize that if sizeof(T) is a multiple of
+    // 8 AlignUpTo can be elided.
+    const size_t n = sizeof(T) * num_elements;
+    return static_cast<T*>(
+        AllocateAlignedWithHookForArray(n, alignof(T), RTTI_TYPE_ID(T)));
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_NDEBUG_INLINE T* DoCreateMessage(Args&&... args) {
+    return InternalHelper<T>::Construct(
+        AllocateInternal(sizeof(T), alignof(T),
+                         internal::ObjectDestructor<
+                             InternalHelper<T>::is_destructor_skippable::value,
+                             T>::destructor,
+                         RTTI_TYPE_ID(T)),
+        this, std::forward<Args>(args)...);
+  }
+
+  // CreateInArenaStorage is used to implement map field. Without it,
+  // Map need to call generated message's protected arena constructor,
+  // which needs to declare Map as friend of generated message.
+  template <typename T, typename... Args>
+  static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) {
+    CreateInArenaStorageInternal(ptr, arena,
+                                 typename is_arena_constructable<T>::type(),
+                                 std::forward<Args>(args)...);
+    if (arena != nullptr) {
+      RegisterDestructorInternal(
+          ptr, arena,
+          typename InternalHelper<T>::is_destructor_skippable::type());
+    }
+  }
+
+  template <typename T, typename... Args>
+  static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
+                                           std::true_type, Args&&... args) {
+    InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...);
+  }
+  template <typename T, typename... Args>
+  static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
+                                           std::false_type, Args&&... args) {
+    new (ptr) T(std::forward<Args>(args)...);
+  }
+
+  template <typename T>
+  static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
+                                         std::true_type) {}
+  template <typename T>
+  static void RegisterDestructorInternal(T* ptr, Arena* arena,
+                                         std::false_type) {
+    arena->OwnDestructor(ptr);
+  }
+
+  // These implement Create(). The second parameter has type 'true_type' if T is
+  // a subtype of Message and 'false_type' otherwise.
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena, std::true_type,
+                                                  Args&&... args) {
+    if (arena == nullptr) {
+      return new T(std::forward<Args>(args)...);
+    } else {
+      auto destructor =
+          internal::ObjectDestructor<std::is_trivially_destructible<T>::value,
+                                     T>::destructor;
+      T* result =
+          new (arena->AllocateInternal(sizeof(T), alignof(T), destructor,
+                                       RTTI_TYPE_ID(T)))
+          T(std::forward<Args>(args)...);
+      return result;
+    }
+  }
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena, std::false_type,
+                                                  Args&&... args) {
+    if (arena == nullptr) {
+      return new T(std::forward<Args>(args)...);
+    } else {
+      auto destructor =
+          internal::ObjectDestructor<std::is_trivially_destructible<T>::value,
+                                     T>::destructor;
+      return new (arena->AllocateInternal(sizeof(T), alignof(T), destructor,
+                                          RTTI_TYPE_ID(T)))
+          T(std::forward<Args>(args)...);
+    }
+  }
+
+  // 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 Message and 'false_type' otherwise. Collapsing
+  // all template instantiations to one for generic Message reduces code size,
+  // using the virtual destructor instead.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::true_type) {
+    if (object != NULL) {
+      impl_.AddCleanup(object, &internal::arena_delete_object<MessageLite>);
+    }
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::false_type) {
+    if (object != NULL) {
+      impl_.AddCleanup(object, &internal::arena_delete_object<T>);
+    }
+  }
+
+  // Implementation for GetArena(). Only message objects with
+  // InternalArenaConstructable_ tags can be associated with an arena, and such
+  // objects must implement a GetArena() method.
+  template <typename T, typename std::enable_if<
+                            is_arena_constructable<T>::value, int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    return InternalHelper<T>::GetArena(value);
+  }
+  template <typename T,
+            typename std::enable_if<!is_arena_constructable<T>::value &&
+                                        has_get_arena<T>::value,
+                                    int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    return value->GetArena();
+  }
+  template <typename T,
+            typename std::enable_if<!is_arena_constructable<T>::value &&
+                                        !has_get_arena<T>::value,
+                                    int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    (void)value;
+    return nullptr;
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetOwningArena(const T* value) {
+    return GetOwningArenaInternal(
+        value, std::is_convertible<T*, MessageLite*>());
+  }
+
+  // Implementation for GetOwningArena(). All and only message objects have
+  // GetOwningArena() method.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetOwningArenaInternal(
+      const T* value, std::true_type) {
+    return InternalHelper<T>::GetOwningArena(value);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetOwningArenaInternal(
+      const T* /* value */, std::false_type) {
+    return nullptr;
+  }
+
+  void* AllocateAlignedWithHookForArray(size_t n, size_t align,
+                                        const std::type_info* type) {
+    if (align <= 8) {
+      return AllocateAlignedWithHookForArray(internal::AlignUpTo8(n), type);
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(
+          AllocateAlignedWithHookForArray(n + align - 8, type), align);
+    }
+  }
+
+  void* AllocateAlignedWithHook(size_t n, size_t align,
+                                const std::type_info* type) {
+    if (align <= 8) {
+      return AllocateAlignedWithHook(internal::AlignUpTo8(n), type);
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(AllocateAlignedWithHook(n + align - 8, type),
+                               align);
+    }
+  }
+
+  void* AllocateAlignedNoHook(size_t n);
+  void* AllocateAlignedWithHook(size_t n, const std::type_info* type);
+  void* AllocateAlignedWithHookForArray(size_t n, const std::type_info* type);
+  std::pair<void*, internal::SerialArena::CleanupNode*>
+  AllocateAlignedWithCleanup(size_t n, const std::type_info* type);
+
+  template <typename Type>
+  friend class internal::GenericTypeHandler;
+  friend class internal::InternalMetadata;  // For user_arena().
+  friend class internal::LazyField;        // For CreateMaybeMessage.
+  friend class internal::EpsCopyInputStream;  // For parser performance
+  friend class MessageLite;
+  template <typename Key, typename T>
+  friend class Map;
+  template <typename>
+  friend class RepeatedField;                   // For ReturnArrayMemory
+  friend class internal::RepeatedPtrFieldBase;  // For ReturnArrayMemory
+  friend struct internal::ArenaTestPeer;
+};
+
+// Defined above for supporting environments without RTTI.
+#undef RTTI_TYPE_ID
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ARENA_H__
diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h
new file mode 100644
index 0000000..7672768
--- /dev/null
+++ b/src/google/protobuf/arena_impl.h
@@ -0,0 +1,686 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 an Arena allocator for better allocation performance.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_IMPL_H__
+#define GOOGLE_PROTOBUF_ARENA_IMPL_H__
+
+#include <atomic>
+#include <limits>
+#include <typeinfo>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/port.h>
+
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif  // ADDRESS_SANITIZER
+
+#include <google/protobuf/arenaz_sampler.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// To prevent sharing cache lines between threads
+#ifdef __cpp_aligned_new
+enum { kCacheAlignment = 64 };
+#else
+enum { kCacheAlignment = alignof(max_align_t) };  // do the best we can
+#endif
+
+inline constexpr size_t AlignUpTo8(size_t n) {
+  // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
+  return (n + 7) & static_cast<size_t>(-8);
+}
+
+using LifecycleIdAtomic = uint64_t;
+
+// MetricsCollector collects stats for a particular arena.
+class PROTOBUF_EXPORT ArenaMetricsCollector {
+ public:
+  ArenaMetricsCollector(bool record_allocs) : record_allocs_(record_allocs) {}
+
+  // Invoked when the arena is about to be destroyed. This method will
+  // typically finalize any metric collection and delete the collector.
+  // space_allocated is the space used by the arena.
+  virtual void OnDestroy(uint64_t space_allocated) = 0;
+
+  // OnReset() is called when the associated arena is reset.
+  // space_allocated is the space used by the arena just before the reset.
+  virtual void OnReset(uint64_t space_allocated) = 0;
+
+  // OnAlloc is called when an allocation happens.
+  // 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)
+  virtual void OnAlloc(const std::type_info* allocated_type,
+                       uint64_t alloc_size) = 0;
+
+  // Does OnAlloc() need to be called?  If false, metric collection overhead
+  // will be reduced since we will not do extra work per allocation.
+  bool RecordAllocs() { return record_allocs_; }
+
+ protected:
+  // This class is destructed by the call to OnDestroy().
+  ~ArenaMetricsCollector() = default;
+  const bool record_allocs_;
+};
+
+struct AllocationPolicy {
+  static constexpr size_t kDefaultStartBlockSize = 256;
+  static constexpr size_t kDefaultMaxBlockSize = 8192;
+
+  size_t start_block_size = kDefaultStartBlockSize;
+  size_t max_block_size = kDefaultMaxBlockSize;
+  void* (*block_alloc)(size_t) = nullptr;
+  void (*block_dealloc)(void*, size_t) = nullptr;
+  ArenaMetricsCollector* metrics_collector = nullptr;
+
+  bool IsDefault() const {
+    return start_block_size == kDefaultMaxBlockSize &&
+           max_block_size == kDefaultMaxBlockSize && block_alloc == nullptr &&
+           block_dealloc == nullptr && metrics_collector == nullptr;
+  }
+};
+
+// Tagged pointer to an AllocationPolicy.
+class TaggedAllocationPolicyPtr {
+ public:
+  constexpr TaggedAllocationPolicyPtr() : policy_(0) {}
+
+  explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy)
+      : policy_(reinterpret_cast<uintptr_t>(policy)) {}
+
+  void set_policy(AllocationPolicy* policy) {
+    auto bits = policy_ & kTagsMask;
+    policy_ = reinterpret_cast<uintptr_t>(policy) | bits;
+  }
+
+  AllocationPolicy* get() {
+    return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask);
+  }
+  const AllocationPolicy* get() const {
+    return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask);
+  }
+
+  AllocationPolicy& operator*() { return *get(); }
+  const AllocationPolicy& operator*() const { return *get(); }
+
+  AllocationPolicy* operator->() { return get(); }
+  const AllocationPolicy* operator->() const { return get(); }
+
+  bool is_user_owned_initial_block() const {
+    return static_cast<bool>(get_mask<kUserOwnedInitialBlock>());
+  }
+  void set_is_user_owned_initial_block(bool v) {
+    set_mask<kUserOwnedInitialBlock>(v);
+  }
+
+  bool should_record_allocs() const {
+    return static_cast<bool>(get_mask<kRecordAllocs>());
+  }
+  void set_should_record_allocs(bool v) { set_mask<kRecordAllocs>(v); }
+
+  uintptr_t get_raw() const { return policy_; }
+
+  inline void RecordAlloc(const std::type_info* allocated_type,
+                          size_t n) const {
+    get()->metrics_collector->OnAlloc(allocated_type, n);
+  }
+
+ private:
+  enum : uintptr_t {
+    kUserOwnedInitialBlock = 1,
+    kRecordAllocs = 2,
+  };
+
+  static constexpr uintptr_t kTagsMask = 7;
+  static constexpr uintptr_t kPtrMask = ~kTagsMask;
+
+  template <uintptr_t kMask>
+  uintptr_t get_mask() const {
+    return policy_ & kMask;
+  }
+  template <uintptr_t kMask>
+  void set_mask(bool v) {
+    if (v) {
+      policy_ |= kMask;
+    } else {
+      policy_ &= ~kMask;
+    }
+  }
+  uintptr_t policy_;
+};
+
+enum class AllocationClient { kDefault, kArray };
+
+// A simple arena allocator. Calls to allocate functions must be properly
+// serialized by the caller, hence this class cannot be used as a general
+// purpose allocator in a multi-threaded program. It serves as a building block
+// for ThreadSafeArena, which provides a thread-safe arena allocator.
+//
+// This class manages
+// 1) Arena bump allocation + owning memory blocks.
+// 2) Maintaining a cleanup list.
+// It delagetes the actual memory allocation back to ThreadSafeArena, which
+// contains the information on block growth policy and backing memory allocation
+// used.
+class PROTOBUF_EXPORT SerialArena {
+ public:
+  struct Memory {
+    void* ptr;
+    size_t size;
+  };
+
+  // Node contains the ptr of the object to be cleaned up and the associated
+  // cleanup function ptr.
+  struct CleanupNode {
+    void* elem;              // Pointer to the object to be cleaned up.
+    void (*cleanup)(void*);  // Function pointer to the destructor or deleter.
+  };
+
+  void CleanupList();
+  uint64_t SpaceAllocated() const {
+    return space_allocated_.load(std::memory_order_relaxed);
+  }
+  uint64_t SpaceUsed() const;
+
+  bool HasSpace(size_t n) const {
+    return n <= static_cast<size_t>(limit_ - ptr_);
+  }
+
+  // See comments on `cached_blocks_` member for details.
+  PROTOBUF_ALWAYS_INLINE void* TryAllocateFromCachedBlock(size_t size) {
+    if (PROTOBUF_PREDICT_FALSE(size < 16)) return nullptr;
+    // We round up to the next larger block in case the memory doesn't match
+    // the pattern we are looking for.
+    const size_t index = Bits::Log2FloorNonZero64(size - 1) - 3;
+
+    if (index >= cached_block_length_) return nullptr;
+    auto& cached_head = cached_blocks_[index];
+    if (cached_head == nullptr) return nullptr;
+
+    void* ret = cached_head;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, size);
+#endif  // ADDRESS_SANITIZER
+    cached_head = cached_head->next;
+    return ret;
+  }
+
+  // In kArray mode we look through cached blocks.
+  // We do not do this by default because most non-array allocations will not
+  // have the right size and will fail to find an appropriate cached block.
+  //
+  // TODO(sbenza): Evaluate if we should use cached blocks for message types of
+  // the right size. We can statically know if the allocation size can benefit
+  // from it.
+  template <AllocationClient alloc_client = AllocationClient::kDefault>
+  void* AllocateAligned(size_t n, const AllocationPolicy* policy) {
+    GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+    GOOGLE_DCHECK_GE(limit_, ptr_);
+
+    if (alloc_client == AllocationClient::kArray) {
+      if (void* res = TryAllocateFromCachedBlock(n)) {
+        return res;
+      }
+    }
+
+    if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) {
+      return AllocateAlignedFallback(n, policy);
+    }
+    return AllocateFromExisting(n);
+  }
+
+ private:
+  void* AllocateFromExisting(size_t n) {
+    void* ret = ptr_;
+    ptr_ += n;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, n);
+#endif  // ADDRESS_SANITIZER
+    return ret;
+  }
+
+  // See comments on `cached_blocks_` member for details.
+  void ReturnArrayMemory(void* p, size_t size) {
+    // We only need to check for 32-bit platforms.
+    // In 64-bit platforms the minimum allocation size from Repeated*Field will
+    // be 16 guaranteed.
+    if (sizeof(void*) < 8) {
+      if (PROTOBUF_PREDICT_FALSE(size < 16)) return;
+    } else {
+      GOOGLE_DCHECK(size >= 16);
+    }
+
+    // We round down to the next smaller block in case the memory doesn't match
+    // the pattern we are looking for. eg, someone might have called Reserve()
+    // on the repeated field.
+    const size_t index = Bits::Log2FloorNonZero64(size) - 4;
+
+    if (PROTOBUF_PREDICT_FALSE(index >= cached_block_length_)) {
+      // We can't put this object on the freelist so make this object the
+      // freelist. It is guaranteed it is larger than the one we have, and
+      // large enough to hold another allocation of `size`.
+      CachedBlock** new_list = static_cast<CachedBlock**>(p);
+      size_t new_size = size / sizeof(CachedBlock*);
+
+      std::copy(cached_blocks_, cached_blocks_ + cached_block_length_,
+                new_list);
+      std::fill(new_list + cached_block_length_, new_list + new_size, nullptr);
+      cached_blocks_ = new_list;
+      // Make the size fit in uint8_t. This is the power of two, so we don't
+      // need anything larger.
+      cached_block_length_ =
+          static_cast<uint8_t>(std::min(size_t{64}, new_size));
+
+      return;
+    }
+
+    auto& cached_head = cached_blocks_[index];
+    auto* new_node = static_cast<CachedBlock*>(p);
+    new_node->next = cached_head;
+    cached_head = new_node;
+#ifdef ADDRESS_SANITIZER
+    ASAN_POISON_MEMORY_REGION(p, size);
+#endif  // ADDRESS_SANITIZER
+  }
+
+ public:
+  // Allocate space if the current region provides enough space.
+  bool MaybeAllocateAligned(size_t n, void** out) {
+    GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+    GOOGLE_DCHECK_GE(limit_, ptr_);
+    if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) return false;
+    *out = AllocateFromExisting(n);
+    return true;
+  }
+
+  std::pair<void*, CleanupNode*> AllocateAlignedWithCleanup(
+      size_t n, const AllocationPolicy* policy) {
+    GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+    if (PROTOBUF_PREDICT_FALSE(!HasSpace(n + kCleanupSize))) {
+      return AllocateAlignedWithCleanupFallback(n, policy);
+    }
+    return AllocateFromExistingWithCleanupFallback(n);
+  }
+
+ private:
+  std::pair<void*, CleanupNode*> AllocateFromExistingWithCleanupFallback(
+      size_t n) {
+    void* ret = ptr_;
+    ptr_ += n;
+    limit_ -= kCleanupSize;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, n);
+    ASAN_UNPOISON_MEMORY_REGION(limit_, kCleanupSize);
+#endif  // ADDRESS_SANITIZER
+    return CreatePair(ret, reinterpret_cast<CleanupNode*>(limit_));
+  }
+
+ public:
+  void AddCleanup(void* elem, void (*cleanup)(void*),
+                  const AllocationPolicy* policy) {
+    auto res = AllocateAlignedWithCleanup(0, policy);
+    res.second->elem = elem;
+    res.second->cleanup = cleanup;
+  }
+
+  void* owner() const { return owner_; }
+  SerialArena* next() const { return next_; }
+  void set_next(SerialArena* next) { next_ = next; }
+
+ private:
+  friend class ThreadSafeArena;
+  friend class ArenaBenchmark;
+
+  // Creates a new SerialArena inside mem using the remaining memory as for
+  // future allocations.
+  static SerialArena* New(SerialArena::Memory mem, void* owner,
+                          ThreadSafeArenaStats* stats);
+  // Free SerialArena returning the memory passed in to New
+  template <typename Deallocator>
+  Memory Free(Deallocator deallocator);
+
+  // Blocks are variable length malloc-ed objects.  The following structure
+  // describes the common header for all blocks.
+  struct Block {
+    Block(Block* next, size_t size) : next(next), size(size), start(nullptr) {}
+
+    char* Pointer(size_t n) {
+      GOOGLE_DCHECK(n <= size);
+      return reinterpret_cast<char*>(this) + n;
+    }
+
+    Block* const next;
+    const size_t size;
+    CleanupNode* start;
+    // data follows
+  };
+
+  void* owner_;            // &ThreadCache of this thread;
+  Block* head_;            // Head of linked list of blocks.
+  SerialArena* next_;      // Next SerialArena in this linked list.
+  size_t space_used_ = 0;  // Necessary for metrics.
+  std::atomic<size_t> space_allocated_;
+
+  // Next pointer to allocate from.  Always 8-byte aligned.  Points inside
+  // head_ (and head_->pos will always be non-canonical).  We keep these
+  // here to reduce indirection.
+  char* ptr_;
+  // Limiting address up to which memory can be allocated from the head block.
+  char* limit_;
+  // For holding sampling information.  The pointer is owned by the
+  // ThreadSafeArena that holds this serial arena.
+  ThreadSafeArenaStats* arena_stats_;
+
+  // Repeated*Field and Arena play together to reduce memory consumption by
+  // reusing blocks. Currently, natural growth of the repeated field types makes
+  // them allocate blocks of size `8 + 2^N, N>=3`.
+  // When the repeated field grows returns the previous block and we put it in
+  // this free list.
+  // `cached_blocks_[i]` points to the free list for blocks of size `8+2^(i+3)`.
+  // The array of freelists is grown when needed in `ReturnArrayMemory()`.
+  struct CachedBlock {
+    // Simple linked list.
+    CachedBlock* next;
+  };
+  uint8_t cached_block_length_ = 0;
+  CachedBlock** cached_blocks_ = nullptr;
+
+  // Constructor is private as only New() should be used.
+  inline SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats);
+  void* AllocateAlignedFallback(size_t n, const AllocationPolicy* policy);
+  std::pair<void*, CleanupNode*> AllocateAlignedWithCleanupFallback(
+      size_t n, const AllocationPolicy* policy);
+  void AllocateNewBlock(size_t n, const AllocationPolicy* policy);
+
+  std::pair<void*, CleanupNode*> CreatePair(void* ptr, CleanupNode* node) {
+    return {ptr, node};
+  }
+
+ public:
+  static constexpr size_t kBlockHeaderSize = AlignUpTo8(sizeof(Block));
+  static constexpr size_t kCleanupSize = AlignUpTo8(sizeof(CleanupNode));
+};
+
+// Tag type used to invoke the constructor of message-owned arena.
+// Only message-owned arenas use this constructor for creation.
+// Such constructors are internal implementation details of the library.
+struct MessageOwned {
+  explicit MessageOwned() = default;
+};
+
+// This class provides the core Arena memory allocation library. Different
+// implementations only need to implement the public interface below.
+// Arena is not a template type as that would only be useful if all protos
+// in turn would be templates, which will/cannot happen. However separating
+// the memory allocation part from the cruft of the API users expect we can
+// use #ifdef the select the best implementation based on hardware / OS.
+class PROTOBUF_EXPORT ThreadSafeArena {
+ public:
+  ThreadSafeArena() { Init(); }
+
+  // Constructor solely used by message-owned arena.
+  ThreadSafeArena(internal::MessageOwned) : tag_and_id_(kMessageOwnedArena) {
+    Init();
+  }
+
+  ThreadSafeArena(char* mem, size_t size) { InitializeFrom(mem, size); }
+
+  explicit ThreadSafeArena(void* mem, size_t size,
+                           const AllocationPolicy& policy) {
+    InitializeWithPolicy(mem, size, policy);
+  }
+
+  // Destructor deletes all owned heap allocated objects, and destructs objects
+  // that have non-trivial destructors, except for proto2 message objects whose
+  // destructors can be skipped. Also, frees all blocks except the initial block
+  // if it was passed in.
+  ~ThreadSafeArena();
+
+  uint64_t Reset();
+
+  uint64_t SpaceAllocated() const;
+  uint64_t SpaceUsed() const;
+
+  template <AllocationClient alloc_client = AllocationClient::kDefault>
+  void* AllocateAligned(size_t n, const std::type_info* type) {
+    SerialArena* arena;
+    if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
+                              GetSerialArenaFast(&arena))) {
+      return arena->AllocateAligned<alloc_client>(n, AllocPolicy());
+    } else {
+      return AllocateAlignedFallback(n, type);
+    }
+  }
+
+  void ReturnArrayMemory(void* p, size_t size) {
+    SerialArena* arena;
+    if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+      arena->ReturnArrayMemory(p, size);
+    }
+  }
+
+  // This function allocates n bytes if the common happy case is true and
+  // returns true. Otherwise does nothing and returns false. This strange
+  // semantics is necessary to allow callers to program functions that only
+  // have fallback function calls in tail position. This substantially improves
+  // code for the happy path.
+  PROTOBUF_NDEBUG_INLINE bool MaybeAllocateAligned(size_t n, void** out) {
+    SerialArena* arena;
+    if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
+                              GetSerialArenaFromThreadCache(&arena))) {
+      return arena->MaybeAllocateAligned(n, out);
+    }
+    return false;
+  }
+
+  std::pair<void*, SerialArena::CleanupNode*> AllocateAlignedWithCleanup(
+      size_t n, const std::type_info* type);
+
+  // Add object pointer and cleanup function pointer to the list.
+  void AddCleanup(void* elem, void (*cleanup)(void*));
+
+  // Checks whether this arena is message-owned.
+  PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
+    return tag_and_id_ & kMessageOwnedArena;
+  }
+
+ private:
+  // Unique for each arena. Changes on Reset().
+  uint64_t tag_and_id_ = 0;
+  // The LSB of tag_and_id_ indicates if the arena is message-owned.
+  enum : uint64_t { kMessageOwnedArena = 1 };
+
+  TaggedAllocationPolicyPtr alloc_policy_;  // Tagged pointer to AllocPolicy.
+
+  static_assert(std::is_trivially_destructible<SerialArena>{},
+                "SerialArena needs to be trivially destructible.");
+  // Pointer to a linked list of SerialArena.
+  std::atomic<SerialArena*> threads_;
+  std::atomic<SerialArena*> hint_;  // Fast thread-local block access
+
+  const AllocationPolicy* AllocPolicy() const { return alloc_policy_.get(); }
+  void InitializeFrom(void* mem, size_t size);
+  void InitializeWithPolicy(void* mem, size_t size, AllocationPolicy policy);
+  void* AllocateAlignedFallback(size_t n, const std::type_info* type);
+  std::pair<void*, SerialArena::CleanupNode*>
+  AllocateAlignedWithCleanupFallback(size_t n, const std::type_info* type);
+
+  void Init();
+  void SetInitialBlock(void* mem, size_t size);
+
+  // Delete or Destruct all objects owned by the arena.
+  void CleanupList();
+
+  inline uint64_t LifeCycleId() const {
+    return tag_and_id_ & ~kMessageOwnedArena;
+  }
+
+  inline void CacheSerialArena(SerialArena* serial) {
+    thread_cache().last_serial_arena = serial;
+    thread_cache().last_lifecycle_id_seen = tag_and_id_;
+    // TODO(haberman): evaluate whether we would gain efficiency by getting rid
+    // of hint_.  It's the only write we do to ThreadSafeArena in the allocation
+    // path, which will dirty the cache line.
+
+    hint_.store(serial, std::memory_order_release);
+  }
+
+  PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(SerialArena** arena) {
+    if (GetSerialArenaFromThreadCache(arena)) return true;
+
+    // Check whether we own the last accessed SerialArena on this arena.  This
+    // fast path optimizes the case where a single thread uses multiple arenas.
+    ThreadCache* tc = &thread_cache();
+    SerialArena* serial = hint_.load(std::memory_order_acquire);
+    if (PROTOBUF_PREDICT_TRUE(serial != nullptr && serial->owner() == tc)) {
+      *arena = serial;
+      return true;
+    }
+    return false;
+  }
+
+  PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFromThreadCache(
+      SerialArena** arena) {
+    // 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.
+    ThreadCache* tc = &thread_cache();
+    if (PROTOBUF_PREDICT_TRUE(tc->last_lifecycle_id_seen == tag_and_id_)) {
+      *arena = tc->last_serial_arena;
+      return true;
+    }
+    return false;
+  }
+  SerialArena* GetSerialArenaFallback(void* me);
+
+  template <typename Functor>
+  void PerSerialArena(Functor fn) {
+    // By omitting an Acquire barrier we ensure that any user code that doesn't
+    // properly synchronize Reset() or the destructor will throw a TSAN warning.
+    SerialArena* serial = threads_.load(std::memory_order_relaxed);
+
+    for (; serial; serial = serial->next()) fn(serial);
+  }
+
+  // Releases all memory except the first block which it returns. The first
+  // block might be owned by the user and thus need some extra checks before
+  // deleting.
+  SerialArena::Memory Free(size_t* space_allocated);
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4324)
+#endif
+  struct alignas(kCacheAlignment) ThreadCache {
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+    // If we are using the ThreadLocalStorage class to store the ThreadCache,
+    // then the ThreadCache's default constructor has to be responsible for
+    // initializing it.
+    ThreadCache()
+        : next_lifecycle_id(0),
+          last_lifecycle_id_seen(-1),
+          last_serial_arena(nullptr) {}
+#endif
+
+    // Number of per-thread lifecycle IDs to reserve. Must be power of two.
+    // To reduce contention on a global atomic, each thread reserves a batch of
+    // IDs.  The following number is calculated based on a stress test with
+    // ~6500 threads all frequently allocating a new arena.
+    static constexpr size_t kPerThreadIds = 256;
+    // Next lifecycle ID available to this thread. We need to reserve a new
+    // batch, if `next_lifecycle_id & (kPerThreadIds - 1) == 0`.
+    uint64_t next_lifecycle_id;
+    // The ThreadCache is considered valid as long as this matches the
+    // lifecycle_id of the arena being used.
+    uint64_t last_lifecycle_id_seen;
+    SerialArena* last_serial_arena;
+  };
+
+  // Lifecycle_id can be highly contended variable in a situation of lots of
+  // arena creation. Make sure that other global variables are not sharing the
+  // cacheline.
+#ifdef _MSC_VER
+#pragma warning(disable : 4324)
+#endif
+  struct alignas(kCacheAlignment) CacheAlignedLifecycleIdGenerator {
+    std::atomic<LifecycleIdAtomic> id;
+  };
+  static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_;
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+  // iOS does not support __thread keyword so we use a custom thread local
+  // storage class we implemented.
+  static ThreadCache& thread_cache();
+#elif defined(PROTOBUF_USE_DLLS)
+  // Thread local variables cannot be exposed through DLL interface but we can
+  // wrap them in static functions.
+  static ThreadCache& thread_cache();
+#else
+  static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_;
+  static ThreadCache& thread_cache() { return thread_cache_; }
+#endif
+
+  ThreadSafeArenaStatsHandle arena_stats_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadSafeArena);
+  // All protos have pointers back to the arena hence Arena must have
+  // pointer stability.
+  ThreadSafeArena(ThreadSafeArena&&) = delete;
+  ThreadSafeArena& operator=(ThreadSafeArena&&) = delete;
+
+ public:
+  // kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
+  // to protect the invariant that pos is always at a multiple of 8.
+  static constexpr size_t kBlockHeaderSize = SerialArena::kBlockHeaderSize;
+  static constexpr size_t kSerialArenaSize =
+      (sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
+  static_assert(kBlockHeaderSize % 8 == 0,
+                "kBlockHeaderSize must be a multiple of 8.");
+  static_assert(kSerialArenaSize % 8 == 0,
+                "kSerialArenaSize must be a multiple of 8.");
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ARENA_IMPL_H__
diff --git a/src/google/protobuf/arena_test_util.cc b/src/google/protobuf/arena_test_util.cc
new file mode 100644
index 0000000..2cb5075
--- /dev/null
+++ b/src/google/protobuf/arena_test_util.cc
@@ -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.
+
+#include <google/protobuf/arena_test_util.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+NoHeapChecker::~NoHeapChecker() {
+  capture_alloc.Unhook();
+  EXPECT_EQ(0, capture_alloc.alloc_count());
+  EXPECT_EQ(0, capture_alloc.free_count());
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h
new file mode 100644
index 0000000..6e42d4b
--- /dev/null
+++ b/src/google/protobuf/arena_test_util.h
@@ -0,0 +1,132 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+namespace google {
+namespace protobuf {
+
+template <typename T, bool use_arena>
+void TestParseCorruptedString(const T& message) {
+  int success_count = 0;
+  std::string s;
+  {
+    // Map order is not deterministic. To make the test deterministic we want
+    // to serialize the proto deterministically.
+    io::StringOutputStream output(&s);
+    io::CodedOutputStream out(&output);
+    out.SetSerializationDeterministic(true);
+    message.SerializePartialToCodedStream(&out);
+  }
+  const int kMaxIters = 900;
+  const int stride = s.size() <= kMaxIters ? 1 : s.size() / kMaxIters;
+  const int start = stride == 1 || use_arena ? 0 : (stride + 1) / 2;
+  for (int i = start; i < s.size(); i += stride) {
+    for (int c = 1 + (i % 17); c < 256; c += 2 * c + (i & 3)) {
+      s[i] ^= c;
+      Arena arena;
+      T* message = Arena::CreateMessage<T>(use_arena ? &arena : nullptr);
+      if (message->ParseFromString(s)) {
+        ++success_count;
+      }
+      if (!use_arena) {
+        delete message;
+      }
+      s[i] ^= c;  // Restore s to its original state.
+    }
+  }
+  // This next line is a low bar.  But getting through the test without crashing
+  // due to use-after-free or other bugs is a big part of what we're checking.
+  GOOGLE_CHECK_GT(success_count, 0);
+}
+
+namespace internal {
+
+struct ArenaTestPeer {
+  static void ReturnArrayMemory(Arena* arena, void* p, size_t size) {
+    arena->ReturnArrayMemory(p, size);
+  }
+};
+
+class NoHeapChecker {
+ public:
+  NoHeapChecker() { capture_alloc.Hook(); }
+  ~NoHeapChecker();
+
+ private:
+  class NewDeleteCapture {
+   public:
+    // TODO(xiaofeng): Implement this for opensource protobuf.
+    void Hook() {}
+    void Unhook() {}
+    int alloc_count() { return 0; }
+    int free_count() { return 0; }
+  } capture_alloc;
+};
+
+// Owns the internal T only if it's not owned by an arena.
+// T needs to be arena constructible and destructor skippable.
+template <typename T>
+class ArenaHolder {
+ public:
+  explicit ArenaHolder(Arena* arena)
+      : field_(Arena::CreateMessage<T>(arena)),
+        owned_by_arena_(arena != nullptr) {
+    GOOGLE_DCHECK(google::protobuf::Arena::is_arena_constructable<T>::value);
+    GOOGLE_DCHECK(google::protobuf::Arena::is_destructor_skippable<T>::value);
+  }
+
+  ~ArenaHolder() {
+    if (!owned_by_arena_) {
+      delete field_;
+    }
+  }
+
+  T* get() { return field_; }
+  T* operator->() { return field_; }
+  T& operator*() { return *field_; }
+
+ private:
+  T* field_;
+  bool owned_by_arena_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
new file mode 100644
index 0000000..7539b4b
--- /dev/null
+++ b/src/google/protobuf/arena_unittest.cc
@@ -0,0 +1,1634 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arena.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <typeinfo>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_arena.pb.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+
+
+// Must be included last
+#include <google/protobuf/port_def.inc>
+
+using proto2_arena_unittest::ArenaMessage;
+using protobuf_unittest::ForeignMessage;
+using protobuf_unittest::TestAllExtensions;
+using protobuf_unittest::TestAllTypes;
+using protobuf_unittest::TestEmptyMessage;
+using protobuf_unittest::TestOneof2;
+
+namespace google {
+namespace protobuf {
+
+class Notifier {
+ public:
+  Notifier() : count_(0) {}
+  void Notify() { count_++; }
+  int GetCount() { return count_; }
+
+ private:
+  int count_;
+};
+
+class SimpleDataType {
+ public:
+  SimpleDataType() : notifier_(NULL) {}
+  void SetNotifier(Notifier* notifier) { notifier_ = notifier; }
+  virtual ~SimpleDataType() {
+    if (notifier_ != NULL) {
+      notifier_->Notify();
+    }
+  };
+
+ private:
+  Notifier* notifier_;
+};
+
+// A simple class that does not allow copying and so cannot be used as a
+// parameter type without "const &".
+class PleaseDontCopyMe {
+ public:
+  explicit PleaseDontCopyMe(int value) : value_(value) {}
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PleaseDontCopyMe);
+};
+
+// A class that takes four different types as constructor arguments.
+class MustBeConstructedWithOneThroughFour {
+ public:
+  MustBeConstructedWithOneThroughFour(int one, const char* two,
+                                      const std::string& three,
+                                      const PleaseDontCopyMe* four)
+      : one_(one), two_(two), three_(three), four_(four) {}
+
+  int one_;
+  const char* const two_;
+  std::string three_;
+  const PleaseDontCopyMe* four_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughFour);
+};
+
+// A class that takes eight different types as constructor arguments.
+class MustBeConstructedWithOneThroughEight {
+ public:
+  MustBeConstructedWithOneThroughEight(int one, const char* two,
+                                       const std::string& three,
+                                       const PleaseDontCopyMe* four, int five,
+                                       const char* six,
+                                       const std::string& seven,
+                                       const std::string& eight)
+      : one_(one),
+        two_(two),
+        three_(three),
+        four_(four),
+        five_(five),
+        six_(six),
+        seven_(seven),
+        eight_(eight) {}
+
+  int one_;
+  const char* const two_;
+  std::string three_;
+  const PleaseDontCopyMe* four_;
+  int five_;
+  const char* const six_;
+  std::string seven_;
+  std::string eight_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughEight);
+};
+
+TEST(ArenaTest, ArenaConstructable) {
+  EXPECT_TRUE(Arena::is_arena_constructable<TestAllTypes>::type::value);
+  EXPECT_TRUE(Arena::is_arena_constructable<const TestAllTypes>::type::value);
+  EXPECT_FALSE(Arena::is_arena_constructable<Arena>::type::value);
+}
+
+TEST(ArenaTest, DestructorSkippable) {
+  EXPECT_TRUE(Arena::is_destructor_skippable<TestAllTypes>::type::value);
+  EXPECT_TRUE(Arena::is_destructor_skippable<const TestAllTypes>::type::value);
+  EXPECT_FALSE(Arena::is_destructor_skippable<Arena>::type::value);
+}
+
+TEST(ArenaTest, BasicCreate) {
+  Arena arena;
+  EXPECT_TRUE(Arena::Create<int32_t>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<int64_t>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<float>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<double>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<std::string>(&arena) != NULL);
+  arena.Own(new int32_t);
+  arena.Own(new int64_t);
+  arena.Own(new float);
+  arena.Own(new double);
+  arena.Own(new std::string);
+  arena.Own<int>(NULL);
+  Notifier notifier;
+  SimpleDataType* data = Arena::Create<SimpleDataType>(&arena);
+  data->SetNotifier(&notifier);
+  data = new SimpleDataType;
+  data->SetNotifier(&notifier);
+  arena.Own(data);
+  arena.Reset();
+  EXPECT_EQ(2, notifier.GetCount());
+}
+
+TEST(ArenaTest, CreateAndConstCopy) {
+  Arena arena;
+  const std::string s("foo");
+  const std::string* s_copy = Arena::Create<std::string>(&arena, s);
+  EXPECT_TRUE(s_copy != NULL);
+  EXPECT_EQ("foo", s);
+  EXPECT_EQ("foo", *s_copy);
+}
+
+TEST(ArenaTest, CreateAndNonConstCopy) {
+  Arena arena;
+  std::string s("foo");
+  const std::string* s_copy = Arena::Create<std::string>(&arena, s);
+  EXPECT_TRUE(s_copy != NULL);
+  EXPECT_EQ("foo", s);
+  EXPECT_EQ("foo", *s_copy);
+}
+
+TEST(ArenaTest, CreateAndMove) {
+  Arena arena;
+  std::string s("foo");
+  const std::string* s_move = Arena::Create<std::string>(&arena, std::move(s));
+  EXPECT_TRUE(s_move != NULL);
+  EXPECT_TRUE(s.empty());  // NOLINT
+  EXPECT_EQ("foo", *s_move);
+}
+
+TEST(ArenaTest, CreateWithFourConstructorArguments) {
+  Arena arena;
+  const std::string three("3");
+  const PleaseDontCopyMe four(4);
+  const MustBeConstructedWithOneThroughFour* new_object =
+      Arena::Create<MustBeConstructedWithOneThroughFour>(&arena, 1, "2", three,
+                                                         &four);
+  EXPECT_TRUE(new_object != NULL);
+  ASSERT_EQ(1, new_object->one_);
+  ASSERT_STREQ("2", new_object->two_);
+  ASSERT_EQ("3", new_object->three_);
+  ASSERT_EQ(4, new_object->four_->value());
+}
+
+TEST(ArenaTest, CreateWithEightConstructorArguments) {
+  Arena arena;
+  const std::string three("3");
+  const PleaseDontCopyMe four(4);
+  const std::string seven("7");
+  const std::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_);
+}
+
+class PleaseMoveMe {
+ public:
+  explicit PleaseMoveMe(const std::string& value) : value_(value) {}
+  PleaseMoveMe(PleaseMoveMe&&) = default;
+  PleaseMoveMe(const PleaseMoveMe&) = delete;
+
+  const std::string& value() const { return value_; }
+
+ private:
+  std::string value_;
+};
+
+TEST(ArenaTest, CreateWithMoveArguments) {
+  Arena arena;
+  PleaseMoveMe one("1");
+  const PleaseMoveMe* new_object =
+      Arena::Create<PleaseMoveMe>(&arena, std::move(one));
+  EXPECT_TRUE(new_object);
+  ASSERT_EQ("1", new_object->value());
+}
+
+TEST(ArenaTest, InitialBlockTooSmall) {
+  // Construct a small blocks of memory to be used by the arena allocator; then,
+  // allocate an object which will not fit in the initial block.
+  for (int size = 0; size <= Arena::kBlockOverhead + 32; size++) {
+    std::vector<char> arena_block(size);
+    ArenaOptions options;
+    options.initial_block = arena_block.data();
+    options.initial_block_size = arena_block.size();
+
+    // Try sometimes with non-default block sizes so that we exercise paths
+    // with and without ArenaImpl::Options.
+    if ((size % 2) != 0) {
+      options.start_block_size += 8;
+    }
+
+    Arena arena(options);
+
+    char* p = Arena::CreateArray<char>(&arena, 96);
+    uintptr_t allocation = reinterpret_cast<uintptr_t>(p);
+
+    // Ensure that the arena allocator did not return memory pointing into the
+    // initial block of memory.
+    uintptr_t arena_start = reinterpret_cast<uintptr_t>(arena_block.data());
+    uintptr_t arena_end = arena_start + arena_block.size();
+    EXPECT_FALSE(allocation >= arena_start && allocation < arena_end);
+
+    // Write to the memory we allocated; this should (but is not guaranteed to)
+    // trigger a check for heap corruption if the object was allocated from the
+    // initially-provided block.
+    memset(p, '\0', 96);
+  }
+}
+
+TEST(ArenaTest, Parsing) {
+  TestAllTypes original;
+  TestUtil::SetAllFields(&original);
+
+  // Test memory leak.
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  TestUtil::ExpectAllFieldsSet(*arena_message);
+
+  // Test that string fields have nul terminator bytes (earlier bug).
+  EXPECT_EQ(strlen(original.optional_string().c_str()),
+            strlen(arena_message->optional_string().c_str()));
+}
+
+TEST(ArenaTest, UnknownFields) {
+  TestAllTypes original;
+  TestUtil::SetAllFields(&original);
+
+  // Test basic parsing into (populating) and reading out of unknown fields on
+  // an arena.
+  Arena arena;
+  TestEmptyMessage* arena_message =
+      Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+
+  TestAllTypes copied;
+  copied.ParseFromString(arena_message->SerializeAsString());
+  TestUtil::ExpectAllFieldsSet(copied);
+
+  // Exercise UFS manual manipulation (setters).
+  arena_message = Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message->mutable_unknown_fields()->AddVarint(
+      TestAllTypes::kOptionalInt32FieldNumber, 42);
+  copied.Clear();
+  copied.ParseFromString(arena_message->SerializeAsString());
+  EXPECT_TRUE(copied.has_optional_int32());
+  EXPECT_EQ(42, copied.optional_int32());
+
+  // Exercise UFS swap path.
+  TestEmptyMessage* arena_message_2 =
+      Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message_2->Swap(arena_message);
+  copied.Clear();
+  copied.ParseFromString(arena_message_2->SerializeAsString());
+  EXPECT_TRUE(copied.has_optional_int32());
+  EXPECT_EQ(42, copied.optional_int32());
+
+  // Test field manipulation.
+  TestEmptyMessage* arena_message_3 =
+      Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message_3->mutable_unknown_fields()->AddVarint(1000, 42);
+  arena_message_3->mutable_unknown_fields()->AddFixed32(1001, 42);
+  arena_message_3->mutable_unknown_fields()->AddFixed64(1002, 42);
+  arena_message_3->mutable_unknown_fields()->AddLengthDelimited(1003);
+  arena_message_3->mutable_unknown_fields()->DeleteSubrange(0, 2);
+  arena_message_3->mutable_unknown_fields()->DeleteByNumber(1002);
+  arena_message_3->mutable_unknown_fields()->DeleteByNumber(1003);
+  EXPECT_TRUE(arena_message_3->unknown_fields().empty());
+}
+
+TEST(ArenaTest, Swap) {
+  Arena arena1;
+  Arena arena2;
+  TestAllTypes* arena1_message;
+  TestAllTypes* arena2_message;
+
+  // Case 1: Swap(), no UFS on either message, both messages on different
+  // arenas. Arena pointers should remain the same after swap.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+
+  // Case 2: Swap(), UFS on one message, both messages on different arenas.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->mutable_unknown_fields()->AddVarint(1, 42);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  EXPECT_EQ(0, arena1_message->unknown_fields().field_count());
+  EXPECT_EQ(1, arena2_message->unknown_fields().field_count());
+  EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint());
+
+  // Case 3: Swap(), UFS on both messages, both messages on different arenas.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->mutable_unknown_fields()->AddVarint(1, 42);
+  arena2_message->mutable_unknown_fields()->AddVarint(2, 84);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  EXPECT_EQ(1, arena1_message->unknown_fields().field_count());
+  EXPECT_EQ(1, arena2_message->unknown_fields().field_count());
+  EXPECT_EQ(84, arena1_message->unknown_fields().field(0).varint());
+  EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint());
+}
+
+TEST(ArenaTest, ReflectionSwapFields) {
+  Arena arena1;
+  Arena arena2;
+  TestAllTypes* arena1_message;
+  TestAllTypes* arena2_message;
+
+  // Case 1: messages on different arenas, only one message is set.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  TestUtil::SetAllFields(arena1_message);
+  const Reflection* reflection = arena1_message->GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*arena1_message, &fields);
+  reflection->SwapFields(arena1_message, arena2_message, fields);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  std::string output;
+  arena1_message->SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+  TestUtil::ExpectAllFieldsSet(*arena2_message);
+  reflection->SwapFields(arena1_message, arena2_message, fields);
+  arena2_message->SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+
+  // Case 2: messages on different arenas, both messages are set.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  TestUtil::SetAllFields(arena1_message);
+  TestUtil::SetAllFields(arena2_message);
+  reflection->SwapFields(arena1_message, arena2_message, fields);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+  TestUtil::ExpectAllFieldsSet(*arena2_message);
+
+  // Case 3: messages on different arenas with different lifetimes.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena3;
+    TestAllTypes* arena3_message = Arena::CreateMessage<TestAllTypes>(&arena3);
+    TestUtil::SetAllFields(arena3_message);
+    reflection->SwapFields(arena1_message, arena3_message, fields);
+  }
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+
+  // Case 4: one message on arena, the other on heap.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes message;
+  TestUtil::SetAllFields(arena1_message);
+  reflection->SwapFields(arena1_message, &message, fields);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(nullptr, message.GetArena());
+  arena1_message->SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(ArenaTest, SetAllocatedMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
+  nested->set_bb(118);
+  arena_message->set_allocated_optional_nested_message(nested);
+  EXPECT_EQ(118, arena_message->optional_nested_message().bb());
+}
+
+TEST(ArenaTest, ReleaseMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  std::unique_ptr<TestAllTypes::NestedMessage> nested(
+      arena_message->release_optional_nested_message());
+  EXPECT_EQ(118, nested->bb());
+
+  TestAllTypes::NestedMessage* released_null =
+      arena_message->release_optional_nested_message();
+  EXPECT_EQ(NULL, released_null);
+}
+
+TEST(ArenaTest, SetAllocatedString) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  std::string* allocated_str = new std::string("hello");
+  arena_message->set_allocated_optional_string(allocated_str);
+  EXPECT_EQ("hello", arena_message->optional_string());
+}
+
+TEST(ArenaTest, ReleaseString) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->set_optional_string("hello");
+  std::unique_ptr<std::string> released_str(
+      arena_message->release_optional_string());
+  EXPECT_EQ("hello", *released_str);
+
+  // Test default value.
+}
+
+
+TEST(ArenaTest, SwapBetweenArenasWithAllFieldsSet) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    arena2_message->Swap(arena1_message);
+    std::string output;
+    arena2_message->SerializeToString(&output);
+    EXPECT_EQ(0, output.size());
+  }
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+}
+
+TEST(ArenaTest, SwapBetweenArenaAndNonArenaWithAllFieldsSet) {
+  TestAllTypes non_arena_message;
+  TestUtil::SetAllFields(&non_arena_message);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    arena2_message->Swap(&non_arena_message);
+    TestUtil::ExpectAllFieldsSet(*arena2_message);
+    TestUtil::ExpectAllFieldsSet(non_arena_message);
+  }
+}
+
+TEST(ArenaTest, UnsafeArenaSwap) {
+  Arena shared_arena;
+  TestAllTypes* message1 = Arena::CreateMessage<TestAllTypes>(&shared_arena);
+  TestAllTypes* message2 = Arena::CreateMessage<TestAllTypes>(&shared_arena);
+  TestUtil::SetAllFields(message1);
+  message1->UnsafeArenaSwap(message2);
+  TestUtil::ExpectAllFieldsSet(*message2);
+}
+
+TEST(ArenaTest, GetOwningArena) {
+  Arena arena;
+  auto* m1 = Arena::CreateMessage<TestAllTypes>(&arena);
+  EXPECT_EQ(Arena::InternalGetOwningArena(m1), &arena);
+  EXPECT_EQ(&arena, Arena::InternalGetOwningArena(
+                        m1->mutable_repeated_foreign_message()));
+  EXPECT_EQ(&arena,
+            Arena::InternalGetOwningArena(m1->mutable_repeated_int32()));
+}
+
+TEST(ArenaTest, SwapBetweenArenasUsingReflection) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    const Reflection* r = arena2_message->GetReflection();
+    r->Swap(arena1_message, arena2_message);
+    std::string output;
+    arena2_message->SerializeToString(&output);
+    EXPECT_EQ(0, output.size());
+  }
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+}
+
+TEST(ArenaTest, SwapBetweenArenaAndNonArenaUsingReflection) {
+  TestAllTypes non_arena_message;
+  TestUtil::SetAllFields(&non_arena_message);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    const Reflection* r = arena2_message->GetReflection();
+    r->Swap(&non_arena_message, arena2_message);
+    TestUtil::ExpectAllFieldsSet(*arena2_message);
+    TestUtil::ExpectAllFieldsSet(non_arena_message);
+  }
+}
+
+TEST(ArenaTest, ReleaseFromArenaMessageMakesCopy) {
+  TestAllTypes::NestedMessage* nested_msg = NULL;
+  std::string* nested_string = NULL;
+  {
+    Arena arena;
+    TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+    arena_message->mutable_optional_nested_message()->set_bb(42);
+    *arena_message->mutable_optional_string() = "Hello";
+    nested_msg = arena_message->release_optional_nested_message();
+    nested_string = arena_message->release_optional_string();
+  }
+  EXPECT_EQ(42, nested_msg->bb());
+  EXPECT_EQ("Hello", *nested_string);
+  delete nested_msg;
+  delete nested_string;
+}
+
+#if PROTOBUF_RTTI
+TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) {
+  TestAllTypes::NestedMessage* nested_msg = NULL;
+  // Note: no string: reflection API only supports releasing submessages.
+  {
+    Arena arena;
+    TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+    arena_message->mutable_optional_nested_message()->set_bb(42);
+    const Reflection* r = arena_message->GetReflection();
+    const FieldDescriptor* f = arena_message->GetDescriptor()->FindFieldByName(
+        "optional_nested_message");
+    nested_msg = static_cast<TestAllTypes::NestedMessage*>(
+        r->ReleaseMessage(arena_message, f));
+  }
+  EXPECT_EQ(42, nested_msg->bb());
+  delete nested_msg;
+}
+#endif  // PROTOBUF_RTTI
+
+TEST(ArenaTest, SetAllocatedAcrossArenas) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes::NestedMessage* heap_submessage =
+      new TestAllTypes::NestedMessage();
+  heap_submessage->set_bb(42);
+  arena1_message->set_allocated_optional_nested_message(heap_submessage);
+  // Should keep same object and add to arena's Own()-list.
+  EXPECT_EQ(heap_submessage, arena1_message->mutable_optional_nested_message());
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+#ifdef PROTOBUF_HAS_DEATH_TEST
+    EXPECT_DEBUG_DEATH(arena1_message->set_allocated_optional_nested_message(
+                           arena2_submessage),
+                       "submessage_arena");
+#endif
+    EXPECT_NE(arena2_submessage,
+              arena1_message->mutable_optional_nested_message());
+  }
+
+  TestAllTypes::NestedMessage* arena1_submessage =
+      Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
+  arena1_submessage->set_bb(42);
+  TestAllTypes* heap_message = new TestAllTypes;
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  EXPECT_DEBUG_DEATH(
+      heap_message->set_allocated_optional_nested_message(arena1_submessage),
+      "submessage_arena");
+#endif
+  EXPECT_NE(arena1_submessage, heap_message->mutable_optional_nested_message());
+  delete heap_message;
+}
+
+TEST(ArenaTest, UnsafeArenaSetAllocatedAcrossArenas) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    arena1_message->unsafe_arena_set_allocated_optional_nested_message(
+        arena2_submessage);
+    EXPECT_EQ(arena2_submessage,
+              arena1_message->mutable_optional_nested_message());
+    EXPECT_EQ(arena2_submessage,
+              arena1_message->unsafe_arena_release_optional_nested_message());
+  }
+
+  TestAllTypes::NestedMessage* arena1_submessage =
+      Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
+  arena1_submessage->set_bb(42);
+  TestAllTypes* heap_message = new TestAllTypes;
+  heap_message->unsafe_arena_set_allocated_optional_nested_message(
+      arena1_submessage);
+  EXPECT_EQ(arena1_submessage, heap_message->mutable_optional_nested_message());
+  EXPECT_EQ(arena1_submessage,
+            heap_message->unsafe_arena_release_optional_nested_message());
+  delete heap_message;
+}
+
+TEST(ArenaTest, SetAllocatedAcrossArenasWithReflection) {
+  // Same as above, with reflection.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  const Reflection* r = arena1_message->GetReflection();
+  const Descriptor* d = arena1_message->GetDescriptor();
+  const FieldDescriptor* msg_field =
+      d->FindFieldByName("optional_nested_message");
+  TestAllTypes::NestedMessage* heap_submessage =
+      new TestAllTypes::NestedMessage();
+  heap_submessage->set_bb(42);
+  r->SetAllocatedMessage(arena1_message, heap_submessage, msg_field);
+  // Should keep same object and add to arena's Own()-list.
+  EXPECT_EQ(heap_submessage, arena1_message->mutable_optional_nested_message());
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+#ifdef PROTOBUF_HAS_DEATH_TEST
+    EXPECT_DEBUG_DEATH(
+        r->SetAllocatedMessage(arena1_message, arena2_submessage, msg_field),
+        "GetOwningArena");
+#endif
+    EXPECT_NE(arena2_submessage,
+              arena1_message->mutable_optional_nested_message());
+  }
+
+  TestAllTypes::NestedMessage* arena1_submessage =
+      Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
+  arena1_submessage->set_bb(42);
+  TestAllTypes* heap_message = new TestAllTypes;
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  EXPECT_DEBUG_DEATH(
+      r->SetAllocatedMessage(heap_message, arena1_submessage, msg_field),
+      "GetOwningArena");
+#endif
+  EXPECT_NE(arena1_submessage, heap_message->mutable_optional_nested_message());
+  delete heap_message;
+}
+
+TEST(ArenaTest, UnsafeArenaSetAllocatedAcrossArenasWithReflection) {
+  // Same as above, with reflection.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  const Reflection* r = arena1_message->GetReflection();
+  const Descriptor* d = arena1_message->GetDescriptor();
+  const FieldDescriptor* msg_field =
+      d->FindFieldByName("optional_nested_message");
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    r->UnsafeArenaSetAllocatedMessage(arena1_message, arena2_submessage,
+                                      msg_field);
+    EXPECT_EQ(arena2_submessage,
+              arena1_message->mutable_optional_nested_message());
+    EXPECT_EQ(arena2_submessage,
+              arena1_message->unsafe_arena_release_optional_nested_message());
+  }
+
+  TestAllTypes::NestedMessage* arena1_submessage =
+      Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
+  arena1_submessage->set_bb(42);
+  TestAllTypes* heap_message = new TestAllTypes;
+  r->UnsafeArenaSetAllocatedMessage(heap_message, arena1_submessage, msg_field);
+  EXPECT_EQ(arena1_submessage, heap_message->mutable_optional_nested_message());
+  EXPECT_EQ(arena1_submessage,
+            heap_message->unsafe_arena_release_optional_nested_message());
+  delete heap_message;
+}
+
+TEST(ArenaTest, AddAllocatedWithReflection) {
+  Arena arena1;
+  ArenaMessage* arena1_message = Arena::CreateMessage<ArenaMessage>(&arena1);
+  const Reflection* r = arena1_message->GetReflection();
+  const Descriptor* d = arena1_message->GetDescriptor();
+  // Message with cc_enable_arenas = true;
+  const FieldDescriptor* fd = d->FindFieldByName("repeated_nested_message");
+  r->AddMessage(arena1_message, fd);
+  r->AddMessage(arena1_message, fd);
+  r->AddMessage(arena1_message, fd);
+  EXPECT_EQ(3, r->FieldSize(*arena1_message, fd));
+}
+
+TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) {
+#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
+  {
+    RepeatedPtrField<TestAllTypes> repeated_field;
+    EXPECT_TRUE(repeated_field.empty());
+    EXPECT_EQ(0, repeated_field.size());
+    // Ownership is passed to repeated_field.
+    TestAllTypes* cleared = new TestAllTypes();
+    repeated_field.AddCleared(cleared);
+    EXPECT_TRUE(repeated_field.empty());
+    EXPECT_EQ(0, repeated_field.size());
+  }
+#endif  // !PROTOBUF_FUTURE_BREAKING_CHANGES
+  {
+    RepeatedPtrField<TestAllTypes> repeated_field;
+    EXPECT_TRUE(repeated_field.empty());
+    EXPECT_EQ(0, repeated_field.size());
+    // Ownership is passed to repeated_field.
+    TestAllTypes* cleared = new TestAllTypes();
+    repeated_field.AddAllocated(cleared);
+    EXPECT_FALSE(repeated_field.empty());
+    EXPECT_EQ(1, repeated_field.size());
+  }
+}
+
+TEST(ArenaTest, AddAllocatedToRepeatedField) {
+  // Heap->arena case.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* heap_submessage =
+        new TestAllTypes::NestedMessage();
+    heap_submessage->set_bb(42);
+    arena1_message->mutable_repeated_nested_message()->AddAllocated(
+        heap_submessage);
+    // Should not copy object -- will use arena_->Own().
+    EXPECT_EQ(heap_submessage, &arena1_message->repeated_nested_message(i));
+    EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb());
+  }
+
+  // Arena1->Arena2 case.
+  arena1_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+#ifdef PROTOBUF_HAS_DEATH_TEST
+    EXPECT_DEBUG_DEATH(
+        arena1_message->mutable_repeated_nested_message()->AddAllocated(
+            arena2_submessage),
+        "value_arena");
+#endif
+    // Should not receive object.
+    EXPECT_TRUE(arena1_message->repeated_nested_message().empty());
+  }
+
+  // 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);
+#ifdef PROTOBUF_HAS_DEATH_TEST
+    EXPECT_DEBUG_DEATH(
+        heap_message->mutable_repeated_nested_message()->AddAllocated(
+            arena2_submessage),
+        "value_arena");
+#endif
+    // Should not receive object.
+    EXPECT_TRUE(heap_message->repeated_nested_message().empty());
+  }
+  delete heap_message;
+
+  // Heap->arena case for strings (which are not arena-allocated).
+  arena1_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    std::string* s = new std::string("Test");
+    arena1_message->mutable_repeated_string()->AddAllocated(s);
+    // Should not copy.
+    EXPECT_EQ(s, &arena1_message->repeated_string(i));
+    EXPECT_EQ("Test", arena1_message->repeated_string(i));
+  }
+}
+
+TEST(ArenaTest, UnsafeArenaAddAllocatedToRepeatedField) {
+  // Heap->arena case.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    auto* heap_submessage = new TestAllTypes::NestedMessage;
+    arena1_message->mutable_repeated_nested_message()->UnsafeArenaAddAllocated(
+        heap_submessage);
+    // Should not copy object.
+    EXPECT_EQ(heap_submessage, &arena1_message->repeated_nested_message(0));
+    EXPECT_EQ(heap_submessage, arena1_message->mutable_repeated_nested_message()
+                                   ->UnsafeArenaReleaseLast());
+    delete heap_submessage;
+  }
+
+  // Arena1->Arena2 case.
+  arena1_message->Clear();
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    arena1_message->mutable_repeated_nested_message()->UnsafeArenaAddAllocated(
+        arena2_submessage);
+    // Should own object.
+    EXPECT_EQ(arena2_submessage, &arena1_message->repeated_nested_message(0));
+    EXPECT_EQ(arena2_submessage,
+              arena1_message->mutable_repeated_nested_message()
+                  ->UnsafeArenaReleaseLast());
+  }
+
+  // Arena->heap case.
+  TestAllTypes* heap_message = new TestAllTypes;
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    heap_message->mutable_repeated_nested_message()->UnsafeArenaAddAllocated(
+        arena2_submessage);
+    // Should own object.
+    EXPECT_EQ(arena2_submessage, &heap_message->repeated_nested_message(0));
+    EXPECT_EQ(arena2_submessage, heap_message->mutable_repeated_nested_message()
+                                     ->UnsafeArenaReleaseLast());
+  }
+  delete heap_message;
+
+  // Heap->arena case for strings (which are not arena-allocated).
+  arena1_message->Clear();
+  {
+    std::string* s = new std::string("Test");
+    arena1_message->mutable_repeated_string()->UnsafeArenaAddAllocated(s);
+    // Should not copy.
+    EXPECT_EQ(s, &arena1_message->repeated_string(0));
+    EXPECT_EQ("Test", arena1_message->repeated_string(0));
+    delete arena1_message->mutable_repeated_string()->UnsafeArenaReleaseLast();
+  }
+}
+
+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);
+#ifdef PROTOBUF_HAS_DEATH_TEST
+    EXPECT_DEBUG_DEATH(
+        r->AddAllocatedMessage(arena1_message, fd, arena2_submessage),
+        "value_arena");
+#endif
+    // Should not receive object.
+    EXPECT_TRUE(arena1_message->repeated_nested_message().empty());
+  }
+
+  // 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);
+#ifdef PROTOBUF_HAS_DEATH_TEST
+    EXPECT_DEBUG_DEATH(
+        r->AddAllocatedMessage(heap_message, fd, arena2_submessage),
+        "value_arena");
+#endif
+    // Should not receive object.
+    EXPECT_TRUE(heap_message->repeated_nested_message().empty());
+  }
+  delete heap_message;
+}
+
+TEST(ArenaTest, ReleaseLastRepeatedField) {
+  // Release from arena-allocated repeated field and ensure that returned object
+  // is heap-allocated.
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* nested =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena);
+    nested->set_bb(42);
+    arena_message->mutable_repeated_nested_message()->AddAllocated(nested);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    const TestAllTypes::NestedMessage* orig_submessage =
+        &arena_message->repeated_nested_message(10 - 1 - i);  // last element
+    TestAllTypes::NestedMessage* released =
+        arena_message->mutable_repeated_nested_message()->ReleaseLast();
+    EXPECT_NE(released, orig_submessage);
+    EXPECT_EQ(42, released->bb());
+    delete released;
+  }
+
+  // Test UnsafeArenaReleaseLast().
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* nested =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena);
+    nested->set_bb(42);
+    arena_message->mutable_repeated_nested_message()->AddAllocated(nested);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    const TestAllTypes::NestedMessage* orig_submessage =
+        &arena_message->repeated_nested_message(10 - 1 - i);  // last element
+    TestAllTypes::NestedMessage* released =
+        arena_message->mutable_repeated_nested_message()
+            ->UnsafeArenaReleaseLast();
+    EXPECT_EQ(released, orig_submessage);
+    EXPECT_EQ(42, released->bb());
+    // no delete -- |released| is on the arena.
+  }
+
+  // Test string case as well. ReleaseLast() in this case must copy the
+  // string, even though it was originally heap-allocated and its pointer
+  // was simply appended to the repeated field's internal vector, because the
+  // string was placed on the arena's destructor list and cannot be removed
+  // from that list (so the arena permanently owns the original instance).
+  arena_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    std::string* s = new std::string("Test");
+    arena_message->mutable_repeated_string()->AddAllocated(s);
+  }
+  for (int i = 0; i < 10; i++) {
+    const std::string* orig_element =
+        &arena_message->repeated_string(10 - 1 - i);
+    std::string* released =
+        arena_message->mutable_repeated_string()->ReleaseLast();
+    EXPECT_NE(released, orig_element);
+    EXPECT_EQ("Test", *released);
+    delete released;
+  }
+}
+
+TEST(ArenaTest, UnsafeArenaAddAllocated) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  for (int i = 0; i < 10; i++) {
+    std::string* arena_string = Arena::Create<std::string>(&arena);
+    message->mutable_repeated_string()->UnsafeArenaAddAllocated(arena_string);
+    EXPECT_EQ(arena_string, message->mutable_repeated_string(i));
+  }
+}
+
+TEST(ArenaTest, OneofMerge) {
+  Arena arena;
+  TestAllTypes* message0 = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes* message1 = Arena::CreateMessage<TestAllTypes>(&arena);
+
+  message0->set_oneof_string("x");
+  ASSERT_TRUE(message0->has_oneof_string());
+  message1->set_oneof_string("y");
+  ASSERT_TRUE(message1->has_oneof_string());
+  EXPECT_EQ("x", message0->oneof_string());
+  EXPECT_EQ("y", message1->oneof_string());
+  message0->MergeFrom(*message1);
+  EXPECT_EQ("y", message0->oneof_string());
+  EXPECT_EQ("y", message1->oneof_string());
+}
+
+TEST(ArenaTest, ArenaOneofReflection) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  const Descriptor* desc = message->GetDescriptor();
+  const Reflection* refl = message->GetReflection();
+
+  const FieldDescriptor* string_field = desc->FindFieldByName("oneof_string");
+  const FieldDescriptor* msg_field =
+      desc->FindFieldByName("oneof_nested_message");
+  const OneofDescriptor* oneof = desc->FindOneofByName("oneof_field");
+
+  refl->SetString(message, string_field, "Test value");
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  refl->ClearOneof(message, oneof);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+
+  Message* submsg = refl->MutableMessage(message, msg_field);
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  refl->ClearOneof(message, oneof);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+  refl->MutableMessage(message, msg_field);
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  submsg = refl->ReleaseMessage(message, msg_field);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+  EXPECT_TRUE(submsg->GetArena() == NULL);
+  delete submsg;
+}
+
+void TestSwapRepeatedField(Arena* arena1, Arena* arena2) {
+  // Test "safe" (copying) semantics for direct Swap() on RepeatedPtrField
+  // between arenas.
+  RepeatedPtrField<TestAllTypes> field1(arena1);
+  RepeatedPtrField<TestAllTypes> field2(arena2);
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(arena1);
+    t->set_optional_string("field1");
+    t->set_optional_int32(i);
+    if (arena1 != NULL) {
+      field1.UnsafeArenaAddAllocated(t);
+    } else {
+      field1.AddAllocated(t);
+    }
+  }
+  for (int i = 0; i < 5; i++) {
+    TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(arena2);
+    t->set_optional_string("field2");
+    t->set_optional_int32(i);
+    if (arena2 != NULL) {
+      field2.UnsafeArenaAddAllocated(t);
+    } else {
+      field2.AddAllocated(t);
+    }
+  }
+  field1.Swap(&field2);
+  EXPECT_EQ(5, field1.size());
+  EXPECT_EQ(10, field2.size());
+  EXPECT_TRUE(std::string("field1") == field2.Get(0).optional_string());
+  EXPECT_TRUE(std::string("field2") == field1.Get(0).optional_string());
+  // Ensure that fields retained their original order:
+  for (int i = 0; i < field1.size(); i++) {
+    EXPECT_EQ(i, field1.Get(i).optional_int32());
+  }
+  for (int i = 0; i < field2.size(); i++) {
+    EXPECT_EQ(i, field2.Get(i).optional_int32());
+  }
+}
+
+TEST(ArenaTest, SwapRepeatedField) {
+  Arena arena;
+  TestSwapRepeatedField(&arena, &arena);
+}
+
+TEST(ArenaTest, SwapRepeatedFieldWithDifferentArenas) {
+  Arena arena1;
+  Arena arena2;
+  TestSwapRepeatedField(&arena1, &arena2);
+}
+
+TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnRightHandSide) {
+  Arena arena;
+  TestSwapRepeatedField(&arena, NULL);
+}
+
+TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnLeftHandSide) {
+  Arena arena;
+  TestSwapRepeatedField(NULL, &arena);
+}
+
+TEST(ArenaTest, ExtensionsOnArena) {
+  Arena arena;
+  // Ensure no leaks.
+  TestAllExtensions* message_ext =
+      Arena::CreateMessage<TestAllExtensions>(&arena);
+  message_ext->SetExtension(protobuf_unittest::optional_int32_extension, 42);
+  message_ext->SetExtension(protobuf_unittest::optional_string_extension,
+                            std::string("test"));
+  message_ext
+      ->MutableExtension(protobuf_unittest::optional_nested_message_extension)
+      ->set_bb(42);
+}
+
+TEST(ArenaTest, RepeatedFieldOnArena) {
+  // Preallocate an initial arena block to avoid mallocs during hooked region.
+  std::vector<char> arena_block(1024 * 1024);
+  Arena arena(arena_block.data(), arena_block.size());
+
+  {
+    internal::NoHeapChecker no_heap;
+
+    // Fill some repeated fields on the arena to test for leaks. Also verify no
+    // memory allocations.
+    RepeatedField<int32_t> repeated_int32(&arena);
+    RepeatedPtrField<TestAllTypes> repeated_message(&arena);
+    for (int i = 0; i < 100; i++) {
+      repeated_int32.Add(42);
+      repeated_message.Add()->set_optional_int32(42);
+      EXPECT_EQ(&arena, repeated_message.Get(0).GetArena());
+      const TestAllTypes* msg_in_repeated_field = &repeated_message.Get(0);
+      TestAllTypes* msg = repeated_message.UnsafeArenaReleaseLast();
+      EXPECT_EQ(msg_in_repeated_field, msg);
+    }
+
+    // UnsafeArenaExtractSubrange (i) should not leak and (ii) should return
+    // on-arena pointers.
+    for (int i = 0; i < 10; i++) {
+      repeated_message.Add()->set_optional_int32(42);
+    }
+    TestAllTypes* extracted_messages[5];
+    repeated_message.UnsafeArenaExtractSubrange(0, 5, extracted_messages);
+    EXPECT_EQ(&arena, repeated_message.Get(0).GetArena());
+    EXPECT_EQ(5, repeated_message.size());
+  }
+
+  // Now, outside the scope of the NoHeapChecker, test ExtractSubrange's copying
+  // semantics.
+  {
+    RepeatedPtrField<TestAllTypes> repeated_message(&arena);
+    for (int i = 0; i < 100; i++) {
+      repeated_message.Add()->set_optional_int32(42);
+    }
+
+    TestAllTypes* extracted_messages[5];
+    // ExtractSubrange should copy to the heap.
+    repeated_message.ExtractSubrange(0, 5, extracted_messages);
+    EXPECT_EQ(NULL, extracted_messages[0]->GetArena());
+    // We need to free the heap-allocated messages to prevent a leak.
+    for (int i = 0; i < 5; i++) {
+      delete extracted_messages[i];
+      extracted_messages[i] = NULL;
+    }
+  }
+
+  // Now check that we can create RepeatedFields/RepeatedPtrFields themselves on
+  // the arena. They have the necessary type traits so that they can behave like
+  // messages in this way. This is useful for higher-level generic templated
+  // code that may allocate messages or repeated fields of messages on an arena.
+  {
+    RepeatedPtrField<TestAllTypes>* repeated_ptr_on_arena =
+        Arena::CreateMessage<RepeatedPtrField<TestAllTypes> >(&arena);
+    for (int i = 0; i < 10; i++) {
+      // Add some elements and let the leak-checker ensure that everything is
+      // freed.
+      repeated_ptr_on_arena->Add();
+    }
+
+    RepeatedField<int>* repeated_int_on_arena =
+        Arena::CreateMessage<RepeatedField<int> >(&arena);
+    for (int i = 0; i < 100; i++) {
+      repeated_int_on_arena->Add(i);
+    }
+
+  }
+
+  arena.Reset();
+}
+
+
+#if PROTOBUF_RTTI
+TEST(ArenaTest, MutableMessageReflection) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  const Reflection* r = message->GetReflection();
+  const Descriptor* d = message->GetDescriptor();
+  const FieldDescriptor* field = d->FindFieldByName("optional_nested_message");
+  TestAllTypes::NestedMessage* submessage =
+      static_cast<TestAllTypes::NestedMessage*>(
+          r->MutableMessage(message, field));
+  TestAllTypes::NestedMessage* submessage_expected =
+      message->mutable_optional_nested_message();
+
+  EXPECT_EQ(submessage_expected, submessage);
+  EXPECT_EQ(&arena, submessage->GetArena());
+
+  const FieldDescriptor* oneof_field =
+      d->FindFieldByName("oneof_nested_message");
+  submessage = static_cast<TestAllTypes::NestedMessage*>(
+      r->MutableMessage(message, oneof_field));
+  submessage_expected = message->mutable_oneof_nested_message();
+
+  EXPECT_EQ(submessage_expected, submessage);
+  EXPECT_EQ(&arena, submessage->GetArena());
+}
+#endif  // PROTOBUF_RTTI
+
+
+void FillArenaAwareFields(TestAllTypes* message) {
+  std::string test_string = "hello world";
+  message->set_optional_int32(42);
+  message->set_optional_string(test_string);
+  message->set_optional_bytes(test_string);
+  message->mutable_optional_nested_message()->set_bb(42);
+
+  message->set_oneof_uint32(42);
+  message->mutable_oneof_nested_message()->set_bb(42);
+  message->set_oneof_string(test_string);
+  message->set_oneof_bytes(test_string);
+
+  message->add_repeated_int32(42);
+  // No repeated string: not yet arena-aware.
+  message->add_repeated_nested_message()->set_bb(42);
+  message->mutable_optional_lazy_message()->set_bb(42);
+}
+
+// Test: no allocations occur on heap while touching all supported field types.
+TEST(ArenaTest, NoHeapAllocationsTest) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  {
+
+    TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+    FillArenaAwareFields(message);
+  }
+
+  arena.Reset();
+}
+
+TEST(ArenaTest, ParseCorruptedString) {
+  TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+  TestParseCorruptedString<TestAllTypes, true>(message);
+  TestParseCorruptedString<TestAllTypes, false>(message);
+}
+
+#if PROTOBUF_RTTI
+// Test construction on an arena via generic MessageLite interface. We should be
+// able to successfully deserialize on the arena without incurring heap
+// allocations, i.e., everything should still be arena-allocation-aware.
+TEST(ArenaTest, MessageLiteOnArena) {
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+  const MessageLite* prototype = &TestAllTypes::default_instance();
+
+  TestAllTypes initial_message;
+  FillArenaAwareFields(&initial_message);
+  std::string serialized;
+  initial_message.SerializeToString(&serialized);
+
+  {
+
+    MessageLite* generic_message = prototype->New(&arena);
+    EXPECT_TRUE(generic_message != NULL);
+    EXPECT_EQ(&arena, generic_message->GetArena());
+    EXPECT_TRUE(generic_message->ParseFromString(serialized));
+    TestAllTypes* deserialized = static_cast<TestAllTypes*>(generic_message);
+    EXPECT_EQ(42, deserialized->optional_int32());
+  }
+
+  arena.Reset();
+}
+#endif  // PROTOBUF_RTTI
+
+// RepeatedField should support non-POD types, and invoke constructors and
+// destructors appropriately, because it's used this way by lots of other code
+// (even if this was not its original intent).
+TEST(ArenaTest, RepeatedFieldWithNonPODType) {
+  {
+    RepeatedField<std::string> field_on_heap;
+    for (int i = 0; i < 100; i++) {
+      *field_on_heap.Add() = "test string long enough to exceed inline buffer";
+    }
+  }
+  {
+    Arena arena;
+    RepeatedField<std::string> field_on_arena(&arena);
+    for (int i = 0; i < 100; i++) {
+      *field_on_arena.Add() = "test string long enough to exceed inline buffer";
+    }
+  }
+}
+
+// Align n to next multiple of 8
+uint64_t Align8(uint64_t n) { return (n + 7) & -8; }
+
+TEST(ArenaTest, SpaceAllocated_and_Used) {
+  Arena arena_1;
+  EXPECT_EQ(0, arena_1.SpaceAllocated());
+  EXPECT_EQ(0, arena_1.SpaceUsed());
+  EXPECT_EQ(0, arena_1.Reset());
+  Arena::CreateArray<char>(&arena_1, 320);
+  // Arena will allocate slightly more than 320 for the block headers.
+  EXPECT_LE(320, arena_1.SpaceAllocated());
+  EXPECT_EQ(Align8(320), arena_1.SpaceUsed());
+  EXPECT_LE(320, arena_1.Reset());
+
+  // Test with initial block.
+  std::vector<char> arena_block(1024);
+  ArenaOptions options;
+  options.start_block_size = 256;
+  options.max_block_size = 8192;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena_2(options);
+  EXPECT_EQ(1024, arena_2.SpaceAllocated());
+  EXPECT_EQ(0, arena_2.SpaceUsed());
+  EXPECT_EQ(1024, arena_2.Reset());
+  Arena::CreateArray<char>(&arena_2, 55);
+  EXPECT_EQ(1024, arena_2.SpaceAllocated());
+  EXPECT_EQ(Align8(55), arena_2.SpaceUsed());
+  EXPECT_EQ(1024, arena_2.Reset());
+}
+
+TEST(ArenaTest, BlockSizeDoubling) {
+  Arena arena;
+  EXPECT_EQ(0, arena.SpaceUsed());
+  EXPECT_EQ(0, arena.SpaceAllocated());
+
+  // Allocate something to get initial block size.
+  Arena::CreateArray<char>(&arena, 1);
+  auto first_block_size = arena.SpaceAllocated();
+
+  // Keep allocating until space used increases.
+  while (arena.SpaceAllocated() == first_block_size) {
+    Arena::CreateArray<char>(&arena, 1);
+  }
+  ASSERT_GT(arena.SpaceAllocated(), first_block_size);
+  auto second_block_size = (arena.SpaceAllocated() - first_block_size);
+
+  EXPECT_EQ(second_block_size, 2*first_block_size);
+}
+
+TEST(ArenaTest, Alignment) {
+  Arena arena;
+  for (int i = 0; i < 200; i++) {
+    void* p = Arena::CreateArray<char>(&arena, i);
+    GOOGLE_CHECK_EQ(reinterpret_cast<uintptr_t>(p) % 8, 0) << i << ": " << p;
+  }
+}
+
+TEST(ArenaTest, BlockSizeSmallerThanAllocation) {
+  for (size_t i = 0; i <= 8; ++i) {
+    ArenaOptions opt;
+    opt.start_block_size = opt.max_block_size = i;
+    Arena arena(opt);
+
+    *Arena::Create<int64_t>(&arena) = 42;
+    EXPECT_GE(arena.SpaceAllocated(), 8);
+    EXPECT_EQ(8, arena.SpaceUsed());
+
+    *Arena::Create<int64_t>(&arena) = 42;
+    EXPECT_GE(arena.SpaceAllocated(), 16);
+    EXPECT_EQ(16, arena.SpaceUsed());
+  }
+}
+
+TEST(ArenaTest, GetArenaShouldReturnTheArenaForArenaAllocatedMessages) {
+  Arena arena;
+  ArenaMessage* message = Arena::CreateMessage<ArenaMessage>(&arena);
+  const ArenaMessage* const_pointer_to_message = message;
+  EXPECT_EQ(&arena, Arena::GetArena(message));
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message));
+
+  // Test that the Message* / MessageLite* specialization SFINAE works.
+  const Message* const_pointer_to_message_type = message;
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message_type));
+  const MessageLite* const_pointer_to_message_lite_type = message;
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message_lite_type));
+}
+
+TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
+  ArenaMessage message;
+  const ArenaMessage* const_pointer_to_message = &message;
+  EXPECT_EQ(NULL, Arena::GetArena(&message));
+  EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
+}
+
+TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaCompatibleTypes) {
+  // Test that GetArena returns nullptr for types that have a GetArena method
+  // that doesn't return Arena*.
+  struct {
+    int GetArena() const { return 0; }
+  } has_get_arena_method_wrong_return_type;
+  EXPECT_EQ(nullptr, Arena::GetArena(&has_get_arena_method_wrong_return_type));
+
+  // Test that GetArena returns nullptr for types that have a GetArena alias.
+  struct {
+    using GetArena = Arena*;
+    GetArena unused;
+  } has_get_arena_alias;
+  EXPECT_EQ(nullptr, Arena::GetArena(&has_get_arena_alias));
+
+  // Test that GetArena returns nullptr for types that have a GetArena data
+  // member.
+  struct {
+    Arena GetArena;
+  } has_get_arena_data_member;
+  EXPECT_EQ(nullptr, Arena::GetArena(&has_get_arena_data_member));
+}
+
+TEST(ArenaTest, AddCleanup) {
+  Arena arena;
+  for (int i = 0; i < 100; i++) {
+    arena.Own(new int);
+  }
+}
+
+TEST(ArenaTest, SpaceReuseForArraysSizeChecks) {
+  // Limit to 1<<20 to avoid using too much memory on the test.
+  for (int i = 0; i < 20; ++i) {
+    SCOPED_TRACE(i);
+    Arena arena;
+    std::vector<void*> pointers;
+
+    const size_t size = 16 << i;
+
+    for (int j = 0; j < 10; ++j) {
+      pointers.push_back(Arena::CreateArray<char>(&arena, size));
+    }
+
+    for (void* p : pointers) {
+      internal::ArenaTestPeer::ReturnArrayMemory(&arena, p, size);
+    }
+
+    std::vector<void*> second_pointers;
+    for (int j = 9; j != 0; --j) {
+      second_pointers.push_back(Arena::CreateArray<char>(&arena, size));
+    }
+
+    // The arena will give us back the pointers we returned, except the first
+    // one. That one becomes part of the freelist data structure.
+    ASSERT_THAT(second_pointers,
+                testing::UnorderedElementsAreArray(
+                    std::vector<void*>(pointers.begin() + 1, pointers.end())));
+  }
+}
+
+TEST(ArenaTest, SpaceReusePoisonsAndUnpoisonsMemory) {
+#ifdef ADDRESS_SANITIZER
+  char buf[1024]{};
+  {
+    Arena arena(buf, sizeof(buf));
+    std::vector<void*> pointers;
+    for (int i = 0; i < 100; ++i) {
+      pointers.push_back(Arena::CreateArray<char>(&arena, 16));
+    }
+    for (void* p : pointers) {
+      internal::ArenaTestPeer::ReturnArrayMemory(&arena, p, 16);
+      // The first one is not poisoned because it becomes the freelist.
+      if (p != pointers[0]) EXPECT_TRUE(__asan_address_is_poisoned(p));
+    }
+
+    bool found_poison = false;
+    for (char& c : buf) {
+      if (__asan_address_is_poisoned(&c)) {
+        found_poison = true;
+        break;
+      }
+    }
+    EXPECT_TRUE(found_poison);
+  }
+
+  // Should not be poisoned after destruction.
+  for (char& c : buf) {
+    ASSERT_FALSE(__asan_address_is_poisoned(&c));
+  }
+
+#else   // ADDRESS_SANITIZER
+  GTEST_SKIP();
+#endif  // ADDRESS_SANITIZER
+}
+
+namespace {
+uint32_t hooks_num_init = 0;
+uint32_t hooks_num_allocations = 0;
+uint32_t hooks_num_reset = 0;
+uint32_t hooks_num_destruct = 0;
+
+void ClearHookCounts() {
+  hooks_num_init = 0;
+  hooks_num_allocations = 0;
+  hooks_num_reset = 0;
+  hooks_num_destruct = 0;
+}
+}  // namespace
+
+// A helper utility class that handles arena callbacks.
+class ArenaOptionsTestFriend final : public internal::ArenaMetricsCollector {
+ public:
+  static internal::ArenaMetricsCollector* NewWithAllocs() {
+    return new ArenaOptionsTestFriend(true);
+  }
+
+  static internal::ArenaMetricsCollector* NewWithoutAllocs() {
+    return new ArenaOptionsTestFriend(false);
+  }
+
+  static void Enable(ArenaOptions* options) {
+    ClearHookCounts();
+    options->make_metrics_collector = &ArenaOptionsTestFriend::NewWithAllocs;
+  }
+
+  static void EnableWithoutAllocs(ArenaOptions* options) {
+    ClearHookCounts();
+    options->make_metrics_collector = &ArenaOptionsTestFriend::NewWithoutAllocs;
+  }
+
+  explicit ArenaOptionsTestFriend(bool record_allocs)
+      : ArenaMetricsCollector(record_allocs) {
+    ++hooks_num_init;
+  }
+  void OnDestroy(uint64_t space_allocated) override {
+    ++hooks_num_destruct;
+    delete this;
+  }
+  void OnReset(uint64_t space_allocated) override { ++hooks_num_reset; }
+  void OnAlloc(const std::type_info* allocated_type,
+               uint64_t alloc_size) override {
+    ++hooks_num_allocations;
+  }
+};
+
+// Test the hooks are correctly called.
+TEST(ArenaTest, ArenaHooksSanity) {
+  ArenaOptions options;
+  ArenaOptionsTestFriend::Enable(&options);
+
+  // Scope for defining the arena
+  {
+    Arena arena(options);
+    EXPECT_EQ(1, hooks_num_init);
+    EXPECT_EQ(0, hooks_num_allocations);
+    Arena::Create<uint64_t>(&arena);
+    if (std::is_trivially_destructible<uint64_t>::value) {
+      EXPECT_EQ(1, hooks_num_allocations);
+    } else {
+      EXPECT_EQ(2, hooks_num_allocations);
+    }
+    arena.Reset();
+    arena.Reset();
+    EXPECT_EQ(2, hooks_num_reset);
+  }
+  EXPECT_EQ(2, hooks_num_reset);
+  EXPECT_EQ(1, hooks_num_destruct);
+}
+
+// Test that allocation hooks are not called when we don't need them.
+TEST(ArenaTest, ArenaHooksWhenAllocationsNotNeeded) {
+  ArenaOptions options;
+  ArenaOptionsTestFriend::EnableWithoutAllocs(&options);
+
+  Arena arena(options);
+  EXPECT_EQ(0, hooks_num_allocations);
+  Arena::Create<uint64_t>(&arena);
+  EXPECT_EQ(0, hooks_num_allocations);
+}
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc
new file mode 100644
index 0000000..af0c9df
--- /dev/null
+++ b/src/google/protobuf/arenastring.cc
@@ -0,0 +1,267 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/arenastring.h>
+
+#include <cstddef>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace  {
+
+// TaggedStringPtr::Flags uses the lower 2 bits as tags.
+// Enforce that allocated data aligns to at least 4 bytes, and that
+// the alignment of the global const string value does as well.
+// The alignment guaranteed by `new std::string` depends on both:
+// - new align = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / max_align_t
+// - alignof(std::string)
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+constexpr size_t kNewAlign = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
+constexpr size_t kNewAlign = alignof(::max_align_t);
+#else
+constexpr size_t kNewAlign = alignof(std::max_align_t);
+#endif
+constexpr size_t kStringAlign = alignof(std::string);
+
+static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 4, "");
+static_assert(alignof(ExplicitlyConstructedArenaString) >= 4, "");
+
+}  // namespace
+
+const std::string& LazyString::Init() const {
+  static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
+  mu.Lock();
+  const std::string* res = inited_.load(std::memory_order_acquire);
+  if (res == nullptr) {
+    auto init_value = init_value_;
+    res = ::new (static_cast<void*>(string_buf_))
+        std::string(init_value.ptr, init_value.size);
+    inited_.store(res, std::memory_order_release);
+  }
+  mu.Unlock();
+  return *res;
+}
+
+namespace {
+
+
+#if defined(NDEBUG) || !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+class ScopedCheckPtrInvariants {
+ public:
+  explicit ScopedCheckPtrInvariants(const TaggedStringPtr*) {}
+};
+
+#endif  // NDEBUG || !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+// Creates a heap allocated std::string value.
+inline TaggedStringPtr CreateString(ConstStringParam value) {
+  TaggedStringPtr res;
+  res.SetAllocated(new std::string(value.data(), value.length()));
+  return res;
+}
+
+#if !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+// Creates an arena allocated std::string value.
+TaggedStringPtr CreateArenaString(Arena& arena, ConstStringParam s) {
+  TaggedStringPtr res;
+  res.SetMutableArena(Arena::Create<std::string>(&arena, s.data(), s.length()));
+  return res;
+}
+
+#endif  // !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+}  // namespace
+
+void ArenaStringPtr::Set(ConstStringParam value, Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) {
+    // If we're not on an arena, skip straight to a true string to avoid
+    // possible copy cost later.
+    tagged_ptr_ = arena != nullptr ? CreateArenaString(*arena, value)
+                                   : CreateString(value);
+  } else {
+    UnsafeMutablePointer()->assign(value.data(), value.length());
+  }
+}
+
+void ArenaStringPtr::Set(std::string&& value, Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) {
+    NewString(arena, std::move(value));
+  } else if (IsFixedSizeArena()) {
+    std::string* current = tagged_ptr_.Get();
+    auto* s = new (current) std::string(std::move(value));
+    arena->OwnDestructor(s);
+    tagged_ptr_.SetMutableArena(s);
+  } else /* !IsFixedSizeArena() */ {
+    *UnsafeMutablePointer() = std::move(value);
+  }
+}
+
+std::string* ArenaStringPtr::Mutable(Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (tagged_ptr_.IsMutable()) {
+    return tagged_ptr_.Get();
+  } else {
+    return MutableSlow(arena);
+  }
+}
+
+std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
+                                     Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (tagged_ptr_.IsMutable()) {
+    return tagged_ptr_.Get();
+  } else {
+    return MutableSlow(arena, default_value);
+  }
+}
+
+std::string* ArenaStringPtr::MutableNoCopy(Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (tagged_ptr_.IsMutable()) {
+    return tagged_ptr_.Get();
+  } else {
+    GOOGLE_DCHECK(IsDefault());
+    // Allocate empty. The contents are not relevant.
+    return NewString(arena);
+  }
+}
+
+template <typename... Lazy>
+std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
+                                         const Lazy&... lazy_default) {
+  GOOGLE_DCHECK(IsDefault());
+
+  // For empty defaults, this ends up calling the default constructor which is
+  // more efficient than a copy construction from
+  // GetEmptyStringAlreadyInited().
+  return NewString(arena, lazy_default.get()...);
+}
+
+std::string* ArenaStringPtr::Release() {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) return nullptr;
+
+  std::string* released = tagged_ptr_.Get();
+  if (tagged_ptr_.IsArena()) {
+    released = tagged_ptr_.IsMutable() ? new std::string(std::move(*released))
+                                       : new std::string(*released);
+  }
+  InitDefault();
+  return released;
+}
+
+void ArenaStringPtr::SetAllocated(std::string* value, Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  // Release what we have first.
+  Destroy();
+
+  if (value == nullptr) {
+    InitDefault();
+  } else {
+#ifndef NDEBUG
+    // On debug builds, copy the string so the address differs.  delete will
+    // fail if value was a stack-allocated temporary/etc., which would have
+    // failed when arena ran its cleanup list.
+    std::string* new_value = new std::string(std::move(*value));
+    delete value;
+    value = new_value;
+#endif  // !NDEBUG
+    InitAllocated(value, arena);
+  }
+}
+
+void ArenaStringPtr::Destroy() {
+  delete tagged_ptr_.GetIfAllocated();
+}
+
+void ArenaStringPtr::ClearToEmpty() {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) {
+    // Already set to default -- do nothing.
+  } else {
+    // Unconditionally mask away the tag.
+    //
+    // UpdateArenaString uses assign when capacity is larger than the new
+    // value, which is trivially true in the donated string case.
+    // const_cast<std::string*>(PtrValue<std::string>())->clear();
+    tagged_ptr_.Get()->clear();
+  }
+}
+
+void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
+                                    ::google::protobuf::Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  (void)arena;
+  if (IsDefault()) {
+    // Already set to default -- do nothing.
+  } else {
+    UnsafeMutablePointer()->assign(default_value.get());
+  }
+}
+
+const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
+                                                ArenaStringPtr* s,
+                                                Arena* arena) {
+  ScopedCheckPtrInvariants check(&s->tagged_ptr_);
+  GOOGLE_DCHECK(arena != nullptr);
+
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+
+  auto* str = s->NewString(arena);
+  ptr = ReadString(ptr, size, str);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ptr;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
new file mode 100644
index 0000000..6bc8395
--- /dev/null
+++ b/src/google/protobuf/arenastring.h
@@ -0,0 +1,480 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
+#define GOOGLE_PROTOBUF_ARENASTRING_H__
+
+#include <algorithm>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/explicitly_constructed.h>
+
+// must be last:
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+class EpsCopyInputStream;
+
+class SwapFieldHelper;
+
+// Declared in message_lite.h
+PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
+    fixed_address_empty_string;
+
+// Lazy string instance to support string fields with non-empty default.
+// These are initialized on the first call to .get().
+class PROTOBUF_EXPORT LazyString {
+ public:
+  // We explicitly make LazyString an aggregate so that MSVC can do constant
+  // initialization on it without marking it `constexpr`.
+  // We do not want to use `constexpr` because it makes it harder to have extern
+  // storage for it and causes library bloat.
+  struct InitValue {
+    const char* ptr;
+    size_t size;
+  };
+  // We keep a union of the initialization value and the std::string to save on
+  // space. We don't need the string array after Init() is done.
+  union {
+    mutable InitValue init_value_;
+    alignas(std::string) mutable char string_buf_[sizeof(std::string)];
+  };
+  mutable std::atomic<const std::string*> inited_;
+
+  const std::string& get() const {
+    // This check generates less code than a call-once invocation.
+    auto* res = inited_.load(std::memory_order_acquire);
+    if (PROTOBUF_PREDICT_FALSE(res == nullptr)) return Init();
+    return *res;
+  }
+
+ private:
+  // Initialize the string in `string_buf_`, update `inited_` and return it.
+  // We return it here to avoid having to read it again in the inlined code.
+  const std::string& Init() const;
+};
+
+class TaggedStringPtr {
+ public:
+  // Bit flags qualifying string properties. We can use 2 bits as
+  // ptr_ is guaranteed and enforced to be aligned on 4 byte boundaries.
+  enum Flags {
+    kArenaBit = 0x1,      // ptr is arena allocated
+    kMutableBit = 0x2,    // ptr contents are fully mutable
+    kMask = 0x3           // Bit mask
+  };
+
+  // Composed logical types
+  enum Type {
+    // Default strings are immutable and never owned.
+    kDefault = 0,
+
+    // Allocated strings are mutable and (as the name implies) owned.
+    // A heap allocated string must be deleted.
+    kAllocated = kMutableBit,
+
+    // Mutable arena strings are strings where the string instance is owned
+    // by the arena, but the string contents itself are owned by the string
+    // instance. Mutable arena string instances need to be destroyed which is
+    // typically done through a cleanup action added to the arena owning it.
+    kMutableArena = kArenaBit | kMutableBit,
+
+    // Fixed size arena strings are strings where both the string instance and
+    // the string contents are fully owned by the arena. Fixed size arena
+    // strings are a platform and c++ library specific customization. Fixed
+    // size arena strings are immutable, with the exception of custom internal
+    // updates to the content that fit inside the existing capacity.
+    // Fixed size arena strings must never be deleted or destroyed.
+    kFixedSizeArena = kArenaBit,
+  };
+
+  TaggedStringPtr() = default;
+  explicit constexpr TaggedStringPtr(ExplicitlyConstructedArenaString* ptr)
+      : ptr_(ptr) {}
+
+  // Sets the value to `p`, tagging the value as being a 'default' value.
+  // See documentation for kDefault for more info.
+  inline const std::string* SetDefault(const std::string* p) {
+    return TagAs(kDefault, const_cast<std::string*>(p));
+  }
+
+  // Sets the value to `p`, tagging the value as a heap allocated value.
+  // Allocated strings are mutable and (as the name implies) owned.
+  // `p` must not be null
+  inline std::string* SetAllocated(std::string* p) {
+    return TagAs(kAllocated, p);
+  }
+
+  // Sets the value to `p`, tagging the value as a fixed size arena string.
+  // See documentation for kFixedSizeArena for more info.
+  // `p` must not be null
+  inline std::string* SetFixedSizeArena(std::string* p) {
+    return TagAs(kFixedSizeArena, p);
+  }
+
+  // Sets the value to `p`, tagging the value as a mutable arena string.
+  // See documentation for kMutableArena for more info.
+  // `p` must not be null
+  inline std::string* SetMutableArena(std::string* p) {
+    return TagAs(kMutableArena, p);
+  }
+
+  // Returns true if the contents of the current string are fully mutable.
+  inline bool IsMutable() const { return as_int() & kMutableBit; }
+
+  // Returns true if the current string is an immutable default value.
+  inline bool IsDefault() const { return (as_int() & kMask) == kDefault; }
+
+  // If the current string is a heap-allocated mutable value, returns a pointer
+  // to it.  Returns nullptr otherwise.
+  inline std::string *GetIfAllocated() const {
+    auto allocated = as_int() ^ kAllocated;
+    if (allocated & kMask) return nullptr;
+
+    auto ptr = reinterpret_cast<std::string*>(allocated);
+    PROTOBUF_ASSUME(ptr != nullptr);
+    return ptr;
+  }
+
+  // Returns true if the current string is an arena allocated value.
+  // This means it's either a mutable or fixed size arena string.
+  inline bool IsArena() const { return as_int() & kArenaBit; }
+
+  // Returns true if the current string is a fixed size arena allocated value.
+  inline bool IsFixedSizeArena() const {
+    return (as_int() & kMask) == kFixedSizeArena;
+  }
+
+  // Returns the contained string pointer.
+  inline std::string* Get() const {
+    return reinterpret_cast<std::string*>(as_int() & ~kMask);
+  }
+
+  // Returns true if the contained pointer is null, indicating some error.
+  // The Null value is only used during parsing for temporary values.
+  // A persisted ArenaStringPtr value is never null.
+  inline bool IsNull() { return ptr_ == nullptr; }
+
+ private:
+  static inline void assert_aligned(const void* p) {
+    GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(p) & kMask, 0UL);
+  }
+
+  inline std::string* TagAs(Type type, std::string* p) {
+    GOOGLE_DCHECK(p != nullptr);
+    assert_aligned(p);
+    ptr_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) | type);
+    return p;
+  }
+
+  uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
+  void* ptr_;
+};
+
+static_assert(std::is_trivial<TaggedStringPtr>::value,
+              "TaggedStringPtr must be trivial");
+
+// This class encapsulates a pointer to a std::string with or without arena
+// owned contents, tagged by the bottom bits of the string pointer. It is a
+// high-level wrapper that almost directly corresponds to the interface required
+// by string fields in generated code. It replaces the old std::string* pointer
+// in such cases.
+//
+// The string pointer is tagged to be either a default, externally owned value,
+// a mutable heap allocated value, or an arena allocated value. The object uses
+// a single global instance of an empty string that is used as the initial
+// default value. Fields that have empty default values directly use this global
+// default. Fields that have non empty default values are supported through
+// lazily initialized default values managed by the LazyString class.
+//
+// Generated code and reflection code both ensure that ptr_ is never null.
+// Because ArenaStringPtr is used in oneof unions, its constructor is a NOP and
+// the field is always manually initialized via method calls.
+//
+// See TaggedStringPtr for more information about the types of string values
+// being held, and the mutable and ownership invariants for each type.
+struct PROTOBUF_EXPORT ArenaStringPtr {
+  ArenaStringPtr() = default;
+  constexpr ArenaStringPtr(ExplicitlyConstructedArenaString* default_value,
+                           ConstantInitialized)
+      : tagged_ptr_(default_value) {}
+
+  // Called from generated code / reflection runtime only. Resets value to point
+  // to a default string pointer, with the semantics that this ArenaStringPtr
+  // does not own the pointed-to memory. Disregards initial value of ptr_ (so
+  // this is the *ONLY* safe method to call after construction or when
+  // reinitializing after becoming the active field in a oneof union).
+  inline void InitDefault();
+
+  // Similar to `InitDefault` except that it allows the default value to be
+  // initialized to an externally owned string. This method is called from
+  // parsing code. `str` must not be null and outlive this instance.
+  inline void InitExternal(const std::string* str);
+
+  // Called from generated code / reflection runtime only. Resets the value of
+  // this instances to the heap allocated value in `str`. `str` must not be
+  // null. Invokes `arena->Own(str)` to transfer ownership into the arena if
+  // `arena` is not null, else, `str` will be owned by ArenaStringPtr. This
+  // function should only be used to initialize a ArenaStringPtr or on an
+  // instance known to not carry any heap allocated value.
+  inline void InitAllocated(std::string* str, Arena* arena);
+
+  void Set(ConstStringParam value, Arena* arena);
+  void Set(std::string&& value, Arena* arena);
+  void Set(const char* s, Arena* arena);
+  void Set(const char* s, size_t n, Arena* arena);
+
+  void SetBytes(ConstStringParam value, Arena* arena);
+  void SetBytes(std::string&& value, Arena* arena);
+  void SetBytes(const char* s, Arena* arena);
+  void SetBytes(const void* p, size_t n, Arena* arena);
+
+  template <typename RefWrappedType>
+  void Set(std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena) {
+    Set(const_string_ref.get(), arena);
+  }
+
+  // Returns a mutable std::string reference.
+  // The version accepting a `LazyString` value is used in the generated code to
+  // initialize mutable copies for fields with a non-empty default where the
+  // default value is lazily initialized.
+  std::string* Mutable(Arena* arena);
+  std::string* Mutable(const LazyString& default_value, Arena* arena);
+
+  // Gets a mutable pointer with unspecified contents.
+  // This function is identical to Mutable(), except it is optimized for the
+  // case where the caller is not interested in the current contents. For
+  // example, if the current field is not mutable, it will re-initialize the
+  // value with an empty string rather than a (non-empty) default value.
+  // Likewise, if the current value is a fixed size arena string with contents,
+  // it will be initialized into an empty mutable arena string.
+  std::string* MutableNoCopy(Arena* arena);
+
+  // Basic accessors.
+  PROTOBUF_NDEBUG_INLINE const std::string& Get() const {
+    // Unconditionally mask away the tag.
+    return *tagged_ptr_.Get();
+  }
+
+  // Returns a pointer to the stored contents for this instance.
+  // This method is for internal debugging and tracking purposes only.
+  PROTOBUF_NDEBUG_INLINE const std::string* UnsafeGetPointer() const
+      PROTOBUF_RETURNS_NONNULL {
+    return tagged_ptr_.Get();
+  }
+
+  // Release returns a std::string* instance that is heap-allocated and is not
+  // Own()'d by any arena. If the field is not set, this returns nullptr. The
+  // caller retains ownership. Clears this field back to the default state.
+  // Used to implement release_<field>() methods on generated classes.
+  PROTOBUF_NODISCARD std::string* Release();
+
+  // Takes a std::string that is heap-allocated, and takes ownership. The
+  // std::string's destructor is registered with the arena. Used to implement
+  // set_allocated_<field> in generated classes.
+  void SetAllocated(std::string* value, Arena* arena);
+
+  // Frees storage (if not on an arena).
+  void Destroy();
+
+  // Clears content, but keeps allocated std::string, to avoid the overhead of
+  // heap operations. After this returns, the content (as seen by the user) will
+  // always be the empty std::string. Assumes that |default_value| is an empty
+  // std::string.
+  void ClearToEmpty();
+
+  // Clears content, assuming that the current value is not the empty
+  // string default.
+  void ClearNonDefaultToEmpty();
+
+  // Clears content, but keeps allocated std::string if arena != nullptr, to
+  // avoid the overhead of heap operations. After this returns, the content
+  // (as seen by the user) will always be equal to |default_value|.
+  void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
+
+  // 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 PROTOBUF_NDEBUG_INLINE static void InternalSwap(ArenaStringPtr* rhs,
+                                                         Arena* rhs_arena,
+                                                         ArenaStringPtr* lhs,
+                                                         Arena* lhs_arena);
+
+  // Internal setter used only at parse time to directly set a donated string
+  // value.
+  void UnsafeSetTaggedPointer(TaggedStringPtr value) { tagged_ptr_ = value; }
+  // Generated code only! An optimization, in certain cases the generated
+  // code is certain we can obtain a std::string with no default checks and
+  // tag tests.
+  std::string* UnsafeMutablePointer() PROTOBUF_RETURNS_NONNULL;
+
+  // Returns true if this instances holds an immutable default value.
+  inline bool IsDefault() const { return tagged_ptr_.IsDefault(); }
+
+ private:
+  template <typename... Args>
+  inline std::string* NewString(Arena* arena, Args&&... args) {
+    if (arena == nullptr) {
+      auto* s = new std::string(std::forward<Args>(args)...);
+      return tagged_ptr_.SetAllocated(s);
+    } else {
+      auto* s = Arena::Create<std::string>(arena, std::forward<Args>(args)...);
+      return tagged_ptr_.SetMutableArena(s);
+    }
+  }
+
+  TaggedStringPtr tagged_ptr_;
+
+  bool IsFixedSizeArena() const { return false; }
+
+  // Swaps tagged pointer without debug hardening. This is to allow python
+  // protobuf to maintain pointer stability even in DEBUG builds.
+  inline PROTOBUF_NDEBUG_INLINE static void UnsafeShallowSwap(
+      ArenaStringPtr* rhs, ArenaStringPtr* lhs) {
+    std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
+  }
+
+  friend class ::google::protobuf::internal::SwapFieldHelper;
+  friend class TcParser;
+
+  // Slow paths.
+
+  // MutableSlow requires that !IsString() || IsDefault
+  // Variadic to support 0 args for empty default and 1 arg for LazyString.
+  template <typename... Lazy>
+  std::string* MutableSlow(::google::protobuf::Arena* arena, const Lazy&... lazy_default);
+
+  friend class EpsCopyInputStream;
+};
+
+inline void ArenaStringPtr::InitDefault() {
+  tagged_ptr_ = TaggedStringPtr(&fixed_address_empty_string);
+}
+
+inline void ArenaStringPtr::InitExternal(const std::string* str) {
+  tagged_ptr_.SetDefault(str);
+}
+
+inline void ArenaStringPtr::InitAllocated(std::string* str, Arena* arena) {
+  if (arena != nullptr) {
+    tagged_ptr_.SetMutableArena(str);
+    arena->Own(str);
+  } else {
+    tagged_ptr_.SetAllocated(str);
+  }
+}
+
+inline void ArenaStringPtr::Set(const char* s, Arena* arena) {
+  Set(ConstStringParam{s}, arena);
+}
+
+inline void ArenaStringPtr::Set(const char* s, size_t n, Arena* arena) {
+  Set(ConstStringParam{s, n}, arena);
+}
+
+inline void ArenaStringPtr::SetBytes(ConstStringParam value, Arena* arena) {
+  Set(value, arena);
+}
+
+inline void ArenaStringPtr::SetBytes(std::string&& value, Arena* arena) {
+  Set(std::move(value), arena);
+}
+
+inline void ArenaStringPtr::SetBytes(const char* s, Arena* arena) {
+  Set(s, arena);
+}
+
+inline void ArenaStringPtr::SetBytes(const void* p, size_t n, Arena* arena) {
+  Set(ConstStringParam{static_cast<const char*>(p), n}, arena);
+}
+
+// Make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
+inline PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap(  //
+    ArenaStringPtr* rhs, Arena* rhs_arena,                        //
+    ArenaStringPtr* lhs, Arena* lhs_arena) {
+  // Silence unused variable warnings in release buildls.
+  (void)rhs_arena;
+  (void)lhs_arena;
+  std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  auto force_realloc = [](ArenaStringPtr* p, Arena* arena) {
+    if (p->IsDefault()) return;
+    std::string* old_value = p->tagged_ptr_.Get();
+    std::string* new_value =
+        p->IsFixedSizeArena()
+            ? Arena::Create<std::string>(arena, *old_value)
+            : Arena::Create<std::string>(arena, std::move(*old_value));
+    if (arena == nullptr) {
+      delete old_value;
+      p->tagged_ptr_.SetAllocated(new_value);
+    } else {
+      p->tagged_ptr_.SetMutableArena(new_value);
+    }
+  };
+  // Because, at this point, tagged_ptr_ has been swapped, arena should also be
+  // swapped.
+  force_realloc(lhs, rhs_arena);
+  force_realloc(rhs, lhs_arena);
+#endif  // PROTOBUF_FORCE_COPY_IN_SWAP
+}
+
+inline void ArenaStringPtr::ClearNonDefaultToEmpty() {
+  // Unconditionally mask away the tag.
+  tagged_ptr_.Get()->clear();
+}
+
+inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
+  GOOGLE_DCHECK(tagged_ptr_.IsMutable());
+  GOOGLE_DCHECK(tagged_ptr_.Get() != nullptr);
+  return tagged_ptr_.Get();
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ARENASTRING_H__
diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc
new file mode 100644
index 0000000..0e5ea9b
--- /dev/null
+++ b/src/google/protobuf/arenastring_unittest.cc
@@ -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.
+
+#include <google/protobuf/arenastring.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message_lite.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+using internal::ArenaStringPtr;
+
+const internal::LazyString nonempty_default{{{"default", 7}}, {nullptr}};
+const std::string* empty_default = &internal::GetEmptyString();
+
+class SingleArena : public testing::TestWithParam<bool> {
+ public:
+  std::unique_ptr<Arena> GetArena() {
+    if (this->GetParam()) return nullptr;
+    return std::unique_ptr<Arena>(new Arena());
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(ArenaString, SingleArena, testing::Bool());
+
+TEST_P(SingleArena, GetSet) {
+  auto arena = GetArena();
+  ArenaStringPtr field;
+  field.InitDefault();
+  EXPECT_EQ("", field.Get());
+  field.Set("Test short", arena.get());
+  EXPECT_EQ("Test short", field.Get());
+  field.Set("Test long long long long value", arena.get());
+  EXPECT_EQ("Test long long long long value", field.Get());
+  field.Set("", arena.get());
+  field.Destroy();
+}
+
+TEST_P(SingleArena, MutableAccessor) {
+  auto arena = GetArena();
+  ArenaStringPtr field;
+  field.InitDefault();
+
+  std::string* mut = field.Mutable(arena.get());
+  EXPECT_EQ(mut, field.Mutable(arena.get()));
+  EXPECT_EQ(mut, &field.Get());
+  EXPECT_NE(empty_default, mut);
+  EXPECT_EQ("", *mut);
+  *mut = "Test long long long long value";  // ensure string allocates storage
+  EXPECT_EQ("Test long long long long value", field.Get());
+  field.Destroy();
+}
+
+TEST_P(SingleArena, NullDefault) {
+  auto arena = GetArena();
+
+  ArenaStringPtr field;
+  field.InitDefault();
+  std::string* mut = field.Mutable(nonempty_default, arena.get());
+  EXPECT_EQ(mut, field.Mutable(nonempty_default, arena.get()));
+  EXPECT_EQ(mut, &field.Get());
+  EXPECT_NE(nullptr, mut);
+  EXPECT_EQ("default", *mut);
+  *mut = "Test long long long long value";  // ensure string allocates storage
+  EXPECT_EQ("Test long long long long value", field.Get());
+  field.Destroy();
+}
+
+class DualArena : public testing::TestWithParam<std::tuple<bool, bool>> {
+ public:
+  std::unique_ptr<Arena> GetLhsArena() {
+    if (std::get<0>(this->GetParam())) return nullptr;
+    return std::unique_ptr<Arena>(new Arena());
+  }
+  std::unique_ptr<Arena> GetRhsArena() {
+    if (std::get<1>(this->GetParam())) return nullptr;
+    return std::unique_ptr<Arena>(new Arena());
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(ArenaString, DualArena,
+                         testing::Combine(testing::Bool(), testing::Bool()));
+
+TEST_P(DualArena, Swap) {
+  auto lhs_arena = GetLhsArena();
+  ArenaStringPtr lhs;
+  lhs.InitDefault();
+  ArenaStringPtr rhs;
+  rhs.InitDefault();
+
+  {
+    auto rhs_arena = GetRhsArena();
+    lhs.Set("lhs value that has some heft", lhs_arena.get());
+    rhs.Set("rhs value that has some heft", rhs_arena.get());
+    ArenaStringPtr::InternalSwap(&lhs, lhs_arena.get(),  //
+                                 &rhs, rhs_arena.get());
+    EXPECT_EQ("rhs value that has some heft", lhs.Get());
+    EXPECT_EQ("lhs value that has some heft", rhs.Get());
+    lhs.Destroy();
+  }
+  EXPECT_EQ("lhs value that has some heft", rhs.Get());
+  rhs.Destroy();
+}
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/arenaz_sampler.cc b/src/google/protobuf/arenaz_sampler.cc
new file mode 100644
index 0000000..0eac693
--- /dev/null
+++ b/src/google/protobuf/arenaz_sampler.cc
@@ -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.
+
+#include <google/protobuf/arenaz_sampler.h>
+
+#include <atomic>
+#include <cstdint>
+#include <limits>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler() {
+  static auto* sampler = new ThreadSafeArenazSampler();
+  return *sampler;
+}
+
+void UnsampleSlow(ThreadSafeArenaStats* info) {
+  GlobalThreadSafeArenazSampler().Unregister(info);
+}
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+namespace {
+
+PROTOBUF_CONSTINIT std::atomic<bool> g_arenaz_enabled{true};
+PROTOBUF_CONSTINIT std::atomic<int32_t> g_arenaz_sample_parameter{1 << 10};
+PROTOBUF_THREAD_LOCAL absl::profiling_internal::ExponentialBiased
+    g_exponential_biased_generator;
+
+}  // namespace
+
+PROTOBUF_THREAD_LOCAL int64_t global_next_sample = 1LL << 10;
+
+ThreadSafeArenaStats::ThreadSafeArenaStats() { PrepareForSampling(); }
+ThreadSafeArenaStats::~ThreadSafeArenaStats() = default;
+
+void ThreadSafeArenaStats::PrepareForSampling() {
+  num_allocations.store(0, std::memory_order_relaxed);
+  num_resets.store(0, std::memory_order_relaxed);
+  bytes_requested.store(0, std::memory_order_relaxed);
+  bytes_allocated.store(0, std::memory_order_relaxed);
+  bytes_wasted.store(0, std::memory_order_relaxed);
+  max_bytes_allocated.store(0, std::memory_order_relaxed);
+  thread_ids.store(0, std::memory_order_relaxed);
+  // The inliner makes hardcoded skip_count difficult (especially when combined
+  // with LTO).  We use the ability to exclude stacks by regex when encoding
+  // instead.
+  depth = absl::GetStackTrace(stack, kMaxStackDepth, /* skip_count= */ 0);
+}
+
+void RecordResetSlow(ThreadSafeArenaStats* info) {
+  const size_t max_bytes =
+      info->max_bytes_allocated.load(std::memory_order_relaxed);
+  const size_t allocated_bytes =
+      info->bytes_allocated.load(std::memory_order_relaxed);
+  if (max_bytes < allocated_bytes) {
+    info->max_bytes_allocated.store(allocated_bytes);
+  }
+  info->bytes_requested.store(0, std::memory_order_relaxed);
+  info->bytes_allocated.store(0, std::memory_order_relaxed);
+  info->bytes_wasted.fetch_add(0, std::memory_order_relaxed);
+  info->num_allocations.fetch_add(0, std::memory_order_relaxed);
+  info->num_resets.fetch_add(1, std::memory_order_relaxed);
+}
+
+void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
+                        size_t allocated, size_t wasted) {
+  info->bytes_requested.fetch_add(requested, std::memory_order_relaxed);
+  info->bytes_allocated.fetch_add(allocated, std::memory_order_relaxed);
+  info->bytes_wasted.fetch_add(wasted, std::memory_order_relaxed);
+  info->num_allocations.fetch_add(1, std::memory_order_relaxed);
+  const uint64_t tid = (1ULL << (GetCachedTID() % 63));
+  const uint64_t thread_ids = info->thread_ids.load(std::memory_order_relaxed);
+  if (!(thread_ids & tid)) {
+    info->thread_ids.store(thread_ids | tid, std::memory_order_relaxed);
+  }
+}
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
+  bool first = *next_sample < 0;
+  *next_sample = g_exponential_biased_generator.GetStride(
+      g_arenaz_sample_parameter.load(std::memory_order_relaxed));
+  // Small values of interval are equivalent to just sampling next time.
+  ABSL_ASSERT(*next_sample >= 1);
+
+  // g_arenaz_enabled can be dynamically flipped, we need to set a threshold low
+  // enough that we will start sampling in a reasonable time, so we just use the
+  // default sampling rate.
+  if (!g_arenaz_enabled.load(std::memory_order_relaxed)) return nullptr;
+  // We will only be negative on our first count, so we should just retry in
+  // that case.
+  if (first) {
+    if (PROTOBUF_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
+    return SampleSlow(next_sample);
+  }
+
+  return GlobalThreadSafeArenazSampler().Register();
+}
+
+void SetThreadSafeArenazEnabled(bool enabled) {
+  g_arenaz_enabled.store(enabled, std::memory_order_release);
+}
+
+void SetThreadSafeArenazSampleParameter(int32_t rate) {
+  if (rate > 0) {
+    g_arenaz_sample_parameter.store(rate, std::memory_order_release);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz sample rate: %lld",
+                 static_cast<long long>(rate));  // NOLINT(runtime/int)
+  }
+}
+
+void SetThreadSafeArenazMaxSamples(int32_t max) {
+  if (max > 0) {
+    GlobalThreadSafeArenazSampler().SetMaxSamples(max);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz max samples: %lld",
+                 static_cast<long long>(max));  // NOLINT(runtime/int)
+  }
+}
+
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {
+  if (next_sample >= 0) {
+    global_next_sample = next_sample;
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz next sample: %lld",
+                 static_cast<long long>(next_sample));  // NOLINT(runtime/int)
+  }
+}
+
+#else
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
+  *next_sample = std::numeric_limits<int64_t>::max();
+  return nullptr;
+}
+
+void SetThreadSafeArenazEnabled(bool enabled) {}
+void SetThreadSafeArenazSampleParameter(int32_t rate) {}
+void SetThreadSafeArenazMaxSamples(int32_t max) {}
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arenaz_sampler.h b/src/google/protobuf/arenaz_sampler.h
new file mode 100644
index 0000000..b04b0cc
--- /dev/null
+++ b/src/google/protobuf/arenaz_sampler.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
+#define GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+struct ThreadSafeArenaStats;
+void RecordResetSlow(ThreadSafeArenaStats* info);
+void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
+                        size_t allocated, size_t wasted);
+// Stores information about a sampled thread safe arena.  All mutations to this
+// *must* be made through `Record*` functions below.  All reads from this *must*
+// only occur in the callback to `ThreadSafeArenazSampler::Iterate`.
+struct ThreadSafeArenaStats
+    : public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
+  // Constructs the object but does not fill in any fields.
+  ThreadSafeArenaStats();
+  ~ThreadSafeArenaStats();
+
+  // Puts the object into a clean state, fills in the logically `const` members,
+  // blocking for any readers that are currently sampling the object.
+  void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+
+  // These fields are mutated by the various Record* APIs and need to be
+  // thread-safe.
+  std::atomic<int> num_allocations;
+  std::atomic<int> num_resets;
+  std::atomic<size_t> bytes_requested;
+  std::atomic<size_t> bytes_allocated;
+  std::atomic<size_t> bytes_wasted;
+  // Records the largest size an arena ever had.  Maintained across resets.
+  std::atomic<size_t> max_bytes_allocated;
+  // Bit i when set to 1 indicates that a thread with tid % 63 = i accessed the
+  // underlying arena.  The field is maintained across resets.
+  std::atomic<uint64_t> thread_ids;
+
+  // All of the fields below are set by `PrepareForSampling`, they must not
+  // be mutated in `Record*` functions.  They are logically `const` in that
+  // sense. These are guarded by init_mu, but that is not externalized to
+  // clients, who can only read them during
+  // `ThreadSafeArenazSampler::Iterate` which will hold the lock.
+  static constexpr int kMaxStackDepth = 64;
+  int32_t depth;
+  void* stack[kMaxStackDepth];
+  static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t requested,
+                                  size_t allocated, size_t wasted) {
+    if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
+    RecordAllocateSlow(info, requested, allocated, wasted);
+  }
+};
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(ThreadSafeArenaStats* info);
+
+class ThreadSafeArenaStatsHandle {
+ public:
+  explicit ThreadSafeArenaStatsHandle() = default;
+  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
+      : info_(info) {}
+
+  ~ThreadSafeArenaStatsHandle() {
+    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
+    UnsampleSlow(info_);
+  }
+
+  ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
+      : info_(absl::exchange(other.info_, nullptr)) {}
+
+  ThreadSafeArenaStatsHandle& operator=(
+      ThreadSafeArenaStatsHandle&& other) noexcept {
+    if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
+      UnsampleSlow(info_);
+    }
+    info_ = absl::exchange(other.info_, nullptr);
+    return *this;
+  }
+
+  void RecordReset() {
+    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordResetSlow(info_);
+  }
+
+  ThreadSafeArenaStats* MutableStats() { return info_; }
+
+  friend void swap(ThreadSafeArenaStatsHandle& lhs,
+                   ThreadSafeArenaStatsHandle& rhs) {
+    std::swap(lhs.info_, rhs.info_);
+  }
+
+  friend class ThreadSafeArenaStatsHandlePeer;
+
+ private:
+  ThreadSafeArenaStats* info_ = nullptr;
+};
+
+using ThreadSafeArenazSampler =
+    ::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
+
+extern PROTOBUF_THREAD_LOCAL int64_t global_next_sample;
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline ThreadSafeArenaStatsHandle Sample() {
+  if (PROTOBUF_PREDICT_TRUE(--global_next_sample > 0)) {
+    return ThreadSafeArenaStatsHandle(nullptr);
+  }
+  return ThreadSafeArenaStatsHandle(SampleSlow(&global_next_sample));
+}
+
+#else
+struct ThreadSafeArenaStats {
+  static void RecordAllocateStats(ThreadSafeArenaStats*, size_t /*requested*/,
+                                  size_t /*allocated*/, size_t /*wasted*/) {}
+};
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(ThreadSafeArenaStats* info);
+
+class ThreadSafeArenaStatsHandle {
+ public:
+  explicit ThreadSafeArenaStatsHandle() = default;
+  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
+
+  void RecordReset() {}
+
+  ThreadSafeArenaStats* MutableStats() { return nullptr; }
+
+  friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
+
+ private:
+  friend class ThreadSafeArenaStatsHandlePeer;
+};
+
+class ThreadSafeArenazSampler {
+ public:
+  void Unregister(ThreadSafeArenaStats*) {}
+  void SetMaxSamples(int32_t) {}
+};
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline ThreadSafeArenaStatsHandle Sample() {
+  return ThreadSafeArenaStatsHandle(nullptr);
+}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+// Returns a global Sampler.
+ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
+
+// Enables or disables sampling for thread safe arenas.
+void SetThreadSafeArenazEnabled(bool enabled);
+
+// Sets the rate at which thread safe arena will be sampled.
+void SetThreadSafeArenazSampleParameter(int32_t rate);
+
+// Sets a soft max for the number of samples that will be kept.
+void SetThreadSafeArenazMaxSamples(int32_t max);
+
+// Sets the current value for when arenas should be next sampled.
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_SRC_PROTOBUF_ARENAZ_SAMPLER_H__
diff --git a/src/google/protobuf/arenaz_sampler_test.cc b/src/google/protobuf/arenaz_sampler_test.cc
new file mode 100644
index 0000000..1bfec54
--- /dev/null
+++ b/src/google/protobuf/arenaz_sampler_test.cc
@@ -0,0 +1,382 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arenaz_sampler.h>
+
+#include <memory>
+#include <random>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+class ThreadSafeArenaStatsHandlePeer {
+ public:
+  static bool IsSampled(const ThreadSafeArenaStatsHandle& h) {
+    return h.info_ != nullptr;
+  }
+
+  static ThreadSafeArenaStats* GetInfo(ThreadSafeArenaStatsHandle* h) {
+    return h->info_;
+  }
+};
+std::vector<size_t> GetBytesAllocated(ThreadSafeArenazSampler* s) {
+  std::vector<size_t> res;
+  s->Iterate([&](const ThreadSafeArenaStats& info) {
+    res.push_back(info.bytes_allocated.load(std::memory_order_acquire));
+  });
+  return res;
+}
+
+ThreadSafeArenaStats* Register(ThreadSafeArenazSampler* s, size_t size) {
+  auto* info = s->Register();
+  assert(info != nullptr);
+  info->bytes_allocated.store(size);
+  return info;
+}
+
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+namespace {
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+
+TEST(ThreadSafeArenaStatsTest, PrepareForSampling) {
+  ThreadSafeArenaStats info;
+  MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+
+  EXPECT_EQ(info.num_allocations.load(), 0);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+  EXPECT_EQ(info.bytes_wasted.load(), 0);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+
+  info.num_allocations.store(1, std::memory_order_relaxed);
+  info.num_resets.store(1, std::memory_order_relaxed);
+  info.bytes_requested.store(1, std::memory_order_relaxed);
+  info.bytes_allocated.store(1, std::memory_order_relaxed);
+  info.bytes_wasted.store(1, std::memory_order_relaxed);
+  info.max_bytes_allocated.store(1, std::memory_order_relaxed);
+
+  info.PrepareForSampling();
+  EXPECT_EQ(info.num_allocations.load(), 0);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+  EXPECT_EQ(info.bytes_wasted.load(), 0);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+}
+
+TEST(ThreadSafeArenaStatsTest, RecordAllocateSlow) {
+  ThreadSafeArenaStats info;
+  MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+  RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
+  EXPECT_EQ(info.num_allocations.load(), 1);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 100);
+  EXPECT_EQ(info.bytes_allocated.load(), 128);
+  EXPECT_EQ(info.bytes_wasted.load(), 0);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+  RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
+                     /*wasted=*/28);
+  EXPECT_EQ(info.num_allocations.load(), 2);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 200);
+  EXPECT_EQ(info.bytes_allocated.load(), 384);
+  EXPECT_EQ(info.bytes_wasted.load(), 28);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+}
+
+TEST(ThreadSafeArenaStatsTest, RecordResetSlow) {
+  ThreadSafeArenaStats info;
+  MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+  RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 128);
+  RecordResetSlow(&info);
+  EXPECT_EQ(info.num_resets.load(), 1);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+}
+
+TEST(ThreadSafeArenazSamplerTest, SmallSampleParameter) {
+  SetThreadSafeArenazEnabled(true);
+  SetThreadSafeArenazSampleParameter(100);
+
+  for (int i = 0; i < 1000; ++i) {
+    int64_t next_sample = 0;
+    ThreadSafeArenaStats* sample = SampleSlow(&next_sample);
+    EXPECT_GT(next_sample, 0);
+    EXPECT_NE(sample, nullptr);
+    UnsampleSlow(sample);
+  }
+}
+
+TEST(ThreadSafeArenazSamplerTest, LargeSampleParameter) {
+  SetThreadSafeArenazEnabled(true);
+  SetThreadSafeArenazSampleParameter(std::numeric_limits<int32_t>::max());
+
+  for (int i = 0; i < 1000; ++i) {
+    int64_t next_sample = 0;
+    ThreadSafeArenaStats* sample = SampleSlow(&next_sample);
+    EXPECT_GT(next_sample, 0);
+    EXPECT_NE(sample, nullptr);
+    UnsampleSlow(sample);
+  }
+}
+
+TEST(ThreadSafeArenazSamplerTest, Sample) {
+  SetThreadSafeArenazEnabled(true);
+  SetThreadSafeArenazSampleParameter(100);
+  SetThreadSafeArenazGlobalNextSample(0);
+  int64_t num_sampled = 0;
+  int64_t total = 0;
+  double sample_rate = 0.0;
+  for (int i = 0; i < 1000000; ++i) {
+    ThreadSafeArenaStatsHandle h = Sample();
+    ++total;
+    if (ThreadSafeArenaStatsHandlePeer::IsSampled(h)) {
+      ++num_sampled;
+    }
+    sample_rate = static_cast<double>(num_sampled) / total;
+    if (0.005 < sample_rate && sample_rate < 0.015) break;
+  }
+  EXPECT_NEAR(sample_rate, 0.01, 0.005);
+}
+
+TEST(ThreadSafeArenazSamplerTest, Handle) {
+  auto& sampler = GlobalThreadSafeArenazSampler();
+  ThreadSafeArenaStatsHandle h(sampler.Register());
+  auto* info = ThreadSafeArenaStatsHandlePeer::GetInfo(&h);
+  info->bytes_allocated.store(0x12345678, std::memory_order_relaxed);
+
+  bool found = false;
+  sampler.Iterate([&](const ThreadSafeArenaStats& h) {
+    if (&h == info) {
+      EXPECT_EQ(h.bytes_allocated.load(), 0x12345678);
+      found = true;
+    }
+  });
+  EXPECT_TRUE(found);
+
+  h = ThreadSafeArenaStatsHandle();
+  found = false;
+  sampler.Iterate([&](const ThreadSafeArenaStats& h) {
+    if (&h == info) {
+      // this will only happen if some other thread has resurrected the info
+      // the old handle was using.
+      if (h.bytes_allocated.load() == 0x12345678) {
+        found = true;
+      }
+    }
+  });
+  EXPECT_FALSE(found);
+}
+
+TEST(ThreadSafeArenazSamplerTest, Registration) {
+  ThreadSafeArenazSampler sampler;
+  auto* info1 = Register(&sampler, 1);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1));
+
+  auto* info2 = Register(&sampler, 2);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 2));
+  info1->bytes_allocated.store(3);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(3, 2));
+
+  sampler.Unregister(info1);
+  sampler.Unregister(info2);
+}
+
+TEST(ThreadSafeArenazSamplerTest, Unregistration) {
+  ThreadSafeArenazSampler sampler;
+  std::vector<ThreadSafeArenaStats*> infos;
+  for (size_t i = 0; i < 3; ++i) {
+    infos.push_back(Register(&sampler, i));
+  }
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 1, 2));
+
+  sampler.Unregister(infos[1]);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 2));
+
+  infos.push_back(Register(&sampler, 3));
+  infos.push_back(Register(&sampler, 4));
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 2, 3, 4));
+  sampler.Unregister(infos[3]);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 2, 4));
+
+  sampler.Unregister(infos[0]);
+  sampler.Unregister(infos[2]);
+  sampler.Unregister(infos[4]);
+  EXPECT_THAT(GetBytesAllocated(&sampler), IsEmpty());
+}
+
+TEST(ThreadSafeArenazSamplerTest, MultiThreaded) {
+  ThreadSafeArenazSampler sampler;
+  absl::Notification stop;
+  ThreadPool pool(10);
+
+  for (int i = 0; i < 10; ++i) {
+    pool.Schedule([&sampler, &stop]() {
+      std::random_device rd;
+      std::mt19937 gen(rd());
+
+      std::vector<ThreadSafeArenaStats*> infoz;
+      while (!stop.HasBeenNotified()) {
+        if (infoz.empty()) {
+          infoz.push_back(sampler.Register());
+        }
+        switch (std::uniform_int_distribution<>(0, 1)(gen)) {
+          case 0: {
+            infoz.push_back(sampler.Register());
+            break;
+          }
+          case 1: {
+            size_t p =
+                std::uniform_int_distribution<>(0, infoz.size() - 1)(gen);
+            ThreadSafeArenaStats* info = infoz[p];
+            infoz[p] = infoz.back();
+            infoz.pop_back();
+            sampler.Unregister(info);
+            break;
+          }
+        }
+      }
+    });
+  }
+  // The threads will hammer away.  Give it a little bit of time for tsan to
+  // spot errors.
+  absl::SleepFor(absl::Seconds(3));
+  stop.Notify();
+}
+
+TEST(ThreadSafeArenazSamplerTest, Callback) {
+  ThreadSafeArenazSampler sampler;
+
+  auto* info1 = Register(&sampler, 1);
+  auto* info2 = Register(&sampler, 2);
+
+  static const ThreadSafeArenaStats* expected;
+
+  auto callback = [](const ThreadSafeArenaStats& info) {
+    // We can't use `info` outside of this callback because the object will be
+    // disposed as soon as we return from here.
+    EXPECT_EQ(&info, expected);
+  };
+
+  // Set the callback.
+  EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
+  expected = info1;
+  sampler.Unregister(info1);
+
+  // Unset the callback.
+  EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
+  expected = nullptr;  // no more calls.
+  sampler.Unregister(info2);
+}
+
+class ThreadSafeArenazSamplerTestThread : public Thread {
+ protected:
+  void Run() override {
+    google::protobuf::ArenaSafeUniquePtr<
+        protobuf_test_messages::proto2::TestAllTypesProto2>
+        message = google::protobuf::MakeArenaSafeUnique<
+            protobuf_test_messages::proto2::TestAllTypesProto2>(arena_);
+    GOOGLE_CHECK(message != nullptr);
+    // Signal that a message on the arena has been created.  This should create
+    // a SerialArena for this thread.
+    if (barrier_->Block()) {
+      delete barrier_;
+    }
+  }
+
+ public:
+  ThreadSafeArenazSamplerTestThread(const thread::Options& options,
+                                    StringPiece name,
+                                    google::protobuf::Arena* arena,
+                                    absl::Barrier* barrier)
+      : Thread(options, name), arena_(arena), barrier_(barrier) {}
+
+ private:
+  google::protobuf::Arena* arena_;
+  absl::Barrier* barrier_;
+};
+
+TEST(ThreadSafeArenazSamplerTest, MultiThread) {
+  SetThreadSafeArenazEnabled(true);
+  // Setting 1 as the parameter value means one in every two arenas would be
+  // sampled, on average.
+  SetThreadSafeArenazSampleParameter(1);
+  SetThreadSafeArenazGlobalNextSample(0);
+  auto& sampler = GlobalThreadSafeArenazSampler();
+  int count = 0;
+  for (int i = 0; i < 10; ++i) {
+    const int kNumThreads = 10;
+    absl::Barrier* barrier = new absl::Barrier(kNumThreads + 1);
+    google::protobuf::Arena arena;
+    thread::Options options;
+    options.set_joinable(true);
+    std::vector<std::unique_ptr<ThreadSafeArenazSamplerTestThread>> threads;
+    for (int i = 0; i < kNumThreads; i++) {
+      auto t = std::make_unique<ThreadSafeArenazSamplerTestThread>(
+          options, StrCat("thread", i), &arena, barrier);
+      t->Start();
+      threads.push_back(std::move(t));
+    }
+    // Wait till each thread has created a message on the arena.
+    if (barrier->Block()) {
+      delete barrier;
+    }
+    sampler.Iterate([&](const ThreadSafeArenaStats& h) { ++count; });
+    for (int i = 0; i < kNumThreads; i++) {
+      threads[i]->Join();
+    }
+  }
+  EXPECT_GT(count, 0);
+}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/annotation_test_util.cc b/src/google/protobuf/compiler/annotation_test_util.cc
new file mode 100644
index 0000000..f0815c5
--- /dev/null
+++ b/src/google/protobuf/compiler/annotation_test_util.cc
@@ -0,0 +1,167 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/annotation_test_util.h>
+
+#include <cstdint>
+#include <memory>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace annotation_test_util {
+namespace {
+
+// A CodeGenerator that captures the FileDescriptor it's passed as a
+// FileDescriptorProto.
+class DescriptorCapturingGenerator : public CodeGenerator {
+ public:
+  // Does not own file; file must outlive the Generator.
+  explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
+      : file_(file) {}
+
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
+    file->CopyTo(file_);
+    return true;
+  }
+
+ private:
+  FileDescriptorProto* file_;
+};
+}  // namespace
+
+void AddFile(const std::string& filename, const std::string& data) {
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data,
+                             true));
+}
+
+bool RunProtoCompiler(const std::string& filename,
+                      const std::string& plugin_specific_args,
+                      CommandLineInterface* cli, FileDescriptorProto* file) {
+  cli->SetInputsAreProtoPathRelative(true);
+
+  DescriptorCapturingGenerator capturing_generator(file);
+  cli->RegisterGenerator("--capture_out", &capturing_generator, "");
+
+  std::string proto_path = "-I" + TestTempDir();
+  std::string capture_out = "--capture_out=" + TestTempDir();
+
+  const char* argv[] = {"protoc", proto_path.c_str(),
+                        plugin_specific_args.c_str(), capture_out.c_str(),
+                        filename.c_str()};
+
+  return cli->Run(5, argv) == 0;
+}
+
+bool DecodeMetadata(const std::string& path, GeneratedCodeInfo* info) {
+  std::string data;
+  GOOGLE_CHECK_OK(File::GetContents(path, &data, true));
+  io::ArrayInputStream input(data.data(), data.size());
+  return info->ParseFromZeroCopyStream(&input);
+}
+
+void FindAnnotationsOnPath(
+    const GeneratedCodeInfo& info, const std::string& source_file,
+    const std::vector<int>& path,
+    std::vector<const GeneratedCodeInfo::Annotation*>* annotations) {
+  for (int i = 0; i < info.annotation_size(); ++i) {
+    const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i);
+    if (annotation->source_file() != source_file ||
+        annotation->path_size() != path.size()) {
+      continue;
+    }
+    int node = 0;
+    for (; node < path.size(); ++node) {
+      if (annotation->path(node) != path[node]) {
+        break;
+      }
+    }
+    if (node == path.size()) {
+      annotations->push_back(annotation);
+    }
+  }
+}
+
+const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
+    const GeneratedCodeInfo& info, const std::string& source_file,
+    const std::vector<int>& path) {
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  FindAnnotationsOnPath(info, source_file, path, &annotations);
+  if (annotations.empty()) {
+    return nullptr;
+  }
+  return annotations[0];
+}
+
+bool AtLeastOneAnnotationMatchesSubstring(
+    const std::string& file_content,
+    const std::vector<const GeneratedCodeInfo::Annotation*>& annotations,
+    const std::string& expected_text) {
+  for (std::vector<const GeneratedCodeInfo::Annotation*>::const_iterator
+           i = annotations.begin(),
+           e = annotations.end();
+       i != e; ++i) {
+    const GeneratedCodeInfo::Annotation* annotation = *i;
+    uint32_t begin = annotation->begin();
+    uint32_t end = annotation->end();
+    if (end < begin || end > file_content.size()) {
+      return false;
+    }
+    if (file_content.substr(begin, end - begin) == expected_text) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool AnnotationMatchesSubstring(const std::string& file_content,
+                                const GeneratedCodeInfo::Annotation* annotation,
+                                const std::string& expected_text) {
+  std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+  annotations.push_back(annotation);
+  return AtLeastOneAnnotationMatchesSubstring(file_content, annotations,
+                                              expected_text);
+}
+}  // namespace annotation_test_util
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/annotation_test_util.h b/src/google/protobuf/compiler/annotation_test_util.h
new file mode 100644
index 0000000..b7c6ddd
--- /dev/null
+++ b/src/google/protobuf/compiler/annotation_test_util.h
@@ -0,0 +1,115 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_ANNOTATION_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
+
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+// Utilities that assist in writing tests for generator annotations.
+// See java/internal/annotation_unittest.cc for an example.
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace annotation_test_util {
+
+// Struct that contains the file generated from a .proto file and its
+// GeneratedCodeInfo. For example, the Java generator will fill this struct
+// (for some 'foo.proto') with:
+//   file_path = "Foo.java"
+//   file_content = content of Foo.java
+//   file_info = parsed content of Foo.java.pb.meta
+struct ExpectedOutput {
+  std::string file_path;
+  std::string file_content;
+  GeneratedCodeInfo file_info;
+  explicit ExpectedOutput(const std::string& file_path)
+      : file_path(file_path) {}
+};
+
+// Creates a file with name `filename` and content `data` in temp test
+// directory.
+void AddFile(const std::string& filename, const std::string& data);
+
+// Runs proto compiler. Captures proto file structure in FileDescriptorProto.
+// Files will be generated in TestTempDir() folder. Callers of this
+// function must read generated files themselves.
+//
+// filename: source .proto file used to generate code.
+// plugin_specific_args: command line arguments specific to current generator.
+//     For Java, this value might be "--java_out=annotate_code:test_temp_dir"
+// cli: instance of command line interface to run generator. See Java's
+//     annotation_unittest.cc for an example of how to initialize it.
+// file: output parameter, will be set to the descriptor of the proto file
+//     specified in filename.
+bool RunProtoCompiler(const std::string& filename,
+                      const std::string& plugin_specific_args,
+                      CommandLineInterface* cli, FileDescriptorProto* file);
+
+bool DecodeMetadata(const std::string& path, GeneratedCodeInfo* info);
+
+// Finds all of the Annotations for a given source file and path.
+// See Location.path in https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto for
+// explanation of what path vector is.
+void FindAnnotationsOnPath(
+    const GeneratedCodeInfo& info, const std::string& source_file,
+    const std::vector<int>& path,
+    std::vector<const GeneratedCodeInfo::Annotation*>* annotations);
+
+// Finds the Annotation for a given source file and path (or returns null if it
+// couldn't). If there are several annotations for given path, returns the first
+// one. See Location.path in
+// https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto for explanation of what path
+// vector is.
+const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
+    const GeneratedCodeInfo& info, const std::string& source_file,
+    const std::vector<int>& path);
+
+// Returns true if at least one of the provided annotations covers a given
+// substring in file_content.
+bool AtLeastOneAnnotationMatchesSubstring(
+    const std::string& file_content,
+    const std::vector<const GeneratedCodeInfo::Annotation*>& annotations,
+    const std::string& expected_text);
+
+// Returns true if the provided annotation covers a given substring in
+// file_content.
+bool AnnotationMatchesSubstring(const std::string& file_content,
+                                const GeneratedCodeInfo::Annotation* annotation,
+                                const std::string& expected_text);
+
+}  // namespace annotation_test_util
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc
new file mode 100644
index 0000000..dc9d450
--- /dev/null
+++ b/src/google/protobuf/compiler/code_generator.cc
@@ -0,0 +1,137 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/code_generator.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/plugin.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+CodeGenerator::~CodeGenerator() {}
+
+bool CodeGenerator::GenerateAll(const std::vector<const FileDescriptor*>& files,
+                                const std::string& parameter,
+                                GeneratorContext* generator_context,
+                                std::string* error) const {
+  // Default implementation is just to call the per file method, and prefix any
+  // error string with the file to provide context.
+  bool succeeded = true;
+  for (int i = 0; i < files.size(); i++) {
+    const FileDescriptor* file = files[i];
+    succeeded = Generate(file, parameter, generator_context, error);
+    if (!succeeded && error && error->empty()) {
+      *error =
+          "Code generator returned false but provided no error "
+          "description.";
+    }
+    if (error && !error->empty()) {
+      *error = file->name() + ": " + *error;
+      break;
+    }
+    if (!succeeded) {
+      break;
+    }
+  }
+  return succeeded;
+}
+
+GeneratorContext::~GeneratorContext() {}
+
+io::ZeroCopyOutputStream* GeneratorContext::OpenForAppend(
+    const std::string& filename) {
+  return nullptr;
+}
+
+io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
+    const std::string& filename, const std::string& insertion_point) {
+  GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
+  return nullptr;  // make compiler happy
+}
+
+io::ZeroCopyOutputStream* GeneratorContext::OpenForInsertWithGeneratedCodeInfo(
+    const std::string& filename, const std::string& insertion_point,
+    const google::protobuf::GeneratedCodeInfo& /*info*/) {
+  return OpenForInsert(filename, insertion_point);
+}
+
+void GeneratorContext::ListParsedFiles(
+    std::vector<const FileDescriptor*>* output) {
+  GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
+}
+
+void GeneratorContext::GetCompilerVersion(Version* version) const {
+  version->set_major(GOOGLE_PROTOBUF_VERSION / 1000000);
+  version->set_minor(GOOGLE_PROTOBUF_VERSION / 1000 % 1000);
+  version->set_patch(GOOGLE_PROTOBUF_VERSION % 1000);
+  version->set_suffix(GOOGLE_PROTOBUF_VERSION_SUFFIX);
+}
+
+// Parses a set of comma-delimited name/value pairs.
+void ParseGeneratorParameter(
+    const std::string& text,
+    std::vector<std::pair<std::string, std::string> >* output) {
+  std::vector<std::string> parts = Split(text, ",", true);
+
+  for (int i = 0; i < parts.size(); i++) {
+    std::string::size_type equals_pos = parts[i].find_first_of('=');
+    std::pair<std::string, std::string> value;
+    if (equals_pos == std::string::npos) {
+      value.first = parts[i];
+      value.second = "";
+    } else {
+      value.first = parts[i].substr(0, equals_pos);
+      value.second = parts[i].substr(equals_pos + 1);
+    }
+    output->push_back(value);
+  }
+}
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+std::string StripProto(const std::string& filename) {
+  if (HasSuffixString(filename, ".protodevel")) {
+    return StripSuffixString(filename, ".protodevel");
+  } else {
+    return StripSuffixString(filename, ".proto");
+  }
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
new file mode 100644
index 0000000..9c0b115
--- /dev/null
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Defines the abstract interface implemented by each of the language-specific
+// code generators.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
+
+#include <string>
+#include <utility>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class ZeroCopyOutputStream;
+}
+class FileDescriptor;
+class GeneratedCodeInfo;
+
+namespace compiler {
+class AccessInfoMap;
+
+class Version;
+
+// Defined in this file.
+class CodeGenerator;
+class GeneratorContext;
+
+// The abstract interface to a class which generates code implementing a
+// particular proto file in a particular language.  A number of these may
+// be registered with CommandLineInterface to support various languages.
+class PROTOC_EXPORT CodeGenerator {
+ public:
+  inline CodeGenerator() {}
+  virtual ~CodeGenerator();
+
+  // Generates code for the given proto file, generating one or more files in
+  // the given output directory.
+  //
+  // A parameter to be passed to the generator can be specified on the command
+  // line. This is intended to be used to pass generator specific parameters.
+  // It is empty if no parameter was given. ParseGeneratorParameter (below),
+  // can be used to accept multiple parameters within the single parameter
+  // command line flag.
+  //
+  // Returns true if successful.  Otherwise, sets *error to a description of
+  // the problem (e.g. "invalid parameter") and returns false.
+  virtual bool Generate(const FileDescriptor* file,
+                        const std::string& parameter,
+                        GeneratorContext* generator_context,
+                        std::string* error) const = 0;
+
+  // Generates code for all given proto files.
+  //
+  // WARNING: The canonical code generator design produces one or two output
+  // files 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 std::vector<const FileDescriptor*>& files,
+                           const std::string& parameter,
+                           GeneratorContext* generator_context,
+                           std::string* error) const;
+
+  // This must be kept in sync with plugin.proto. See that file for
+  // documentation on each value.
+  enum Feature {
+    FEATURE_PROTO3_OPTIONAL = 1,
+  };
+
+  // Implement this to indicate what features this code generator supports.
+  //
+  // This must be a bitwise OR of values from the Feature enum above (or zero).
+  virtual uint64_t GetSupportedFeatures() const { return 0; }
+
+  // This is no longer used, but this class is part of the opensource protobuf
+  // library, so it has to remain to keep vtables the same for the current
+  // version of the library. When protobufs does a api breaking change, the
+  // method can be removed.
+  virtual bool HasGenerateAll() const { return true; }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator);
+};
+
+// CodeGenerators generate one or more files in a given directory.  This
+// abstract interface represents the directory to which the CodeGenerator is
+// to write and other information about the context in which the Generator
+// runs.
+class PROTOC_EXPORT GeneratorContext {
+ public:
+  inline GeneratorContext() {
+  }
+  virtual ~GeneratorContext();
+
+  // Opens the given file, truncating it if it exists, and returns a
+  // ZeroCopyOutputStream that writes to the file.  The caller takes ownership
+  // of the returned object.  This method never fails (a dummy stream will be
+  // returned instead).
+  //
+  // The filename given should be relative to the root of the source tree.
+  // E.g. the C++ generator, when generating code for "foo/bar.proto", will
+  // generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that
+  // "foo/" is included in these filenames.  The filename is not allowed to
+  // contain "." or ".." components.
+  virtual io::ZeroCopyOutputStream* Open(const std::string& filename) = 0;
+
+  // Similar to Open() but the output will be appended to the file if exists
+  virtual io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename);
+
+  // Creates a ZeroCopyOutputStream which will insert code into the given file
+  // at the given insertion point.  See plugin.proto (plugin.pb.h) for more
+  // information on insertion points.  The default implementation
+  // assert-fails -- it exists only for backwards-compatibility.
+  //
+  // WARNING:  This feature is currently EXPERIMENTAL and is subject to change.
+  virtual io::ZeroCopyOutputStream* OpenForInsert(
+      const std::string& filename, const std::string& insertion_point);
+
+  // Similar to OpenForInsert, but if `info` is non-empty, will open (or create)
+  // filename.pb.meta and insert info at the appropriate place with the
+  // necessary shifts. The default implementation ignores `info`.
+  //
+  // WARNING:  This feature will be REMOVED in the near future.
+  virtual io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo(
+      const std::string& filename, const std::string& insertion_point,
+      const google::protobuf::GeneratedCodeInfo& info);
+
+  // Returns a vector of FileDescriptors for all the files being compiled
+  // in this run.  Useful for languages, such as Go, that treat files
+  // differently when compiled as a set rather than individually.
+  virtual void ListParsedFiles(std::vector<const FileDescriptor*>* output);
+
+  // Retrieves the version number of the protocol compiler associated with
+  // this GeneratorContext.
+  virtual void GetCompilerVersion(Version* version) const;
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext);
+};
+
+// The type GeneratorContext was once called OutputDirectory. This typedef
+// provides backward compatibility.
+typedef GeneratorContext OutputDirectory;
+
+// Several code generators treat the parameter argument as holding a
+// list of options separated by commas.  This helper function parses
+// a set of comma-delimited name/value pairs: e.g.,
+//   "foo=bar,baz,moo=corge"
+// parses to the pairs:
+//   ("foo", "bar"), ("baz", ""), ("moo", "corge")
+PROTOC_EXPORT void ParseGeneratorParameter(
+    const std::string&, std::vector<std::pair<std::string, std::string> >*);
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+PROTOC_EXPORT std::string StripProto(const std::string& filename);
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
new file mode 100644
index 0000000..5e9a2c4
--- /dev/null
+++ b/src/google/protobuf/compiler/command_line_interface.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  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>
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+
+#include <fstream>
+#include <iostream>
+
+#include <limits.h>  // For PATH_MAX
+
+#include <memory>
+
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#elif defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/compiler/subprocess.h>
+#include <google/protobuf/compiler/plugin.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/compiler/zip_writer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#ifndef O_BINARY
+#ifdef _O_BINARY
+#define O_BINARY _O_BINARY
+#else
+#define O_BINARY 0  // If this isn't defined, the platform doesn't need it.
+#endif
+#endif
+
+namespace {
+#if defined(_WIN32)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::mkdir;
+using google::protobuf::io::win32::open;
+using google::protobuf::io::win32::setmode;
+using google::protobuf::io::win32::write;
+#endif
+
+static const char* kDefaultDirectDependenciesViolationMsg =
+    "File is imported but not declared in --direct_dependencies: %s";
+
+// Returns true if the text looks like a Windows-style absolute path, starting
+// with a drive letter.  Example:  "C:\foo".  TODO(kenton):  Share this with
+// copy in importer.cc?
+static bool IsWindowsAbsolutePath(const std::string& text) {
+#if defined(_WIN32) || defined(__CYGWIN__)
+  return text.size() >= 3 && text[1] == ':' && isalpha(text[0]) &&
+         (text[2] == '/' || text[2] == '\\') && text.find_last_of(':') == 1;
+#else
+  return false;
+#endif
+}
+
+void SetFdToTextMode(int fd) {
+#ifdef _WIN32
+  if (setmode(fd, _O_TEXT) == -1) {
+    // This should never happen, I think.
+    GOOGLE_LOG(WARNING) << "setmode(" << fd << ", _O_TEXT): " << strerror(errno);
+  }
+#endif
+  // (Text and binary are the same on non-Windows platforms.)
+}
+
+void SetFdToBinaryMode(int fd) {
+#ifdef _WIN32
+  if (setmode(fd, _O_BINARY) == -1) {
+    // This should never happen, I think.
+    GOOGLE_LOG(WARNING) << "setmode(" << fd << ", _O_BINARY): " << strerror(errno);
+  }
+#endif
+  // (Text and binary are the same on non-Windows platforms.)
+}
+
+void AddTrailingSlash(std::string* path) {
+  if (!path->empty() && path->at(path->size() - 1) != '/') {
+    path->push_back('/');
+  }
+}
+
+bool VerifyDirectoryExists(const std::string& path) {
+  if (path.empty()) return true;
+
+  if (access(path.c_str(), F_OK) == -1) {
+    std::cerr << path << ": " << strerror(errno) << std::endl;
+    return false;
+  } else {
+    return true;
+  }
+}
+
+// Try to create the parent directory of the given file, creating the parent's
+// parent if necessary, and so on.  The full file name is actually
+// (prefix + filename), but we assume |prefix| already exists and only create
+// directories listed in |filename|.
+bool TryCreateParentDirectory(const std::string& prefix,
+                              const std::string& filename) {
+  // Recursively create parent directories to the output file.
+  // On Windows, both '/' and '\' are valid path separators.
+  std::vector<std::string> parts =
+      Split(filename, "/\\", true);
+  std::string path_so_far = prefix;
+  for (int i = 0; i < parts.size() - 1; i++) {
+    path_so_far += parts[i];
+    if (mkdir(path_so_far.c_str(), 0777) != 0) {
+      if (errno != EEXIST) {
+        std::cerr << filename << ": while trying to create directory "
+                  << path_so_far << ": " << strerror(errno) << std::endl;
+        return false;
+      }
+    }
+    path_so_far += '/';
+  }
+
+  return true;
+}
+
+// Get the absolute path of this protoc binary.
+bool GetProtocAbsolutePath(std::string* path) {
+#ifdef _WIN32
+  char buffer[MAX_PATH];
+  int len = GetModuleFileNameA(nullptr, buffer, MAX_PATH);
+#elif defined(__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);
+  }
+#elif defined(__FreeBSD__)
+  char buffer[PATH_MAX];
+  size_t len = PATH_MAX;
+  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+  if (sysctl(mib, 4, &buffer, &len, nullptr, 0) != 0) {
+    len = 0;
+  }
+#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 std::string& path) {
+  // Checking the descriptor.proto file should be good enough.
+  std::string file_path = path + "/google/protobuf/descriptor.proto";
+  return access(file_path.c_str(), F_OK) != -1;
+}
+
+// Add the paths where google/protobuf/descriptor.proto and other well-known
+// type protos are installed.
+void AddDefaultProtoPaths(
+    std::vector<std::pair<std::string, std::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.
+  std::string path;
+  if (!GetProtocAbsolutePath(&path)) {
+    return;
+  }
+  // Strip the binary name.
+  size_t pos = path.find_last_of("/\\");
+  if (pos == std::string::npos || pos == 0) {
+    return;
+  }
+  path = path.substr(0, pos);
+  // Check the binary's directory.
+  if (IsInstalledProtoPath(path)) {
+    paths->push_back(std::pair<std::string, std::string>("", path));
+    return;
+  }
+  // Check if there is an include subdirectory.
+  if (IsInstalledProtoPath(path + "/include")) {
+    paths->push_back(
+        std::pair<std::string, std::string>("", path + "/include"));
+    return;
+  }
+  // Check if the upper level directory has an "include" subdirectory.
+  pos = path.find_last_of("/\\");
+  if (pos == std::string::npos || pos == 0) {
+    return;
+  }
+  path = path.substr(0, pos);
+  if (IsInstalledProtoPath(path + "/include")) {
+    paths->push_back(
+        std::pair<std::string, std::string>("", path + "/include"));
+    return;
+  }
+}
+
+std::string PluginName(const std::string& plugin_prefix,
+                       const std::string& directive) {
+  // Assuming the directive starts with "--" and ends with "_out" or "_opt",
+  // strip the "--" and "_out/_opt" and add the plugin prefix.
+  return plugin_prefix + "gen-" + directive.substr(2, directive.size() - 6);
+}
+
+}  // namespace
+
+// A MultiFileErrorCollector that prints errors to stderr.
+class CommandLineInterface::ErrorPrinter
+    : public MultiFileErrorCollector,
+      public io::ErrorCollector,
+      public DescriptorPool::ErrorCollector {
+ public:
+  ErrorPrinter(ErrorFormat format, DiskSourceTree* tree = nullptr)
+      : format_(format),
+        tree_(tree),
+        found_errors_(false),
+        found_warnings_(false) {}
+  ~ErrorPrinter() override {}
+
+  // implements MultiFileErrorCollector ------------------------------
+  void AddError(const std::string& filename, int line, int column,
+                const std::string& message) override {
+    found_errors_ = true;
+    AddErrorOrWarning(filename, line, column, message, "error", std::cerr);
+  }
+
+  void AddWarning(const std::string& filename, int line, int column,
+                  const std::string& message) override {
+    found_warnings_ = true;
+    AddErrorOrWarning(filename, line, column, message, "warning", std::clog);
+  }
+
+  // implements io::ErrorCollector -----------------------------------
+  void AddError(int line, int column, const std::string& message) override {
+    AddError("input", line, column, message);
+  }
+
+  void AddWarning(int line, int column, const std::string& message) override {
+    AddErrorOrWarning("input", line, column, message, "warning", std::clog);
+  }
+
+  // implements DescriptorPool::ErrorCollector-------------------------
+  void AddError(const std::string& filename, const std::string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const std::string& message) override {
+    AddErrorOrWarning(filename, -1, -1, message, "error", std::cerr);
+  }
+
+  void AddWarning(const std::string& filename, const std::string& element_name,
+                  const Message* descriptor, ErrorLocation location,
+                  const std::string& message) override {
+    AddErrorOrWarning(filename, -1, -1, message, "warning", std::clog);
+  }
+
+  bool FoundErrors() const { return found_errors_; }
+
+  bool FoundWarnings() const { return found_warnings_; }
+
+ private:
+  void AddErrorOrWarning(const std::string& filename, int line, int column,
+                         const std::string& message, const std::string& type,
+                         std::ostream& out) {
+    // Print full path when running under MSVS
+    std::string dfile;
+    if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
+        tree_ != nullptr && tree_->VirtualFileToDiskFile(filename, &dfile)) {
+      out << dfile;
+    } else {
+      out << filename;
+    }
+
+    // Users typically expect 1-based line/column numbers, so we add 1
+    // to each here.
+    if (line != -1) {
+      // Allow for both GCC- and Visual-Studio-compatible output.
+      switch (format_) {
+        case CommandLineInterface::ERROR_FORMAT_GCC:
+          out << ":" << (line + 1) << ":" << (column + 1);
+          break;
+        case CommandLineInterface::ERROR_FORMAT_MSVS:
+          out << "(" << (line + 1) << ") : " << type
+              << " in column=" << (column + 1);
+          break;
+      }
+    }
+
+    if (type == "warning") {
+      out << ": warning: " << message << std::endl;
+    } else {
+      out << ": " << message << std::endl;
+    }
+  }
+
+  const ErrorFormat format_;
+  DiskSourceTree* tree_;
+  bool found_errors_;
+  bool found_warnings_;
+};
+
+// -------------------------------------------------------------------
+
+// A GeneratorContext implementation that buffers files in memory, then dumps
+// them all to disk on demand.
+class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
+ public:
+  GeneratorContextImpl(const std::vector<const FileDescriptor*>& parsed_files);
+
+  // Write all files in the directory to disk at the given output location,
+  // which must end in a '/'.
+  bool WriteAllToDisk(const std::string& prefix);
+
+  // Write the contents of this directory to a ZIP-format archive with the
+  // given name.
+  bool WriteAllToZip(const std::string& filename);
+
+  // Add a boilerplate META-INF/MANIFEST.MF file as required by the Java JAR
+  // format, unless one has already been written.
+  void AddJarManifest();
+
+  // Get name of all output files.
+  void GetOutputFilenames(std::vector<std::string>* output_filenames);
+
+  // implements GeneratorContext --------------------------------------
+  io::ZeroCopyOutputStream* Open(const std::string& filename) override;
+  io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename) override;
+  io::ZeroCopyOutputStream* OpenForInsert(
+      const std::string& filename, const std::string& insertion_point) override;
+  io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo(
+      const std::string& filename, const std::string& insertion_point,
+      const google::protobuf::GeneratedCodeInfo& info) override;
+  void ListParsedFiles(std::vector<const FileDescriptor*>* output) override {
+    *output = parsed_files_;
+  }
+
+ private:
+  friend class MemoryOutputStream;
+
+  // The files_ field maps from path keys to file content values. It's a map
+  // instead of an unordered_map so that files are written in order (good when
+  // writing zips).
+  std::map<std::string, std::string> files_;
+  const std::vector<const FileDescriptor*>& parsed_files_;
+  bool had_error_;
+};
+
+class CommandLineInterface::MemoryOutputStream
+    : public io::ZeroCopyOutputStream {
+ public:
+  MemoryOutputStream(GeneratorContextImpl* directory,
+                     const std::string& filename, bool append_mode);
+  MemoryOutputStream(GeneratorContextImpl* directory,
+                     const std::string& filename,
+                     const std::string& insertion_point);
+  MemoryOutputStream(GeneratorContextImpl* directory,
+                     const std::string& filename,
+                     const std::string& insertion_point,
+                     const google::protobuf::GeneratedCodeInfo& info);
+  ~MemoryOutputStream() override;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override {
+    return inner_->Next(data, size);
+  }
+  void BackUp(int count) override { inner_->BackUp(count); }
+  int64_t ByteCount() const override { return inner_->ByteCount(); }
+
+ private:
+  // Checks to see if "filename_.pb.meta" exists in directory_; if so, fixes the
+  // offsets in that GeneratedCodeInfo record to reflect bytes inserted in
+  // filename_ at original offset insertion_offset with length insertion_length.
+  // Also adds in the data from info_to_insert_ with updated offsets governed by
+  // insertion_offset and indent_length. We assume that insertions will not
+  // occur within any given annotated span of text. insertion_content must end
+  // with an endline.
+  void UpdateMetadata(const std::string& insertion_content,
+                      size_t insertion_offset, size_t insertion_length,
+                      size_t indent_length);
+
+  // Inserts info_to_insert_ into target_info, assuming that the relevant
+  // insertion was made at insertion_offset in file_content with the given
+  // indent_length. insertion_content must end with an endline.
+  void InsertShiftedInfo(const std::string& insertion_content,
+                         size_t insertion_offset, size_t indent_length,
+                         google::protobuf::GeneratedCodeInfo& target_info);
+
+  // Where to insert the string when it's done.
+  GeneratorContextImpl* directory_;
+  std::string filename_;
+  std::string insertion_point_;
+
+  // The string we're building.
+  std::string data_;
+
+  // Whether we should append the output stream to the existing file.
+  bool append_mode_;
+
+  // StringOutputStream writing to data_.
+  std::unique_ptr<io::StringOutputStream> inner_;
+
+  // The GeneratedCodeInfo to insert at the insertion point.
+  google::protobuf::GeneratedCodeInfo info_to_insert_;
+};
+
+// -------------------------------------------------------------------
+
+CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl(
+    const std::vector<const FileDescriptor*>& parsed_files)
+    : parsed_files_(parsed_files), had_error_(false) {}
+
+bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
+    const std::string& prefix) {
+  if (had_error_) {
+    return false;
+  }
+
+  if (!VerifyDirectoryExists(prefix)) {
+    return false;
+  }
+
+  for (const auto& pair : files_) {
+    const std::string& relative_filename = pair.first;
+    const char* data = pair.second.data();
+    int size = pair.second.size();
+
+    if (!TryCreateParentDirectory(prefix, relative_filename)) {
+      return false;
+    }
+    std::string filename = prefix + relative_filename;
+
+    // Create the output file.
+    int file_descriptor;
+    do {
+      file_descriptor =
+          open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+    } while (file_descriptor < 0 && errno == EINTR);
+
+    if (file_descriptor < 0) {
+      int error = errno;
+      std::cerr << filename << ": " << strerror(error);
+      return false;
+    }
+
+    // Write the file.
+    while (size > 0) {
+      int write_result;
+      do {
+        write_result = write(file_descriptor, data, size);
+      } while (write_result < 0 && errno == EINTR);
+
+      if (write_result <= 0) {
+        // Write error.
+
+        // FIXME(kenton):  According to the man page, if write() returns zero,
+        //   there was no error; write() simply did not write anything.  It's
+        //   unclear under what circumstances this might happen, but presumably
+        //   errno won't be set in this case.  I am confused as to how such an
+        //   event should be handled.  For now I'm treating it as an error,
+        //   since retrying seems like it could lead to an infinite loop.  I
+        //   suspect this never actually happens anyway.
+
+        if (write_result < 0) {
+          int error = errno;
+          std::cerr << filename << ": write: " << strerror(error);
+        } else {
+          std::cerr << filename << ": write() returned zero?" << std::endl;
+        }
+        return false;
+      }
+
+      data += write_result;
+      size -= write_result;
+    }
+
+    if (close(file_descriptor) != 0) {
+      int error = errno;
+      std::cerr << filename << ": close: " << strerror(error);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
+    const std::string& filename) {
+  if (had_error_) {
+    return false;
+  }
+
+  // Create the output file.
+  int file_descriptor;
+  do {
+    file_descriptor =
+        open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+  } while (file_descriptor < 0 && errno == EINTR);
+
+  if (file_descriptor < 0) {
+    int error = errno;
+    std::cerr << filename << ": " << strerror(error);
+    return false;
+  }
+
+  // Create the ZipWriter
+  io::FileOutputStream stream(file_descriptor);
+  ZipWriter zip_writer(&stream);
+
+  for (const auto& pair : files_) {
+    zip_writer.Write(pair.first, pair.second);
+  }
+
+  zip_writer.WriteDirectory();
+
+  if (stream.GetErrno() != 0) {
+    std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
+    return false;
+  }
+
+  if (!stream.Close()) {
+    std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
+  auto pair = files_.insert({"META-INF/MANIFEST.MF", ""});
+  if (pair.second) {
+    pair.first->second =
+        "Manifest-Version: 1.0\n"
+        "Created-By: 1.6.0 (protoc)\n"
+        "\n";
+  }
+}
+
+void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames(
+    std::vector<std::string>* output_filenames) {
+  for (const auto& pair : files_) {
+    output_filenames->push_back(pair.first);
+  }
+}
+
+io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
+    const std::string& filename) {
+  return new MemoryOutputStream(this, filename, false);
+}
+
+io::ZeroCopyOutputStream*
+CommandLineInterface::GeneratorContextImpl::OpenForAppend(
+    const std::string& filename) {
+  return new MemoryOutputStream(this, filename, true);
+}
+
+io::ZeroCopyOutputStream*
+CommandLineInterface::GeneratorContextImpl::OpenForInsert(
+    const std::string& filename, const std::string& insertion_point) {
+  return new MemoryOutputStream(this, filename, insertion_point);
+}
+
+io::ZeroCopyOutputStream*
+CommandLineInterface::GeneratorContextImpl::OpenForInsertWithGeneratedCodeInfo(
+    const std::string& filename, const std::string& insertion_point,
+    const google::protobuf::GeneratedCodeInfo& info) {
+  return new MemoryOutputStream(this, filename, insertion_point, info);
+}
+
+// -------------------------------------------------------------------
+
+CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
+    GeneratorContextImpl* directory, const std::string& filename,
+    bool append_mode)
+    : directory_(directory),
+      filename_(filename),
+      append_mode_(append_mode),
+      inner_(new io::StringOutputStream(&data_)) {}
+
+CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
+    GeneratorContextImpl* directory, const std::string& filename,
+    const std::string& insertion_point)
+    : directory_(directory),
+      filename_(filename),
+      insertion_point_(insertion_point),
+      inner_(new io::StringOutputStream(&data_)) {}
+
+CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
+    GeneratorContextImpl* directory, const std::string& filename,
+    const std::string& insertion_point, const google::protobuf::GeneratedCodeInfo& info)
+    : directory_(directory),
+      filename_(filename),
+      insertion_point_(insertion_point),
+      inner_(new io::StringOutputStream(&data_)),
+      info_to_insert_(info) {}
+
+void CommandLineInterface::MemoryOutputStream::InsertShiftedInfo(
+    const std::string& insertion_content, size_t insertion_offset,
+    size_t indent_length, google::protobuf::GeneratedCodeInfo& target_info) {
+  // Keep track of how much extra data was added for indents before the
+  // current annotation being inserted. `pos` and `source_annotation.begin()`
+  // are offsets in `insertion_content`. `insertion_offset` is updated so that
+  // it can be added to an annotation's `begin` field to reflect that
+  // annotation's updated location after `insertion_content` was inserted into
+  // the target file.
+  size_t pos = 0;
+  insertion_offset += indent_length;
+  for (const auto& source_annotation : info_to_insert_.annotation()) {
+    GeneratedCodeInfo::Annotation* annotation = target_info.add_annotation();
+    int inner_indent = 0;
+    // insertion_content is guaranteed to end in an endline. This last endline
+    // has no effect on indentation.
+    for (; pos < source_annotation.end() && pos < insertion_content.size() - 1;
+         ++pos) {
+      if (insertion_content[pos] == '\n') {
+        if (pos >= source_annotation.begin()) {
+          // The beginning of the annotation is at insertion_offset, but the end
+          // can still move further in the target file.
+          inner_indent += indent_length;
+        } else {
+          insertion_offset += indent_length;
+        }
+      }
+    }
+    *annotation = source_annotation;
+    annotation->set_begin(annotation->begin() + insertion_offset);
+    insertion_offset += inner_indent;
+    annotation->set_end(annotation->end() + insertion_offset);
+  }
+}
+
+void CommandLineInterface::MemoryOutputStream::UpdateMetadata(
+    const std::string& insertion_content, size_t insertion_offset,
+    size_t insertion_length, size_t indent_length) {
+  auto it = directory_->files_.find(filename_ + ".pb.meta");
+  if (it == directory_->files_.end() && info_to_insert_.annotation().empty()) {
+    // No metadata was recorded for this file.
+    return;
+  }
+  GeneratedCodeInfo metadata;
+  bool is_text_format = false;
+  std::string* encoded_data = nullptr;
+  if (it != directory_->files_.end()) {
+    encoded_data = &it->second;
+    // Try to decode a GeneratedCodeInfo proto from the .pb.meta file. It may be
+    // in wire or text format. Keep the same format when the data is written out
+    // later.
+    if (!metadata.ParseFromString(*encoded_data)) {
+      if (!TextFormat::ParseFromString(*encoded_data, &metadata)) {
+        // The metadata is invalid.
+        std::cerr
+            << filename_
+            << ".pb.meta: Could not parse metadata as wire or text format."
+            << std::endl;
+        return;
+      }
+      // Generators that use the public plugin interface emit text-format
+      // metadata (because in the public plugin protocol, file content must be
+      // UTF8-encoded strings).
+      is_text_format = true;
+    }
+  } else {
+    // Create a new file to store the new metadata in info_to_insert_.
+    encoded_data =
+        &directory_->files_.insert({filename_ + ".pb.meta", ""}).first->second;
+  }
+  GeneratedCodeInfo new_metadata;
+  bool crossed_offset = false;
+  size_t to_add = 0;
+  for (const auto& source_annotation : metadata.annotation()) {
+    // The first time an annotation at or after the insertion point is found,
+    // insert the new metadata from info_to_insert_. Shift all annotations
+    // after the new metadata by the length of the text that was inserted
+    // (including any additional indent length).
+    if (source_annotation.begin() >= insertion_offset && !crossed_offset) {
+      crossed_offset = true;
+      InsertShiftedInfo(insertion_content, insertion_offset, indent_length,
+                        new_metadata);
+      to_add += insertion_length;
+    }
+    GeneratedCodeInfo::Annotation* annotation = new_metadata.add_annotation();
+    *annotation = source_annotation;
+    annotation->set_begin(annotation->begin() + to_add);
+    annotation->set_end(annotation->end() + to_add);
+  }
+  // If there were never any annotations at or after the insertion point,
+  // make sure to still insert the new metadata from info_to_insert_.
+  if (!crossed_offset) {
+    InsertShiftedInfo(insertion_content, insertion_offset, indent_length,
+                      new_metadata);
+  }
+  if (is_text_format) {
+    TextFormat::PrintToString(new_metadata, encoded_data);
+  } else {
+    new_metadata.SerializeToString(encoded_data);
+  }
+}
+
+CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
+  // Make sure all data has been written.
+  inner_.reset();
+
+  // Insert into the directory.
+  auto pair = directory_->files_.insert({filename_, ""});
+  auto it = pair.first;
+  bool already_present = !pair.second;
+
+  if (insertion_point_.empty()) {
+    // This was just a regular Open().
+    if (already_present) {
+      if (append_mode_) {
+        it->second.append(data_);
+      } else {
+        std::cerr << filename_ << ": Tried to write the same file twice."
+                  << std::endl;
+        directory_->had_error_ = true;
+      }
+      return;
+    }
+
+    it->second.swap(data_);
+  } else {
+    // This was an OpenForInsert().
+
+    // If the data doesn't end with a clean line break, add one.
+    if (!data_.empty() && data_[data_.size() - 1] != '\n') {
+      data_.push_back('\n');
+    }
+
+    // Find the file we are going to insert into.
+    if (!already_present) {
+      std::cerr << filename_
+                << ": Tried to insert into file that doesn't exist."
+                << std::endl;
+      directory_->had_error_ = true;
+      return;
+    }
+    std::string* target = &it->second;
+
+    // Find the insertion point.
+    std::string magic_string =
+        strings::Substitute("@@protoc_insertion_point($0)", insertion_point_);
+    std::string::size_type pos = target->find(magic_string);
+
+    if (pos == std::string::npos) {
+      std::cerr << filename_ << ": insertion point \"" << insertion_point_
+                << "\" not found." << std::endl;
+      directory_->had_error_ = true;
+      return;
+    }
+
+    if ((pos > 3) && (target->substr(pos - 3, 2) == "/*")) {
+      // Support for inline "/* @@protoc_insertion_point() */"
+      pos = pos - 3;
+    } else {
+      // Seek backwards to the beginning of the line, which is where we will
+      // insert the data.  Note that this has the effect of pushing the
+      // insertion point down, so the data is inserted before it.  This is
+      // intentional because it means that multiple insertions at the same point
+      // will end up in the expected order in the final output.
+      pos = target->find_last_of('\n', pos);
+      if (pos == std::string::npos) {
+        // Insertion point is on the first line.
+        pos = 0;
+      } else {
+        // Advance to character after '\n'.
+        ++pos;
+      }
+    }
+
+    // Extract indent.
+    std::string indent_(*target, pos,
+                        target->find_first_not_of(" \t", pos) - pos);
+
+    if (indent_.empty()) {
+      // No indent.  This makes things easier.
+      target->insert(pos, data_);
+      UpdateMetadata(data_, pos, data_.size(), 0);
+    } else {
+      // Calculate how much space we need.
+      int indent_size = 0;
+      for (int i = 0; i < data_.size(); i++) {
+        if (data_[i] == '\n') indent_size += indent_.size();
+      }
+
+      // Make a hole for it.
+      target->insert(pos, data_.size() + indent_size, '\0');
+
+      // Now copy in the data.
+      std::string::size_type data_pos = 0;
+      char* target_ptr = ::google::protobuf::string_as_array(target) + pos;
+      while (data_pos < data_.size()) {
+        // Copy indent.
+        memcpy(target_ptr, indent_.data(), indent_.size());
+        target_ptr += indent_.size();
+
+        // Copy line from data_.
+        // We already guaranteed that data_ ends with a newline (above), so this
+        // search can't fail.
+        std::string::size_type line_length =
+            data_.find_first_of('\n', data_pos) + 1 - data_pos;
+        memcpy(target_ptr, data_.data() + data_pos, line_length);
+        target_ptr += line_length;
+        data_pos += line_length;
+      }
+      UpdateMetadata(data_, pos, data_.size() + indent_size, indent_.size());
+
+      GOOGLE_CHECK_EQ(target_ptr,
+               ::google::protobuf::string_as_array(target) + pos + data_.size() + indent_size);
+    }
+  }
+}
+
+// ===================================================================
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+const char* const CommandLineInterface::kPathSeparator = ";";
+#else
+const char* const CommandLineInterface::kPathSeparator = ":";
+#endif
+
+CommandLineInterface::CommandLineInterface()
+    : direct_dependencies_violation_msg_(
+          kDefaultDirectDependenciesViolationMsg) {}
+
+CommandLineInterface::~CommandLineInterface() {}
+
+void CommandLineInterface::RegisterGenerator(const std::string& flag_name,
+                                             CodeGenerator* generator,
+                                             const std::string& help_text) {
+  GeneratorInfo info;
+  info.flag_name = flag_name;
+  info.generator = generator;
+  info.help_text = help_text;
+  generators_by_flag_name_[flag_name] = info;
+}
+
+void CommandLineInterface::RegisterGenerator(
+    const std::string& flag_name, const std::string& option_flag_name,
+    CodeGenerator* generator, const std::string& help_text) {
+  GeneratorInfo info;
+  info.flag_name = flag_name;
+  info.option_flag_name = option_flag_name;
+  info.generator = generator;
+  info.help_text = help_text;
+  generators_by_flag_name_[flag_name] = info;
+  generators_by_option_name_[option_flag_name] = info;
+}
+
+void CommandLineInterface::AllowPlugins(const std::string& exe_name_prefix) {
+  plugin_prefix_ = exe_name_prefix;
+}
+
+namespace {
+
+bool ContainsProto3Optional(const Descriptor* desc) {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->has_optional_keyword()) {
+      return true;
+    }
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    if (ContainsProto3Optional(desc->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ContainsProto3Optional(const FileDescriptor* file) {
+  if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    for (int i = 0; i < file->message_type_count(); i++) {
+      if (ContainsProto3Optional(file->message_type(i))) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+namespace {
+std::unique_ptr<SimpleDescriptorDatabase>
+PopulateSingleSimpleDescriptorDatabase(const std::string& descriptor_set_name);
+}
+
+int CommandLineInterface::Run(int argc, const char* const argv[]) {
+  Clear();
+  switch (ParseArguments(argc, argv)) {
+    case PARSE_ARGUMENT_DONE_AND_EXIT:
+      return 0;
+    case PARSE_ARGUMENT_FAIL:
+      return 1;
+    case PARSE_ARGUMENT_DONE_AND_CONTINUE:
+      break;
+  }
+
+  std::vector<const FileDescriptor*> parsed_files;
+  std::unique_ptr<DiskSourceTree> disk_source_tree;
+  std::unique_ptr<ErrorPrinter> error_collector;
+  std::unique_ptr<DescriptorPool> descriptor_pool;
+
+  // The SimpleDescriptorDatabases here are the constituents of the
+  // MergedDescriptorDatabase descriptor_set_in_database, so this vector is for
+  // managing their lifetimes. Its scope should match descriptor_set_in_database
+  std::vector<std::unique_ptr<SimpleDescriptorDatabase>>
+      databases_per_descriptor_set;
+  std::unique_ptr<MergedDescriptorDatabase> descriptor_set_in_database;
+
+  std::unique_ptr<SourceTreeDescriptorDatabase> source_tree_database;
+
+  // Any --descriptor_set_in FileDescriptorSet objects will be used as a
+  // fallback to input_files on command line, so create that db first.
+  if (!descriptor_set_in_names_.empty()) {
+    for (const std::string& name : descriptor_set_in_names_) {
+      std::unique_ptr<SimpleDescriptorDatabase> database_for_descriptor_set =
+          PopulateSingleSimpleDescriptorDatabase(name);
+      if (!database_for_descriptor_set) {
+        return EXIT_FAILURE;
+      }
+      databases_per_descriptor_set.push_back(
+          std::move(database_for_descriptor_set));
+    }
+
+    std::vector<DescriptorDatabase*> raw_databases_per_descriptor_set;
+    raw_databases_per_descriptor_set.reserve(
+        databases_per_descriptor_set.size());
+    for (const std::unique_ptr<SimpleDescriptorDatabase>& db :
+         databases_per_descriptor_set) {
+      raw_databases_per_descriptor_set.push_back(db.get());
+    }
+    descriptor_set_in_database.reset(
+        new MergedDescriptorDatabase(raw_databases_per_descriptor_set));
+  }
+
+  if (proto_path_.empty()) {
+    // If there are no --proto_path flags, then just look in the specified
+    // --descriptor_set_in files.  But first, verify that the input files are
+    // there.
+    if (!VerifyInputFilesInDescriptors(descriptor_set_in_database.get())) {
+      return 1;
+    }
+
+    error_collector.reset(new ErrorPrinter(error_format_));
+    descriptor_pool.reset(new DescriptorPool(descriptor_set_in_database.get(),
+                                             error_collector.get()));
+  } else {
+    disk_source_tree.reset(new DiskSourceTree());
+    if (!InitializeDiskSourceTree(disk_source_tree.get(),
+                                  descriptor_set_in_database.get())) {
+      return 1;
+    }
+
+    error_collector.reset(
+        new ErrorPrinter(error_format_, disk_source_tree.get()));
+
+    source_tree_database.reset(new SourceTreeDescriptorDatabase(
+        disk_source_tree.get(), descriptor_set_in_database.get()));
+    source_tree_database->RecordErrorsTo(error_collector.get());
+
+    descriptor_pool.reset(new DescriptorPool(
+        source_tree_database.get(),
+        source_tree_database->GetValidationErrorCollector()));
+  }
+
+  descriptor_pool->EnforceWeakDependencies(true);
+  if (!ParseInputFiles(descriptor_pool.get(), disk_source_tree.get(),
+                       &parsed_files)) {
+    return 1;
+  }
+
+
+  // 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.
+  GeneratorContextMap output_directories;
+
+  // Generate output.
+  if (mode_ == MODE_COMPILE) {
+    for (int i = 0; i < output_directives_.size(); i++) {
+      std::string output_location = output_directives_[i].output_location;
+      if (!HasSuffixString(output_location, ".zip") &&
+          !HasSuffixString(output_location, ".jar") &&
+          !HasSuffixString(output_location, ".srcjar")) {
+        AddTrailingSlash(&output_location);
+      }
+
+      auto& generator = output_directories[output_location];
+
+      if (!generator) {
+        // First time we've seen this output location.
+        generator.reset(new GeneratorContextImpl(parsed_files));
+      }
+
+      if (!GenerateOutput(parsed_files, output_directives_[i],
+                          generator.get())) {
+        return 1;
+      }
+    }
+  }
+
+  // Write all output to disk.
+  for (const auto& pair : output_directories) {
+    const std::string& location = pair.first;
+    GeneratorContextImpl* directory = pair.second.get();
+    if (HasSuffixString(location, "/")) {
+      if (!directory->WriteAllToDisk(location)) {
+        return 1;
+      }
+    } else {
+      if (HasSuffixString(location, ".jar")) {
+        directory->AddJarManifest();
+      }
+
+      if (!directory->WriteAllToZip(location)) {
+        return 1;
+      }
+    }
+  }
+
+  if (!dependency_out_name_.empty()) {
+    GOOGLE_DCHECK(disk_source_tree.get());
+    if (!GenerateDependencyManifestFile(parsed_files, output_directories,
+                                        disk_source_tree.get())) {
+      return 1;
+    }
+  }
+
+  if (!descriptor_set_out_name_.empty()) {
+    if (!WriteDescriptorSet(parsed_files)) {
+      return 1;
+    }
+  }
+
+  if (mode_ == MODE_ENCODE || mode_ == MODE_DECODE) {
+    if (codec_type_.empty()) {
+      // HACK:  Define an EmptyMessage type to use for decoding.
+      DescriptorPool pool;
+      FileDescriptorProto file;
+      file.set_name("empty_message.proto");
+      file.add_message_type()->set_name("EmptyMessage");
+      GOOGLE_CHECK(pool.BuildFile(file) != nullptr);
+      codec_type_ = "EmptyMessage";
+      if (!EncodeOrDecode(&pool)) {
+        return 1;
+      }
+    } else {
+      if (!EncodeOrDecode(descriptor_pool.get())) {
+        return 1;
+      }
+    }
+  }
+
+  if (error_collector->FoundErrors() ||
+      (fatal_warnings_ && error_collector->FoundWarnings())) {
+    return 1;
+  }
+
+  if (mode_ == MODE_PRINT) {
+    switch (print_mode_) {
+      case PRINT_FREE_FIELDS:
+        for (int i = 0; i < parsed_files.size(); ++i) {
+          const FileDescriptor* fd = parsed_files[i];
+          for (int j = 0; j < fd->message_type_count(); ++j) {
+            PrintFreeFieldNumbers(fd->message_type(j));
+          }
+        }
+        break;
+      case PRINT_NONE:
+        GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
+                      "flag parsing in the CommandLineInterface.";
+        return 1;
+
+        // Do not add a default case.
+    }
+  }
+
+  return 0;
+}
+
+bool CommandLineInterface::InitializeDiskSourceTree(
+    DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
+  AddDefaultProtoPaths(&proto_path_);
+
+  // Set up the source tree.
+  for (int i = 0; i < proto_path_.size(); i++) {
+    source_tree->MapPath(proto_path_[i].first, proto_path_[i].second);
+  }
+
+  // Map input files to virtual paths if possible.
+  if (!MakeInputsBeProtoPathRelative(source_tree, fallback_database)) {
+    return false;
+  }
+
+  return true;
+}
+
+namespace {
+std::unique_ptr<SimpleDescriptorDatabase>
+PopulateSingleSimpleDescriptorDatabase(const std::string& descriptor_set_name) {
+  int fd;
+  do {
+    fd = open(descriptor_set_name.c_str(), O_RDONLY | O_BINARY);
+  } while (fd < 0 && errno == EINTR);
+  if (fd < 0) {
+    std::cerr << descriptor_set_name << ": " << strerror(ENOENT) << std::endl;
+    return nullptr;
+  }
+
+  FileDescriptorSet file_descriptor_set;
+  bool parsed = file_descriptor_set.ParseFromFileDescriptor(fd);
+  if (close(fd) != 0) {
+    std::cerr << descriptor_set_name << ": close: " << strerror(errno)
+              << std::endl;
+    return nullptr;
+  }
+
+  if (!parsed) {
+    std::cerr << descriptor_set_name << ": Unable to parse." << std::endl;
+    return nullptr;
+  }
+
+  std::unique_ptr<SimpleDescriptorDatabase> database{
+      new SimpleDescriptorDatabase()};
+
+  for (int j = 0; j < file_descriptor_set.file_size(); j++) {
+    FileDescriptorProto previously_added_file_descriptor_proto;
+    if (database->FindFileByName(file_descriptor_set.file(j).name(),
+                                 &previously_added_file_descriptor_proto)) {
+      // already present - skip
+      continue;
+    }
+    if (!database->Add(file_descriptor_set.file(j))) {
+      return nullptr;
+    }
+  }
+  return database;
+}
+
+}  // namespace
+
+
+bool CommandLineInterface::VerifyInputFilesInDescriptors(
+    DescriptorDatabase* database) {
+  for (const auto& input_file : input_files_) {
+    FileDescriptorProto file_descriptor;
+    if (!database->FindFileByName(input_file, &file_descriptor)) {
+      std::cerr << "Could not find file in descriptor database: " << input_file
+                << ": " << strerror(ENOENT) << std::endl;
+      return false;
+    }
+
+    // Enforce --disallow_services.
+    if (disallow_services_ && file_descriptor.service_size() > 0) {
+      std::cerr << file_descriptor.name()
+                << ": This file contains services, but "
+                   "--disallow_services was used."
+                << std::endl;
+      return false;
+    }
+
+  }
+  return true;
+}
+
+bool CommandLineInterface::ParseInputFiles(
+    DescriptorPool* descriptor_pool, DiskSourceTree* source_tree,
+    std::vector<const FileDescriptor*>* parsed_files) {
+
+  if (!proto_path_.empty()) {
+    // Track unused imports in all source files that were loaded from the
+    // filesystem. We do not track unused imports for files loaded from
+    // descriptor sets as they may be programmatically generated in which case
+    // exerting this level of rigor is less desirable. We're also making the
+    // assumption that the initial parse of the proto from the filesystem
+    // was rigorous in checking unused imports and that the descriptor set
+    // being parsed was produced then and that it was subsequent mutations
+    // of that descriptor set that left unused imports.
+    //
+    // Note that relying on proto_path exclusively is limited in that we may
+    // be loading descriptors from both the filesystem and descriptor sets
+    // depending on the invocation. At least for invocations that are
+    // exclusively reading from descriptor sets, we can eliminate this failure
+    // condition.
+    for (const auto& input_file : input_files_) {
+      descriptor_pool->AddUnusedImportTrackFile(input_file);
+    }
+  }
+
+  bool result = true;
+  // Parse each file.
+  for (const auto& input_file : input_files_) {
+    // Import the file.
+    const FileDescriptor* parsed_file =
+        descriptor_pool->FindFileByName(input_file);
+    if (parsed_file == nullptr) {
+      result = false;
+      break;
+    }
+    parsed_files->push_back(parsed_file);
+
+    // Enforce --disallow_services.
+    if (disallow_services_ && parsed_file->service_count() > 0) {
+      std::cerr << parsed_file->name()
+                << ": This file contains services, but "
+                   "--disallow_services was used."
+                << std::endl;
+      result = false;
+      break;
+    }
+
+
+    // Enforce --direct_dependencies
+    if (direct_dependencies_explicitly_set_) {
+      bool indirect_imports = false;
+      for (int i = 0; i < parsed_file->dependency_count(); i++) {
+        if (direct_dependencies_.find(parsed_file->dependency(i)->name()) ==
+            direct_dependencies_.end()) {
+          indirect_imports = true;
+          std::cerr << parsed_file->name() << ": "
+                    << StringReplace(direct_dependencies_violation_msg_, "%s",
+                                     parsed_file->dependency(i)->name(),
+                                     true /* replace_all */)
+                    << std::endl;
+        }
+      }
+      if (indirect_imports) {
+        result = false;
+        break;
+      }
+    }
+  }
+  descriptor_pool->ClearUnusedImportTrackFiles();
+  return result;
+}
+
+void CommandLineInterface::Clear() {
+  // Clear all members that are set by Run().  Note that we must not clear
+  // members which are set by other methods before Run() is called.
+  executable_name_.clear();
+  proto_path_.clear();
+  input_files_.clear();
+  direct_dependencies_.clear();
+  direct_dependencies_violation_msg_ = kDefaultDirectDependenciesViolationMsg;
+  output_directives_.clear();
+  codec_type_.clear();
+  descriptor_set_in_names_.clear();
+  descriptor_set_out_name_.clear();
+  dependency_out_name_.clear();
+
+
+  mode_ = MODE_COMPILE;
+  print_mode_ = PRINT_NONE;
+  imports_in_descriptor_set_ = false;
+  source_info_in_descriptor_set_ = false;
+  disallow_services_ = false;
+  direct_dependencies_explicitly_set_ = false;
+  deterministic_output_ = false;
+}
+
+bool CommandLineInterface::MakeProtoProtoPathRelative(
+    DiskSourceTree* source_tree, std::string* proto,
+    DescriptorDatabase* fallback_database) {
+  // If it's in the fallback db, don't report non-existent file errors.
+  FileDescriptorProto fallback_file;
+  bool in_fallback_database =
+      fallback_database != nullptr &&
+      fallback_database->FindFileByName(*proto, &fallback_file);
+
+  // If the input file path is not a physical file path, it must be a virtual
+  // path.
+  if (access(proto->c_str(), F_OK) < 0) {
+    std::string disk_file;
+    if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
+        in_fallback_database) {
+      return true;
+    } else {
+      std::cerr << "Could not make proto path relative: " << *proto << ": "
+                << strerror(ENOENT) << std::endl;
+      return false;
+    }
+  }
+
+  std::string virtual_file, shadowing_disk_file;
+  switch (source_tree->DiskFileToVirtualFile(*proto, &virtual_file,
+                                             &shadowing_disk_file)) {
+    case DiskSourceTree::SUCCESS:
+      *proto = virtual_file;
+      break;
+    case DiskSourceTree::SHADOWED:
+      std::cerr << *proto << ": Input is shadowed in the --proto_path by \""
+                << shadowing_disk_file
+                << "\".  Either use the latter file as your input or reorder "
+                   "the --proto_path so that the former file's location "
+                   "comes first."
+                << std::endl;
+      return false;
+    case DiskSourceTree::CANNOT_OPEN: {
+      if (in_fallback_database) {
+        return true;
+      }
+      std::string error_str = source_tree->GetLastErrorMessage().empty()
+                                  ? strerror(errno)
+                                  : source_tree->GetLastErrorMessage();
+      std::cerr << "Could not map to virtual file: " << *proto << ": "
+                << error_str << std::endl;
+      return false;
+    }
+    case DiskSourceTree::NO_MAPPING: {
+      // Try to interpret the path as a virtual path.
+      std::string disk_file;
+      if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
+          in_fallback_database) {
+        return true;
+      } else {
+        // The input file path can't be mapped to any --proto_path and it also
+        // can't be interpreted as a virtual path.
+        std::cerr
+            << *proto
+            << ": File does not reside within any path "
+               "specified using --proto_path (or -I).  You must specify a "
+               "--proto_path which encompasses this file.  Note that the "
+               "proto_path must be an exact prefix of the .proto file "
+               "names -- protoc is too dumb to figure out when two paths "
+               "(e.g. absolute and relative) are equivalent (it's harder "
+               "than you think)."
+            << std::endl;
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool CommandLineInterface::MakeInputsBeProtoPathRelative(
+    DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
+  for (auto& input_file : input_files_) {
+    if (!MakeProtoProtoPathRelative(source_tree, &input_file,
+                                    fallback_database)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+bool CommandLineInterface::ExpandArgumentFile(
+    const std::string& file, std::vector<std::string>* arguments) {
+  // The argument file is searched in the working directory only. We don't
+  // use the proto import path here.
+  std::ifstream file_stream(file.c_str());
+  if (!file_stream.is_open()) {
+    return false;
+  }
+  std::string argument;
+  // We don't support any kind of shell expansion right now.
+  while (std::getline(file_stream, argument)) {
+    arguments->push_back(argument);
+  }
+  return true;
+}
+
+CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments(
+    int argc, const char* const argv[]) {
+  executable_name_ = argv[0];
+
+  std::vector<std::string> arguments;
+  for (int i = 1; i < argc; ++i) {
+    if (argv[i][0] == '@') {
+      if (!ExpandArgumentFile(argv[i] + 1, &arguments)) {
+        std::cerr << "Failed to open argument file: " << (argv[i] + 1)
+                  << std::endl;
+        return PARSE_ARGUMENT_FAIL;
+      }
+      continue;
+    }
+    arguments.push_back(argv[i]);
+  }
+
+  // if no arguments are given, show help
+  if (arguments.empty()) {
+    PrintHelpText();
+    return PARSE_ARGUMENT_DONE_AND_EXIT;  // Exit without running compiler.
+  }
+
+  // Iterate through all arguments and parse them.
+  for (int i = 0; i < arguments.size(); ++i) {
+    std::string name, value;
+
+    if (ParseArgument(arguments[i].c_str(), &name, &value)) {
+      // Returned true => Use the next argument as the flag value.
+      if (i + 1 == arguments.size() || arguments[i + 1][0] == '-') {
+        std::cerr << "Missing value for flag: " << name << std::endl;
+        if (name == "--decode") {
+          std::cerr << "To decode an unknown message, use --decode_raw."
+                    << std::endl;
+        }
+        return PARSE_ARGUMENT_FAIL;
+      } else {
+        ++i;
+        value = arguments[i];
+      }
+    }
+
+    ParseArgumentStatus status = InterpretArgument(name, value);
+    if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE) return status;
+  }
+
+  // Make sure each plugin option has a matching plugin output.
+  bool foundUnknownPluginOption = false;
+  for (std::map<std::string, std::string>::const_iterator i =
+           plugin_parameters_.begin();
+       i != plugin_parameters_.end(); ++i) {
+    if (plugins_.find(i->first) != plugins_.end()) {
+      continue;
+    }
+    bool foundImplicitPlugin = false;
+    for (std::vector<OutputDirective>::const_iterator j =
+             output_directives_.begin();
+         j != output_directives_.end(); ++j) {
+      if (j->generator == nullptr) {
+        std::string plugin_name = PluginName(plugin_prefix_, j->name);
+        if (plugin_name == i->first) {
+          foundImplicitPlugin = true;
+          break;
+        }
+      }
+    }
+    if (!foundImplicitPlugin) {
+      std::cerr << "Unknown flag: "
+                // strip prefix + "gen-" and add back "_opt"
+                << "--" + i->first.substr(plugin_prefix_.size() + 4) + "_opt"
+                << std::endl;
+      foundUnknownPluginOption = true;
+    }
+  }
+  if (foundUnknownPluginOption) {
+    return PARSE_ARGUMENT_FAIL;
+  }
+
+  // The --proto_path & --descriptor_set_in flags both specify places to look
+  // for proto files. If neither were given, use the current working directory.
+  if (proto_path_.empty() && descriptor_set_in_names_.empty()) {
+    // Don't use make_pair as the old/default standard library on Solaris
+    // doesn't support it without explicit template parameters, which are
+    // incompatible with C++0x's make_pair.
+    proto_path_.push_back(std::pair<std::string, std::string>("", "."));
+  }
+
+  // Check error cases that span multiple flag values.
+  bool missing_proto_definitions = false;
+  switch (mode_) {
+    case MODE_COMPILE:
+      missing_proto_definitions = input_files_.empty();
+      break;
+    case MODE_DECODE:
+      // Handle --decode_raw separately, since it requires that no proto
+      // definitions are specified.
+      if (codec_type_.empty()) {
+        if (!input_files_.empty() || !descriptor_set_in_names_.empty()) {
+          std::cerr
+              << "When using --decode_raw, no input files should be given."
+              << std::endl;
+          return PARSE_ARGUMENT_FAIL;
+        }
+        missing_proto_definitions = false;
+        break;  // only for --decode_raw
+      }
+      // --decode (not raw) is handled the same way as the rest of the modes.
+      PROTOBUF_FALLTHROUGH_INTENDED;
+    case MODE_ENCODE:
+    case MODE_PRINT:
+      missing_proto_definitions =
+          input_files_.empty() && descriptor_set_in_names_.empty();
+      break;
+    default:
+      GOOGLE_LOG(FATAL) << "Unexpected mode: " << mode_;
+  }
+  if (missing_proto_definitions) {
+    std::cerr << "Missing input file." << std::endl;
+    return PARSE_ARGUMENT_FAIL;
+  }
+  if (mode_ == MODE_COMPILE && output_directives_.empty() &&
+      descriptor_set_out_name_.empty()) {
+    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 (mode_ != MODE_ENCODE && deterministic_output_) {
+    std::cerr << "Can only use --deterministic_output with --encode."
+              << 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_out_name_.empty()) {
+    std::cerr << "--include_imports only makes sense when combined with "
+                 "--descriptor_set_out."
+              << std::endl;
+  }
+  if (source_info_in_descriptor_set_ && descriptor_set_out_name_.empty()) {
+    std::cerr << "--include_source_info only makes sense when combined with "
+                 "--descriptor_set_out."
+              << std::endl;
+  }
+
+  return PARSE_ARGUMENT_DONE_AND_CONTINUE;
+}
+
+bool CommandLineInterface::ParseArgument(const char* arg, std::string* name,
+                                         std::string* value) {
+  bool parsed_value = false;
+
+  if (arg[0] != '-') {
+    // Not a flag.
+    name->clear();
+    parsed_value = true;
+    *value = arg;
+  } else if (arg[1] == '-') {
+    // Two dashes:  Multi-character name, with '=' separating name and
+    //   value.
+    const char* equals_pos = strchr(arg, '=');
+    if (equals_pos != nullptr) {
+      *name = std::string(arg, equals_pos - arg);
+      *value = equals_pos + 1;
+      parsed_value = true;
+    } else {
+      *name = arg;
+    }
+  } else {
+    // One dash:  One-character name, all subsequent characters are the
+    //   value.
+    if (arg[1] == '\0') {
+      // arg is just "-".  We treat this as an input file, except that at
+      // present this will just lead to a "file not found" error.
+      name->clear();
+      *value = arg;
+      parsed_value = true;
+    } else {
+      *name = std::string(arg, 2);
+      *value = arg + 2;
+      parsed_value = !value->empty();
+    }
+  }
+
+  // Need to return true iff the next arg should be used as the value for this
+  // one, false otherwise.
+
+  if (parsed_value) {
+    // We already parsed a value for this flag.
+    return false;
+  }
+
+  if (*name == "-h" || *name == "--help" || *name == "--disallow_services" ||
+      *name == "--include_imports" || *name == "--include_source_info" ||
+      *name == "--version" || *name == "--decode_raw" ||
+      *name == "--print_free_field_numbers" ||
+      *name == "--experimental_allow_proto3_optional" ||
+      *name == "--deterministic_output" || *name == "--fatal_warnings") {
+    // HACK:  These are the only flags that don't take a value.
+    //   They probably should not be hard-coded like this but for now it's
+    //   not worth doing better.
+    return false;
+  }
+
+  // Next argument is the flag value.
+  return true;
+}
+
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::InterpretArgument(const std::string& name,
+                                        const std::string& value) {
+  if (name.empty()) {
+    // Not a flag.  Just a filename.
+    if (value.empty()) {
+      std::cerr
+          << "You seem to have passed an empty string as one of the "
+             "arguments to "
+          << executable_name_
+          << ".  This is actually "
+             "sort of hard to do.  Congrats.  Unfortunately it is not valid "
+             "input so the program is going to die now."
+          << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+#if defined(_WIN32)
+    // On Windows, the shell (typically cmd.exe) does not expand wildcards in
+    // file names (e.g. foo\*.proto), so we do it ourselves.
+    switch (google::protobuf::io::win32::ExpandWildcards(
+        value, [this](const std::string& path) {
+          this->input_files_.push_back(path);
+        })) {
+      case google::protobuf::io::win32::ExpandWildcardsResult::kSuccess:
+        break;
+      case google::protobuf::io::win32::ExpandWildcardsResult::
+          kErrorNoMatchingFile:
+        // Path does not exist, is not a file, or it's longer than MAX_PATH and
+        // long path handling is disabled.
+        std::cerr << "Invalid file name pattern or missing input file \""
+                  << value << "\"" << std::endl;
+        return PARSE_ARGUMENT_FAIL;
+      default:
+        std::cerr << "Cannot convert path \"" << value
+                  << "\" to or from Windows style" << std::endl;
+        return PARSE_ARGUMENT_FAIL;
+    }
+#else   // not _WIN32
+    // On other platforms than Windows (e.g. Linux, Mac OS) the shell (typically
+    // Bash) expands wildcards.
+    input_files_.push_back(value);
+#endif  // _WIN32
+
+  } else if (name == "-I" || name == "--proto_path") {
+    // Java's -classpath (and some other languages) delimits path components
+    // with colons.  Let's accept that syntax too just to make things more
+    // intuitive.
+    std::vector<std::string> parts = Split(
+        value, CommandLineInterface::kPathSeparator,
+        true);
+
+    for (int i = 0; i < parts.size(); i++) {
+      std::string virtual_path;
+      std::string disk_path;
+
+      std::string::size_type equals_pos = parts[i].find_first_of('=');
+      if (equals_pos == std::string::npos) {
+        virtual_path = "";
+        disk_path = parts[i];
+      } else {
+        virtual_path = parts[i].substr(0, equals_pos);
+        disk_path = parts[i].substr(equals_pos + 1);
+      }
+
+      if (disk_path.empty()) {
+        std::cerr
+            << "--proto_path passed empty directory name.  (Use \".\" for "
+               "current directory.)"
+            << std::endl;
+        return PARSE_ARGUMENT_FAIL;
+      }
+
+      // Make sure disk path exists, warn otherwise.
+      if (access(disk_path.c_str(), F_OK) < 0) {
+        // Try the original path; it may have just happened to have a '=' in it.
+        if (access(parts[i].c_str(), F_OK) < 0) {
+          std::cerr << disk_path << ": warning: directory does not exist."
+                    << std::endl;
+        } else {
+          virtual_path = "";
+          disk_path = parts[i];
+        }
+      }
+
+      // Don't use make_pair as the old/default standard library on Solaris
+      // doesn't support it without explicit template parameters, which are
+      // incompatible with C++0x's make_pair.
+      proto_path_.push_back(
+          std::pair<std::string, std::string>(virtual_path, disk_path));
+    }
+
+  } else if (name == "--direct_dependencies") {
+    if (direct_dependencies_explicitly_set_) {
+      std::cerr << name
+                << " may only be passed once. To specify multiple "
+                   "direct dependencies, pass them all as a single "
+                   "parameter separated by ':'."
+                << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+    direct_dependencies_explicitly_set_ = true;
+    std::vector<std::string> direct =
+        Split(value, ":", true);
+    GOOGLE_DCHECK(direct_dependencies_.empty());
+    direct_dependencies_.insert(direct.begin(), direct.end());
+
+  } else if (name == "--direct_dependencies_violation_msg") {
+    direct_dependencies_violation_msg_ = value;
+
+  } else if (name == "--descriptor_set_in") {
+    if (!descriptor_set_in_names_.empty()) {
+      std::cerr << name
+                << " may only be passed once. To specify multiple "
+                   "descriptor sets, pass them all as a single "
+                   "parameter separated by '"
+                << CommandLineInterface::kPathSeparator << "'." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    if (value.empty()) {
+      std::cerr << name << " requires a non-empty value." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    if (!dependency_out_name_.empty()) {
+      std::cerr << name << " cannot be used with --dependency_out."
+                << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+    descriptor_set_in_names_ = Split(
+        value, CommandLineInterface::kPathSeparator,
+        true);
+
+  } else if (name == "-o" || name == "--descriptor_set_out") {
+    if (!descriptor_set_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;
+    }
+    if (mode_ != MODE_COMPILE) {
+      std::cerr
+          << "Cannot use --encode or --decode and generate descriptors at the "
+             "same time."
+          << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    descriptor_set_out_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;
+    }
+    if (!descriptor_set_in_names_.empty()) {
+      std::cerr << name << " cannot be used with --descriptor_set_in."
+                << 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;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    imports_in_descriptor_set_ = true;
+
+  } else if (name == "--include_source_info") {
+    if (source_info_in_descriptor_set_) {
+      std::cerr << name << " may only be passed once." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    source_info_in_descriptor_set_ = true;
+
+  } else if (name == "-h" || name == "--help") {
+    PrintHelpText();
+    return PARSE_ARGUMENT_DONE_AND_EXIT;  // Exit without running compiler.
+
+  } else if (name == "--version") {
+    if (!version_info_.empty()) {
+      std::cout << version_info_ << std::endl;
+    }
+    std::cout << "libprotoc " << internal::VersionString(PROTOBUF_VERSION)
+              << PROTOBUF_VERSION_SUFFIX << std::endl;
+    return PARSE_ARGUMENT_DONE_AND_EXIT;  // Exit without running compiler.
+
+  } else if (name == "--disallow_services") {
+    disallow_services_ = true;
+
+
+  } else if (name == "--experimental_allow_proto3_optional") {
+    // Flag is no longer observed, but we allow it for backward compat.
+  } else if (name == "--encode" || name == "--decode" ||
+             name == "--decode_raw") {
+    if (mode_ != MODE_COMPILE) {
+      std::cerr << "Only one of --encode and --decode can be specified."
+                << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    if (!output_directives_.empty() || !descriptor_set_out_name_.empty()) {
+      std::cerr << "Cannot use " << name
+                << " and generate code or descriptors at the same time."
+                << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+    mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
+
+    if (value.empty() && name != "--decode_raw") {
+      std::cerr << "Type name for " << name << " cannot be blank." << std::endl;
+      if (name == "--decode") {
+        std::cerr << "To decode an unknown message, use --decode_raw."
+                  << std::endl;
+      }
+      return PARSE_ARGUMENT_FAIL;
+    } else if (!value.empty() && name == "--decode_raw") {
+      std::cerr << "--decode_raw does not take a parameter." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+    codec_type_ = value;
+
+  } else if (name == "--deterministic_output") {
+    deterministic_output_ = true;
+
+  } else if (name == "--error_format") {
+    if (value == "gcc") {
+      error_format_ = ERROR_FORMAT_GCC;
+    } else if (value == "msvs") {
+      error_format_ = ERROR_FORMAT_MSVS;
+    } else {
+      std::cerr << "Unknown error format: " << value << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+  } else if (name == "--fatal_warnings") {
+    if (fatal_warnings_) {
+      std::cerr << name << " may only be passed once." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    fatal_warnings_ = true;
+  } else if (name == "--plugin") {
+    if (plugin_prefix_.empty()) {
+      std::cerr << "This compiler does not support plugins." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+
+    std::string plugin_name;
+    std::string path;
+
+    std::string::size_type equals_pos = value.find_first_of('=');
+    if (equals_pos == std::string::npos) {
+      // Use the basename of the file.
+      std::string::size_type slash_pos = value.find_last_of('/');
+      if (slash_pos == std::string::npos) {
+        plugin_name = value;
+      } else {
+        plugin_name = value.substr(slash_pos + 1);
+      }
+      path = value;
+    } else {
+      plugin_name = value.substr(0, equals_pos);
+      path = value.substr(equals_pos + 1);
+    }
+
+    plugins_[plugin_name] = path;
+
+  } else if (name == "--print_free_field_numbers") {
+    if (mode_ != MODE_COMPILE) {
+      std::cerr << "Cannot use " << name
+                << " and use --encode, --decode or print "
+                << "other info at the same time." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    if (!output_directives_.empty() || !descriptor_set_out_name_.empty()) {
+      std::cerr << "Cannot use " << name
+                << " and generate code or descriptors at the same time."
+                << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    mode_ = MODE_PRINT;
+    print_mode_ = PRINT_FREE_FIELDS;
+  } else {
+    // Some other flag.  Look it up in the generators list.
+    const GeneratorInfo* generator_info =
+        FindOrNull(generators_by_flag_name_, name);
+    if (generator_info == nullptr &&
+        (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
+      // Check if it's a generator option flag.
+      generator_info = FindOrNull(generators_by_option_name_, name);
+      if (generator_info != nullptr) {
+        std::string* parameters =
+            &generator_parameters_[generator_info->flag_name];
+        if (!parameters->empty()) {
+          parameters->append(",");
+        }
+        parameters->append(value);
+      } else if (HasPrefixString(name, "--") && HasSuffixString(name, "_opt")) {
+        std::string* parameters =
+            &plugin_parameters_[PluginName(plugin_prefix_, name)];
+        if (!parameters->empty()) {
+          parameters->append(",");
+        }
+        parameters->append(value);
+      } else {
+        std::cerr << "Unknown flag: " << name << std::endl;
+        return PARSE_ARGUMENT_FAIL;
+      }
+    } else {
+      // It's an output flag.  Add it to the output directives.
+      if (mode_ != MODE_COMPILE) {
+        std::cerr << "Cannot use --encode, --decode or print .proto info and "
+                     "generate code at the same time."
+                  << std::endl;
+        return PARSE_ARGUMENT_FAIL;
+      }
+
+      OutputDirective directive;
+      directive.name = name;
+      if (generator_info == nullptr) {
+        directive.generator = nullptr;
+      } else {
+        directive.generator = generator_info->generator;
+      }
+
+      // Split value at ':' to separate the generator parameter from the
+      // filename.  However, avoid doing this if the colon is part of a valid
+      // Windows-style absolute path.
+      std::string::size_type colon_pos = value.find_first_of(':');
+      if (colon_pos == std::string::npos || IsWindowsAbsolutePath(value)) {
+        directive.output_location = value;
+      } else {
+        directive.parameter = value.substr(0, colon_pos);
+        directive.output_location = value.substr(colon_pos + 1);
+      }
+
+      output_directives_.push_back(directive);
+    }
+  }
+
+  return PARSE_ARGUMENT_DONE_AND_CONTINUE;
+}
+
+void CommandLineInterface::PrintHelpText() {
+  // Sorry for indentation here; line wrapping would be uglier.
+  std::cout << "Usage: " << executable_name_ << " [OPTION] PROTO_FILES";
+  std::cout << R"(
+Parse PROTO_FILES and generate output based on the options given:
+  -IPATH, --proto_path=PATH   Specify the directory in which to search for
+                              imports.  May be specified multiple times;
+                              directories will be searched in order.  If not
+                              given, the current working directory is used.
+                              If not found in any of the these directories,
+                              the --descriptor_set_in descriptors will be
+                              checked for required proto file.
+  --version                   Show version info and exit.
+  -h, --help                  Show this text and exit.
+  --encode=MESSAGE_TYPE       Read a text-format message of the given type
+                              from standard input and write it in binary
+                              to standard output.  The message type must
+                              be defined in PROTO_FILES or their imports.
+  --deterministic_output      When using --encode, ensure map fields are
+                              deterministically ordered. Note that this order
+                              is not canonical, and changes across builds or
+                              releases of protoc.
+  --decode=MESSAGE_TYPE       Read a binary message of the given type from
+                              standard input and write it in text format
+                              to standard output.  The message type must
+                              be defined in PROTO_FILES or their imports.
+  --decode_raw                Read an arbitrary protocol message from
+                              standard input and write the raw tag/value
+                              pairs in text format to standard output.  No
+                              PROTO_FILES should be given when using this
+                              flag.
+  --descriptor_set_in=FILES   Specifies a delimited list of FILES
+                              each containing a FileDescriptorSet (a
+                              protocol buffer defined in descriptor.proto).
+                              The FileDescriptor for each of the PROTO_FILES
+                              provided will be loaded from these
+                              FileDescriptorSets. If a FileDescriptor
+                              appears multiple times, the first occurrence
+                              will be used.
+  -oFILE,                     Writes a FileDescriptorSet (a protocol buffer,
+    --descriptor_set_out=FILE defined in descriptor.proto) containing all of
+                              the input files to FILE.
+  --include_imports           When using --descriptor_set_out, also include
+                              all dependencies of the input files in the
+                              set, so that the set is self-contained.
+  --include_source_info       When using --descriptor_set_out, do not strip
+                              SourceCodeInfo from the FileDescriptorProto.
+                              This results in vastly larger descriptors that
+                              include information about the original
+                              location of each decl in the source file as
+                              well as surrounding comments.
+  --dependency_out=FILE       Write a dependency output file in the format
+                              expected by make. This writes the transitive
+                              set of input file paths to FILE
+  --error_format=FORMAT       Set the format in which to print errors.
+                              FORMAT may be 'gcc' (the default) or 'msvs'
+                              (Microsoft Visual Studio format).
+  --fatal_warnings            Make warnings be fatal (similar to -Werr in
+                              gcc). This flag will make protoc return
+                              with a non-zero exit code if any warnings
+                              are generated.
+  --print_free_field_numbers  Print the free field numbers of the messages
+                              defined in the given proto files. Groups share
+                              the same field number space with the parent
+                              message. Extension ranges are counted as
+                              occupied fields numbers.)";
+  if (!plugin_prefix_.empty()) {
+    std::cout << R"(
+  --plugin=EXECUTABLE         Specifies a plugin executable to use.
+                              Normally, protoc searches the PATH for
+                              plugins, but you may specify additional
+                              executables not in the path using this flag.
+                              Additionally, EXECUTABLE may be of the form
+                              NAME=PATH, in which case the given plugin name
+                              is mapped to the given executable even if
+                              the executable's own name differs.)";
+  }
+
+  for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
+       iter != generators_by_flag_name_.end(); ++iter) {
+    // FIXME(kenton):  If the text is long enough it will wrap, which is ugly,
+    //   but fixing this nicely (e.g. splitting on spaces) is probably more
+    //   trouble than it's worth.
+    std::cout << std::endl
+              << "  " << iter->first << "=OUT_DIR "
+              << std::string(19 - iter->first.size(),
+                             ' ')  // Spaces for alignment.
+              << iter->second.help_text;
+  }
+  std::cout << R"(
+  @<filename>                 Read options and filenames from file. If a
+                              relative file path is specified, the file
+                              will be searched in the working directory.
+                              The --proto_path option will not affect how
+                              this argument file is searched. Content of
+                              the file will be expanded in the position of
+                              @<filename> as in the argument list. Note
+                              that shell expansion is not applied to the
+                              content of the file (i.e., you cannot use
+                              quotes, wildcards, escapes, commands, etc.).
+                              Each line corresponds to a single argument,
+                              even if it contains spaces.)";
+  std::cout << std::endl;
+}
+
+bool CommandLineInterface::EnforceProto3OptionalSupport(
+    const std::string& codegen_name, uint64_t supported_features,
+    const std::vector<const FileDescriptor*>& parsed_files) const {
+  bool supports_proto3_optional =
+      supported_features & CodeGenerator::FEATURE_PROTO3_OPTIONAL;
+  if (!supports_proto3_optional) {
+    for (const auto fd : parsed_files) {
+      if (ContainsProto3Optional(fd)) {
+        std::cerr << fd->name()
+                  << ": is a proto3 file that contains optional fields, but "
+                     "code generator "
+                  << codegen_name
+                  << " hasn't been updated to support optional fields in "
+                     "proto3. Please ask the owner of this code generator to "
+                     "support proto3 optional.";
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool CommandLineInterface::GenerateOutput(
+    const std::vector<const FileDescriptor*>& parsed_files,
+    const OutputDirective& output_directive,
+    GeneratorContext* generator_context) {
+  // Call the generator.
+  std::string error;
+  if (output_directive.generator == nullptr) {
+    // This is a plugin.
+    GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") &&
+          HasSuffixString(output_directive.name, "_out"))
+        << "Bad name for plugin generator: " << output_directive.name;
+
+    std::string plugin_name = PluginName(plugin_prefix_, output_directive.name);
+    std::string parameters = output_directive.parameter;
+    if (!plugin_parameters_[plugin_name].empty()) {
+      if (!parameters.empty()) {
+        parameters.append(",");
+      }
+      parameters.append(plugin_parameters_[plugin_name]);
+    }
+    if (!GeneratePluginOutput(parsed_files, plugin_name, parameters,
+                              generator_context, &error)) {
+      std::cerr << output_directive.name << ": " << error << std::endl;
+      return false;
+    }
+  } else {
+    // Regular generator.
+    std::string parameters = output_directive.parameter;
+    if (!generator_parameters_[output_directive.name].empty()) {
+      if (!parameters.empty()) {
+        parameters.append(",");
+      }
+      parameters.append(generator_parameters_[output_directive.name]);
+    }
+    if (!EnforceProto3OptionalSupport(
+            output_directive.name,
+            output_directive.generator->GetSupportedFeatures(), parsed_files)) {
+      return false;
+    }
+
+    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;
+    }
+  }
+
+  return true;
+}
+
+bool CommandLineInterface::GenerateDependencyManifestFile(
+    const std::vector<const FileDescriptor*>& parsed_files,
+    const GeneratorContextMap& output_directories,
+    DiskSourceTree* source_tree) {
+  FileDescriptorSet file_set;
+
+  std::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());
+  }
+
+  std::vector<std::string> output_filenames;
+  for (const auto& pair : output_directories) {
+    const std::string& location = pair.first;
+    GeneratorContextImpl* directory = pair.second.get();
+    std::vector<std::string> relative_output_filenames;
+    directory->GetOutputFilenames(&relative_output_filenames);
+    for (int i = 0; i < relative_output_filenames.size(); i++) {
+      std::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);
+    }
+  }
+
+  if (!descriptor_set_out_name_.empty()) {
+    output_filenames.push_back(descriptor_set_out_name_);
+  }
+
+  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 std::string& virtual_file = file.name();
+    std::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;
+    }
+  }
+
+  return true;
+}
+
+bool CommandLineInterface::GeneratePluginOutput(
+    const std::vector<const FileDescriptor*>& parsed_files,
+    const std::string& plugin_name, const std::string& parameter,
+    GeneratorContext* generator_context, std::string* error) {
+  CodeGeneratorRequest request;
+  CodeGeneratorResponse response;
+  std::string processed_parameter = parameter;
+
+
+  // Build the request.
+  if (!processed_parameter.empty()) {
+    request.set_parameter(processed_parameter);
+  }
+
+
+  std::set<const FileDescriptor*> already_seen;
+  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());
+  }
+
+  google::protobuf::compiler::Version* version =
+      request.mutable_compiler_version();
+  version->set_major(PROTOBUF_VERSION / 1000000);
+  version->set_minor(PROTOBUF_VERSION / 1000 % 1000);
+  version->set_patch(PROTOBUF_VERSION % 1000);
+  version->set_suffix(PROTOBUF_VERSION_SUFFIX);
+
+  // Invoke the plugin.
+  Subprocess subprocess;
+
+  if (plugins_.count(plugin_name) > 0) {
+    subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME);
+  } else {
+    subprocess.Start(plugin_name, Subprocess::SEARCH_PATH);
+  }
+
+  std::string communicate_error;
+  if (!subprocess.Communicate(request, &response, &communicate_error)) {
+    *error = strings::Substitute("$0: $1", plugin_name, communicate_error);
+    return false;
+  }
+
+  // Write the files.  We do this even if there was a generator error in order
+  // to match the behavior of a compiled-in generator.
+  std::unique_ptr<io::ZeroCopyOutputStream> current_output;
+  for (int i = 0; i < response.file_size(); i++) {
+    const CodeGeneratorResponse::File& output_file = response.file(i);
+
+    if (!output_file.insertion_point().empty()) {
+      std::string filename = output_file.name();
+      // Open a file for insert.
+      // We reset current_output to nullptr first so that the old file is closed
+      // before the new one is opened.
+      current_output.reset();
+      current_output.reset(
+          generator_context->OpenForInsertWithGeneratedCodeInfo(
+              filename, output_file.insertion_point(),
+              output_file.generated_code_info()));
+    } else if (!output_file.name().empty()) {
+      // Starting a new file.  Open it.
+      // We reset current_output to nullptr first so that the old file is closed
+      // before the new one is opened.
+      current_output.reset();
+      current_output.reset(generator_context->Open(output_file.name()));
+    } else if (current_output == nullptr) {
+      *error = strings::Substitute(
+          "$0: First file chunk returned by plugin did not specify a file "
+          "name.",
+          plugin_name);
+      return false;
+    }
+
+    // Use CodedOutputStream for convenience; otherwise we'd need to provide
+    // our own buffer-copying loop.
+    io::CodedOutputStream writer(current_output.get());
+    writer.WriteString(output_file.content());
+  }
+
+  // Check for errors.
+  if (!response.error().empty()) {
+    // Generator returned an error.
+    *error = response.error();
+    return false;
+  } else if (!EnforceProto3OptionalSupport(
+                 plugin_name, response.supported_features(), parsed_files)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
+  // Look up the type.
+  const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
+  if (type == nullptr) {
+    std::cerr << "Type not defined: " << codec_type_ << std::endl;
+    return false;
+  }
+
+  DynamicMessageFactory dynamic_factory(pool);
+  std::unique_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
+
+  if (mode_ == MODE_ENCODE) {
+    SetFdToTextMode(STDIN_FILENO);
+    SetFdToBinaryMode(STDOUT_FILENO);
+  } else {
+    SetFdToBinaryMode(STDIN_FILENO);
+    SetFdToTextMode(STDOUT_FILENO);
+  }
+
+  io::FileInputStream in(STDIN_FILENO);
+  io::FileOutputStream out(STDOUT_FILENO);
+
+  if (mode_ == MODE_ENCODE) {
+    // Input is text.
+    ErrorPrinter error_collector(error_format_);
+    TextFormat::Parser parser;
+    parser.RecordErrorsTo(&error_collector);
+    parser.AllowPartialMessage(true);
+
+    if (!parser.Parse(&in, message.get())) {
+      std::cerr << "Failed to parse input." << std::endl;
+      return false;
+    }
+  } else {
+    // Input is binary.
+    if (!message->ParsePartialFromZeroCopyStream(&in)) {
+      std::cerr << "Failed to parse input." << std::endl;
+      return false;
+    }
+  }
+
+  if (!message->IsInitialized()) {
+    std::cerr << "warning:  Input message is missing required fields:  "
+              << message->InitializationErrorString() << std::endl;
+  }
+
+  if (mode_ == MODE_ENCODE) {
+    // Output is binary.
+    io::CodedOutputStream coded_out(&out);
+    coded_out.SetSerializationDeterministic(deterministic_output_);
+    if (!message->SerializePartialToCodedStream(&coded_out)) {
+      std::cerr << "output: I/O error." << std::endl;
+      return false;
+    }
+  } else {
+    // Output is text.
+    if (!TextFormat::Print(*message, &out)) {
+      std::cerr << "output: I/O error." << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool CommandLineInterface::WriteDescriptorSet(
+    const std::vector<const FileDescriptor*>& parsed_files) {
+  FileDescriptorSet file_set;
+
+  std::set<const FileDescriptor*> already_seen;
+  if (!imports_in_descriptor_set_) {
+    // Since we don't want to output transitive dependencies, but we do want
+    // things to be in dependency order, add all dependencies that aren't in
+    // parsed_files to already_seen.  This will short circuit the recursion
+    // in GetTransitiveDependencies.
+    std::set<const FileDescriptor*> to_output;
+    to_output.insert(parsed_files.begin(), parsed_files.end());
+    for (int i = 0; i < parsed_files.size(); i++) {
+      const FileDescriptor* file = parsed_files[i];
+      for (int j = 0; j < file->dependency_count(); j++) {
+        const FileDescriptor* dependency = file->dependency(j);
+        // if the dependency isn't in parsed files, mark it as already seen
+        if (to_output.find(dependency) == to_output.end()) {
+          already_seen.insert(dependency);
+        }
+      }
+    }
+  }
+  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());
+  }
+
+  int fd;
+  do {
+    fd = open(descriptor_set_out_name_.c_str(),
+              O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+  } while (fd < 0 && errno == EINTR);
+
+  if (fd < 0) {
+    perror(descriptor_set_out_name_.c_str());
+    return false;
+  }
+
+  io::FileOutputStream out(fd);
+
+  {
+    io::CodedOutputStream coded_out(&out);
+    // Determinism is useful here because build outputs are sometimes checked
+    // into version control.
+    coded_out.SetSerializationDeterministic(true);
+    if (!file_set.SerializeToCodedStream(&coded_out)) {
+      std::cerr << descriptor_set_out_name_ << ": " << strerror(out.GetErrno())
+                << std::endl;
+      out.Close();
+      return false;
+    }
+  }
+
+  if (!out.Close()) {
+    std::cerr << descriptor_set_out_name_ << ": " << strerror(out.GetErrno())
+              << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+void CommandLineInterface::GetTransitiveDependencies(
+    const FileDescriptor* file, bool include_json_name,
+    bool include_source_code_info,
+    std::set<const FileDescriptor*>* already_seen,
+    RepeatedPtrField<FileDescriptorProto>* output) {
+  if (!already_seen->insert(file).second) {
+    // Already saw this file.  Skip.
+    return;
+  }
+
+  // Add all dependencies.
+  for (int i = 0; i < file->dependency_count(); i++) {
+    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);
+  }
+}
+
+namespace {
+
+// Utility function for PrintFreeFieldNumbers.
+// Stores occupied ranges into the ranges parameter, and next level of sub
+// message types into the nested_messages parameter.  The FieldRange is left
+// inclusive, right exclusive. i.e. [a, b).
+//
+// Nested Messages:
+// Note that it only stores the nested message type, iff the nested type is
+// either a direct child of the given descriptor, or the nested type is a
+// descendant of the given descriptor and all the nodes between the
+// nested type and the given descriptor are group types. e.g.
+//
+// message Foo {
+//   message Bar {
+//     message NestedBar {}
+//   }
+//   group Baz = 1 {
+//     group NestedBazGroup = 2 {
+//       message Quz {
+//         message NestedQuz {}
+//       }
+//     }
+//     message NestedBaz {}
+//   }
+// }
+//
+// In this case, Bar, Quz and NestedBaz will be added into the nested types.
+// Since free field numbers of group types will not be printed, this makes sure
+// the nested message types in groups will not be dropped. The nested_messages
+// parameter will contain the direct children (when groups are ignored in the
+// tree) of the given descriptor for the caller to traverse. The declaration
+// order of the nested messages is also preserved.
+typedef std::pair<int, int> FieldRange;
+void GatherOccupiedFieldRanges(
+    const Descriptor* descriptor, std::set<FieldRange>* ranges,
+    std::vector<const Descriptor*>* nested_messages) {
+  std::set<const Descriptor*> groups;
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* fd = descriptor->field(i);
+    ranges->insert(FieldRange(fd->number(), fd->number() + 1));
+    if (fd->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(fd->message_type());
+    }
+  }
+  for (int i = 0; i < descriptor->extension_range_count(); ++i) {
+    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) {
+    const Descriptor* nested_desc = descriptor->nested_type(i);
+    if (groups.find(nested_desc) != groups.end()) {
+      GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
+    } else {
+      nested_messages->push_back(nested_desc);
+    }
+  }
+}
+
+// Utility function for PrintFreeFieldNumbers.
+// Actually prints the formatted free field numbers for given message name and
+// occupied ranges.
+void FormatFreeFieldNumbers(const std::string& name,
+                            const std::set<FieldRange>& ranges) {
+  std::string output;
+  StringAppendF(&output, "%-35s free:", name.c_str());
+  int next_free_number = 1;
+  for (std::set<FieldRange>::const_iterator i = ranges.begin();
+       i != ranges.end(); ++i) {
+    // This happens when groups re-use parent field numbers, in which
+    // case we skip the FieldRange entirely.
+    if (next_free_number >= i->second) continue;
+
+    if (next_free_number < i->first) {
+      if (next_free_number + 1 == i->first) {
+        // Singleton
+        StringAppendF(&output, " %d", next_free_number);
+      } else {
+        // Range
+        StringAppendF(&output, " %d-%d", next_free_number,
+                              i->first - 1);
+      }
+    }
+    next_free_number = i->second;
+  }
+  if (next_free_number <= FieldDescriptor::kMaxNumber) {
+    StringAppendF(&output, " %d-INF", next_free_number);
+  }
+  std::cout << output << std::endl;
+}
+
+}  // namespace
+
+void CommandLineInterface::PrintFreeFieldNumbers(const Descriptor* descriptor) {
+  std::set<FieldRange> ranges;
+  std::vector<const Descriptor*> nested_messages;
+  GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
+
+  for (int i = 0; i < nested_messages.size(); ++i) {
+    PrintFreeFieldNumbers(nested_messages[i]);
+  }
+  FormatFreeFieldNumbers(descriptor->full_name(), ranges);
+}
+
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
new file mode 100644
index 0000000..e842550
--- /dev/null
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -0,0 +1,464 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Implements the Protocol Compiler front-end such that it may be reused by
+// custom compilers written to support other languages.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
+#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;           // descriptor.h
+class DescriptorDatabase;   // descriptor_database.h
+class DescriptorPool;       // descriptor.h
+class FileDescriptor;       // descriptor.h
+class FileDescriptorSet;    // descriptor.h
+class FileDescriptorProto;  // descriptor.pb.h
+template <typename T>
+class RepeatedPtrField;          // repeated_field.h
+class SimpleDescriptorDatabase;  // descriptor_database.h
+
+namespace compiler {
+
+class CodeGenerator;     // code_generator.h
+class GeneratorContext;  // code_generator.h
+class DiskSourceTree;    // importer.h
+
+// This class implements the command-line interface to the protocol compiler.
+// It is designed to make it very easy to create a custom protocol compiler
+// supporting the languages of your choice.  For example, if you wanted to
+// create a custom protocol compiler binary which includes both the regular
+// C++ support plus support for your own custom output "Foo", you would
+// write a class "FooGenerator" which implements the CodeGenerator interface,
+// then write a main() procedure like this:
+//
+//   int main(int argc, char* argv[]) {
+//     google::protobuf::compiler::CommandLineInterface cli;
+//
+//     // Support generation of C++ source and headers.
+//     google::protobuf::compiler::cpp::CppGenerator cpp_generator;
+//     cli.RegisterGenerator("--cpp_out", &cpp_generator,
+//       "Generate C++ source and header.");
+//
+//     // Support generation of Foo code.
+//     FooGenerator foo_generator;
+//     cli.RegisterGenerator("--foo_out", &foo_generator,
+//       "Generate Foo file.");
+//
+//     return cli.Run(argc, argv);
+//   }
+//
+// The compiler is invoked with syntax like:
+//   protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto
+//
+// The .proto file to compile can be specified on the command line using either
+// its physical file path, or a virtual path relative to a directory specified
+// in --proto_path. For example, for src/foo.proto, the following two protoc
+// invocations work the same way:
+//   1. protoc --proto_path=src src/foo.proto (physical file path)
+//   2. protoc --proto_path=src foo.proto (virtual path relative to src)
+//
+// If a file path can be interpreted both as a physical file path and as a
+// relative virtual path, the physical file path takes precedence.
+//
+// For a full description of the command-line syntax, invoke it with --help.
+class PROTOC_EXPORT CommandLineInterface {
+ public:
+  static const char* const kPathSeparator;
+
+  CommandLineInterface();
+  ~CommandLineInterface();
+
+  // Register a code generator for a language.
+  //
+  // Parameters:
+  // * flag_name: The command-line flag used to specify an output file of
+  //   this type.  The name must start with a '-'.  If the name is longer
+  //   than one letter, it must start with two '-'s.
+  // * generator: The CodeGenerator which will be called to generate files
+  //   of this type.
+  // * help_text: Text describing this flag in the --help output.
+  //
+  // Some generators accept extra parameters.  You can specify this parameter
+  // on the command-line by placing it before the output directory, separated
+  // by a colon:
+  //   protoc --foo_out=enable_bar:outdir
+  // The text before the colon is passed to CodeGenerator::Generate() as the
+  // "parameter".
+  void RegisterGenerator(const std::string& flag_name, CodeGenerator* generator,
+                         const std::string& help_text);
+
+  // Register a code generator for a language.
+  // Besides flag_name you can specify another option_flag_name that could be
+  // used to pass extra parameters to the registered code generator.
+  // Suppose you have registered a generator by calling:
+  //   command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...)
+  // Then you could invoke the compiler with a command like:
+  //   protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz
+  // This will pass "enable_bar,enable_baz" as the parameter to the generator.
+  void RegisterGenerator(const std::string& flag_name,
+                         const std::string& option_flag_name,
+                         CodeGenerator* generator,
+                         const std::string& help_text);
+
+  // Enables "plugins".  In this mode, if a command-line flag ends with "_out"
+  // but does not match any registered generator, the compiler will attempt to
+  // find a "plugin" to implement the generator.  Plugins are just executables.
+  // They should live somewhere in the PATH.
+  //
+  // The compiler determines the executable name to search for by concatenating
+  // exe_name_prefix with the unrecognized flag name, removing "_out".  So, for
+  // example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out,
+  // the compiler will try to run the program "protoc-gen-foo".
+  //
+  // The plugin program should implement the following usage:
+  //   plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS
+  // --out indicates the output directory (as passed to the --foo_out
+  // parameter); if omitted, the current directory should be used.  --parameter
+  // gives the generator parameter, if any was provided (see below).  The
+  // PROTO_FILES list the .proto files which were given on the compiler
+  // command-line; these are the files for which the plugin is expected to
+  // generate output code.  Finally, DESCRIPTORS is an encoded FileDescriptorSet
+  // (as defined in descriptor.proto).  This is piped to the plugin's stdin.
+  // The set will include descriptors for all the files listed in PROTO_FILES as
+  // well as all files that they import.  The plugin MUST NOT attempt to read
+  // the PROTO_FILES directly -- it must use the FileDescriptorSet.
+  //
+  // The plugin should generate whatever files are necessary, as code generators
+  // normally do.  It should write the names of all files it generates to
+  // stdout.  The names should be relative to the output directory, NOT absolute
+  // names or relative to the current directory.  If any errors occur, error
+  // messages should be written to stderr.  If an error is fatal, the plugin
+  // should exit with a non-zero exit code.
+  //
+  // Plugins can have generator parameters similar to normal built-in
+  // generators. Extra generator parameters can be passed in via a matching
+  // "_opt" parameter. For example:
+  //   protoc --plug_out=enable_bar:outdir --plug_opt=enable_baz
+  // This will pass "enable_bar,enable_baz" as the parameter to the plugin.
+  //
+  void AllowPlugins(const std::string& exe_name_prefix);
+
+  // Run the Protocol Compiler with the given command-line parameters.
+  // Returns the error code which should be returned by main().
+  //
+  // It may not be safe to call Run() in a multi-threaded environment because
+  // it calls strerror().  I'm not sure why you'd want to do this anyway.
+  int Run(int argc, const char* const argv[]);
+
+  // DEPRECATED. Calling this method has no effect. Protocol compiler now
+  // always try to find the .proto file relative to the current directory
+  // first and if the file is not found, it will then treat the input path
+  // as a virtual path.
+  void SetInputsAreProtoPathRelative(bool /* enable */) {}
+
+  // Provides some text which will be printed when the --version flag is
+  // used.  The version of libprotoc will also be printed on the next line
+  // after this text.
+  void SetVersionInfo(const std::string& text) { version_info_ = text; }
+
+
+ private:
+  // -----------------------------------------------------------------
+
+  class ErrorPrinter;
+  class GeneratorContextImpl;
+  class MemoryOutputStream;
+  typedef std::unordered_map<std::string, std::unique_ptr<GeneratorContextImpl>>
+      GeneratorContextMap;
+
+  // Clear state from previous Run().
+  void Clear();
+
+  // Remaps the proto file so that it is relative to one of the directories
+  // in proto_path_.  Returns false if an error occurred.
+  bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree,
+                                  std::string* proto,
+                                  DescriptorDatabase* fallback_database);
+
+  // Remaps each file in input_files_ so that it is relative to one of the
+  // directories in proto_path_.  Returns false if an error occurred.
+  bool MakeInputsBeProtoPathRelative(DiskSourceTree* source_tree,
+                                     DescriptorDatabase* fallback_database);
+
+  // Fails if these files use proto3 optional and the code generator doesn't
+  // support it. This is a permanent check.
+  bool EnforceProto3OptionalSupport(
+      const std::string& codegen_name, uint64_t supported_features,
+      const std::vector<const FileDescriptor*>& parsed_files) const;
+
+
+  // Return status for ParseArguments() and InterpretArgument().
+  enum ParseArgumentStatus {
+    PARSE_ARGUMENT_DONE_AND_CONTINUE,
+    PARSE_ARGUMENT_DONE_AND_EXIT,
+    PARSE_ARGUMENT_FAIL
+  };
+
+  // Parse all command-line arguments.
+  ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
+
+  // Read an argument file and append the file's content to the list of
+  // arguments. Return false if the file cannot be read.
+  bool ExpandArgumentFile(const std::string& file,
+                          std::vector<std::string>* arguments);
+
+  // Parses a command-line argument into a name/value pair.  Returns
+  // true if the next argument in the argv should be used as the value,
+  // false otherwise.
+  //
+  // Examples:
+  //   "-Isrc/protos" ->
+  //     name = "-I", value = "src/protos"
+  //   "--cpp_out=src/foo.pb2.cc" ->
+  //     name = "--cpp_out", value = "src/foo.pb2.cc"
+  //   "foo.proto" ->
+  //     name = "", value = "foo.proto"
+  bool ParseArgument(const char* arg, std::string* name, std::string* value);
+
+  // Interprets arguments parsed with ParseArgument.
+  ParseArgumentStatus InterpretArgument(const std::string& name,
+                                        const std::string& value);
+
+  // Print the --help text to stderr.
+  void PrintHelpText();
+
+  // Loads proto_path_ into the provided source_tree.
+  bool InitializeDiskSourceTree(DiskSourceTree* source_tree,
+                                DescriptorDatabase* fallback_database);
+
+  // Verify that all the input files exist in the given database.
+  bool VerifyInputFilesInDescriptors(DescriptorDatabase* fallback_database);
+
+  // Parses input_files_ into parsed_files
+  bool ParseInputFiles(DescriptorPool* descriptor_pool,
+                       DiskSourceTree* source_tree,
+                       std::vector<const FileDescriptor*>* parsed_files);
+
+  // Generate the given output file from the given input.
+  struct OutputDirective;  // see below
+  bool GenerateOutput(const std::vector<const FileDescriptor*>& parsed_files,
+                      const OutputDirective& output_directive,
+                      GeneratorContext* generator_context);
+  bool GeneratePluginOutput(
+      const std::vector<const FileDescriptor*>& parsed_files,
+      const std::string& plugin_name, const std::string& parameter,
+      GeneratorContext* generator_context, std::string* error);
+
+  // Implements --encode and --decode.
+  bool EncodeOrDecode(const DescriptorPool* pool);
+
+  // Implements the --descriptor_set_out option.
+  bool WriteDescriptorSet(
+      const std::vector<const FileDescriptor*>& parsed_files);
+
+  // Implements the --dependency_out option
+  bool GenerateDependencyManifestFile(
+      const std::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
+  // depends on it, so that you can call DescriptorPool::BuildFile() on them
+  // 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,
+      std::set<const FileDescriptor*>* already_seen,
+      RepeatedPtrField<FileDescriptorProto>* output);
+
+  // Implements the --print_free_field_numbers. This function prints free field
+  // numbers into stdout for the message and it's nested message types in
+  // post-order, i.e. nested types first. Printed range are left-right
+  // inclusive, i.e. [a, b].
+  //
+  // Groups:
+  // For historical reasons, groups are considered to share the same
+  // field number space with the parent message, thus it will not print free
+  // field numbers for groups. The field numbers used in the groups are
+  // excluded in the free field numbers of the parent message.
+  //
+  // Extension Ranges:
+  // Extension ranges are considered ocuppied field numbers and they will not be
+  // listed as free numbers in the output.
+  void PrintFreeFieldNumbers(const Descriptor* descriptor);
+
+  // -----------------------------------------------------------------
+
+  // The name of the executable as invoked (i.e. argv[0]).
+  std::string executable_name_;
+
+  // Version info set with SetVersionInfo().
+  std::string version_info_;
+
+  // Registered generators.
+  struct GeneratorInfo {
+    std::string flag_name;
+    std::string option_flag_name;
+    CodeGenerator* generator;
+    std::string help_text;
+  };
+  typedef std::map<std::string, GeneratorInfo> GeneratorMap;
+  GeneratorMap generators_by_flag_name_;
+  GeneratorMap generators_by_option_name_;
+  // A map from generator names to the parameters specified using the option
+  // flag. For example, if the user invokes the compiler with:
+  //   protoc --foo_out=outputdir --foo_opt=enable_bar ...
+  // Then there will be an entry ("--foo_out", "enable_bar") in this map.
+  std::map<std::string, std::string> generator_parameters_;
+  // Similar to generator_parameters_, but stores the parameters for plugins.
+  std::map<std::string, std::string> plugin_parameters_;
+
+  // See AllowPlugins().  If this is empty, plugins aren't allowed.
+  std::string plugin_prefix_;
+
+  // Maps specific plugin names to files.  When executing a plugin, this map
+  // is searched first to find the plugin executable.  If not found here, the
+  // PATH (or other OS-specific search strategy) is searched.
+  std::map<std::string, std::string> plugins_;
+
+  // Stuff parsed from command line.
+  enum Mode {
+    MODE_COMPILE,  // Normal mode:  parse .proto files and compile them.
+    MODE_ENCODE,   // --encode:  read text from stdin, write binary to stdout.
+    MODE_DECODE,   // --decode:  read binary from stdin, write text to stdout.
+    MODE_PRINT,    // Print mode: print info of the given .proto files and exit.
+  };
+
+  Mode mode_ = MODE_COMPILE;
+
+  enum PrintMode {
+    PRINT_NONE,         // Not in MODE_PRINT
+    PRINT_FREE_FIELDS,  // --print_free_fields
+  };
+
+  PrintMode print_mode_ = PRINT_NONE;
+
+  enum ErrorFormat {
+    ERROR_FORMAT_GCC,  // GCC error output format (default).
+    ERROR_FORMAT_MSVS  // Visual Studio output (--error_format=msvs).
+  };
+
+  ErrorFormat error_format_ = ERROR_FORMAT_GCC;
+
+  // True if we should treat warnings as errors that fail the compilation.
+  bool fatal_warnings_ = false;
+
+  std::vector<std::pair<std::string, std::string> >
+      proto_path_;                        // Search path for proto files.
+  std::vector<std::string> input_files_;  // Names of the input proto files.
+
+  // Names of proto files which are allowed to be imported. Used by build
+  // systems to enforce depend-on-what-you-import.
+  std::set<std::string> direct_dependencies_;
+  bool direct_dependencies_explicitly_set_ = false;
+
+  // If there's a violation of depend-on-what-you-import, this string will be
+  // presented to the user. "%s" will be replaced with the violating import.
+  std::string direct_dependencies_violation_msg_;
+
+  // output_directives_ lists all the files we are supposed to output and what
+  // generator to use for each.
+  struct OutputDirective {
+    std::string name;          // E.g. "--foo_out"
+    CodeGenerator* generator;  // NULL for plugins
+    std::string parameter;
+    std::string output_location;
+  };
+  std::vector<OutputDirective> output_directives_;
+
+  // When using --encode or --decode, this names the type we are encoding or
+  // decoding.  (Empty string indicates --decode_raw.)
+  std::string codec_type_;
+
+  // If --descriptor_set_in was given, these are filenames containing
+  // parsed FileDescriptorSets to be used for loading protos.  Otherwise, empty.
+  std::vector<std::string> descriptor_set_in_names_;
+
+  // If --descriptor_set_out was given, this is the filename to which the
+  // FileDescriptorSet should be written.  Otherwise, empty.
+  std::string descriptor_set_out_name_;
+
+  // If --dependency_out was given, this is the path to the file where the
+  // dependency file will be written. Otherwise, empty.
+  std::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.
+  bool imports_in_descriptor_set_;
+
+  // True if --include_source_info was given, meaning that we should not strip
+  // SourceCodeInfo from the DescriptorSet.
+  bool source_info_in_descriptor_set_ = false;
+
+  // Was the --disallow_services flag used?
+  bool disallow_services_ = false;
+
+  // When using --encode, this will be passed to SetSerializationDeterministic.
+  bool deterministic_output_ = false;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface);
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
new file mode 100644
index 0000000..f48135e
--- /dev/null
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -0,0 +1,2787 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cstdint>
+
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/mock_code_generator.h>
+#include <google/protobuf/compiler/subprocess.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#if defined(_WIN32)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::dup;
+using google::protobuf::io::win32::dup2;
+using google::protobuf::io::win32::open;
+using google::protobuf::io::win32::write;
+#endif
+
+// 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 {
+
+bool FileExists(const std::string& path) {
+  return File::Exists(path);
+}
+
+class CommandLineInterfaceTest : public testing::Test {
+ protected:
+  void SetUp() override;
+  void TearDown() override;
+
+  // Runs the CommandLineInterface with the given command line.  The
+  // command is automatically split on spaces, and the string "$tmpdir"
+  // is replaced with TestTempDir().
+  void Run(const std::string& command);
+  void RunWithArgs(std::vector<std::string> args);
+
+  // -----------------------------------------------------------------
+  // Methods to set up the test (called before Run()).
+
+  class NullCodeGenerator;
+
+  // Normally plugins are allowed for all tests.  Call this to explicitly
+  // disable them.
+  void DisallowPlugins() { disallow_plugins_ = true; }
+
+  // Create a temp file within temp_directory_ with the given name.
+  // The containing directory is also created if necessary.
+  void CreateTempFile(const std::string& name, const std::string& contents);
+
+  // Create a subdirectory within temp_directory_.
+  void CreateTempDir(const std::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
+
+  // -----------------------------------------------------------------
+  // Methods to check the test results (called after Run()).
+
+  // Checks that no text was written to stderr during Run(), and Run()
+  // returned 0.
+  void ExpectNoErrors();
+
+  // Checks that Run() returned non-zero and the stderr output is exactly
+  // the text given.  expected_test may contain references to "$tmpdir",
+  // which will be replaced by the temporary directory path.
+  void ExpectErrorText(const std::string& expected_text);
+
+  // Checks that Run() returned non-zero and the stderr contains the given
+  // substring.
+  void ExpectErrorSubstring(const std::string& expected_substring);
+
+  // Checks that Run() returned zero and the stderr contains the given
+  // substring.
+  void ExpectWarningSubstring(const std::string& expected_substring);
+
+  // Checks that the captured stdout is the same as the expected_text.
+  void ExpectCapturedStdout(const std::string& expected_text);
+
+  // Checks that Run() returned zero and the stdout contains the given
+  // substring.
+  void ExpectCapturedStdoutSubstringWithZeroReturnCode(
+      const std::string& expected_substring);
+
+  // Checks that Run() returned zero and the stderr contains the given
+  // substring.
+  void ExpectCapturedStderrSubstringWithZeroReturnCode(
+      const std::string& expected_substring);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Returns true if ExpectErrorSubstring(expected_substring) would pass, but
+  // does not fail otherwise.
+  bool HasAlternateErrorSubstring(const std::string& expected_substring);
+#endif  // _WIN32 && !__CYGWIN__
+
+  // Checks that MockCodeGenerator::Generate() was called in the given
+  // context (or the generator in test_plugin.cc, which produces the same
+  // output).  That is, this tests if the generator with the given name
+  // was called with the given parameter and proto file and produced the
+  // given output file.  This is checked by reading the output file and
+  // checking that it contains the content that MockCodeGenerator would
+  // generate given these inputs.  message_name is the name of the first
+  // message that appeared in the proto file; this is just to make extra
+  // sure that the correct file was parsed.
+  void ExpectGenerated(const std::string& generator_name,
+                       const std::string& parameter,
+                       const std::string& proto_name,
+                       const std::string& message_name);
+  void ExpectGenerated(const std::string& generator_name,
+                       const std::string& parameter,
+                       const std::string& proto_name,
+                       const std::string& message_name,
+                       const std::string& output_directory);
+  void ExpectGeneratedWithMultipleInputs(const std::string& generator_name,
+                                         const std::string& all_proto_names,
+                                         const std::string& proto_name,
+                                         const std::string& message_name);
+  void ExpectGeneratedWithInsertions(const std::string& generator_name,
+                                     const std::string& parameter,
+                                     const std::string& insertions,
+                                     const std::string& proto_name,
+                                     const std::string& message_name);
+  void CheckGeneratedAnnotations(const std::string& name,
+                                 const std::string& file);
+
+#if defined(_WIN32)
+  void ExpectNullCodeGeneratorCalled(const std::string& parameter);
+#endif  // _WIN32
+
+
+  void ReadDescriptorSet(const std::string& filename,
+                         FileDescriptorSet* descriptor_set);
+
+  void WriteDescriptorSet(const std::string& filename,
+                          const FileDescriptorSet* descriptor_set);
+
+  void ExpectFileContent(const std::string& filename,
+                         const std::string& content);
+
+  // The default code generators support all features. Use this to create a
+  // code generator that omits the given feature(s).
+  void CreateGeneratorWithMissingFeatures(const std::string& name,
+                                          const std::string& description,
+                                          uint64_t features) {
+    MockCodeGenerator* generator = new MockCodeGenerator(name);
+    generator->SuppressFeatures(features);
+    mock_generators_to_delete_.push_back(generator);
+    cli_.RegisterGenerator(name, generator, description);
+  }
+
+ private:
+  // The object we are testing.
+  CommandLineInterface cli_;
+
+  // Was DisallowPlugins() called?
+  bool disallow_plugins_;
+
+  // We create a directory within TestTempDir() in order to add extra
+  // protection against accidentally deleting user files (since we recursively
+  // delete this directory during the test).  This is the full path of that
+  // directory.
+  std::string temp_directory_;
+
+  // The result of Run().
+  int return_code_;
+
+  // The captured stderr output.
+  std::string error_text_;
+
+  // The captured stdout.
+  std::string captured_stdout_;
+
+  // Pointers which need to be deleted later.
+  std::vector<CodeGenerator*> mock_generators_to_delete_;
+
+  NullCodeGenerator* null_generator_;
+};
+
+class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator {
+ public:
+  NullCodeGenerator() : called_(false) {}
+  ~NullCodeGenerator() override {}
+
+  mutable bool called_;
+  mutable std::string parameter_;
+
+  // implements CodeGenerator ----------------------------------------
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
+    called_ = true;
+    parameter_ = parameter;
+    return true;
+  }
+};
+
+// ===================================================================
+
+void CommandLineInterfaceTest::SetUp() {
+  temp_directory_ = TestTempDir() + "/proto2_cli_test_temp";
+
+  // If the temp directory already exists, it must be left over from a
+  // previous run.  Delete it.
+  if (FileExists(temp_directory_)) {
+    File::DeleteRecursively(temp_directory_, NULL, NULL);
+  }
+
+  // Create the temp directory.
+  GOOGLE_CHECK_OK(File::CreateDir(temp_directory_, 0777));
+
+  // Register generators.
+  CodeGenerator* generator = new MockCodeGenerator("test_generator");
+  mock_generators_to_delete_.push_back(generator);
+  cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output.");
+  cli_.RegisterGenerator("-t", generator, "Test output.");
+
+  generator = new MockCodeGenerator("alt_generator");
+  mock_generators_to_delete_.push_back(generator);
+  cli_.RegisterGenerator("--alt_out", generator, "Alt output.");
+
+  generator = null_generator_ = new NullCodeGenerator();
+  mock_generators_to_delete_.push_back(generator);
+  cli_.RegisterGenerator("--null_out", generator, "Null output.");
+
+
+  disallow_plugins_ = false;
+}
+
+void CommandLineInterfaceTest::TearDown() {
+  // Delete the temp directory.
+  if (FileExists(temp_directory_)) {
+    File::DeleteRecursively(temp_directory_, NULL, NULL);
+  }
+
+  // Delete all the MockCodeGenerators.
+  for (int i = 0; i < mock_generators_to_delete_.size(); i++) {
+    delete mock_generators_to_delete_[i];
+  }
+  mock_generators_to_delete_.clear();
+}
+
+void CommandLineInterfaceTest::Run(const std::string& command) {
+  RunWithArgs(Split(command, " ", true));
+}
+
+void CommandLineInterfaceTest::RunWithArgs(std::vector<std::string> args) {
+  if (!disallow_plugins_) {
+    cli_.AllowPlugins("prefix-");
+    std::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.
+        // Unfortunately, due to an apparent bug on Cygwin/MinGW, if one program
+        // wrapped in this way (e.g. protobuf-tests.exe) tries to execute
+        // another
+        // program wrapped in this way (e.g. test_plugin.exe), the latter fails
+        // with error code 127 and no explanation message.  Presumably the
+        // problem
+        // is that the wrapper for protobuf-tests.exe set some environment
+        // variables that confuse the wrapper for test_plugin.exe.  Luckily, it
+        // turns out that if we simply invoke the wrapped test_plugin.exe
+        // directly, it works -- I guess the environment variables set by the
+        // protobuf-tests.exe wrapper happen to be correct for it too.  So we do
+        // that.
+        ".libs/test_plugin.exe",  // Win32 w/autotool (Cygwin / MinGW)
+        "test_plugin.exe",        // Other Win32 (MSVC)
+        "test_plugin",            // Unix
+    };
+    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()) {
+      GOOGLE_LOG(ERROR)
+          << "Plugin executable not found.  Plugin tests are likely to fail.";
+    } else {
+      args.push_back("--plugin=prefix-gen-plug=" + plugin_path);
+    }
+  }
+
+  std::unique_ptr<const char*[]> argv(new const char*[args.size()]);
+
+  for (int i = 0; i < args.size(); i++) {
+    args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
+    argv[i] = args[i].c_str();
+  }
+
+  // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
+  // stdout at the same time. Need to figure out why and add this capture back
+  // for Cygwin.
+#if !defined(__CYGWIN__)
+  CaptureTestStdout();
+#endif
+  CaptureTestStderr();
+
+  return_code_ = cli_.Run(args.size(), argv.get());
+
+  error_text_ = GetCapturedTestStderr();
+#if !defined(__CYGWIN__)
+  captured_stdout_ = GetCapturedTestStdout();
+#endif
+}
+
+// -------------------------------------------------------------------
+
+void CommandLineInterfaceTest::CreateTempFile(const std::string& name,
+                                              const std::string& contents) {
+  // Create parent directory, if necessary.
+  std::string::size_type slash_pos = name.find_last_of('/');
+  if (slash_pos != std::string::npos) {
+    std::string dir = name.substr(0, slash_pos);
+    if (!FileExists(temp_directory_ + "/" + dir)) {
+      GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir,
+                                          0777));
+    }
+  }
+
+  // Write file.
+  std::string full_name = temp_directory_ + "/" + name;
+  GOOGLE_CHECK_OK(File::SetContents(
+      full_name, StringReplace(contents, "$tmpdir", temp_directory_, true),
+      true));
+}
+
+void CommandLineInterfaceTest::CreateTempDir(const std::string& name) {
+  GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + name,
+                                      0777));
+}
+
+// -------------------------------------------------------------------
+
+void CommandLineInterfaceTest::ExpectNoErrors() {
+  EXPECT_EQ(0, return_code_);
+  EXPECT_EQ("", error_text_);
+}
+
+void CommandLineInterfaceTest::ExpectErrorText(
+    const std::string& expected_text) {
+  EXPECT_NE(0, return_code_);
+  EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true),
+            error_text_);
+}
+
+void CommandLineInterfaceTest::ExpectErrorSubstring(
+    const std::string& expected_substring) {
+  EXPECT_NE(0, return_code_);
+  EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
+}
+
+void CommandLineInterfaceTest::ExpectWarningSubstring(
+    const std::string& expected_substring) {
+  EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
+  EXPECT_EQ(0, return_code_);
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
+    const std::string& expected_substring) {
+  EXPECT_NE(0, return_code_);
+  return error_text_.find(expected_substring) != std::string::npos;
+}
+#endif  // _WIN32 && !__CYGWIN__
+
+void CommandLineInterfaceTest::ExpectGenerated(
+    const std::string& generator_name, const std::string& parameter,
+    const std::string& proto_name, const std::string& message_name) {
+  MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name,
+                                     message_name, proto_name, temp_directory_);
+}
+
+void CommandLineInterfaceTest::ExpectGenerated(
+    const std::string& generator_name, const std::string& parameter,
+    const std::string& proto_name, const std::string& message_name,
+    const std::string& output_directory) {
+  MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name,
+                                     message_name, proto_name,
+                                     temp_directory_ + "/" + output_directory);
+}
+
+void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs(
+    const std::string& generator_name, const std::string& all_proto_names,
+    const std::string& proto_name, const std::string& message_name) {
+  MockCodeGenerator::ExpectGenerated(generator_name, "", "", proto_name,
+                                     message_name, all_proto_names,
+                                     temp_directory_);
+}
+
+void CommandLineInterfaceTest::ExpectGeneratedWithInsertions(
+    const std::string& generator_name, const std::string& parameter,
+    const std::string& insertions, const std::string& proto_name,
+    const std::string& message_name) {
+  MockCodeGenerator::ExpectGenerated(generator_name, parameter, insertions,
+                                     proto_name, message_name, proto_name,
+                                     temp_directory_);
+}
+
+void CommandLineInterfaceTest::CheckGeneratedAnnotations(
+    const std::string& name, const std::string& file) {
+  MockCodeGenerator::CheckGeneratedAnnotations(name, file, temp_directory_);
+}
+
+#if defined(_WIN32)
+void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled(
+    const std::string& parameter) {
+  EXPECT_TRUE(null_generator_->called_);
+  EXPECT_EQ(parameter, null_generator_->parameter_);
+}
+#endif  // _WIN32
+
+
+void CommandLineInterfaceTest::ReadDescriptorSet(
+    const std::string& filename, FileDescriptorSet* descriptor_set) {
+  std::string path = temp_directory_ + "/" + filename;
+  std::string file_contents;
+  GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
+
+  if (!descriptor_set->ParseFromString(file_contents)) {
+    FAIL() << "Could not parse file contents: " << path;
+  }
+}
+
+void CommandLineInterfaceTest::WriteDescriptorSet(
+    const std::string& filename, const FileDescriptorSet* descriptor_set) {
+  std::string binary_proto;
+  GOOGLE_CHECK(descriptor_set->SerializeToString(&binary_proto));
+  CreateTempFile(filename, binary_proto);
+}
+
+void CommandLineInterfaceTest::ExpectCapturedStdout(
+    const std::string& expected_text) {
+  EXPECT_EQ(expected_text, captured_stdout_);
+}
+
+void CommandLineInterfaceTest::ExpectCapturedStdoutSubstringWithZeroReturnCode(
+    const std::string& expected_substring) {
+  EXPECT_EQ(0, return_code_);
+  EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring,
+                      captured_stdout_);
+}
+
+void CommandLineInterfaceTest::ExpectCapturedStderrSubstringWithZeroReturnCode(
+    const std::string& expected_substring) {
+  EXPECT_EQ(0, return_code_);
+  EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
+}
+
+void CommandLineInterfaceTest::ExpectFileContent(const std::string& filename,
+                                                 const std::string& content) {
+  std::string path = temp_directory_ + "/" + filename;
+  std::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) {
+  // Test that the common case works.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, BasicOutput_DescriptorSetIn) {
+  // Test that the common case works.
+  FileDescriptorSet file_descriptor_set;
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, BasicPlugin) {
+  // Test that basic plugins work.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --plug_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, BasicPlugin_DescriptorSetIn) {
+  // Test that basic plugins work.
+
+  FileDescriptorSet file_descriptor_set;
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) {
+  // Invoke a generator and a plugin at the same time.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin_DescriptorSetIn) {
+  // Invoke a generator and a plugin at the same time.
+
+  FileDescriptorSet file_descriptor_set;
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputs) {
+  // Test parsing multiple input files.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto bar.proto");
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputs_DescriptorSetIn) {
+  // Test parsing multiple input files.
+  FileDescriptorSet file_descriptor_set;
+
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bar.proto");
+  file_descriptor_proto->add_message_type()->set_name("Bar");
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto bar.proto");
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputs_UnusedImport_DescriptorSetIn) {
+  // Test unused import warning is not raised when descriptor_set_in is called
+  // and custom options are in unknown field instead of uninterpreted_options.
+  FileDescriptorSet file_descriptor_set;
+
+  const FileDescriptor* descriptor_file =
+      FileDescriptorProto::descriptor()->file();
+  descriptor_file->CopyTo(file_descriptor_set.add_file());
+
+  FileDescriptorProto& any_proto = *file_descriptor_set.add_file();
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+
+  const FileDescriptor* custom_file =
+      protobuf_unittest::AggregateMessage::descriptor()->file();
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  custom_file->CopyTo(file_descriptor_proto);
+  file_descriptor_proto->set_name("custom_options.proto");
+  // Add a custom message option.
+  FieldDescriptorProto* extension_option =
+      file_descriptor_proto->add_extension();
+  extension_option->set_name("unknown_option");
+  extension_option->set_extendee(".google.protobuf.MessageOptions");
+  extension_option->set_number(1111);
+  extension_option->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  extension_option->set_type(FieldDescriptorProto::TYPE_INT64);
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("import_custom_unknown_options.proto");
+  file_descriptor_proto->add_dependency("custom_options.proto");
+  // Add custom message option to unknown field. This custom option is
+  // not known in generated pool, thus option will be in unknown fields.
+  file_descriptor_proto->add_message_type()->set_name("Bar");
+  file_descriptor_proto->mutable_message_type(0)
+      ->mutable_options()
+      ->mutable_unknown_fields()
+      ->AddVarint(1111, 2222);
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin "
+      "import_custom_unknown_options.proto");
+
+  // TODO(jieluo): Fix this test. This test case only happens when
+  // CommandLineInterface::Run() is used instead of invoke protoc combined
+  // with descriptor_set_in, and same custom options are defined in both
+  // generated pool and descriptor_set_in. There's no such uages for now but
+  // still need to be fixed.
+  /*
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("import_custom_extension_options.proto");
+  file_descriptor_proto->add_dependency("custom_options.proto");
+  // Add custom message option to unknown field. This custom option is
+  // also defined in generated pool, thus option will be in extensions.
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+  file_descriptor_proto->mutable_message_type(0)
+      ->mutable_options()
+      ->mutable_unknown_fields()
+      ->AddVarint(protobuf_unittest::message_opt1.number(), 2222);
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin import_custom_unknown_options.proto "
+      "import_custom_extension_options.proto");
+  */
+
+  ExpectNoErrors();
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport) {
+  // Test parsing multiple input files with an import of a separate file.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"baz.proto\";\n"
+                 "message Bar {\n"
+                 "  optional Baz a = 1;\n"
+                 "}\n");
+  CreateTempFile("baz.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Baz {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto bar.proto");
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport_DescriptorSetIn) {
+  // Test parsing multiple input files with an import of a separate file.
+  FileDescriptorSet file_descriptor_set;
+
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bar.proto");
+  file_descriptor_proto->add_dependency("baz.proto");
+  DescriptorProto* message = file_descriptor_proto->add_message_type();
+  message->set_name("Bar");
+  FieldDescriptorProto* field = message->add_field();
+  field->set_type_name("Baz");
+  field->set_name("a");
+  field->set_number(1);
+
+  WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
+
+  file_descriptor_set.clear_file();
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("baz.proto");
+  file_descriptor_proto->add_message_type()->set_name("Baz");
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bat.proto");
+  file_descriptor_proto->add_dependency("baz.proto");
+  message = file_descriptor_proto->add_message_type();
+  message->set_name("Bat");
+  field = message->add_field();
+  field->set_type_name("Baz");
+  field->set_name("a");
+  field->set_number(1);
+
+  WriteDescriptorSet("baz_and_bat.bin", &file_descriptor_set);
+  Run(strings::Substitute(
+      "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
+      "--descriptor_set_in=$0 foo.proto bar.proto",
+      std::string("$tmpdir/foo_and_bar.bin") +
+          CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin"));
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+
+  Run(strings::Substitute(
+      "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
+      "--descriptor_set_in=$0 baz.proto bat.proto",
+      std::string("$tmpdir/foo_and_bar.bin") +
+          CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin"));
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto",
+                                    "baz.proto", "Baz");
+  ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto",
+                                    "bat.proto", "Bat");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto",
+                                    "baz.proto", "Baz");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto",
+                                    "bat.proto", "Bat");
+}
+
+TEST_F(CommandLineInterfaceTest,
+       MultipleInputsWithImport_DescriptorSetIn_DuplicateFileDescriptor) {
+  // Test parsing multiple input files with an import of a separate file.
+  FileDescriptorSet file_descriptor_set;
+
+  FileDescriptorProto foo_file_descriptor_proto;
+  foo_file_descriptor_proto.set_name("foo.proto");
+  foo_file_descriptor_proto.add_message_type()->set_name("Foo");
+
+  file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto);
+
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bar.proto");
+  file_descriptor_proto->add_dependency("baz.proto");
+  file_descriptor_proto->add_dependency("foo.proto");
+  DescriptorProto* message = file_descriptor_proto->add_message_type();
+  message->set_name("Bar");
+  FieldDescriptorProto* field = message->add_field();
+  field->set_type_name("Baz");
+  field->set_name("a");
+  field->set_number(1);
+  field = message->add_field();
+  field->set_type_name("Foo");
+  field->set_name("f");
+  field->set_number(2);
+  WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
+
+  file_descriptor_set.clear_file();
+  file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto);
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("baz.proto");
+  file_descriptor_proto->add_dependency("foo.proto");
+  message = file_descriptor_proto->add_message_type();
+  message->set_name("Baz");
+  field = message->add_field();
+  field->set_type_name("Foo");
+  field->set_name("f");
+  field->set_number(1);
+  WriteDescriptorSet("foo_and_baz.bin", &file_descriptor_set);
+
+  Run(strings::Substitute(
+      "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
+      "--descriptor_set_in=$0 bar.proto",
+      std::string("$tmpdir/foo_and_bar.bin") +
+          CommandLineInterface::kPathSeparator + "$tmpdir/foo_and_baz.bin"));
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "bar.proto", "Bar");
+  ExpectGenerated("test_plugin", "", "bar.proto", "Bar");
+}
+
+TEST_F(CommandLineInterfaceTest,
+       MultipleInputsWithImport_DescriptorSetIn_MissingImport) {
+  // Test parsing multiple input files with an import of a separate file.
+  FileDescriptorSet file_descriptor_set;
+
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bar.proto");
+  file_descriptor_proto->add_dependency("baz.proto");
+  DescriptorProto* message = file_descriptor_proto->add_message_type();
+  message->set_name("Bar");
+  FieldDescriptorProto* field = message->add_field();
+  field->set_type_name("Baz");
+  field->set_name("a");
+  field->set_number(1);
+
+  WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
+
+  file_descriptor_set.clear_file();
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("baz.proto");
+  file_descriptor_proto->add_message_type()->set_name("Baz");
+
+  WriteDescriptorSet("baz.bin", &file_descriptor_set);
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo_and_bar.bin "
+      "foo.proto bar.proto");
+  ExpectErrorSubstring(
+      "bar.proto: Import \"baz.proto\" was not found or had errors.");
+  ExpectErrorSubstring("bar.proto: \"Baz\" is not defined.");
+}
+
+TEST_F(CommandLineInterfaceTest,
+       InputsOnlyFromDescriptorSetIn_UnusedImportIsNotReported) {
+  FileDescriptorSet file_descriptor_set;
+
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("unused.proto");
+  file_descriptor_proto->add_message_type()->set_name("Unused");
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bar.proto");
+  file_descriptor_proto->add_dependency("unused.proto");
+  file_descriptor_proto->add_message_type()->set_name("Bar");
+
+  WriteDescriptorSet("unused_and_bar.bin", &file_descriptor_set);
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/unused_and_bar.bin unused.proto bar.proto");
+  ExpectNoErrors();
+}
+
+TEST_F(CommandLineInterfaceTest,
+       InputsFromDescriptorSetInAndFileSystem_UnusedImportIsReported) {
+  FileDescriptorSet file_descriptor_set;
+
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("unused.proto");
+  file_descriptor_proto->add_message_type()->set_name("Unused");
+
+  file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("bar.proto");
+  file_descriptor_proto->add_dependency("unused.proto");
+  file_descriptor_proto->add_message_type()->set_name("Bar");
+
+  WriteDescriptorSet("unused_and_bar.bin", &file_descriptor_set);
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo {\n"
+                 "  optional Bar bar = 1;\n"
+                 "}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/unused_and_bar.bin "
+      "--proto_path=$tmpdir unused.proto bar.proto foo.proto");
+  // Reporting unused imports here is unfair, since it's unactionable. Notice
+  // the lack of a line number.
+  // TODO(b/144853061): If the file with unused import is from the descriptor
+  // set and not from the file system, suppress the warning.
+  ExpectWarningSubstring("bar.proto: warning: Import unused.proto is unused.");
+}
+
+TEST_F(CommandLineInterfaceTest,
+       OnlyReportsUnusedImportsForFilesBeingGenerated) {
+  CreateTempFile("unused.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Unused {}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"unused.proto\";\n"
+                 "message Bar {}\n");
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo {\n"
+                 "  optional Bar bar = 1;\n"
+                 "}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+  ExpectNoErrors();
+}
+
+TEST_F(CommandLineInterfaceTest, ReportsTransitiveMisingImports_LeafFirst) {
+  CreateTempFile("unused.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Unused {}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"unused.proto\";\n"
+                 "message Bar {}\n");
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo {\n"
+                 "  optional Bar bar = 1;\n"
+                 "}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir bar.proto foo.proto");
+  ExpectWarningSubstring(
+      "bar.proto:2:1: warning: Import unused.proto is unused.");
+}
+
+TEST_F(CommandLineInterfaceTest, ReportsTransitiveMisingImports_LeafLast) {
+  CreateTempFile("unused.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Unused {}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"unused.proto\";\n"
+                 "message Bar {}\n");
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo {\n"
+                 "  optional Bar bar = 1;\n"
+                 "}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto bar.proto");
+  ExpectWarningSubstring(
+      "bar.proto:2:1: warning: Import unused.proto is unused.");
+}
+TEST_F(CommandLineInterfaceTest, CreateDirectory) {
+  // Test that when we output to a sub-directory, it is created.
+
+  CreateTempFile("bar/baz/foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  CreateTempDir("out");
+  CreateTempDir("plugout");
+
+  Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout "
+      "--proto_path=$tmpdir bar/baz/foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out");
+  ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
+  // Test that generator parameters are correctly parsed from the command line.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=TestParameter:$tmpdir "
+      "--plug_out=TestPluginParameter:$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo");
+  ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) {
+  // Test that generator parameters specified with the option flag are
+  // correctly passed to the code generator.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  // Create the "a" and "b" sub-directories.
+  CreateTempDir("a");
+  CreateTempDir("b");
+
+  Run("protocol_compiler "
+      "--test_opt=foo1 "
+      "--test_out=bar:$tmpdir/a "
+      "--test_opt=foo2 "
+      "--test_out=baz:$tmpdir/b "
+      "--test_opt=foo3 "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo",
+                  "a");
+  ExpectGenerated("test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo",
+                  "b");
+}
+
+TEST_F(CommandLineInterfaceTest, ExtraPluginParameters) {
+  // Test that generator parameters specified with the option flag are
+  // correctly passed to the code generator.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  // Create the "a" and "b" sub-directories.
+  CreateTempDir("a");
+  CreateTempDir("b");
+
+  Run("protocol_compiler "
+      "--plug_opt=foo1 "
+      "--plug_out=bar:$tmpdir/a "
+      "--plug_opt=foo2 "
+      "--plug_out=baz:$tmpdir/b "
+      "--plug_opt=foo3 "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_plugin", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a");
+  ExpectGenerated("test_plugin", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
+}
+
+TEST_F(CommandLineInterfaceTest, UnrecognizedExtraParameters) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
+      "--unknown_plug_a_opt=Foo "
+      "--unknown_plug_b_opt=Bar "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("Unknown flag: --unknown_plug_a_opt");
+  ExpectErrorSubstring("Unknown flag: --unknown_plug_b_opt");
+}
+
+TEST_F(CommandLineInterfaceTest, ExtraPluginParametersForOutParameters) {
+  // This doesn't rely on the plugin having been registered and instead that
+  // the existence of --[name]_out is enough to make the --[name]_opt valid.
+  // However, running out of process plugins found via the search path (i.e. -
+  // not pre registered with --plugin) isn't support in this test suite, so we
+  // list the options pre/post the _out directive, and then include _opt that
+  // will be unknown, and confirm the failure output is about the expected
+  // unknown directive, which means the other were accepted.
+  // NOTE: UnrecognizedExtraParameters confirms that if two unknown _opt
+  // directives appear, they both are reported.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
+      "--xyz_opt=foo=bar --xyz_out=$tmpdir "
+      "--abc_out=$tmpdir --abc_opt=foo=bar "
+      "--unknown_plug_opt=Foo "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorText("Unknown flag: --unknown_plug_opt\n");
+}
+
+TEST_F(CommandLineInterfaceTest, Insert) {
+  // Test running a generator that inserts code into another's output.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler "
+      "--test_out=TestParameter:$tmpdir "
+      "--plug_out=TestPluginParameter:$tmpdir "
+      "--test_out=insert=test_generator,test_plugin:$tmpdir "
+      "--plug_out=insert=test_generator,test_plugin:$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGeneratedWithInsertions("test_generator", "TestParameter",
+                                "test_generator,test_plugin", "foo.proto",
+                                "Foo");
+  ExpectGeneratedWithInsertions("test_plugin", "TestPluginParameter",
+                                "test_generator,test_plugin", "foo.proto",
+                                "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, InsertWithAnnotationFixup) {
+  // Check that annotation spans are updated after insertions.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_Annotate {}\n");
+
+  Run("protocol_compiler "
+      "--test_out=TestParameter:$tmpdir "
+      "--plug_out=TestPluginParameter:$tmpdir "
+      "--test_out=insert_endlines=test_generator,test_plugin:$tmpdir "
+      "--plug_out=insert_endlines=test_generator,test_plugin:$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  CheckGeneratedAnnotations("test_generator", "foo.proto");
+  CheckGeneratedAnnotations("test_plugin", "foo.proto");
+}
+
+#if defined(_WIN32)
+
+TEST_F(CommandLineInterfaceTest, WindowsOutputPath) {
+  // Test that the output path can be a Windows-style path.
+
+  CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
+
+  Run("protocol_compiler --null_out=C:\\ "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectNullCodeGeneratorCalled("");
+}
+
+TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) {
+  // Test that we can have a windows-style output path and a parameter.
+
+  CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
+
+  Run("protocol_compiler --null_out=bar:C:\\ "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectNullCodeGeneratorCalled("bar");
+}
+
+TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
+  // Test that the directories can end in backslashes.  Some users claim this
+  // doesn't work on their system.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir\\ "
+      "--proto_path=$tmpdir\\ foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
+  EXPECT_EQ("The system cannot find the file specified.\r\n",
+            Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
+}
+
+#endif  // defined(_WIN32) || defined(__CYGWIN__)
+
+TEST_F(CommandLineInterfaceTest, PathLookup) {
+  // Test that specifying multiple directories in the proto search path works.
+
+  CreateTempFile("b/bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar {}\n");
+  CreateTempFile("a/foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo {\n"
+                 "  optional Bar a = 1;\n"
+                 "}\n");
+  CreateTempFile("b/foo.proto", "this should not be parsed\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) {
+  // Same as PathLookup, but we provide the proto_path in a single flag.
+
+  CreateTempFile("b/bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar {}\n");
+  CreateTempFile("a/foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo {\n"
+                 "  optional Bar a = 1;\n"
+                 "}\n");
+  CreateTempFile("b/foo.proto", "this should not be parsed\n");
+
+  Run(strings::Substitute(
+      "protocol_compiler --test_out=$$tmpdir --proto_path=$0 foo.proto",
+      std::string("$tmpdir/a") + CommandLineInterface::kPathSeparator +
+          "$tmpdir/b"));
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, NonRootMapping) {
+  // Test setting up a search path mapping a directory to a non-root location.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=bar=$tmpdir bar/foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, PathWithEqualsSign) {
+  // Test setting up a search path which happens to have '=' in it.
+
+  CreateTempDir("with=sign");
+  CreateTempFile("with=sign/foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir/with=sign foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleGenerators) {
+  // Test that we can have multiple generators and use both in one invocation,
+  // each with a different output directory.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  // Create the "a" and "b" sub-directories.
+  CreateTempDir("a");
+  CreateTempDir("b");
+
+  Run("protocol_compiler "
+      "--test_out=$tmpdir/a "
+      "--alt_out=$tmpdir/b "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a");
+  ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b");
+}
+
+TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) {
+  // Test that --disallow_services doesn't cause a problem when there are no
+  // services.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --disallow_services --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) {
+  // Test that --disallow_services produces an error when there are services.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n"
+                 "service Bar {}\n");
+
+  Run("protocol_compiler --disallow_services --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("foo.proto: This file contains services");
+}
+
+TEST_F(CommandLineInterfaceTest, AllowServicesHasService) {
+  // Test that services work fine as long as --disallow_services is not used.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n"
+                 "service Bar {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+
+TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing_EmptyList) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo { optional Bar bar = 1; }");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar { optional string text = 1; }");
+
+  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
+      "--direct_dependencies= foo.proto");
+
+  ExpectErrorText(
+      "foo.proto: File is imported but not declared in --direct_dependencies: "
+      "bar.proto\n");
+}
+
+TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "import \"bla.proto\";\n"
+                 "message Foo { optional Bar bar = 1; optional Bla bla = 2; }");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar { optional string text = 1; }");
+  CreateTempFile("bla.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bla { optional int64 number = 1; }");
+
+  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
+      "--direct_dependencies=bla.proto foo.proto");
+
+  ExpectErrorText(
+      "foo.proto: File is imported but not declared in --direct_dependencies: "
+      "bar.proto\n");
+}
+
+TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo { optional Bar bar = 1; }");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar { optional string text = 1; }");
+
+  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
+      "--direct_dependencies=bar.proto foo.proto");
+
+  ExpectNoErrors();
+}
+
+TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation_MultiImports) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "import \"bla.proto\";\n"
+                 "message Foo { optional Bar bar = 1; optional Bla bla = 2; }");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar { optional string text = 1; }");
+  CreateTempFile("bla.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bla { optional int64 number = 1; }");
+
+  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
+      "--direct_dependencies=bar.proto:bla.proto foo.proto");
+
+  ExpectNoErrors();
+}
+
+TEST_F(CommandLineInterfaceTest, DirectDependencies_ProvidedMultipleTimes) {
+  CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
+
+  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
+      "--direct_dependencies=bar.proto --direct_dependencies=bla.proto "
+      "foo.proto");
+
+  ExpectErrorText(
+      "--direct_dependencies may only be passed once. To specify multiple "
+      "direct dependencies, pass them all as a single parameter separated by "
+      "':'.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, DirectDependencies_CustomErrorMessage) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "message Foo { optional Bar bar = 1; }");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar { optional string text = 1; }");
+
+  std::vector<std::string> commands;
+  commands.push_back("protocol_compiler");
+  commands.push_back("--test_out=$tmpdir");
+  commands.push_back("--proto_path=$tmpdir");
+  commands.push_back("--direct_dependencies=");
+  commands.push_back("--direct_dependencies_violation_msg=Bla \"%s\" Bla");
+  commands.push_back("foo.proto");
+  RunWithArgs(commands);
+
+  ExpectErrorText("foo.proto: Bla \"bar.proto\" Bla\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) {
+  // Test that we can accept working-directory-relative input files.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir $tmpdir/foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
+  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 --descriptor_set_out=$tmpdir/descriptor_set "
+      "--proto_path=$tmpdir bar.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+  if (HasFatalFailure()) return;
+  EXPECT_EQ(1, descriptor_set.file_size());
+  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());
+  // foo should come first since the output is in dependency order.
+  // since bar and baz are unordered, they should be in command line order.
+  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+  EXPECT_EQ("bar.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(1).message_type(0).name());
+  EXPECT_EQ("foo", descriptor_set.file(1).message_type(0).field(0).name());
+  EXPECT_TRUE(descriptor_set.file(1).message_type(0).field(0).has_json_name());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
+  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 --descriptor_set_out=$tmpdir/descriptor_set "
+      "--include_source_info --proto_path=$tmpdir bar.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+  if (HasFatalFailure()) return;
+  EXPECT_EQ(1, descriptor_set.file_size());
+  EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
+  // Source code info included.
+  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
+  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 --descriptor_set_out=$tmpdir/descriptor_set "
+      "--include_imports --proto_path=$tmpdir bar.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+  if (HasFatalFailure()) return;
+  EXPECT_EQ(2, descriptor_set.file_size());
+  if (descriptor_set.file(0).name() == "bar.proto") {
+    std::swap(descriptor_set.mutable_file()->mutable_data()[0],
+              descriptor_set.mutable_file()->mutable_data()[1]);
+  }
+  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+  EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
+  // Descriptor set should not have source code info.
+  EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+  EXPECT_FALSE(descriptor_set.file(1).has_source_code_info());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
+  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 --descriptor_set_out=$tmpdir/descriptor_set "
+      "--include_imports --include_source_info --proto_path=$tmpdir bar.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+  if (HasFatalFailure()) return;
+  EXPECT_EQ(2, descriptor_set.file_size());
+  if (descriptor_set.file(0).name() == "bar.proto") {
+    std::swap(descriptor_set.mutable_file()->mutable_data()[0],
+              descriptor_set.mutable_file()->mutable_data()[1]);
+  }
+  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+  EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
+  // Source code info included.
+  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+  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");
+
+  std::string current_working_directory = getcwd(nullptr, 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");
+}
+
+TEST_F(CommandLineInterfaceTest,
+       WriteDependencyManifestFileWithDescriptorSetOut) {
+  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 "
+      "--descriptor_set_out=$tmpdir/bar.pb --proto_path=$tmpdir bar.proto");
+
+  ExpectNoErrors();
+
+  ExpectFileContent("manifest",
+                    "$tmpdir/bar.pb: "
+                    "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
+}
+#endif  // !_WIN32
+
+TEST_F(CommandLineInterfaceTest, TestArgumentFile) {
+  // Test parsing multiple input files using an argument file.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar {}\n");
+  CreateTempFile("arguments.txt",
+                 "--test_out=$tmpdir\n"
+                 "--plug_out=$tmpdir\n"
+                 "--proto_path=$tmpdir\n"
+                 "--direct_dependencies_violation_msg=%s is not imported\n"
+                 "foo.proto\n"
+                 "bar.proto");
+
+  Run("protocol_compiler @$tmpdir/arguments.txt");
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+}
+
+
+// -------------------------------------------------------------------
+
+TEST_F(CommandLineInterfaceTest, ParseErrors) {
+  // Test that parse errors are reported.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "badsyntax\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorText(
+      "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ParseErrors_DescriptorSetIn) {
+  // Test that parse errors are reported.
+  CreateTempFile("foo.bin", "not a FileDescriptorSet");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
+
+  ExpectErrorText("$tmpdir/foo.bin: Unable to parse.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) {
+  // Test that parse errors are reported from multiple files.
+
+  // We set up files such that foo.proto actually depends on bar.proto in
+  // two ways:  Directly and through baz.proto.  bar.proto's errors should
+  // only be reported once.
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "badsyntax\n");
+  CreateTempFile("baz.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n");
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n"
+                 "import \"baz.proto\";\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorText(
+      "bar.proto:2:1: Expected top-level statement (e.g. \"message\").\n"
+      "baz.proto:2:1: Import \"bar.proto\" was not found or had errors.\n"
+      "foo.proto:2:1: Import \"bar.proto\" was not found or had errors.\n"
+      "foo.proto:3:1: Import \"baz.proto\" was not found or had errors.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, RecursiveImportFails) {
+  // Create a proto file that imports itself.
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"foo.proto\";\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring(
+      "foo.proto:2:1: File recursively imports itself: "
+      "foo.proto -> foo.proto\n");
+}
+
+TEST_F(CommandLineInterfaceTest, InputNotFoundError) {
+  // Test what happens if the input file is not found.
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorText(
+      "Could not make proto path relative: foo.proto: No such file or "
+      "directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, InputNotFoundError_DescriptorSetIn) {
+  // Test what happens if the input file is not found.
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
+
+  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) {
+  // Test what happens when a working-directory-relative input file is not
+  // found.
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir $tmpdir/foo.proto");
+
+  ExpectErrorText(
+      "Could not make proto path relative: $tmpdir/foo.proto: No such file or "
+      "directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) {
+  // Test what happens when a working-directory-relative input file is not
+  // mapped to a virtual path.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  // Create a directory called "bar" so that we can point --proto_path at it.
+  CreateTempFile("bar/dummy", "");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
+
+  ExpectErrorText(
+      "$tmpdir/foo.proto: File does not reside within any path "
+      "specified using --proto_path (or -I).  You must specify a "
+      "--proto_path which encompasses this file.  Note that the "
+      "proto_path must be an exact prefix of the .proto file "
+      "names -- protoc is too dumb to figure out when two paths "
+      "(e.g. absolute and relative) are equivalent (it's harder "
+      "than you think).\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) {
+  // Check what happens if the input file is not found *and* is not mapped
+  // in the proto_path.
+
+  // Create a directory called "bar" so that we can point --proto_path at it.
+  CreateTempFile("bar/dummy", "");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
+
+  ExpectErrorText(
+      "Could not make proto path relative: $tmpdir/foo.proto: No such file or "
+      "directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) {
+  // Test what happens when a working-directory-relative input file is shadowed
+  // by another file in the virtual path.
+
+  CreateTempFile("foo/foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+  CreateTempFile("bar/foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir/foo --proto_path=$tmpdir/bar "
+      "$tmpdir/bar/foo.proto");
+
+  ExpectErrorText(
+      "$tmpdir/bar/foo.proto: Input is shadowed in the --proto_path "
+      "by \"$tmpdir/foo/foo.proto\".  Either use the latter "
+      "file as your input or reorder the --proto_path so that the "
+      "former file's location comes first.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) {
+  // Test what happens if the input file is not found.
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir/foo foo.proto");
+
+  ExpectErrorText(
+      "$tmpdir/foo: warning: directory does not exist.\n"
+      "Could not make proto path relative: foo.proto: No such file or "
+      "directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) {
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto");
+  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto");
+  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) {
+  // Test what happens if a proto is in a --descriptor_set_in and also exists
+  // on disk.
+  FileDescriptorSet file_descriptor_set;
+
+  // NOTE: This file desc SHOULD be different from the one created as a temp
+  //       to make it easier to test that the file was output instead of the
+  //       contents of the --descriptor_set_in file.
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message FooBar { required string foo_message = 1; }\n");
+
+  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+      "--descriptor_set_in=$tmpdir/foo.bin "
+      "--include_source_info "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+
+  EXPECT_EQ(1, descriptor_set.file_size());
+  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+  // Descriptor set SHOULD have source code info.
+  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+
+  EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name());
+  EXPECT_EQ("foo_message",
+            descriptor_set.file(0).message_type(0).field(0).name());
+}
+
+TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) {
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--dependency_out=$tmpdir/manifest "
+      "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
+  ExpectErrorText(
+      "--descriptor_set_in cannot be used with --dependency_out.\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--descriptor_set_in=$tmpdir/foo.bin "
+      "--dependency_out=$tmpdir/manifest foo.proto");
+  ExpectErrorText(
+      "--dependency_out cannot be used with --descriptor_set_in.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingInputError) {
+  // Test that we get an error if no inputs are given.
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir");
+
+  ExpectErrorText("Missing input file.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingOutputError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --proto_path=$tmpdir foo.proto");
+
+  ExpectErrorText("Missing output directives.\n");
+}
+
+TEST_F(CommandLineInterfaceTest, OutputWriteError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  std::string output_file =
+      MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto");
+
+  // Create a directory blocking our output location.
+  CreateTempDir(output_file);
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  // MockCodeGenerator no longer detects an error because we actually write to
+  // an in-memory location first, then dump to disk at the end.  This is no
+  // big deal.
+  //   ExpectErrorSubstring("MockCodeGenerator detected write error.");
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
+  if (HasAlternateErrorSubstring(output_file + ": Permission denied")) {
+    return;
+  }
+#endif
+
+  ExpectErrorSubstring(output_file + ": Is a directory");
+}
+
+TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  std::string output_file =
+      MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto");
+
+  // Create a directory blocking our output location.
+  CreateTempDir(output_file);
+
+  Run("protocol_compiler --plug_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
+  if (HasAlternateErrorSubstring(output_file + ": Permission denied")) {
+    return;
+  }
+#endif
+
+  ExpectErrorSubstring(output_file + ": Is a directory");
+}
+
+TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir/nosuchdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("nosuchdir/: No such file or directory");
+}
+
+TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --plug_out=$tmpdir/nosuchdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("nosuchdir/: No such file or directory");
+}
+
+TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir/foo.proto "
+      "--proto_path=$tmpdir foo.proto");
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Windows with MSVCRT.dll produces EINVAL instead of ENOTDIR.
+  if (HasAlternateErrorSubstring("foo.proto/: Invalid argument")) {
+    return;
+  }
+#endif
+
+  ExpectErrorSubstring("foo.proto/: Not a directory");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorError) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_Error {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring(
+      "--test_out: foo.proto: Saw message type MockCodeGenerator_Error.");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorPluginError) {
+  // Test a generator plugin that returns an error.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_Error {}\n");
+
+  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring(
+      "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error.");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) {
+  // Test a generator plugin that exits with an error code.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_Exit {}\n");
+
+  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit.");
+  ExpectErrorSubstring(
+      "--plug_out: prefix-gen-plug: Plugin failed with status code 123.");
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) {
+  // Test a generator plugin that crashes.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_Abort {}\n");
+
+  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort.");
+
+#ifdef _WIN32
+  // Windows doesn't have signals.  It looks like abort()ing causes the process
+  // to exit with status code 3, but let's not depend on the exact number here.
+  ExpectErrorSubstring(
+      "--plug_out: prefix-gen-plug: Plugin failed with status code");
+#else
+  // Don't depend on the exact signal number.
+  ExpectErrorSubstring("--plug_out: prefix-gen-plug: Plugin killed by signal");
+#endif
+}
+
+TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_HasSourceCodeInfo {}\n");
+
+  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring(
+      "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, PluginReceivesCompilerVersion) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message MockCodeGenerator_ShowVersionNumber {\n"
+                 "  optional int32 value = 1;\n"
+                 "}\n");
+
+  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring(StringPrintf("Saw compiler_version: %d %s",
+                                    GOOGLE_PROTOBUF_VERSION,
+                                    GOOGLE_PROTOBUF_VERSION_SUFFIX));
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
+  // Test what happens if the plugin isn't found.
+
+  CreateTempFile("error.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --badplug_out=TestParameter:$tmpdir "
+      "--plugin=prefix-gen-badplug=no_such_file "
+      "--proto_path=$tmpdir error.proto");
+
+#ifdef _WIN32
+  ExpectErrorSubstring("--badplug_out: prefix-gen-badplug: " +
+                       Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
+#else
+  // Error written to stdout by child process after exec() fails.
+  ExpectErrorSubstring("no_such_file: program not found or is not executable");
+
+  ExpectErrorSubstring(
+      "Please specify a program using absolute path or make sure "
+      "the program is available in your PATH system variable");
+
+  // Error written by parent process when child fails.
+  ExpectErrorSubstring(
+      "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1.");
+#endif
+}
+
+TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) {
+  // Test what happens if plugins aren't allowed.
+
+  CreateTempFile("error.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  DisallowPlugins();
+  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
+      "--proto_path=$tmpdir error.proto");
+
+  ExpectErrorSubstring("Unknown flag: --plug_out");
+}
+
+TEST_F(CommandLineInterfaceTest, HelpText) {
+  Run("test_exec_name --help");
+
+  ExpectCapturedStdoutSubstringWithZeroReturnCode("Usage: test_exec_name ");
+  ExpectCapturedStdoutSubstringWithZeroReturnCode("--test_out=OUT_DIR");
+  ExpectCapturedStdoutSubstringWithZeroReturnCode("Test output.");
+  ExpectCapturedStdoutSubstringWithZeroReturnCode("--alt_out=OUT_DIR");
+  ExpectCapturedStdoutSubstringWithZeroReturnCode("Alt output.");
+}
+
+TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
+  // Test --error_format=gcc (which is the default, but we want to verify
+  // that it can be set explicitly).
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "badsyntax\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir --error_format=gcc foo.proto");
+
+  ExpectErrorText(
+      "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
+}
+
+TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) {
+  // Test --error_format=msvs
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "badsyntax\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir --error_format=msvs foo.proto");
+
+  ExpectErrorText(
+      "$tmpdir/foo.proto(2) : error in column=1: Expected top-level statement "
+      "(e.g. \"message\").\n");
+}
+
+TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) {
+  // Test invalid --error_format
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "badsyntax\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir --error_format=invalid foo.proto");
+
+  ExpectErrorText("Unknown error format: invalid\n");
+}
+
+TEST_F(CommandLineInterfaceTest, Warnings) {
+  // Test --fatal_warnings.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "import \"bar.proto\";\n");
+  CreateTempFile("bar.proto", "syntax = \"proto2\";\n");
+
+  Run("protocol_compiler --test_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+  ExpectCapturedStderrSubstringWithZeroReturnCode(
+      "foo.proto:2:1: warning: Import bar.proto is unused.");
+
+  Run("protocol_compiler --test_out=$tmpdir --fatal_warnings "
+      "--proto_path=$tmpdir foo.proto");
+  ExpectErrorSubstring("foo.proto:2:1: warning: Import bar.proto is unused.");
+}
+
+// -------------------------------------------------------------------
+// Flag parsing tests
+
+TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) {
+  // Test that a single-character flag works.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler -t$tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) {
+  // Test that separating the flag value with a space works.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler --test_out $tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) {
+  // Test that separating the flag value with a space works for
+  // single-character flags.
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Foo {}\n");
+
+  Run("protocol_compiler -t $tmpdir "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingValueError) {
+  // Test that we get an error if a flag is missing its value.
+
+  Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto");
+
+  ExpectErrorText("Missing value for flag: --test_out\n");
+}
+
+TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) {
+  // Test that we get an error if the last argument is a flag requiring a
+  // value.
+
+  Run("protocol_compiler --test_out");
+
+  ExpectErrorText("Missing value for flag: --test_out\n");
+}
+
+TEST_F(CommandLineInterfaceTest, Proto3OptionalDisallowedNoCodegenSupport) {
+  CreateTempFile("google/foo.proto",
+                 "syntax = \"proto3\";\n"
+                 "message Foo {\n"
+                 "  optional int32 i = 1;\n"
+                 "}\n");
+
+  CreateGeneratorWithMissingFeatures("--no_proto3_optional_out",
+                                     "Doesn't support proto3 optional",
+                                     CodeGenerator::FEATURE_PROTO3_OPTIONAL);
+
+  Run("protocol_compiler --experimental_allow_proto3_optional "
+      "--proto_path=$tmpdir google/foo.proto --no_proto3_optional_out=$tmpdir");
+
+  ExpectErrorSubstring(
+      "code generator --no_proto3_optional_out hasn't been updated to support "
+      "optional fields in proto3");
+}
+
+TEST_F(CommandLineInterfaceTest, Proto3OptionalAllowWithFlag) {
+  CreateTempFile("google/foo.proto",
+                 "syntax = \"proto3\";\n"
+                 "message Foo {\n"
+                 "  optional int32 i = 1;\n"
+                 "}\n");
+
+  Run("protocol_compiler --experimental_allow_proto3_optional "
+      "--proto_path=$tmpdir google/foo.proto --test_out=$tmpdir");
+  ExpectNoErrors();
+}
+
+TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) {
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "package foo;\n"
+                 "message Foo {\n"
+                 "  optional int32 a = 2;\n"
+                 "  optional string b = 4;\n"
+                 "  optional string c = 5;\n"
+                 "  optional int64 d = 8;\n"
+                 "  optional double e = 10;\n"
+                 "}\n");
+  CreateTempFile("bar.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Bar {\n"
+                 "  optional int32 a = 2;\n"
+                 "  extensions 4 to 5;\n"
+                 "  optional int64 d = 8;\n"
+                 "  extensions 10;\n"
+                 "}\n");
+  CreateTempFile("baz.proto",
+                 "syntax = \"proto2\";\n"
+                 "message Baz {\n"
+                 "  optional int32 a = 2;\n"
+                 "  optional int64 d = 8;\n"
+                 "  extensions 15 to max;\n"  // unordered.
+                 "  extensions 13;\n"
+                 "  extensions 10 to 12;\n"
+                 "  extensions 5;\n"
+                 "  extensions 4;\n"
+                 "}\n");
+  CreateTempFile(
+      "quz.proto",
+      "syntax = \"proto2\";\n"
+      "message Quz {\n"
+      "  message Foo {}\n"  // nested message
+      "  optional int32 a = 2;\n"
+      "  optional group C = 4 {\n"
+      "    optional int32 d = 5;\n"
+      "  }\n"
+      "  extensions 8 to 10;\n"
+      "  optional group E = 11 {\n"
+      "    optional int32 f = 9;\n"    // explicitly reuse extension range 8-10
+      "    optional group G = 15 {\n"  // nested group
+      "      message Foo {}\n"         // nested message inside nested group
+      "    }\n"
+      "  }\n"
+      "}\n");
+
+  Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir "
+      "foo.proto bar.proto baz.proto quz.proto");
+
+  ExpectNoErrors();
+
+  // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
+  // stdout at the same time. Need to figure out why and add this test back
+  // for Cygwin.
+#if !defined(__CYGWIN__)
+  ExpectCapturedStdout(
+      "foo.Foo                             free: 1 3 6-7 9 11-INF\n"
+      "Bar                                 free: 1 3 6-7 9 11-INF\n"
+      "Baz                                 free: 1 3 6-7 9 14\n"
+      "Quz.Foo                             free: 1-INF\n"
+      "Quz.E.G.Foo                         free: 1-INF\n"
+      "Quz                                 free: 1 3 6-7 12-14 16-INF\n");
+#endif
+}
+
+// ===================================================================
+
+// Test for --encode and --decode.  Note that it would be easier to do this
+// test as a shell script, but we'd like to be able to run the test on
+// platforms that don't have a Bourne-compatible shell available (especially
+// Windows/MSVC).
+
+enum EncodeDecodeTestMode { PROTO_PATH, DESCRIPTOR_SET_IN };
+
+class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> {
+ protected:
+  void SetUp() override {
+    WriteUnittestProtoDescriptorSet();
+    duped_stdin_ = dup(STDIN_FILENO);
+  }
+
+  void TearDown() override {
+    dup2(duped_stdin_, STDIN_FILENO);
+    close(duped_stdin_);
+  }
+
+  void RedirectStdinFromText(const std::string& input) {
+    std::string filename = TestTempDir() + "/test_stdin";
+    GOOGLE_CHECK_OK(File::SetContents(filename, input, true));
+    GOOGLE_CHECK(RedirectStdinFromFile(filename));
+  }
+
+  bool RedirectStdinFromFile(const std::string& filename) {
+    int fd = open(filename.c_str(), O_RDONLY);
+    if (fd < 0) return false;
+    dup2(fd, STDIN_FILENO);
+    close(fd);
+    return true;
+  }
+
+  // Remove '\r' characters from text.
+  std::string StripCR(const std::string& text) {
+    std::string result;
+
+    for (int i = 0; i < text.size(); i++) {
+      if (text[i] != '\r') {
+        result.push_back(text[i]);
+      }
+    }
+
+    return result;
+  }
+
+  enum Type { TEXT, BINARY };
+  enum ReturnCode { SUCCESS, ERROR };
+
+  bool Run(const std::string& command, bool specify_proto_files = true) {
+    std::vector<std::string> args;
+    args.push_back("protoc");
+    for (StringPiece split_piece :
+         Split(command, " ", true)) {
+      args.push_back(std::string(split_piece));
+    }
+    if (specify_proto_files) {
+      switch (GetParam()) {
+        case PROTO_PATH:
+          args.push_back("--proto_path=" + TestUtil::TestSourceDir());
+          break;
+        case DESCRIPTOR_SET_IN:
+          args.push_back(StrCat("--descriptor_set_in=",
+                                      unittest_proto_descriptor_set_filename_));
+          break;
+        default:
+          ADD_FAILURE() << "unexpected EncodeDecodeTestMode: " << GetParam();
+      }
+    }
+
+    std::unique_ptr<const char*[]> argv(new const char*[args.size()]);
+    for (int i = 0; i < args.size(); i++) {
+      argv[i] = args[i].c_str();
+    }
+
+    CommandLineInterface cli;
+
+    CaptureTestStdout();
+    CaptureTestStderr();
+
+    int result = cli.Run(args.size(), argv.get());
+
+    captured_stdout_ = GetCapturedTestStdout();
+    captured_stderr_ = GetCapturedTestStderr();
+
+    return result == 0;
+  }
+
+  void ExpectStdoutMatchesBinaryFile(const std::string& filename) {
+    std::string expected_output;
+    GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
+
+    // Don't use EXPECT_EQ because we don't want to print raw binary data to
+    // stdout on failure.
+    EXPECT_TRUE(captured_stdout_ == expected_output);
+  }
+
+  void ExpectStdoutMatchesTextFile(const std::string& filename) {
+    std::string expected_output;
+    GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
+
+    ExpectStdoutMatchesText(expected_output);
+  }
+
+  void ExpectStdoutMatchesText(const std::string& expected_text) {
+    EXPECT_EQ(StripCR(expected_text), StripCR(captured_stdout_));
+  }
+
+  void ExpectStderrMatchesText(const std::string& expected_text) {
+    EXPECT_EQ(StripCR(expected_text), StripCR(captured_stderr_));
+  }
+
+  void ExpectStderrContainsText(const std::string& expected_text) {
+    EXPECT_NE(StripCR(captured_stderr_).find(StripCR(expected_text)),
+              std::string::npos);
+  }
+
+ private:
+  void WriteUnittestProtoDescriptorSet() {
+    unittest_proto_descriptor_set_filename_ =
+        TestTempDir() + "/unittest_proto_descriptor_set.bin";
+    FileDescriptorSet file_descriptor_set;
+    protobuf_unittest::TestAllTypes test_all_types;
+    test_all_types.descriptor()->file()->CopyTo(file_descriptor_set.add_file());
+
+    protobuf_unittest_import::ImportMessage import_message;
+    import_message.descriptor()->file()->CopyTo(file_descriptor_set.add_file());
+
+    protobuf_unittest_import::PublicImportMessage public_import_message;
+    public_import_message.descriptor()->file()->CopyTo(
+        file_descriptor_set.add_file());
+    GOOGLE_DCHECK(file_descriptor_set.IsInitialized());
+
+    std::string binary_proto;
+    GOOGLE_CHECK(file_descriptor_set.SerializeToString(&binary_proto));
+    GOOGLE_CHECK_OK(File::SetContents(unittest_proto_descriptor_set_filename_,
+                               binary_proto, true));
+  }
+
+  int duped_stdin_;
+  std::string captured_stdout_;
+  std::string captured_stderr_;
+  std::string unittest_proto_descriptor_set_filename_;
+};
+
+TEST_P(EncodeDecodeTest, Encode) {
+  RedirectStdinFromFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/"
+      "testdata/text_format_unittest_data_oneof_implemented.txt"));
+  std::string args;
+  if (GetParam() != DESCRIPTOR_SET_IN) {
+    args.append(
+        TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto"));
+  }
+  EXPECT_TRUE(Run(args + " --encode=protobuf_unittest.TestAllTypes"));
+  ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/testdata/golden_message_oneof_implemented"));
+  ExpectStderrMatchesText("");
+}
+
+TEST_P(EncodeDecodeTest, Decode) {
+  RedirectStdinFromFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/testdata/golden_message_oneof_implemented"));
+  EXPECT_TRUE(
+      Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
+          " --decode=protobuf_unittest.TestAllTypes"));
+  ExpectStdoutMatchesTextFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/"
+      "testdata/text_format_unittest_data_oneof_implemented.txt"));
+  ExpectStderrMatchesText("");
+}
+
+TEST_P(EncodeDecodeTest, Partial) {
+  RedirectStdinFromText("");
+  EXPECT_TRUE(
+      Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
+          " --encode=protobuf_unittest.TestRequired"));
+  ExpectStdoutMatchesText("");
+  ExpectStderrMatchesText(
+      "warning:  Input message is missing required fields:  a, b, c\n");
+}
+
+TEST_P(EncodeDecodeTest, DecodeRaw) {
+  protobuf_unittest::TestAllTypes message;
+  message.set_optional_int32(123);
+  message.set_optional_string("foo");
+  std::string data;
+  message.SerializeToString(&data);
+
+  RedirectStdinFromText(data);
+  EXPECT_TRUE(Run("--decode_raw", /*specify_proto_files=*/false));
+  ExpectStdoutMatchesText(
+      "1: 123\n"
+      "14: \"foo\"\n");
+  ExpectStderrMatchesText("");
+}
+
+TEST_P(EncodeDecodeTest, UnknownType) {
+  EXPECT_FALSE(
+      Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
+          " --encode=NoSuchType"));
+  ExpectStdoutMatchesText("");
+  ExpectStderrMatchesText("Type not defined: NoSuchType\n");
+}
+
+TEST_P(EncodeDecodeTest, ProtoParseError) {
+  EXPECT_FALSE(
+      Run("net/proto2/internal/no_such_file.proto "
+          "--encode=NoSuchType"));
+  ExpectStdoutMatchesText("");
+  ExpectStderrContainsText(
+      "net/proto2/internal/no_such_file.proto: No such file or directory\n");
+}
+
+TEST_P(EncodeDecodeTest, EncodeDeterministicOutput) {
+  RedirectStdinFromFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/"
+      "testdata/text_format_unittest_data_oneof_implemented.txt"));
+  std::string args;
+  if (GetParam() != DESCRIPTOR_SET_IN) {
+    args.append(
+        TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto"));
+  }
+  EXPECT_TRUE(Run(
+      args + " --encode=protobuf_unittest.TestAllTypes --deterministic_output"));
+  ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/testdata/golden_message_oneof_implemented"));
+  ExpectStderrMatchesText("");
+}
+
+TEST_P(EncodeDecodeTest, DecodeDeterministicOutput) {
+  RedirectStdinFromFile(TestUtil::GetTestDataPath(
+      "net/proto2/internal/testdata/golden_message_oneof_implemented"));
+  EXPECT_FALSE(
+      Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
+          " --decode=protobuf_unittest.TestAllTypes --deterministic_output"));
+  ExpectStderrMatchesText(
+      "Can only use --deterministic_output with --encode.\n");
+}
+
+INSTANTIATE_TEST_SUITE_P(FileDescriptorSetSource, EncodeDecodeTest,
+                         testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN));
+}  // anonymous namespace
+
+#endif  // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+
+#include <google/protobuf/port_undef.inc>
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc
new file mode 100644
index 0000000..2619e60
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc
@@ -0,0 +1,195 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This test insures that net/proto2/proto/descriptor.pb.{h,cc} match exactly
+// what would be generated by the protocol compiler.  These files are not
+// generated automatically at build time because they are compiled into the
+// protocol compiler itself.  So, if they were auto-generated, you'd have a
+// chicken-and-egg problem.
+//
+// If this test fails, run the script
+// "generate_descriptor_proto.sh" and add
+// descriptor.pb.{h,cc} to your changelist.
+
+#include <map>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/cpp/generator.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() override {}
+
+  std::string text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const std::string& filename, int line, int column,
+                const std::string& message) override {
+    strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
+                              message);
+  }
+};
+
+class MockGeneratorContext : public GeneratorContext {
+ public:
+  void ExpectFileMatches(const std::string& virtual_filename,
+                         const std::string& physical_filename) {
+    auto it = files_.find(virtual_filename);
+    ASSERT_TRUE(it != files_.end())
+        << "Generator failed to generate file: " << virtual_filename;
+
+    std::string expected_contents = *it->second;
+    std::string actual_contents;
+    GOOGLE_CHECK_OK(
+        File::GetContents(TestUtil::TestSourceDir() + "/" + physical_filename,
+                          &actual_contents, true))
+        << physical_filename;
+    CleanStringLineEndings(&actual_contents, false);
+
+#ifdef WRITE_FILES  // Define to debug mismatched files.
+    GOOGLE_CHECK_OK(File::SetContents("/tmp/expected.cc", expected_contents,
+                               true));
+    GOOGLE_CHECK_OK(
+        File::SetContents("/tmp/actual.cc", actual_contents, true));
+#endif
+
+    ASSERT_EQ(expected_contents, actual_contents)
+        << physical_filename
+        << " needs to be regenerated.  Please run "
+           "generate_descriptor_proto.sh. "
+           "Then add this file to your CL.";
+  }
+
+  // implements GeneratorContext --------------------------------------
+
+  io::ZeroCopyOutputStream* Open(const std::string& filename) override {
+    auto& map_slot = files_[filename];
+    map_slot.reset(new std::string);
+    return new io::StringOutputStream(map_slot.get());
+  }
+
+ private:
+  std::map<std::string, std::unique_ptr<std::string>> files_;
+};
+
+const char kDescriptorParameter[] = "dllexport_decl=PROTOBUF_EXPORT";
+const char kPluginParameter[] = "dllexport_decl=PROTOC_EXPORT";
+
+
+const char* test_protos[][2] = {
+    {"google/protobuf/descriptor", kDescriptorParameter},
+    {"google/protobuf/compiler/plugin", kPluginParameter},
+};
+
+TEST(BootstrapTest, GeneratedFilesMatch) {
+  // We need a mapping from the actual file to virtual and actual path
+  // of the data to compare to.
+  std::map<std::string, std::string> vpath_map;
+  std::map<std::string, std::string> rpath_map;
+  rpath_map["third_party/protobuf/test_messages_proto2"] =
+      "net/proto2/z_generated_example/test_messages_proto2";
+  rpath_map["third_party/protobuf/test_messages_proto3"] =
+      "net/proto2/z_generated_example/test_messages_proto3";
+  rpath_map["net/proto2/internal/proto2_weak"] =
+      "net/proto2/z_generated_example/proto2_weak";
+
+  DiskSourceTree source_tree;
+  source_tree.MapPath("", TestUtil::TestSourceDir());
+
+  for (auto file_parameter : test_protos) {
+    MockErrorCollector error_collector;
+    Importer importer(&source_tree, &error_collector);
+    const FileDescriptor* file =
+        importer.Import(file_parameter[0] + std::string(".proto"));
+    ASSERT_TRUE(file != nullptr)
+        << "Can't import file " << file_parameter[0] + std::string(".proto")
+        << "\n";
+    EXPECT_EQ("", error_collector.text_);
+    CppGenerator generator;
+    MockGeneratorContext context;
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+    generator.set_opensource_runtime(true);
+    generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
+#endif
+    std::string error;
+    ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error));
+
+    std::string vpath =
+        FindWithDefault(vpath_map, file_parameter[0], file_parameter[0]);
+    std::string rpath =
+        FindWithDefault(rpath_map, file_parameter[0], file_parameter[0]);
+    context.ExpectFileMatches(vpath + ".pb.cc", rpath + ".pb.cc");
+    context.ExpectFileMatches(vpath + ".pb.h", rpath + ".pb.h");
+  }
+}
+
+// test Generate in cpp_generator.cc
+TEST(BootstrapTest, OptionNotExist) {
+  cpp::CppGenerator generator;
+  DescriptorPool pool;
+  GeneratorContext* generator_context = nullptr;
+  std::string parameter = "aaa";
+  std::string error;
+  ASSERT_FALSE(generator.Generate(
+      pool.FindFileByName("google/protobuf/descriptor.proto"), parameter,
+      generator_context, &error));
+  EXPECT_EQ(error, "Unknown generator option: " + parameter);
+}
+
+}  // namespace
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
new file mode 100644
index 0000000..1716ab2
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -0,0 +1,6 @@
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_
+#define GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_
+
+#include <google/protobuf/compiler/cpp/generator.h>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_
diff --git a/src/google/protobuf/compiler/cpp/enum.cc b/src/google/protobuf/compiler/cpp/enum.cc
new file mode 100644
index 0000000..8124369
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/enum.cc
@@ -0,0 +1,438 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/enum.h>
+
+#include <cstdint>
+#include <limits>
+#include <map>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/names.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
+// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// generation of the GOOGLE_ARRAYSIZE constant.
+bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
+  int32_t max_value = descriptor->value(0)->number();
+  for (int i = 0; i < descriptor->value_count(); i++) {
+    if (descriptor->value(i)->number() > max_value) {
+      max_value = descriptor->value(i)->number();
+    }
+  }
+  return max_value != std::numeric_limits<int32_t>::max();
+}
+
+// Returns the number of unique numeric enum values. This is less than
+// descriptor->value_count() when there are aliased values.
+int CountUniqueValues(const EnumDescriptor* descriptor) {
+  std::set<int> values;
+  for (int i = 0; i < descriptor->value_count(); ++i) {
+    values.insert(descriptor->value(i)->number());
+  }
+  return values.size();
+}
+
+}  // namespace
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
+                             const std::map<std::string, std::string>& vars,
+                             const Options& options)
+    : descriptor_(descriptor),
+      classname_(ClassName(descriptor, false)),
+      options_(options),
+      generate_array_size_(ShouldGenerateArraySize(descriptor)),
+      variables_(vars) {
+  variables_["classname"] = classname_;
+  variables_["classtype"] = QualifiedClassName(descriptor_, options);
+  variables_["short_name"] = descriptor_->name();
+  variables_["nested_name"] = descriptor_->name();
+  variables_["resolved_name"] = ResolveKeyword(descriptor_->name());
+  variables_["prefix"] =
+      (descriptor_->containing_type() == nullptr) ? "" : classname_ + "_";
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::GenerateDefinition(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format("enum ${1$$classname$$}$ : int {\n", descriptor_);
+  format.Indent();
+
+  const EnumValueDescriptor* min_value = descriptor_->value(0);
+  const EnumValueDescriptor* max_value = descriptor_->value(0);
+
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    auto format_value = format;
+    format_value.Set("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.
+    format_value.Set("number", Int32ToString(descriptor_->value(i)->number()));
+    format_value.Set("deprecation",
+                     DeprecatedAttribute(options_, descriptor_->value(i)));
+
+    if (i > 0) format_value(",\n");
+    format_value("${1$$prefix$$name$$}$ $deprecation$= $number$",
+                 descriptor_->value(i));
+
+    if (descriptor_->value(i)->number() < min_value->number()) {
+      min_value = descriptor_->value(i);
+    }
+    if (descriptor_->value(i)->number() > max_value->number()) {
+      max_value = descriptor_->value(i);
+    }
+  }
+
+  if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    // For new enum semantics: generate min and max sentinel values equal to
+    // INT32_MIN and INT32_MAX
+    if (descriptor_->value_count() > 0) format(",\n");
+    format(
+        "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = "
+        "std::numeric_limits<$int32$>::min(),\n"
+        "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = "
+        "std::numeric_limits<$int32$>::max()");
+  }
+
+  format.Outdent();
+  format("\n};\n");
+
+  format(
+      "$dllexport_decl $bool $classname$_IsValid(int value);\n"
+      "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = "
+      "$prefix$$2$;\n"
+      "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = "
+      "$prefix$$3$;\n",
+      descriptor_, EnumValueName(min_value), EnumValueName(max_value));
+
+  if (generate_array_size_) {
+    format(
+        "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = "
+        "$prefix$$short_name$_MAX + 1;\n\n",
+        descriptor_);
+  }
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format(
+        "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* "
+        "$classname$_descriptor();\n");
+  }
+
+  // The _Name and _Parse functions. The lite implementation is table-based, so
+  // we make sure to keep the tables hidden in the .cc file.
+  if (!HasDescriptorMethods(descriptor_->file(), options_)) {
+    format("const std::string& $classname$_Name($classname$ value);\n");
+  }
+  // The _Name() function accepts the enum type itself but also any integral
+  // type.
+  format(
+      "template<typename T>\n"
+      "inline const std::string& $classname$_Name(T enum_t_value) {\n"
+      "  static_assert(::std::is_same<T, $classname$>::value ||\n"
+      "    ::std::is_integral<T>::value,\n"
+      "    \"Incorrect type passed to function $classname$_Name.\");\n");
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format(
+        "  return ::$proto_ns$::internal::NameOfEnum(\n"
+        "    $classname$_descriptor(), enum_t_value);\n");
+  } else {
+    format(
+        "  return $classname$_Name(static_cast<$classname$>(enum_t_value));\n");
+  }
+  format("}\n");
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format(
+        "inline bool $classname$_Parse(\n"
+        "    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* "
+        "value) "
+        "{\n"
+        "  return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n"
+        "    $classname$_descriptor(), name, value);\n"
+        "}\n");
+  } else {
+    format(
+        "bool $classname$_Parse(\n"
+        "    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* "
+        "value);\n");
+  }
+}
+
+void EnumGenerator::GenerateGetEnumDescriptorSpecializations(
+    io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format(
+      "template <> struct is_proto_enum< $classtype$> : ::std::true_type "
+      "{};\n");
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format(
+        "template <>\n"
+        "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n"
+        "  return $classtype$_descriptor();\n"
+        "}\n");
+  }
+}
+
+void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("typedef $classname$ $resolved_name$;\n");
+
+  for (int j = 0; j < descriptor_->value_count(); j++) {
+    std::string deprecated_attr =
+        DeprecatedAttribute(options_, descriptor_->value(j));
+    format(
+        "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n"
+        "  $classname$_$3$;\n",
+        deprecated_attr, descriptor_->value(j),
+        EnumValueName(descriptor_->value(j)));
+  }
+
+  format(
+      "static inline bool $nested_name$_IsValid(int value) {\n"
+      "  return $classname$_IsValid(value);\n"
+      "}\n"
+      "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n"
+      "  $classname$_$nested_name$_MIN;\n"
+      "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n"
+      "  $classname$_$nested_name$_MAX;\n",
+      descriptor_);
+  if (generate_array_size_) {
+    format(
+        "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n"
+        "  $classname$_$nested_name$_ARRAYSIZE;\n",
+        descriptor_);
+  }
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format(
+        "static inline const ::$proto_ns$::EnumDescriptor*\n"
+        "$nested_name$_descriptor() {\n"
+        "  return $classname$_descriptor();\n"
+        "}\n");
+  }
+
+  format(
+      "template<typename T>\n"
+      "static inline const std::string& $nested_name$_Name(T enum_t_value) {\n"
+      "  static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
+      "    ::std::is_integral<T>::value,\n"
+      "    \"Incorrect type passed to function $nested_name$_Name.\");\n"
+      "  return $classname$_Name(enum_t_value);\n"
+      "}\n");
+  format(
+      "static inline bool "
+      "$nested_name$_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,\n"
+      "    $resolved_name$* value) {\n"
+      "  return $classname$_Parse(name, value);\n"
+      "}\n");
+}
+
+void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format(
+        "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n"
+        "  ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n"
+        "  return $file_level_enum_descriptors$[$1$];\n"
+        "}\n",
+        idx);
+  }
+
+  format(
+      "bool $classname$_IsValid(int value) {\n"
+      "  switch (value) {\n");
+
+  // Multiple values may have the same number.  Make sure we only cover
+  // each number once by first constructing a set containing all valid
+  // numbers, then printing a case statement for each element.
+
+  std::set<int> numbers;
+  for (int j = 0; j < descriptor_->value_count(); j++) {
+    const EnumValueDescriptor* value = descriptor_->value(j);
+    numbers.insert(value->number());
+  }
+
+  for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end();
+       ++iter) {
+    format("    case $1$:\n", Int32ToString(*iter));
+  }
+
+  format(
+      "      return true;\n"
+      "    default:\n"
+      "      return false;\n"
+      "  }\n"
+      "}\n"
+      "\n");
+
+  if (!HasDescriptorMethods(descriptor_->file(), options_)) {
+    // In lite mode (where descriptors are unavailable), we generate separate
+    // tables for mapping between enum names and numbers. The _entries table
+    // contains the bulk of the data and is sorted by name, while
+    // _entries_by_number is sorted by number and just contains pointers into
+    // _entries. The two tables allow mapping from name to number and number to
+    // name, both in time logarithmic in the number of enum entries. This could
+    // probably be made faster, but for now the tables are intended to be simple
+    // and compact.
+    //
+    // Enums with allow_alias = true support multiple entries with the same
+    // numerical value. In cases where there are multiple names for the same
+    // number, we treat the first name appearing in the .proto file as the
+    // canonical one.
+    std::map<std::string, int> name_to_number;
+    std::map<int, std::string> number_to_canonical_name;
+    for (int i = 0; i < descriptor_->value_count(); i++) {
+      const EnumValueDescriptor* value = descriptor_->value(i);
+      name_to_number.emplace(value->name(), value->number());
+      // The same number may appear with multiple names, so we use emplace() to
+      // let the first name win.
+      number_to_canonical_name.emplace(value->number(), value->name());
+    }
+
+    format(
+        "static ::$proto_ns$::internal::ExplicitlyConstructed<std::string> "
+        "$classname$_strings[$1$] = {};\n\n",
+        CountUniqueValues(descriptor_));
+
+    // We concatenate all the names for a given enum into one big string
+    // literal. If instead we store an array of string literals, the linker
+    // seems to put all enum strings for a given .proto file in the same
+    // section, which hinders its ability to strip out unused strings.
+    format("static const char $classname$_names[] =");
+    for (const auto& p : name_to_number) {
+      format("\n  \"$1$\"", p.first);
+    }
+    format(";\n\n");
+
+    format(
+        "static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] "
+        "= {\n");
+    int i = 0;
+    std::map<int, int> number_to_index;
+    int data_index = 0;
+    for (const auto& p : name_to_number) {
+      format("  { {$classname$_names + $1$, $2$}, $3$ },\n", data_index,
+             p.first.size(), p.second);
+      if (number_to_canonical_name[p.second] == p.first) {
+        number_to_index.emplace(p.second, i);
+      }
+      ++i;
+      data_index += p.first.size();
+    }
+
+    format(
+        "};\n"
+        "\n"
+        "static const int $classname$_entries_by_number[] = {\n");
+    for (const auto& p : number_to_index) {
+      format("  $1$, // $2$ -> $3$\n", p.second, p.first,
+             number_to_canonical_name[p.first]);
+    }
+    format(
+        "};\n"
+        "\n");
+
+    format(
+        "const std::string& $classname$_Name(\n"
+        "    $classname$ value) {\n"
+        "  static const bool dummy =\n"
+        "      ::$proto_ns$::internal::InitializeEnumStrings(\n"
+        "          $classname$_entries,\n"
+        "          $classname$_entries_by_number,\n"
+        "          $1$, $classname$_strings);\n"
+        "  (void) dummy;\n"
+        "  int idx = ::$proto_ns$::internal::LookUpEnumName(\n"
+        "      $classname$_entries,\n"
+        "      $classname$_entries_by_number,\n"
+        "      $1$, value);\n"
+        "  return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n"
+        "                     $classname$_strings[idx].get();\n"
+        "}\n",
+        CountUniqueValues(descriptor_));
+    format(
+        "bool $classname$_Parse(\n"
+        "    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* "
+        "value) "
+        "{\n"
+        "  int int_value;\n"
+        "  bool success = ::$proto_ns$::internal::LookUpEnumValue(\n"
+        "      $classname$_entries, $1$, name, &int_value);\n"
+        "  if (success) {\n"
+        "    *value = static_cast<$classname$>(int_value);\n"
+        "  }\n"
+        "  return success;\n"
+        "}\n",
+        descriptor_->value_count());
+  }
+
+  if (descriptor_->containing_type() != nullptr) {
+    std::string parent = ClassName(descriptor_->containing_type(), false);
+    // Before C++17, we must define the static constants which were
+    // declared in the header, to give the linker a place to put them.
+    // But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not.
+    format(
+        "#if (__cplusplus < 201703) && "
+        "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n");
+
+    for (int i = 0; i < descriptor_->value_count(); i++) {
+      format("constexpr $classname$ $1$::$2$;\n", parent,
+             EnumValueName(descriptor_->value(i)));
+    }
+    format(
+        "constexpr $classname$ $1$::$nested_name$_MIN;\n"
+        "constexpr $classname$ $1$::$nested_name$_MAX;\n",
+        parent);
+    if (generate_array_size_) {
+      format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent);
+    }
+
+    format(
+        "#endif  // (__cplusplus < 201703) && "
+        "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n");
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/enum.h b/src/google/protobuf/compiler/cpp/enum.h
new file mode 100644
index 0000000..610d4fc
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/enum.h
@@ -0,0 +1,106 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_CPP_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
+
+#include <map>
+#include <set>
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class EnumGenerator {
+ public:
+  // See generator.cc for the meaning of dllexport_decl.
+  EnumGenerator(const EnumDescriptor* descriptor,
+                const std::map<std::string, std::string>& vars,
+                const Options& options);
+  ~EnumGenerator();
+
+  // 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.
+  void GenerateDefinition(io::Printer* printer);
+
+  // Generate specialization of GetEnumDescriptor<MyEnum>().
+  // Precondition: in ::google::protobuf namespace.
+  void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
+
+  // For enums nested within a message, generate code to import all the enum's
+  // symbols (e.g. the enum type name, all its values, etc.) into the class's
+  // namespace.  This should be placed inside the class definition in the
+  // header.
+  void GenerateSymbolImports(io::Printer* printer) const;
+
+  // Source file stuff.
+
+  // Generate non-inline methods related to the enum, such as IsValidValue().
+  // Goes in the .cc file. EnumDescriptors are stored in an array, idx is
+  // the index in this array that corresponds with this enum.
+  void GenerateMethods(int idx, io::Printer* printer);
+
+ private:
+  const EnumDescriptor* descriptor_;
+  const std::string classname_;
+  const Options& options_;
+  // whether to generate the *_ARRAYSIZE constant.
+  const bool generate_array_size_;
+
+  std::map<std::string, std::string> variables_;
+
+  friend class FileGenerator;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
diff --git a/src/google/protobuf/compiler/cpp/enum_field.cc b/src/google/protobuf/compiler/cpp/enum_field.cc
new file mode 100644
index 0000000..8ffb699
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/enum_field.cc
@@ -0,0 +1,451 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/enum_field.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor,
+                      std::map<std::string, std::string>* variables,
+                      const Options& options) {
+  SetCommonFieldVariables(descriptor, variables, options);
+  const EnumValueDescriptor* default_value = descriptor->default_value_enum();
+  (*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options);
+  (*variables)["default"] = Int32ToString(default_value->number());
+  (*variables)["full_name"] = descriptor->full_name();
+  (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
+  bool cold = ShouldSplit(descriptor, options);
+  (*variables)["cached_byte_size_field"] =
+      MakeVarintCachedSizeFieldName(descriptor, cold);
+}
+
+}  // namespace
+
+// ===================================================================
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       const Options& options)
+    : FieldGenerator(descriptor, options) {
+  SetEnumVariables(descriptor, &variables_, options);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("int $name$_;\n");
+}
+
+void EnumFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
+      "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n"
+      "private:\n"
+      "$type$ ${1$_internal_$name$$}$() const;\n"
+      "void ${1$_internal_set_$name$$}$($type$ value);\n"
+      "public:\n",
+      descriptor_);
+}
+
+void EnumFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$ $classname$::_internal_$name$() const {\n"
+      "  return static_cast< $type$ >($field$);\n"
+      "}\n"
+      "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline void $classname$::_internal_set_$name$($type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
+    format("  assert($type$_IsValid(value));\n");
+  }
+  format(
+      "  $set_hasbit$\n"
+      "  $field$ = value;\n"
+      "}\n"
+      "inline void $classname$::set_$name$($type$ value) {\n"
+      "$maybe_prepare_split_message$"
+      "  _internal_set_$name$(value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n");
+}
+
+void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$ = $default$;\n");
+}
+
+void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->_internal_set_$name$(from._internal_$name$());\n");
+}
+
+void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("swap($field$, other->$field$);\n");
+}
+
+void EnumFieldGenerator::GenerateCopyConstructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->$field$ = from.$field$;\n");
+}
+
+void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "target = stream->EnsureSpace(target);\n"
+      "target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
+      "  $number$, this->_internal_$name$(), target);\n");
+}
+
+void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "total_size += $tag_size$ +\n"
+      "  ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n");
+}
+
+void EnumFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("/*decltype($field$)*/$default$");
+}
+
+void EnumFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    format("decltype(Impl_::Split::$name$_){$default$}");
+    return;
+  }
+  format("decltype($field$){$default$}");
+}
+
+void EnumFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){}");
+}
+
+// ===================================================================
+
+EnumOneofFieldGenerator::EnumOneofFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : EnumFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
+
+void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$ $classname$::_internal_$name$() const {\n"
+      "  if (_internal_has_$name$()) {\n"
+      "    return static_cast< $type$ >($field$);\n"
+      "  }\n"
+      "  return static_cast< $type$ >($default$);\n"
+      "}\n"
+      "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline void $classname$::_internal_set_$name$($type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
+    format("  assert($type$_IsValid(value));\n");
+  }
+  format(
+      "  if (!_internal_has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "  }\n"
+      "  $field$ = value;\n"
+      "}\n"
+      "inline void $classname$::set_$name$($type$ value) {\n"
+      "  _internal_set_$name$(value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n");
+}
+
+void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$ = $default$;\n");
+}
+
+void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void EnumOneofFieldGenerator::GenerateConstructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n");
+}
+
+// ===================================================================
+
+RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(descriptor, options) {
+  SetEnumVariables(descriptor, &variables_, options);
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::GeneratePrivateMembers(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("::$proto_ns$::RepeatedField<int> $name$_;\n");
+  if (descriptor_->is_packed() &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    format("mutable std::atomic<int> $cached_byte_size_name$;\n");
+  }
+}
+
+void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "private:\n"
+      "$type$ ${1$_internal_$name$$}$(int index) const;\n"
+      "void ${1$_internal_add_$name$$}$($type$ value);\n"
+      "::$proto_ns$::RepeatedField<int>* "
+      "${1$_internal_mutable_$name$$}$();\n"
+      "public:\n"
+      "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
+      "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
+      "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
+      "$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& "
+      "${1$$name$$}$() const;\n"
+      "$deprecated_attr$::$proto_ns$::RepeatedField<int>* "
+      "${1$mutable_$name$$}$();\n",
+      descriptor_);
+}
+
+void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$ $classname$::_internal_$name$(int index) const {\n"
+      "  return static_cast< $type$ >($field$.Get(index));\n"
+      "}\n"
+      "inline $type$ $classname$::$name$(int index) const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$(index);\n"
+      "}\n"
+      "inline void $classname$::set_$name$(int index, $type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
+    format("  assert($type$_IsValid(value));\n");
+  }
+  format(
+      "  $field$.Set(index, value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline void $classname$::_internal_add_$name$($type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
+    format("  assert($type$_IsValid(value));\n");
+  }
+  format(
+      "  $field$.Add(value);\n"
+      "}\n"
+      "inline void $classname$::add_$name$($type$ value) {\n"
+      "  _internal_add_$name$(value);\n"
+      "$annotate_add$"
+      "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "}\n"
+      "inline const ::$proto_ns$::RepeatedField<int>&\n"
+      "$classname$::$name$() const {\n"
+      "$annotate_list$"
+      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+      "  return $field$;\n"
+      "}\n"
+      "inline ::$proto_ns$::RepeatedField<int>*\n"
+      "$classname$::_internal_mutable_$name$() {\n"
+      "  return &$field$;\n"
+      "}\n"
+      "inline ::$proto_ns$::RepeatedField<int>*\n"
+      "$classname$::mutable_$name$() {\n"
+      "$annotate_mutable_list$"
+      "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
+      "  return _internal_mutable_$name$();\n"
+      "}\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.Clear();\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->$field$.MergeFrom(from.$field$);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.InternalSwap(&other->$field$);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateConstructorCode(
+    io::Printer* printer) const {
+  // Not needed for repeated fields.
+}
+
+void RepeatedEnumFieldGenerator::GenerateDestructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.~RepeatedField();\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (descriptor_->is_packed()) {
+    // Write the tag and the size.
+    format(
+        "{\n"
+        "  int byte_size = "
+        "$cached_byte_size_field$.load(std::memory_order_relaxed);\n"
+        "  if (byte_size > 0) {\n"
+        "    target = stream->WriteEnumPacked(\n"
+        "        $number$, $field$, byte_size, target);\n"
+        "  }\n"
+        "}\n");
+  } else {
+    format(
+        "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
+        "  target = stream->EnsureSpace(target);\n"
+        "  target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
+        "      $number$, this->_internal_$name$(i), target);\n"
+        "}\n");
+  }
+}
+
+void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "{\n"
+      "  size_t data_size = 0;\n"
+      "  unsigned int count = static_cast<unsigned "
+      "int>(this->_internal_$name$_size());");
+  format.Indent();
+  format(
+      "for (unsigned int i = 0; i < count; i++) {\n"
+      "  data_size += ::_pbi::WireFormatLite::EnumSize(\n"
+      "    this->_internal_$name$(static_cast<int>(i)));\n"
+      "}\n");
+
+  if (descriptor_->is_packed()) {
+    format(
+        "if (data_size > 0) {\n"
+        "  total_size += $tag_size$ +\n"
+        "    "
+        "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
+        "}\n"
+        "int cached_size = ::_pbi::ToCachedSize(data_size);\n"
+        "$cached_byte_size_field$.store(cached_size,\n"
+        "                                std::memory_order_relaxed);\n"
+        "total_size += data_size;\n");
+  } else {
+    format("total_size += ($tag_size$UL * count) + data_size;\n");
+  }
+  format.Outdent();
+  format("}\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("/*decltype($field$)*/{}");
+  if (descriptor_->is_packed() &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    format("\n, /*decltype($cached_byte_size_field$)*/{0}");
+  }
+}
+
+void RepeatedEnumFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){arena}");
+  if (descriptor_->is_packed() &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    // std::atomic has no copy constructor, which prevents explicit aggregate
+    // initialization pre-C++17.
+    format("\n, /*decltype($cached_byte_size_field$)*/{0}");
+  }
+}
+
+void RepeatedEnumFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){from.$field$}");
+  if (descriptor_->is_packed() &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    // std::atomic has no copy constructor.
+    format("\n, /*decltype($cached_byte_size_field$)*/{0}");
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/enum_field.h b/src/google/protobuf/compiler/cpp/enum_field.h
new file mode 100644
index 0000000..61bae85
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/enum_field.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class EnumFieldGenerator : public FieldGenerator {
+ public:
+  EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
+  ~EnumFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override {}
+  void GenerateCopyConstructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class EnumOneofFieldGenerator : public EnumFieldGenerator {
+ public:
+  EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options);
+  ~EnumOneofFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public FieldGenerator {
+ public:
+  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
+  ~RepeatedEnumFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+  void GenerateCopyConstructorCode(io::Printer*  /*printer*/) const override {
+    GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
+  }
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/extension.cc b/src/google/protobuf/compiler/cpp/extension.cc
new file mode 100644
index 0000000..950ed9e
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/extension.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/extension.h>
+
+#include <map>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
+                                       const Options& options,
+                                       MessageSCCAnalyzer* scc_analyzer)
+    : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
+  // Construct type_traits_.
+  if (descriptor_->is_repeated()) {
+    type_traits_ = "Repeated";
+  }
+
+  switch (descriptor_->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_ENUM:
+      type_traits_.append("EnumTypeTraits< ");
+      type_traits_.append(ClassName(descriptor_->enum_type(), true));
+      type_traits_.append(", ");
+      type_traits_.append(ClassName(descriptor_->enum_type(), true));
+      type_traits_.append("_IsValid>");
+      break;
+    case FieldDescriptor::CPPTYPE_STRING:
+      type_traits_.append("StringTypeTraits");
+      break;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      type_traits_.append("MessageTypeTraits< ");
+      type_traits_.append(ClassName(descriptor_->message_type(), true));
+      type_traits_.append(" >");
+      break;
+    default:
+      type_traits_.append("PrimitiveTypeTraits< ");
+      type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
+      type_traits_.append(" >");
+      break;
+  }
+  SetCommonVars(options, &variables_);
+  SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_);
+  variables_["extendee"] =
+      QualifiedClassName(descriptor_->containing_type(), options_);
+  variables_["type_traits"] = type_traits_;
+  std::string name = descriptor_->name();
+  variables_["name"] = ResolveKeyword(name);
+  variables_["constant_name"] = FieldConstantName(descriptor_);
+  variables_["field_type"] =
+      StrCat(static_cast<int>(descriptor_->type()));
+  variables_["packed"] = descriptor_->is_packed() ? "true" : "false";
+
+  std::string scope =
+      IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : "";
+  variables_["scope"] = scope;
+  variables_["scoped_name"] = ExtensionName(descriptor_);
+  variables_["number"] = StrCat(descriptor_->number());
+
+  bool add_verify_fn =
+      // Only verify msgs.
+      descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      // Options say to verify.
+      ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
+      ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
+
+  variables_["verify_fn"] =
+      add_verify_fn
+          ? StrCat("&", FieldMessageTypeName(descriptor_, options_),
+                         "::InternalVerify")
+          : "nullptr";
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+bool ExtensionGenerator::IsScoped() const {
+  return descriptor_->extension_scope() != nullptr;
+}
+
+void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+
+  // If this is a class member, it needs to be declared "static".  Otherwise,
+  // it needs to be "extern".  In the latter case, it also needs the DLL
+  // export/import specifier.
+  std::string qualifier;
+  if (!IsScoped()) {
+    qualifier = "extern";
+    if (!options_.dllexport_decl.empty()) {
+      qualifier = options_.dllexport_decl + " " + qualifier;
+    }
+  } else {
+    qualifier = "static";
+  }
+
+  format(
+      "static const int $constant_name$ = $number$;\n"
+      "$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
+      "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
+      "  ${2$$name$$}$;\n",
+      qualifier, descriptor_);
+}
+
+void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
+  // If we are building for lite with implicit weak fields, we want to skip over
+  // any custom options (i.e. extensions of messages from descriptor.proto).
+  // This prevents the creation of any unnecessary linker references to the
+  // descriptor messages.
+  if (options_.lite_implicit_weak_fields &&
+      descriptor_->containing_type()->file()->name() ==
+          "net/proto2/proto/descriptor.proto") {
+    return;
+  }
+
+  Formatter format(printer, variables_);
+  std::string default_str;
+  // If this is a class member, it needs to be declared in its class scope.
+  if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+    // We need to declare a global string which will contain the default value.
+    // We cannot declare it at class scope because that would require exposing
+    // it in the header which would be annoying for other reasons.  So we
+    // replace :: with _ in the name and declare it as a global.
+    default_str =
+        StringReplace(variables_["scoped_name"], "::", "_", true) + "_default";
+    format("const std::string $1$($2$);\n", default_str,
+           DefaultValue(options_, descriptor_));
+  } else if (descriptor_->message_type()) {
+    // We have to initialize the default instance for extensions at registration
+    // time.
+    default_str =
+        FieldMessageTypeName(descriptor_, options_) + "::default_instance()";
+  } else {
+    default_str = DefaultValue(options_, descriptor_);
+  }
+
+  // Likewise, class members need to declare the field constant variable.
+  if (IsScoped()) {
+    format(
+        "#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)\n"
+        "const int $scope$$constant_name$;\n"
+        "#endif\n");
+  }
+
+  format(
+      "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 "
+      "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
+      "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$>\n"
+      "  $scoped_name$($constant_name$, $1$, $verify_fn$);\n",
+      default_str);
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/extension.h b/src/google/protobuf/compiler/cpp/extension.h
new file mode 100644
index 0000000..282931f
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/extension.h
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+class FieldDescriptor;  // descriptor.h
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MessageSCCAnalyzer;
+
+// Generates code for an extension, which may be within the scope of some
+// message or may be at file scope.  This is much simpler than FieldGenerator
+// since extensions are just simple identifiers with interesting types.
+class ExtensionGenerator {
+ public:
+  // See generator.cc for the meaning of dllexport_decl.
+  explicit ExtensionGenerator(const FieldDescriptor* descriptor,
+                              const Options& options,
+                              MessageSCCAnalyzer* scc_analyzer);
+  ~ExtensionGenerator();
+
+  // Header stuff.
+  void GenerateDeclaration(io::Printer* printer) const;
+
+  // Source file stuff.
+  void GenerateDefinition(io::Printer* printer);
+
+  bool IsScoped() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::string type_traits_;
+  Options options_;
+  MessageSCCAnalyzer* scc_analyzer_;
+
+  std::map<std::string, std::string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/cpp/field.cc b/src/google/protobuf/compiler/cpp/field.cc
new file mode 100644
index 0000000..90d2084
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/field.cc
@@ -0,0 +1,421 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/field.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/primitive_field.h>
+#include <google/protobuf/compiler/cpp/string_field.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/compiler/cpp/enum_field.h>
+#include <google/protobuf/compiler/cpp/map_field.h>
+#include <google/protobuf/compiler/cpp/message_field.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+
+namespace {
+
+void MaySetAnnotationVariable(const Options& options,
+                              StringPiece annotation_name,
+                              StringPiece substitute_template_prefix,
+                              StringPiece prepared_template,
+                              int field_index, StringPiece access_type,
+                              std::map<std::string, std::string>* variables) {
+  if (options.field_listener_options.forbidden_field_listener_events.count(
+          std::string(annotation_name)))
+    return;
+  (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute(
+      StrCat(substitute_template_prefix, prepared_template, ");\n"),
+      field_index, access_type);
+}
+
+std::string GenerateTemplateForOneofString(const FieldDescriptor* descriptor,
+                                           StringPiece proto_ns,
+                                           StringPiece field_member) {
+  std::string field_name = google::protobuf::compiler::cpp::FieldName(descriptor);
+  std::string field_pointer =
+      descriptor->options().ctype() == google::protobuf::FieldOptions::STRING
+          ? "$0.UnsafeGetPointer()"
+          : "$0";
+
+  if (descriptor->default_value_string().empty()) {
+    return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ",
+                                         field_pointer, ": nullptr"),
+                            field_member);
+  }
+
+  if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) {
+    return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ",
+                                         field_pointer, ": nullptr"),
+                            field_member);
+  }
+
+  std::string default_value_pointer =
+      descriptor->options().ctype() == google::protobuf::FieldOptions::STRING
+          ? "&$1.get()"
+          : "&$1";
+  return strings::Substitute(
+      StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ",
+                   default_value_pointer),
+      field_member, MakeDefaultFieldName(descriptor));
+}
+
+std::string GenerateTemplateForSingleString(const FieldDescriptor* descriptor,
+                                            StringPiece field_member) {
+  if (descriptor->default_value_string().empty()) {
+    return StrCat("&", field_member);
+  }
+
+  if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) {
+    return strings::Substitute(
+        "$0.IsDefault() ? &$1.get() : $0.UnsafeGetPointer()", field_member,
+        MakeDefaultFieldName(descriptor));
+  }
+
+  return StrCat("&", field_member);
+}
+
+}  // namespace
+
+void AddAccessorAnnotations(const FieldDescriptor* descriptor,
+                            const Options& options,
+                            std::map<std::string, std::string>* variables) {
+  // Can be expanded to include more specific calls, for example, for arena or
+  // clear calls.
+  static constexpr const char* kAccessorsAnnotations[] = {
+      "annotate_add",     "annotate_get",         "annotate_has",
+      "annotate_list",    "annotate_mutable",     "annotate_mutable_list",
+      "annotate_release", "annotate_set",         "annotate_size",
+      "annotate_clear",   "annotate_add_mutable",
+  };
+  for (size_t i = 0; i < GOOGLE_ARRAYSIZE(kAccessorsAnnotations); ++i) {
+    (*variables)[kAccessorsAnnotations[i]] = "";
+  }
+  if (options.annotate_accessor) {
+    for (size_t i = 0; i < GOOGLE_ARRAYSIZE(kAccessorsAnnotations); ++i) {
+      (*variables)[kAccessorsAnnotations[i]] = StrCat(
+          "  ", FieldName(descriptor), "_AccessedNoStrip = true;\n");
+    }
+  }
+  if (!options.field_listener_options.inject_field_listener_events) {
+    return;
+  }
+  if (descriptor->file()->options().optimize_for() ==
+      google::protobuf::FileOptions::LITE_RUNTIME) {
+    return;
+  }
+  std::string field_member = (*variables)["field"];
+  const google::protobuf::OneofDescriptor* oneof_member =
+      descriptor->real_containing_oneof();
+  const std::string proto_ns = (*variables)["proto_ns"];
+  const std::string substitute_template_prefix =
+      StrCat("  ", (*variables)["tracker"], ".$1<$0>(this, ");
+  std::string prepared_template;
+
+  // Flat template is needed if the prepared one is introspecting the values
+  // inside the returned values, for example, for repeated fields and maps.
+  std::string prepared_flat_template;
+  std::string prepared_add_template;
+  // TODO(b/190614678): Support fields with type Message or Map.
+  if (descriptor->is_repeated() && !descriptor->is_map()) {
+    if (descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
+        descriptor->type() != FieldDescriptor::TYPE_GROUP) {
+      prepared_template = strings::Substitute("&$0.Get(index)", field_member);
+      prepared_add_template =
+          strings::Substitute("&$0.Get($0.size() - 1)", field_member);
+    } else {
+      prepared_template = "nullptr";
+      prepared_add_template = "nullptr";
+    }
+  } else if (descriptor->is_map()) {
+    prepared_template = "nullptr";
+  } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
+             !IsExplicitLazy(descriptor)) {
+    prepared_template = "nullptr";
+  } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+    if (oneof_member) {
+      prepared_template = GenerateTemplateForOneofString(
+          descriptor, (*variables)["proto_ns"], field_member);
+    } else {
+      prepared_template =
+          GenerateTemplateForSingleString(descriptor, field_member);
+    }
+  } else {
+    prepared_template = StrCat("&", field_member);
+  }
+  if (descriptor->is_repeated() && !descriptor->is_map() &&
+      descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
+      descriptor->type() != FieldDescriptor::TYPE_GROUP) {
+    prepared_flat_template = StrCat("&", field_member);
+  } else {
+    prepared_flat_template = prepared_template;
+  }
+
+  MaySetAnnotationVariable(options, "get", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnGet",
+                           variables);
+  MaySetAnnotationVariable(options, "set", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnSet",
+                           variables);
+  MaySetAnnotationVariable(options, "has", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnHas",
+                           variables);
+  MaySetAnnotationVariable(options, "mutable", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnMutable",
+                           variables);
+  MaySetAnnotationVariable(options, "release", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnRelease",
+                           variables);
+  MaySetAnnotationVariable(options, "clear", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnClear", variables);
+  MaySetAnnotationVariable(options, "size", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnSize", variables);
+  MaySetAnnotationVariable(options, "list", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnList", variables);
+  MaySetAnnotationVariable(options, "mutable_list", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnMutableList", variables);
+  MaySetAnnotationVariable(options, "add", substitute_template_prefix,
+                           prepared_add_template, descriptor->index(), "OnAdd",
+                           variables);
+  MaySetAnnotationVariable(options, "add_mutable", substitute_template_prefix,
+                           prepared_add_template, descriptor->index(),
+                           "OnAddMutable", variables);
+}
+
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             std::map<std::string, std::string>* variables,
+                             const Options& options) {
+  SetCommonVars(options, variables);
+  SetCommonMessageDataVariables(descriptor->containing_type(), variables);
+
+  (*variables)["ns"] = Namespace(descriptor, options);
+  (*variables)["name"] = FieldName(descriptor);
+  (*variables)["index"] = StrCat(descriptor->index());
+  (*variables)["number"] = StrCat(descriptor->number());
+  (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
+  (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+  bool split = ShouldSplit(descriptor, options);
+  (*variables)["field"] = FieldMemberName(descriptor, split);
+
+  (*variables)["tag_size"] = StrCat(
+      WireFormat::TagSize(descriptor->number(), descriptor->type()));
+  (*variables)["deprecated_attr"] = DeprecatedAttribute(options, descriptor);
+
+  (*variables)["set_hasbit"] = "";
+  (*variables)["clear_hasbit"] = "";
+  (*variables)["maybe_prepare_split_message"] =
+      split ? "  PrepareSplitMessageForWrite();\n" : "";
+
+  AddAccessorAnnotations(descriptor, options, variables);
+
+  // These variables are placeholders to pick out the beginning and ends of
+  // identifiers for annotations (when doing so with existing variables would
+  // be ambiguous or impossible). They should never be set to anything but the
+  // empty string.
+  (*variables)["{"] = "";
+  (*variables)["}"] = "";
+}
+
+void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) {
+  if (!HasHasbit(descriptor_)) {
+    GOOGLE_CHECK_EQ(has_bit_index, -1);
+    return;
+  }
+  variables_["set_hasbit"] = StrCat(
+      variables_["has_bits"], "[", has_bit_index / 32, "] |= 0x",
+      strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;");
+  variables_["clear_hasbit"] = StrCat(
+      variables_["has_bits"], "[", has_bit_index / 32, "] &= ~0x",
+      strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;");
+}
+
+void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {
+  if (!IsStringInlined(descriptor_, options_)) {
+    GOOGLE_CHECK_EQ(inlined_string_index, -1);
+    return;
+  }
+  // The first bit is the tracking bit for on demand registering ArenaDtor.
+  GOOGLE_CHECK_GT(inlined_string_index, 0)
+      << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking";
+  variables_["inlined_string_donated"] = StrCat(
+      "(", variables_["inlined_string_donated_array"], "[",
+      inlined_string_index / 32, "] & 0x",
+      strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
+      "u) != 0;");
+  variables_["donating_states_word"] =
+      StrCat(variables_["inlined_string_donated_array"], "[",
+                   inlined_string_index / 32, "]");
+  variables_["mask_for_undonate"] = StrCat(
+      "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
+      "u");
+}
+
+void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    format("decltype(Impl_::Split::$name$_){arena}");
+    return;
+  }
+  format("decltype($field$){arena}");
+}
+
+void FieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("/*decltype($field$)*/{}");
+}
+
+void FieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){from.$field$}");
+}
+
+void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
+  if (ShouldSplit(descriptor_, options_)) {
+    // There is no copy constructor for the `Split` struct, so we need to copy
+    // the value here.
+    Formatter format(printer, variables_);
+    format("$field$ = from.$field$;\n");
+  }
+}
+
+void SetCommonOneofFieldVariables(
+    const FieldDescriptor* descriptor,
+    std::map<std::string, std::string>* variables) {
+  const std::string prefix = descriptor->containing_oneof()->name() + "_.";
+  (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
+}
+
+FieldGenerator::~FieldGenerator() {}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
+                                     const Options& options,
+                                     MessageSCCAnalyzer* scc_analyzer)
+    : descriptor_(descriptor), field_generators_(descriptor->field_count()) {
+  // Construct all the FieldGenerators.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    field_generators_[i].reset(
+        MakeGenerator(descriptor->field(i), options, scc_analyzer));
+  }
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator(
+    const FieldDescriptor* field, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+
+  return nullptr;
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGenerator(
+    const FieldDescriptor* field, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  FieldGenerator* generator =
+      MakeGoogleInternalGenerator(field, options, scc_analyzer);
+  if (generator) {
+    return generator;
+  }
+
+  if (field->is_repeated()) {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (field->is_map()) {
+          return new MapFieldGenerator(field, options, scc_analyzer);
+        } else {
+          return new RepeatedMessageFieldGenerator(field, options,
+                                                   scc_analyzer);
+        }
+      case FieldDescriptor::CPPTYPE_STRING:
+        return new RepeatedStringFieldGenerator(field, options);
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return new RepeatedEnumFieldGenerator(field, options);
+      default:
+        return new RepeatedPrimitiveFieldGenerator(field, options);
+    }
+  } else if (field->real_containing_oneof()) {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        return new MessageOneofFieldGenerator(field, options, scc_analyzer);
+      case FieldDescriptor::CPPTYPE_STRING:
+        return new StringOneofFieldGenerator(field, options);
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return new EnumOneofFieldGenerator(field, options);
+      default:
+        return new PrimitiveOneofFieldGenerator(field, options);
+    }
+  } else {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        return new MessageFieldGenerator(field, options, scc_analyzer);
+      case FieldDescriptor::CPPTYPE_STRING:
+        return new StringFieldGenerator(field, options);
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return new EnumFieldGenerator(field, options);
+      default:
+        return new PrimitiveFieldGenerator(field, options);
+    }
+  }
+}
+
+FieldGeneratorMap::~FieldGeneratorMap() {}
+
+const FieldGenerator& FieldGeneratorMap::get(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+  return *field_generators_[field->index()];
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/field.h b/src/google/protobuf/compiler/cpp/field.h
new file mode 100644
index 0000000..dd2a51a
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/field.h
@@ -0,0 +1,270 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Helper function: set variables in the map that are the same for all
+// field code generators.
+// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
+// 'deprecation'].
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             std::map<std::string, std::string>* variables,
+                             const Options& options);
+
+void SetCommonOneofFieldVariables(
+    const FieldDescriptor* descriptor,
+    std::map<std::string, std::string>* variables);
+
+class FieldGenerator {
+ public:
+  explicit FieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options)
+      : descriptor_(descriptor), options_(options) {}
+  virtual ~FieldGenerator();
+  virtual void GenerateSerializeWithCachedSizes(
+      io::Printer* printer) const final{};
+  // Generate lines of code declaring members fields of the message class
+  // needed to represent this field.  These are placed inside the message
+  // class.
+  virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
+
+  // Generate static default variable for this field. These are placed inside
+  // the message class. Most field types don't need this, so the default
+  // implementation is empty.
+  virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
+
+  // 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 accessor functions for this field.
+  // These are placed inside the header after all class definitions.
+  virtual void GenerateInlineAccessorDefinitions(
+      io::Printer* printer) const = 0;
+
+  // Generate definitions of accessors that aren't inlined.  These are
+  // placed somewhere in the .cc file.
+  // Most field types don't need this, so the default implementation is empty.
+  virtual void GenerateNonInlineAccessorDefinitions(
+      io::Printer* /*printer*/) const {}
+
+  // Generate declarations of accessors that are for internal purposes only.
+  // Most field types don't need this, so the default implementation is empty.
+  virtual void GenerateInternalAccessorDefinitions(
+      io::Printer* /*printer*/) const {}
+
+  // Generate definitions of accessors that are for internal purposes only.
+  // Most field types don't need this, so the default implementation is empty.
+  virtual void GenerateInternalAccessorDeclarations(
+      io::Printer* /*printer*/) const {}
+
+  // Generate lines of code (statements, not declarations) which clear the
+  // field.  This is used to define the clear_$name$() method
+  virtual void GenerateClearingCode(io::Printer* printer) const = 0;
+
+  // Generate lines of code (statements, not declarations) which clear the
+  // field as part of the Clear() method for the whole message.  For message
+  // types which have field presence bits, MessageGenerator::GenerateClear
+  // will have already checked the presence bits.
+  //
+  // Since most field types can re-use GenerateClearingCode, this method is
+  // not pure virtual.
+  virtual void GenerateMessageClearingCode(io::Printer* printer) const {
+    GenerateClearingCode(printer);
+  }
+
+  // Generate lines of code (statements, not declarations) which merges the
+  // contents of the field from the current message to the target message,
+  // which is stored in the generated code variable "from".
+  // This is used to fill in the MergeFrom method for the whole message.
+  // Details of this usage can be found in message.cc under the
+  // GenerateMergeFrom method.
+  virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+
+  // Generates a copy constructor
+  virtual void GenerateCopyConstructorCode(io::Printer* printer) const;
+
+  // Generate lines of code (statements, not declarations) which swaps
+  // this field and the corresponding field of another message, which
+  // is stored in the generated code variable "other". This is used to
+  // define the Swap method. Details of usage can be found in
+  // message.cc under the GenerateSwap method.
+  virtual void GenerateSwappingCode(io::Printer* printer) const = 0;
+
+  // Generate initialization code for private members declared by
+  // GeneratePrivateMembers(). These go into the message class's SharedCtor()
+  // method, invoked by each of the generated constructors.
+  virtual void GenerateConstructorCode(io::Printer* printer) const = 0;
+
+  // Generate initialization code for private members in the cold struct.
+  virtual void GenerateCreateSplitMessageCode(io::Printer* printer) const {}
+
+  // Generate any code that needs to go in the class's SharedDtor() method,
+  // invoked by the destructor.
+  // Most field types don't need this, so the default implementation is empty.
+  virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {}
+
+  // Generate a manual destructor invocation for use when the message is on an
+  // arena. The code that this method generates will be executed inside a
+  // shared-for-the-whole-message-class method registered with
+  // OwnDestructor().
+  virtual void GenerateArenaDestructorCode(io::Printer* printer) const {
+    GOOGLE_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone)
+        << descriptor_->cpp_type_name();
+  }
+
+  // Generate initialization code for private members declared by
+  // GeneratePrivateMembers(). These go into the SharedCtor's
+  // aggregate initialization of the _impl_ struct and must follow the syntax
+  // (e.g. `decltype($field$){$default$}`). Does not include `:` or `,`
+  // separators.  Default values should be specified here when possible.
+  //
+  // Note: We use `decltype($field$)` for both explicit construction and the
+  // fact that it's self-documenting.  Pre-C++17, copy elision isn't guaranteed
+  // in aggregate initialization so a valid copy/move constructor must exist
+  // (even though it's not used).  Because of this, we need to comment out the
+  // decltype and fallback to implicit construction.
+  virtual void GenerateAggregateInitializer(io::Printer* printer) const;
+
+  // Generate constinit initialization code for private members declared by
+  // GeneratePrivateMembers(). These go into the constexpr constructor's
+  // aggregate initialization of the _impl_ struct and must follow the syntax
+  // (e.g. `/*decltype($field$)*/{}`, see above). Does not
+  // include `:` or `,` separators.
+  virtual void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const;
+
+  // Generate copy initialization code for private members declared by
+  // GeneratePrivateMembers(). These go into the copy constructor's
+  // aggregate initialization of the _impl_ struct and must follow the syntax
+  // (e.g. `decltype($field$){from.$field$}`, see above). Does not
+  // include `:` or `,` separators.
+  virtual void GenerateCopyAggregateInitializer(io::Printer* printer) const;
+
+  // Generate lines to serialize this field directly to the array "target",
+  // which are placed within the message's SerializeWithCachedSizesToArray()
+  // method. This must also advance "target" past the written bytes.
+  virtual void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const = 0;
+
+  // Generate lines to compute the serialized size of this field, which
+  // are placed in the message's ByteSize() method.
+  virtual void GenerateByteSize(io::Printer* printer) const = 0;
+
+  // Generates lines to call IsInitialized() for eligible message fields. Non
+  // message fields won't need to override this function.
+  virtual void GenerateIsInitialized(io::Printer* printer) const {}
+
+  virtual bool IsInlined() const { return false; }
+
+  virtual ArenaDtorNeeds NeedsArenaDestructor() const {
+    return ArenaDtorNeeds::kNone;
+  }
+
+  void SetHasBitIndex(int32_t has_bit_index);
+  void SetInlinedStringIndex(int32_t inlined_string_index);
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  const Options& options_;
+  std::map<std::string, std::string> variables_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+  FieldGeneratorMap(const Descriptor* descriptor, const Options& options,
+                    MessageSCCAnalyzer* scc_analyzer);
+  ~FieldGeneratorMap();
+
+  const FieldGenerator& get(const FieldDescriptor* field) const;
+
+  void SetHasBitIndices(const std::vector<int>& has_bit_indices_) {
+    for (int i = 0; i < descriptor_->field_count(); ++i) {
+      field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]);
+    }
+  }
+
+  void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) {
+    for (int i = 0; i < descriptor_->field_count(); ++i) {
+      field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]);
+    }
+  }
+
+ private:
+  const Descriptor* descriptor_;
+  std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
+
+  static FieldGenerator* MakeGoogleInternalGenerator(
+      const FieldDescriptor* field, const Options& options,
+      MessageSCCAnalyzer* scc_analyzer);
+  static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+                                       const Options& options,
+                                       MessageSCCAnalyzer* scc_analyzer);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/file.cc b/src/google/protobuf/compiler/cpp/file.cc
new file mode 100644
index 0000000..838e0ab
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/file.cc
@@ -0,0 +1,1382 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/file.h>
+
+#include <iostream>
+#include <map>
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/enum.h>
+#include <google/protobuf/compiler/cpp/extension.h>
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/message.h>
+#include <google/protobuf/compiler/cpp/service.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+// When we forward-declare things, we want to create a sorted order so our
+// output is deterministic and minimizes namespace changes.
+template <class T>
+std::string GetSortKey(const T& val) {
+  return val.full_name();
+}
+
+template <>
+std::string GetSortKey<FileDescriptor>(const FileDescriptor& val) {
+  return val.name();
+}
+
+template <class T>
+bool CompareSortKeys(const T* a, const T* b) {
+  return GetSortKey(*a) < GetSortKey(*b);
+}
+
+template <class T>
+std::vector<const T*> Sorted(const std::unordered_set<const T*>& vals) {
+  std::vector<const T*> sorted(vals.begin(), vals.end());
+  std::sort(sorted.begin(), sorted.end(), CompareSortKeys<T>);
+  return sorted;
+}
+
+// TODO(b/203101078): remove pragmas that suppresses uninitialized warnings when
+// clang bug is fixed.
+inline void MuteWuninitialized(Formatter& format) {
+  format(
+      "#if defined(__llvm__)\n"
+      "  #pragma clang diagnostic push\n"
+      "  #pragma clang diagnostic ignored \"-Wuninitialized\"\n"
+      "#endif  // __llvm__\n");
+}
+
+inline void UnmuteWuninitialized(Formatter& format) {
+  format(
+      "#if defined(__llvm__)\n"
+      "  #pragma clang diagnostic pop\n"
+      "#endif  // __llvm__\n");
+}
+
+}  // namespace
+
+FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
+    : file_(file), options_(options), scc_analyzer_(options) {
+  // These variables are the same on a file level
+  SetCommonVars(options, &variables_);
+  variables_["dllexport_decl"] = options.dllexport_decl;
+  variables_["tablename"] = UniqueName("TableStruct", file_, options_);
+  variables_["file_level_metadata"] =
+      UniqueName("file_level_metadata", file_, options_);
+  variables_["desc_table"] = DescriptorTableName(file_, options_);
+  variables_["file_level_enum_descriptors"] =
+      UniqueName("file_level_enum_descriptors", file_, options_);
+  variables_["file_level_service_descriptors"] =
+      UniqueName("file_level_service_descriptors", file_, options_);
+  variables_["filename"] = file_->name();
+  variables_["package_ns"] = Namespace(file_, options);
+
+  std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file);
+  for (int i = 0; i < msgs.size(); i++) {
+    // Deleted in destructor
+    MessageGenerator* msg_gen =
+        new MessageGenerator(msgs[i], variables_, i, options, &scc_analyzer_);
+    message_generators_.emplace_back(msg_gen);
+    msg_gen->AddGenerators(&enum_generators_, &extension_generators_);
+  }
+
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    enum_generators_.emplace_back(
+        new EnumGenerator(file->enum_type(i), variables_, options));
+  }
+
+  for (int i = 0; i < file->service_count(); i++) {
+    service_generators_.emplace_back(
+        new ServiceGenerator(file->service(i), variables_, options));
+  }
+  if (HasGenericServices(file_, options_)) {
+    for (int i = 0; i < service_generators_.size(); i++) {
+      service_generators_[i]->index_in_metadata_ = i;
+    }
+  }
+  for (int i = 0; i < file->extension_count(); i++) {
+    extension_generators_.emplace_back(
+        new ExtensionGenerator(file->extension(i), options, &scc_analyzer_));
+  }
+  for (int i = 0; i < file->weak_dependency_count(); ++i) {
+    weak_deps_.insert(file->weak_dependency(i));
+  }
+}
+
+FileGenerator::~FileGenerator() = default;
+
+void FileGenerator::GenerateMacroUndefs(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  // Only do this for protobuf's own types. There are some google3 protos using
+  // macros as field names and the generated code compiles after the macro
+  // expansion. Undefing these macros actually breaks such code.
+  if (file_->name() != "net/proto2/compiler/proto/plugin.proto" &&
+      file_->name() != "google/protobuf/compiler/plugin.proto") {
+    return;
+  }
+  std::vector<std::string> names_to_undef;
+  std::vector<const FieldDescriptor*> fields;
+  ListAllFields(file_, &fields);
+  for (int i = 0; i < fields.size(); i++) {
+    const std::string& name = fields[i]->name();
+    static const char* kMacroNames[] = {"major", "minor"};
+    for (int j = 0; j < GOOGLE_ARRAYSIZE(kMacroNames); ++j) {
+      if (name == kMacroNames[j]) {
+        names_to_undef.push_back(name);
+        break;
+      }
+    }
+  }
+  for (int i = 0; i < names_to_undef.size(); ++i) {
+    format(
+        "#ifdef $1$\n"
+        "#undef $1$\n"
+        "#endif\n",
+        names_to_undef[i]);
+  }
+}
+
+void FileGenerator::GenerateHeader(io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  // port_def.inc must be included after all other includes.
+  IncludeFile("net/proto2/public/port_def.inc", printer);
+  format("#define $1$$ dllexport_decl$\n", FileDllExport(file_, options_));
+  GenerateMacroUndefs(printer);
+
+  // For Any support with lite protos, we need to friend AnyMetadata, so we
+  // forward-declare it here.
+  format(
+      "PROTOBUF_NAMESPACE_OPEN\n"
+      "namespace internal {\n"
+      "class AnyMetadata;\n"
+      "}  // namespace internal\n"
+      "PROTOBUF_NAMESPACE_CLOSE\n");
+
+  GenerateGlobalStateFunctionDeclarations(printer);
+
+  GenerateForwardDeclarations(printer);
+
+  {
+    NamespaceOpener ns(Namespace(file_, options_), format);
+
+    format("\n");
+
+    GenerateEnumDefinitions(printer);
+
+    format(kThickSeparator);
+    format("\n");
+
+    GenerateMessageDefinitions(printer);
+
+    format("\n");
+    format(kThickSeparator);
+    format("\n");
+
+    GenerateServiceDefinitions(printer);
+
+    GenerateExtensionIdentifiers(printer);
+
+    format("\n");
+    format(kThickSeparator);
+    format("\n");
+
+    GenerateInlineFunctionDefinitions(printer);
+
+    format(
+        "\n"
+        "// @@protoc_insertion_point(namespace_scope)\n"
+        "\n");
+  }
+
+  // We need to specialize some templates in the ::google::protobuf namespace:
+  GenerateProto2NamespaceEnumSpecializations(printer);
+
+  format(
+      "\n"
+      "// @@protoc_insertion_point(global_scope)\n"
+      "\n");
+  IncludeFile("net/proto2/public/port_undef.inc", printer);
+}
+
+void FileGenerator::GenerateProtoHeader(io::Printer* printer,
+                                        const std::string& info_path) {
+  Formatter format(printer, variables_);
+  if (!options_.proto_h) {
+    return;
+  }
+
+  GenerateTopHeaderGuard(printer, false);
+
+  if (!options_.opensource_runtime) {
+    format(
+        "#ifdef SWIG\n"
+        "#error \"Do not SWIG-wrap protobufs.\"\n"
+        "#endif  // SWIG\n"
+        "\n");
+  }
+
+  if (IsBootstrapProto(options_, file_)) {
+    format("// IWYU pragma: private, include \"$1$.proto.h\"\n\n",
+           StripProto(file_->name()));
+  }
+
+  GenerateLibraryIncludes(printer);
+
+  for (int i = 0; i < file_->public_dependency_count(); i++) {
+    const FileDescriptor* dep = file_->public_dependency(i);
+    format("#include \"$1$.proto.h\"\n", StripProto(dep->name()));
+  }
+
+  format("// @@protoc_insertion_point(includes)\n");
+
+  GenerateMetadataPragma(printer, info_path);
+
+  GenerateHeader(printer);
+
+  GenerateBottomHeaderGuard(printer, false);
+}
+
+void FileGenerator::GeneratePBHeader(io::Printer* printer,
+                                     const std::string& info_path) {
+  Formatter format(printer, variables_);
+  GenerateTopHeaderGuard(printer, true);
+
+  if (options_.proto_h) {
+    std::string target_basename = StripProto(file_->name());
+    if (!options_.opensource_runtime) {
+      GetBootstrapBasename(options_, target_basename, &target_basename);
+    }
+    format("#include \"$1$.proto.h\"  // IWYU pragma: export\n",
+           target_basename);
+  } else {
+    GenerateLibraryIncludes(printer);
+  }
+
+  if (options_.transitive_pb_h) {
+    GenerateDependencyIncludes(printer);
+  }
+
+  // This is unfortunately necessary for some plugins. I don't see why we
+  // need two of the same insertion points.
+  // TODO(gerbens) remove this.
+  format("// @@protoc_insertion_point(includes)\n");
+
+  GenerateMetadataPragma(printer, info_path);
+
+  if (!options_.proto_h) {
+    GenerateHeader(printer);
+  } else {
+    {
+      NamespaceOpener ns(Namespace(file_, options_), format);
+      format(
+          "\n"
+          "// @@protoc_insertion_point(namespace_scope)\n");
+    }
+    format(
+        "\n"
+        "// @@protoc_insertion_point(global_scope)\n"
+        "\n");
+  }
+
+  GenerateBottomHeaderGuard(printer, true);
+}
+
+void FileGenerator::DoIncludeFile(const std::string& google3_name,
+                                  bool do_export, io::Printer* printer) {
+  Formatter format(printer, variables_);
+  const std::string prefix = "net/proto2/";
+  GOOGLE_CHECK(google3_name.find(prefix) == 0) << google3_name;
+
+  if (options_.opensource_runtime) {
+    std::string path = google3_name.substr(prefix.size());
+
+    path = StringReplace(path, "internal/", "", false);
+    path = StringReplace(path, "proto/", "", false);
+    path = StringReplace(path, "public/", "", false);
+    if (options_.runtime_include_base.empty()) {
+      format("#include <google/protobuf/$1$>", path);
+    } else {
+      format("#include \"$1$google/protobuf/$2$\"",
+             options_.runtime_include_base, path);
+    }
+  } else {
+    std::string path = google3_name;
+    // The bootstrapped proto generated code needs to use the
+    // third_party/protobuf header paths to avoid circular dependencies.
+    if (options_.bootstrap) {
+      path = StringReplace(google3_name, "net/proto2/public",
+                           "third_party/protobuf", false);
+    }
+    format("#include \"$1$\"", path);
+  }
+
+  if (do_export) {
+    format("  // IWYU pragma: export");
+  }
+
+  format("\n");
+}
+
+std::string FileGenerator::CreateHeaderInclude(const std::string& basename,
+                                               const FileDescriptor* file) {
+  bool use_system_include = false;
+  std::string name = basename;
+
+  if (options_.opensource_runtime) {
+    if (IsWellKnownMessage(file)) {
+      if (options_.runtime_include_base.empty()) {
+        use_system_include = true;
+      } else {
+        name = options_.runtime_include_base + basename;
+      }
+    }
+  }
+
+  std::string left = "\"";
+  std::string right = "\"";
+  if (use_system_include) {
+    left = "<";
+    right = ">";
+  }
+  return left + name + right;
+}
+
+void FileGenerator::GenerateSourceIncludes(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  std::string target_basename = StripProto(file_->name());
+  if (!options_.opensource_runtime) {
+    GetBootstrapBasename(options_, target_basename, &target_basename);
+  }
+  target_basename += options_.proto_h ? ".proto.h" : ".pb.h";
+  format(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n"
+      "#include $1$\n"
+      "\n"
+      "#include <algorithm>\n"  // for swap()
+      "\n",
+      CreateHeaderInclude(target_basename, file_));
+
+  IncludeFile("net/proto2/io/public/coded_stream.h", printer);
+  // TODO(gerbens) This is to include parse_context.h, we need a better way
+  IncludeFile("net/proto2/public/extension_set.h", printer);
+  IncludeFile("net/proto2/public/wire_format_lite.h", printer);
+
+  // Unknown fields implementation in lite mode uses StringOutputStream
+  if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) {
+    IncludeFile("net/proto2/io/public/zero_copy_stream_impl_lite.h", printer);
+  }
+
+  if (HasDescriptorMethods(file_, options_)) {
+    IncludeFile("net/proto2/public/descriptor.h", printer);
+    IncludeFile("net/proto2/public/generated_message_reflection.h", printer);
+    IncludeFile("net/proto2/public/reflection_ops.h", printer);
+    IncludeFile("net/proto2/public/wire_format.h", printer);
+  }
+
+  if (HasGeneratedMethods(file_, options_) &&
+      options_.tctable_mode != Options::kTCTableNever) {
+    IncludeFile("net/proto2/public/generated_message_tctable_impl.h", printer);
+  }
+
+  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);
+      // Do not import weak deps.
+      if (!options_.opensource_runtime && IsDepWeak(dep)) continue;
+      std::string basename = StripProto(dep->name());
+      if (IsBootstrapProto(options_, file_)) {
+        GetBootstrapBasename(options_, basename, &basename);
+      }
+      format("#include \"$1$.proto.h\"\n", basename);
+    }
+  }
+  if (HasCordFields(file_, options_)) {
+    format(
+        "#include \"third_party/absl/strings/internal/string_constant.h\"\n");
+  }
+
+  format("// @@protoc_insertion_point(includes)\n");
+  IncludeFile("net/proto2/public/port_def.inc", printer);
+}
+
+void FileGenerator::GenerateSourcePrelude(io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  // For MSVC builds, we use #pragma init_seg to move the initialization of our
+  // libraries to happen before the user code.
+  // This worksaround the fact that MSVC does not do constant initializers when
+  // required by the standard.
+  format("\nPROTOBUF_PRAGMA_INIT_SEG\n");
+
+  // Generate convenience aliases.
+  format(
+      "\n"
+      "namespace _pb = ::$1$;\n"
+      "namespace _pbi = _pb::internal;\n",
+      ProtobufNamespace(options_));
+  if (HasGeneratedMethods(file_, options_) &&
+      options_.tctable_mode != Options::kTCTableNever) {
+    format("namespace _fl = _pbi::field_layout;\n");
+  }
+  format("\n");
+}
+
+void FileGenerator::GenerateSourceDefaultInstance(int idx,
+                                                  io::Printer* printer) {
+  Formatter format(printer, variables_);
+  MessageGenerator* generator = message_generators_[idx].get();
+  // Generate the split instance first because it's needed in the constexpr
+  // constructor.
+  if (ShouldSplit(generator->descriptor_, options_)) {
+    // Use a union to disable the destructor of the _instance member.
+    // We can constant initialize, but the object will still have a non-trivial
+    // destructor that we need to elide.
+    format(
+        "struct $1$ {\n"
+        "  PROTOBUF_CONSTEXPR $1$()\n"
+        "      : _instance{",
+        DefaultInstanceType(generator->descriptor_, options_,
+                            /*split=*/true));
+    generator->GenerateInitDefaultSplitInstance(printer);
+    format(
+        "} {}\n"
+        "  ~$1$() {}\n"
+        "  union {\n"
+        "    $2$ _instance;\n"
+        "  };\n"
+        "};\n",
+        DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
+        StrCat(generator->classname_, "::Impl_::Split"));
+    // NO_DESTROY is not necessary for correctness. The empty destructor is
+    // enough. However, the empty destructor fails to be elided in some
+    // configurations (like non-opt or with certain sanitizers). NO_DESTROY is
+    // there just to improve performance and binary size in these builds.
+    format(
+        "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
+        "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
+        DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
+        DefaultInstanceName(generator->descriptor_, options_, /*split=*/true));
+  }
+
+  generator->GenerateConstexprConstructor(printer);
+  format(
+      "struct $1$ {\n"
+      "  PROTOBUF_CONSTEXPR $1$()\n"
+      "      : _instance(::_pbi::ConstantInitialized{}) {}\n"
+      "  ~$1$() {}\n"
+      "  union {\n"
+      "    $2$ _instance;\n"
+      "  };\n"
+      "};\n",
+      DefaultInstanceType(generator->descriptor_, options_),
+      generator->classname_);
+  format(
+      "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
+      "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
+      DefaultInstanceType(generator->descriptor_, options_),
+      DefaultInstanceName(generator->descriptor_, options_));
+
+  for (int i = 0; i < generator->descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = generator->descriptor_->field(i);
+    if (IsStringInlined(field, options_)) {
+      // Force the initialization of the inlined string in the default instance.
+      format(
+          "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type "
+          "$1$::Impl_::_init_inline_$2$_ = "
+          "($3$._instance.$4$.Init(), std::true_type{});\n",
+          ClassName(generator->descriptor_), FieldName(field),
+          DefaultInstanceName(generator->descriptor_, options_),
+          FieldMemberName(field, ShouldSplit(field, options_)));
+    }
+  }
+
+  if (options_.lite_implicit_weak_fields) {
+    format(
+        "PROTOBUF_CONSTINIT const void* $1$ =\n"
+        "    &$2$;\n",
+        DefaultInstancePtr(generator->descriptor_, options_),
+        DefaultInstanceName(generator->descriptor_, options_));
+  }
+}
+
+// A list of things defined in one .pb.cc file that we need to reference from
+// another .pb.cc file.
+struct FileGenerator::CrossFileReferences {
+  // Populated if we are referencing from messages or files.
+  std::unordered_set<const Descriptor*> weak_default_instances;
+
+  // Only if we are referencing from files.
+  std::unordered_set<const FileDescriptor*> strong_reflection_files;
+  std::unordered_set<const FileDescriptor*> weak_reflection_files;
+};
+
+void FileGenerator::GetCrossFileReferencesForField(const FieldDescriptor* field,
+                                                   CrossFileReferences* refs) {
+  const Descriptor* msg = field->message_type();
+  if (msg == nullptr) return;
+
+  if (IsImplicitWeakField(field, options_, &scc_analyzer_) ||
+      IsWeak(field, options_)) {
+    refs->weak_default_instances.insert(msg);
+  }
+}
+
+void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file,
+                                                  CrossFileReferences* refs) {
+  ForEachField(file, [this, refs](const FieldDescriptor* field) {
+    GetCrossFileReferencesForField(field, refs);
+  });
+
+  if (!HasDescriptorMethods(file, options_)) return;
+
+  for (int i = 0; i < file->dependency_count(); i++) {
+    const FileDescriptor* dep = file->dependency(i);
+    if (IsDepWeak(dep)) {
+      refs->weak_reflection_files.insert(dep);
+    } else {
+      refs->strong_reflection_files.insert(dep);
+    }
+  }
+}
+
+// Generates references to variables defined in other files.
+void FileGenerator::GenerateInternalForwardDeclarations(
+    const CrossFileReferences& refs, io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  {
+    NamespaceOpener ns(format);
+    for (auto instance : Sorted(refs.weak_default_instances)) {
+      ns.ChangeTo(Namespace(instance, options_));
+      if (options_.lite_implicit_weak_fields) {
+        format(
+            "PROTOBUF_CONSTINIT __attribute__((weak)) const void* $1$ =\n"
+            "    &::_pbi::implicit_weak_message_default_instance;\n",
+            DefaultInstancePtr(instance, options_));
+      } else {
+        format("extern __attribute__((weak)) $1$ $2$;\n",
+               DefaultInstanceType(instance, options_),
+               DefaultInstanceName(instance, options_));
+      }
+    }
+  }
+
+  for (auto file : Sorted(refs.weak_reflection_files)) {
+    format(
+        "extern __attribute__((weak)) const ::_pbi::DescriptorTable $1$;\n",
+        DescriptorTableName(file, options_));
+  }
+}
+
+void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
+  Formatter format(printer, variables_);
+  GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
+
+  if (IsAnyMessage(file_, options_)) MuteWuninitialized(format);
+
+  CrossFileReferences refs;
+  ForEachField(message_generators_[idx]->descriptor_,
+               [this, &refs](const FieldDescriptor* field) {
+                 GetCrossFileReferencesForField(field, &refs);
+               });
+  GenerateInternalForwardDeclarations(refs, printer);
+
+  {  // package namespace
+    NamespaceOpener ns(Namespace(file_, options_), format);
+
+    // Define default instances
+    GenerateSourceDefaultInstance(idx, printer);
+
+    // Generate classes.
+    format("\n");
+    message_generators_[idx]->GenerateClassMethods(printer);
+
+    format(
+        "\n"
+        "// @@protoc_insertion_point(namespace_scope)\n");
+  }  // end package namespace
+
+  {
+    NamespaceOpener proto_ns(ProtobufNamespace(options_), format);
+    message_generators_[idx]->GenerateSourceInProto2Namespace(printer);
+  }
+
+  if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format);
+
+  format(
+      "\n"
+      "// @@protoc_insertion_point(global_scope)\n");
+}
+
+void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) {
+  Formatter format(printer, variables_);
+  GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
+  NamespaceOpener ns(Namespace(file_, options_), format);
+  extension_generators_[idx]->GenerateDefinition(printer);
+}
+
+void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
+
+  {
+    // Define the code to initialize reflection. This code uses a global
+    // constructor to register reflection data with the runtime pre-main.
+    if (HasDescriptorMethods(file_, options_)) {
+      GenerateReflectionInitializationCode(printer);
+    }
+  }
+
+  NamespaceOpener ns(Namespace(file_, options_), format);
+
+  // Generate enums.
+  for (int i = 0; i < enum_generators_.size(); i++) {
+    enum_generators_[i]->GenerateMethods(i, printer);
+  }
+}
+
+void FileGenerator::GenerateSource(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
+  CrossFileReferences refs;
+  GetCrossFileReferencesForFile(file_, &refs);
+  GenerateInternalForwardDeclarations(refs, printer);
+
+  if (IsAnyMessage(file_, options_)) MuteWuninitialized(format);
+
+  {
+    NamespaceOpener ns(Namespace(file_, options_), format);
+
+    // Define default instances
+    for (int i = 0; i < message_generators_.size(); i++) {
+      GenerateSourceDefaultInstance(i, printer);
+    }
+  }
+
+  {
+    if (HasDescriptorMethods(file_, options_)) {
+      // Define the code to initialize reflection. This code uses a global
+      // constructor to register reflection data with the runtime pre-main.
+      GenerateReflectionInitializationCode(printer);
+    }
+  }
+
+  {
+    NamespaceOpener ns(Namespace(file_, options_), format);
+
+    // Actually implement the protos
+
+    // Generate enums.
+    for (int i = 0; i < enum_generators_.size(); i++) {
+      enum_generators_[i]->GenerateMethods(i, printer);
+    }
+
+    // Generate classes.
+    for (int i = 0; i < message_generators_.size(); i++) {
+      format("\n");
+      format(kThickSeparator);
+      format("\n");
+      message_generators_[i]->GenerateClassMethods(printer);
+    }
+
+    if (HasGenericServices(file_, options_)) {
+      // Generate services.
+      for (int i = 0; i < service_generators_.size(); i++) {
+        if (i == 0) format("\n");
+        format(kThickSeparator);
+        format("\n");
+        service_generators_[i]->GenerateImplementation(printer);
+      }
+    }
+
+    // Define extensions.
+    for (int i = 0; i < extension_generators_.size(); i++) {
+      extension_generators_[i]->GenerateDefinition(printer);
+    }
+
+    format(
+        "\n"
+        "// @@protoc_insertion_point(namespace_scope)\n");
+  }
+
+  {
+    NamespaceOpener proto_ns(ProtobufNamespace(options_), format);
+    for (int i = 0; i < message_generators_.size(); i++) {
+      message_generators_[i]->GenerateSourceInProto2Namespace(printer);
+    }
+  }
+
+  format(
+      "\n"
+      "// @@protoc_insertion_point(global_scope)\n");
+
+  if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format);
+
+  IncludeFile("net/proto2/public/port_undef.inc", printer);
+}
+
+void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  if (!message_generators_.empty()) {
+    format("static ::_pb::Metadata $file_level_metadata$[$1$];\n",
+           message_generators_.size());
+  }
+  if (!enum_generators_.empty()) {
+    format(
+        "static const ::_pb::EnumDescriptor* "
+        "$file_level_enum_descriptors$[$1$];\n",
+        enum_generators_.size());
+  } else {
+    format(
+        "static "
+        "constexpr ::_pb::EnumDescriptor const** "
+        "$file_level_enum_descriptors$ = nullptr;\n");
+  }
+  if (HasGenericServices(file_, options_) && file_->service_count() > 0) {
+    format(
+        "static "
+        "const ::_pb::ServiceDescriptor* "
+        "$file_level_service_descriptors$[$1$];\n",
+        file_->service_count());
+  } else {
+    format(
+        "static "
+        "constexpr ::_pb::ServiceDescriptor const** "
+        "$file_level_service_descriptors$ = nullptr;\n");
+  }
+
+  if (!message_generators_.empty()) {
+    format(
+        "\n"
+        "const $uint32$ $tablename$::offsets[] "
+        "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
+    format.Indent();
+    std::vector<std::pair<size_t, size_t> > pairs;
+    pairs.reserve(message_generators_.size());
+    for (int i = 0; i < message_generators_.size(); i++) {
+      pairs.push_back(message_generators_[i]->GenerateOffsets(printer));
+    }
+    format.Outdent();
+    format(
+        "};\n"
+        "static const ::_pbi::MigrationSchema schemas[] "
+        "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
+    format.Indent();
+    {
+      int offset = 0;
+      for (int i = 0; i < message_generators_.size(); i++) {
+        message_generators_[i]->GenerateSchema(printer, offset,
+                                               pairs[i].second);
+        offset += pairs[i].first;
+      }
+    }
+    format.Outdent();
+    format(
+        "};\n"
+        "\nstatic const ::_pb::Message* const file_default_instances[] = {\n");
+    format.Indent();
+    for (int i = 0; i < message_generators_.size(); i++) {
+      const Descriptor* descriptor = message_generators_[i]->descriptor_;
+      format("&$1$::_$2$_default_instance_._instance,\n",
+             Namespace(descriptor, options_),  // 1
+             ClassName(descriptor));           // 2
+    }
+    format.Outdent();
+    format(
+        "};\n"
+        "\n");
+  } else {
+    // we still need these symbols to exist
+    format(
+        // MSVC doesn't like empty arrays, so we add a dummy.
+        "const $uint32$ $tablename$::offsets[1] = {};\n"
+        "static constexpr ::_pbi::MigrationSchema* schemas = nullptr;\n"
+        "static constexpr ::_pb::Message* const* "
+        "file_default_instances = nullptr;\n"
+        "\n");
+  }
+
+  // ---------------------------------------------------------------
+
+  // Embed the descriptor.  We simply serialize the entire
+  // FileDescriptorProto/ and embed it as a string literal, which is parsed and
+  // built into real descriptors at initialization time.
+  const std::string protodef_name =
+      UniqueName("descriptor_table_protodef", file_, options_);
+  format("const char $1$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =\n",
+         protodef_name);
+  format.Indent();
+  FileDescriptorProto file_proto;
+  file_->CopyTo(&file_proto);
+  std::string file_data;
+  file_proto.SerializeToString(&file_data);
+
+  {
+    if (file_data.size() > 65535) {
+      // Workaround for MSVC: "Error C1091: compiler limit: string exceeds
+      // 65535 bytes in length". Declare a static array of chars rather than
+      // use a string literal. Only write 25 bytes per line.
+      static const int kBytesPerLine = 25;
+      format("{ ");
+      for (int i = 0; i < file_data.size();) {
+        for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
+          format("'$1$', ", CEscape(file_data.substr(i, 1)));
+        }
+        format("\n");
+      }
+      format("'\\0' }");  // null-terminate
+    } else {
+      // Only write 40 bytes per line.
+      static const int kBytesPerLine = 40;
+      for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+        format(
+            "\"$1$\"\n",
+            EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+      }
+    }
+    format(";\n");
+  }
+  format.Outdent();
+
+  CrossFileReferences refs;
+  GetCrossFileReferencesForFile(file_, &refs);
+  int num_deps =
+      refs.strong_reflection_files.size() + refs.weak_reflection_files.size();
+
+  // Build array of DescriptorTable deps.
+  if (num_deps > 0) {
+    format(
+        "static const ::_pbi::DescriptorTable* const "
+        "$desc_table$_deps[$1$] = {\n",
+        num_deps);
+
+    for (auto dep : Sorted(refs.strong_reflection_files)) {
+      format("  &::$1$,\n", DescriptorTableName(dep, options_));
+    }
+    for (auto dep : Sorted(refs.weak_reflection_files)) {
+      format("  &::$1$,\n", DescriptorTableName(dep, options_));
+    }
+
+    format("};\n");
+  }
+
+  // The DescriptorTable itself.
+  // Should be "bool eager = NeedsEagerDescriptorAssignment(file_, options_);"
+  // however this might cause a tsan failure in superroot b/148382879,
+  // so disable for now.
+  bool eager = false;
+  format(
+      "static ::_pbi::once_flag $desc_table$_once;\n"
+      "const ::_pbi::DescriptorTable $desc_table$ = {\n"
+      "    false, $1$, $2$, $3$,\n"
+      "    \"$filename$\",\n"
+      "    &$desc_table$_once, $4$, $5$, $6$,\n"
+      "    schemas, file_default_instances, $tablename$::offsets,\n"
+      "    $7$, $file_level_enum_descriptors$,\n"
+      "    $file_level_service_descriptors$,\n"
+      "};\n"
+      // This function exists to be marked as weak.
+      // It can significantly speed up compilation by breaking up LLVM's SCC in
+      // the .pb.cc translation units. Large translation units see a reduction
+      // of more than 35% of walltime for optimized builds.
+      // Without the weak attribute all the messages in the file, including all
+      // the vtables and everything they use become part of the same SCC through
+      // a cycle like:
+      // GetMetadata -> descriptor table -> default instances ->
+      //   vtables -> GetMetadata
+      // By adding a weak function here we break the connection from the
+      // individual vtables back into the descriptor table.
+      "PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* "
+      "$desc_table$_getter() {\n"
+      "  return &$desc_table$;\n"
+      "}\n"
+      "\n",
+      eager ? "true" : "false", file_data.size(), protodef_name,
+      num_deps == 0 ? "nullptr" : variables_["desc_table"] + "_deps", num_deps,
+      message_generators_.size(),
+      message_generators_.empty() ? "nullptr"
+                                  : variables_["file_level_metadata"]);
+
+  // For descriptor.proto we want to avoid doing any dynamic initialization,
+  // because in some situations that would otherwise pull in a lot of
+  // unnecessary code that can't be stripped by --gc-sections. Descriptor
+  // initialization will still be performed lazily when it's needed.
+  if (file_->name() != "net/proto2/proto/descriptor.proto") {
+    format(
+        "// Force running AddDescriptors() at dynamic initialization time.\n"
+        "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 "
+        "static ::_pbi::AddDescriptorsRunner $1$(&$desc_table$);\n",
+        UniqueName("dynamic_init_dummy", file_, options_));
+  }
+}
+
+class FileGenerator::ForwardDeclarations {
+ public:
+  void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; }
+  void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; }
+  void AddSplit(const Descriptor* d) { splits_[ClassName(d)] = d; }
+
+  void Print(const Formatter& format, const Options& options) const {
+    for (const auto& p : enums_) {
+      const std::string& enumname = p.first;
+      const EnumDescriptor* enum_desc = p.second;
+      format(
+          "enum ${1$$2$$}$ : int;\n"
+          "bool $2$_IsValid(int value);\n",
+          enum_desc, enumname);
+    }
+    for (const auto& p : classes_) {
+      const std::string& classname = p.first;
+      const Descriptor* class_desc = p.second;
+      format(
+          "class ${1$$2$$}$;\n"
+          "struct $3$;\n"
+          "$dllexport_decl $extern $3$ $4$;\n",
+          class_desc, classname, DefaultInstanceType(class_desc, options),
+          DefaultInstanceName(class_desc, options));
+    }
+    for (const auto& p : splits_) {
+      const Descriptor* class_desc = p.second;
+      format(
+          "struct $1$;\n"
+          "$dllexport_decl $extern $1$ $2$;\n",
+          DefaultInstanceType(class_desc, options, /*split=*/true),
+          DefaultInstanceName(class_desc, options, /*split=*/true));
+    }
+  }
+
+  void PrintTopLevelDecl(const Formatter& format,
+                         const Options& options) const {
+    for (const auto& pair : classes_) {
+      format(
+          "template<> $dllexport_decl $"
+          "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n",
+          QualifiedClassName(pair.second, options));
+    }
+  }
+
+ private:
+  std::map<std::string, const Descriptor*> classes_;
+  std::map<std::string, const EnumDescriptor*> enums_;
+  std::map<std::string, const Descriptor*> splits_;
+};
+
+static void PublicImportDFS(const FileDescriptor* fd,
+                            std::unordered_set<const FileDescriptor*>* fd_set) {
+  for (int i = 0; i < fd->public_dependency_count(); i++) {
+    const FileDescriptor* dep = fd->public_dependency(i);
+    if (fd_set->insert(dep).second) PublicImportDFS(dep, fd_set);
+  }
+}
+
+void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  std::vector<const Descriptor*> classes;
+  std::vector<const EnumDescriptor*> enums;
+
+  FlattenMessagesInFile(file_, &classes);  // All messages need forward decls.
+
+  if (options_.proto_h) {  // proto.h needs extra forward declarations.
+    // All classes / enums referred to as field members
+    std::vector<const FieldDescriptor*> fields;
+    ListAllFields(file_, &fields);
+    for (int i = 0; i < fields.size(); i++) {
+      classes.push_back(fields[i]->containing_type());
+      classes.push_back(fields[i]->message_type());
+      enums.push_back(fields[i]->enum_type());
+    }
+    ListAllTypesForServices(file_, &classes);
+  }
+
+  // Calculate the set of files whose definitions we get through include.
+  // No need to forward declare types that are defined in these.
+  std::unordered_set<const FileDescriptor*> public_set;
+  PublicImportDFS(file_, &public_set);
+
+  std::map<std::string, ForwardDeclarations> decls;
+  for (int i = 0; i < classes.size(); i++) {
+    const Descriptor* d = classes[i];
+    if (d && !public_set.count(d->file()))
+      decls[Namespace(d, options_)].AddMessage(d);
+  }
+  for (int i = 0; i < enums.size(); i++) {
+    const EnumDescriptor* d = enums[i];
+    if (d && !public_set.count(d->file()))
+      decls[Namespace(d, options_)].AddEnum(d);
+  }
+  for (const auto& mg : message_generators_) {
+    const Descriptor* d = mg->descriptor_;
+    if ((d != nullptr) && (public_set.count(d->file()) == 0u) &&
+        ShouldSplit(mg->descriptor_, options_))
+      decls[Namespace(d, options_)].AddSplit(d);
+  }
+
+  {
+    NamespaceOpener ns(format);
+    for (const auto& pair : decls) {
+      ns.ChangeTo(pair.first);
+      pair.second.Print(format, options_);
+    }
+  }
+  format("PROTOBUF_NAMESPACE_OPEN\n");
+  for (const auto& pair : decls) {
+    pair.second.PrintTopLevelDecl(format, options_);
+  }
+  format("PROTOBUF_NAMESPACE_CLOSE\n");
+}
+
+void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, bool pb_h) {
+  Formatter format(printer, variables_);
+  // Generate top of header.
+  format(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n"
+      "#ifndef $1$\n"
+      "#define $1$\n"
+      "\n"
+      "#include <limits>\n"
+      "#include <string>\n",
+      IncludeGuard(file_, pb_h, options_));
+  if (!options_.opensource_runtime && !enum_generators_.empty()) {
+    // Add header to provide std::is_integral for safe Enum_Name() function.
+    format("#include <type_traits>\n");
+  }
+  format("\n");
+}
+
+void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h) {
+  Formatter format(printer, variables_);
+  format("#endif  // $GOOGLE_PROTOBUF$_INCLUDED_$1$\n",
+         IncludeGuard(file_, pb_h, options_));
+}
+
+void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (UsingImplicitWeakFields(file_, options_)) {
+    IncludeFile("net/proto2/public/implicit_weak_message.h", printer);
+  }
+  if (HasWeakFields(file_, options_)) {
+    GOOGLE_CHECK(!options_.opensource_runtime);
+    IncludeFile("net/proto2/public/weak_field_map.h", printer);
+  }
+  if (HasLazyFields(file_, options_, &scc_analyzer_)) {
+    GOOGLE_CHECK(!options_.opensource_runtime);
+    IncludeFile("net/proto2/public/lazy_field.h", printer);
+  }
+  if (ShouldVerify(file_, options_, &scc_analyzer_)) {
+    IncludeFile("net/proto2/public/wire_format_verify.h", printer);
+  }
+
+  if (options_.opensource_runtime) {
+    // Verify the protobuf library header version is compatible with the protoc
+    // version before going any further.
+    IncludeFile("net/proto2/public/port_def.inc", printer);
+    format(
+        "#if PROTOBUF_VERSION < $1$\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 $2$ < 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",
+        PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC,  // 1
+        PROTOBUF_VERSION);                       // 2
+    IncludeFile("net/proto2/public/port_undef.inc", printer);
+  }
+
+  // OK, it's now safe to #include other files.
+  IncludeFile("net/proto2/io/public/coded_stream.h", printer);
+  IncludeFile("net/proto2/public/arena.h", printer);
+  IncludeFile("net/proto2/public/arenastring.h", printer);
+  if ((options_.force_inline_string || options_.profile_driven_inline_string) &&
+      !options_.opensource_runtime) {
+    IncludeFile("net/proto2/public/inlined_string_field.h", printer);
+  }
+  if (HasSimpleBaseClasses(file_, options_)) {
+    IncludeFile("net/proto2/public/generated_message_bases.h", printer);
+  }
+  if (HasGeneratedMethods(file_, options_) &&
+      options_.tctable_mode != Options::kTCTableNever) {
+    IncludeFile("net/proto2/public/generated_message_tctable_decl.h", printer);
+  }
+  IncludeFile("net/proto2/public/generated_message_util.h", printer);
+  IncludeFile("net/proto2/public/metadata_lite.h", printer);
+
+  if (HasDescriptorMethods(file_, options_)) {
+    IncludeFile("net/proto2/public/generated_message_reflection.h", printer);
+  }
+
+  if (!message_generators_.empty()) {
+    if (HasDescriptorMethods(file_, options_)) {
+      IncludeFile("net/proto2/public/message.h", printer);
+    } else {
+      IncludeFile("net/proto2/public/message_lite.h", printer);
+    }
+  }
+  if (options_.opensource_runtime) {
+    // Open-source relies on unconditional includes of these.
+    IncludeFileAndExport("net/proto2/public/repeated_field.h", printer);
+    IncludeFileAndExport("net/proto2/public/extension_set.h", printer);
+  } else {
+    // Google3 includes these files only when they are necessary.
+    if (HasExtensionsOrExtendableMessage(file_)) {
+      IncludeFileAndExport("net/proto2/public/extension_set.h", printer);
+    }
+    if (HasRepeatedFields(file_)) {
+      IncludeFileAndExport("net/proto2/public/repeated_field.h", printer);
+    }
+    if (HasStringPieceFields(file_, options_)) {
+      IncludeFile("net/proto2/public/string_piece_field_support.h", printer);
+    }
+    if (HasCordFields(file_, options_)) {
+      format("#include \"third_party/absl/strings/cord.h\"\n");
+    }
+  }
+  if (HasMapFields(file_)) {
+    IncludeFileAndExport("net/proto2/public/map.h", printer);
+    if (HasDescriptorMethods(file_, options_)) {
+      IncludeFile("net/proto2/public/map_entry.h", printer);
+      IncludeFile("net/proto2/public/map_field_inl.h", printer);
+    } else {
+      IncludeFile("net/proto2/public/map_entry_lite.h", printer);
+      IncludeFile("net/proto2/public/map_field_lite.h", printer);
+    }
+  }
+
+  if (HasEnumDefinitions(file_)) {
+    if (HasDescriptorMethods(file_, options_)) {
+      IncludeFile("net/proto2/public/generated_enum_reflection.h", printer);
+    } else {
+      IncludeFile("net/proto2/public/generated_enum_util.h", printer);
+    }
+  }
+
+  if (HasGenericServices(file_, options_)) {
+    IncludeFile("net/proto2/public/service.h", printer);
+  }
+
+  if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) {
+    IncludeFile("net/proto2/public/unknown_field_set.h", printer);
+  }
+}
+
+void FileGenerator::GenerateMetadataPragma(io::Printer* printer,
+                                           const std::string& info_path) {
+  Formatter format(printer, variables_);
+  if (!info_path.empty() && !options_.annotation_pragma_name.empty() &&
+      !options_.annotation_guard_name.empty()) {
+    format.Set("guard", options_.annotation_guard_name);
+    format.Set("pragma", options_.annotation_pragma_name);
+    format.Set("info_path", info_path);
+    format(
+        "#ifdef $guard$\n"
+        "#pragma $pragma$ \"$info_path$\"\n"
+        "#endif  // $guard$\n");
+  }
+}
+
+void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    std::string basename = StripProto(file_->dependency(i)->name());
+
+    // Do not import weak deps.
+    if (IsDepWeak(file_->dependency(i))) continue;
+
+    if (IsBootstrapProto(options_, file_)) {
+      GetBootstrapBasename(options_, basename, &basename);
+    }
+
+    format("#include $1$\n",
+           CreateHeaderInclude(basename + ".pb.h", file_->dependency(i)));
+  }
+}
+
+void FileGenerator::GenerateGlobalStateFunctionDeclarations(
+    io::Printer* printer) {
+  Formatter format(printer, variables_);
+  // Forward-declare the DescriptorTable because this is referenced by .pb.cc
+  // files depending on this file.
+  //
+  // The TableStruct is also outputted in weak_message_field.cc, because the
+  // weak fields must refer to table struct but cannot include the header.
+  // Also it annotates extra weak attributes.
+  // TODO(gerbens) make sure this situation is handled better.
+  format(
+      "\n"
+      "// Internal implementation detail -- do not use these members.\n"
+      "struct $dllexport_decl $$tablename$ {\n"
+      "  static const $uint32$ offsets[];\n"
+      "};\n");
+  if (HasDescriptorMethods(file_, options_)) {
+    format(
+        "$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable "
+        "$desc_table$;\n");
+  }
+}
+
+void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  // Generate class definitions.
+  for (int i = 0; i < message_generators_.size(); i++) {
+    if (i > 0) {
+      format("\n");
+      format(kThinSeparator);
+      format("\n");
+    }
+    message_generators_[i]->GenerateClassDefinition(printer);
+  }
+}
+
+void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) {
+  // Generate enum definitions.
+  for (int i = 0; i < enum_generators_.size(); i++) {
+    enum_generators_[i]->GenerateDefinition(printer);
+  }
+}
+
+void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (HasGenericServices(file_, options_)) {
+    // Generate service definitions.
+    for (int i = 0; i < service_generators_.size(); i++) {
+      if (i > 0) {
+        format("\n");
+        format(kThinSeparator);
+        format("\n");
+      }
+      service_generators_[i]->GenerateDeclarations(printer);
+    }
+
+    format("\n");
+    format(kThickSeparator);
+    format("\n");
+  }
+}
+
+void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
+  // Declare extension identifiers. These are in global scope and so only
+  // the global scope extensions.
+  for (auto& extension_generator : extension_generators_) {
+    if (extension_generator->IsScoped()) continue;
+    extension_generator->GenerateDeclaration(printer);
+  }
+}
+
+void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  // TODO(gerbens) remove pragmas when gcc is no longer used. Current version
+  // of gcc fires a bogus error when compiled with strict-aliasing.
+  format(
+      "#ifdef __GNUC__\n"
+      "  #pragma GCC diagnostic push\n"
+      "  #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n"
+      "#endif  // __GNUC__\n");
+  // Generate class inline methods.
+  for (int i = 0; i < message_generators_.size(); i++) {
+    if (i > 0) {
+      format(kThinSeparator);
+      format("\n");
+    }
+    message_generators_[i]->GenerateInlineMethods(printer);
+  }
+  format(
+      "#ifdef __GNUC__\n"
+      "  #pragma GCC diagnostic pop\n"
+      "#endif  // __GNUC__\n");
+
+  for (int i = 0; i < message_generators_.size(); i++) {
+    if (i > 0) {
+      format(kThinSeparator);
+      format("\n");
+    }
+  }
+}
+
+void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
+    io::Printer* printer) {
+  Formatter format(printer, variables_);
+  // Emit GetEnumDescriptor specializations into google::protobuf namespace:
+  if (HasEnumDefinitions(file_)) {
+    format("\n");
+    {
+      NamespaceOpener proto_ns(ProtobufNamespace(options_), format);
+      format("\n");
+      for (int i = 0; i < enum_generators_.size(); i++) {
+        enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+      }
+      format("\n");
+    }
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/file.h b/src/google/protobuf/compiler/cpp/file.h
new file mode 100644
index 0000000..ca05361
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/file.h
@@ -0,0 +1,209 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
+
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor;  // descriptor.h
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class EnumGenerator;       // enum.h
+class MessageGenerator;    // message.h
+class ServiceGenerator;    // service.h
+class ExtensionGenerator;  // extension.h
+
+class FileGenerator {
+ public:
+  // See generator.cc for the meaning of dllexport_decl.
+  FileGenerator(const FileDescriptor* file, const Options& options);
+  ~FileGenerator();
+
+  // Shared code between the two header generators below.
+  void GenerateHeader(io::Printer* printer);
+
+  // info_path, if non-empty, should be the path (relative to printer's
+  // output) to the metadata file describing this proto header.
+  void GenerateProtoHeader(io::Printer* printer, const std::string& info_path);
+  // info_path, if non-empty, should be the path (relative to printer's
+  // output) to the metadata file describing this PB header.
+  void GeneratePBHeader(io::Printer* printer, const std::string& info_path);
+  void GenerateSource(io::Printer* printer);
+
+  // The following member functions are used when the lite_implicit_weak_fields
+  // option is set. In this mode the code is organized a bit differently to
+  // promote better linker stripping of unused code. In particular, we generate
+  // one .cc file per message, one .cc file per extension, and a main pb.cc file
+  // containing everything else.
+
+  int NumMessages() const { return message_generators_.size(); }
+  int NumExtensions() const { return extension_generators_.size(); }
+  // Generates the source file for one message.
+  void GenerateSourceForMessage(int idx, io::Printer* printer);
+  // Generates the source file for one extension.
+  void GenerateSourceForExtension(int idx, io::Printer* printer);
+  // Generates a source file containing everything except messages and
+  // extensions.
+  void GenerateGlobalSource(io::Printer* printer);
+
+ private:
+  // Internal type used by GenerateForwardDeclarations (defined in file.cc).
+  class ForwardDeclarations;
+  struct CrossFileReferences;
+
+  void IncludeFile(const std::string& google3_name, io::Printer* printer) {
+    DoIncludeFile(google3_name, false, printer);
+  }
+  void IncludeFileAndExport(const std::string& google3_name,
+                            io::Printer* printer) {
+    DoIncludeFile(google3_name, true, printer);
+  }
+  void DoIncludeFile(const std::string& google3_name, bool do_export,
+                     io::Printer* printer);
+
+  std::string CreateHeaderInclude(const std::string& basename,
+                                  const FileDescriptor* file);
+  void GetCrossFileReferencesForField(const FieldDescriptor* field,
+                                      CrossFileReferences* refs);
+  void GetCrossFileReferencesForFile(const FileDescriptor* file,
+                                     CrossFileReferences* refs);
+  void GenerateInternalForwardDeclarations(const CrossFileReferences& refs,
+                                           io::Printer* printer);
+  void GenerateSourceIncludes(io::Printer* printer);
+  void GenerateSourcePrelude(io::Printer* printer);
+  void GenerateSourceDefaultInstance(int idx, io::Printer* printer);
+
+  void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs,
+                          io::Printer* printer);
+  void GenerateReflectionInitializationCode(io::Printer* printer);
+
+  // For other imports, generates their forward-declarations.
+  void GenerateForwardDeclarations(io::Printer* printer);
+
+  // Generates top or bottom of a header file.
+  void GenerateTopHeaderGuard(io::Printer* printer, bool pb_h);
+  void GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h);
+
+  // Generates #include directives.
+  void GenerateLibraryIncludes(io::Printer* printer);
+  void GenerateDependencyIncludes(io::Printer* printer);
+
+  // Generate a pragma to pull in metadata using the given info_path (if
+  // non-empty). info_path should be relative to printer's output.
+  void GenerateMetadataPragma(io::Printer* printer,
+                              const std::string& info_path);
+
+  // Generates a couple of different pieces before definitions:
+  void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
+
+  // Generates types for classes.
+  void GenerateMessageDefinitions(io::Printer* printer);
+
+  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 definitions.
+  void GenerateInlineFunctionDefinitions(io::Printer* printer);
+
+  void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer);
+
+  // Sometimes the names we use in a .proto file happen to be defined as
+  // macros on some platforms (e.g., macro/minor used in plugin.proto are
+  // defined as macros in sys/types.h on FreeBSD and a few other platforms).
+  // To make the generated code compile on these platforms, we either have to
+  // undef the macro for these few platforms, or rename the field name for all
+  // platforms. Since these names are part of protobuf public API, renaming is
+  // generally a breaking change so we prefer the #undef approach.
+  void GenerateMacroUndefs(io::Printer* printer);
+
+  bool IsDepWeak(const FileDescriptor* dep) const {
+    if (weak_deps_.count(dep) != 0) {
+      GOOGLE_CHECK(!options_.opensource_runtime);
+      return true;
+    }
+    return false;
+  }
+
+  std::set<const FileDescriptor*> weak_deps_;
+
+  const FileDescriptor* file_;
+  const Options options_;
+
+  MessageSCCAnalyzer scc_analyzer_;
+
+  std::map<std::string, std::string> variables_;
+
+  // Contains the post-order walk of all the messages (and child messages) in
+  // this file. If you need a pre-order walk just reverse iterate.
+  std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
+  std::vector<std::unique_ptr<EnumGenerator>> enum_generators_;
+  std::vector<std::unique_ptr<ServiceGenerator>> service_generators_;
+  std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
diff --git a/src/google/protobuf/compiler/cpp/generator.cc b/src/google/protobuf/compiler/cpp/generator.cc
new file mode 100644
index 0000000..63a2bce
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/generator.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/generator.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/compiler/cpp/file.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+CppGenerator::CppGenerator() {}
+CppGenerator::~CppGenerator() {}
+
+namespace {
+std::string NumberedCcFileName(const std::string& basename, int number) {
+  return StrCat(basename, ".out/", number, ".cc");
+}
+}  // namespace
+
+bool CppGenerator::Generate(const FileDescriptor* file,
+                            const std::string& parameter,
+                            GeneratorContext* generator_context,
+                            std::string* error) const {
+  std::vector<std::pair<std::string, std::string> > options;
+  ParseGeneratorParameter(parameter, &options);
+
+  // -----------------------------------------------------------------
+  // parse generator options
+
+  // If the dllexport_decl option is passed to the compiler, we need to write
+  // it in front of every symbol that should be exported if this .proto is
+  // compiled into a Windows DLL.  E.g., if the user invokes the protocol
+  // compiler as:
+  //   protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto
+  // then we'll define classes like this:
+  //   class FOO_EXPORT Foo {
+  //     ...
+  //   }
+  // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
+  // __declspec(dllimport) depending on what is being compiled.
+  //
+  // If the proto_h option is passed to the compiler, we will generate all
+  // classes and enums so that they can be forward-declared from files that
+  // need them from imports.
+  //
+  // If the lite option is passed to the compiler, we will generate the
+  // current files and all transitive dependencies using the LITE runtime.
+  Options file_options;
+
+  file_options.opensource_runtime = opensource_runtime_;
+  file_options.runtime_include_base = runtime_include_base_;
+
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "dllexport_decl") {
+      file_options.dllexport_decl = options[i].second;
+    } else if (options[i].first == "safe_boundary_check") {
+      file_options.safe_boundary_check = true;
+    } else if (options[i].first == "annotate_headers") {
+      file_options.annotate_headers = true;
+    } else if (options[i].first == "annotation_pragma_name") {
+      file_options.annotation_pragma_name = options[i].second;
+    } else if (options[i].first == "annotation_guard_name") {
+      file_options.annotation_guard_name = options[i].second;
+    } else if (options[i].first == "speed") {
+      file_options.enforce_mode = EnforceOptimizeMode::kSpeed;
+    } else if (options[i].first == "code_size") {
+      file_options.enforce_mode = EnforceOptimizeMode::kCodeSize;
+    } else if (options[i].first == "lite") {
+      file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime;
+    } else if (options[i].first == "lite_implicit_weak_fields") {
+      file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime;
+      file_options.lite_implicit_weak_fields = true;
+      if (!options[i].second.empty()) {
+        file_options.num_cc_files =
+            strto32(options[i].second.c_str(), nullptr, 10);
+      }
+    } else if (options[i].first == "proto_h") {
+      file_options.proto_h = true;
+    } else if (options[i].first == "annotate_accessor") {
+      file_options.annotate_accessor = true;
+    } else if (options[i].first == "inject_field_listener_events") {
+      file_options.field_listener_options.inject_field_listener_events = true;
+    } else if (options[i].first == "forbidden_field_listener_events") {
+      std::size_t pos = 0;
+      do {
+        std::size_t next_pos = options[i].second.find_first_of("+", pos);
+        if (next_pos == std::string::npos) {
+          next_pos = options[i].second.size();
+        }
+        if (next_pos > pos)
+          file_options.field_listener_options.forbidden_field_listener_events
+              .insert(options[i].second.substr(pos, next_pos - pos));
+        pos = next_pos + 1;
+      } while (pos < options[i].second.size());
+    } else if (options[i].first == "verified_lazy") {
+      file_options.unverified_lazy = false;
+    } else if (options[i].first == "unverified_lazy_message_sets") {
+      file_options.unverified_lazy_message_sets = true;
+    } else if (options[i].first == "message_owned_arena_trial") {
+      file_options.message_owned_arena_trial = true;
+    } else if (options[i].first == "force_eagerly_verified_lazy") {
+      file_options.force_eagerly_verified_lazy = true;
+    } else if (options[i].first == "experimental_tail_call_table_mode") {
+      if (options[i].second == "never") {
+        file_options.tctable_mode = Options::kTCTableNever;
+      } else if (options[i].second == "guarded") {
+        file_options.tctable_mode = Options::kTCTableGuarded;
+      } else if (options[i].second == "always") {
+        file_options.tctable_mode = Options::kTCTableAlways;
+      } else {
+        *error = "Unknown value for experimental_tail_call_table_mode: " +
+                 options[i].second;
+        return false;
+      }
+    } else {
+      *error = "Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  // The safe_boundary_check option controls behavior for Google-internal
+  // protobuf APIs.
+  if (file_options.safe_boundary_check && file_options.opensource_runtime) {
+    *error =
+        "The safe_boundary_check option is not supported outside of Google.";
+    return false;
+  }
+
+  // -----------------------------------------------------------------
+
+
+  std::string basename = StripProto(file->name());
+
+  if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap,
+                     &basename)) {
+    return true;
+  }
+
+  FileGenerator file_generator(file, file_options);
+
+  // Generate header(s).
+  if (file_options.proto_h) {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        generator_context->Open(basename + ".proto.h"));
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    std::string info_path = basename + ".proto.h.meta";
+    io::Printer printer(
+        output.get(), '$',
+        file_options.annotate_headers ? &annotation_collector : nullptr);
+    file_generator.GenerateProtoHeader(
+        &printer, file_options.annotate_headers ? info_path : "");
+    if (file_options.annotate_headers) {
+      std::unique_ptr<io::ZeroCopyOutputStream> info_output(
+          generator_context->Open(info_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
+  }
+
+  {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        generator_context->Open(basename + ".pb.h"));
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    std::string info_path = basename + ".pb.h.meta";
+    io::Printer printer(
+        output.get(), '$',
+        file_options.annotate_headers ? &annotation_collector : nullptr);
+    file_generator.GeneratePBHeader(
+        &printer, file_options.annotate_headers ? info_path : "");
+    if (file_options.annotate_headers) {
+      std::unique_ptr<io::ZeroCopyOutputStream> info_output(
+          generator_context->Open(info_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
+  }
+
+  // Generate cc file(s).
+  if (UsingImplicitWeakFields(file, file_options)) {
+    {
+      // This is the global .cc file, containing
+      // enum/services/tables/reflection
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          generator_context->Open(basename + ".pb.cc"));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateGlobalSource(&printer);
+    }
+
+    int num_cc_files =
+        file_generator.NumMessages() + file_generator.NumExtensions();
+
+    // If we're using implicit weak fields then we allow the user to
+    // optionally specify how many files to generate, not counting the global
+    // pb.cc file. If we have more files than messages, then some files will
+    // be generated as empty placeholders.
+    if (file_options.num_cc_files > 0) {
+      GOOGLE_CHECK_LE(num_cc_files, file_options.num_cc_files)
+          << "There must be at least as many numbered .cc files as messages "
+             "and extensions.";
+      num_cc_files = file_options.num_cc_files;
+    }
+    int cc_file_number = 0;
+    for (int i = 0; i < file_generator.NumMessages(); i++) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+          NumberedCcFileName(basename, cc_file_number++)));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateSourceForMessage(i, &printer);
+    }
+    for (int i = 0; i < file_generator.NumExtensions(); i++) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+          NumberedCcFileName(basename, cc_file_number++)));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateSourceForExtension(i, &printer);
+    }
+    // Create empty placeholder files if necessary to match the expected number
+    // of files.
+    for (; cc_file_number < num_cc_files; ++cc_file_number) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+          NumberedCcFileName(basename, cc_file_number)));
+    }
+  } else {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        generator_context->Open(basename + ".pb.cc"));
+    io::Printer printer(output.get(), '$');
+    file_generator.GenerateSource(&printer);
+  }
+
+  return true;
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/generator.h b/src/google/protobuf/compiler/cpp/generator.h
new file mode 100644
index 0000000..1a374b9
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/generator.h
@@ -0,0 +1,107 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Generates C++ code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// CodeGenerator implementation which generates a C++ source file and
+// header.  If you create your own protocol compiler binary and you want
+// it to support C++ output, you can do so by registering an instance of this
+// CodeGenerator with the CommandLineInterface in your main() function.
+class PROTOC_EXPORT CppGenerator : public CodeGenerator {
+ public:
+  CppGenerator();
+  ~CppGenerator() override;
+
+  enum class Runtime {
+    kGoogle3,     // Use the internal google3 runtime.
+    kOpensource,  // Use the open-source runtime.
+
+    // Use the open-source runtime with google3 #include paths.  We make these
+    // absolute to avoid ambiguity, so the runtime will be #included like:
+    //   #include "third_party/protobuf/.../google/protobuf/message.h"
+    kOpensourceGoogle3
+  };
+
+  void set_opensource_runtime(bool opensource) {
+    opensource_runtime_ = opensource;
+  }
+
+  // If set to a non-empty string, generated code will do:
+  //   #include "<BASE>/google/protobuf/message.h"
+  // instead of:
+  //   #include <google/protobuf/message.h>
+  // This has no effect if opensource_runtime = false.
+  void set_runtime_include_base(const std::string& base) {
+    runtime_include_base_ = base;
+  }
+
+  // implements CodeGenerator ----------------------------------------
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* generator_context,
+                std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override {
+    // We don't fully support this yet, but this is needed to unblock the tests,
+    // and we will have full support before the experimental flag is removed.
+    return FEATURE_PROTO3_OPTIONAL;
+  }
+
+ private:
+  bool opensource_runtime_ = true;
+  std::string runtime_include_base_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
new file mode 100644
index 0000000..4b7c5c9
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -0,0 +1,1599 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/helpers.h>
+
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <map>
+#include <memory>
+#include <queue>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/names.h>
+#include <google/protobuf/compiler/cpp/options.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/hash.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+static const char kAnyMessageName[] = "Any";
+static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+
+std::string DotsToColons(const std::string& name) {
+  return StringReplace(name, ".", "::", true);
+}
+
+static const char* const kKeywordList[] = {  //
+    "NULL",
+    "alignas",
+    "alignof",
+    "and",
+    "and_eq",
+    "asm",
+    "auto",
+    "bitand",
+    "bitor",
+    "bool",
+    "break",
+    "case",
+    "catch",
+    "char",
+    "class",
+    "compl",
+    "const",
+    "constexpr",
+    "const_cast",
+    "continue",
+    "decltype",
+    "default",
+    "delete",
+    "do",
+    "double",
+    "dynamic_cast",
+    "else",
+    "enum",
+    "explicit",
+    "export",
+    "extern",
+    "false",
+    "float",
+    "for",
+    "friend",
+    "goto",
+    "if",
+    "inline",
+    "int",
+    "long",
+    "mutable",
+    "namespace",
+    "new",
+    "noexcept",
+    "not",
+    "not_eq",
+    "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"};
+
+static std::unordered_set<std::string>* MakeKeywordsMap() {
+  auto* result = new std::unordered_set<std::string>();
+  for (const auto keyword : kKeywordList) {
+    result->emplace(keyword);
+  }
+  return result;
+}
+
+static std::unordered_set<std::string>& kKeywords = *MakeKeywordsMap();
+
+std::string IntTypeName(const Options& options, const std::string& type) {
+  return type + "_t";
+}
+
+void SetIntVar(const Options& options, const std::string& type,
+               std::map<std::string, std::string>* variables) {
+  (*variables)[type] = IntTypeName(options, type);
+}
+
+// Returns true if the message can potentially allocate memory for its field.
+// This is used to determine if message-owned arena will be useful.
+bool AllocExpected(const Descriptor* descriptor) {
+  return false;
+}
+
+// Describes different approaches to detect non-canonical int32 encoding. Only
+// kNever or kAlways is eligible for *simple* verification methods.
+enum class VerifyInt32Type {
+  kCustom,  // Only check if field number matches.
+  kNever,   // Do not check.
+  kAlways,  // Always check.
+};
+
+inline VerifySimpleType VerifyInt32TypeToVerifyCustom(VerifyInt32Type t) {
+  static VerifySimpleType kCustomTypes[] = {
+      VerifySimpleType::kCustom, VerifySimpleType::kCustomInt32Never,
+      VerifySimpleType::kCustomInt32Always};
+  return kCustomTypes[static_cast<int32_t>(t) -
+                      static_cast<int32_t>(VerifyInt32Type::kCustom)];
+}
+
+}  // namespace
+
+bool IsLazy(const FieldDescriptor* field, const Options& options,
+            MessageSCCAnalyzer* scc_analyzer) {
+  return IsLazilyVerifiedLazy(field, options) ||
+         IsEagerlyVerifiedLazy(field, options, scc_analyzer);
+}
+
+// Returns true if "field" is a message field that is backed by LazyField per
+// profile (go/pdlazy).
+inline bool IsEagerlyVerifiedLazyByProfile(const FieldDescriptor* field,
+                                           const Options& options,
+                                           MessageSCCAnalyzer* scc_analyzer) {
+  return false;
+}
+
+bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, const Options& options,
+                           MessageSCCAnalyzer* scc_analyzer) {
+  return false;
+}
+
+bool IsLazilyVerifiedLazy(const FieldDescriptor* field,
+                          const Options& options) {
+  return false;
+}
+
+void SetCommonVars(const Options& options,
+                   std::map<std::string, std::string>* variables) {
+  (*variables)["proto_ns"] = ProtobufNamespace(options);
+
+  // Warning: there is some clever naming/splitting here to avoid extract script
+  // rewrites.  The names of these variables must not be things that the extract
+  // script will rewrite.  That's why we use "CHK" (for example) instead of
+  // "GOOGLE_CHECK".
+  if (options.opensource_runtime) {
+    (*variables)["GOOGLE_PROTOBUF"] = "GOOGLE_PROTOBUF";
+    (*variables)["CHK"] = "GOOGLE_CHECK";
+    (*variables)["DCHK"] = "GOOGLE_DCHECK";
+  } else {
+    // These values are things the extract script would rewrite if we did not
+    // split them.  It might not strictly matter since we don't generate google3
+    // code in open-source.  But it's good to prevent surprising things from
+    // happening.
+    (*variables)["GOOGLE_PROTOBUF"] =
+        "GOOGLE3"
+        "_PROTOBUF";
+    (*variables)["CHK"] =
+        "CH"
+        "ECK";
+    (*variables)["DCHK"] =
+        "DCH"
+        "ECK";
+  }
+
+  SetIntVar(options, "int8", variables);
+  SetIntVar(options, "uint8", variables);
+  SetIntVar(options, "uint32", variables);
+  SetIntVar(options, "uint64", variables);
+  SetIntVar(options, "int32", variables);
+  SetIntVar(options, "int64", variables);
+  (*variables)["string"] = "std::string";
+}
+
+void SetCommonMessageDataVariables(
+    const Descriptor* descriptor,
+    std::map<std::string, std::string>* variables) {
+  std::string prefix = IsMapEntryMessage(descriptor) ? "" : "_impl_.";
+  (*variables)["any_metadata"] = prefix + "_any_metadata_";
+  (*variables)["cached_size"] = prefix + "_cached_size_";
+  (*variables)["extensions"] = prefix + "_extensions_";
+  (*variables)["has_bits"] = prefix + "_has_bits_";
+  (*variables)["inlined_string_donated_array"] =
+      prefix + "_inlined_string_donated_";
+  (*variables)["oneof_case"] = prefix + "_oneof_case_";
+  (*variables)["tracker"] = "Impl_::_tracker_";
+  (*variables)["weak_field_map"] = prefix + "_weak_field_map_";
+  (*variables)["split"] = prefix + "_split_";
+  (*variables)["cached_split_ptr"] = "cached_split_ptr";
+}
+
+void SetUnknownFieldsVariable(const Descriptor* descriptor,
+                              const Options& options,
+                              std::map<std::string, std::string>* variables) {
+  std::string proto_ns = ProtobufNamespace(options);
+  std::string unknown_fields_type;
+  if (UseUnknownFieldSet(descriptor->file(), options)) {
+    unknown_fields_type = "::" + proto_ns + "::UnknownFieldSet";
+    (*variables)["unknown_fields"] =
+        "_internal_metadata_.unknown_fields<" + unknown_fields_type + ">(" +
+        unknown_fields_type + "::default_instance)";
+  } else {
+    unknown_fields_type =
+        PrimitiveTypeName(options, FieldDescriptor::CPPTYPE_STRING);
+    (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields<" +
+                                     unknown_fields_type + ">(::" + proto_ns +
+                                     "::internal::GetEmptyString)";
+  }
+  (*variables)["unknown_fields_type"] = unknown_fields_type;
+  (*variables)["have_unknown_fields"] =
+      "_internal_metadata_.have_unknown_fields()";
+  (*variables)["mutable_unknown_fields"] =
+      "_internal_metadata_.mutable_unknown_fields<" + unknown_fields_type +
+      ">()";
+}
+
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter) {
+  std::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') {
+      // Capital letters 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;
+    }
+  }
+  return result;
+}
+
+const char kThickSeparator[] =
+    "// ===================================================================\n";
+const char kThinSeparator[] =
+    "// -------------------------------------------------------------------\n";
+
+bool CanInitializeByZeroing(const FieldDescriptor* field) {
+  if (field->is_repeated() || field->is_extension()) return false;
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return field->default_value_enum()->number() == 0;
+    case FieldDescriptor::CPPTYPE_INT32:
+      return field->default_value_int32() == 0;
+    case FieldDescriptor::CPPTYPE_INT64:
+      return field->default_value_int64() == 0;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return field->default_value_uint32() == 0;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return field->default_value_uint64() == 0;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return field->default_value_float() == 0;
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return field->default_value_double() == 0;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() == false;
+    default:
+      return false;
+  }
+}
+
+std::string ClassName(const Descriptor* descriptor) {
+  const Descriptor* parent = descriptor->containing_type();
+  std::string res;
+  if (parent) res += ClassName(parent) + "_";
+  res += descriptor->name();
+  if (IsMapEntryMessage(descriptor)) res += "_DoNotUse";
+  return ResolveKeyword(res);
+}
+
+std::string ClassName(const EnumDescriptor* enum_descriptor) {
+  if (enum_descriptor->containing_type() == nullptr) {
+    return ResolveKeyword(enum_descriptor->name());
+  } else {
+    return ClassName(enum_descriptor->containing_type()) + "_" +
+           enum_descriptor->name();
+  }
+}
+
+std::string QualifiedClassName(const Descriptor* d, const Options& options) {
+  return QualifiedFileLevelSymbol(d->file(), ClassName(d), options);
+}
+
+std::string QualifiedClassName(const EnumDescriptor* d,
+                               const Options& options) {
+  return QualifiedFileLevelSymbol(d->file(), ClassName(d), options);
+}
+
+std::string QualifiedClassName(const Descriptor* d) {
+  return QualifiedClassName(d, Options());
+}
+
+std::string QualifiedClassName(const EnumDescriptor* d) {
+  return QualifiedClassName(d, Options());
+}
+
+std::string ExtensionName(const FieldDescriptor* d) {
+  if (const Descriptor* scope = d->extension_scope())
+    return StrCat(ClassName(scope), "::", ResolveKeyword(d->name()));
+  return ResolveKeyword(d->name());
+}
+
+std::string QualifiedExtensionName(const FieldDescriptor* d,
+                                   const Options& options) {
+  GOOGLE_DCHECK(d->is_extension());
+  return QualifiedFileLevelSymbol(d->file(), ExtensionName(d), options);
+}
+
+std::string QualifiedExtensionName(const FieldDescriptor* d) {
+  return QualifiedExtensionName(d, Options());
+}
+
+std::string Namespace(const std::string& package) {
+  if (package.empty()) return "";
+  return "::" + DotsToColons(package);
+}
+
+std::string Namespace(const FileDescriptor* d, const Options& options) {
+  std::string ret = Namespace(d->package());
+  if (IsWellKnownMessage(d) && options.opensource_runtime) {
+    // Written with string concatenation to prevent rewriting of
+    // ::google::protobuf.
+    ret = StringReplace(ret,
+                        "::google::"
+                        "protobuf",
+                        "::PROTOBUF_NAMESPACE_ID", false);
+  }
+  return ret;
+}
+
+std::string Namespace(const Descriptor* d, const Options& options) {
+  return Namespace(d->file(), options);
+}
+
+std::string Namespace(const FieldDescriptor* d, const Options& options) {
+  return Namespace(d->file(), options);
+}
+
+std::string Namespace(const EnumDescriptor* d, const Options& options) {
+  return Namespace(d->file(), options);
+}
+
+std::string DefaultInstanceType(const Descriptor* descriptor,
+                                const Options& /*options*/, bool split) {
+  return ClassName(descriptor) + (split ? "__Impl_Split" : "") +
+         "DefaultTypeInternal";
+}
+
+std::string DefaultInstanceName(const Descriptor* descriptor,
+                                const Options& /*options*/, bool split) {
+  return "_" + ClassName(descriptor, false) + (split ? "__Impl_Split" : "") +
+         "_default_instance_";
+}
+
+std::string DefaultInstancePtr(const Descriptor* descriptor,
+                               const Options& options, bool split) {
+  return DefaultInstanceName(descriptor, options, split) + "ptr_";
+}
+
+std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
+                                         const Options& options, bool split) {
+  return QualifiedFileLevelSymbol(
+      descriptor->file(), DefaultInstanceName(descriptor, options, split),
+      options);
+}
+
+std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
+                                        const Options& options, bool split) {
+  return QualifiedDefaultInstanceName(descriptor, options, split) + "ptr_";
+}
+
+std::string DescriptorTableName(const FileDescriptor* file,
+                                const Options& options) {
+  return UniqueName("descriptor_table", file, options);
+}
+
+std::string FileDllExport(const FileDescriptor* file, const Options& options) {
+  return UniqueName("PROTOBUF_INTERNAL_EXPORT", file, options);
+}
+
+std::string SuperClassName(const Descriptor* descriptor,
+                           const Options& options) {
+  if (!HasDescriptorMethods(descriptor->file(), options)) {
+    return "::" + ProtobufNamespace(options) + "::MessageLite";
+  }
+  auto simple_base = SimpleBaseClass(descriptor, options);
+  if (simple_base.empty()) {
+    return "::" + ProtobufNamespace(options) + "::Message";
+  }
+  return "::" + ProtobufNamespace(options) + "::internal::" + simple_base;
+}
+
+std::string ResolveKeyword(const std::string& name) {
+  if (kKeywords.count(name) > 0) {
+    return name + "_";
+  }
+  return name;
+}
+
+std::string FieldName(const FieldDescriptor* field) {
+  std::string result = field->name();
+  LowerString(&result);
+  if (kKeywords.count(result) > 0) {
+    result.append("_");
+  }
+  return result;
+}
+
+std::string FieldMemberName(const FieldDescriptor* field, bool split) {
+  StringPiece prefix =
+      IsMapEntryMessage(field->containing_type()) ? "" : "_impl_.";
+  StringPiece split_prefix = split ? "_split_->" : "";
+  if (field->real_containing_oneof() == nullptr) {
+    return StrCat(prefix, split_prefix, FieldName(field), "_");
+  }
+  // Oneof fields are never split.
+  GOOGLE_CHECK(!split);
+  return StrCat(prefix, field->containing_oneof()->name(), "_.",
+                      FieldName(field), "_");
+}
+
+std::string OneofCaseConstantName(const FieldDescriptor* field) {
+  GOOGLE_DCHECK(field->containing_oneof());
+  std::string field_name = UnderscoresToCamelCase(field->name(), true);
+  return "k" + field_name;
+}
+
+std::string QualifiedOneofCaseConstantName(const FieldDescriptor* field) {
+  GOOGLE_DCHECK(field->containing_oneof());
+  const std::string qualification =
+      QualifiedClassName(field->containing_type());
+  return StrCat(qualification, "::", OneofCaseConstantName(field));
+}
+
+std::string EnumValueName(const EnumValueDescriptor* enum_value) {
+  std::string result = enum_value->name();
+  if (kKeywords.count(result) > 0) {
+    result.append("_");
+  }
+  return result;
+}
+
+int EstimateAlignmentSize(const FieldDescriptor* field) {
+  if (field == nullptr) return 0;
+  if (field->is_repeated()) return 8;
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return 1;
+
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return 4;
+
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT64:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return 8;
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return -1;  // Make compiler happy.
+}
+
+std::string FieldConstantName(const FieldDescriptor* field) {
+  std::string field_name = UnderscoresToCamelCase(field->name(), true);
+  std::string result = "k" + field_name + "FieldNumber";
+
+  if (!field->is_extension() &&
+      field->containing_type()->FindFieldByCamelcaseName(
+          field->camelcase_name()) != field) {
+    // This field's camelcase name is not unique.  As a hack, add the field
+    // number to the constant name.  This makes the constant rather useless,
+    // but what can we do?
+    result += "_" + StrCat(field->number());
+  }
+
+  return result;
+}
+
+std::string FieldMessageTypeName(const FieldDescriptor* field,
+                                 const Options& options) {
+  // Note:  The Google-internal version of Protocol Buffers uses this function
+  //   as a hook point for hacks to support legacy code.
+  return QualifiedClassName(field->message_type(), options);
+}
+
+std::string StripProto(const std::string& filename) {
+  /*
+   * TODO(github/georgthegreat) remove this proxy method
+   * once Google's internal codebase will become ready
+   */
+  return compiler::StripProto(filename);
+}
+
+const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
+  switch (type) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return "int32_t";
+    case FieldDescriptor::CPPTYPE_INT64:
+      return "int64_t";
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return "uint32_t";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return "uint64_t";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "double";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return "int";
+    case FieldDescriptor::CPPTYPE_STRING:
+      return "std::string";
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return nullptr;
+
+      // No default because we want the compiler to complain if any new
+      // CppTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return nullptr;
+}
+
+std::string PrimitiveTypeName(const Options& options,
+                              FieldDescriptor::CppType type) {
+  switch (type) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return IntTypeName(options, "int32");
+    case FieldDescriptor::CPPTYPE_INT64:
+      return IntTypeName(options, "int64");
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return IntTypeName(options, "uint32");
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return IntTypeName(options, "uint64");
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "double";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return "int";
+    case FieldDescriptor::CPPTYPE_STRING:
+      return "std::string";
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "";
+
+      // No default because we want the compiler to complain if any new
+      // CppTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return "";
+}
+
+const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
+  switch (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_FLOAT:
+      return "Float";
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "Double";
+
+    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_GROUP:
+      return "Group";
+    case FieldDescriptor::TYPE_MESSAGE:
+      return "Message";
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return "";
+}
+
+std::string Int32ToString(int number) {
+  if (number == std::numeric_limits<int32_t>::min()) {
+    // This needs to be special-cased, see explanation here:
+    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
+    return StrCat(number + 1, " - 1");
+  } else {
+    return StrCat(number);
+  }
+}
+
+static std::string Int64ToString(int64_t number) {
+  if (number == std::numeric_limits<int64_t>::min()) {
+    // This needs to be special-cased, see explanation here:
+    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
+    return StrCat("int64_t{", number + 1, "} - 1");
+  }
+  return StrCat("int64_t{", number, "}");
+}
+
+static std::string UInt64ToString(uint64_t number) {
+  return StrCat("uint64_t{", number, "u}");
+}
+
+std::string DefaultValue(const FieldDescriptor* field) {
+  return DefaultValue(Options(), field);
+}
+
+std::string DefaultValue(const Options& options, const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return Int32ToString(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return StrCat(field->default_value_uint32()) + "u";
+    case FieldDescriptor::CPPTYPE_INT64:
+      return Int64ToString(field->default_value_int64());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return UInt64ToString(field->default_value_uint64());
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value = field->default_value_double();
+      if (value == std::numeric_limits<double>::infinity()) {
+        return "std::numeric_limits<double>::infinity()";
+      } else if (value == -std::numeric_limits<double>::infinity()) {
+        return "-std::numeric_limits<double>::infinity()";
+      } else if (value != value) {
+        return "std::numeric_limits<double>::quiet_NaN()";
+      } else {
+        return SimpleDtoa(value);
+      }
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value = field->default_value_float();
+      if (value == std::numeric_limits<float>::infinity()) {
+        return "std::numeric_limits<float>::infinity()";
+      } else if (value == -std::numeric_limits<float>::infinity()) {
+        return "-std::numeric_limits<float>::infinity()";
+      } else if (value != value) {
+        return "std::numeric_limits<float>::quiet_NaN()";
+      } else {
+        std::string float_value = SimpleFtoa(value);
+        // If floating point value contains a period (.) or an exponent
+        // (either E or e), then append suffix 'f' to make it a float
+        // literal.
+        if (float_value.find_first_of(".eE") != std::string::npos) {
+          float_value.push_back('f');
+        }
+        return float_value;
+      }
+    }
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      // Lazy:  Generate a static_cast because we don't have a helper function
+      //   that constructs the full name of an enum value.
+      return strings::Substitute(
+          "static_cast< $0 >($1)", ClassName(field->enum_type(), true),
+          Int32ToString(field->default_value_enum()->number()));
+    case FieldDescriptor::CPPTYPE_STRING:
+      return "\"" +
+             EscapeTrigraphs(CEscape(field->default_value_string())) +
+             "\"";
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "*" + FieldMessageTypeName(field, options) +
+             "::internal_default_instance()";
+  }
+  // Can't actually get here; make compiler happy.  (We could add a default
+  // case above but then we wouldn't get the nice compiler warning when a
+  // new type is added.)
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return "";
+}
+
+// Convert a file name into a valid identifier.
+std::string FilenameIdentifier(const std::string& filename) {
+  std::string result;
+  for (int i = 0; i < filename.size(); i++) {
+    if (ascii_isalnum(filename[i])) {
+      result.push_back(filename[i]);
+    } else {
+      // Not alphanumeric.  To avoid any possibility of name conflicts we
+      // use the hex code for the character.
+      StrAppend(&result, "_",
+                      strings::Hex(static_cast<uint8_t>(filename[i])));
+    }
+  }
+  return result;
+}
+
+std::string UniqueName(const std::string& name, const std::string& filename,
+                       const Options& options) {
+  return name + "_" + FilenameIdentifier(filename);
+}
+
+// Return the qualified C++ name for a file level symbol.
+std::string QualifiedFileLevelSymbol(const FileDescriptor* file,
+                                     const std::string& name,
+                                     const Options& options) {
+  if (file->package().empty()) {
+    return StrCat("::", name);
+  }
+  return StrCat(Namespace(file, options), "::", name);
+}
+
+// Escape C++ trigraphs by escaping question marks to \?
+std::string EscapeTrigraphs(const std::string& to_escape) {
+  return StringReplace(to_escape, "?", "\\?", true);
+}
+
+// Escaped function name to eliminate naming conflict.
+std::string SafeFunctionName(const Descriptor* descriptor,
+                             const FieldDescriptor* field,
+                             const std::string& prefix) {
+  // Do not use FieldName() since it will escape keywords.
+  std::string name = field->name();
+  LowerString(&name);
+  std::string function_name = prefix + name;
+  if (descriptor->FindFieldByName(function_name)) {
+    // Single underscore will also make it conflicting with the private data
+    // member. We use double underscore to escape function names.
+    function_name.append("__");
+  } else if (kKeywords.count(name) > 0) {
+    // If the field name is a keyword, we append the underscore back to keep it
+    // consistent with other function names.
+    function_name.append("_");
+  }
+  return function_name;
+}
+
+bool IsStringInlined(const FieldDescriptor* descriptor,
+                     const Options& options) {
+  (void)descriptor;
+  (void)options;
+  return false;
+}
+
+static bool HasLazyFields(const Descriptor* descriptor, const Options& options,
+                          MessageSCCAnalyzer* scc_analyzer) {
+  for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
+    if (IsLazy(descriptor->field(field_idx), options, scc_analyzer)) {
+      return true;
+    }
+  }
+  for (int idx = 0; idx < descriptor->extension_count(); idx++) {
+    if (IsLazy(descriptor->extension(idx), options, scc_analyzer)) {
+      return true;
+    }
+  }
+  for (int idx = 0; idx < descriptor->nested_type_count(); idx++) {
+    if (HasLazyFields(descriptor->nested_type(idx), options, scc_analyzer)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Does the given FileDescriptor use lazy fields?
+bool HasLazyFields(const FileDescriptor* file, const Options& options,
+                   MessageSCCAnalyzer* scc_analyzer) {
+  for (int i = 0; i < file->message_type_count(); i++) {
+    const Descriptor* descriptor(file->message_type(i));
+    if (HasLazyFields(descriptor, options, scc_analyzer)) {
+      return true;
+    }
+  }
+  for (int field_idx = 0; field_idx < file->extension_count(); field_idx++) {
+    if (IsLazy(file->extension(field_idx), options, scc_analyzer)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ShouldSplit(const Descriptor*, const Options&) { return false; }
+bool ShouldSplit(const FieldDescriptor*, const Options&) { return false; }
+
+static bool HasRepeatedFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) {
+      return true;
+    }
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasRepeatedFields(descriptor->nested_type(i))) return true;
+  }
+  return false;
+}
+
+bool HasRepeatedFields(const FileDescriptor* file) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasRepeatedFields(file->message_type(i))) return true;
+  }
+  return false;
+}
+
+static bool IsStringPieceField(const FieldDescriptor* field,
+                               const Options& options) {
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+         EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
+}
+
+static bool HasStringPieceFields(const Descriptor* descriptor,
+                                 const Options& options) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (IsStringPieceField(descriptor->field(i), options)) return true;
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasStringPieceFields(descriptor->nested_type(i), options)) return true;
+  }
+  return false;
+}
+
+bool HasStringPieceFields(const FileDescriptor* file, const Options& options) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasStringPieceFields(file->message_type(i), options)) return true;
+  }
+  return false;
+}
+
+static bool IsCordField(const FieldDescriptor* field, const Options& options) {
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+         EffectiveStringCType(field, options) == FieldOptions::CORD;
+}
+
+static bool HasCordFields(const Descriptor* descriptor,
+                          const Options& options) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (IsCordField(descriptor->field(i), options)) return true;
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasCordFields(descriptor->nested_type(i), options)) return true;
+  }
+  return false;
+}
+
+bool HasCordFields(const FileDescriptor* file, const Options& options) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasCordFields(file->message_type(i), options)) return true;
+  }
+  return false;
+}
+
+static bool HasExtensionsOrExtendableMessage(const Descriptor* descriptor) {
+  if (descriptor->extension_range_count() > 0) return true;
+  if (descriptor->extension_count() > 0) return true;
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasExtensionsOrExtendableMessage(descriptor->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool HasExtensionsOrExtendableMessage(const FileDescriptor* file) {
+  if (file->extension_count() > 0) return true;
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasExtensionsOrExtendableMessage(file->message_type(i))) return true;
+  }
+  return false;
+}
+
+static bool HasMapFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (descriptor->field(i)->is_map()) {
+      return true;
+    }
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasMapFields(descriptor->nested_type(i))) return true;
+  }
+  return false;
+}
+
+bool HasMapFields(const FileDescriptor* file) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasMapFields(file->message_type(i))) return true;
+  }
+  return false;
+}
+
+static bool HasEnumDefinitions(const Descriptor* message_type) {
+  if (message_type->enum_type_count() > 0) return true;
+  for (int i = 0; i < message_type->nested_type_count(); ++i) {
+    if (HasEnumDefinitions(message_type->nested_type(i))) return true;
+  }
+  return false;
+}
+
+bool HasEnumDefinitions(const FileDescriptor* file) {
+  if (file->enum_type_count() > 0) return true;
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasEnumDefinitions(file->message_type(i))) return true;
+  }
+  return false;
+}
+
+bool ShouldVerify(const Descriptor* descriptor, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer) {
+  (void)descriptor;
+  (void)options;
+  (void)scc_analyzer;
+  return false;
+}
+
+bool ShouldVerify(const FileDescriptor* file, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer) {
+  (void)file;
+  (void)options;
+  (void)scc_analyzer;
+  return false;
+}
+
+bool IsUtf8String(const FieldDescriptor* field) {
+  return IsProto3(field->file()) &&
+      field->type() == FieldDescriptor::TYPE_STRING;
+}
+
+VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) {
+  (void)descriptor;
+  return VerifySimpleType::kCustom;
+}
+
+bool IsStringOrMessage(const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_UINT64:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_BOOL:
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return false;
+    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return true;
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
+                                         const Options& options) {
+  GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
+  if (options.opensource_runtime) {
+    // Open-source protobuf release only supports STRING ctype.
+    return FieldOptions::STRING;
+  } else {
+    // Google-internal supports all ctypes.
+    return field->options().ctype();
+  }
+}
+
+bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
+  return descriptor->name() == kAnyProtoFile;
+}
+
+bool IsAnyMessage(const Descriptor* descriptor, const Options& options) {
+  return descriptor->name() == kAnyMessageName &&
+         IsAnyMessage(descriptor->file(), options);
+}
+
+bool IsWellKnownMessage(const FileDescriptor* file) {
+  static const std::unordered_set<std::string> well_known_files{
+      "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",
+  };
+  return well_known_files.find(file->name()) != well_known_files.end();
+}
+
+static bool FieldEnforceUtf8(const FieldDescriptor* field,
+                             const Options& options) {
+  return true;
+}
+
+static bool FileUtf8Verification(const FileDescriptor* file,
+                                 const Options& options) {
+  return true;
+}
+
+// Which level of UTF-8 enforcemant is placed on this file.
+Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field,
+                               const Options& options) {
+  if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
+      FieldEnforceUtf8(field, options)) {
+    return Utf8CheckMode::kStrict;
+  } else if (GetOptimizeFor(field->file(), options) !=
+                 FileOptions::LITE_RUNTIME &&
+             FileUtf8Verification(field->file(), options)) {
+    return Utf8CheckMode::kVerify;
+  } else {
+    return Utf8CheckMode::kNone;
+  }
+}
+
+static void GenerateUtf8CheckCode(const FieldDescriptor* field,
+                                  const Options& options, bool for_parse,
+                                  const char* parameters,
+                                  const char* strict_function,
+                                  const char* verify_function,
+                                  const Formatter& format) {
+  switch (GetUtf8CheckMode(field, options)) {
+    case Utf8CheckMode::kStrict: {
+      if (for_parse) {
+        format("DO_(");
+      }
+      format("::$proto_ns$::internal::WireFormatLite::$1$(\n", strict_function);
+      format.Indent();
+      format(parameters);
+      if (for_parse) {
+        format("::$proto_ns$::internal::WireFormatLite::PARSE,\n");
+      } else {
+        format("::$proto_ns$::internal::WireFormatLite::SERIALIZE,\n");
+      }
+      format("\"$1$\")", field->full_name());
+      if (for_parse) {
+        format(")");
+      }
+      format(";\n");
+      format.Outdent();
+      break;
+    }
+    case Utf8CheckMode::kVerify: {
+      format("::$proto_ns$::internal::WireFormat::$1$(\n", verify_function);
+      format.Indent();
+      format(parameters);
+      if (for_parse) {
+        format("::$proto_ns$::internal::WireFormat::PARSE,\n");
+      } else {
+        format("::$proto_ns$::internal::WireFormat::SERIALIZE,\n");
+      }
+      format("\"$1$\");\n", field->full_name());
+      format.Outdent();
+      break;
+    }
+    case Utf8CheckMode::kNone:
+      break;
+  }
+}
+
+void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
+                                    const Options& options, bool for_parse,
+                                    const char* parameters,
+                                    const Formatter& format) {
+  GenerateUtf8CheckCode(field, options, for_parse, parameters,
+                        "VerifyUtf8String", "VerifyUTF8StringNamedField",
+                        format);
+}
+
+void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
+                                  const Options& options, bool for_parse,
+                                  const char* parameters,
+                                  const Formatter& format) {
+  GenerateUtf8CheckCode(field, options, for_parse, parameters, "VerifyUtf8Cord",
+                        "VerifyUTF8CordNamedField", format);
+}
+
+void FlattenMessagesInFile(const FileDescriptor* file,
+                           std::vector<const Descriptor*>* result) {
+  for (int i = 0; i < file->message_type_count(); i++) {
+    ForEachMessage(file->message_type(i), [&](const Descriptor* descriptor) {
+      result->push_back(descriptor);
+    });
+  }
+}
+
+bool HasWeakFields(const Descriptor* descriptor, const Options& options) {
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    if (IsWeak(descriptor->field(i), options)) return true;
+  }
+  return false;
+}
+
+bool HasWeakFields(const FileDescriptor* file, const Options& options) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasWeakFields(file->message_type(i), options)) return true;
+  }
+  return false;
+}
+
+bool UsingImplicitWeakFields(const FileDescriptor* file,
+                             const Options& options) {
+  return options.lite_implicit_weak_fields &&
+         GetOptimizeFor(file, options) == FileOptions::LITE_RUNTIME;
+}
+
+bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
+                         MessageSCCAnalyzer* scc_analyzer) {
+  return UsingImplicitWeakFields(field->file(), options) &&
+         field->type() == FieldDescriptor::TYPE_MESSAGE &&
+         !field->is_required() && !field->is_map() && !field->is_extension() &&
+         !IsWellKnownMessage(field->message_type()->file()) &&
+         field->message_type()->file()->name() !=
+             "net/proto2/proto/descriptor.proto" &&
+         // We do not support implicit weak fields between messages in the same
+         // strongly-connected component.
+         scc_analyzer->GetSCC(field->containing_type()) !=
+             scc_analyzer->GetSCC(field->message_type());
+}
+
+MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
+  if (analysis_cache_.count(scc)) return analysis_cache_[scc];
+  MessageAnalysis result;
+  if (UsingImplicitWeakFields(scc->GetFile(), options_)) {
+    result.contains_weak = true;
+  }
+  for (int i = 0; i < scc->descriptors.size(); i++) {
+    const Descriptor* descriptor = scc->descriptors[i];
+    if (descriptor->extension_range_count() > 0) {
+      result.contains_extension = true;
+    }
+    for (int j = 0; j < descriptor->field_count(); j++) {
+      const FieldDescriptor* field = descriptor->field(j);
+      if (field->is_required()) {
+        result.contains_required = true;
+      }
+      if (field->options().weak()) {
+        result.contains_weak = true;
+      }
+      switch (field->type()) {
+        case FieldDescriptor::TYPE_STRING:
+        case FieldDescriptor::TYPE_BYTES: {
+          if (field->options().ctype() == FieldOptions::CORD) {
+            result.contains_cord = true;
+          }
+          break;
+        }
+        case FieldDescriptor::TYPE_GROUP:
+        case FieldDescriptor::TYPE_MESSAGE: {
+          const SCC* child = analyzer_.GetSCC(field->message_type());
+          if (child != scc) {
+            MessageAnalysis analysis = GetSCCAnalysis(child);
+            result.contains_cord |= analysis.contains_cord;
+            result.contains_extension |= analysis.contains_extension;
+            if (!ShouldIgnoreRequiredFieldCheck(field, options_)) {
+              result.contains_required |= analysis.contains_required;
+            }
+            result.contains_weak |= analysis.contains_weak;
+          } else {
+            // This field points back into the same SCC hence the messages
+            // in the SCC are recursive. Note if SCC contains more than two
+            // nodes it has to be recursive, however this test also works for
+            // a single node that is recursive.
+            result.is_recursive = true;
+          }
+          break;
+        }
+        default:
+          break;
+      }
+    }
+  }
+  // We deliberately only insert the result here. After we contracted the SCC
+  // in the graph, the graph should be a DAG. Hence we shouldn't need to mark
+  // nodes visited as we can never return to them. By inserting them here
+  // we will go in an infinite loop if the SCC is not correct.
+  return analysis_cache_[scc] = result;
+}
+
+void ListAllFields(const Descriptor* d,
+                   std::vector<const FieldDescriptor*>* fields) {
+  // Collect sub messages
+  for (int i = 0; i < d->nested_type_count(); i++) {
+    ListAllFields(d->nested_type(i), fields);
+  }
+  // Collect message level extensions.
+  for (int i = 0; i < d->extension_count(); i++) {
+    fields->push_back(d->extension(i));
+  }
+  // Add types of fields necessary
+  for (int i = 0; i < d->field_count(); i++) {
+    fields->push_back(d->field(i));
+  }
+}
+
+void ListAllFields(const FileDescriptor* d,
+                   std::vector<const FieldDescriptor*>* fields) {
+  // Collect file level message.
+  for (int i = 0; i < d->message_type_count(); i++) {
+    ListAllFields(d->message_type(i), fields);
+  }
+  // Collect message level extensions.
+  for (int i = 0; i < d->extension_count(); i++) {
+    fields->push_back(d->extension(i));
+  }
+}
+
+void ListAllTypesForServices(const FileDescriptor* fd,
+                             std::vector<const Descriptor*>* types) {
+  for (int i = 0; i < fd->service_count(); i++) {
+    const ServiceDescriptor* sd = fd->service(i);
+    for (int j = 0; j < sd->method_count(); j++) {
+      const MethodDescriptor* method = sd->method(j);
+      types->push_back(method->input_type());
+      types->push_back(method->output_type());
+    }
+  }
+}
+
+bool GetBootstrapBasename(const Options& options, const std::string& basename,
+                          std::string* bootstrap_basename) {
+  if (options.opensource_runtime) {
+    return false;
+  }
+
+  std::unordered_map<std::string, std::string> bootstrap_mapping{
+      {"net/proto2/proto/descriptor",
+       "third_party/protobuf/descriptor"},
+      {"net/proto2/compiler/proto/plugin",
+       "net/proto2/compiler/proto/plugin"},
+      {"net/proto2/compiler/proto/profile",
+       "net/proto2/compiler/proto/profile_bootstrap"},
+  };
+  auto iter = bootstrap_mapping.find(basename);
+  if (iter == bootstrap_mapping.end()) {
+    *bootstrap_basename = basename;
+    return false;
+  } else {
+    *bootstrap_basename = iter->second;
+    return true;
+  }
+}
+
+bool IsBootstrapProto(const Options& options, const FileDescriptor* file) {
+  std::string my_name = StripProto(file->name());
+  return GetBootstrapBasename(options, my_name, &my_name);
+}
+
+bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context,
+                    bool bootstrap_flag, std::string* basename) {
+  std::string bootstrap_basename;
+  if (!GetBootstrapBasename(options, *basename, &bootstrap_basename)) {
+    return false;
+  }
+
+  if (bootstrap_flag) {
+    // Adjust basename, but don't abort code generation.
+    *basename = bootstrap_basename;
+    return false;
+  } else {
+    const std::string& forward_to_basename = bootstrap_basename;
+
+    // Generate forwarding headers and empty .pb.cc.
+    {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          generator_context->Open(*basename + ".pb.h"));
+      io::Printer printer(output.get(), '$', nullptr);
+      printer.Print(
+          "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n"
+          "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n"
+          "#include \"$forward_to_basename$.pb.h\"  // IWYU pragma: export\n"
+          "#endif  // PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n",
+          "forward_to_basename", forward_to_basename, "filename_identifier",
+          FilenameIdentifier(*basename));
+
+      if (!options.opensource_runtime) {
+        // HACK HACK HACK, tech debt from the deeps of proto1 and SWIG
+        // protocoltype is SWIG'ed and we need to forward
+        if (*basename == "net/proto/protocoltype") {
+          printer.Print(
+              "#ifdef SWIG\n"
+              "%include \"$forward_to_basename$.pb.h\"\n"
+              "#endif  // SWIG\n",
+              "forward_to_basename", forward_to_basename);
+        }
+      }
+    }
+
+    {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          generator_context->Open(*basename + ".proto.h"));
+      io::Printer printer(output.get(), '$', nullptr);
+      printer.Print(
+          "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n"
+          "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n"
+          "#include \"$forward_to_basename$.proto.h\"  // IWYU pragma: "
+          "export\n"
+          "#endif  // "
+          "PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n",
+          "forward_to_basename", forward_to_basename, "filename_identifier",
+          FilenameIdentifier(*basename));
+    }
+
+    {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          generator_context->Open(*basename + ".pb.cc"));
+      io::Printer printer(output.get(), '$', nullptr);
+      printer.Print("\n");
+    }
+
+    {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          generator_context->Open(*basename + ".pb.h.meta"));
+    }
+
+    {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          generator_context->Open(*basename + ".proto.h.meta"));
+    }
+
+    // Abort code generation.
+    return true;
+  }
+}
+
+static bool HasExtensionFromFile(const Message& msg, const FileDescriptor* file,
+                                 const Options& options,
+                                 bool* has_opt_codesize_extension) {
+  std::vector<const FieldDescriptor*> fields;
+  auto reflection = msg.GetReflection();
+  reflection->ListFields(msg, &fields);
+  for (auto field : fields) {
+    const auto* field_msg = field->message_type();
+    if (field_msg == nullptr) {
+      // It so happens that enums Is_Valid are still generated so enums work.
+      // Only messages have potential problems.
+      continue;
+    }
+    // If this option has an extension set AND that extension is defined in the
+    // same file we have bootstrap problem.
+    if (field->is_extension()) {
+      const auto* msg_extension_file = field->message_type()->file();
+      if (msg_extension_file == file) return true;
+      if (has_opt_codesize_extension &&
+          GetOptimizeFor(msg_extension_file, options) ==
+              FileOptions::CODE_SIZE) {
+        *has_opt_codesize_extension = true;
+      }
+    }
+    // Recurse in this field to see if there is a problem in there
+    if (field->is_repeated()) {
+      for (int i = 0; i < reflection->FieldSize(msg, field); i++) {
+        if (HasExtensionFromFile(reflection->GetRepeatedMessage(msg, field, i),
+                                 file, options, has_opt_codesize_extension)) {
+          return true;
+        }
+      }
+    } else {
+      if (HasExtensionFromFile(reflection->GetMessage(msg, field), file,
+                               options, has_opt_codesize_extension)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static bool HasBootstrapProblem(const FileDescriptor* file,
+                                const Options& options,
+                                bool* has_opt_codesize_extension) {
+  static auto& cache = *new std::unordered_map<const FileDescriptor*, bool>;
+  auto it = cache.find(file);
+  if (it != cache.end()) return it->second;
+  // In order to build the data structures for the reflective parse, it needs
+  // to parse the serialized descriptor describing all the messages defined in
+  // this file. Obviously this presents a bootstrap problem for descriptor
+  // messages.
+  if (file->name() == "net/proto2/proto/descriptor.proto" ||
+      file->name() == "google/protobuf/descriptor.proto") {
+    return true;
+  }
+  // Unfortunately we're not done yet. The descriptor option messages allow
+  // for extensions. So we need to be able to parse these extensions in order
+  // to parse the file descriptor for a file that has custom options. This is a
+  // problem when these custom options extensions are defined in the same file.
+  FileDescriptorProto linkedin_fd_proto;
+  const DescriptorPool* pool = file->pool();
+  const Descriptor* fd_proto_descriptor =
+      pool->FindMessageTypeByName(linkedin_fd_proto.GetTypeName());
+  // Not all pools have descriptor.proto in them. In these cases there for sure
+  // are no custom options.
+  if (fd_proto_descriptor == nullptr) return false;
+
+  // It's easier to inspect file as a proto, because we can use reflection on
+  // the proto to iterate over all content.
+  file->CopyTo(&linkedin_fd_proto);
+
+  // linkedin_fd_proto is a generated proto linked in the proto compiler. As
+  // such it doesn't know the extensions that are potentially present in the
+  // descriptor pool constructed from the protos that are being compiled. These
+  // custom options are therefore in the unknown fields.
+  // By building the corresponding FileDescriptorProto in the pool constructed
+  // by the protos that are being compiled, ie. file's pool, the unknown fields
+  // are converted to extensions.
+  DynamicMessageFactory factory(pool);
+  Message* fd_proto = factory.GetPrototype(fd_proto_descriptor)->New();
+  fd_proto->ParseFromString(linkedin_fd_proto.SerializeAsString());
+
+  bool& res = cache[file];
+  res = HasExtensionFromFile(*fd_proto, file, options,
+                             has_opt_codesize_extension);
+  delete fd_proto;
+  return res;
+}
+
+FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
+                                        const Options& options,
+                                        bool* has_opt_codesize_extension) {
+  if (has_opt_codesize_extension) *has_opt_codesize_extension = false;
+  switch (options.enforce_mode) {
+    case EnforceOptimizeMode::kSpeed:
+      return FileOptions::SPEED;
+    case EnforceOptimizeMode::kLiteRuntime:
+      return FileOptions::LITE_RUNTIME;
+    case EnforceOptimizeMode::kCodeSize:
+      if (file->options().optimize_for() == FileOptions::LITE_RUNTIME) {
+        return FileOptions::LITE_RUNTIME;
+      }
+      if (HasBootstrapProblem(file, options, has_opt_codesize_extension)) {
+        return FileOptions::SPEED;
+      }
+      return FileOptions::CODE_SIZE;
+    case EnforceOptimizeMode::kNoEnforcement:
+      if (file->options().optimize_for() == FileOptions::CODE_SIZE) {
+        if (HasBootstrapProblem(file, options, has_opt_codesize_extension)) {
+          GOOGLE_LOG(WARNING) << "Proto states optimize_for = CODE_SIZE, but we "
+                          "cannot honor that because it contains custom option "
+                          "extensions defined in the same proto.";
+          return FileOptions::SPEED;
+        }
+      }
+      return file->options().optimize_for();
+  }
+
+  GOOGLE_LOG(FATAL) << "Unknown optimization enforcement requested.";
+  // The phony return below serves to silence a warning from GCC 8.
+  return FileOptions::SPEED;
+}
+
+inline bool IsMessageOwnedArenaEligible(const Descriptor* desc,
+                                        const Options& options) {
+  return GetOptimizeFor(desc->file(), options) != FileOptions::LITE_RUNTIME &&
+         !options.bootstrap && !options.opensource_runtime &&
+         AllocExpected(desc);
+}
+
+bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options) {
+  (void)desc;
+  (void)options;
+  return false;
+}
+
+bool EnableMessageOwnedArenaTrial(const Descriptor* desc,
+                                  const Options& options) {
+  return false;
+}
+
+bool HasMessageFieldOrExtension(const Descriptor* desc) {
+  if (desc->extension_range_count() > 0) return true;
+  for (const auto* f : FieldRange(desc)) {
+    if (f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) return true;
+  }
+  return false;
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h
new file mode 100644
index 0000000..d8dcda7
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/helpers.h
@@ -0,0 +1,1064 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_CPP_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/cpp/names.h>
+#include <google/protobuf/compiler/cpp/options.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+enum class ArenaDtorNeeds { kNone = 0, kOnDemand = 1, kRequired = 2 };
+
+inline std::string ProtobufNamespace(const Options& /* options */) {
+  return "PROTOBUF_NAMESPACE_ID";
+}
+
+inline std::string MacroPrefix(const Options& /* options */) {
+  return "GOOGLE_PROTOBUF";
+}
+
+inline std::string DeprecatedAttribute(const Options& /* options */,
+                                       const FieldDescriptor* d) {
+  return d->options().deprecated() ? "PROTOBUF_DEPRECATED " : "";
+}
+
+inline std::string DeprecatedAttribute(const Options& /* options */,
+                                       const EnumValueDescriptor* d) {
+  return d->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM " : "";
+}
+
+// Commonly-used separator comments.  Thick is a line of '=', thin is a line
+// of '-'.
+extern const char kThickSeparator[];
+extern const char kThinSeparator[];
+
+void SetCommonVars(const Options& options,
+                   std::map<std::string, std::string>* variables);
+
+// Variables to access message data from the message scope.
+void SetCommonMessageDataVariables(
+    const Descriptor* descriptor,
+    std::map<std::string, std::string>* variables);
+
+void SetUnknownFieldsVariable(const Descriptor* descriptor,
+                              const Options& options,
+                              std::map<std::string, std::string>* variables);
+
+bool GetBootstrapBasename(const Options& options, const std::string& basename,
+                          std::string* bootstrap_basename);
+bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context,
+                    bool bootstrap_flag, std::string* basename);
+bool IsBootstrapProto(const Options& options, const FileDescriptor* file);
+
+// Name space of the proto file. This namespace is such that the string
+// "<namespace>::some_name" is the correct fully qualified namespace.
+// This means if the package is empty the namespace is "", and otherwise
+// the namespace is "::foo::bar::...::baz" without trailing semi-colons.
+std::string Namespace(const FileDescriptor* d, const Options& options);
+std::string Namespace(const Descriptor* d, const Options& options);
+std::string Namespace(const FieldDescriptor* d, const Options& options);
+std::string Namespace(const EnumDescriptor* d, const Options& options);
+
+// Returns true if it's safe to reset "field" to zero.
+bool CanInitializeByZeroing(const FieldDescriptor* field);
+
+std::string ClassName(const Descriptor* descriptor);
+std::string ClassName(const EnumDescriptor* enum_descriptor);
+
+std::string QualifiedClassName(const Descriptor* d, const Options& options);
+std::string QualifiedClassName(const EnumDescriptor* d, const Options& options);
+
+std::string QualifiedClassName(const Descriptor* d);
+std::string QualifiedClassName(const EnumDescriptor* d);
+
+// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very
+// unreadable at the callsite.
+// Returns the non-nested type name for the given type.  If "qualified" is
+// true, prefix the type with the full namespace.  For example, if you had:
+//   package foo.bar;
+//   message Baz { message Moo {} }
+// Then the qualified ClassName for Moo would be:
+//   ::foo::bar::Baz_Moo
+// While the non-qualified version would be:
+//   Baz_Moo
+inline std::string ClassName(const Descriptor* descriptor, bool qualified) {
+  return qualified ? QualifiedClassName(descriptor, Options())
+                   : ClassName(descriptor);
+}
+
+inline std::string ClassName(const EnumDescriptor* descriptor, bool qualified) {
+  return qualified ? QualifiedClassName(descriptor, Options())
+                   : ClassName(descriptor);
+}
+
+// Returns the extension name prefixed with the class name if nested but without
+// the package name.
+std::string ExtensionName(const FieldDescriptor* d);
+
+std::string QualifiedExtensionName(const FieldDescriptor* d,
+                                   const Options& options);
+std::string QualifiedExtensionName(const FieldDescriptor* d);
+
+// Type name of default instance.
+std::string DefaultInstanceType(const Descriptor* descriptor,
+                                const Options& options, bool split = false);
+
+// Non-qualified name of the default_instance of this message.
+std::string DefaultInstanceName(const Descriptor* descriptor,
+                                const Options& options, bool split = false);
+
+// Non-qualified name of the default instance pointer. This is used only for
+// implicit weak fields, where we need an extra indirection.
+std::string DefaultInstancePtr(const Descriptor* descriptor,
+                               const Options& options, bool split = false);
+
+// Fully qualified name of the default_instance of this message.
+std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
+                                         const Options& options,
+                                         bool split = false);
+
+// Fully qualified name of the default instance pointer.
+std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
+                                        const Options& options,
+                                        bool split = false);
+
+// DescriptorTable variable name.
+std::string DescriptorTableName(const FileDescriptor* file,
+                                const Options& options);
+
+// When declaring symbol externs from another file, this macro will supply the
+// dllexport needed for the target file, if any.
+std::string FileDllExport(const FileDescriptor* file, const Options& options);
+
+// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite.
+std::string SuperClassName(const Descriptor* descriptor,
+                           const Options& options);
+
+// Adds an underscore if necessary to prevent conflicting with a keyword.
+std::string ResolveKeyword(const std::string& name);
+
+// 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().
+std::string FieldName(const FieldDescriptor* field);
+
+// Returns the (unqualified) private member name for this field in C++ code.
+std::string FieldMemberName(const FieldDescriptor* field, bool split);
+
+// Returns an estimate of the compiler's alignment for the field.  This
+// can't guarantee to be correct because the generated code could be compiled on
+// different systems with different alignment rules.  The estimates below assume
+// 64-bit pointers.
+int EstimateAlignmentSize(const FieldDescriptor* field);
+
+// Get the unqualified name that should be used for a field's field
+// number constant.
+std::string FieldConstantName(const FieldDescriptor* field);
+
+// Returns the scope where the field was defined (for extensions, this is
+// different from the message type to which the field applies).
+inline const Descriptor* FieldScope(const FieldDescriptor* field) {
+  return field->is_extension() ? field->extension_scope()
+                               : field->containing_type();
+}
+
+// Returns the fully-qualified type name field->message_type().  Usually this
+// is just ClassName(field->message_type(), true);
+std::string FieldMessageTypeName(const FieldDescriptor* field,
+                                 const Options& options);
+
+// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
+const char* PrimitiveTypeName(FieldDescriptor::CppType type);
+std::string PrimitiveTypeName(const Options& options,
+                              FieldDescriptor::CppType type);
+
+// Get the declared type name in CamelCase format, as is used e.g. for the
+// methods of WireFormat.  For example, TYPE_INT32 becomes "Int32".
+const char* DeclaredTypeMethodName(FieldDescriptor::Type type);
+
+// Return the code that evaluates to the number when compiled.
+std::string Int32ToString(int number);
+
+// Get code that evaluates to the field's default value.
+std::string DefaultValue(const Options& options, const FieldDescriptor* field);
+
+// Compatibility function for callers outside proto2.
+std::string DefaultValue(const FieldDescriptor* field);
+
+// Convert a file name into a valid identifier.
+std::string FilenameIdentifier(const std::string& filename);
+
+// For each .proto file generates a unique name. To prevent collisions of
+// symbols in the global namespace
+std::string UniqueName(const std::string& name, const std::string& filename,
+                       const Options& options);
+inline std::string UniqueName(const std::string& name, const FileDescriptor* d,
+                              const Options& options) {
+  return UniqueName(name, d->name(), options);
+}
+inline std::string UniqueName(const std::string& name, const Descriptor* d,
+                              const Options& options) {
+  return UniqueName(name, d->file(), options);
+}
+inline std::string UniqueName(const std::string& name, const EnumDescriptor* d,
+                              const Options& options) {
+  return UniqueName(name, d->file(), options);
+}
+inline std::string UniqueName(const std::string& name,
+                              const ServiceDescriptor* d,
+                              const Options& options) {
+  return UniqueName(name, d->file(), options);
+}
+
+// Versions for call sites that only support the internal runtime (like proto1
+// support).
+inline Options InternalRuntimeOptions() {
+  Options options;
+  options.opensource_runtime = false;
+  return options;
+}
+inline std::string UniqueName(const std::string& name,
+                              const std::string& filename) {
+  return UniqueName(name, filename, InternalRuntimeOptions());
+}
+inline std::string UniqueName(const std::string& name,
+                              const FileDescriptor* d) {
+  return UniqueName(name, d->name(), InternalRuntimeOptions());
+}
+inline std::string UniqueName(const std::string& name, const Descriptor* d) {
+  return UniqueName(name, d->file(), InternalRuntimeOptions());
+}
+inline std::string UniqueName(const std::string& name,
+                              const EnumDescriptor* d) {
+  return UniqueName(name, d->file(), InternalRuntimeOptions());
+}
+inline std::string UniqueName(const std::string& name,
+                              const ServiceDescriptor* d) {
+  return UniqueName(name, d->file(), InternalRuntimeOptions());
+}
+
+// Return the qualified C++ name for a file level symbol.
+std::string QualifiedFileLevelSymbol(const FileDescriptor* file,
+                                     const std::string& name,
+                                     const Options& options);
+
+// Escape C++ trigraphs by escaping question marks to \?
+std::string EscapeTrigraphs(const std::string& to_escape);
+
+// Escaped function name to eliminate naming conflict.
+std::string SafeFunctionName(const Descriptor* descriptor,
+                             const FieldDescriptor* field,
+                             const std::string& prefix);
+
+// Returns true if generated messages have public unknown fields accessors
+inline bool PublicUnknownFieldsAccessors(const Descriptor* message) {
+  return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+// Returns the optimize mode for <file>, respecting <options.enforce_lite>.
+FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
+                                        const Options& options);
+
+// Determines whether unknown fields will be stored in an UnknownFieldSet or
+// a string.
+inline bool UseUnknownFieldSet(const FileDescriptor* file,
+                               const Options& options) {
+  return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
+}
+
+inline bool IsWeak(const FieldDescriptor* field, const Options& options) {
+  if (field->options().weak()) {
+    GOOGLE_CHECK(!options.opensource_runtime);
+    return true;
+  }
+  return false;
+}
+
+bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
+
+// For a string field, returns the effective ctype.  If the actual ctype is
+// not supported, returns the default of STRING.
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
+                                         const Options& options);
+
+inline bool IsCord(const FieldDescriptor* field, const Options& options) {
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+         EffectiveStringCType(field, options) == FieldOptions::CORD;
+}
+
+inline bool IsString(const FieldDescriptor* field, const Options& options) {
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+         EffectiveStringCType(field, options) == FieldOptions::STRING;
+}
+
+inline bool IsStringPiece(const FieldDescriptor* field,
+                          const Options& options) {
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+         EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
+}
+
+class MessageSCCAnalyzer;
+
+// Does the given FileDescriptor use lazy fields?
+bool HasLazyFields(const FileDescriptor* file, const Options& options,
+                   MessageSCCAnalyzer* scc_analyzer);
+
+// Is the given field a supported lazy field?
+bool IsLazy(const FieldDescriptor* field, const Options& options,
+            MessageSCCAnalyzer* scc_analyzer);
+
+// Is this an explicit (non-profile driven) lazy field, as denoted by
+// lazy/unverified_lazy in the descriptor?
+inline bool IsExplicitLazy(const FieldDescriptor* field) {
+  return field->options().lazy() || field->options().unverified_lazy();
+}
+
+bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, const Options& options,
+                           MessageSCCAnalyzer* scc_analyzer);
+
+bool IsLazilyVerifiedLazy(const FieldDescriptor* field, const Options& options);
+
+// Is the given message being split (go/pdsplit)?
+bool ShouldSplit(const Descriptor* desc, const Options& options);
+
+// Is the given field being split out?
+bool ShouldSplit(const FieldDescriptor* field, const Options& options);
+
+inline bool IsFieldUsed(const FieldDescriptor* /* field */,
+                        const Options& /* options */) {
+  return true;
+}
+
+// Returns true if "field" is stripped.
+inline bool IsFieldStripped(const FieldDescriptor* /*field*/,
+                            const Options& /*options*/) {
+  return false;
+}
+
+// Does the file contain any definitions that need extension_set.h?
+bool HasExtensionsOrExtendableMessage(const FileDescriptor* file);
+
+// Does the file have any repeated fields, necessitating the file to include
+// repeated_field.h? This does not include repeated extensions, since those are
+// all stored internally in an ExtensionSet, not a separate RepeatedField*.
+bool HasRepeatedFields(const FileDescriptor* file);
+
+// Does the file have any string/bytes fields with ctype=STRING_PIECE? This
+// does not include extensions, since ctype is ignored for extensions.
+bool HasStringPieceFields(const FileDescriptor* file, const Options& options);
+
+// Does the file have any string/bytes fields with ctype=CORD? This does not
+// include extensions, since ctype is ignored for extensions.
+bool HasCordFields(const FileDescriptor* file, const Options& options);
+
+// Does the file have any map fields, necessitating the file to include
+// map_field_inl.h and map.h.
+bool HasMapFields(const FileDescriptor* file);
+
+// Does this file have any enum type definitions?
+bool HasEnumDefinitions(const FileDescriptor* file);
+
+// Does this file have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+inline bool HasGeneratedMethods(const FileDescriptor* file,
+                                const Options& options) {
+  return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE;
+}
+
+// Do message classes in this file have descriptor and reflection methods?
+inline bool HasDescriptorMethods(const FileDescriptor* file,
+                                 const Options& options) {
+  return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
+}
+
+// Should we generate generic services for this file?
+inline bool HasGenericServices(const FileDescriptor* file,
+                               const Options& options) {
+  return file->service_count() > 0 &&
+         GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME &&
+         file->options().cc_generic_services();
+}
+
+inline bool IsProto2MessageSet(const Descriptor* descriptor,
+                               const Options& options) {
+  return !options.opensource_runtime &&
+         options.enforce_mode != EnforceOptimizeMode::kLiteRuntime &&
+         !options.lite_implicit_weak_fields &&
+         descriptor->options().message_set_wire_format() &&
+         descriptor->full_name() == "google.protobuf.bridge.MessageSet";
+}
+
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+  return descriptor->options().map_entry();
+}
+
+// Returns true if the field's CPPTYPE is string or message.
+bool IsStringOrMessage(const FieldDescriptor* field);
+
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter);
+
+inline bool IsProto3(const FileDescriptor* file) {
+  return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool HasHasbit(const FieldDescriptor* field) {
+  // This predicate includes proto3 message fields only if they have "optional".
+  //   Foo submsg1 = 1;           // HasHasbit() == false
+  //   optional Foo submsg2 = 2;  // HasHasbit() == true
+  // This is slightly odd, as adding "optional" to a singular proto3 field does
+  // not change the semantics or API. However whenever any field in a message
+  // has a hasbit, it forces reflection to include hasbit offsets for *all*
+  // fields, even if almost all of them are set to -1 (no hasbit). So to avoid
+  // causing a sudden size regression for ~all proto3 messages, we give proto3
+  // message fields a hasbit only if "optional" is present. If the user is
+  // explicitly writing "optional", it is likely they are writing it on
+  // primitive fields also.
+  return (field->has_optional_keyword() || field->is_required()) &&
+         !field->options().weak();
+}
+
+// Returns true if 'enum' semantics are such that unknown values are preserved
+// in the enum field itself, rather than going to the UnknownFieldSet.
+inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) {
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool IsCrossFileMessage(const FieldDescriptor* field) {
+  return field->type() == FieldDescriptor::TYPE_MESSAGE &&
+         field->message_type()->file() != field->file();
+}
+
+inline std::string MakeDefaultName(const FieldDescriptor* field) {
+  return StrCat("_i_give_permission_to_break_this_code_default_",
+                      FieldName(field), "_");
+}
+
+// Semantically distinct from MakeDefaultName in that it gives the C++ code
+// referencing a default field from the message scope, rather than just the
+// variable name.
+// For example, declarations of default variables should always use just
+// MakeDefaultName to produce code like:
+//   Type _i_give_permission_to_break_this_code_default_field_;
+//
+// Code that references these should use MakeDefaultFieldName, in case the field
+// exists at some nested level like:
+//   internal_container_._i_give_permission_to_break_this_code_default_field_;
+inline std::string MakeDefaultFieldName(const FieldDescriptor* field) {
+  return StrCat("Impl_::", MakeDefaultName(field));
+}
+
+inline std::string MakeVarintCachedSizeName(const FieldDescriptor* field) {
+  return StrCat("_", FieldName(field), "_cached_byte_size_");
+}
+
+// Semantically distinct from MakeVarintCachedSizeName in that it gives the C++
+// code referencing the object from the message scope, rather than just the
+// variable name.
+// For example, declarations of default variables should always use just
+// MakeVarintCachedSizeName to produce code like:
+//   Type _field_cached_byte_size_;
+//
+// Code that references these variables should use
+// MakeVarintCachedSizeFieldName, in case the field exists at some nested level
+// like:
+//   internal_container_._field_cached_byte_size_;
+inline std::string MakeVarintCachedSizeFieldName(const FieldDescriptor* field,
+                                                 bool split) {
+  return StrCat("_impl_.", split ? "_split_->" : "", "_",
+                      FieldName(field), "_cached_byte_size_");
+}
+
+// Note: A lot of libraries detect Any protos based on Descriptor::full_name()
+// while the two functions below use FileDescriptor::name(). In a sane world the
+// two approaches should be equivalent. But if you are dealing with descriptors
+// from untrusted sources, you might need to match semantics across libraries.
+bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options);
+bool IsAnyMessage(const Descriptor* descriptor, const Options& options);
+
+bool IsWellKnownMessage(const FileDescriptor* descriptor);
+
+inline std::string IncludeGuard(const FileDescriptor* file, bool pb_h,
+                                const Options& options) {
+  // If we are generating a .pb.h file and the proto_h option is enabled, then
+  // the .pb.h gets an extra suffix.
+  std::string filename_identifier = FilenameIdentifier(
+      file->name() + (pb_h && options.proto_h ? ".pb.h" : ""));
+
+  if (IsWellKnownMessage(file)) {
+    // For well-known messages we need third_party/protobuf and net/proto2 to
+    // have distinct include guards, because some source files include both and
+    // both need to be defined (the third_party copies will be in the
+    // google::protobuf_opensource namespace).
+    return MacroPrefix(options) + "_INCLUDED_" + filename_identifier;
+  } else {
+    // Ideally this case would use distinct include guards for opensource and
+    // google3 protos also.  (The behavior of "first #included wins" is not
+    // ideal).  But unfortunately some legacy code includes both and depends on
+    // the identical include guards to avoid compile errors.
+    //
+    // We should clean this up so that this case can be removed.
+    return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier;
+  }
+}
+
+// Returns the OptimizeMode for this file, furthermore it updates a status
+// bool if has_opt_codesize_extension is non-null. If this status bool is true
+// it means this file contains an extension that itself is defined as
+// optimized_for = CODE_SIZE.
+FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
+                                        const Options& options,
+                                        bool* has_opt_codesize_extension);
+inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
+                                               const Options& options) {
+  return GetOptimizeFor(file, options, nullptr);
+}
+inline bool NeedsEagerDescriptorAssignment(const FileDescriptor* file,
+                                           const Options& options) {
+  bool has_opt_codesize_extension;
+  if (GetOptimizeFor(file, options, &has_opt_codesize_extension) ==
+          FileOptions::CODE_SIZE &&
+      has_opt_codesize_extension) {
+    // If this filedescriptor contains an extension from another file which
+    // is optimized_for = CODE_SIZE. We need to be careful in the ordering so
+    // we eagerly build the descriptors in the dependencies before building
+    // the descriptors of this file.
+    return true;
+  } else {
+    // If we have a generated code based parser we never need eager
+    // initialization of descriptors of our deps.
+    return false;
+  }
+}
+
+// This orders the messages in a .pb.cc as it's outputted by file.cc
+void FlattenMessagesInFile(const FileDescriptor* file,
+                           std::vector<const Descriptor*>* result);
+inline std::vector<const Descriptor*> FlattenMessagesInFile(
+    const FileDescriptor* file) {
+  std::vector<const Descriptor*> result;
+  FlattenMessagesInFile(file, &result);
+  return result;
+}
+
+template <typename F>
+void ForEachMessage(const Descriptor* descriptor, F&& func) {
+  for (int i = 0; i < descriptor->nested_type_count(); i++)
+    ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func));
+  func(descriptor);
+}
+
+template <typename F>
+void ForEachMessage(const FileDescriptor* descriptor, F&& func) {
+  for (int i = 0; i < descriptor->message_type_count(); i++)
+    ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func));
+}
+
+bool HasWeakFields(const Descriptor* desc, const Options& options);
+bool HasWeakFields(const FileDescriptor* desc, const Options& options);
+
+// Returns true if the "required" restriction check should be ignored for the
+// given field.
+inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
+                                                  const Options& options) {
+  // Do not check "required" for lazily verified lazy fields.
+  return IsLazilyVerifiedLazy(field, options);
+}
+
+struct MessageAnalysis {
+  bool is_recursive = false;
+  bool contains_cord = false;
+  bool contains_extension = false;
+  bool contains_required = false;
+  bool contains_weak = false;  // Implicit weak as well.
+};
+
+// This class is used in FileGenerator, to ensure linear instead of
+// quadratic performance, if we do this per message we would get O(V*(V+E)).
+// Logically this is just only used in message.cc, but in the header for
+// FileGenerator to help share it.
+class PROTOC_EXPORT MessageSCCAnalyzer {
+ public:
+  explicit MessageSCCAnalyzer(const Options& options) : options_(options) {}
+
+  MessageAnalysis GetSCCAnalysis(const SCC* scc);
+
+  bool HasRequiredFields(const Descriptor* descriptor) {
+    MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor));
+    return result.contains_required || result.contains_extension;
+  }
+  bool HasWeakField(const Descriptor* descriptor) {
+    MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor));
+    return result.contains_weak;
+  }
+  const SCC* GetSCC(const Descriptor* descriptor) {
+    return analyzer_.GetSCC(descriptor);
+  }
+
+ private:
+  struct DepsGenerator {
+    std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
+      std::vector<const Descriptor*> deps;
+      for (int i = 0; i < desc->field_count(); i++) {
+        if (desc->field(i)->message_type()) {
+          deps.push_back(desc->field(i)->message_type());
+        }
+      }
+      return deps;
+    }
+  };
+  SCCAnalyzer<DepsGenerator> analyzer_;
+  Options options_;
+  std::map<const SCC*, MessageAnalysis> analysis_cache_;
+};
+
+void ListAllFields(const Descriptor* d,
+                   std::vector<const FieldDescriptor*>* fields);
+void ListAllFields(const FileDescriptor* d,
+                   std::vector<const FieldDescriptor*>* fields);
+
+template <class T>
+void ForEachField(const Descriptor* d, T&& func) {
+  for (int i = 0; i < d->nested_type_count(); i++) {
+    ForEachField(d->nested_type(i), std::forward<T&&>(func));
+  }
+  for (int i = 0; i < d->extension_count(); i++) {
+    func(d->extension(i));
+  }
+  for (int i = 0; i < d->field_count(); i++) {
+    func(d->field(i));
+  }
+}
+
+template <class T>
+void ForEachField(const FileDescriptor* d, T&& func) {
+  for (int i = 0; i < d->message_type_count(); i++) {
+    ForEachField(d->message_type(i), std::forward<T&&>(func));
+  }
+  for (int i = 0; i < d->extension_count(); i++) {
+    func(d->extension(i));
+  }
+}
+
+void ListAllTypesForServices(const FileDescriptor* fd,
+                             std::vector<const Descriptor*>* types);
+
+// Indicates whether we should use implicit weak fields for this file.
+bool UsingImplicitWeakFields(const FileDescriptor* file,
+                             const Options& options);
+
+// Indicates whether to treat this field as implicitly weak.
+bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
+                         MessageSCCAnalyzer* scc_analyzer);
+
+inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) {
+  if (!HasDescriptorMethods(desc->file(), options)) return false;
+  if (desc->extension_range_count() != 0) return false;
+  if (desc->field_count() == 0) return true;
+  // TODO(jorg): Support additional common message types with only one
+  // or two fields
+  return false;
+}
+
+inline bool HasSimpleBaseClasses(const FileDescriptor* file,
+                                 const Options& options) {
+  bool v = false;
+  ForEachMessage(file, [&v, &options](const Descriptor* desc) {
+    v |= HasSimpleBaseClass(desc, options);
+  });
+  return v;
+}
+
+inline std::string SimpleBaseClass(const Descriptor* desc,
+                                   const Options& options) {
+  if (!HasDescriptorMethods(desc->file(), options)) return "";
+  if (desc->extension_range_count() != 0) return "";
+  if (desc->field_count() == 0) {
+    return "ZeroFieldsBase";
+  }
+  // TODO(jorg): Support additional common message types with only one
+  // or two fields
+  return "";
+}
+
+// Returns true if this message has a _tracker_ field.
+inline bool HasTracker(const Descriptor* desc, const Options& options) {
+  return options.field_listener_options.inject_field_listener_events &&
+         desc->file()->options().optimize_for() !=
+             google::protobuf::FileOptions::LITE_RUNTIME;
+}
+
+// Returns true if this message needs an Impl_ struct for it's data.
+inline bool HasImplData(const Descriptor* desc, const Options& options) {
+  return !HasSimpleBaseClass(desc, options);
+}
+
+// Formatter is a functor class which acts as a closure around printer and
+// the variable map. It's much like printer->Print except it supports both named
+// variables that are substituted using a key value map and direct arguments. In
+// the format string $1$, $2$, etc... are substituted for the first, second, ...
+// direct argument respectively in the format call, it accepts both strings and
+// integers. The implementation verifies all arguments are used and are "first"
+// used in order of appearance in the argument list. For example,
+//
+// Format("return array[$1$];", 3) -> "return array[3];"
+// Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order)
+// Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;"
+//
+// The arguments can be used more than once like
+//
+// Format("array[$1$] = $2$;  // Index = $1$", 3, "Bla") ->
+//        "array[3] = Bla;  // Index = 3"
+//
+// If you use more arguments use the following style to help the reader,
+//
+// Format("int $1$() {\n"
+//        "  array[$2$] = $3$;\n"
+//        "  return $4$;"
+//        "}\n",
+//        funname, // 1
+//        idx,  // 2
+//        varname,  // 3
+//        retval);  // 4
+//
+// but consider using named variables. Named variables like $foo$, with some
+// identifier foo, are looked up in the map. One additional feature is that
+// spaces are accepted between the '$' delimiters, $ foo$ will
+// substitute to " bar" if foo stands for "bar", but in case it's empty
+// will substitute to "". Hence, for example,
+//
+// Format(vars, "$dllexport $void fun();") -> "void fun();"
+//                                            "__declspec(export) void fun();"
+//
+// which is convenient to prevent double, leading or trailing spaces.
+class PROTOC_EXPORT Formatter {
+ public:
+  explicit Formatter(io::Printer* printer) : printer_(printer) {}
+  Formatter(io::Printer* printer,
+            const std::map<std::string, std::string>& vars)
+      : printer_(printer), vars_(vars) {}
+
+  template <typename T>
+  void Set(const std::string& key, const T& value) {
+    vars_[key] = ToString(value);
+  }
+
+  void AddMap(const std::map<std::string, std::string>& vars) {
+    for (const auto& keyval : vars) vars_[keyval.first] = keyval.second;
+  }
+
+  template <typename... Args>
+  void operator()(const char* format, const Args&... args) const {
+    printer_->FormatInternal({ToString(args)...}, vars_, format);
+  }
+
+  void Indent() const { printer_->Indent(); }
+  void Outdent() const { printer_->Outdent(); }
+  io::Printer* printer() const { return printer_; }
+
+  class PROTOC_EXPORT ScopedIndenter {
+   public:
+    explicit ScopedIndenter(Formatter* format) : format_(format) {
+      format_->Indent();
+    }
+    ~ScopedIndenter() { format_->Outdent(); }
+
+   private:
+    Formatter* format_;
+  };
+
+  PROTOBUF_NODISCARD ScopedIndenter ScopedIndent() {
+    return ScopedIndenter(this);
+  }
+  template <typename... Args>
+  PROTOBUF_NODISCARD ScopedIndenter ScopedIndent(const char* format,
+                                                 const Args&&... args) {
+    (*this)(format, static_cast<Args&&>(args)...);
+    return ScopedIndenter(this);
+  }
+
+  class PROTOC_EXPORT SaveState {
+   public:
+    explicit SaveState(Formatter* format)
+        : format_(format), vars_(format->vars_) {}
+    ~SaveState() { format_->vars_.swap(vars_); }
+
+   private:
+    Formatter* format_;
+    std::map<std::string, std::string> vars_;
+  };
+
+ private:
+  io::Printer* printer_;
+  std::map<std::string, std::string> vars_;
+
+  // Convenience overloads to accept different types as arguments.
+  static std::string ToString(const std::string& s) { return s; }
+  template <typename I, typename = typename std::enable_if<
+                            std::is_integral<I>::value>::type>
+  static std::string ToString(I x) {
+    return StrCat(x);
+  }
+  static std::string ToString(strings::Hex x) { return StrCat(x); }
+  static std::string ToString(const FieldDescriptor* d) { return Payload(d); }
+  static std::string ToString(const Descriptor* d) { return Payload(d); }
+  static std::string ToString(const EnumDescriptor* d) { return Payload(d); }
+  static std::string ToString(const EnumValueDescriptor* d) {
+    return Payload(d);
+  }
+  static std::string ToString(const OneofDescriptor* d) { return Payload(d); }
+
+  template <typename Descriptor>
+  static std::string Payload(const Descriptor* descriptor) {
+    std::vector<int> path;
+    descriptor->GetLocationPath(&path);
+    GeneratedCodeInfo::Annotation annotation;
+    for (int index : path) {
+      annotation.add_path(index);
+    }
+    annotation.set_source_file(descriptor->file()->name());
+    return annotation.SerializeAsString();
+  }
+};
+
+template <class T>
+void PrintFieldComment(const Formatter& format, 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;
+  std::string def = field->DebugStringWithOptions(options);
+  format("// $1$\n", def.substr(0, def.find_first_of('\n')));
+}
+
+class PROTOC_EXPORT NamespaceOpener {
+ public:
+  explicit NamespaceOpener(const Formatter& format)
+      : printer_(format.printer()) {}
+  NamespaceOpener(const std::string& name, const Formatter& format)
+      : NamespaceOpener(format) {
+    ChangeTo(name);
+  }
+  ~NamespaceOpener() { ChangeTo(""); }
+
+  void ChangeTo(const std::string& name) {
+    std::vector<std::string> new_stack_ =
+        Split(name, "::", true);
+    size_t len = std::min(name_stack_.size(), new_stack_.size());
+    size_t common_idx = 0;
+    while (common_idx < len) {
+      if (name_stack_[common_idx] != new_stack_[common_idx]) break;
+      common_idx++;
+    }
+    for (auto it = name_stack_.crbegin();
+         it != name_stack_.crend() - common_idx; ++it) {
+      if (*it == "PROTOBUF_NAMESPACE_ID") {
+        printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n");
+      } else {
+        printer_->Print("}  // namespace $ns$\n", "ns", *it);
+      }
+    }
+    name_stack_.swap(new_stack_);
+    for (size_t i = common_idx; i < name_stack_.size(); ++i) {
+      if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") {
+        printer_->Print("PROTOBUF_NAMESPACE_OPEN\n");
+      } else {
+        printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]);
+      }
+    }
+  }
+
+ private:
+  io::Printer* printer_;
+  std::vector<std::string> name_stack_;
+};
+
+enum class Utf8CheckMode {
+  kStrict = 0,  // Parsing will fail if non UTF-8 data is in string fields.
+  kVerify = 1,  // Only log an error but parsing will succeed.
+  kNone = 2,    // No UTF-8 check.
+};
+
+Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field,
+                               const Options& options);
+
+void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
+                                    const Options& options, bool for_parse,
+                                    const char* parameters,
+                                    const Formatter& format);
+
+void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
+                                  const Options& options, bool for_parse,
+                                  const char* parameters,
+                                  const Formatter& format);
+
+template <typename T>
+struct FieldRangeImpl {
+  struct Iterator {
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = const FieldDescriptor*;
+    using difference_type = int;
+
+    value_type operator*() { return descriptor->field(idx); }
+
+    friend bool operator==(const Iterator& a, const Iterator& b) {
+      GOOGLE_DCHECK(a.descriptor == b.descriptor);
+      return a.idx == b.idx;
+    }
+    friend bool operator!=(const Iterator& a, const Iterator& b) {
+      return !(a == b);
+    }
+
+    Iterator& operator++() {
+      idx++;
+      return *this;
+    }
+
+    int idx;
+    const T* descriptor;
+  };
+
+  Iterator begin() const { return {0, descriptor}; }
+  Iterator end() const { return {descriptor->field_count(), descriptor}; }
+
+  const T* descriptor;
+};
+
+template <typename T>
+FieldRangeImpl<T> FieldRange(const T* desc) {
+  return {desc};
+}
+
+struct OneOfRangeImpl {
+  struct Iterator {
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = const OneofDescriptor*;
+    using difference_type = int;
+
+    value_type operator*() { return descriptor->oneof_decl(idx); }
+
+    friend bool operator==(const Iterator& a, const Iterator& b) {
+      GOOGLE_DCHECK(a.descriptor == b.descriptor);
+      return a.idx == b.idx;
+    }
+    friend bool operator!=(const Iterator& a, const Iterator& b) {
+      return !(a == b);
+    }
+
+    Iterator& operator++() {
+      idx++;
+      return *this;
+    }
+
+    int idx;
+    const Descriptor* descriptor;
+  };
+
+  Iterator begin() const { return {0, descriptor}; }
+  Iterator end() const {
+    return {descriptor->real_oneof_decl_count(), descriptor};
+  }
+
+  const Descriptor* descriptor;
+};
+
+inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; }
+
+PROTOC_EXPORT std::string StripProto(const std::string& filename);
+
+bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options);
+
+bool EnableMessageOwnedArenaTrial(const Descriptor* desc,
+                                  const Options& options);
+
+bool ShouldVerify(const Descriptor* descriptor, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer);
+bool ShouldVerify(const FileDescriptor* file, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer);
+
+// Indicates whether to use predefined verify methods for a given message. If a
+// message is "simple" and needs no special verification per field (e.g. message
+// field, repeated packed, UTF8 string, etc.), we can use either VerifySimple or
+// VerifySimpleAlwaysCheckInt32 methods as all verification can be done based on
+// the wire type.
+//
+// Otherwise, we need "custom" verify methods tailored to a message to pass
+// which field needs a special verification; i.e. InternalVerify.
+enum class VerifySimpleType {
+  kSimpleInt32Never,   // Use VerifySimple
+  kSimpleInt32Always,  // Use VerifySimpleAlwaysCheckInt32
+  kCustom,             // Use InternalVerify and check only for int32
+  kCustomInt32Never,   // Use InternalVerify but never check for int32
+  kCustomInt32Always,  // Use InternalVerify and always check for int32
+};
+
+// Returns VerifySimpleType if messages can be verified by predefined methods.
+VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor);
+
+bool IsUtf8String(const FieldDescriptor* field);
+
+bool HasMessageFieldOrExtension(const Descriptor* desc);
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
diff --git a/src/google/protobuf/compiler/cpp/map_field.cc b/src/google/protobuf/compiler/cpp/map_field.cc
new file mode 100644
index 0000000..3a55ef5
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/map_field.cc
@@ -0,0 +1,338 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/map_field.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+bool IsProto3Field(const FieldDescriptor* field_descriptor) {
+  const FileDescriptor* file_descriptor = field_descriptor->file();
+  return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         std::map<std::string, std::string>* variables,
+                         const Options& options) {
+  SetCommonFieldVariables(descriptor, variables, options);
+  (*variables)["type"] = ClassName(descriptor->message_type(), false);
+  (*variables)["full_name"] = descriptor->full_name();
+
+  const FieldDescriptor* key = descriptor->message_type()->map_key();
+  const FieldDescriptor* val = descriptor->message_type()->map_value();
+  (*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
+  switch (val->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      (*variables)["val_cpp"] = FieldMessageTypeName(val, options);
+      break;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
+      break;
+    default:
+      (*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type());
+  }
+  (*variables)["key_wire_type"] =
+      "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type()));
+  (*variables)["val_wire_type"] =
+      "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type()));
+  (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
+  (*variables)["number"] = StrCat(descriptor->number());
+  (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor));
+
+  if (HasDescriptorMethods(descriptor->file(), options)) {
+    (*variables)["lite"] = "";
+  } else {
+    (*variables)["lite"] = "Lite";
+  }
+}
+
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+                                     const Options& options,
+                                     MessageSCCAnalyzer* scc_analyzer)
+    : FieldGenerator(descriptor, options),
+      has_required_fields_(
+          scc_analyzer->HasRequiredFields(descriptor->message_type())) {
+  SetMessageVariables(descriptor, &variables_, options);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "::$proto_ns$::internal::MapField$lite$<\n"
+      "    $map_classname$,\n"
+      "    $key_cpp$, $val_cpp$,\n"
+      "    ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
+      "    ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> "
+      "$name$_;\n");
+}
+
+void MapFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "private:\n"
+      "const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
+      "    ${1$_internal_$name$$}$() const;\n"
+      "::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
+      "    ${1$_internal_mutable_$name$$}$();\n"
+      "public:\n"
+      "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
+      "    ${1$$name$$}$() const;\n"
+      "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
+      "    ${1$mutable_$name$$}$();\n",
+      descriptor_);
+}
+
+void MapFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
+      "$classname$::_internal_$name$() const {\n"
+      "  return $field$.GetMap();\n"
+      "}\n"
+      "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
+      "$classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_map:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
+      "$classname$::_internal_mutable_$name$() {\n"
+      "$maybe_prepare_split_message$"
+      "  return $field$.MutableMap();\n"
+      "}\n"
+      "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
+      "$classname$::mutable_$name$() {\n"
+      "$annotate_mutable$"
+      "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
+      "  return _internal_mutable_$name$();\n"
+      "}\n");
+}
+
+void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.Clear();\n");
+}
+
+void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->$field$.MergeFrom(from.$field$);\n");
+}
+
+void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.InternalSwap(&other->$field$);\n");
+}
+
+void MapFieldGenerator::GenerateCopyConstructorCode(
+    io::Printer* printer) const {
+  GenerateConstructorCode(printer);
+  GenerateMergingCode(printer);
+}
+
+static void GenerateSerializationLoop(Formatter& format, bool string_key,
+                                      bool string_value,
+                                      bool is_deterministic) {
+  if (is_deterministic) {
+    format(
+        "for (const auto& entry : "
+        "::_pbi::MapSorter$1$<MapType>(map_field)) {\n",
+        (string_key ? "Ptr" : "Flat"));
+  } else {
+    format("for (const auto& entry : map_field) {\n");
+  }
+  {
+    auto loop_scope = format.ScopedIndent();
+    format(
+        "target = WireHelper::InternalSerialize($number$, "
+        "entry.first, entry.second, target, stream);\n");
+
+    if (string_key || string_value) {
+      format("check_utf8(entry);\n");
+    }
+  }
+  format("}\n");
+}
+
+void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("if (!this->_internal_$name$().empty()) {\n");
+  format.Indent();
+  const FieldDescriptor* key_field = descriptor_->message_type()->map_key();
+  const FieldDescriptor* value_field = descriptor_->message_type()->map_value();
+  const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
+  const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
+
+  format(
+      "using MapType = ::_pb::Map<$key_cpp$, $val_cpp$>;\n"
+      "using WireHelper = $map_classname$::Funcs;\n"
+      "const auto& map_field = this->_internal_$name$();\n");
+  bool utf8_check = string_key || string_value;
+  if (utf8_check) {
+    format("auto check_utf8 = [](const MapType::value_type& entry) {\n");
+    {
+      auto check_scope = format.ScopedIndent();
+      // p may be unused when GetUtf8CheckMode evaluates to kNone,
+      // thus disabling the validation.
+      format("(void)entry;\n");
+      if (string_key) {
+        GenerateUtf8CheckCodeForString(
+            key_field, options_, false,
+            "entry.first.data(), static_cast<int>(entry.first.length()),\n",
+            format);
+      }
+      if (string_value) {
+        GenerateUtf8CheckCodeForString(
+            value_field, options_, false,
+            "entry.second.data(), static_cast<int>(entry.second.length()),\n",
+            format);
+      }
+    }
+    format("};\n");
+  }
+
+  format(
+      "\n"
+      "if (stream->IsSerializationDeterministic() && "
+      "map_field.size() > 1) {\n");
+  {
+    auto deterministic_scope = format.ScopedIndent();
+    GenerateSerializationLoop(format, string_key, string_value, true);
+  }
+  format("} else {\n");
+  {
+    auto map_order_scope = format.ScopedIndent();
+    GenerateSerializationLoop(format, string_key, string_value, false);
+  }
+  format("}\n");
+  format.Outdent();
+  format("}\n");
+}
+
+void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "total_size += $tag_size$ *\n"
+      "    "
+      "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
+      "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "    it = this->_internal_$name$().begin();\n"
+      "    it != this->_internal_$name$().end(); ++it) {\n"
+      "  total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
+      "it->second);\n"
+      "}\n");
+}
+
+void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const {
+  if (!has_required_fields_) return;
+
+  Formatter format(printer, variables_);
+  format(
+      "if (!::$proto_ns$::internal::AllAreInitialized($field$)) return "
+      "false;\n");
+}
+
+void MapFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    format("/*decltype($field$)*/{::_pbi::ConstantInitialized()}");
+  } else {
+    format("/*decltype($field$)*/{}");
+  }
+}
+
+void MapFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  // MapField has no move constructor, which prevents explicit aggregate
+  // initialization pre-C++17.
+  format("/*decltype($field$)*/{}");
+}
+
+void MapFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    format(
+        "/*decltype($classname$::Split::$name$_)*/"
+        "{::_pbi::ArenaInitialized(), arena}");
+    return;
+  }
+  // MapField has no move constructor.
+  format("/*decltype($field$)*/{::_pbi::ArenaInitialized(), arena}");
+}
+
+void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    format("$cached_split_ptr$->$name$_.Destruct();\n");
+    format("$cached_split_ptr$->$name$_.~MapField$lite$();\n");
+    return;
+  }
+  format("$field$.Destruct();\n");
+  format("$field$.~MapField$lite$();\n");
+}
+
+void MapFieldGenerator::GenerateArenaDestructorCode(
+    io::Printer* printer) const {
+  if (NeedsArenaDestructor() == ArenaDtorNeeds::kNone) {
+    return;
+  }
+
+  Formatter format(printer, variables_);
+  // _this is the object being destructed (we are inside a static method here).
+  format("_this->$field$.Destruct();\n");
+}
+
+ArenaDtorNeeds MapFieldGenerator::NeedsArenaDestructor() const {
+  return HasDescriptorMethods(descriptor_->file(), options_)
+             ? ArenaDtorNeeds::kRequired
+             : ArenaDtorNeeds::kNone;
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/map_field.h b/src/google/protobuf/compiler/cpp/map_field.h
new file mode 100644
index 0000000..678a128
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/map_field.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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/message_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+  MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options,
+                    MessageSCCAnalyzer* scc_analyzer);
+  ~MapFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override {}
+  void GenerateCopyConstructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateIsInitialized(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateArenaDestructorCode(io::Printer* printer) const override;
+  ArenaDtorNeeds NeedsArenaDestructor() const override;
+
+ private:
+  const bool has_required_fields_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
new file mode 100644
index 0000000..69069da
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -0,0 +1,4446 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/message.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <memory>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/cpp/enum.h>
+#include <google/protobuf/compiler/cpp/extension.h>
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/padding_optimizer.h>
+#include <google/protobuf/compiler/cpp/parse_function_generator.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/hash.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+static constexpr int kNoHasbit = -1;
+
+// Create an expression that evaluates to
+//  "for all i, (_has_bits_[i] & masks[i]) == masks[i]"
+// masks is allowed to be shorter than _has_bits_, but at least one element of
+// masks must be non-zero.
+std::string ConditionalToCheckBitmasks(
+    const std::vector<uint32_t>& masks, bool return_success = true,
+    StringPiece has_bits_var = "_impl_._has_bits_") {
+  std::vector<std::string> parts;
+  for (int i = 0; i < masks.size(); i++) {
+    if (masks[i] == 0) continue;
+    std::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_var, "[", i, "] & ", m, ") ^ ", m, ")"));
+  }
+  GOOGLE_CHECK(!parts.empty());
+  // If we have multiple parts, each expected to be 0, then bitwise-or them.
+  std::string result =
+      parts.size() == 1
+          ? parts[0]
+          : StrCat("(", Join(parts, "\n       | "), ")");
+  return result + (return_success ? " == 0" : " != 0");
+}
+
+void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field,
+                        const std::vector<int>& has_bit_indices,
+                        io::Printer* printer, int* cached_has_word_index) {
+  if (!field->options().weak()) {
+    int has_bit_index = has_bit_indices[field->index()];
+    if (*cached_has_word_index != (has_bit_index / 32)) {
+      *cached_has_word_index = (has_bit_index / 32);
+      format("cached_has_bits = $has_bits$[$1$];\n", *cached_has_word_index);
+    }
+    const std::string mask =
+        StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
+    format("if (cached_has_bits & 0x$1$u) {\n", mask);
+  } else {
+    format("if (has_$1$()) {\n", FieldName(field));
+  }
+  format.Indent();
+}
+
+struct FieldOrderingByNumber {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    return a->number() < b->number();
+  }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+std::vector<const FieldDescriptor*> SortFieldsByNumber(
+    const Descriptor* descriptor) {
+  std::vector<const FieldDescriptor*> fields(descriptor->field_count());
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields[i] = descriptor->field(i);
+  }
+  std::sort(fields.begin(), fields.end(), FieldOrderingByNumber());
+  return fields;
+}
+
+// Functor for sorting extension ranges by their "start" field number.
+struct ExtensionRangeSorter {
+  bool operator()(const Descriptor::ExtensionRange* left,
+                  const Descriptor::ExtensionRange* right) const {
+    return left->start < right->start;
+  }
+};
+
+bool IsPOD(const FieldDescriptor* field) {
+  if (field->is_repeated() || field->is_extension()) return false;
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_UINT64:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return true;
+    case FieldDescriptor::CPPTYPE_STRING:
+      return false;
+    default:
+      return false;
+  }
+}
+
+// Helper for the code that emits the SharedCtor() and InternalSwap() methods.
+// Anything that is a POD or a "normal" message (represented by a pointer) can
+// be manipulated as raw bytes.
+bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field,
+                                const Options& options,
+                                MessageSCCAnalyzer* scc_analyzer) {
+  bool ret = CanInitializeByZeroing(field);
+
+  // Non-repeated, non-lazy message fields are simply raw pointers, so we can
+  // swap them or use memset to initialize these in SharedCtor. We cannot use
+  // this in Clear, as we need to potentially delete the existing value.
+  ret =
+      ret || (!field->is_repeated() && !IsLazy(field, options, scc_analyzer) &&
+              field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
+  return ret;
+}
+
+bool StrContains(const std::string& haystack, const std::string& needle) {
+  return haystack.find(needle) != std::string::npos;
+}
+
+// Finds runs of fields for which `predicate` is true.
+// RunMap maps from fields that start each run to the number of fields in that
+// run.  This is optimized for the common case that there are very few runs in
+// a message and that most of the eligible fields appear together.
+using RunMap = std::unordered_map<const FieldDescriptor*, size_t>;
+RunMap FindRuns(const std::vector<const FieldDescriptor*>& fields,
+                const std::function<bool(const FieldDescriptor*)>& predicate) {
+  RunMap runs;
+  const FieldDescriptor* last_start = nullptr;
+
+  for (auto field : fields) {
+    if (predicate(field)) {
+      if (last_start == nullptr) {
+        last_start = field;
+      }
+
+      runs[last_start]++;
+    } else {
+      last_start = nullptr;
+    }
+  }
+  return runs;
+}
+
+// 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
+// !HasHasbit(field).
+bool EmitFieldNonDefaultCondition(io::Printer* printer,
+                                  const std::string& prefix,
+                                  const FieldDescriptor* field) {
+  GOOGLE_CHECK(!HasHasbit(field));
+  Formatter format(printer);
+  format.Set("prefix", prefix);
+  format.Set("name", FieldName(field));
+  // Merge and serialize semantics: primitive fields are merged/serialized only
+  // if non-zero (numeric) or non-empty (string).
+  if (!field->is_repeated() && !field->containing_oneof()) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      format("if (!$prefix$_internal_$name$().empty()) {\n");
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // Message fields still have has_$name$() methods.
+      format("if ($prefix$_internal_has_$name$()) {\n");
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) {
+      format(
+          "static_assert(sizeof(uint32_t) == sizeof(float), \"Code assumes "
+          "uint32_t and float are the same size.\");\n"
+          "float tmp_$name$ = $prefix$_internal_$name$();\n"
+          "uint32_t raw_$name$;\n"
+          "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n"
+          "if (raw_$name$ != 0) {\n");
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+      format(
+          "static_assert(sizeof(uint64_t) == sizeof(double), \"Code assumes "
+          "uint64_t and double are the same size.\");\n"
+          "double tmp_$name$ = $prefix$_internal_$name$();\n"
+          "uint64_t raw_$name$;\n"
+          "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n"
+          "if (raw_$name$ != 0) {\n");
+    } else {
+      format("if ($prefix$_internal_$name$() != 0) {\n");
+    }
+    format.Indent();
+    return true;
+  } else if (field->real_containing_oneof()) {
+    format("if (_internal_has_$name$()) {\n");
+    format.Indent();
+    return true;
+  }
+  return false;
+}
+
+// Does the given field have a has_$name$() method?
+bool HasHasMethod(const FieldDescriptor* field) {
+  if (!IsProto3(field->file())) {
+    // In proto1/proto2, every field has a has_$name$() method.
+    return true;
+  }
+  // For message types without true field presence, only fields with a message
+  // type or inside an one-of have a has_$name$() method.
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+         field->has_optional_keyword() || field->real_containing_oneof();
+}
+
+// Collects map entry message type information.
+void CollectMapInfo(const Options& options, const Descriptor* descriptor,
+                    std::map<std::string, std::string>* variables) {
+  GOOGLE_CHECK(IsMapEntryMessage(descriptor));
+  std::map<std::string, std::string>& vars = *variables;
+  const FieldDescriptor* key = descriptor->map_key();
+  const FieldDescriptor* val = descriptor->map_value();
+  vars["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
+  switch (val->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      vars["val_cpp"] = FieldMessageTypeName(val, options);
+      break;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      vars["val_cpp"] = ClassName(val->enum_type(), true);
+      break;
+    default:
+      vars["val_cpp"] = PrimitiveTypeName(options, val->cpp_type());
+  }
+  vars["key_wire_type"] =
+      "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type()));
+  vars["val_wire_type"] =
+      "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type()));
+}
+
+// Does the given field have a private (internal helper only) has_$name$()
+// method?
+bool HasPrivateHasMethod(const FieldDescriptor* field) {
+  // Only for oneofs in message types with no field presence. has_$name$(),
+  // based on the oneof case, is still useful internally for generated code.
+  return IsProto3(field->file()) && field->real_containing_oneof();
+}
+
+// TODO(ckennelly):  Cull these exclusions if/when these protos do not have
+// their methods overridden by subclasses.
+
+bool ShouldMarkClassAsFinal(const Descriptor* descriptor,
+                            const Options& options) {
+  return true;
+}
+
+
+// Returns true to make the message serialize in order, decided by the following
+// factors in the order of precedence.
+// --options().message_set_wire_format() == true
+// --the message is in the allowlist (true)
+// --GOOGLE_PROTOBUF_SHUFFLE_SERIALIZE is defined (false)
+// --a ranage of message names that are allowed to stay in order (true)
+bool ShouldSerializeInOrder(const Descriptor* descriptor,
+                            const Options& options) {
+  return true;
+}
+
+bool IsCrossFileMapField(const FieldDescriptor* field) {
+  if (!field->is_map()) {
+    return false;
+  }
+
+  const Descriptor* d = field->message_type();
+  const FieldDescriptor* value = d->FindFieldByNumber(2);
+
+  return IsCrossFileMessage(value);
+}
+
+bool IsCrossFileMaybeMap(const FieldDescriptor* field) {
+  if (IsCrossFileMapField(field)) {
+    return true;
+  }
+
+  return IsCrossFileMessage(field);
+}
+
+bool IsRequired(const std::vector<const FieldDescriptor*>& v) {
+  return v.front()->is_required();
+}
+
+bool HasNonSplitOptionalString(const Descriptor* desc, const Options& options) {
+  for (const auto* field : FieldRange(desc)) {
+    if (IsString(field, options) && !field->is_repeated() &&
+        !field->real_containing_oneof() && !ShouldSplit(field, options)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Collects neighboring fields based on a given criteria (equivalent predicate).
+template <typename Predicate>
+std::vector<std::vector<const FieldDescriptor*>> CollectFields(
+    const std::vector<const FieldDescriptor*>& fields,
+    const Predicate& equivalent) {
+  std::vector<std::vector<const FieldDescriptor*>> chunks;
+  for (auto field : fields) {
+    if (chunks.empty() || !equivalent(chunks.back().back(), field)) {
+      chunks.emplace_back();
+    }
+    chunks.back().push_back(field);
+  }
+  return chunks;
+}
+
+// Returns a bit mask based on has_bit index of "fields" that are typically on
+// the same chunk. It is used in a group presence check where _has_bits_ is
+// masked to tell if any thing in "fields" is present.
+uint32_t GenChunkMask(const std::vector<const FieldDescriptor*>& fields,
+                      const std::vector<int>& has_bit_indices) {
+  GOOGLE_CHECK(!fields.empty());
+  int first_index_offset = has_bit_indices[fields.front()->index()] / 32;
+  uint32_t chunk_mask = 0;
+  for (auto field : fields) {
+    // "index" defines where in the _has_bits_ the field appears.
+    int index = has_bit_indices[field->index()];
+    GOOGLE_CHECK_EQ(first_index_offset, index / 32);
+    chunk_mask |= static_cast<uint32_t>(1) << (index % 32);
+  }
+  GOOGLE_CHECK_NE(0, chunk_mask);
+  return chunk_mask;
+}
+
+// Return the number of bits set in n, a non-negative integer.
+static int popcnt(uint32_t n) {
+  int result = 0;
+  while (n != 0) {
+    result += (n & 1);
+    n = n / 2;
+  }
+  return result;
+}
+
+// For a run of cold chunks, opens and closes an external if statement that
+// checks multiple has_bits words to skip bulk of cold fields.
+class ColdChunkSkipper {
+ public:
+  ColdChunkSkipper(
+      const Descriptor* descriptor, const Options& options,
+      const std::vector<std::vector<const FieldDescriptor*>>& chunks,
+      const std::vector<int>& has_bit_indices, const double cold_threshold)
+      : chunks_(chunks),
+        has_bit_indices_(has_bit_indices),
+        access_info_map_(options.access_info_map),
+        cold_threshold_(cold_threshold) {
+    SetCommonVars(options, &variables_);
+    SetCommonMessageDataVariables(descriptor, &variables_);
+  }
+
+  // May open an external if check for a batch of cold fields. "from" is the
+  // prefix to _has_bits_ to allow MergeFrom to use "from._has_bits_".
+  // Otherwise, it should be "".
+  void OnStartChunk(int chunk, int cached_has_word_index,
+                    const std::string& from, io::Printer* printer);
+  bool OnEndChunk(int chunk, io::Printer* printer);
+
+ private:
+  bool IsColdChunk(int chunk);
+
+  int HasbitWord(int chunk, int offset) {
+    return has_bit_indices_[chunks_[chunk][offset]->index()] / 32;
+  }
+
+  const std::vector<std::vector<const FieldDescriptor*>>& chunks_;
+  const std::vector<int>& has_bit_indices_;
+  const AccessInfoMap* access_info_map_;
+  const double cold_threshold_;
+  std::map<std::string, std::string> variables_;
+  int limit_chunk_ = -1;
+};
+
+// Tuning parameters for ColdChunkSkipper.
+const double kColdRatio = 0.005;
+
+bool ColdChunkSkipper::IsColdChunk(int chunk) {
+  // Mark this variable as used until it is actually used
+  (void)cold_threshold_;
+  return false;
+}
+
+
+void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index,
+                                    const std::string& from,
+                                    io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (!access_info_map_) {
+    return;
+  } else if (chunk < limit_chunk_) {
+    // We are already inside a run of cold chunks.
+    return;
+  } else if (!IsColdChunk(chunk)) {
+    // We can't start a run of cold chunks.
+    return;
+  }
+
+  // Find the end of consecutive cold chunks.
+  limit_chunk_ = chunk;
+  while (limit_chunk_ < chunks_.size() && IsColdChunk(limit_chunk_)) {
+    limit_chunk_++;
+  }
+
+  if (limit_chunk_ <= chunk + 1) {
+    // Require at least two chunks to emit external has_bit checks.
+    limit_chunk_ = -1;
+    return;
+  }
+
+  // Emit has_bit check for each has_bit_dword index.
+  format("if (PROTOBUF_PREDICT_FALSE(");
+  int first_word = HasbitWord(chunk, 0);
+  while (chunk < limit_chunk_) {
+    uint32_t mask = 0;
+    int this_word = HasbitWord(chunk, 0);
+    // Generate mask for chunks on the same word.
+    for (; chunk < limit_chunk_ && HasbitWord(chunk, 0) == this_word; chunk++) {
+      for (auto field : chunks_[chunk]) {
+        int hasbit_index = has_bit_indices_[field->index()];
+        // Fields on a chunk must be in the same word.
+        GOOGLE_CHECK_EQ(this_word, hasbit_index / 32);
+        mask |= 1 << (hasbit_index % 32);
+      }
+    }
+
+    if (this_word != first_word) {
+      format(" ||\n    ");
+    }
+    format.Set("mask", strings::Hex(mask, strings::ZERO_PAD_8));
+    if (this_word == cached_has_word_index) {
+      format("(cached_has_bits & 0x$mask$u) != 0");
+    } else {
+      format("($1$_impl_._has_bits_[$2$] & 0x$mask$u) != 0", from, this_word);
+    }
+  }
+  format(")) {\n");
+  format.Indent();
+}
+
+bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (chunk != limit_chunk_ - 1) {
+    return false;
+  }
+  format.Outdent();
+  format("}\n");
+  return true;
+}
+
+void MaySetAnnotationVariable(const Options& options,
+                              StringPiece annotation_name,
+                              StringPiece injector_template_prefix,
+                              StringPiece injector_template_suffix,
+                              std::map<std::string, std::string>* variables) {
+  if (options.field_listener_options.forbidden_field_listener_events.count(
+          std::string(annotation_name)))
+    return;
+  (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute(
+      StrCat(injector_template_prefix, injector_template_suffix),
+      (*variables)["classtype"]);
+}
+
+void GenerateExtensionAnnotations(
+    const Descriptor* descriptor, const Options& options,
+    std::map<std::string, std::string>* variables) {
+  const std::map<std::string, std::string> accessor_annotations_to_hooks = {
+      {"annotate_extension_has", "OnHasExtension"},
+      {"annotate_extension_clear", "OnClearExtension"},
+      {"annotate_extension_repeated_size", "OnExtensionSize"},
+      {"annotate_extension_get", "OnGetExtension"},
+      {"annotate_extension_mutable", "OnMutableExtension"},
+      {"annotate_extension_set", "OnSetExtension"},
+      {"annotate_extension_release", "OnReleaseExtension"},
+      {"annotate_repeated_extension_get", "OnGetExtension"},
+      {"annotate_repeated_extension_mutable", "OnMutableExtension"},
+      {"annotate_repeated_extension_set", "OnSetExtension"},
+      {"annotate_repeated_extension_add", "OnAddExtension"},
+      {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"},
+      {"annotate_repeated_extension_list", "OnListExtension"},
+      {"annotate_repeated_extension_list_mutable", "OnMutableListExtension"},
+  };
+  for (const auto& annotation : accessor_annotations_to_hooks) {
+    (*variables)[annotation.first] = "";
+  }
+  if (!HasTracker(descriptor, options)) {
+    return;
+  }
+  StringPiece tracker = (*variables)["tracker"];
+  StringPiece extensions = (*variables)["extensions"];
+  for (const auto& annotation : accessor_annotations_to_hooks) {
+    const std::string& annotation_name = annotation.first;
+    const std::string& listener_call = annotation.second;
+    if (!StrContains(annotation_name, "repeated") &&
+        !StrContains(annotation_name, "size") &&
+        !StrContains(annotation_name, "clear")) {
+      // Primitive fields accessors.
+      // "Has" is here as users calling "has" on a repeated field is a mistake.
+      (*variables)[annotation_name] = StrCat(
+          "  ", tracker, ".", listener_call,
+          "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), ",
+          extensions, ", id.default_value_ref()));");
+    } else if (StrContains(annotation_name, "repeated") &&
+               !StrContains(annotation_name, "list") &&
+               !StrContains(annotation_name, "size")) {
+      // Repeated index accessors.
+      std::string str_index = "index";
+      if (StrContains(annotation_name, "add")) {
+        str_index = StrCat(extensions, ".ExtensionSize(id.number()) - 1");
+      }
+      (*variables)[annotation_name] =
+          StrCat("  ", tracker, ".", listener_call,
+                       "(this, id.number(), "
+                       "_proto_TypeTraits::GetPtr(id.number(), ",
+                       extensions, ", ", str_index, "));");
+    } else if (StrContains(annotation_name, "list") ||
+               StrContains(annotation_name, "size")) {
+      // Repeated full accessors.
+      (*variables)[annotation_name] = StrCat(
+          "  ", tracker, ".", listener_call,
+          "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), ",
+          extensions, "));");
+    } else {
+      // Generic accessors such as "clear".
+      // TODO(b/190614678): Generalize clear from both repeated and non repeated
+      // calls, currently their underlying memory interfaces are very different.
+      // Or think of removing clear callback as no usages are needed and no
+      // memory exist after calling clear().
+    }
+  }
+}
+
+}  // anonymous namespace
+
+// ===================================================================
+
+MessageGenerator::MessageGenerator(
+    const Descriptor* descriptor,
+    const std::map<std::string, std::string>& vars, int index_in_file_messages,
+    const Options& options, MessageSCCAnalyzer* scc_analyzer)
+    : descriptor_(descriptor),
+      index_in_file_messages_(index_in_file_messages),
+      classname_(ClassName(descriptor, false)),
+      options_(options),
+      field_generators_(descriptor, options, scc_analyzer),
+      max_has_bit_index_(0),
+      max_inlined_string_index_(0),
+      num_weak_fields_(0),
+      scc_analyzer_(scc_analyzer),
+      variables_(vars) {
+  if (!message_layout_helper_) {
+    message_layout_helper_.reset(new PaddingOptimizer());
+  }
+  SetCommonMessageDataVariables(descriptor, &variables_);
+
+  // Variables that apply to this class
+  variables_["classname"] = classname_;
+  variables_["classtype"] = QualifiedClassName(descriptor_, options);
+  variables_["full_name"] = descriptor_->full_name();
+  variables_["superclass"] = SuperClassName(descriptor_, options_);
+  variables_["annotate_serialize"] = "";
+  variables_["annotate_deserialize"] = "";
+  variables_["annotate_reflection"] = "";
+  variables_["annotate_bytesize"] = "";
+  variables_["annotate_mergefrom"] = "";
+
+  if (HasTracker(descriptor_, options_)) {
+    const std::string injector_template =
+        StrCat("  ", variables_["tracker"], ".");
+
+    MaySetAnnotationVariable(options, "serialize", injector_template,
+                             "OnSerialize(this);\n", &variables_);
+    MaySetAnnotationVariable(options, "deserialize", injector_template,
+                             "OnDeserialize(this);\n", &variables_);
+    // TODO(danilak): Ideally annotate_reflection should not exist and we need
+    // to annotate all reflective calls on our own, however, as this is a cause
+    // for side effects, i.e. reading values dynamically, we want the users know
+    // that dynamic access can happen.
+    MaySetAnnotationVariable(options, "reflection", injector_template,
+                             "OnGetMetadata();\n", &variables_);
+    MaySetAnnotationVariable(options, "bytesize", injector_template,
+                             "OnByteSize(this);\n", &variables_);
+    MaySetAnnotationVariable(options, "mergefrom", injector_template,
+                             "OnMergeFrom(_this, &from);\n", &variables_);
+  }
+
+  GenerateExtensionAnnotations(descriptor_, options_, &variables_);
+
+  SetUnknownFieldsVariable(descriptor_, options_, &variables_);
+
+  // Compute optimized field order to be used for layout and initialization
+  // purposes.
+  for (auto field : FieldRange(descriptor_)) {
+    if (IsFieldStripped(field, options_)) {
+      continue;
+    }
+
+    if (IsWeak(field, options_)) {
+      num_weak_fields_++;
+    } else if (!field->real_containing_oneof()) {
+      optimized_order_.push_back(field);
+    }
+  }
+
+  message_layout_helper_->OptimizeLayout(&optimized_order_, options_,
+                                         scc_analyzer_);
+
+  // This message has hasbits iff one or more fields need one.
+  for (auto field : optimized_order_) {
+    if (HasHasbit(field)) {
+      if (has_bit_indices_.empty()) {
+        has_bit_indices_.resize(descriptor_->field_count(), kNoHasbit);
+      }
+      has_bit_indices_[field->index()] = max_has_bit_index_++;
+    }
+    if (IsStringInlined(field, options_)) {
+      if (inlined_string_indices_.empty()) {
+        inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit);
+        // The bitset[0] is for arena dtor tracking. Donating states start from
+        // bitset[1];
+        max_inlined_string_index_++;
+      }
+      inlined_string_indices_[field->index()] = max_inlined_string_index_++;
+    }
+  }
+
+  if (!has_bit_indices_.empty()) {
+    field_generators_.SetHasBitIndices(has_bit_indices_);
+  }
+
+  if (!inlined_string_indices_.empty()) {
+    field_generators_.SetInlinedStringIndices(inlined_string_indices_);
+  }
+
+  num_required_fields_ = 0;
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    if (descriptor->field(i)->is_required()) {
+      ++num_required_fields_;
+    }
+  }
+
+  parse_function_generator_.reset(new ParseFunctionGenerator(
+      descriptor_, max_has_bit_index_, has_bit_indices_,
+      inlined_string_indices_, options_, scc_analyzer_, variables_));
+}
+
+MessageGenerator::~MessageGenerator() = default;
+
+size_t MessageGenerator::HasBitsSize() const {
+  return (max_has_bit_index_ + 31) / 32;
+}
+
+size_t MessageGenerator::InlinedStringDonatedSize() const {
+  return (max_inlined_string_index_ + 31) / 32;
+}
+
+int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const {
+  return has_bit_indices_.empty() ? kNoHasbit
+                                  : has_bit_indices_[field->index()];
+}
+
+int MessageGenerator::HasByteIndex(const FieldDescriptor* field) const {
+  int hasbit = HasBitIndex(field);
+  return hasbit == kNoHasbit ? kNoHasbit : hasbit / 8;
+}
+
+int MessageGenerator::HasWordIndex(const FieldDescriptor* field) const {
+  int hasbit = HasBitIndex(field);
+  return hasbit == kNoHasbit ? kNoHasbit : hasbit / 32;
+}
+
+void MessageGenerator::AddGenerators(
+    std::vector<std::unique_ptr<EnumGenerator>>* enum_generators,
+    std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) {
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    enum_generators->emplace_back(
+        new EnumGenerator(descriptor_->enum_type(i), variables_, options_));
+    enum_generators_.push_back(enum_generators->back().get());
+  }
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    extension_generators->emplace_back(new ExtensionGenerator(
+        descriptor_->extension(i), options_, scc_analyzer_));
+    extension_generators_.push_back(extension_generators->back().get());
+  }
+}
+
+void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  // optimized_fields_ does not contain fields where
+  //    field->real_containing_oneof()
+  // so we need to iterate over those as well.
+  //
+  // We place the non-oneof fields in optimized_order_, as that controls the
+  // order of the _has_bits_ entries and we want GDB's pretty printers to be
+  // able to infer these indices from the k[FIELDNAME]FieldNumber order.
+  std::vector<const FieldDescriptor*> ordered_fields;
+  ordered_fields.reserve(descriptor_->field_count());
+
+  ordered_fields.insert(ordered_fields.begin(), optimized_order_.begin(),
+                        optimized_order_.end());
+  for (auto field : FieldRange(descriptor_)) {
+    if (!field->real_containing_oneof() && !field->options().weak() &&
+        !IsFieldStripped(field, options_)) {
+      continue;
+    }
+    ordered_fields.push_back(field);
+  }
+
+  if (!ordered_fields.empty()) {
+    format("enum : int {\n");
+    for (auto field : ordered_fields) {
+      Formatter::SaveState save(&format);
+
+      std::map<std::string, std::string> vars;
+      SetCommonFieldVariables(field, &vars, options_);
+      format.AddMap(vars);
+      format("  ${1$$2$$}$ = $number$,\n", field, FieldConstantName(field));
+    }
+    format("};\n");
+  }
+  for (auto field : ordered_fields) {
+    PrintFieldComment(format, field);
+
+    Formatter::SaveState save(&format);
+
+    std::map<std::string, std::string> vars;
+    SetCommonFieldVariables(field, &vars, options_);
+    format.AddMap(vars);
+
+    if (field->is_repeated()) {
+      format("$deprecated_attr$int ${1$$name$_size$}$() const$2$\n", field,
+             !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}");
+      if (!IsFieldStripped(field, options_)) {
+        format(
+            "private:\n"
+            "int ${1$_internal_$name$_size$}$() const;\n"
+            "public:\n",
+            field);
+      }
+    } else if (HasHasMethod(field)) {
+      format("$deprecated_attr$bool ${1$has_$name$$}$() const$2$\n", field,
+             !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}");
+      if (!IsFieldStripped(field, options_)) {
+        format(
+            "private:\n"
+            "bool _internal_has_$name$() const;\n"
+            "public:\n");
+      }
+    } else if (HasPrivateHasMethod(field)) {
+      if (!IsFieldStripped(field, options_)) {
+        format(
+            "private:\n"
+            "bool ${1$_internal_has_$name$$}$() const;\n"
+            "public:\n",
+            field);
+      }
+    }
+    format("$deprecated_attr$void ${1$clear_$name$$}$()$2$\n", field,
+           !IsFieldStripped(field, options_) ? ";" : "{__builtin_trap();}");
+
+    // Generate type-specific accessor declarations.
+    field_generators_.get(field).GenerateAccessorDeclarations(printer);
+
+    format("\n");
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    // Generate accessors for extensions.
+    // We use "_proto_TypeTraits" as a type name below because "TypeTraits"
+    // causes problems if the class has a nested message or enum type with that
+    // name and "_TypeTraits" is technically reserved for the C++ library since
+    // it starts with an underscore followed by a capital letter.
+    //
+    // For similar reason, we use "_field_type" and "_is_packed" as parameter
+    // names below, so that "field_type" and "is_packed" can be used as field
+    // names.
+    format(R"(
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline bool HasExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_extension_has$
+  return $extensions$.Has(id.number());
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void ClearExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+  $extensions$.ClearExtension(id.number());
+$annotate_extension_clear$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline int ExtensionSize(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_extension_repeated_size$
+  return $extensions$.ExtensionSize(id.number());
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_extension_get$
+  return _proto_TypeTraits::Get(id.number(), $extensions$,
+                                id.default_value());
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_extension_mutable$
+  return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                    &$extensions$);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void SetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Singular::ConstType value) {
+  _proto_TypeTraits::Set(id.number(), _field_type, value, &$extensions$);
+$annotate_extension_set$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void SetAllocatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Singular::MutableType value) {
+  _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                  &$extensions$);
+$annotate_extension_set$
+}
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void UnsafeArenaSetAllocatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Singular::MutableType value) {
+  _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                             value, &$extensions$);
+$annotate_extension_set$
+}
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+PROTOBUF_NODISCARD inline
+    typename _proto_TypeTraits::Singular::MutableType
+    ReleaseExtension(
+        const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+            $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_extension_release$
+  return _proto_TypeTraits::Release(id.number(), _field_type,
+                                    &$extensions$);
+}
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Singular::MutableType
+UnsafeArenaReleaseExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_extension_release$
+  return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                               &$extensions$);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    int index) const {
+$annotate_repeated_extension_get$
+  return _proto_TypeTraits::Get(id.number(), $extensions$, index);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    int index) {
+$annotate_repeated_extension_mutable$
+  return _proto_TypeTraits::Mutable(id.number(), index, &$extensions$);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void SetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+  _proto_TypeTraits::Set(id.number(), index, value, &$extensions$);
+$annotate_repeated_extension_set$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+  typename _proto_TypeTraits::Repeated::MutableType to_add =
+      _proto_TypeTraits::Add(id.number(), _field_type, &$extensions$);
+$annotate_repeated_extension_add_mutable$
+  return to_add;
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void AddExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Repeated::ConstType value) {
+  _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                         &$extensions$);
+$annotate_repeated_extension_add$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+GetRepeatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_repeated_extension_list$
+  return _proto_TypeTraits::GetRepeated(id.number(), $extensions$);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+MutableRepeatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_repeated_extension_list_mutable$
+  return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                            _is_packed, &$extensions$);
+}
+
+)");
+    // Generate MessageSet specific APIs for proto2 MessageSet.
+    // For testing purposes we don't check for bridge.MessageSet, so
+    // we don't use IsProto2MessageSet
+    if (descriptor_->options().message_set_wire_format() &&
+        !options_.opensource_runtime && !options_.lite_implicit_weak_fields) {
+      // Special-case MessageSet
+      format("GOOGLE_PROTOBUF_EXTENSION_MESSAGE_SET_ACCESSORS($classname$)\n");
+    }
+  }
+
+  for (auto oneof : OneOfRange(descriptor_)) {
+    Formatter::SaveState saver(&format);
+    format.Set("oneof_name", oneof->name());
+    format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true));
+    format(
+        "void ${1$clear_$oneof_name$$}$();\n"
+        "$camel_oneof_name$Case $oneof_name$_case() const;\n",
+        oneof);
+  }
+}
+
+void MessageGenerator::GenerateSingularFieldHasBits(
+    const FieldDescriptor* field, Formatter format) {
+  if (IsFieldStripped(field, options_)) {
+    format(
+        "inline bool $classname$::has_$name$() const { "
+        "__builtin_trap(); }\n");
+    return;
+  }
+  if (field->options().weak()) {
+    format(
+        "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_has$"
+        "  return $weak_field_map$.Has($number$);\n"
+        "}\n");
+    return;
+  }
+  if (HasHasbit(field)) {
+    int has_bit_index = HasBitIndex(field);
+    GOOGLE_CHECK_NE(has_bit_index, kNoHasbit);
+
+    format.Set("has_array_index", has_bit_index / 32);
+    format.Set("has_mask",
+               strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
+    format(
+        "inline bool $classname$::_internal_has_$name$() const {\n"
+        "  bool value = "
+        "($has_bits$[$has_array_index$] & 0x$has_mask$u) != 0;\n");
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !IsLazy(field, options_, scc_analyzer_)) {
+      // We maintain the invariant that for a submessage x, has_x() returning
+      // true implies that x_ is not null. By giving this information to the
+      // compiler, we allow it to eliminate unnecessary null checks later on.
+      format("  PROTOBUF_ASSUME(!value || $field$ != nullptr);\n");
+    }
+
+    format(
+        "  return value;\n"
+        "}\n"
+        "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_has$"
+        "  return _internal_has_$name$();\n"
+        "}\n");
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Message fields have a has_$name$() method.
+    if (IsLazy(field, options_, scc_analyzer_)) {
+      format(
+          "inline bool $classname$::_internal_has_$name$() const {\n"
+          "  return !$field$.IsCleared();\n"
+          "}\n");
+    } else {
+      format(
+          "inline bool $classname$::_internal_has_$name$() const {\n"
+          "  return this != internal_default_instance() "
+          "&& $field$ != nullptr;\n"
+          "}\n");
+    }
+    format(
+        "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_has$"
+        "  return _internal_has_$name$();\n"
+        "}\n");
+  }
+}
+
+void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format.Set("oneof_name", oneof->name());
+    format.Set("oneof_index", oneof->index());
+    format.Set("cap_oneof_name", ToUpper(oneof->name()));
+    format(
+        "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 Formatter& format) {
+  if (IsFieldStripped(field, options_)) {
+    if (HasHasMethod(field)) {
+      format(
+          "inline bool $classname$::has_$name$() const { "
+          "__builtin_trap(); }\n");
+    }
+    format(
+        "inline void $classname$::set_has_$name$() { __builtin_trap(); "
+        "}\n");
+    return;
+  }
+  // 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).
+  //
+  // If has_$name$() is private, there is no need to add an internal accessor.
+  // Only annotate public accessors.
+  if (HasHasMethod(field)) {
+    format(
+        "inline bool $classname$::_internal_has_$name$() const {\n"
+        "  return $oneof_name$_case() == k$field_name$;\n"
+        "}\n"
+        "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_has$"
+        "  return _internal_has_$name$();\n"
+        "}\n");
+  } else if (HasPrivateHasMethod(field)) {
+    format(
+        "inline bool $classname$::_internal_has_$name$() const {\n"
+        "  return $oneof_name$_case() == k$field_name$;\n"
+        "}\n");
+  }
+  // set_has_$name$() for oneof fields is always private; hence should not be
+  // annotated.
+  format(
+      "inline void $classname$::set_has_$name$() {\n"
+      "  $oneof_case$[$oneof_index$] = k$field_name$;\n"
+      "}\n");
+}
+
+void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field,
+                                          bool is_inline, Formatter format) {
+  if (IsFieldStripped(field, options_)) {
+    format("void $classname$::clear_$name$() { __builtin_trap(); }\n");
+    return;
+  }
+
+  // Generate clear_$name$().
+  if (is_inline) {
+    format("inline ");
+  }
+  format("void $classname$::clear_$name$() {\n");
+
+  format.Indent();
+
+  if (field->real_containing_oneof()) {
+    // Clear this field only if it is the active field in this oneof,
+    // otherwise ignore
+    format("if (_internal_has_$name$()) {\n");
+    format.Indent();
+    field_generators_.get(field).GenerateClearingCode(format.printer());
+    format("clear_has_$oneof_name$();\n");
+    format.Outdent();
+    format("}\n");
+  } else {
+    if (ShouldSplit(field, options_)) {
+      format("if (IsSplitMessageDefault()) return;\n");
+    }
+    field_generators_.get(field).GenerateClearingCode(format.printer());
+    if (HasHasbit(field)) {
+      int has_bit_index = HasBitIndex(field);
+      format.Set("has_array_index", has_bit_index / 32);
+      format.Set("has_mask",
+                 strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
+      format("$has_bits$[$has_array_index$] &= ~0x$has_mask$u;\n");
+    }
+  }
+  format("$annotate_clear$");
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format("// $classname$\n\n");
+
+  for (auto field : FieldRange(descriptor_)) {
+    PrintFieldComment(format, field);
+
+    if (IsFieldStripped(field, options_)) {
+      continue;
+    }
+
+    std::map<std::string, std::string> vars;
+    SetCommonFieldVariables(field, &vars, options_);
+
+    Formatter::SaveState saver(&format);
+    format.AddMap(vars);
+
+    // Generate has_$name$() or $name$_size().
+    if (field->is_repeated()) {
+      if (IsFieldStripped(field, options_)) {
+        format(
+            "inline int $classname$::$name$_size() const { "
+            "__builtin_trap(); }\n");
+      } else {
+        format(
+            "inline int $classname$::_internal_$name$_size() const {\n"
+            "  return $field$$1$.size();\n"
+            "}\n"
+            "inline int $classname$::$name$_size() const {\n"
+            "$annotate_size$"
+            "  return _internal_$name$_size();\n"
+            "}\n",
+            IsImplicitWeakField(field, options_, scc_analyzer_) &&
+                    field->message_type()
+                ? ".weak"
+                : "");
+      }
+    } else if (field->real_containing_oneof()) {
+      format.Set("field_name", UnderscoresToCamelCase(field->name(), true));
+      format.Set("oneof_name", field->containing_oneof()->name());
+      format.Set("oneof_index",
+                 StrCat(field->containing_oneof()->index()));
+      GenerateOneofMemberHasBits(field, format);
+    } else {
+      // Singular field.
+      GenerateSingularFieldHasBits(field, format);
+    }
+
+    if (!IsCrossFileMaybeMap(field)) {
+      GenerateFieldClear(field, true, format);
+    }
+
+    // Generate type-specific accessors.
+    if (!IsFieldStripped(field, options_)) {
+      field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
+    }
+
+    format("\n");
+  }
+
+  // Generate has_$name$() and clear_has_$name$() functions for oneofs.
+  GenerateOneofHasBits(printer);
+}
+
+void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format.Set("class_final",
+             ShouldMarkClassAsFinal(descriptor_, options_) ? "final" : "");
+
+  if (IsMapEntryMessage(descriptor_)) {
+    std::map<std::string, std::string> vars;
+    CollectMapInfo(options_, descriptor_, &vars);
+    vars["lite"] =
+        HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite";
+    format.AddMap(vars);
+    format(
+        "class $classname$ : public "
+        "::$proto_ns$::internal::MapEntry$lite$<$classname$, \n"
+        "    $key_cpp$, $val_cpp$,\n"
+        "    ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
+        "    ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> {\n"
+        "public:\n"
+        "  typedef ::$proto_ns$::internal::MapEntry$lite$<$classname$, \n"
+        "    $key_cpp$, $val_cpp$,\n"
+        "    ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
+        "    ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> "
+        "SuperType;\n"
+        "  $classname$();\n"
+        "  explicit PROTOBUF_CONSTEXPR $classname$(\n"
+        "      ::$proto_ns$::internal::ConstantInitialized);\n"
+        "  explicit $classname$(::$proto_ns$::Arena* arena);\n"
+        "  void MergeFrom(const $classname$& other);\n"
+        "  static const $classname$* internal_default_instance() { return "
+        "reinterpret_cast<const "
+        "$classname$*>(&_$classname$_default_instance_); }\n");
+    auto utf8_check = GetUtf8CheckMode(descriptor_->field(0), options_);
+    if (descriptor_->field(0)->type() == FieldDescriptor::TYPE_STRING &&
+        utf8_check != Utf8CheckMode::kNone) {
+      if (utf8_check == Utf8CheckMode::kStrict) {
+        format(
+            "  static bool ValidateKey(std::string* s) {\n"
+            "    return ::$proto_ns$::internal::WireFormatLite::"
+            "VerifyUtf8String(s->data(), static_cast<int>(s->size()), "
+            "::$proto_ns$::internal::WireFormatLite::PARSE, \"$1$\");\n"
+            " }\n",
+            descriptor_->field(0)->full_name());
+      } else {
+        GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify);
+        format(
+            "  static bool ValidateKey(std::string* s) {\n"
+            "#ifndef NDEBUG\n"
+            "    ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n"
+            "       s->data(), static_cast<int>(s->size()), "
+            "::$proto_ns$::internal::"
+            "WireFormatLite::PARSE, \"$1$\");\n"
+            "#else\n"
+            "    (void) s;\n"
+            "#endif\n"
+            "    return true;\n"
+            " }\n",
+            descriptor_->field(0)->full_name());
+      }
+    } else {
+      format("  static bool ValidateKey(void*) { return true; }\n");
+    }
+    if (descriptor_->field(1)->type() == FieldDescriptor::TYPE_STRING &&
+        utf8_check != Utf8CheckMode::kNone) {
+      if (utf8_check == Utf8CheckMode::kStrict) {
+        format(
+            "  static bool ValidateValue(std::string* s) {\n"
+            "    return ::$proto_ns$::internal::WireFormatLite::"
+            "VerifyUtf8String(s->data(), static_cast<int>(s->size()), "
+            "::$proto_ns$::internal::WireFormatLite::PARSE, \"$1$\");\n"
+            " }\n",
+            descriptor_->field(1)->full_name());
+      } else {
+        GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify);
+        format(
+            "  static bool ValidateValue(std::string* s) {\n"
+            "#ifndef NDEBUG\n"
+            "    ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n"
+            "       s->data(), static_cast<int>(s->size()), "
+            "::$proto_ns$::internal::"
+            "WireFormatLite::PARSE, \"$1$\");\n"
+            "#else\n"
+            "    (void) s;\n"
+            "#endif\n"
+            "    return true;\n"
+            " }\n",
+            descriptor_->field(1)->full_name());
+      }
+    } else {
+      format("  static bool ValidateValue(void*) { return true; }\n");
+    }
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      format(
+          "  using ::$proto_ns$::Message::MergeFrom;\n"
+          ""
+          "  ::$proto_ns$::Metadata GetMetadata() const final;\n");
+    }
+    format(
+        "  friend struct ::$tablename$;\n"
+        "};\n");
+    return;
+  }
+
+  format(
+      "class $dllexport_decl $${1$$classname$$}$$ class_final$ :\n"
+      "    public $superclass$ /* @@protoc_insertion_point("
+      "class_definition:$full_name$) */ {\n",
+      descriptor_);
+  format(" public:\n");
+  format.Indent();
+
+  if (EnableMessageOwnedArena(descriptor_, options_)) {
+    format(
+        "inline $classname$() : $classname$("
+        "::$proto_ns$::Arena::InternalCreateMessageOwnedArena(), true) {}\n");
+  } else if (EnableMessageOwnedArenaTrial(descriptor_, options_)) {
+    format(
+        "inline $classname$() : $classname$(InMoaTrial() ? "
+        "::$proto_ns$::Arena::InternalCreateMessageOwnedArena() : nullptr, "
+        "InMoaTrial()) {}\n");
+  } else {
+    format("inline $classname$() : $classname$(nullptr) {}\n");
+  }
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format("~$classname$() override;\n");
+  }
+  format(
+      "explicit PROTOBUF_CONSTEXPR "
+      "$classname$(::$proto_ns$::internal::ConstantInitialized);\n"
+      "\n"
+      "$classname$(const $classname$& from);\n"
+      "$classname$($classname$&& from) noexcept\n"
+      "  : $classname$() {\n"
+      "  *this = ::std::move(from);\n"
+      "}\n"
+      "\n"
+      "inline $classname$& operator=(const $classname$& from) {\n"
+      "  CopyFrom(from);\n"
+      "  return *this;\n"
+      "}\n"
+      "inline $classname$& operator=($classname$&& from) noexcept {\n"
+      "  if (this == &from) return *this;\n"
+      "  if (GetOwningArena() == from.GetOwningArena()\n"
+      "#ifdef PROTOBUF_FORCE_COPY_IN_MOVE\n"
+      "      && GetOwningArena() != nullptr\n"
+      "#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE\n"
+      "  ) {\n"
+      "    InternalSwap(&from);\n"
+      "  } else {\n"
+      "    CopyFrom(from);\n"
+      "  }\n"
+      "  return *this;\n"
+      "}\n"
+      "\n");
+
+  if (PublicUnknownFieldsAccessors(descriptor_)) {
+    format(
+        "inline const $unknown_fields_type$& unknown_fields() const {\n"
+        "  return $unknown_fields$;\n"
+        "}\n"
+        "inline $unknown_fields_type$* mutable_unknown_fields() {\n"
+        "  return $mutable_unknown_fields$;\n"
+        "}\n"
+        "\n");
+  }
+
+  // Only generate this member if it's not disabled.
+  if (HasDescriptorMethods(descriptor_->file(), options_) &&
+      !descriptor_->options().no_standard_descriptor_accessor()) {
+    format(
+        "static const ::$proto_ns$::Descriptor* descriptor() {\n"
+        "  return GetDescriptor();\n"
+        "}\n");
+  }
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    // These shadow non-static methods of the same names in Message.  We
+    // redefine them here because calls directly on the generated class can be
+    // statically analyzed -- we know what descriptor types are being requested.
+    // It also avoids a vtable dispatch.
+    //
+    // We would eventually like to eliminate the methods in Message, and having
+    // this separate also lets us track calls to the base class methods
+    // separately.
+    format(
+        "static const ::$proto_ns$::Descriptor* GetDescriptor() {\n"
+        "  return default_instance().GetMetadata().descriptor;\n"
+        "}\n"
+        "static const ::$proto_ns$::Reflection* GetReflection() {\n"
+        "  return default_instance().GetMetadata().reflection;\n"
+        "}\n");
+  }
+
+  format(
+      "static const $classname$& default_instance() {\n"
+      "  return *internal_default_instance();\n"
+      "}\n");
+
+  // Generate enum values for every field in oneofs. One list is generated for
+  // each oneof with an additional *_NOT_SET value.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format("enum $1$Case {\n", UnderscoresToCamelCase(oneof->name(), true));
+    format.Indent();
+    for (auto field : FieldRange(oneof)) {
+      format("$1$ = $2$,\n", OneofCaseConstantName(field),  // 1
+             field->number());                              // 2
+    }
+    format("$1$_NOT_SET = 0,\n", ToUpper(oneof->name()));
+    format.Outdent();
+    format(
+        "};\n"
+        "\n");
+  }
+
+  // TODO(gerbens) make this private, while still granting other protos access.
+  format(
+      "static inline const $classname$* internal_default_instance() {\n"
+      "  return reinterpret_cast<const $classname$*>(\n"
+      "             &_$classname$_default_instance_);\n"
+      "}\n"
+      "static constexpr int kIndexInFileMessages =\n"
+      "  $1$;\n"
+      "\n",
+      index_in_file_messages_);
+
+  if (IsAnyMessage(descriptor_, options_)) {
+    format(
+        "// implements Any -----------------------------------------------\n"
+        "\n");
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      format(
+          "bool PackFrom(const ::$proto_ns$::Message& message) {\n"
+          "  $DCHK$_NE(&message, this);\n"
+          "  return $any_metadata$.PackFrom(GetArena(), message);\n"
+          "}\n"
+          "bool PackFrom(const ::$proto_ns$::Message& message,\n"
+          "              ::PROTOBUF_NAMESPACE_ID::ConstStringParam "
+          "type_url_prefix) {\n"
+          "  $DCHK$_NE(&message, this);\n"
+          "  return $any_metadata$.PackFrom(GetArena(), message, "
+          "type_url_prefix);\n"
+          "}\n"
+          "bool UnpackTo(::$proto_ns$::Message* message) const {\n"
+          "  return $any_metadata$.UnpackTo(message);\n"
+          "}\n"
+          "static bool GetAnyFieldDescriptors(\n"
+          "    const ::$proto_ns$::Message& message,\n"
+          "    const ::$proto_ns$::FieldDescriptor** type_url_field,\n"
+          "    const ::$proto_ns$::FieldDescriptor** value_field);\n"
+          "template <typename T, class = typename std::enable_if<"
+          "!std::is_convertible<T, const ::$proto_ns$::Message&>"
+          "::value>::type>\n"
+          "bool PackFrom(const T& message) {\n"
+          "  return $any_metadata$.PackFrom<T>(GetArena(), message);\n"
+          "}\n"
+          "template <typename T, class = typename std::enable_if<"
+          "!std::is_convertible<T, const ::$proto_ns$::Message&>"
+          "::value>::type>\n"
+          "bool PackFrom(const T& message,\n"
+          "              ::PROTOBUF_NAMESPACE_ID::ConstStringParam "
+          "type_url_prefix) {\n"
+          "  return $any_metadata$.PackFrom<T>(GetArena(), message, "
+          "type_url_prefix);"
+          "}\n"
+          "template <typename T, class = typename std::enable_if<"
+          "!std::is_convertible<T, const ::$proto_ns$::Message&>"
+          "::value>::type>\n"
+          "bool UnpackTo(T* message) const {\n"
+          "  return $any_metadata$.UnpackTo<T>(message);\n"
+          "}\n");
+    } else {
+      format(
+          "template <typename T>\n"
+          "bool PackFrom(const T& message) {\n"
+          "  return $any_metadata$.PackFrom(GetArena(), message);\n"
+          "}\n"
+          "template <typename T>\n"
+          "bool PackFrom(const T& message,\n"
+          "              ::PROTOBUF_NAMESPACE_ID::ConstStringParam "
+          "type_url_prefix) {\n"
+          "  return $any_metadata$.PackFrom(GetArena(), message, "
+          "type_url_prefix);\n"
+          "}\n"
+          "template <typename T>\n"
+          "bool UnpackTo(T* message) const {\n"
+          "  return $any_metadata$.UnpackTo(message);\n"
+          "}\n");
+    }
+    format(
+        "template<typename T> bool Is() const {\n"
+        "  return $any_metadata$.Is<T>();\n"
+        "}\n"
+        "static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam "
+        "type_url,\n"
+        "                            std::string* full_type_name);\n");
+  }
+
+  format(
+      "friend void swap($classname$& a, $classname$& b) {\n"
+      "  a.Swap(&b);\n"
+      "}\n"
+      "inline void Swap($classname$* other) {\n"
+      "  if (other == this) return;\n"
+      "#ifdef PROTOBUF_FORCE_COPY_IN_SWAP\n"
+      "  if (GetOwningArena() != nullptr &&\n"
+      "      GetOwningArena() == other->GetOwningArena()) {\n "
+      "#else  // PROTOBUF_FORCE_COPY_IN_SWAP\n"
+      "  if (GetOwningArena() == other->GetOwningArena()) {\n"
+      "#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP\n"
+      "    InternalSwap(other);\n"
+      "  } else {\n"
+      "    ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);\n"
+      "  }\n"
+      "}\n"
+      "void UnsafeArenaSwap($classname$* other) {\n"
+      "  if (other == this) return;\n"
+      "  $DCHK$(GetOwningArena() == other->GetOwningArena());\n"
+      "  InternalSwap(other);\n"
+      "}\n");
+
+  format(
+      "\n"
+      "// implements Message ----------------------------------------------\n"
+      "\n"
+      "$classname$* New(::$proto_ns$::Arena* arena = nullptr) const final {\n"
+      "  return CreateMaybeMessage<$classname$>(arena);\n"
+      "}\n");
+
+  // For instances that derive from Message (rather than MessageLite), some
+  // methods are virtual and should be marked as final.
+  format.Set("full_final", HasDescriptorMethods(descriptor_->file(), options_)
+                               ? "final"
+                               : "");
+
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      if (!HasSimpleBaseClass(descriptor_, options_)) {
+        format(
+            // Use Message's built-in MergeFrom and CopyFrom when the passed-in
+            // argument is a generic Message instance, and only define the
+            // custom MergeFrom and CopyFrom instances when the source of the
+            // merge/copy is known to be the same class as the destination.
+            "using $superclass$::CopyFrom;\n"
+            "void CopyFrom(const $classname$& from);\n"
+            ""
+            "using $superclass$::MergeFrom;\n"
+            "void MergeFrom("
+            " const $classname$& from) {\n"
+            "  $classname$::MergeImpl(*this, from);\n"
+            "}\n"
+            "private:\n"
+            "static void MergeImpl(::$proto_ns$::Message& to_msg, const "
+            "::$proto_ns$::Message& from_msg);\n"
+            "public:\n");
+      } else {
+        format(
+            "using $superclass$::CopyFrom;\n"
+            "inline void CopyFrom(const $classname$& from) {\n"
+            "  $superclass$::CopyImpl(*this, from);\n"
+            "}\n"
+            ""
+            "using $superclass$::MergeFrom;\n"
+            "void MergeFrom(const $classname$& from) {\n"
+            "  $superclass$::MergeImpl(*this, from);\n"
+            "}\n"
+            "public:\n");
+      }
+    } else {
+      format(
+          "void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)"
+          "  final;\n"
+          "void CopyFrom(const $classname$& from);\n"
+          "void MergeFrom(const $classname$& from);\n");
+    }
+
+    if (!HasSimpleBaseClass(descriptor_, options_)) {
+      format(
+          "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n"
+          "bool IsInitialized() const final;\n"
+          "\n"
+          "size_t ByteSizeLong() const final;\n");
+
+      parse_function_generator_->GenerateMethodDecls(printer);
+
+      format(
+          "$uint8$* _InternalSerialize(\n"
+          "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+          "const final;\n");
+    }
+  }
+
+  if (options_.field_listener_options.inject_field_listener_events) {
+    format("static constexpr int _kInternalFieldNumber = $1$;\n",
+           descriptor_->field_count());
+  }
+
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format(
+        "int GetCachedSize() const final { return "
+        "$cached_size$.Get(); }"
+        "\n\nprivate:\n"
+        "void SharedCtor(::$proto_ns$::Arena* arena, bool is_message_owned);\n"
+        "void SharedDtor();\n"
+        "void SetCachedSize(int size) const$ full_final$;\n"
+        "void InternalSwap($classname$* other);\n");
+  }
+
+  format(
+      // Friend AnyMetadata so that it can call this FullMessageName() method.
+      "\nprivate:\n"
+      "friend class ::$proto_ns$::internal::AnyMetadata;\n"
+      "static $1$ FullMessageName() {\n"
+      "  return \"$full_name$\";\n"
+      "}\n",
+      options_.opensource_runtime ? "::PROTOBUF_NAMESPACE_ID::StringPiece"
+                                  : "::StringPiece");
+
+  format(
+      // TODO(gerbens) Make this private! Currently people are deriving from
+      // protos to give access to this constructor, breaking the invariants
+      // we rely on.
+      "protected:\n"
+      "explicit $classname$(::$proto_ns$::Arena* arena,\n"
+      "                     bool is_message_owned = false);\n");
+
+  switch (NeedsArenaDestructor()) {
+    case ArenaDtorNeeds::kOnDemand:
+      format(
+          "private:\n"
+          "static void ArenaDtor(void* object);\n"
+          "inline void OnDemandRegisterArenaDtor(::$proto_ns$::Arena* arena) "
+          "override {\n"
+          "  if (arena == nullptr || ($inlined_string_donated_array$[0] & "
+          "0x1u) "
+          "== "
+          "0) {\n"
+          "   return;\n"
+          "  }\n"
+          "  $inlined_string_donated_array$[0] &= 0xFFFFFFFEu;\n"
+          "  arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+          "}\n");
+      break;
+    case ArenaDtorNeeds::kRequired:
+      format(
+          "private:\n"
+          "static void ArenaDtor(void* object);\n");
+      break;
+    case ArenaDtorNeeds::kNone:
+      break;
+  }
+
+  format(
+      "public:\n"
+      "\n");
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    if (HasGeneratedMethods(descriptor_->file(), options_)) {
+      format(
+          "static const ClassData _class_data_;\n"
+          "const ::$proto_ns$::Message::ClassData*"
+          "GetClassData() const final;\n"
+          "\n");
+    }
+    format(
+        "::$proto_ns$::Metadata GetMetadata() const final;\n"
+        "\n");
+  } else {
+    format(
+        "std::string GetTypeName() const final;\n"
+        "\n");
+  }
+
+  if (ShouldSplit(descriptor_, options_)) {
+    format(
+        "private:\n"
+        "inline bool IsSplitMessageDefault() const {\n"
+        "  return $split$ == reinterpret_cast<Impl_::Split*>(&$1$);\n"
+        "}\n"
+        "PROTOBUF_NOINLINE void PrepareSplitMessageForWrite();\n"
+        "public:\n",
+        DefaultInstanceName(descriptor_, options_, /*split=*/true));
+  }
+
+  format(
+      "// nested types ----------------------------------------------------\n"
+      "\n");
+
+  // Import all nested message classes into this class's scope with typedefs.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    const Descriptor* nested_type = descriptor_->nested_type(i);
+    if (!IsMapEntryMessage(nested_type)) {
+      format.Set("nested_full_name", ClassName(nested_type, false));
+      format.Set("nested_name", ResolveKeyword(nested_type->name()));
+      format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n",
+             nested_type);
+    }
+  }
+
+  if (descriptor_->nested_type_count() > 0) {
+    format("\n");
+  }
+
+  // Import all nested enums and their values into this class's scope with
+  // typedefs and constants.
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    enum_generators_[i]->GenerateSymbolImports(printer);
+    format("\n");
+  }
+
+  format(
+      "// accessors -------------------------------------------------------\n"
+      "\n");
+
+  // Generate accessor methods for all fields.
+  GenerateFieldAccessorDeclarations(printer);
+
+  // Declare extension identifiers.
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    extension_generators_[i]->GenerateDeclaration(printer);
+  }
+
+
+  format("// @@protoc_insertion_point(class_scope:$full_name$)\n");
+
+  // Generate private members.
+  format.Outdent();
+  format(" private:\n");
+  format.Indent();
+  // TODO(seongkim): Remove hack to track field access and remove this class.
+  format("class _Internal;\n");
+
+  for (auto field : FieldRange(descriptor_)) {
+    // set_has_***() generated in all oneofs.
+    if (!field->is_repeated() && !field->options().weak() &&
+        field->real_containing_oneof()) {
+      format("void set_has_$1$();\n", FieldName(field));
+    }
+  }
+  format("\n");
+
+  // Generate oneof function declarations
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format(
+        "inline bool has_$1$() const;\n"
+        "inline void clear_has_$1$();\n\n",
+        oneof->name());
+  }
+
+  if (HasGeneratedMethods(descriptor_->file(), options_) &&
+      !descriptor_->options().message_set_wire_format() &&
+      num_required_fields_ > 1) {
+    format(
+        "// helper for ByteSizeLong()\n"
+        "size_t RequiredFieldsByteSizeFallback() const;\n\n");
+  }
+
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
+    parse_function_generator_->GenerateDataDecls(printer);
+  }
+
+  // Prepare decls for _cached_size_ and _has_bits_.  Their position in the
+  // output will be determined later.
+
+  bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_);
+  const std::string cached_size_decl =
+      "mutable ::$proto_ns$::internal::CachedSize _cached_size_;\n";
+
+  const size_t sizeof_has_bits = HasBitsSize();
+  const std::string has_bits_decl =
+      sizeof_has_bits == 0 ? ""
+                           : StrCat("::$proto_ns$::internal::HasBits<",
+                                          sizeof_has_bits, "> _has_bits_;\n");
+
+  format(
+      "template <typename T> friend class "
+      "::$proto_ns$::Arena::InternalHelper;\n"
+      "typedef void InternalArenaConstructable_;\n"
+      "typedef void DestructorSkippable_;\n");
+
+  // To minimize padding, data members are divided into three sections:
+  // (1) members assumed to align to 8 bytes
+  // (2) members corresponding to message fields, re-ordered to optimize
+  //     alignment.
+  // (3) members assumed to align to 4 bytes.
+
+  format("struct Impl_ {\n");
+  format.Indent();
+
+  // Members assumed to align to 8 bytes:
+
+  if (descriptor_->extension_range_count() > 0) {
+    format(
+        "::$proto_ns$::internal::ExtensionSet _extensions_;\n"
+        "\n");
+  }
+
+  if (HasTracker(descriptor_, options_)) {
+    format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n",
+           ClassName(descriptor_));
+  }
+
+  // Generate _inlined_string_donated_ for inlined string type.
+  // TODO(congliu): To avoid affecting the locality of `_has_bits_`, should this
+  // be below or above `_has_bits_`?
+  if (!inlined_string_indices_.empty()) {
+    format("::$proto_ns$::internal::HasBits<$1$> _inlined_string_donated_;\n",
+           InlinedStringDonatedSize());
+  }
+
+  if (!has_bit_indices_.empty()) {
+    // _has_bits_ is frequently accessed, so to reduce code size and improve
+    // speed, it should be close to the start of the object. Placing
+    // _cached_size_ together with _has_bits_ improves cache locality despite
+    // potential alignment padding.
+    format(has_bits_decl.c_str());
+    if (need_to_emit_cached_size) {
+      format(cached_size_decl.c_str());
+      need_to_emit_cached_size = false;
+    }
+  }
+
+  // Field members:
+
+  // Emit some private and static members
+  for (auto field : optimized_order_) {
+    const FieldGenerator& generator = field_generators_.get(field);
+    generator.GenerateStaticMembers(printer);
+    if (!ShouldSplit(field, options_)) {
+      generator.GeneratePrivateMembers(printer);
+    }
+  }
+  if (ShouldSplit(descriptor_, options_)) {
+    format("struct Split {\n");
+    format.Indent();
+    for (auto field : optimized_order_) {
+      if (!ShouldSplit(field, options_)) continue;
+      const FieldGenerator& generator = field_generators_.get(field);
+      generator.GeneratePrivateMembers(printer);
+    }
+    format.Outdent();
+    format(
+        "  typedef void InternalArenaConstructable_;\n"
+        "  typedef void DestructorSkippable_;\n"
+        "};\n"
+        "Split* _split_;\n");
+  }
+
+  // For each oneof generate a union
+  for (auto oneof : OneOfRange(descriptor_)) {
+    std::string camel_oneof_name = UnderscoresToCamelCase(oneof->name(), true);
+    format("union $1$Union {\n", camel_oneof_name);
+    format.Indent();
+    format(
+        // explicit empty constructor is needed when union contains
+        // ArenaStringPtr members for string fields.
+        "constexpr $1$Union() : _constinit_{} {}\n"
+        "  ::$proto_ns$::internal::ConstantInitialized _constinit_;\n",
+        camel_oneof_name);
+    for (auto field : FieldRange(oneof)) {
+      if (!IsFieldStripped(field, options_)) {
+        field_generators_.get(field).GeneratePrivateMembers(printer);
+      }
+    }
+    format.Outdent();
+    format("} $1$_;\n", oneof->name());
+    for (auto field : FieldRange(oneof)) {
+      if (!IsFieldStripped(field, options_)) {
+        field_generators_.get(field).GenerateStaticMembers(printer);
+      }
+    }
+  }
+
+  // Members assumed to align to 4 bytes:
+
+  if (need_to_emit_cached_size) {
+    format(cached_size_decl.c_str());
+    need_to_emit_cached_size = false;
+  }
+
+  // Generate _oneof_case_.
+  if (descriptor_->real_oneof_decl_count() > 0) {
+    format(
+        "$uint32$ _oneof_case_[$1$];\n"
+        "\n",
+        descriptor_->real_oneof_decl_count());
+  }
+
+  if (num_weak_fields_) {
+    format("::$proto_ns$::internal::WeakFieldMap _weak_field_map_;\n");
+  }
+  // Generate _any_metadata_ for the Any type.
+  if (IsAnyMessage(descriptor_, options_)) {
+    format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n");
+  }
+
+  format.Outdent();
+  format("};\n");
+
+  // Only create the _impl_ field if it contains data.
+  if (HasImplData(descriptor_, options_)) {
+    format("union { Impl_ _impl_; };\n");
+  }
+
+  if (ShouldSplit(descriptor_, options_)) {
+    format(
+        "static Impl_::Split* CreateSplitMessage("
+        "::$proto_ns$::Arena* arena);\n");
+    format("friend struct $1$;\n",
+           DefaultInstanceType(descriptor_, options_, /*split=*/true));
+  }
+
+  // The TableStruct struct needs access to the private parts, in order to
+  // construct the offsets of all members.
+  format("friend struct ::$tablename$;\n");
+
+  format.Outdent();
+  format("};");
+  GOOGLE_DCHECK(!need_to_emit_cached_size);
+}  // NOLINT(readability/fn_size)
+
+void MessageGenerator::GenerateInlineMethods(io::Printer* printer) {
+  if (IsMapEntryMessage(descriptor_)) return;
+  GenerateFieldAccessorDefinitions(printer);
+
+  // Generate oneof_case() functions.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    Formatter format(printer, variables_);
+    format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true));
+    format.Set("oneof_name", oneof->name());
+    format.Set("oneof_index", oneof->index());
+    format(
+        "inline $classname$::$camel_oneof_name$Case $classname$::"
+        "${1$$oneof_name$_case$}$() const {\n"
+        "  return $classname$::$camel_oneof_name$Case("
+        "$oneof_case$[$oneof_index$]);\n"
+        "}\n",
+        oneof);
+  }
+}
+
+void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
+                                      int has_offset) {
+  Formatter format(printer, variables_);
+  has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)
+                   ? offset + has_offset
+                   : -1;
+  int inlined_string_indices_offset;
+  if (inlined_string_indices_.empty()) {
+    inlined_string_indices_offset = -1;
+  } else {
+    GOOGLE_DCHECK_NE(has_offset, -1);
+    GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_));
+    inlined_string_indices_offset = has_offset + has_bit_indices_.size();
+  }
+
+  format("{ $1$, $2$, $3$, sizeof($classtype$)},\n", offset, has_offset,
+         inlined_string_indices_offset);
+}
+
+void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (IsMapEntryMessage(descriptor_)) {
+    format(
+        "$classname$::$classname$() {}\n"
+        "$classname$::$classname$(::$proto_ns$::Arena* arena)\n"
+        "    : SuperType(arena) {}\n"
+        "void $classname$::MergeFrom(const $classname$& other) {\n"
+        "  MergeFromInternal(other);\n"
+        "}\n");
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      if (!descriptor_->options().map_entry()) {
+        format(
+            "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+            "$annotate_reflection$"
+            "  return ::_pbi::AssignDescriptors(\n"
+            "      &$desc_table$_getter, &$desc_table$_once,\n"
+            "      $file_level_metadata$[$1$]);\n"
+            "}\n",
+            index_in_file_messages_);
+      } else {
+        format(
+            "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+            "  return ::_pbi::AssignDescriptors(\n"
+            "      &$desc_table$_getter, &$desc_table$_once,\n"
+            "      $file_level_metadata$[$1$]);\n"
+            "}\n",
+            index_in_file_messages_);
+      }
+    }
+    return;
+  }
+
+  if (IsAnyMessage(descriptor_, options_)) {
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      format(
+          "bool $classname$::GetAnyFieldDescriptors(\n"
+          "    const ::$proto_ns$::Message& message,\n"
+          "    const ::$proto_ns$::FieldDescriptor** type_url_field,\n"
+          "    const ::$proto_ns$::FieldDescriptor** value_field) {\n"
+          "  return ::_pbi::GetAnyFieldDescriptors(\n"
+          "      message, type_url_field, value_field);\n"
+          "}\n");
+    }
+    format(
+        "bool $classname$::ParseAnyTypeUrl(\n"
+        "    ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,\n"
+        "    std::string* full_type_name) {\n"
+        "  return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);\n"
+        "}\n"
+        "\n");
+  }
+
+  format(
+      "class $classname$::_Internal {\n"
+      " public:\n");
+  format.Indent();
+  if (!has_bit_indices_.empty()) {
+    format(
+        "using HasBits = "
+        "decltype(std::declval<$classname$>().$has_bits$);\n");
+  }
+  for (auto field : FieldRange(descriptor_)) {
+    field_generators_.get(field).GenerateInternalAccessorDeclarations(printer);
+    if (IsFieldStripped(field, options_)) {
+      continue;
+    }
+    if (HasHasbit(field)) {
+      int has_bit_index = HasBitIndex(field);
+      GOOGLE_CHECK_NE(has_bit_index, kNoHasbit) << field->full_name();
+      format(
+          "static void set_has_$1$(HasBits* has_bits) {\n"
+          "  (*has_bits)[$2$] |= $3$u;\n"
+          "}\n",
+          FieldName(field), has_bit_index / 32, (1u << (has_bit_index % 32)));
+    }
+  }
+  if (num_required_fields_ > 0) {
+    const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask();
+    format(
+        "static bool MissingRequiredFields(const HasBits& has_bits) "
+        "{\n"
+        "  return $1$;\n"
+        "}\n",
+        ConditionalToCheckBitmasks(masks_for_has_bits, false, "has_bits"));
+  }
+
+  format.Outdent();
+  format("};\n\n");
+  for (auto field : FieldRange(descriptor_)) {
+    if (!IsFieldStripped(field, options_)) {
+      field_generators_.get(field).GenerateInternalAccessorDefinitions(
+          printer);
+    }
+  }
+
+  // Generate non-inline field definitions.
+  for (auto field : FieldRange(descriptor_)) {
+    if (IsFieldStripped(field, options_)) {
+      continue;
+    }
+    field_generators_.get(field).GenerateNonInlineAccessorDefinitions(printer);
+    if (IsCrossFileMaybeMap(field)) {
+      Formatter::SaveState saver(&format);
+      std::map<std::string, std::string> vars;
+      SetCommonFieldVariables(field, &vars, options_);
+      if (field->real_containing_oneof()) {
+        SetCommonOneofFieldVariables(field, &vars);
+      }
+      format.AddMap(vars);
+      GenerateFieldClear(field, false, format);
+    }
+  }
+
+  GenerateStructors(printer);
+  format("\n");
+
+  if (descriptor_->real_oneof_decl_count() > 0) {
+    GenerateOneofClear(printer);
+    format("\n");
+  }
+
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
+    GenerateClear(printer);
+    format("\n");
+
+    if (!HasSimpleBaseClass(descriptor_, options_)) {
+      parse_function_generator_->GenerateMethodImpls(printer);
+      format("\n");
+
+      parse_function_generator_->GenerateDataDefinitions(printer);
+    }
+
+    GenerateSerializeWithCachedSizesToArray(printer);
+    format("\n");
+
+    GenerateByteSize(printer);
+    format("\n");
+
+    GenerateMergeFrom(printer);
+    format("\n");
+
+    GenerateClassSpecificMergeImpl(printer);
+    format("\n");
+
+    GenerateCopyFrom(printer);
+    format("\n");
+
+    GenerateIsInitialized(printer);
+    format("\n");
+  }
+
+  if (ShouldSplit(descriptor_, options_)) {
+    format(
+        "void $classname$::PrepareSplitMessageForWrite() {\n"
+        "  if (IsSplitMessageDefault()) {\n"
+        "    $split$ = CreateSplitMessage(GetArenaForAllocation());\n"
+        "  }\n"
+        "}\n");
+  }
+
+  GenerateVerify(printer);
+
+  GenerateSwap(printer);
+  format("\n");
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    if (!descriptor_->options().map_entry()) {
+      format(
+          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+          "$annotate_reflection$"
+          "  return ::_pbi::AssignDescriptors(\n"
+          "      &$desc_table$_getter, &$desc_table$_once,\n"
+          "      $file_level_metadata$[$1$]);\n"
+          "}\n",
+          index_in_file_messages_);
+    } else {
+      format(
+          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+          "  return ::_pbi::AssignDescriptors(\n"
+          "      &$desc_table$_getter, &$desc_table$_once,\n"
+          "      $file_level_metadata$[$1$]);\n"
+          "}\n",
+          index_in_file_messages_);
+    }
+  } else {
+    format(
+        "std::string $classname$::GetTypeName() const {\n"
+        "  return \"$full_name$\";\n"
+        "}\n"
+        "\n");
+  }
+
+  if (HasTracker(descriptor_, options_)) {
+    format(
+        "::$proto_ns$::AccessListener<$classtype$> "
+        "$1$::$tracker$(&FullMessageName);\n",
+        ClassName(descriptor_));
+  }
+}
+
+std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
+    io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)) {
+    format("PROTOBUF_FIELD_OFFSET($classtype$, $has_bits$),\n");
+  } else {
+    format("~0u,  // no _has_bits_\n");
+  }
+  format("PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n");
+  if (descriptor_->extension_range_count() > 0) {
+    format("PROTOBUF_FIELD_OFFSET($classtype$, $extensions$),\n");
+  } else {
+    format("~0u,  // no _extensions_\n");
+  }
+  if (descriptor_->real_oneof_decl_count() > 0) {
+    format("PROTOBUF_FIELD_OFFSET($classtype$, $oneof_case$[0]),\n");
+  } else {
+    format("~0u,  // no _oneof_case_\n");
+  }
+  if (num_weak_fields_ > 0) {
+    format("PROTOBUF_FIELD_OFFSET($classtype$, $weak_field_map$),\n");
+  } else {
+    format("~0u,  // no _weak_field_map_\n");
+  }
+  if (!inlined_string_indices_.empty()) {
+    format(
+        "PROTOBUF_FIELD_OFFSET($classtype$, "
+        "$inlined_string_donated_array$),\n");
+  } else {
+    format("~0u,  // no _inlined_string_donated_\n");
+  }
+  const int kNumGenericOffsets = 6;  // the number of fixed offsets above
+  const size_t offsets = kNumGenericOffsets + descriptor_->field_count() +
+                         descriptor_->real_oneof_decl_count();
+  size_t entries = offsets;
+  for (auto field : FieldRange(descriptor_)) {
+    if (IsFieldStripped(field, options_)) {
+      format("~0u,  // stripped\n");
+      continue;
+    }
+    // TODO(sbenza): We should not have an entry in the offset table for fields
+    // that do not use them.
+    if (field->options().weak() || field->real_containing_oneof()) {
+      // Mark the field to prevent unintentional access through reflection.
+      // Don't use the top bit because that is for unused fields.
+      format("::_pbi::kInvalidFieldOffsetTag");
+    } else {
+      format("PROTOBUF_FIELD_OFFSET($classtype$$1$, $2$)",
+             ShouldSplit(field, options_) ? "::Impl_::Split" : "",
+             ShouldSplit(field, options_)
+                 ? FieldName(field) + "_"
+                 : FieldMemberName(field, /*cold=*/false));
+    }
+
+    // Some information about a field is in the pdproto profile. The profile is
+    // only available at compile time. So we embed such information in the
+    // offset of the field, so that the information is available when
+    // reflectively accessing the field at run time.
+    //
+    // Embed whether the field is eagerly verified lazy or inlined string to the
+    // LSB of the offset.
+    if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) {
+      format(" | 0x1u  // eagerly verified lazy\n");
+    } else if (IsStringInlined(field, options_)) {
+      format(" | 0x1u  // inlined\n");
+    }
+    format(",\n");
+  }
+
+  int count = 0;
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format("PROTOBUF_FIELD_OFFSET($classtype$, _impl_.$1$_),\n", oneof->name());
+    count++;
+  }
+  GOOGLE_CHECK_EQ(count, descriptor_->real_oneof_decl_count());
+
+  if (IsMapEntryMessage(descriptor_)) {
+    entries += 2;
+    format(
+        "0,\n"
+        "1,\n");
+  } else if (!has_bit_indices_.empty()) {
+    entries += has_bit_indices_.size();
+    for (int i = 0; i < has_bit_indices_.size(); i++) {
+      const std::string index =
+          has_bit_indices_[i] >= 0 ? StrCat(has_bit_indices_[i]) : "~0u";
+      format("$1$,\n", index);
+    }
+  }
+  if (!inlined_string_indices_.empty()) {
+    entries += inlined_string_indices_.size();
+    for (int inlined_string_index : inlined_string_indices_) {
+      const std::string index =
+          inlined_string_index >= 0
+              ? StrCat(inlined_string_index, ",  // inlined_string_index")
+              : "~0u,";
+      format("$1$\n", index);
+    }
+  }
+
+  return std::make_pair(entries, offsets);
+}
+
+void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+
+  format(
+      "inline void $classname$::SharedCtor(\n"
+      "    ::_pb::Arena* arena, bool is_message_owned) {\n"
+      "  (void)arena;\n"
+      "  (void)is_message_owned;\n");
+
+  format.Indent();
+  // Impl_ _impl_.
+  format("new (&_impl_) Impl_{");
+  format.Indent();
+  const char* field_sep = " ";
+  const auto put_sep = [&] {
+    format("\n$1$ ", field_sep);
+    field_sep = ",";
+  };
+
+  // Note: any fields without move/copy constructors can't be explicitly
+  // aggregate initialized pre-C++17.
+  if (descriptor_->extension_range_count() > 0) {
+    put_sep();
+    format("/*decltype($extensions$)*/{::_pbi::ArenaInitialized(), arena}");
+  }
+  if (!inlined_string_indices_.empty()) {
+    put_sep();
+    format("decltype($inlined_string_donated_array$){}");
+  }
+  bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_);
+  if (!has_bit_indices_.empty()) {
+    put_sep();
+    format("decltype($has_bits$){}");
+    if (need_to_emit_cached_size) {
+      put_sep();
+      format("/*decltype($cached_size$)*/{}");
+      need_to_emit_cached_size = false;
+    }
+  }
+
+  // Initialize member variables with arena constructor.
+  for (auto field : optimized_order_) {
+    GOOGLE_DCHECK(!IsFieldStripped(field, options_));
+    if (ShouldSplit(field, options_)) {
+      continue;
+    }
+    put_sep();
+    field_generators_.get(field).GenerateAggregateInitializer(printer);
+  }
+  if (ShouldSplit(descriptor_, options_)) {
+    put_sep();
+    format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
+           DefaultInstanceName(descriptor_, options_, /*split=*/true));
+  }
+  for (auto oneof : OneOfRange(descriptor_)) {
+    put_sep();
+    format("decltype(_impl_.$1$_){}", oneof->name());
+  }
+
+  if (need_to_emit_cached_size) {
+    put_sep();
+    format("/*decltype($cached_size$)*/{}");
+  }
+
+  if (descriptor_->real_oneof_decl_count() != 0) {
+    put_sep();
+    format("/*decltype($oneof_case$)*/{}");
+  }
+  if (num_weak_fields_ > 0) {
+    put_sep();
+    format("decltype($weak_field_map$){arena}");
+  }
+  if (IsAnyMessage(descriptor_, options_)) {
+    put_sep();
+    // AnyMetadata has no move constructor.
+    format("/*decltype($any_metadata$)*/{&_impl_.type_url_, &_impl_.value_}");
+  }
+
+  format.Outdent();
+  format("\n};\n");
+
+  if (!inlined_string_indices_.empty()) {
+    // Donate inline string fields.
+    format.Indent();
+    // The last bit is the tracking bit for registering ArenaDtor. The bit is 1
+    // means ArenaDtor is not registered on construction, and on demand register
+    // is needed.
+    format("if (arena != nullptr) {\n");
+    if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) {
+      format(
+          "  if (!is_message_owned) {\n"
+          "    $inlined_string_donated_array$[0] = ~0u;\n"
+          "  } else {\n"
+          // We should not register ArenaDtor for MOA.
+          "    $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n"
+          "  }\n");
+    } else {
+      format("  $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n");
+    }
+    for (size_t i = 1; i < InlinedStringDonatedSize(); ++i) {
+      format("  $inlined_string_donated_array$[$1$] = ~0u;\n", i);
+    }
+    format("}\n");
+    format.Outdent();
+  }
+
+  for (const FieldDescriptor* field : optimized_order_) {
+    if (ShouldSplit(field, options_)) {
+      continue;
+    }
+    field_generators_.get(field).GenerateConstructorCode(printer);
+  }
+
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format("clear_has_$1$();\n", oneof->name());
+  }
+
+  format.Outdent();
+  format("}\n\n");
+}
+
+void MessageGenerator::GenerateCreateSplitMessage(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format(
+      "$classname$::Impl_::Split* "
+      "$classname$::CreateSplitMessage(::$proto_ns$::Arena* arena) {\n");
+  format.Indent();
+  const char* field_sep = " ";
+  const auto put_sep = [&] {
+    format("\n$1$ ", field_sep);
+    field_sep = ",";
+  };
+  format(
+      "const size_t size = sizeof(Impl_::Split);\n"
+      "void* chunk = (arena == nullptr) ?\n"
+      "  ::operator new(size) :\n"
+      "  arena->AllocateAligned(size, alignof(Impl_::Split));\n"
+      "Impl_::Split* ptr = reinterpret_cast<Impl_::Split*>(chunk);\n"
+      "new (ptr) Impl_::Split{");
+  format.Indent();
+  for (const FieldDescriptor* field : optimized_order_) {
+    GOOGLE_DCHECK(!IsFieldStripped(field, options_));
+    if (ShouldSplit(field, options_)) {
+      put_sep();
+      field_generators_.get(field).GenerateAggregateInitializer(printer);
+    }
+  }
+  format.Outdent();
+  format("};\n");
+  for (const FieldDescriptor* field : optimized_order_) {
+    GOOGLE_DCHECK(!IsFieldStripped(field, options_));
+    if (ShouldSplit(field, options_)) {
+      field_generators_.get(field).GenerateCreateSplitMessageCode(printer);
+    }
+  }
+  format("return ptr;\n");
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) {
+  if (!ShouldSplit(descriptor_, options_)) return;
+
+  Formatter format(printer, variables_);
+  const char* field_sep = " ";
+  const auto put_sep = [&] {
+    format("\n$1$ ", field_sep);
+    field_sep = ",";
+  };
+  for (const auto* field : optimized_order_) {
+    if (ShouldSplit(field, options_)) {
+      put_sep();
+      field_generators_.get(field).GenerateConstexprAggregateInitializer(
+          printer);
+    }
+  }
+}
+
+void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+
+  format("inline void $classname$::SharedDtor() {\n");
+  format.Indent();
+  format("$DCHK$(GetArenaForAllocation() == nullptr);\n");
+
+  if (descriptor_->extension_range_count() > 0) {
+    format("$extensions$.~ExtensionSet();\n");
+  }
+
+  // Write the destructors for each field except oneof members.
+  // optimized_order_ does not contain oneof fields.
+  for (auto field : optimized_order_) {
+    if (ShouldSplit(field, options_)) {
+      continue;
+    }
+    field_generators_.get(field).GenerateDestructorCode(printer);
+  }
+  if (ShouldSplit(descriptor_, options_)) {
+    format("if (!IsSplitMessageDefault()) {\n");
+    format.Indent();
+    format("auto* $cached_split_ptr$ = $split$;\n");
+    for (auto field : optimized_order_) {
+      if (ShouldSplit(field, options_)) {
+        field_generators_.get(field).GenerateDestructorCode(printer);
+      }
+    }
+    format("delete $cached_split_ptr$;\n");
+    format.Outdent();
+    format("}\n");
+  }
+
+  // Generate code to destruct oneofs. Clearing should do the work.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format(
+        "if (has_$1$()) {\n"
+        "  clear_$1$();\n"
+        "}\n",
+        oneof->name());
+  }
+
+  if (num_weak_fields_) {
+    format("$weak_field_map$.ClearAll();\n");
+  }
+
+  if (IsAnyMessage(descriptor_, options_)) {
+    format("$any_metadata$.~AnyMetadata();\n");
+  }
+
+  format.Outdent();
+  format(
+      "}\n"
+      "\n");
+}
+
+ArenaDtorNeeds MessageGenerator::NeedsArenaDestructor() const {
+  if (HasSimpleBaseClass(descriptor_, options_)) return ArenaDtorNeeds::kNone;
+  ArenaDtorNeeds needs = ArenaDtorNeeds::kNone;
+  for (const auto* field : FieldRange(descriptor_)) {
+    if (IsFieldStripped(field, options_)) continue;
+    needs =
+        std::max(needs, field_generators_.get(field).NeedsArenaDestructor());
+  }
+  return needs;
+}
+
+void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) {
+  GOOGLE_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone);
+
+  Formatter format(printer, variables_);
+
+  // Generate the ArenaDtor() method. Track whether any fields actually produced
+  // code that needs to be called.
+  format("void $classname$::ArenaDtor(void* object) {\n");
+  format.Indent();
+
+  // This code is placed inside a static method, rather than an ordinary one,
+  // since that simplifies Arena's destructor list (ordinary function pointers
+  // rather than member function pointers). _this is the object being
+  // destructed.
+  format("$classname$* _this = reinterpret_cast< $classname$* >(object);\n");
+
+  // Process non-oneof fields first.
+  for (auto field : optimized_order_) {
+    if (IsFieldStripped(field, options_) || ShouldSplit(field, options_))
+      continue;
+    const FieldGenerator& fg = field_generators_.get(field);
+    fg.GenerateArenaDestructorCode(printer);
+  }
+  if (ShouldSplit(descriptor_, options_)) {
+    format("if (!_this->IsSplitMessageDefault()) {\n");
+    format.Indent();
+    for (auto field : optimized_order_) {
+      if (IsFieldStripped(field, options_) || !ShouldSplit(field, options_))
+        continue;
+      const FieldGenerator& fg = field_generators_.get(field);
+      fg.GenerateArenaDestructorCode(printer);
+    }
+    format.Outdent();
+    format("}\n");
+  }
+
+  // Process oneof fields.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    for (auto field : FieldRange(oneof)) {
+      if (IsFieldStripped(field, options_)) continue;
+      field_generators_.get(field).GenerateArenaDestructorCode(printer);
+    }
+  }
+
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  if (IsMapEntryMessage(descriptor_) || !HasImplData(descriptor_, options_)) {
+    format(
+        "PROTOBUF_CONSTEXPR $classname$::$classname$(\n"
+        "    ::_pbi::ConstantInitialized) {}\n");
+    return;
+  }
+
+  format(
+      "PROTOBUF_CONSTEXPR $classname$::$classname$(\n"
+      "    ::_pbi::ConstantInitialized)");
+
+  bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_);
+  format(": _impl_{");
+  format.Indent();
+  const char* field_sep = " ";
+  const auto put_sep = [&] {
+    format("\n$1$ ", field_sep);
+    field_sep = ",";
+  };
+  if (descriptor_->extension_range_count() > 0) {
+    put_sep();
+    format("/*decltype($extensions$)*/{}");
+  }
+  if (!inlined_string_indices_.empty()) {
+    put_sep();
+    format("/*decltype($inlined_string_donated_array$)*/{}");
+  }
+  if (!has_bit_indices_.empty()) {
+    put_sep();
+    format("/*decltype($has_bits$)*/{}");
+    if (need_to_emit_cached_size) {
+      put_sep();
+      format("/*decltype($cached_size$)*/{}");
+      need_to_emit_cached_size = false;
+    }
+  }
+  for (auto field : optimized_order_) {
+    if (ShouldSplit(field, options_)) {
+      continue;
+    }
+    put_sep();
+    field_generators_.get(field).GenerateConstexprAggregateInitializer(
+        printer);
+  }
+  if (ShouldSplit(descriptor_, options_)) {
+    put_sep();
+    format("/*decltype($split$)*/&$1$._instance",
+           DefaultInstanceName(descriptor_, options_, /*split=*/true));
+  }
+
+  for (auto oneof : OneOfRange(descriptor_)) {
+    put_sep();
+    format("/*decltype(_impl_.$1$_)*/{}", oneof->name());
+  }
+
+  if (need_to_emit_cached_size) {
+    put_sep();
+    format("/*decltype($cached_size$)*/{}");
+  }
+
+  if (descriptor_->real_oneof_decl_count() != 0) {
+    put_sep();
+    format("/*decltype($oneof_case$)*/{}");
+  }
+
+  if (num_weak_fields_) {
+    put_sep();
+    format("/*decltype($weak_field_map$)*/{}");
+  }
+
+  if (IsAnyMessage(descriptor_, options_)) {
+    put_sep();
+    format(
+        "/*decltype($any_metadata$)*/{&_impl_.type_url_, "
+        "&_impl_.value_}");
+  }
+
+  format.Outdent();
+  format("} {}\n");
+}
+
+void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+
+  const RunMap runs =
+      FindRuns(optimized_order_, [this](const FieldDescriptor* field) {
+        return IsPOD(field) && !ShouldSplit(field, options_);
+      });
+
+  std::string pod_template =
+      "::memcpy(&$first$, &from.$first$,\n"
+      "  static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n"
+      "  reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n";
+
+  if (ShouldSplit(descriptor_, options_)) {
+    format("if (!from.IsSplitMessageDefault()) {\n");
+    format.Indent();
+    format("_this->PrepareSplitMessageForWrite();\n");
+    for (auto field : optimized_order_) {
+      if (ShouldSplit(field, options_)) {
+        field_generators_.get(field).GenerateCopyConstructorCode(printer);
+      }
+    }
+    format.Outdent();
+    format("}\n");
+  }
+
+  for (size_t i = 0; i < optimized_order_.size(); ++i) {
+    const FieldDescriptor* field = optimized_order_[i];
+    if (ShouldSplit(field, options_)) {
+      continue;
+    }
+    const auto it = runs.find(field);
+
+    // We only apply the memset technique to runs of more than one field, as
+    // assignment is better than memset for generated code clarity.
+    if (it != runs.end() && it->second > 1) {
+      // Use a memset, then skip run_length fields.
+      const size_t run_length = it->second;
+      const std::string first_field_name =
+          FieldMemberName(field, /*cold=*/false);
+      const std::string last_field_name =
+          FieldMemberName(optimized_order_[i + run_length - 1], /*cold=*/false);
+
+      format.Set("first", first_field_name);
+      format.Set("last", last_field_name);
+
+      format(pod_template.c_str());
+
+      i += run_length - 1;
+      // ++i at the top of the loop.
+    } else {
+      field_generators_.get(field).GenerateCopyConstructorCode(printer);
+    }
+  }
+}
+
+void MessageGenerator::GenerateStructors(io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  format(
+      "$classname$::$classname$(::$proto_ns$::Arena* arena,\n"
+      "                         bool is_message_owned)\n"
+      "  : $1$(arena, is_message_owned) {\n",
+      SuperClassName(descriptor_, options_));
+
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format("  SharedCtor(arena, is_message_owned);\n");
+    if (NeedsArenaDestructor() == ArenaDtorNeeds::kRequired) {
+      format(
+          "  if (arena != nullptr && !is_message_owned) {\n"
+          "    arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+          "  }\n");
+    }
+  }
+  format(
+      "  // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
+      "}\n");
+
+  std::map<std::string, std::string> vars;
+  SetUnknownFieldsVariable(descriptor_, options_, &vars);
+  format.AddMap(vars);
+
+  // Generate the copy constructor.
+  if (UsingImplicitWeakFields(descriptor_->file(), options_)) {
+    // If we are in lite mode and using implicit weak fields, we generate a
+    // one-liner copy constructor that delegates to MergeFrom. This saves some
+    // code size and also cuts down on the complexity of implicit weak fields.
+    // We might eventually want to do this for all lite protos.
+    format(
+        "$classname$::$classname$(const $classname$& from)\n"
+        "  : $classname$() {\n"
+        "  MergeFrom(from);\n"
+        "}\n");
+  } else {
+    format(
+        "$classname$::$classname$(const $classname$& from)\n"
+        "  : $superclass$() {\n");
+    format.Indent();
+    format("$classname$* const _this = this; (void)_this;\n");
+
+    if (HasImplData(descriptor_, options_)) {
+      const char* field_sep = " ";
+      const auto put_sep = [&] {
+        format("\n$1$ ", field_sep);
+        field_sep = ",";
+      };
+
+      format("new (&_impl_) Impl_{");
+      format.Indent();
+
+      if (descriptor_->extension_range_count() > 0) {
+        put_sep();
+        format("/*decltype($extensions$)*/{}");
+      }
+      if (!inlined_string_indices_.empty()) {
+        // Do not copy inlined_string_donated_, because this is not an arena
+        // constructor.
+        put_sep();
+        format("decltype($inlined_string_donated_array$){}");
+      }
+      bool need_to_emit_cached_size =
+          !HasSimpleBaseClass(descriptor_, options_);
+      if (!has_bit_indices_.empty()) {
+        put_sep();
+        format("decltype($has_bits$){from.$has_bits$}");
+        if (need_to_emit_cached_size) {
+          put_sep();
+          format("/*decltype($cached_size$)*/{}");
+          need_to_emit_cached_size = false;
+        }
+      }
+
+      // Initialize member variables with arena constructor.
+      for (auto field : optimized_order_) {
+        if (ShouldSplit(field, options_)) {
+          continue;
+        }
+        put_sep();
+        field_generators_.get(field).GenerateCopyAggregateInitializer(printer);
+      }
+      if (ShouldSplit(descriptor_, options_)) {
+        put_sep();
+        format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
+               DefaultInstanceName(descriptor_, options_, /*split=*/true));
+      }
+      for (auto oneof : OneOfRange(descriptor_)) {
+        put_sep();
+        format("decltype(_impl_.$1$_){}", oneof->name());
+      }
+
+      if (need_to_emit_cached_size) {
+        put_sep();
+        format("/*decltype($cached_size$)*/{}");
+      }
+
+      if (descriptor_->real_oneof_decl_count() != 0) {
+        put_sep();
+        format("/*decltype($oneof_case$)*/{}");
+      }
+      if (num_weak_fields_ > 0) {
+        put_sep();
+        format("decltype($weak_field_map$){from.$weak_field_map$}");
+      }
+      if (IsAnyMessage(descriptor_, options_)) {
+        put_sep();
+        format(
+            "/*decltype($any_metadata$)*/{&_impl_.type_url_, &_impl_.value_}");
+      }
+      format.Outdent();
+      format("};\n\n");
+    }
+
+    format(
+        "_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._internal_"
+        "metadata_);\n");
+
+    if (descriptor_->extension_range_count() > 0) {
+      format(
+          "$extensions$.MergeFrom(internal_default_instance(), "
+          "from.$extensions$);\n");
+    }
+
+    GenerateCopyConstructorBody(printer);
+
+    // Copy oneof fields. Oneof field requires oneof case check.
+    for (auto oneof : OneOfRange(descriptor_)) {
+      format(
+          "clear_has_$1$();\n"
+          "switch (from.$1$_case()) {\n",
+          oneof->name());
+      format.Indent();
+      for (auto field : FieldRange(oneof)) {
+        format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
+        format.Indent();
+        if (!IsFieldStripped(field, options_)) {
+          field_generators_.get(field).GenerateMergingCode(printer);
+        }
+        format("break;\n");
+        format.Outdent();
+        format("}\n");
+      }
+      format(
+          "case $1$_NOT_SET: {\n"
+          "  break;\n"
+          "}\n",
+          ToUpper(oneof->name()));
+      format.Outdent();
+      format("}\n");
+    }
+
+    format.Outdent();
+    format(
+        "  // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
+        "}\n"
+        "\n");
+  }
+
+  // Generate the shared constructor code.
+  GenerateSharedConstructorCode(printer);
+
+  if (ShouldSplit(descriptor_, options_)) {
+    GenerateCreateSplitMessage(printer);
+  }
+
+  // Generate the destructor.
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format(
+        "$classname$::~$classname$() {\n"
+        "  // @@protoc_insertion_point(destructor:$full_name$)\n");
+    format(
+        "  if (auto *arena = "
+        "_internal_metadata_.DeleteReturnArena<$unknown_fields_type$>()) {\n"
+        "  (void)arena;\n");
+    if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) {
+      format("    ArenaDtor(this);\n");
+    }
+    format(
+        "    return;\n"
+        "  }\n");
+    format(
+        "  SharedDtor();\n"
+        "}\n"
+        "\n");
+  } else {
+    // For messages using simple base classes, having no destructor
+    // allows our vtable to share the same destructor as every other
+    // message with a simple base class.  This works only as long as
+    // we have no fields needing destruction, of course.  (No strings
+    // or extensions)
+  }
+
+  // Generate the shared destructor code.
+  GenerateSharedDestructorCode(printer);
+
+  // Generate the arena-specific destructor code.
+  if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) {
+    GenerateArenaDestructorCode(printer);
+  }
+
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    // Generate SetCachedSize.
+    format(
+        "void $classname$::SetCachedSize(int size) const {\n"
+        "  $cached_size$.Set(size);\n"
+        "}\n");
+  }
+}
+
+void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  format(
+      "template<> "
+      "PROTOBUF_NOINLINE $classtype$*\n"
+      "Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n"
+      "  return Arena::CreateMessageInternal< $classtype$ >(arena);\n"
+      "}\n");
+}
+
+void MessageGenerator::GenerateClear(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+
+  // The maximum number of bytes we will memset to zero without checking their
+  // hasbit to see if a zero-init is necessary.
+  const int kMaxUnconditionalPrimitiveBytesClear = 4;
+
+  format(
+      "void $classname$::Clear() {\n"
+      "// @@protoc_insertion_point(message_clear_start:$full_name$)\n");
+  format.Indent();
+
+  format(
+      // TODO(jwb): It would be better to avoid emitting this if it is not used,
+      // rather than emitting a workaround for the resulting warning.
+      "$uint32$ cached_has_bits = 0;\n"
+      "// Prevent compiler warnings about cached_has_bits being unused\n"
+      "(void) cached_has_bits;\n\n");
+
+  if (descriptor_->extension_range_count() > 0) {
+    format("$extensions$.Clear();\n");
+  }
+
+  // Collect fields into chunks. Each chunk may have an if() condition that
+  // checks all hasbits in the chunk and skips it if none are set.
+  int zero_init_bytes = 0;
+  for (const auto& field : optimized_order_) {
+    if (CanInitializeByZeroing(field)) {
+      zero_init_bytes += EstimateAlignmentSize(field);
+    }
+  }
+  bool merge_zero_init = zero_init_bytes > kMaxUnconditionalPrimitiveBytesClear;
+  int chunk_count = 0;
+
+  std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields(
+      optimized_order_,
+      [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool {
+        chunk_count++;
+        // This predicate guarantees that there is only a single zero-init
+        // (memset) per chunk, and if present it will be at the beginning.
+        bool same = HasByteIndex(a) == HasByteIndex(b) &&
+                    a->is_repeated() == b->is_repeated() &&
+                    ShouldSplit(a, options_) == ShouldSplit(b, options_) &&
+                    (CanInitializeByZeroing(a) == CanInitializeByZeroing(b) ||
+                     (CanInitializeByZeroing(a) &&
+                      (chunk_count == 1 || merge_zero_init)));
+        if (!same) chunk_count = 0;
+        return same;
+      });
+
+  ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_,
+                                kColdRatio);
+  int cached_has_word_index = -1;
+
+  for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+    std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+    cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer);
+
+    const FieldDescriptor* memset_start = nullptr;
+    const FieldDescriptor* memset_end = nullptr;
+    bool saw_non_zero_init = false;
+    bool chunk_is_cold = !chunk.empty() && ShouldSplit(chunk.front(), options_);
+    for (const auto& field : chunk) {
+      if (CanInitializeByZeroing(field)) {
+        GOOGLE_CHECK(!saw_non_zero_init);
+        if (!memset_start) memset_start = field;
+        memset_end = field;
+      } else {
+        saw_non_zero_init = true;
+      }
+    }
+
+    // Whether we wrap this chunk in:
+    //   if (cached_has_bits & <chunk hasbits) { /* chunk. */ }
+    // We can omit the if() for chunk size 1, or if our fields do not have
+    // hasbits. I don't understand the rationale for the last part of the
+    // condition, but it matches the old logic.
+    const bool have_outer_if = HasBitIndex(chunk.front()) != kNoHasbit &&
+                               chunk.size() > 1 &&
+                               (memset_end != chunk.back() || merge_zero_init);
+
+    if (have_outer_if) {
+      // Emit an if() that will let us skip the whole chunk if none are set.
+      uint32_t chunk_mask = GenChunkMask(chunk, has_bit_indices_);
+      std::string chunk_mask_str =
+          StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8));
+
+      // Check (up to) 8 has_bits at a time if we have more than one field in
+      // this chunk.  Due to field layout ordering, we may check
+      // _has_bits_[last_chunk * 8 / 32] multiple times.
+      GOOGLE_DCHECK_LE(2, popcnt(chunk_mask));
+      GOOGLE_DCHECK_GE(8, popcnt(chunk_mask));
+
+      if (cached_has_word_index != HasWordIndex(chunk.front())) {
+        cached_has_word_index = HasWordIndex(chunk.front());
+        format("cached_has_bits = $has_bits$[$1$];\n", cached_has_word_index);
+      }
+      format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str);
+      format.Indent();
+    }
+
+    if (chunk_is_cold) {
+      format("if (!IsSplitMessageDefault()) {\n");
+      format.Indent();
+    }
+
+    if (memset_start) {
+      if (memset_start == memset_end) {
+        // For clarity, do not memset a single field.
+        field_generators_.get(memset_start)
+            .GenerateMessageClearingCode(printer);
+      } else {
+        GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_start, options_));
+        GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_end, options_));
+        format(
+            "::memset(&$1$, 0, static_cast<size_t>(\n"
+            "    reinterpret_cast<char*>(&$2$) -\n"
+            "    reinterpret_cast<char*>(&$1$)) + sizeof($2$));\n",
+            FieldMemberName(memset_start, chunk_is_cold),
+            FieldMemberName(memset_end, chunk_is_cold));
+      }
+    }
+
+    // Clear all non-zero-initializable fields in the chunk.
+    for (const auto& field : chunk) {
+      if (CanInitializeByZeroing(field)) continue;
+      // It's faster to just overwrite primitive types, but we should only
+      // clear strings and messages if they were set.
+      //
+      // TODO(kenton):  Let the CppFieldGenerator decide this somehow.
+      bool have_enclosing_if =
+          HasBitIndex(field) != kNoHasbit &&
+          (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+           field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
+
+      if (have_enclosing_if) {
+        PrintPresenceCheck(format, field, has_bit_indices_, printer,
+                           &cached_has_word_index);
+      }
+
+      field_generators_.get(field).GenerateMessageClearingCode(printer);
+
+      if (have_enclosing_if) {
+        format.Outdent();
+        format("}\n");
+      }
+    }
+
+    if (chunk_is_cold) {
+      format.Outdent();
+      format("}\n");
+    }
+
+    if (have_outer_if) {
+      format.Outdent();
+      format("}\n");
+    }
+
+    if (cold_skipper.OnEndChunk(chunk_index, printer)) {
+      // Reset here as it may have been updated in just closed if statement.
+      cached_has_word_index = -1;
+    }
+  }
+
+  // Step 4: Unions.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format("clear_$1$();\n", oneof->name());
+  }
+
+  if (num_weak_fields_) {
+    format("$weak_field_map$.ClearAll();\n");
+  }
+
+  // We don't clear donated status.
+
+  if (!has_bit_indices_.empty()) {
+    // Step 5: Everything else.
+    format("$has_bits$.Clear();\n");
+  }
+
+  std::map<std::string, std::string> vars;
+  SetUnknownFieldsVariable(descriptor_, options_, &vars);
+  format.AddMap(vars);
+  format("_internal_metadata_.Clear<$unknown_fields_type$>();\n");
+
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateOneofClear(io::Printer* printer) {
+  // Generated function clears the active field and union case (e.g. foo_case_).
+  int i = 0;
+  for (auto oneof : OneOfRange(descriptor_)) {
+    Formatter format(printer, variables_);
+    format.Set("oneofname", oneof->name());
+
+    format(
+        "void $classname$::clear_$oneofname$() {\n"
+        "// @@protoc_insertion_point(one_of_clear_start:$full_name$)\n");
+    format.Indent();
+    format("switch ($oneofname$_case()) {\n");
+    format.Indent();
+    for (auto field : FieldRange(oneof)) {
+      format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
+      format.Indent();
+      // We clear only allocated objects in oneofs
+      if (!IsStringOrMessage(field) || IsFieldStripped(field, options_)) {
+        format("// No need to clear\n");
+      } else {
+        field_generators_.get(field).GenerateClearingCode(printer);
+      }
+      format("break;\n");
+      format.Outdent();
+      format("}\n");
+    }
+    format(
+        "case $1$_NOT_SET: {\n"
+        "  break;\n"
+        "}\n",
+        ToUpper(oneof->name()));
+    format.Outdent();
+    format(
+        "}\n"
+        "$oneof_case$[$1$] = $2$_NOT_SET;\n",
+        i, ToUpper(oneof->name()));
+    format.Outdent();
+    format(
+        "}\n"
+        "\n");
+    i++;
+  }
+}
+
+void MessageGenerator::GenerateSwap(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+
+  format("void $classname$::InternalSwap($classname$* other) {\n");
+  format.Indent();
+  format("using std::swap;\n");
+
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
+    if (descriptor_->extension_range_count() > 0) {
+      format(
+          "$extensions$.InternalSwap(&other->$extensions$);"
+          "\n");
+    }
+
+    std::map<std::string, std::string> vars;
+    SetUnknownFieldsVariable(descriptor_, options_, &vars);
+    format.AddMap(vars);
+    if (HasNonSplitOptionalString(descriptor_, options_)) {
+      format(
+          "auto* lhs_arena = GetArenaForAllocation();\n"
+          "auto* rhs_arena = other->GetArenaForAllocation();\n");
+    }
+    format("_internal_metadata_.InternalSwap(&other->_internal_metadata_);\n");
+
+    if (!has_bit_indices_.empty()) {
+      for (int i = 0; i < HasBitsSize(); ++i) {
+        format("swap($has_bits$[$1$], other->$has_bits$[$1$]);\n", i);
+      }
+    }
+
+    // If possible, we swap several fields at once, including padding.
+    const RunMap runs =
+        FindRuns(optimized_order_, [this](const FieldDescriptor* field) {
+          return !ShouldSplit(field, options_) &&
+                 CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_);
+        });
+
+    for (size_t i = 0; i < optimized_order_.size(); ++i) {
+      const FieldDescriptor* field = optimized_order_[i];
+      if (ShouldSplit(field, options_)) {
+        continue;
+      }
+      const auto it = runs.find(field);
+
+      // We only apply the memswap technique to runs of more than one field, as
+      // `swap(field_, other.field_)` is better than
+      // `memswap<...>(&field_, &other.field_)` for generated code readability.
+      if (it != runs.end() && it->second > 1) {
+        // Use a memswap, then skip run_length fields.
+        const size_t run_length = it->second;
+        const std::string first_field_name =
+            FieldMemberName(field, /*cold=*/false);
+        const std::string last_field_name = FieldMemberName(
+            optimized_order_[i + run_length - 1], /*cold=*/false);
+
+        format.Set("first", first_field_name);
+        format.Set("last", last_field_name);
+
+        format(
+            "::PROTOBUF_NAMESPACE_ID::internal::memswap<\n"
+            "    PROTOBUF_FIELD_OFFSET($classname$, $last$)\n"
+            "    + sizeof($classname$::$last$)\n"
+            "    - PROTOBUF_FIELD_OFFSET($classname$, $first$)>(\n"
+            "        reinterpret_cast<char*>(&$first$),\n"
+            "        reinterpret_cast<char*>(&other->$first$));\n");
+
+        i += run_length - 1;
+        // ++i at the top of the loop.
+      } else {
+        field_generators_.get(field).GenerateSwappingCode(printer);
+      }
+    }
+    if (ShouldSplit(descriptor_, options_)) {
+      format("swap($split$, other->$split$);\n");
+    }
+
+    for (auto oneof : OneOfRange(descriptor_)) {
+      format("swap(_impl_.$1$_, other->_impl_.$1$_);\n", oneof->name());
+    }
+
+    for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
+      format("swap($oneof_case$[$1$], other->$oneof_case$[$1$]);\n", i);
+    }
+
+    if (num_weak_fields_) {
+      format(
+          "$weak_field_map$.UnsafeArenaSwap(&other->$weak_field_map$)"
+          ";\n");
+    }
+
+    if (!inlined_string_indices_.empty()) {
+      for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) {
+        format(
+            "swap($inlined_string_donated_array$[$1$], "
+            "other->$inlined_string_donated_array$[$1$]);\n",
+            i);
+      }
+    }
+  } else {
+    format("GetReflection()->Swap(this, other);");
+  }
+
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateMergeFrom(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      // We don't override the generalized MergeFrom (aka that which
+      // takes in the Message base class as a parameter); instead we just
+      // let the base Message::MergeFrom take care of it.  The base MergeFrom
+      // knows how to quickly confirm the types exactly match, and if so, will
+      // use GetClassData() to retrieve the address of MergeImpl, which calls
+      // the fast MergeFrom overload.  Most callers avoid all this by passing
+      // a "from" message that is the same type as the message being merged
+      // into, rather than a generic Message.
+
+      format(
+          "const ::$proto_ns$::Message::ClassData "
+          "$classname$::_class_data_ = {\n"
+          "    ::$proto_ns$::Message::CopyWithSourceCheck,\n"
+          "    $classname$::MergeImpl\n"
+          "};\n"
+          "const ::$proto_ns$::Message::ClassData*"
+          "$classname$::GetClassData() const { return &_class_data_; }\n"
+          "\n");
+    } else {
+      // Generate CheckTypeAndMergeFrom().
+      format(
+          "void $classname$::CheckTypeAndMergeFrom(\n"
+          "    const ::$proto_ns$::MessageLite& from) {\n"
+          "  MergeFrom(*::_pbi::DownCast<const $classname$*>(\n"
+          "      &from));\n"
+          "}\n");
+    }
+  } else {
+    // In the simple case, we just define ClassData that vectors back to the
+    // simple implementation of Copy and Merge.
+    format(
+        "const ::$proto_ns$::Message::ClassData "
+        "$classname$::_class_data_ = {\n"
+        "    $superclass$::CopyImpl,\n"
+        "    $superclass$::MergeImpl,\n"
+        "};\n"
+        "const ::$proto_ns$::Message::ClassData*"
+        "$classname$::GetClassData() const { return &_class_data_; }\n"
+        "\n"
+        "\n");
+  }
+}
+
+void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
+  Formatter format(printer, variables_);
+  if (!HasDescriptorMethods(descriptor_->file(), options_)) {
+    // For messages that don't inherit from Message, just implement MergeFrom
+    // directly.
+    format(
+        "void $classname$::MergeFrom(const $classname$& from) {\n"
+        "  $classname$* const _this = this;\n");
+  } else {
+    format(
+        "void $classname$::MergeImpl(::$proto_ns$::Message& to_msg, const "
+        "::$proto_ns$::Message& from_msg) {\n"
+        "  auto* const _this = static_cast<$classname$*>(&to_msg);\n"
+        "  auto& from = static_cast<const $classname$&>(from_msg);\n");
+  }
+  format.Indent();
+  format(
+      "$annotate_mergefrom$"
+      "// @@protoc_insertion_point(class_specific_merge_from_start:"
+      "$full_name$)\n");
+  format("$DCHK$_NE(&from, _this);\n");
+
+  format(
+      "$uint32$ cached_has_bits = 0;\n"
+      "(void) cached_has_bits;\n\n");
+
+  if (ShouldSplit(descriptor_, options_)) {
+    format(
+        "if (!from.IsSplitMessageDefault()) {\n"
+        "  _this->PrepareSplitMessageForWrite();\n"
+        "}\n");
+  }
+
+  std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields(
+      optimized_order_,
+      [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool {
+        return HasByteIndex(a) == HasByteIndex(b) &&
+               ShouldSplit(a, options_) == ShouldSplit(b, options_);
+      });
+
+  ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_,
+                                kColdRatio);
+
+  // cached_has_word_index maintains that:
+  //   cached_has_bits = from._has_bits_[cached_has_word_index]
+  // for cached_has_word_index >= 0
+  int cached_has_word_index = -1;
+
+  for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+    const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+    bool have_outer_if =
+        chunk.size() > 1 && HasByteIndex(chunk.front()) != kNoHasbit;
+    cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.",
+                              printer);
+
+    if (have_outer_if) {
+      // Emit an if() that will let us skip the whole chunk if none are set.
+      uint32_t chunk_mask = GenChunkMask(chunk, has_bit_indices_);
+      std::string chunk_mask_str =
+          StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8));
+
+      // Check (up to) 8 has_bits at a time if we have more than one field in
+      // this chunk.  Due to field layout ordering, we may check
+      // _has_bits_[last_chunk * 8 / 32] multiple times.
+      GOOGLE_DCHECK_LE(2, popcnt(chunk_mask));
+      GOOGLE_DCHECK_GE(8, popcnt(chunk_mask));
+
+      if (cached_has_word_index != HasWordIndex(chunk.front())) {
+        cached_has_word_index = HasWordIndex(chunk.front());
+        format("cached_has_bits = from.$has_bits$[$1$];\n",
+               cached_has_word_index);
+      }
+
+      format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str);
+      format.Indent();
+    }
+
+    // Go back and emit merging code for each of the fields we processed.
+    bool deferred_has_bit_changes = false;
+    for (const auto field : chunk) {
+      const FieldGenerator& generator = field_generators_.get(field);
+
+      if (field->is_repeated()) {
+        generator.GenerateMergingCode(printer);
+      } else if (field->is_optional() && !HasHasbit(field)) {
+        // Merge semantics without true field presence: primitive fields are
+        // merged only if non-zero (numeric) or non-empty (string).
+        bool have_enclosing_if =
+            EmitFieldNonDefaultCondition(printer, "from.", field);
+        generator.GenerateMergingCode(printer);
+        if (have_enclosing_if) {
+          format.Outdent();
+          format("}\n");
+        }
+      } else if (field->options().weak() ||
+                 cached_has_word_index != HasWordIndex(field)) {
+        // Check hasbit, not using cached bits.
+        GOOGLE_CHECK(HasHasbit(field));
+        format("if (from._internal_has_$1$()) {\n", FieldName(field));
+        format.Indent();
+        generator.GenerateMergingCode(printer);
+        format.Outdent();
+        format("}\n");
+      } else {
+        // Check hasbit, using cached bits.
+        GOOGLE_CHECK(HasHasbit(field));
+        int has_bit_index = has_bit_indices_[field->index()];
+        const std::string mask = StrCat(
+            strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
+        format("if (cached_has_bits & 0x$1$u) {\n", mask);
+        format.Indent();
+
+        if (have_outer_if && IsPOD(field)) {
+          // Defer hasbit modification until the end of chunk.
+          // This can reduce the number of loads/stores by up to 7 per 8 fields.
+          deferred_has_bit_changes = true;
+          generator.GenerateCopyConstructorCode(printer);
+        } else {
+          generator.GenerateMergingCode(printer);
+        }
+
+        format.Outdent();
+        format("}\n");
+      }
+    }
+
+    if (have_outer_if) {
+      if (deferred_has_bit_changes) {
+        // Flush the has bits for the primitives we deferred.
+        GOOGLE_CHECK_LE(0, cached_has_word_index);
+        format("_this->$has_bits$[$1$] |= cached_has_bits;\n",
+               cached_has_word_index);
+      }
+
+      format.Outdent();
+      format("}\n");
+    }
+
+    if (cold_skipper.OnEndChunk(chunk_index, printer)) {
+      // Reset here as it may have been updated in just closed if statement.
+      cached_has_word_index = -1;
+    }
+  }
+
+  // Merge oneof fields. Oneof field requires oneof case check.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format("switch (from.$1$_case()) {\n", oneof->name());
+    format.Indent();
+    for (auto field : FieldRange(oneof)) {
+      format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
+      format.Indent();
+      if (!IsFieldStripped(field, options_)) {
+        field_generators_.get(field).GenerateMergingCode(printer);
+      }
+      format("break;\n");
+      format.Outdent();
+      format("}\n");
+    }
+    format(
+        "case $1$_NOT_SET: {\n"
+        "  break;\n"
+        "}\n",
+        ToUpper(oneof->name()));
+    format.Outdent();
+    format("}\n");
+  }
+  if (num_weak_fields_) {
+    format(
+        "_this->$weak_field_map$.MergeFrom(from.$weak_field_map$);"
+        "\n");
+  }
+
+  // Merging of extensions and unknown fields is done last, to maximize
+  // the opportunity for tail calls.
+  if (descriptor_->extension_range_count() > 0) {
+    format(
+        "_this->$extensions$.MergeFrom(internal_default_instance(), "
+        "from.$extensions$);\n");
+  }
+
+  format(
+      "_this->_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._"
+      "internal_"
+      "metadata_);\n");
+
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateCopyFrom(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    // We don't override the generalized CopyFrom (aka that which
+    // takes in the Message base class as a parameter); instead we just
+    // let the base Message::CopyFrom take care of it.  The base MergeFrom
+    // knows how to quickly confirm the types exactly match, and if so, will
+    // use GetClassData() to get the address of Message::CopyWithSourceCheck,
+    // which calls Clear() and then MergeFrom(), as well as making sure that
+    // clearing the destination message doesn't alter the source, when in debug
+    // builds. Most callers avoid this by passing a "from" message that is the
+    // same type as the message being merged into, rather than a generic
+    // Message.
+  }
+
+  // Generate the class-specific CopyFrom.
+  format(
+      "void $classname$::CopyFrom(const $classname$& from) {\n"
+      "// @@protoc_insertion_point(class_specific_copy_from_start:"
+      "$full_name$)\n");
+  format.Indent();
+
+  format("if (&from == this) return;\n");
+
+  if (!options_.opensource_runtime && HasMessageFieldOrExtension(descriptor_)) {
+    // This check is disabled in the opensource release because we're
+    // concerned that many users do not define NDEBUG in their release builds.
+    // It is also disabled if a message has neither message fields nor
+    // extensions, as it's impossible to copy from its descendant.
+    //
+    // Note that FailIfCopyFromDescendant is implemented by reflection and not
+    // available for lite runtime. In that case, check if the size of the source
+    // has changed after Clear.
+    format("#ifndef NDEBUG\n");
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      format("FailIfCopyFromDescendant(*this, from);\n");
+    } else {
+      format("size_t from_size = from.ByteSizeLong();\n");
+    }
+    format(
+        "#endif\n"
+        "Clear();\n");
+    if (!HasDescriptorMethods(descriptor_->file(), options_)) {
+      format(
+          "#ifndef NDEBUG\n"
+          "$CHK$_EQ(from_size, from.ByteSizeLong())\n"
+          "  << \"Source of CopyFrom changed when clearing target.  Either \"\n"
+          "     \"source is a nested message in target (not allowed), or \"\n"
+          "     \"another thread is modifying the source.\";\n"
+          "#endif\n");
+    }
+  } else {
+    format("Clear();\n");
+  }
+  format("MergeFrom(from);\n");
+
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateVerify(io::Printer* printer) {
+}
+
+void MessageGenerator::GenerateSerializeOneofFields(
+    io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) {
+  Formatter format(printer, variables_);
+  GOOGLE_CHECK(!fields.empty());
+  if (fields.size() == 1) {
+    GenerateSerializeOneField(printer, fields[0], -1);
+    return;
+  }
+  // We have multiple mutually exclusive choices.  Emit a switch statement.
+  const OneofDescriptor* oneof = fields[0]->containing_oneof();
+  format("switch ($1$_case()) {\n", oneof->name());
+  format.Indent();
+  for (auto field : fields) {
+    format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
+    format.Indent();
+    field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(
+        printer);
+    format("break;\n");
+    format.Outdent();
+    format("}\n");
+  }
+  format.Outdent();
+  // Doing nothing is an option.
+  format(
+      "  default: ;\n"
+      "}\n");
+}
+
+void MessageGenerator::GenerateSerializeOneField(io::Printer* printer,
+                                                 const FieldDescriptor* field,
+                                                 int cached_has_bits_index) {
+  Formatter format(printer, variables_);
+  if (!field->options().weak()) {
+    // For weakfields, PrintFieldComment is called during iteration.
+    PrintFieldComment(format, field);
+  }
+
+  bool have_enclosing_if = false;
+  if (field->options().weak()) {
+  } else if (HasHasbit(field)) {
+    // Attempt to use the state of cached_has_bits, if possible.
+    int has_bit_index = HasBitIndex(field);
+    if (cached_has_bits_index == has_bit_index / 32) {
+      const std::string mask =
+          StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
+
+      format("if (cached_has_bits & 0x$1$u) {\n", mask);
+    } else {
+      format("if (_internal_has_$1$()) {\n", FieldName(field));
+    }
+
+    format.Indent();
+    have_enclosing_if = true;
+  } else if (field->is_optional() && !HasHasbit(field)) {
+    have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field);
+  }
+
+  field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(printer);
+
+  if (have_enclosing_if) {
+    format.Outdent();
+    format("}\n");
+  }
+  format("\n");
+}
+
+void MessageGenerator::GenerateSerializeOneExtensionRange(
+    io::Printer* printer, const Descriptor::ExtensionRange* range) {
+  std::map<std::string, std::string> vars = variables_;
+  vars["start"] = StrCat(range->start);
+  vars["end"] = StrCat(range->end);
+  Formatter format(printer, vars);
+  format("// Extension range [$start$, $end$)\n");
+  format(
+      "target = $extensions$._InternalSerialize(\n"
+      "internal_default_instance(), $start$, $end$, target, stream);\n\n");
+}
+
+void MessageGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    format(
+        "$uint8$* $classname$::_InternalSerialize(\n"
+        "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+        "const {\n"
+        "$annotate_serialize$"
+        "  target = $extensions$."
+        "InternalSerializeMessageSetWithCachedSizesToArray(\n"  //
+        "internal_default_instance(), target, stream);\n");
+    std::map<std::string, std::string> vars;
+    SetUnknownFieldsVariable(descriptor_, options_, &vars);
+    format.AddMap(vars);
+    format(
+        "  target = ::_pbi::"
+        "InternalSerializeUnknownMessageSetItemsToArray(\n"
+        "               $unknown_fields$, target, stream);\n");
+    format(
+        "  return target;\n"
+        "}\n");
+    return;
+  }
+
+  format(
+      "$uint8$* $classname$::_InternalSerialize(\n"
+      "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+      "const {\n"
+      "$annotate_serialize$");
+  format.Indent();
+
+  format("// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n");
+
+  if (!ShouldSerializeInOrder(descriptor_, options_)) {
+    format.Outdent();
+    format("#ifdef NDEBUG\n");
+    format.Indent();
+  }
+
+  GenerateSerializeWithCachedSizesBody(printer);
+
+  if (!ShouldSerializeInOrder(descriptor_, options_)) {
+    format.Outdent();
+    format("#else  // NDEBUG\n");
+    format.Indent();
+
+    GenerateSerializeWithCachedSizesBodyShuffled(printer);
+
+    format.Outdent();
+    format("#endif  // !NDEBUG\n");
+    format.Indent();
+  }
+
+  format("// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n");
+
+  format.Outdent();
+  format(
+      "  return target;\n"
+      "}\n");
+}
+
+void MessageGenerator::GenerateSerializeWithCachedSizesBody(
+    io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+  // If there are multiple fields in a row from the same oneof then we
+  // coalesce them and emit a switch statement.  This is more efficient
+  // because it lets the C++ compiler know this is a "at most one can happen"
+  // situation. If we emitted "if (has_x()) ...; if (has_y()) ..." the C++
+  // compiler's emitted code might check has_y() even when has_x() is true.
+  class LazySerializerEmitter {
+   public:
+    LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer)
+        : mg_(mg),
+          format_(printer),
+          eager_(IsProto3(mg->descriptor_->file())),
+          cached_has_bit_index_(kNoHasbit) {}
+
+    ~LazySerializerEmitter() { Flush(); }
+
+    // If conditions allow, try to accumulate a run of fields from the same
+    // oneof, and handle them at the next Flush().
+    void Emit(const FieldDescriptor* field) {
+      if (eager_ || MustFlush(field)) {
+        Flush();
+      }
+      if (!field->real_containing_oneof()) {
+        // TODO(ckennelly): Defer non-oneof fields similarly to oneof fields.
+
+        if (!field->options().weak() && !field->is_repeated() && !eager_) {
+          // We speculatively load the entire _has_bits_[index] contents, even
+          // if it is for only one field.  Deferring non-oneof emitting would
+          // allow us to determine whether this is going to be useful.
+          int has_bit_index = mg_->has_bit_indices_[field->index()];
+          if (cached_has_bit_index_ != has_bit_index / 32) {
+            // Reload.
+            int new_index = has_bit_index / 32;
+
+            format_("cached_has_bits = _impl_._has_bits_[$1$];\n", new_index);
+
+            cached_has_bit_index_ = new_index;
+          }
+        }
+
+        mg_->GenerateSerializeOneField(format_.printer(), field,
+                                       cached_has_bit_index_);
+      } else {
+        v_.push_back(field);
+      }
+    }
+
+    void EmitIfNotNull(const FieldDescriptor* field) {
+      if (field != nullptr) {
+        Emit(field);
+      }
+    }
+
+    void Flush() {
+      if (!v_.empty()) {
+        mg_->GenerateSerializeOneofFields(format_.printer(), v_);
+        v_.clear();
+      }
+    }
+
+   private:
+    // If we have multiple fields in v_ then they all must be from the same
+    // oneof.  Would adding field to v_ break that invariant?
+    bool MustFlush(const FieldDescriptor* field) {
+      return !v_.empty() &&
+             v_[0]->containing_oneof() != field->containing_oneof();
+    }
+
+    MessageGenerator* mg_;
+    Formatter format_;
+    const bool eager_;
+    std::vector<const FieldDescriptor*> v_;
+
+    // cached_has_bit_index_ maintains that:
+    //   cached_has_bits = from._has_bits_[cached_has_bit_index_]
+    // for cached_has_bit_index_ >= 0
+    int cached_has_bit_index_;
+  };
+
+  class LazyExtensionRangeEmitter {
+   public:
+    LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* printer)
+        : mg_(mg), format_(printer) {}
+
+    void AddToRange(const Descriptor::ExtensionRange* range) {
+      if (!has_current_range_) {
+        current_combined_range_ = *range;
+        has_current_range_ = true;
+      } else {
+        current_combined_range_.start =
+            std::min(current_combined_range_.start, range->start);
+        current_combined_range_.end =
+            std::max(current_combined_range_.end, range->end);
+      }
+    }
+
+    void Flush() {
+      if (has_current_range_) {
+        mg_->GenerateSerializeOneExtensionRange(format_.printer(),
+                                                &current_combined_range_);
+      }
+      has_current_range_ = false;
+    }
+
+   private:
+    MessageGenerator* mg_;
+    Formatter format_;
+    bool has_current_range_ = false;
+    Descriptor::ExtensionRange current_combined_range_;
+  };
+
+  // We need to track the largest weak field, because weak fields are serialized
+  // differently than normal fields.  The WeakFieldMap::FieldWriter will
+  // serialize all weak fields that are ordinally between the last serialized
+  // weak field and the current field.  In order to guarantee that all weak
+  // fields are serialized, we need to make sure to emit the code to serialize
+  // the largest weak field present at some point.
+  class LargestWeakFieldHolder {
+   public:
+    const FieldDescriptor* Release() {
+      const FieldDescriptor* result = field_;
+      field_ = nullptr;
+      return result;
+    }
+    void ReplaceIfLarger(const FieldDescriptor* field) {
+      if (field_ == nullptr || field_->number() < field->number()) {
+        field_ = field;
+      }
+    }
+
+   private:
+    const FieldDescriptor* field_ = nullptr;
+  };
+
+  std::vector<const FieldDescriptor*> ordered_fields =
+      SortFieldsByNumber(descriptor_);
+
+  std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
+  sorted_extensions.reserve(descriptor_->extension_range_count());
+  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(),
+            ExtensionRangeSorter());
+  if (num_weak_fields_) {
+    format(
+        "::_pbi::WeakFieldMap::FieldWriter field_writer("
+        "$weak_field_map$);\n");
+  }
+
+  format(
+      "$uint32$ cached_has_bits = 0;\n"
+      "(void) cached_has_bits;\n\n");
+
+  // Merge the fields and the extension ranges, both sorted by field number.
+  {
+    LazySerializerEmitter e(this, printer);
+    LazyExtensionRangeEmitter re(this, printer);
+    LargestWeakFieldHolder largest_weak_field;
+    int i, j;
+    for (i = 0, j = 0;
+         i < ordered_fields.size() || j < sorted_extensions.size();) {
+      if ((j == sorted_extensions.size()) ||
+          (i < descriptor_->field_count() &&
+           ordered_fields[i]->number() < sorted_extensions[j]->start)) {
+        const FieldDescriptor* field = ordered_fields[i++];
+        if (IsFieldStripped(field, options_)) {
+          continue;
+        }
+        re.Flush();
+        if (field->options().weak()) {
+          largest_weak_field.ReplaceIfLarger(field);
+          PrintFieldComment(format, field);
+        } else {
+          e.EmitIfNotNull(largest_weak_field.Release());
+          e.Emit(field);
+        }
+      } else {
+        e.EmitIfNotNull(largest_weak_field.Release());
+        e.Flush();
+        re.AddToRange(sorted_extensions[j++]);
+      }
+    }
+    re.Flush();
+    e.EmitIfNotNull(largest_weak_field.Release());
+  }
+
+  std::map<std::string, std::string> vars;
+  SetUnknownFieldsVariable(descriptor_, options_, &vars);
+  format.AddMap(vars);
+  format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
+  format.Indent();
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    format(
+        "target = "
+        "::_pbi::WireFormat::"
+        "InternalSerializeUnknownFieldsToArray(\n"
+        "    $unknown_fields$, target, stream);\n");
+  } else {
+    format(
+        "target = stream->WriteRaw($unknown_fields$.data(),\n"
+        "    static_cast<int>($unknown_fields$.size()), target);\n");
+  }
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled(
+    io::Printer* printer) {
+  Formatter format(printer, variables_);
+
+  std::vector<const FieldDescriptor*> ordered_fields =
+      SortFieldsByNumber(descriptor_);
+  ordered_fields.erase(
+      std::remove_if(ordered_fields.begin(), ordered_fields.end(),
+                     [this](const FieldDescriptor* f) {
+                       return !IsFieldUsed(f, options_);
+                     }),
+      ordered_fields.end());
+
+  std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
+  sorted_extensions.reserve(descriptor_->extension_range_count());
+  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(),
+            ExtensionRangeSorter());
+
+  int num_fields = ordered_fields.size() + sorted_extensions.size();
+  constexpr int kLargePrime = 1000003;
+  GOOGLE_CHECK_LT(num_fields, kLargePrime)
+      << "Prime offset must be greater than the number of fields to ensure "
+         "those are coprime.";
+
+  if (num_weak_fields_) {
+    format(
+        "::_pbi::WeakFieldMap::FieldWriter field_writer("
+        "$weak_field_map$);\n");
+  }
+
+  format("for (int i = $1$; i >= 0; i-- ) {\n", num_fields - 1);
+
+  format.Indent();
+  format("switch(i) {\n");
+  format.Indent();
+
+  int index = 0;
+  for (const auto* f : ordered_fields) {
+    format("case $1$: {\n", index++);
+    format.Indent();
+
+    GenerateSerializeOneField(printer, f, -1);
+
+    format("break;\n");
+    format.Outdent();
+    format("}\n");
+  }
+
+  for (const auto* r : sorted_extensions) {
+    format("case $1$: {\n", index++);
+    format.Indent();
+
+    GenerateSerializeOneExtensionRange(printer, r);
+
+    format("break;\n");
+    format.Outdent();
+    format("}\n");
+  }
+
+  format(
+      "default: {\n"
+      "  $DCHK$(false) << \"Unexpected index: \" << i;\n"
+      "}\n");
+  format.Outdent();
+  format("}\n");
+
+  format.Outdent();
+  format("}\n");
+
+  std::map<std::string, std::string> vars;
+  SetUnknownFieldsVariable(descriptor_, options_, &vars);
+  format.AddMap(vars);
+  format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
+  format.Indent();
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    format(
+        "target = "
+        "::_pbi::WireFormat::"
+        "InternalSerializeUnknownFieldsToArray(\n"
+        "    $unknown_fields$, target, stream);\n");
+  } else {
+    format(
+        "target = stream->WriteRaw($unknown_fields$.data(),\n"
+        "    static_cast<int>($unknown_fields$.size()), target);\n");
+  }
+  format.Outdent();
+  format("}\n");
+}
+
+std::vector<uint32_t> MessageGenerator::RequiredFieldsBitMask() const {
+  const int array_size = HasBitsSize();
+  std::vector<uint32_t> masks(array_size, 0);
+
+  for (auto field : FieldRange(descriptor_)) {
+    if (!field->is_required()) {
+      continue;
+    }
+
+    const int has_bit_index = has_bit_indices_[field->index()];
+    masks[has_bit_index / 32] |= static_cast<uint32_t>(1)
+                                 << (has_bit_index % 32);
+  }
+  return masks;
+}
+
+void MessageGenerator::GenerateByteSize(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    std::map<std::string, std::string> vars;
+    SetUnknownFieldsVariable(descriptor_, options_, &vars);
+    format.AddMap(vars);
+    format(
+        "size_t $classname$::ByteSizeLong() const {\n"
+        "$annotate_bytesize$"
+        "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n"
+        "  size_t total_size = $extensions$.MessageSetByteSize();\n"
+        "  if ($have_unknown_fields$) {\n"
+        "    total_size += ::_pbi::\n"
+        "        ComputeUnknownMessageSetItemsSize($unknown_fields$);\n"
+        "  }\n"
+        "  int cached_size = "
+        "::_pbi::ToCachedSize(total_size);\n"
+        "  SetCachedSize(cached_size);\n"
+        "  return total_size;\n"
+        "}\n");
+    return;
+  }
+
+  if (num_required_fields_ > 1) {
+    // Emit a function (rarely used, we hope) that handles the required fields
+    // by checking for each one individually.
+    format(
+        "size_t $classname$::RequiredFieldsByteSizeFallback() const {\n"
+        "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:"
+        "$full_name$)\n");
+    format.Indent();
+    format("size_t total_size = 0;\n");
+    for (auto field : optimized_order_) {
+      if (field->is_required()) {
+        format(
+            "\n"
+            "if (_internal_has_$1$()) {\n",
+            FieldName(field));
+        format.Indent();
+        PrintFieldComment(format, field);
+        field_generators_.get(field).GenerateByteSize(printer);
+        format.Outdent();
+        format("}\n");
+      }
+    }
+    format(
+        "\n"
+        "return total_size;\n");
+    format.Outdent();
+    format("}\n");
+  }
+
+  format(
+      "size_t $classname$::ByteSizeLong() const {\n"
+      "$annotate_bytesize$"
+      "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n");
+  format.Indent();
+  format(
+      "size_t total_size = 0;\n"
+      "\n");
+
+  if (descriptor_->extension_range_count() > 0) {
+    format(
+        "total_size += $extensions$.ByteSize();\n"
+        "\n");
+  }
+
+  std::map<std::string, std::string> vars;
+  SetUnknownFieldsVariable(descriptor_, options_, &vars);
+  format.AddMap(vars);
+
+  // Handle required fields (if any).  We expect all of them to be
+  // present, so emit one conditional that checks for that.  If they are all
+  // present then the fast path executes; otherwise the slow path executes.
+  if (num_required_fields_ > 1) {
+    // The fast path works if all required fields are present.
+    const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask();
+    format("if ($1$) {  // All required fields are present.\n",
+           ConditionalToCheckBitmasks(masks_for_has_bits));
+    format.Indent();
+    // Oneof fields cannot be required, so optimized_order_ contains all of the
+    // fields that we need to potentially emit.
+    for (auto field : optimized_order_) {
+      if (!field->is_required()) continue;
+      PrintFieldComment(format, field);
+      field_generators_.get(field).GenerateByteSize(printer);
+      format("\n");
+    }
+    format.Outdent();
+    format(
+        "} else {\n"  // the slow path
+        "  total_size += RequiredFieldsByteSizeFallback();\n"
+        "}\n");
+  } else {
+    // num_required_fields_ <= 1: no need to be tricky
+    for (auto field : optimized_order_) {
+      if (!field->is_required()) continue;
+      PrintFieldComment(format, field);
+      format("if (_internal_has_$1$()) {\n", FieldName(field));
+      format.Indent();
+      field_generators_.get(field).GenerateByteSize(printer);
+      format.Outdent();
+      format("}\n");
+    }
+  }
+
+  std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields(
+      optimized_order_,
+      [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool {
+        return a->label() == b->label() && HasByteIndex(a) == HasByteIndex(b) &&
+               ShouldSplit(a, options_) == ShouldSplit(b, options_);
+      });
+
+  // Remove chunks with required fields.
+  chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired),
+               chunks.end());
+
+  ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_,
+                                kColdRatio);
+  int cached_has_word_index = -1;
+
+  format(
+      "$uint32$ cached_has_bits = 0;\n"
+      "// Prevent compiler warnings about cached_has_bits being unused\n"
+      "(void) cached_has_bits;\n\n");
+
+  for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+    const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+    const bool have_outer_if =
+        chunk.size() > 1 && HasWordIndex(chunk[0]) != kNoHasbit;
+    cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer);
+
+    if (have_outer_if) {
+      // Emit an if() that will let us skip the whole chunk if none are set.
+      uint32_t chunk_mask = GenChunkMask(chunk, has_bit_indices_);
+      std::string chunk_mask_str =
+          StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8));
+
+      // Check (up to) 8 has_bits at a time if we have more than one field in
+      // this chunk.  Due to field layout ordering, we may check
+      // _has_bits_[last_chunk * 8 / 32] multiple times.
+      GOOGLE_DCHECK_LE(2, popcnt(chunk_mask));
+      GOOGLE_DCHECK_GE(8, popcnt(chunk_mask));
+
+      if (cached_has_word_index != HasWordIndex(chunk.front())) {
+        cached_has_word_index = HasWordIndex(chunk.front());
+        format("cached_has_bits = $has_bits$[$1$];\n", cached_has_word_index);
+      }
+      format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str);
+      format.Indent();
+    }
+
+    // Go back and emit checks for each of the fields we processed.
+    for (int j = 0; j < chunk.size(); j++) {
+      const FieldDescriptor* field = chunk[j];
+      const FieldGenerator& generator = field_generators_.get(field);
+      bool have_enclosing_if = false;
+      bool need_extra_newline = false;
+
+      PrintFieldComment(format, field);
+
+      if (field->is_repeated()) {
+        // No presence check is required.
+        need_extra_newline = true;
+      } else if (HasHasbit(field)) {
+        PrintPresenceCheck(format, field, has_bit_indices_, printer,
+                           &cached_has_word_index);
+        have_enclosing_if = true;
+      } else {
+        // Without field presence: field is serialized only if it has a
+        // non-default value.
+        have_enclosing_if =
+            EmitFieldNonDefaultCondition(printer, "this->", field);
+      }
+
+      generator.GenerateByteSize(printer);
+
+      if (have_enclosing_if) {
+        format.Outdent();
+        format(
+            "}\n"
+            "\n");
+      }
+      if (need_extra_newline) {
+        format("\n");
+      }
+    }
+
+    if (have_outer_if) {
+      format.Outdent();
+      format("}\n");
+    }
+
+    if (cold_skipper.OnEndChunk(chunk_index, printer)) {
+      // Reset here as it may have been updated in just closed if statement.
+      cached_has_word_index = -1;
+    }
+  }
+
+  // Fields inside a oneof don't use _has_bits_ so we count them in a separate
+  // pass.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    format("switch ($1$_case()) {\n", oneof->name());
+    format.Indent();
+    for (auto field : FieldRange(oneof)) {
+      PrintFieldComment(format, field);
+      format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
+      format.Indent();
+      if (!IsFieldStripped(field, options_)) {
+        field_generators_.get(field).GenerateByteSize(printer);
+      }
+      format("break;\n");
+      format.Outdent();
+      format("}\n");
+    }
+    format(
+        "case $1$_NOT_SET: {\n"
+        "  break;\n"
+        "}\n",
+        ToUpper(oneof->name()));
+    format.Outdent();
+    format("}\n");
+  }
+
+  if (num_weak_fields_) {
+    // TagSize + MessageSize
+    format("total_size += $weak_field_map$.ByteSizeLong();\n");
+  }
+
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    // We go out of our way to put the computation of the uncommon path of
+    // unknown fields in tail position. This allows for better code generation
+    // of this function for simple protos.
+    format(
+        "return MaybeComputeUnknownFieldsSize(total_size, &$cached_size$);\n");
+  } else {
+    format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
+    format("  total_size += $unknown_fields$.size();\n");
+    format("}\n");
+
+    // We update _cached_size_ even though this is a const method.  Because
+    // const methods might be called concurrently this needs to be atomic
+    // operations or the program is undefined.  In practice, since any
+    // concurrent writes will be writing the exact same value, normal writes
+    // will work on all common processors. We use a dedicated wrapper class to
+    // abstract away the underlying atomic. This makes it easier on platforms
+    // where even relaxed memory order might have perf impact to replace it with
+    // ordinary loads and stores.
+    format(
+        "int cached_size = ::_pbi::ToCachedSize(total_size);\n"
+        "SetCachedSize(cached_size);\n"
+        "return total_size;\n");
+  }
+
+  format.Outdent();
+  format("}\n");
+}
+
+void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  Formatter format(printer, variables_);
+  format("bool $classname$::IsInitialized() const {\n");
+  format.Indent();
+
+  if (descriptor_->extension_range_count() > 0) {
+    format(
+        "if (!$extensions$.IsInitialized()) {\n"
+        "  return false;\n"
+        "}\n\n");
+  }
+
+  if (num_required_fields_ > 0) {
+    format(
+        "if (_Internal::MissingRequiredFields($has_bits$))"
+        " return false;\n");
+  }
+
+  // Now check that all non-oneof embedded messages are initialized.
+  for (auto field : optimized_order_) {
+    field_generators_.get(field).GenerateIsInitialized(printer);
+  }
+  if (num_weak_fields_) {
+    // For Weak fields.
+    format("if (!$weak_field_map$.IsInitialized()) return false;\n");
+  }
+  // Go through the oneof fields, emitting a switch if any might have required
+  // fields.
+  for (auto oneof : OneOfRange(descriptor_)) {
+    bool has_required_fields = false;
+    for (auto field : FieldRange(oneof)) {
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+          !ShouldIgnoreRequiredFieldCheck(field, options_) &&
+          scc_analyzer_->HasRequiredFields(field->message_type())) {
+        has_required_fields = true;
+        break;
+      }
+    }
+
+    if (!has_required_fields) {
+      continue;
+    }
+
+    format("switch ($1$_case()) {\n", oneof->name());
+    format.Indent();
+    for (auto field : FieldRange(oneof)) {
+      format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
+      format.Indent();
+      if (!IsFieldStripped(field, options_)) {
+        field_generators_.get(field).GenerateIsInitialized(printer);
+      }
+      format("break;\n");
+      format.Outdent();
+      format("}\n");
+    }
+    format(
+        "case $1$_NOT_SET: {\n"
+        "  break;\n"
+        "}\n",
+        ToUpper(oneof->name()));
+    format.Outdent();
+    format("}\n");
+  }
+
+  format.Outdent();
+  format(
+      "  return true;\n"
+      "}\n");
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/cpp/message.h b/src/google/protobuf/compiler/cpp/message.h
new file mode 100644
index 0000000..5bdfcb3
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/message.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
+
+#include <cstdint>
+#include <memory>
+#include <set>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/message_layout_helper.h>
+#include <google/protobuf/compiler/cpp/options.h>
+#include <google/protobuf/compiler/cpp/parse_function_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class EnumGenerator;       // enum.h
+class ExtensionGenerator;  // extension.h
+
+class MessageGenerator {
+ public:
+  // See generator.cc for the meaning of dllexport_decl.
+  MessageGenerator(const Descriptor* descriptor,
+                   const std::map<std::string, std::string>& vars,
+                   int index_in_file_messages, const Options& options,
+                   MessageSCCAnalyzer* scc_analyzer);
+  ~MessageGenerator();
+
+  // Append the two types of nested generators to the corresponding vector.
+  void AddGenerators(
+      std::vector<std::unique_ptr<EnumGenerator>>* enum_generators,
+      std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators);
+
+  // Generate definitions for this class and all its nested types.
+  void GenerateClassDefinition(io::Printer* printer);
+
+  // Generate definitions of inline methods (placed at the end of the header
+  // file).
+  void GenerateInlineMethods(io::Printer* printer);
+
+  // Source file stuff.
+
+  // Generate all non-inline methods for this class.
+  void GenerateClassMethods(io::Printer* printer);
+
+  // Generate source file code that should go outside any namespace.
+  void GenerateSourceInProto2Namespace(io::Printer* printer);
+
+ private:
+  // Generate declarations and definitions of accessors for fields.
+  void GenerateFieldAccessorDeclarations(io::Printer* printer);
+  void GenerateFieldAccessorDefinitions(io::Printer* printer);
+
+  // Generate the field offsets array.  Returns the a pair of the total number
+  // of entries generated and the index of the first has_bit entry.
+  std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer);
+  void GenerateSchema(io::Printer* printer, int offset, int has_offset);
+
+  // Generate constructors and destructor.
+  void GenerateStructors(io::Printer* printer);
+
+  // The compiler typically generates multiple copies of each constructor and
+  // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx
+  // Placing common code in a separate method reduces the generated code size.
+  //
+  // Generate the shared constructor code.
+  void GenerateSharedConstructorCode(io::Printer* printer);
+  // Generate the shared destructor code.
+  void GenerateSharedDestructorCode(io::Printer* printer);
+  // Generate the arena-specific destructor code.
+  void GenerateArenaDestructorCode(io::Printer* printer);
+
+  // Generate the constexpr constructor for constant initialization of the
+  // default instance.
+  void GenerateConstexprConstructor(io::Printer* printer);
+
+  void GenerateCreateSplitMessage(io::Printer* printer);
+  void GenerateInitDefaultSplitInstance(io::Printer* printer);
+
+  // Generate standard Message methods.
+  void GenerateClear(io::Printer* printer);
+  void GenerateOneofClear(io::Printer* printer);
+  void GenerateVerify(io::Printer* printer);
+  void GenerateSerializeWithCachedSizes(io::Printer* printer);
+  void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
+  void GenerateSerializeWithCachedSizesBody(io::Printer* printer);
+  void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* printer);
+  void GenerateByteSize(io::Printer* printer);
+  void GenerateMergeFrom(io::Printer* printer);
+  void GenerateClassSpecificMergeImpl(io::Printer* printer);
+  void GenerateCopyFrom(io::Printer* printer);
+  void GenerateSwap(io::Printer* printer);
+  void GenerateIsInitialized(io::Printer* printer);
+
+  // Helpers for GenerateSerializeWithCachedSizes().
+  //
+  // cached_has_bit_index maintains that:
+  //   cached_has_bits = _has_bits_[cached_has_bit_index]
+  // for cached_has_bit_index >= 0
+  void GenerateSerializeOneField(io::Printer* printer,
+                                 const FieldDescriptor* field,
+                                 int cached_has_bits_index);
+  // Generate a switch statement to serialize 2+ fields from the same oneof.
+  // Or, if fields.size() == 1, just call GenerateSerializeOneField().
+  void GenerateSerializeOneofFields(
+      io::Printer* printer, const std::vector<const FieldDescriptor*>& fields);
+  void GenerateSerializeOneExtensionRange(
+      io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+  // Generates has_foo() functions and variables for singular field has-bits.
+  void GenerateSingularFieldHasBits(const FieldDescriptor* field,
+                                    Formatter format);
+  // Generates has_foo() functions and variables for oneof field has-bits.
+  void GenerateOneofHasBits(io::Printer* printer);
+  // Generates has_foo_bar() functions for oneof members.
+  void GenerateOneofMemberHasBits(const FieldDescriptor* field,
+                                  const Formatter& format);
+  // Generates the clear_foo() method for a field.
+  void GenerateFieldClear(const FieldDescriptor* field, bool is_inline,
+                          Formatter format);
+
+  // Generates the body of the message's copy constructor.
+  void GenerateCopyConstructorBody(io::Printer* printer) const;
+
+  // Returns the level that this message needs ArenaDtor. If the message has
+  // a field that is not arena-exclusive, it needs an ArenaDtor
+  // (go/proto-destructor).
+  //
+  // - Returning kNone means we don't need to generate ArenaDtor.
+  // - Returning kOnDemand means we need to generate ArenaDtor, but don't need
+  //   to register ArenaDtor at construction. Such as when the message's
+  //   ArenaDtor code is only for destructing inlined string.
+  // - Returning kRequired means we meed to generate ArenaDtor and register it
+  //   at construction.
+  ArenaDtorNeeds NeedsArenaDestructor() const;
+
+  size_t HasBitsSize() const;
+  size_t InlinedStringDonatedSize() const;
+  int HasBitIndex(const FieldDescriptor* a) const;
+  int HasByteIndex(const FieldDescriptor* a) const;
+  int HasWordIndex(const FieldDescriptor* a) const;
+  bool SameHasByte(const FieldDescriptor* a, const FieldDescriptor* b) const;
+  std::vector<uint32_t> RequiredFieldsBitMask() const;
+
+  const Descriptor* descriptor_;
+  int index_in_file_messages_;
+  std::string classname_;
+  Options options_;
+  FieldGeneratorMap field_generators_;
+  // optimized_order_ is the order we layout the message's fields in the
+  // class. This is reused to initialize the fields in-order for cache
+  // efficiency.
+  //
+  // optimized_order_ excludes oneof fields and weak fields.
+  std::vector<const FieldDescriptor*> optimized_order_;
+  std::vector<int> has_bit_indices_;
+  int max_has_bit_index_;
+
+  // A map from field index to inlined_string index. For non-inlined-string
+  // fields, the element is -1. If there is no inlined string in the message,
+  // this is empty.
+  std::vector<int> inlined_string_indices_;
+  // The count of inlined_string fields in the message.
+  int max_inlined_string_index_;
+
+  std::vector<const EnumGenerator*> enum_generators_;
+  std::vector<const ExtensionGenerator*> extension_generators_;
+  int num_required_fields_;
+  int num_weak_fields_;
+
+  std::unique_ptr<MessageLayoutHelper> message_layout_helper_;
+  std::unique_ptr<ParseFunctionGenerator> parse_function_generator_;
+
+  MessageSCCAnalyzer* scc_analyzer_;
+
+  std::map<std::string, std::string> variables_;
+
+  friend class FileGenerator;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/cpp/message_field.cc b/src/google/protobuf/compiler/cpp/message_field.cc
new file mode 100644
index 0000000..7e87a07
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/message_field.cc
@@ -0,0 +1,958 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/message_field.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+std::string ReinterpretCast(const std::string& type,
+                            const std::string& expression,
+                            bool implicit_weak_field) {
+  if (implicit_weak_field) {
+    return "reinterpret_cast< " + type + " >(" + expression + ")";
+  } else {
+    return expression;
+  }
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         const Options& options, bool implicit_weak,
+                         std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, variables, options);
+  (*variables)["type"] = FieldMessageTypeName(descriptor, options);
+  (*variables)["casted_member"] = ReinterpretCast(
+      (*variables)["type"] + "*", (*variables)["field"], implicit_weak);
+  (*variables)["casted_member_const"] =
+      ReinterpretCast("const " + (*variables)["type"] + "&",
+                      "*" + (*variables)["field"], implicit_weak);
+  (*variables)["type_default_instance"] =
+      QualifiedDefaultInstanceName(descriptor->message_type(), options);
+  (*variables)["type_default_instance_ptr"] = ReinterpretCast(
+      "const ::PROTOBUF_NAMESPACE_ID::MessageLite*",
+      QualifiedDefaultInstancePtr(descriptor->message_type(), options),
+      implicit_weak);
+  (*variables)["type_reference_function"] =
+      implicit_weak ? ("  ::" + (*variables)["proto_ns"] +
+                       "::internal::StrongReference(reinterpret_cast<const " +
+                       (*variables)["type"] + "&>(\n" +
+                       (*variables)["type_default_instance"] + "));\n")
+                    : "";
+  // NOTE: Escaped here to unblock proto1->proto2 migration.
+  // TODO(liujisi): Extend this to apply for other conflicting methods.
+  (*variables)["release_name"] =
+      SafeFunctionName(descriptor->containing_type(), descriptor, "release_");
+  (*variables)["full_name"] = descriptor->full_name();
+}
+
+}  // namespace
+
+// ===================================================================
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             const Options& options,
+                                             MessageSCCAnalyzer* scc_analyzer)
+    : FieldGenerator(descriptor, options),
+      implicit_weak_field_(
+          IsImplicitWeakField(descriptor, options, scc_analyzer)),
+      has_required_fields_(
+          scc_analyzer->HasRequiredFields(descriptor->message_type())) {
+  SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format("::$proto_ns$::MessageLite* $name$_;\n");
+  } else {
+    format("$type$* $name$_;\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (IsFieldStripped(descriptor_, options_)) {
+    format(
+        "$deprecated_attr$const $type$& ${1$$name$$}$() const { "
+        "__builtin_trap(); }\n"
+        "PROTOBUF_NODISCARD $deprecated_attr$$type$* "
+        "${1$$release_name$$}$() { "
+        "__builtin_trap(); }\n"
+        "$deprecated_attr$$type$* ${1$mutable_$name$$}$() { "
+        "__builtin_trap(); }\n"
+        "$deprecated_attr$void ${1$set_allocated_$name$$}$"
+        "($type$* $name$) { __builtin_trap(); }\n"
+        "$deprecated_attr$void "
+        "${1$unsafe_arena_set_allocated_$name$$}$(\n"
+        "    $type$* $name$) { __builtin_trap(); }\n"
+        "$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$() { "
+        "__builtin_trap(); }\n",
+        descriptor_);
+    return;
+  }
+  format(
+      "$deprecated_attr$const $type$& ${1$$name$$}$() const;\n"
+      "PROTOBUF_NODISCARD $deprecated_attr$$type$* "
+      "${1$$release_name$$}$();\n"
+      "$deprecated_attr$$type$* ${1$mutable_$name$$}$();\n"
+      "$deprecated_attr$void ${1$set_allocated_$name$$}$"
+      "($type$* $name$);\n",
+      descriptor_);
+  if (!IsFieldStripped(descriptor_, options_)) {
+    format(
+        "private:\n"
+        "const $type$& ${1$_internal_$name$$}$() const;\n"
+        "$type$* ${1$_internal_mutable_$name$$}$();\n"
+        "public:\n",
+        descriptor_);
+  }
+  format(
+      "$deprecated_attr$void "
+      "${1$unsafe_arena_set_allocated_$name$$}$(\n"
+      "    $type$* $name$);\n"
+      "$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$();\n",
+      descriptor_);
+}
+
+void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
+    io::Printer* printer) const {}
+
+void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline const $type$& $classname$::_internal_$name$() const {\n"
+      "$type_reference_function$"
+      "  const $type$* p = $casted_member$;\n"
+      "  return p != nullptr ? *p : reinterpret_cast<const $type$&>(\n"
+      "      $type_default_instance$);\n"
+      "}\n"
+      "inline const $type$& $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n");
+
+  format(
+      "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
+      "    $type$* $name$) {\n"
+      "$maybe_prepare_split_message$"
+      // If we're not on an arena, free whatever we were holding before.
+      // (If we are on arena, we can just forget the earlier pointer.)
+      "  if (GetArenaForAllocation() == nullptr) {\n"
+      "    delete reinterpret_cast<::$proto_ns$::MessageLite*>($field$);\n"
+      "  }\n");
+  if (implicit_weak_field_) {
+    format(
+        "  $field$ = reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n");
+  } else {
+    format("  $field$ = $name$;\n");
+  }
+  format(
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
+      ":$full_name$)\n"
+      "}\n");
+  format(
+      "inline $type$* $classname$::$release_name$() {\n"
+      "$type_reference_function$"
+      "$annotate_release$"
+      "$maybe_prepare_split_message$"
+      "  $clear_hasbit$\n"
+      "  $type$* temp = $casted_member$;\n"
+      "  $field$ = nullptr;\n"
+      "#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE\n"
+      "  auto* old =  reinterpret_cast<::$proto_ns$::MessageLite*>(temp);\n"
+      "  temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
+      "  if (GetArenaForAllocation() == nullptr) { delete old; }\n"
+      "#else  // PROTOBUF_FORCE_COPY_IN_RELEASE\n"
+      "  if (GetArenaForAllocation() != nullptr) {\n"
+      "    temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
+      "  }\n"
+      "#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE\n"
+      "  return temp;\n"
+      "}\n"
+      "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+      "$annotate_release$"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "$type_reference_function$"
+      "$maybe_prepare_split_message$"
+      "  $clear_hasbit$\n"
+      "  $type$* temp = $casted_member$;\n"
+      "  $field$ = nullptr;\n"
+      "  return temp;\n"
+      "}\n");
+
+  format(
+      "inline $type$* $classname$::_internal_mutable_$name$() {\n"
+      "$type_reference_function$"
+      "  $set_hasbit$\n"
+      "  if ($field$ == nullptr) {\n"
+      "    auto* p = CreateMaybeMessage<$type$>(GetArenaForAllocation());\n");
+  if (implicit_weak_field_) {
+    format("    $field$ = reinterpret_cast<::$proto_ns$::MessageLite*>(p);\n");
+  } else {
+    format("    $field$ = p;\n");
+  }
+  format(
+      "  }\n"
+      "  return $casted_member$;\n"
+      "}\n"
+      "inline $type$* $classname$::mutable_$name$() {\n"
+      // TODO(b/122856539): add tests to make sure all write accessors are able
+      // to prepare split message allocation.
+      "$maybe_prepare_split_message$"
+      "  $type$* _msg = _internal_mutable_$name$();\n"
+      "$annotate_mutable$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return _msg;\n"
+      "}\n");
+
+  // We handle the most common case inline, and delegate less common cases to
+  // the slow fallback function.
+  format(
+      "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "  ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n");
+  format(
+      "$maybe_prepare_split_message$"
+      "  if (message_arena == nullptr) {\n");
+  if (IsCrossFileMessage(descriptor_)) {
+    format(
+        "    delete reinterpret_cast< ::$proto_ns$::MessageLite*>($field$);\n");
+  } else {
+    format("    delete $field$;\n");
+  }
+  format(
+      "  }\n"
+      "  if ($name$) {\n");
+  if (IsCrossFileMessage(descriptor_)) {
+    // We have to read the arena through the virtual method, because the type
+    // isn't defined in this file.
+    format(
+        "    ::$proto_ns$::Arena* submessage_arena =\n"
+        "        ::$proto_ns$::Arena::InternalGetOwningArena(\n"
+        "                reinterpret_cast<::$proto_ns$::MessageLite*>("
+        "$name$));\n");
+  } else {
+    format(
+        "    ::$proto_ns$::Arena* submessage_arena =\n"
+        "        ::$proto_ns$::Arena::InternalGetOwningArena("
+        "$name$);\n");
+  }
+  format(
+      "    if (message_arena != submessage_arena) {\n"
+      "      $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n"
+      "          message_arena, $name$, submessage_arena);\n"
+      "    }\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n");
+  if (implicit_weak_field_) {
+    format("  $field$ = reinterpret_cast<MessageLite*>($name$);\n");
+  } else {
+    format("  $field$ = $name$;\n");
+  }
+  format(
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+}
+
+void MessageFieldGenerator::GenerateInternalAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format(
+        "static const ::$proto_ns$::MessageLite& $name$("
+        "const $classname$* msg);\n"
+        "static ::$proto_ns$::MessageLite* mutable_$name$("
+        "$classname$* msg);\n");
+  } else {
+    format("static const $type$& $name$(const $classname$* msg);\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateInternalAccessorDefinitions(
+    io::Printer* printer) const {
+  // In theory, these accessors could be inline in _Internal. However, in
+  // practice, the linker is then not able to throw them out making implicit
+  // weak dependencies not work at all.
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    // These private accessors are used by MergeFrom and
+    // MergePartialFromCodedStream, and their purpose is to provide access to
+    // the field without creating a strong dependency on the message type.
+    format(
+        "const ::$proto_ns$::MessageLite& $classname$::_Internal::$name$(\n"
+        "    const $classname$* msg) {\n"
+        "  if (msg->$field$ != nullptr) {\n"
+        "    return *msg->$field$;\n"
+        "  } else {\n"
+        "    return *$type_default_instance_ptr$;\n"
+        "  }\n"
+        "}\n");
+    format(
+        "::$proto_ns$::MessageLite*\n"
+        "$classname$::_Internal::mutable_$name$($classname$* msg) {\n");
+    if (HasHasbit(descriptor_)) {
+      format("  msg->$set_hasbit$\n");
+    }
+    if (descriptor_->real_containing_oneof() == nullptr) {
+      format("  if (msg->$field$ == nullptr) {\n");
+    } else {
+      format(
+          "  if (!msg->_internal_has_$name$()) {\n"
+          "    msg->clear_$oneof_name$();\n"
+          "    msg->set_has_$name$();\n");
+    }
+    format(
+        "    msg->$field$ = $type_default_instance_ptr$->New(\n"
+        "        msg->GetArenaForAllocation());\n"
+        "  }\n"
+        "  return msg->$field$;\n"
+        "}\n");
+  } else {
+    // This inline accessor directly returns member field and is used in
+    // Serialize such that AFDO profile correctly captures access information to
+    // message fields under serialize.
+    format(
+        "const $type$&\n"
+        "$classname$::_Internal::$name$(const $classname$* msg) {\n"
+        "  return *msg->$field$;\n"
+        "}\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (!HasHasbit(descriptor_)) {
+    // If we don't have has-bits, message presence is indicated only by ptr !=
+    // nullptr. Thus on clear, we need to delete the object.
+    format(
+        "if (GetArenaForAllocation() == nullptr && $field$ != nullptr) {\n"
+        "  delete $field$;\n"
+        "}\n"
+        "$field$ = nullptr;\n");
+  } else {
+    format("if ($field$ != nullptr) $field$->Clear();\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateMessageClearingCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (!HasHasbit(descriptor_)) {
+    // If we don't have has-bits, message presence is indicated only by ptr !=
+    // nullptr. Thus on clear, we need to delete the object.
+    format(
+        "if (GetArenaForAllocation() == nullptr && $field$ != nullptr) {\n"
+        "  delete $field$;\n"
+        "}\n"
+        "$field$ = nullptr;\n");
+  } else {
+    format(
+        "$DCHK$($field$ != nullptr);\n"
+        "$field$->Clear();\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format(
+        "_Internal::mutable_$name$(_this)->CheckTypeAndMergeFrom(\n"
+        "    _Internal::$name$(&from));\n");
+  } else {
+    format(
+        "_this->_internal_mutable_$name$()->$type$::MergeFrom(\n"
+        "    from._internal_$name$());\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format("swap($field$, other->$field$);\n");
+}
+
+void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (options_.opensource_runtime) {
+    // TODO(gerbens) Remove this when we don't need to destruct default
+    // instances.  In google3 a default instance will never get deleted so we
+    // don't need to worry about that but in opensource protobuf default
+    // instances are deleted in shutdown process and we need to take special
+    // care when handling them.
+    format("if (this != internal_default_instance()) ");
+  }
+  if (ShouldSplit(descriptor_, options_)) {
+    format("delete $cached_split_ptr$->$name$_;\n");
+    return;
+  }
+  format("delete $field$;\n");
+}
+
+void MessageFieldGenerator::GenerateCopyConstructorCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format(
+      "if (from._internal_has_$name$()) {\n"
+      "  _this->$field$ = new $type$(*from.$field$);\n"
+      "}\n");
+}
+
+void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+    format(
+        "target = ::$proto_ns$::internal::WireFormatLite::\n"
+        "  InternalWrite$declared_type$($number$, _Internal::$name$(this),\n"
+        "    _Internal::$name$(this).GetCachedSize(), target, stream);\n");
+  } else {
+    format(
+        "target = stream->EnsureSpace(target);\n"
+        "target = ::$proto_ns$::internal::WireFormatLite::\n"
+        "  InternalWrite$declared_type$(\n"
+        "    $number$, _Internal::$name$(this), target, stream);\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format(
+      "total_size += $tag_size$ +\n"
+      "  ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+      "    *$field$);\n");
+}
+
+void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  if (!has_required_fields_) return;
+
+  Formatter format(printer, variables_);
+  format(
+      "if (_internal_has_$name$()) {\n"
+      "  if (!$field$->IsInitialized()) return false;\n"
+      "}\n");
+}
+
+void MessageFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("/*decltype($field$)*/nullptr");
+}
+
+void MessageFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){nullptr}");
+}
+
+void MessageFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    format("decltype(Impl_::Split::$name$_){nullptr}");
+    return;
+  }
+  format("decltype($field$){nullptr}");
+}
+
+// ===================================================================
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer)
+    : MessageFieldGenerator(descriptor, options, scc_analyzer) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
+
+void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "  ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n"
+      "  clear_$oneof_name$();\n"
+      "  if ($name$) {\n");
+  if (descriptor_->file() != descriptor_->message_type()->file()) {
+    // We have to read the arena through the virtual method, because the type
+    // isn't defined in this file.
+    format(
+        "    ::$proto_ns$::Arena* submessage_arena =\n"
+        "        ::$proto_ns$::Arena::InternalGetOwningArena(\n"
+        "                reinterpret_cast<::$proto_ns$::MessageLite*>("
+        "$name$));\n");
+  } else {
+    format(
+        "    ::$proto_ns$::Arena* submessage_arena =\n"
+        "      ::$proto_ns$::Arena::InternalGetOwningArena($name$);\n");
+  }
+  format(
+      "    if (message_arena != submessage_arena) {\n"
+      "      $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n"
+      "          message_arena, $name$, submessage_arena);\n"
+      "    }\n"
+      "    set_has_$name$();\n"
+      "    $field$ = $name$;\n"
+      "  }\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+}
+
+void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$* $classname$::$release_name$() {\n"
+      "$annotate_release$"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "$type_reference_function$"
+      "  if (_internal_has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    $type$* temp = $casted_member$;\n"
+      "    if (GetArenaForAllocation() != nullptr) {\n"
+      "      temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
+      "    }\n"
+      "    $field$ = nullptr;\n"
+      "    return temp;\n"
+      "  } else {\n"
+      "    return nullptr;\n"
+      "  }\n"
+      "}\n");
+
+  format(
+      "inline const $type$& $classname$::_internal_$name$() const {\n"
+      "$type_reference_function$"
+      "  return _internal_has_$name$()\n"
+      "      ? $casted_member_const$\n"
+      "      : reinterpret_cast< $type$&>($type_default_instance$);\n"
+      "}\n"
+      "inline const $type$& $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+      "$annotate_release$"
+      "  // @@protoc_insertion_point(field_unsafe_arena_release"
+      ":$full_name$)\n"
+      "$type_reference_function$"
+      "  if (_internal_has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    $type$* temp = $casted_member$;\n"
+      "    $field$ = nullptr;\n"
+      "    return temp;\n"
+      "  } else {\n"
+      "    return nullptr;\n"
+      "  }\n"
+      "}\n"
+      "inline void $classname$::unsafe_arena_set_allocated_$name$"
+      "($type$* $name$) {\n"
+      // We rely on the oneof clear method to free the earlier contents of
+      // this oneof. We can directly use the pointer we're given to set the
+      // new value.
+      "  clear_$oneof_name$();\n"
+      "  if ($name$) {\n"
+      "    set_has_$name$();\n");
+  if (implicit_weak_field_) {
+    format(
+        "    $field$ = "
+        "reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n");
+  } else {
+    format("    $field$ = $name$;\n");
+  }
+  format(
+      "  }\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
+      "$full_name$)\n"
+      "}\n"
+      "inline $type$* $classname$::_internal_mutable_$name$() {\n"
+      "$type_reference_function$"
+      "  if (!_internal_has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n");
+  if (implicit_weak_field_) {
+    format(
+        "    $field$ = "
+        "reinterpret_cast<::$proto_ns$::MessageLite*>(CreateMaybeMessage< "
+        "$type$ >(GetArenaForAllocation()));\n");
+  } else {
+    format(
+        "    $field$ = CreateMaybeMessage< $type$ "
+        ">(GetArenaForAllocation());\n");
+  }
+  format(
+      "  }\n"
+      "  return $casted_member$;\n"
+      "}\n"
+      "inline $type$* $classname$::mutable_$name$() {\n"
+      "  $type$* _msg = _internal_mutable_$name$();\n"
+      "$annotate_mutable$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return _msg;\n"
+      "}\n");
+}
+
+void MessageOneofFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format(
+      "if (GetArenaForAllocation() == nullptr) {\n"
+      "  delete $field$;\n"
+      "}\n");
+}
+
+void MessageOneofFieldGenerator::GenerateMessageClearingCode(
+    io::Printer* printer) const {
+  GenerateClearingCode(printer);
+}
+
+void MessageOneofFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void MessageOneofFieldGenerator::GenerateDestructorCode(
+    io::Printer* printer) const {
+  // We inherit from MessageFieldGenerator, so we need to override the default
+  // behavior.
+}
+
+void MessageOneofFieldGenerator::GenerateConstructorCode(
+    io::Printer* printer) const {
+  // Don't print any constructor code. The field is in a union. We allocate
+  // space only when this field is used.
+}
+
+void MessageOneofFieldGenerator::GenerateIsInitialized(
+    io::Printer* printer) const {
+  if (!has_required_fields_) return;
+
+  Formatter format(printer, variables_);
+  format(
+      "if (_internal_has_$name$()) {\n"
+      "  if (!$field$->IsInitialized()) return false;\n"
+      "}\n");
+}
+
+// ===================================================================
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer)
+    : FieldGenerator(descriptor, options),
+      implicit_weak_field_(
+          IsImplicitWeakField(descriptor, options, scc_analyzer)),
+      has_required_fields_(
+          scc_analyzer->HasRequiredFields(descriptor->message_type())) {
+  SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::GeneratePrivateMembers(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format("::$proto_ns$::WeakRepeatedPtrField< $type$ > $name$_;\n");
+  } else {
+    format("::$proto_ns$::RepeatedPtrField< $type$ > $name$_;\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (IsFieldStripped(descriptor_, options_)) {
+    format(
+        "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index) { "
+        "__builtin_trap(); }\n"
+        "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n"
+        "    ${1$mutable_$name$$}$() { __builtin_trap(); }\n"
+        "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const { "
+        "__builtin_trap(); }\n"
+        "$deprecated_attr$$type$* ${1$add_$name$$}$() { "
+        "__builtin_trap(); }\n"
+        "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
+        "    ${1$$name$$}$() const { __builtin_trap(); }\n",
+        descriptor_);
+    return;
+  }
+  format(
+      "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index);\n"
+      "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n"
+      "    ${1$mutable_$name$$}$();\n",
+      descriptor_);
+  if (!IsFieldStripped(descriptor_, options_)) {
+    format(
+        "private:\n"
+        "const $type$& ${1$_internal_$name$$}$(int index) const;\n"
+        "$type$* ${1$_internal_add_$name$$}$();\n"
+        "public:\n",
+        descriptor_);
+  }
+  format(
+      "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n"
+      "$deprecated_attr$$type$* ${1$add_$name$$}$();\n"
+      "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
+      "    ${1$$name$$}$() const;\n",
+      descriptor_);
+}
+
+void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format.Set("weak", implicit_weak_field_ ? ".weak" : "");
+
+  format(
+      "inline $type$* $classname$::mutable_$name$(int index) {\n"
+      "$annotate_mutable$"
+      // TODO(dlj): move insertion points
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "$type_reference_function$"
+      "  return $field$$weak$.Mutable(index);\n"
+      "}\n"
+      "inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n"
+      "$classname$::mutable_$name$() {\n"
+      "$annotate_mutable_list$"
+      "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
+      "$type_reference_function$"
+      "  return &$field$$weak$;\n"
+      "}\n");
+
+  if (options_.safe_boundary_check) {
+    format(
+        "inline const $type$& $classname$::_internal_$name$(int index) const "
+        "{\n"
+        "  return $field$$weak$.InternalCheckedGet(index,\n"
+        "      reinterpret_cast<const $type$&>($type_default_instance$));\n"
+        "}\n");
+  } else {
+    format(
+        "inline const $type$& $classname$::_internal_$name$(int index) const "
+        "{\n"
+        "$type_reference_function$"
+        "  return $field$$weak$.Get(index);\n"
+        "}\n");
+  }
+
+  format(
+      "inline const $type$& $classname$::$name$(int index) const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$(index);\n"
+      "}\n"
+      "inline $type$* $classname$::_internal_add_$name$() {\n"
+      "  return $field$$weak$.Add();\n"
+      "}\n"
+      "inline $type$* $classname$::add_$name$() {\n"
+      "  $type$* _add = _internal_add_$name$();\n"
+      "$annotate_add_mutable$"
+      "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "  return _add;\n"
+      "}\n");
+
+  format(
+      "inline const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
+      "$classname$::$name$() const {\n"
+      "$annotate_list$"
+      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+      "$type_reference_function$"
+      "  return $field$$weak$;\n"
+      "}\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format("$field$.Clear();\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format("_this->$field$.MergeFrom(from.$field$);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format("$field$.InternalSwap(&other->$field$);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateConstructorCode(
+    io::Printer* printer) const {
+  // Not needed for repeated fields.
+}
+
+void RepeatedMessageFieldGenerator::GenerateDestructorCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format("$field$.~WeakRepeatedPtrField();\n");
+  } else {
+    format("$field$.~RepeatedPtrField();\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format(
+        "for (auto it = this->$field$.pointer_begin(),\n"
+        "          end = this->$field$.pointer_end(); it < end; ++it) {\n");
+    if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+      format(
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "    InternalWrite$declared_type$($number$, "
+          "**it, (**it).GetCachedSize(), target, stream);\n");
+    } else {
+      format(
+          "  target = stream->EnsureSpace(target);\n"
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "    InternalWrite$declared_type$($number$, **it, target, "
+          "stream);\n");
+    }
+    format("}\n");
+  } else {
+    format(
+        "for (unsigned i = 0,\n"
+        "    n = static_cast<unsigned>(this->_internal_$name$_size());"
+        " i < n; i++) {\n");
+    if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+      format(
+          "  const auto& repfield = this->_internal_$name$(i);\n"
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "      InternalWrite$declared_type$($number$, "
+          "repfield, repfield.GetCachedSize(), target, stream);\n"
+          "}\n");
+    } else {
+      format(
+          "  target = stream->EnsureSpace(target);\n"
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "    InternalWrite$declared_type$($number$, "
+          "this->_internal_$name$(i), target, stream);\n"
+          "}\n");
+    }
+  }
+}
+
+void RepeatedMessageFieldGenerator::GenerateByteSize(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  Formatter format(printer, variables_);
+  format(
+      "total_size += $tag_size$UL * this->_internal_$name$_size();\n"
+      "for (const auto& msg : this->$field$) {\n"
+      "  total_size +=\n"
+      "    ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(msg);\n"
+      "}\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateIsInitialized(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
+  if (!has_required_fields_) return;
+
+  Formatter format(printer, variables_);
+  if (implicit_weak_field_) {
+    format(
+        "if (!::$proto_ns$::internal::AllAreInitializedWeak($field$.weak))\n"
+        "  return false;\n");
+  } else {
+    format(
+        "if (!::$proto_ns$::internal::AllAreInitialized($field$))\n"
+        "  return false;\n");
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/message_field.h b/src/google/protobuf/compiler/cpp/message_field.h
new file mode 100644
index 0000000..70c42c0
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/message_field.h
@@ -0,0 +1,148 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/field.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MessageFieldGenerator : public FieldGenerator {
+ public:
+  MessageFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options,
+                        MessageSCCAnalyzer* scc_analyzer);
+  ~MessageFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateNonInlineAccessorDefinitions(
+      io::Printer* printer) const override;
+  void GenerateInternalAccessorDeclarations(
+      io::Printer* printer) const override;
+  void GenerateInternalAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMessageClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override {}
+  void GenerateCopyConstructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateIsInitialized(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+
+ protected:
+  const bool implicit_weak_field_;
+  const bool has_required_fields_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class MessageOneofFieldGenerator : public MessageFieldGenerator {
+ public:
+  MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options,
+                             MessageSCCAnalyzer* scc_analyzer);
+  ~MessageOneofFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateNonInlineAccessorDefinitions(
+      io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+
+  // MessageFieldGenerator, from which we inherit, overrides this so we need to
+  // override it as well.
+  void GenerateMessageClearingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+  void GenerateIsInitialized(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public FieldGenerator {
+ public:
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                const Options& options,
+                                MessageSCCAnalyzer* scc_analyzer);
+  ~RepeatedMessageFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+  void GenerateCopyConstructorCode(io::Printer* printer) const override {}
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateIsInitialized(io::Printer* printer) const override;
+
+ private:
+  const bool implicit_weak_field_;
+  const bool has_required_fields_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/message_layout_helper.h b/src/google/protobuf/compiler/cpp/message_layout_helper.h
new file mode 100644
index 0000000..a8813a1
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/message_layout_helper.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.
+
+// Author: seongkim@google.com (Seong Beom Kim)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MessageSCCAnalyzer;
+
+// Provides an abstract interface to optimize message layout
+// by rearranging the fields of a message.
+class MessageLayoutHelper {
+ public:
+  virtual ~MessageLayoutHelper() {}
+
+  virtual void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
+                              const Options& options,
+                              MessageSCCAnalyzer* scc_analyzer) = 0;
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
diff --git a/src/google/protobuf/compiler/cpp/message_size_unittest.cc b/src/google/protobuf/compiler/cpp/message_size_unittest.cc
new file mode 100644
index 0000000..761988b
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/message_size_unittest.cc
@@ -0,0 +1,272 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/unittest.pb.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace cpp_unittest {
+
+
+#if !defined(GOOGLE_CHECK_MESSAGE_SIZE)
+#define GOOGLE_CHECK_MESSAGE_SIZE(t, expected)
+#endif
+
+// Mock structures to lock down the size of messages in a platform-independent
+// way.  The commented sizes only apply when build with clang x86_64.
+struct MockMessageBase {
+  virtual ~MockMessageBase() = default;  // 8 bytes vtable
+  void* internal_metadata;               // 8 bytes
+};
+GOOGLE_CHECK_MESSAGE_SIZE(MockMessageBase, 16);
+
+struct MockZeroFieldsBase : public MockMessageBase {
+  int cached_size;  // 4 bytes
+  // + 4 bytes padding
+};
+GOOGLE_CHECK_MESSAGE_SIZE(MockZeroFieldsBase, 24);
+
+struct MockExtensionSet {
+  void* arena;       // 8 bytes
+  int16_t capacity;  // 4 bytes
+  int16_t size;      // 4 bytes
+  void* data;        // 8 bytes
+};
+GOOGLE_CHECK_MESSAGE_SIZE(MockExtensionSet, 24);
+
+struct MockRepeatedPtrField {
+  void* arena;       // 8 bytes
+  int current_size;  // 4 bytes
+  int total_size;    // 4 bytes
+  void* data;        // 8 bytes
+};
+GOOGLE_CHECK_MESSAGE_SIZE(MockRepeatedPtrField, 24);
+
+struct MockRepeatedField {
+  int current_size;  // 4 bytes
+  int total_size;    // 4 bytes
+  void* data;        // 8 bytes
+};
+GOOGLE_CHECK_MESSAGE_SIZE(MockRepeatedField, 16);
+
+TEST(GeneratedMessageTest, MockSizes) {
+  // Consistency checks -- if these fail, the tests below will definitely fail.
+  GOOGLE_CHECK_EQ(sizeof(MessageLite), sizeof(MockMessageBase));
+  GOOGLE_CHECK_EQ(sizeof(Message), sizeof(MockMessageBase));
+  GOOGLE_CHECK_EQ(sizeof(internal::ZeroFieldsBase), sizeof(MockZeroFieldsBase));
+  GOOGLE_CHECK_EQ(sizeof(internal::ExtensionSet), sizeof(MockExtensionSet));
+  GOOGLE_CHECK_EQ(sizeof(RepeatedPtrField<std::string>), sizeof(MockRepeatedPtrField));
+  GOOGLE_CHECK_EQ(sizeof(RepeatedField<int>), sizeof(MockRepeatedField));
+}
+
+TEST(GeneratedMessageTest, EmptyMessageSize) {
+  EXPECT_EQ(sizeof(protobuf_unittest::TestEmptyMessage),
+            sizeof(MockZeroFieldsBase));
+}
+
+TEST(GeneratedMessageTest, ReservedSize) {
+  EXPECT_EQ(sizeof(protobuf_unittest::TestReservedFields),
+            sizeof(MockZeroFieldsBase));
+}
+
+TEST(GeneratedMessageTest, EmptyMessageWithExtensionsSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    MockExtensionSet extensions;                   // 24 bytes
+    int cached_size;                               // 4 bytes
+    // + 4 bytes of padding
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 48);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestEmptyMessageWithExtensions),
+            sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, RecursiveMessageSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    void* a;                                       // 8 bytes
+    int32_t i;                                     // 4 bytes
+    // + 4 bytes padding
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 40);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestRecursiveMessage),
+            sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, OneStringSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    void* data;                                    // 8 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
+  EXPECT_EQ(sizeof(protobuf_unittest::OneString), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, MoreStringSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    MockRepeatedPtrField data;                     // 24 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 48);
+  EXPECT_EQ(sizeof(protobuf_unittest::MoreString), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, Int32MessageSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    int32_t data;                                  // 4 bytes
+    // + 4 bytes padding
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
+  EXPECT_EQ(sizeof(protobuf_unittest::Int32Message), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, Int64MessageSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    int64_t data;                                  // 8 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
+  EXPECT_EQ(sizeof(protobuf_unittest::Int64Message), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, BoolMessageSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    bool data;                                     // 1 byte
+    // + 3 bytes padding
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
+  EXPECT_EQ(sizeof(protobuf_unittest::BoolMessage), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, OneofSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    void* foo;                                     // 8 bytes
+    int cached_size;                               // 4 bytes
+    uint32_t oneof_case[1];                        // 4 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestOneof), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, Oneof2Size) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    void* baz_string;                              // 8 bytes
+    int32_t baz_int;                               // 4 bytes
+                                                   // + 4 bytes padding
+    void* foo;                                     // 8 bytes
+    void* bar;                                     // 8 bytes
+    uint32_t oneof_case[2];                        // 8 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 64);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestOneof2), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, FieldOrderingsSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    MockExtensionSet extensions;                   // 24 bytes
+    void* my_string;                               // 8 bytes
+    void* optional_nested_message;                 // 8 bytes
+    int64_t my_int;                                // 8 bytes
+    float my_float;                                // 4 bytes
+    // + 4 bytes of padding
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 80);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestFieldOrderings), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, TestMessageSize) {
+  // We expect the message to contain (not in this order):
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    int has_bits[1];                               // 4 bytes
+    int cached_size;                               // 4 bytes
+    void* m4;                                      // 8 bytes
+    int64_t m2;                                    // 8 bytes
+    bool m1;                                       // 1 bytes
+    bool m3;                                       // 1 bytes
+                                                   // + 2 bytes padding
+    int m5;                                        // 4 bytes
+    int64_t m6;                                    // 8 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 56);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestMessageSize), sizeof(MockGenerated));
+}
+
+TEST(GeneratedMessageTest, PackedTypesSize) {
+  struct MockGenerated : public MockMessageBase {  // 16 bytes
+    MockRepeatedField packed_int32;                // 16 bytes
+    int packed_int32_cached_byte_size;             // 4 bytes + 4 bytes padding
+    MockRepeatedField packed_int64;                // 16 bytes
+    int packed_int64_cached_byte_size;             // 4 bytes + 4 bytes padding
+    MockRepeatedField packed_uint32;               // 16 bytes
+    int packed_uint32_cached_byte_size;            // 4 bytes + 4 bytes padding
+    MockRepeatedField packed_uint64;               // 16 bytes
+    int packed_uint64_cached_byte_size;            // 4 bytes + 4 bytes padding
+    MockRepeatedField packed_sint32;               // 16 bytes
+    int packed_sint32_cached_byte_size;            // 4 bytes + 4 bytes padding
+    MockRepeatedField packed_sint64;               // 16 bytes
+    int packed_sint64_cached_byte_size;            // 4 bytes + 4 bytes padding
+    MockRepeatedField packed_fixed32;              // 16 bytes
+    MockRepeatedField packed_fixed64;              // 16 bytes
+    MockRepeatedField packed_sfixed32;             // 16 bytes
+    MockRepeatedField packed_sfixed64;             // 16 bytes
+    MockRepeatedField packed_float;                // 16 bytes
+    MockRepeatedField packed_double;               // 16 bytes
+    MockRepeatedField packed_bool;                 // 16 bytes
+    MockRepeatedField packed_enum;                 // 16 bytes
+    int packed_enum_cached_byte_size;              // 4 bytes
+    int cached_size;                               // 4 bytes
+  };
+  GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 16 * 15 + 8 * 6 + 8);
+  EXPECT_EQ(sizeof(protobuf_unittest::TestPackedTypes), sizeof(MockGenerated));
+}
+
+}  // namespace cpp_unittest
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
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..1ffd357
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -0,0 +1,161 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/cpp/generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/compiler/annotation_test_util.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace atu = annotation_test_util;
+
+namespace {
+
+class CppMetadataTest : public ::testing::Test {
+ public:
+  // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
+  // code from the previously added file with name `filename`. Returns true on
+  // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to
+  // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info.
+  bool CaptureMetadata(const std::string& filename, FileDescriptorProto* file,
+                       std::string* pb_h, GeneratedCodeInfo* pb_h_info,
+                       std::string* proto_h, GeneratedCodeInfo* proto_h_info,
+                       std::string* pb_cc) {
+    CommandLineInterface cli;
+    CppGenerator cpp_generator;
+    cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
+    std::string cpp_out =
+        "--cpp_out=annotate_headers=true,"
+        "annotation_pragma_name=pragma_name,"
+        "annotation_guard_name=guard_name:" +
+        TestTempDir();
+
+    const bool result = atu::RunProtoCompiler(filename, cpp_out, &cli, file);
+
+    if (!result) {
+      return result;
+    }
+
+    std::string output_base = TestTempDir() + "/" + StripProto(filename);
+
+    if (pb_cc != nullptr) {
+      GOOGLE_CHECK_OK(
+          File::GetContents(output_base + ".pb.cc", pb_cc, true));
+    }
+
+    if (pb_h != nullptr && pb_h_info != nullptr) {
+      GOOGLE_CHECK_OK(
+          File::GetContents(output_base + ".pb.h", pb_h, true));
+      if (!atu::DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
+        return false;
+      }
+    }
+
+    if (proto_h != nullptr && proto_h_info != nullptr) {
+      GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
+                                 true));
+      if (!atu::DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+};
+
+const char kSmallTestFile[] =
+    "syntax = \"proto2\";\n"
+    "package foo;\n"
+    "enum Enum { VALUE = 0; }\n"
+    "message Message { }\n";
+
+TEST_F(CppMetadataTest, CapturesEnumNames) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Enum", file.enum_type(0).name());
+  std::vector<int> enum_path;
+  enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+  enum_path.push_back(0);
+  const GeneratedCodeInfo::Annotation* enum_annotation =
+      atu::FindAnnotationOnPath(info, "test.proto", enum_path);
+  EXPECT_TRUE(nullptr != enum_annotation);
+  EXPECT_TRUE(atu::AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
+}
+
+TEST_F(CppMetadataTest, AddsPragma) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_TRUE(pb_h.find("#ifdef guard_name") != std::string::npos);
+  EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
+              std::string::npos);
+}
+
+TEST_F(CppMetadataTest, CapturesMessageNames) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  std::string pb_h;
+  atu::AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  std::vector<int> message_path;
+  message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+  message_path.push_back(0);
+  const GeneratedCodeInfo::Annotation* message_annotation =
+      atu::FindAnnotationOnPath(info, "test.proto", message_path);
+  EXPECT_TRUE(nullptr != message_annotation);
+  EXPECT_TRUE(
+      atu::AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
+}
+
+}  // namespace
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/move_unittest.cc b/src/google/protobuf/compiler/cpp/move_unittest.cc
new file mode 100644
index 0000000..eb7cd1c
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/move_unittest.cc
@@ -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.
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <gtest/gtest.h>
+
+#if LANG_CXX11
+#include <type_traits>
+#endif
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace cpp_unittest {
+
+// Moves are enabled only when compiling with a C++11 compiler or newer.
+#if LANG_CXX11
+
+TEST(MovableMessageTest, MoveConstructor) {
+  protobuf_unittest::TestAllTypes message1;
+  TestUtil::SetAllFields(&message1);
+  const auto* nested = &message1.optional_nested_message();
+
+  protobuf_unittest::TestAllTypes message2(std::move(message1));
+  TestUtil::ExpectAllFieldsSet(message2);
+
+  // Check if the optional_nested_message was actually moved (and not just
+  // copied).
+  EXPECT_EQ(nested, &message2.optional_nested_message());
+  EXPECT_NE(nested, &message1.optional_nested_message());
+}
+
+TEST(MovableMessageTest, MoveAssignmentOperator) {
+  protobuf_unittest::TestAllTypes message1;
+  TestUtil::SetAllFields(&message1);
+  const auto* nested = &message1.optional_nested_message();
+
+  protobuf_unittest::TestAllTypes message2;
+  message2 = std::move(message1);
+  TestUtil::ExpectAllFieldsSet(message2);
+
+  // Check if the optional_nested_message was actually moved (and not just
+  // copied).
+  EXPECT_EQ(nested, &message2.optional_nested_message());
+  EXPECT_NE(nested, &message1.optional_nested_message());
+}
+
+TEST(MovableMessageTest, SelfMoveAssignment) {
+  // The `self` reference is necessary to defeat -Wself-move.
+  protobuf_unittest::TestAllTypes message, &self = message;
+  TestUtil::SetAllFields(&message);
+  message = std::move(self);
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(MovableMessageTest, MoveSameArena) {
+  Arena arena;
+
+  auto* message1_on_arena =
+      Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+  TestUtil::SetAllFields(message1_on_arena);
+  const auto* nested = &message1_on_arena->optional_nested_message();
+
+  auto* message2_on_arena =
+      Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+
+  // Moving messages on the same arena should lead to swapped pointers.
+  *message2_on_arena = std::move(*message1_on_arena);
+  EXPECT_EQ(nested, &message2_on_arena->optional_nested_message());
+}
+
+TEST(MovableMessageTest, MoveDifferentArenas) {
+  Arena arena1, arena2;
+
+  auto* message1_on_arena =
+      Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1);
+  TestUtil::SetAllFields(message1_on_arena);
+  const auto* nested = &message1_on_arena->optional_nested_message();
+
+  auto* message2_on_arena =
+      Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2);
+
+  // Moving messages on two different arenas should lead to a copy.
+  *message2_on_arena = std::move(*message1_on_arena);
+  EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
+  TestUtil::ExpectAllFieldsSet(*message1_on_arena);
+  TestUtil::ExpectAllFieldsSet(*message2_on_arena);
+}
+
+TEST(MovableMessageTest, MoveFromArena) {
+  Arena arena;
+
+  auto* message1_on_arena =
+      Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+  TestUtil::SetAllFields(message1_on_arena);
+  const auto* nested = &message1_on_arena->optional_nested_message();
+
+  protobuf_unittest::TestAllTypes message2;
+
+  // Moving from a message on the arena should lead to a copy.
+  message2 = std::move(*message1_on_arena);
+  EXPECT_NE(nested, &message2.optional_nested_message());
+  TestUtil::ExpectAllFieldsSet(*message1_on_arena);
+  TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(MovableMessageTest, MoveToArena) {
+  Arena arena;
+
+  protobuf_unittest::TestAllTypes message1;
+  TestUtil::SetAllFields(&message1);
+  const auto* nested = &message1.optional_nested_message();
+
+  auto* message2_on_arena =
+      Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+
+  // Moving to a message on the arena should lead to a copy.
+  *message2_on_arena = std::move(message1);
+  EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
+  TestUtil::ExpectAllFieldsSet(message1);
+  TestUtil::ExpectAllFieldsSet(*message2_on_arena);
+}
+
+TEST(MovableMessageTest, Noexcept) {
+  EXPECT_TRUE(
+      std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>());
+  EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>());
+}
+
+#endif  // LANG_CXX11
+
+}  // namespace cpp_unittest
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/names.h b/src/google/protobuf/compiler/cpp/names.h
new file mode 100644
index 0000000..7404ac5
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/names.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_CPP_NAMES_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__
+
+#include <string>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class FieldDescriptor;
+
+namespace compiler {
+namespace cpp {
+
+// Returns the unqualified C++ name.
+//
+// For example, if you had:
+//   package foo.bar;
+//   message Baz { message Moo {} }
+// Then the non-qualified version would be:
+//   Baz_Moo
+std::string ClassName(const Descriptor* descriptor);
+std::string ClassName(const EnumDescriptor* enum_descriptor);
+
+// Returns the fully qualified C++ name.
+//
+// For example, if you had:
+//   package foo.bar;
+//   message Baz { message Moo {} }
+// Then the qualified ClassName for Moo would be:
+//   ::foo::bar::Baz_Moo
+std::string QualifiedClassName(const Descriptor* d);
+std::string QualifiedClassName(const EnumDescriptor* d);
+std::string QualifiedExtensionName(const FieldDescriptor* d);
+
+// 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().
+std::string FieldName(const FieldDescriptor* field);
+
+// Requires that this field is in a oneof. Returns the (unqualified) case
+// constant for this field.
+std::string OneofCaseConstantName(const FieldDescriptor* field);
+// Returns the quafilied case constant for this field.
+std::string QualifiedOneofCaseConstantName(const FieldDescriptor* field);
+
+// Get the (unqualified) name that should be used for this enum value in C++
+// code.
+std::string EnumValueName(const EnumValueDescriptor* enum_value);
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+PROTOC_EXPORT std::string StripProto(const std::string& filename);
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__
diff --git a/src/google/protobuf/compiler/cpp/options.h b/src/google/protobuf/compiler/cpp/options.h
new file mode 100644
index 0000000..5d935e9
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/options.h
@@ -0,0 +1,101 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: rennie@google.com (Jeffrey Rennie)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+
+#include <set>
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+class AccessInfoMap;
+
+namespace cpp {
+
+enum class EnforceOptimizeMode {
+  kNoEnforcement,  // Use the runtime specified by the file specific options.
+  kSpeed,          // Full runtime with a generated code implementation.
+  kCodeSize,       // Full runtime with a reflective implementation.
+  kLiteRuntime,
+};
+
+struct FieldListenerOptions {
+  bool inject_field_listener_events = false;
+  std::set<std::string> forbidden_field_listener_events;
+};
+
+// Generator options (see generator.cc for a description of each):
+struct Options {
+  const AccessInfoMap* access_info_map = nullptr;
+  std::string dllexport_decl;
+  std::string runtime_include_base;
+  std::string annotation_pragma_name;
+  std::string annotation_guard_name;
+  FieldListenerOptions field_listener_options;
+  EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement;
+  enum {
+    kTCTableNever,
+    kTCTableGuarded,
+    kTCTableAlways
+  } tctable_mode = kTCTableNever;
+  int num_cc_files = 0;
+  bool safe_boundary_check = false;
+  bool proto_h = false;
+  bool transitive_pb_h = true;
+  bool annotate_headers = false;
+  bool lite_implicit_weak_fields = false;
+  bool bootstrap = false;
+  bool opensource_runtime = false;
+  bool annotate_accessor = false;
+  bool unused_field_stripping = false;
+  bool unverified_lazy_message_sets = false;
+  bool unverified_lazy = false;
+  bool profile_driven_inline_string = true;
+  bool message_owned_arena_trial = false;
+  bool force_split = false;
+#ifdef PROTOBUF_STABLE_EXPERIMENTS
+  bool force_eagerly_verified_lazy = true;
+  bool force_inline_string = true;
+#else   // PROTOBUF_STABLE_EXPERIMENTS
+  bool force_eagerly_verified_lazy = false;
+  bool force_inline_string = false;
+#endif  // !PROTOBUF_STABLE_EXPERIMENTS
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/cpp/padding_optimizer.cc b/src/google/protobuf/compiler/cpp/padding_optimizer.cc
new file mode 100644
index 0000000..2091052
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/padding_optimizer.cc
@@ -0,0 +1,228 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/padding_optimizer.h>
+
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+// FieldGroup is just a helper for PaddingOptimizer below. It holds a vector of
+// fields that are grouped together because they have compatible alignment, and
+// a preferred location in the final field ordering.
+class FieldGroup {
+ public:
+  FieldGroup() : preferred_location_(0) {}
+
+  // A group with a single field.
+  FieldGroup(double preferred_location, const FieldDescriptor* field)
+      : preferred_location_(preferred_location), fields_(1, field) {}
+
+  // Append the fields in 'other' to this group.
+  void Append(const FieldGroup& other) {
+    if (other.fields_.empty()) {
+      return;
+    }
+    // Preferred location is the average among all the fields, so we weight by
+    // the number of fields on each FieldGroup object.
+    preferred_location_ = (preferred_location_ * fields_.size() +
+                           (other.preferred_location_ * other.fields_.size())) /
+                          (fields_.size() + other.fields_.size());
+    fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
+  }
+
+  void SetPreferredLocation(double location) { preferred_location_ = location; }
+  const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
+
+  // FieldGroup objects sort by their preferred location.
+  bool operator<(const FieldGroup& other) const {
+    return preferred_location_ < other.preferred_location_;
+  }
+
+ private:
+  // "preferred_location_" is an estimate of where this group should go in the
+  // final list of fields.  We compute this by taking the average index of each
+  // field in this group in the original ordering of fields.  This is very
+  // approximate, but should put this group close to where its member fields
+  // originally went.
+  double preferred_location_;
+  std::vector<const FieldDescriptor*> fields_;
+  // We rely on the default copy constructor and operator= so this type can be
+  // used in a vector.
+};
+
+}  // namespace
+
+// Reorder 'fields' so that if the fields are output into a c++ class in the new
+// order, fields of similar family (see below) are together and within each
+// family, alignment padding is minimized.
+//
+// We try to do this while keeping each field as close as possible to its field
+// number order so that we don't reduce cache locality much for function that
+// access each field in order.  Originally, OptimizePadding used declaration
+// order for its decisions, but generated code minus the serializer/parsers uses
+// the output of OptimizePadding as well (stored in
+// MessageGenerator::optimized_order_).  Since the serializers use field number
+// order, we use that as a tie-breaker.
+//
+// We classify each field into a particular "family" of fields, that we perform
+// the same operation on in our generated functions.
+//
+// REPEATED is placed first, as the C++ compiler automatically initializes
+// these fields in layout order.
+//
+// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and
+// calls ArenaStringPtr::Destroy on each.
+//
+// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset
+// non-repeated fields otherwise.
+//
+// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls
+// delete on each.  We initialize these fields with a NULL pointer (see
+// MessageFieldGenerator::GenerateConstructorCode), which allows them to be
+// memset.
+//
+// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
+//
+// OTHER these fields are initialized one-by-one.
+void PaddingOptimizer::OptimizeLayout(
+    std::vector<const FieldDescriptor*>* fields, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  // The sorted numeric order of Family determines the declaration order in the
+  // memory layout.
+  enum Family {
+    REPEATED = 0,
+    STRING = 1,
+    // Laying out LAZY_MESSAGE before MESSAGE allows a single memset to zero
+    // MESSAGE and ZERO_INITIALIZABLE fields together.
+    LAZY_MESSAGE = 2,
+    MESSAGE = 3,
+    ZERO_INITIALIZABLE = 4,
+    OTHER = 5,
+    kMaxFamily
+  };
+
+  // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
+  std::vector<FieldGroup> aligned_to_1[kMaxFamily];
+  std::vector<FieldGroup> aligned_to_4[kMaxFamily];
+  std::vector<FieldGroup> aligned_to_8[kMaxFamily];
+  for (int i = 0; i < fields->size(); ++i) {
+    const FieldDescriptor* field = (*fields)[i];
+
+    Family f = OTHER;
+    if (field->is_repeated()) {
+      f = REPEATED;
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      f = STRING;
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      f = MESSAGE;
+      if (IsLazy(field, options, scc_analyzer)) {
+        f = LAZY_MESSAGE;
+      }
+    } else if (CanInitializeByZeroing(field)) {
+      f = ZERO_INITIALIZABLE;
+    }
+
+    const int j = field->number();
+    switch (EstimateAlignmentSize(field)) {
+      case 1:
+        aligned_to_1[f].push_back(FieldGroup(j, field));
+        break;
+      case 4:
+        aligned_to_4[f].push_back(FieldGroup(j, field));
+        break;
+      case 8:
+        aligned_to_8[f].push_back(FieldGroup(j, field));
+        break;
+      default:
+        GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field)
+                   << "for a field " << field->full_name() << ".";
+    }
+  }
+
+  // For each family, group fields to optimize padding.
+  for (int f = 0; f < kMaxFamily; f++) {
+    // Now group fields aligned to 1 byte into sets of 4, and treat those like a
+    // single field aligned to 4 bytes.
+    for (int i = 0; i < aligned_to_1[f].size(); i += 4) {
+      FieldGroup field_group;
+      for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) {
+        field_group.Append(aligned_to_1[f][j]);
+      }
+      aligned_to_4[f].push_back(field_group);
+    }
+    // Sort by preferred location to keep fields as close to their field number
+    // order as possible.  Using stable_sort ensures that the output is
+    // consistent across runs.
+    std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end());
+
+    // Now group fields aligned to 4 bytes (or the 4-field groups created above)
+    // into pairs, and treat those like a single field aligned to 8 bytes.
+    for (int i = 0; i < aligned_to_4[f].size(); i += 2) {
+      FieldGroup field_group;
+      for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) {
+        field_group.Append(aligned_to_4[f][j]);
+      }
+      if (i == aligned_to_4[f].size() - 1) {
+        if (f == OTHER) {
+          // Move incomplete 4-byte block to the beginning.  This is done to
+          // pair with the (possible) leftover blocks from the
+          // ZERO_INITIALIZABLE family.
+          field_group.SetPreferredLocation(-1);
+        } else {
+          // Move incomplete 4-byte block to the end.
+          field_group.SetPreferredLocation(double{FieldDescriptor::kMaxNumber});
+        }
+      }
+      aligned_to_8[f].push_back(field_group);
+    }
+    // Sort by preferred location.
+    std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end());
+  }
+
+  // Now pull out all the FieldDescriptors in order.
+  fields->clear();
+  for (int f = 0; f < kMaxFamily; ++f) {
+    for (int i = 0; i < aligned_to_8[f].size(); ++i) {
+      fields->insert(fields->end(), aligned_to_8[f][i].fields().begin(),
+                     aligned_to_8[f][i].fields().end());
+    }
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/padding_optimizer.h b/src/google/protobuf/compiler/cpp/padding_optimizer.h
new file mode 100644
index 0000000..9c76f38
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/padding_optimizer.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.
+
+// Author: seongkim@google.com (Seong Beom Kim)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
+
+#include <google/protobuf/compiler/cpp/message_layout_helper.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Rearranges the fields of a message to minimize padding.
+// Fields are grouped by the type and the size.
+// For example, grouping four boolean fields and one int32
+// field results in zero padding overhead. See OptimizeLayout's
+// comment for details.
+class PaddingOptimizer : public MessageLayoutHelper {
+ public:
+  PaddingOptimizer() {}
+  ~PaddingOptimizer() override {}
+
+  void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
+                      const Options& options,
+                      MessageSCCAnalyzer* scc_analyzer) override;
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
new file mode 100644
index 0000000..0f1d767
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
@@ -0,0 +1,1725 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/parse_function_generator.h>
+
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+using google::protobuf::internal::WireFormat;
+using google::protobuf::internal::WireFormatLite;
+
+std::vector<const FieldDescriptor*> GetOrderedFields(
+    const Descriptor* descriptor, const Options& options) {
+  std::vector<const FieldDescriptor*> ordered_fields;
+  for (auto field : FieldRange(descriptor)) {
+    if (!IsFieldStripped(field, options)) {
+      ordered_fields.push_back(field);
+    }
+  }
+  std::sort(ordered_fields.begin(), ordered_fields.end(),
+            [](const FieldDescriptor* a, const FieldDescriptor* b) {
+              return a->number() < b->number();
+            });
+  return ordered_fields;
+}
+
+bool HasInternalAccessors(const FieldOptions::CType ctype) {
+  return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD;
+}
+
+int TagSize(uint32_t field_number) {
+  if (field_number < 16) return 1;
+  GOOGLE_CHECK_LT(field_number, (1 << 14))
+      << "coded tag for " << field_number << " too big for uint16_t";
+  return 2;
+}
+
+std::string FieldParseFunctionName(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options);
+
+bool IsFieldEligibleForFastParsing(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  const auto* field = entry.field;
+  // Map, oneof, weak, and lazy fields are not handled on the fast path.
+  if (field->is_map() || field->real_containing_oneof() ||
+      field->options().weak() ||
+      IsImplicitWeakField(field, options, scc_analyzer) ||
+      IsLazy(field, options, scc_analyzer)) {
+    return false;
+  }
+
+  // We will check for a valid auxiliary index range later. However, we might
+  // want to change the value we check for inlined string fields.
+  int aux_idx = entry.aux_idx;
+
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      // If enum values are not validated at parse time, then this field can be
+      // handled on the fast path like an int32.
+      if (HasPreservingUnknownEnumSemantics(field)) {
+        break;
+      }
+      if (field->is_repeated() && field->is_packed()) {
+        return false;
+      }
+      break;
+
+      // Some bytes fields can be handled on fast path.
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      if (field->options().ctype() != FieldOptions::STRING) {
+        return false;
+      }
+      if (IsStringInlined(field, options)) {
+        GOOGLE_CHECK(!field->is_repeated());
+        // For inlined strings, the donation state index is stored in the
+        // `aux_idx` field of the fast parsing info. We need to check the range
+        // of that value instead of the auxiliary index.
+        aux_idx = entry.inlined_string_idx;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  if (HasHasbit(field)) {
+    // The tailcall parser can only update the first 32 hasbits. Fields with
+    // has-bits beyond the first 32 are handled by mini parsing/fallback.
+    GOOGLE_CHECK_GE(entry.hasbit_idx, 0) << field->DebugString();
+    if (entry.hasbit_idx >= 32) return false;
+  }
+
+  // If the field needs auxiliary data, then the aux index is needed. This
+  // must fit in a uint8_t.
+  if (aux_idx > std::numeric_limits<uint8_t>::max()) {
+    return false;
+  }
+
+  // The largest tag that can be read by the tailcall parser is two bytes
+  // when varint-coded. This allows 14 bits for the numeric tag value:
+  //   byte 0   byte 1
+  //   1nnnnttt 0nnnnnnn
+  //    ^^^^^^^  ^^^^^^^
+  if (field->number() >= 1 << 11) return false;
+
+  return true;
+}
+
+std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize(
+    const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries,
+    int table_size_log2, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  std::vector<TailCallTableInfo::FastFieldInfo> result(1 << table_size_log2);
+  const uint32_t idx_mask = result.size() - 1;
+
+  for (const auto& entry : field_entries) {
+    if (!IsFieldEligibleForFastParsing(entry, options, scc_analyzer)) {
+      continue;
+    }
+
+    const auto* field = entry.field;
+    uint32_t tag = WireFormat::MakeTag(field);
+
+    // Construct the varint-coded tag. If it is more than 7 bits, we need to
+    // shift the high bits and add a continue bit.
+    if (uint32_t hibits = tag & 0xFFFFFF80) {
+      tag = tag + hibits + 128;  // tag = lobits + 2*hibits + 128
+    }
+
+    // The field index is determined by the low bits of the field number, where
+    // the table size determines the width of the mask. The largest table
+    // supported is 32 entries. The parse loop uses these bits directly, so that
+    // the dispatch does not require arithmetic:
+    //        byte 0   byte 1
+    //   tag: 1nnnnttt 0nnnnnnn
+    //        ^^^^^
+    //         idx (table_size_log2=5)
+    // This means that any field number that does not fit in the lower 4 bits
+    // will always have the top bit of its table index asserted.
+    const uint32_t fast_idx = (tag >> 3) & idx_mask;
+
+    TailCallTableInfo::FastFieldInfo& info = result[fast_idx];
+    if (info.field != nullptr) {
+      // This field entry is already filled.
+      continue;
+    }
+
+    // Fill in this field's entry:
+    GOOGLE_CHECK(info.func_name.empty()) << info.func_name;
+    info.func_name = FieldParseFunctionName(entry, options);
+    info.field = field;
+    info.coded_tag = tag;
+    // If this field does not have presence, then it can set an out-of-bounds
+    // bit (tailcall parsing uses a uint64_t for hasbits, but only stores 32).
+    info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63;
+    if (IsStringInlined(field, options)) {
+      GOOGLE_CHECK(!field->is_repeated());
+      info.aux_idx = static_cast<uint8_t>(entry.inlined_string_idx);
+    } else {
+      info.aux_idx = static_cast<uint8_t>(entry.aux_idx);
+    }
+  }
+  return result;
+}
+
+// Filter out fields that will be handled by mini parsing.
+std::vector<const FieldDescriptor*> FilterMiniParsedFields(
+    const std::vector<const FieldDescriptor*>& fields, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  std::vector<const FieldDescriptor*> generated_fallback_fields;
+
+  for (const auto* field : fields) {
+    bool handled = false;
+    switch (field->type()) {
+      case FieldDescriptor::TYPE_DOUBLE:
+      case FieldDescriptor::TYPE_FLOAT:
+      case FieldDescriptor::TYPE_FIXED32:
+      case FieldDescriptor::TYPE_SFIXED32:
+      case FieldDescriptor::TYPE_FIXED64:
+      case FieldDescriptor::TYPE_SFIXED64:
+      case FieldDescriptor::TYPE_BOOL:
+      case FieldDescriptor::TYPE_UINT32:
+      case FieldDescriptor::TYPE_SINT32:
+      case FieldDescriptor::TYPE_INT32:
+      case FieldDescriptor::TYPE_UINT64:
+      case FieldDescriptor::TYPE_SINT64:
+      case FieldDescriptor::TYPE_INT64:
+        // These are handled by MiniParse, so we don't need any generated
+        // fallback code.
+        handled = true;
+        break;
+
+      case FieldDescriptor::TYPE_ENUM:
+        if (field->is_repeated() && !HasPreservingUnknownEnumSemantics(field)) {
+          // TODO(b/206890171): handle packed repeated closed enums
+          // Non-packed repeated can be handled using tables, but we still
+          // need to generate fallback code for all repeated enums in order to
+          // handle packed encoding. This is because of the lite/full split
+          // when handling invalid enum values in a packed field.
+          handled = false;
+        } else {
+          handled = true;
+        }
+        break;
+
+      case FieldDescriptor::TYPE_BYTES:
+      case FieldDescriptor::TYPE_STRING:
+        if (IsStringInlined(field, options)) {
+          // TODO(b/198211897): support InilnedStringField.
+          handled = false;
+        } else {
+          handled = true;
+        }
+        break;
+
+      case FieldDescriptor::TYPE_MESSAGE:
+      case FieldDescriptor::TYPE_GROUP:
+        // TODO(b/210762816): support remaining field types.
+        if (field->is_map() || IsWeak(field, options) ||
+            IsImplicitWeakField(field, options, scc_analyzer) ||
+            IsLazy(field, options, scc_analyzer)) {
+          handled = false;
+        } else {
+          handled = true;
+        }
+        break;
+
+      default:
+        handled = false;
+        break;
+    }
+    if (!handled) generated_fallback_fields.push_back(field);
+  }
+
+  return generated_fallback_fields;
+}
+
+}  // namespace
+
+TailCallTableInfo::TailCallTableInfo(
+    const Descriptor* descriptor, const Options& options,
+    const std::vector<const FieldDescriptor*>& ordered_fields,
+    const std::vector<int>& has_bit_indices,
+    const std::vector<int>& inlined_string_indices,
+    MessageSCCAnalyzer* scc_analyzer) {
+  int oneof_count = descriptor->real_oneof_decl_count();
+  // If this message has any oneof fields, store the case offset in the first
+  // auxiliary entry.
+  if (oneof_count > 0) {
+    GOOGLE_LOG_IF(DFATAL, ordered_fields.empty())
+        << "Invalid message: " << descriptor->full_name() << " has "
+        << oneof_count << " oneof declarations, but no fields";
+    aux_entries.push_back(StrCat("_fl::Offset{offsetof(",
+                                       ClassName(descriptor),
+                                       ", _impl_._oneof_case_)}"));
+  }
+
+  // If this message has any inlined string fields, store the donation state
+  // offset in the second auxiliary entry.
+  if (!inlined_string_indices.empty()) {
+    aux_entries.resize(2);  // pad if necessary
+    aux_entries[1] =
+        StrCat("_fl::Offset{offsetof(", ClassName(descriptor),
+                     ", _impl_._inlined_string_donated_)}");
+  }
+
+  // Fill in mini table entries.
+  for (const FieldDescriptor* field : ordered_fields) {
+    field_entries.push_back(
+        {field, (HasHasbit(field) ? has_bit_indices[field->index()] : -1)});
+    auto& entry = field_entries.back();
+
+    if (field->type() == FieldDescriptor::TYPE_MESSAGE ||
+        field->type() == FieldDescriptor::TYPE_GROUP) {
+      // Message-typed fields have a FieldAux with the default instance pointer.
+      if (field->is_map()) {
+        // TODO(b/205904770): generate aux entries for maps
+      } else if (IsWeak(field, options)) {
+        // Don't generate anything for weak fields. They are handled by the
+        // generated fallback.
+      } else if (IsImplicitWeakField(field, options, scc_analyzer)) {
+        // Implicit weak fields don't need to store a default instance pointer.
+      } else if (IsLazy(field, options, scc_analyzer)) {
+        // Lazy fields are handled by the generated fallback function.
+      } else {
+        field_entries.back().aux_idx = aux_entries.size();
+        const Descriptor* field_type = field->message_type();
+        aux_entries.push_back(StrCat(
+            "reinterpret_cast<const ", QualifiedClassName(field_type, options),
+            "*>(&", QualifiedDefaultInstanceName(field_type, options), ")"));
+      }
+    } else if (field->type() == FieldDescriptor::TYPE_ENUM &&
+               !HasPreservingUnknownEnumSemantics(field)) {
+      // Enum fields which preserve unknown values (proto3 behavior) are
+      // effectively int32 fields with respect to parsing -- i.e., the value
+      // does not need to be validated at parse time.
+      //
+      // Enum fields which do not preserve unknown values (proto2 behavior) use
+      // a FieldAux to store validation information. If the enum values are
+      // sequential (and within a range we can represent), then the FieldAux
+      // entry represents the range using the minimum value (which must fit in
+      // an int16_t) and count (a uint16_t). Otherwise, the entry holds a
+      // pointer to the generated Name_IsValid function.
+
+      entry.aux_idx = aux_entries.size();
+      const EnumDescriptor* enum_type = field->enum_type();
+      GOOGLE_CHECK_GT(enum_type->value_count(), 0) << enum_type->DebugString();
+
+      // Check if the enum values are a single, contiguous range.
+      std::vector<int> enum_values;
+      for (int i = 0, N = enum_type->value_count(); i < N; ++i) {
+        enum_values.push_back(enum_type->value(i)->number());
+      }
+      auto values_begin = enum_values.begin();
+      auto values_end = enum_values.end();
+      std::sort(values_begin, values_end);
+      enum_values.erase(std::unique(values_begin, values_end), values_end);
+
+      if (enum_values.back() - enum_values[0] == enum_values.size() - 1 &&
+          enum_values[0] >= std::numeric_limits<int16_t>::min() &&
+          enum_values[0] <= std::numeric_limits<int16_t>::max() &&
+          enum_values.size() <= std::numeric_limits<uint16_t>::max()) {
+        entry.is_enum_range = true;
+        aux_entries.push_back(
+            StrCat(enum_values[0], ", ", enum_values.size()));
+      } else {
+        entry.is_enum_range = false;
+        aux_entries.push_back(
+            StrCat(QualifiedClassName(enum_type, options), "_IsValid"));
+      }
+    } else if ((field->type() == FieldDescriptor::TYPE_STRING ||
+                field->type() == FieldDescriptor::TYPE_BYTES) &&
+               IsStringInlined(field, options)) {
+      GOOGLE_CHECK(!field->is_repeated());
+      // Inlined strings have an extra marker to represent their donation state.
+      int idx = inlined_string_indices[field->index()];
+      // For mini parsing, the donation state index is stored as an `offset`
+      // auxiliary entry.
+      entry.aux_idx = aux_entries.size();
+      aux_entries.push_back(StrCat("_fl::Offset{", idx, "}"));
+      // For fast table parsing, the donation state index is stored instead of
+      // the aux_idx (this will limit the range to 8 bits).
+      entry.inlined_string_idx = idx;
+    }
+  }
+
+  // Choose the smallest fast table that covers the maximum number of fields.
+  table_size_log2 = 0;  // fallback value
+  int num_fast_fields = -1;
+  for (int try_size_log2 : {0, 1, 2, 3, 4, 5}) {
+    size_t try_size = 1 << try_size_log2;
+    auto split_fields = SplitFastFieldsForSize(field_entries, try_size_log2,
+                                               options, scc_analyzer);
+    GOOGLE_CHECK_EQ(split_fields.size(), try_size);
+    int try_num_fast_fields = 0;
+    for (const auto& info : split_fields) {
+      if (info.field != nullptr) ++try_num_fast_fields;
+    }
+    // Use this size if (and only if) it covers more fields.
+    if (try_num_fast_fields > num_fast_fields) {
+      fast_path_fields = std::move(split_fields);
+      table_size_log2 = try_size_log2;
+      num_fast_fields = try_num_fast_fields;
+    }
+    // The largest table we allow has the same number of entries as the message
+    // has fields, rounded up to the next power of 2 (e.g., a message with 5
+    // fields can have a fast table of size 8). A larger table *might* cover
+    // more fields in certain cases, but a larger table in that case would have
+    // mostly empty entries; so, we cap the size to avoid pathologically sparse
+    // tables.
+    if (try_size > ordered_fields.size()) {
+      break;
+    }
+  }
+
+  // Filter out fields that are handled by MiniParse. We don't need to generate
+  // a fallback for these, which saves code size.
+  fallback_fields = FilterMiniParsedFields(ordered_fields, options,
+                                           scc_analyzer);
+
+  // If there are no fallback fields, and at most one extension range, the
+  // parser can use a generic fallback function. Otherwise, a message-specific
+  // fallback routine is needed.
+  use_generated_fallback =
+      !fallback_fields.empty() || descriptor->extension_range_count() > 1;
+}
+
+ParseFunctionGenerator::ParseFunctionGenerator(
+    const Descriptor* descriptor, int max_has_bit_index,
+    const std::vector<int>& has_bit_indices,
+    const std::vector<int>& inlined_string_indices, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer,
+    const std::map<std::string, std::string>& vars)
+    : descriptor_(descriptor),
+      scc_analyzer_(scc_analyzer),
+      options_(options),
+      variables_(vars),
+      inlined_string_indices_(inlined_string_indices),
+      ordered_fields_(GetOrderedFields(descriptor_, options_)),
+      num_hasbits_(max_has_bit_index) {
+  if (should_generate_tctable()) {
+    tc_table_info_.reset(new TailCallTableInfo(
+        descriptor_, options_, ordered_fields_, has_bit_indices,
+        inlined_string_indices, scc_analyzer));
+  }
+  SetCommonVars(options_, &variables_);
+  SetCommonMessageDataVariables(descriptor_, &variables_);
+  SetUnknownFieldsVariable(descriptor_, options_, &variables_);
+  variables_["classname"] = ClassName(descriptor, false);
+}
+
+void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  if (should_generate_tctable()) {
+    format.Outdent();
+    if (should_generate_guarded_tctable()) {
+      format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+    }
+    format(
+        " private:\n"
+        "  static const char* Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL);\n"
+        " public:\n");
+    if (should_generate_guarded_tctable()) {
+      format("#endif\n");
+    }
+    format.Indent();
+  }
+  format(
+      "const char* _InternalParse(const char* ptr, "
+      "::$proto_ns$::internal::ParseContext* ctx) final;\n");
+}
+
+void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) {
+  Formatter format(printer, variables_);
+  bool need_parse_function = true;
+  if (descriptor_->options().message_set_wire_format()) {
+    // Special-case MessageSet.
+    need_parse_function = false;
+    format(
+        "const char* $classname$::_InternalParse(const char* ptr,\n"
+        "                  ::_pbi::ParseContext* ctx) {\n"
+        "$annotate_deserialize$");
+    if (!options_.unverified_lazy_message_sets &&
+        ShouldVerify(descriptor_, options_, scc_analyzer_)) {
+      format(
+          "  ctx->set_lazy_eager_verify_func(&$classname$::InternalVerify);\n");
+    }
+    format(
+        "  return $extensions$.ParseMessageSet(ptr, \n"
+        "      internal_default_instance(), &_internal_metadata_, ctx);\n"
+        "}\n");
+  }
+  if (!should_generate_tctable()) {
+    if (need_parse_function) {
+      GenerateLoopingParseFunction(format);
+    }
+    return;
+  }
+  if (should_generate_guarded_tctable()) {
+    format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
+  }
+  if (need_parse_function) {
+    GenerateTailcallParseFunction(format);
+  }
+  if (tc_table_info_->use_generated_fallback) {
+    GenerateTailcallFallbackFunction(format);
+  }
+  if (should_generate_guarded_tctable()) {
+    if (need_parse_function) {
+      format("\n#else  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
+      GenerateLoopingParseFunction(format);
+    }
+    format("\n#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+  }
+}
+
+bool ParseFunctionGenerator::should_generate_tctable() const {
+  if (options_.tctable_mode == Options::kTCTableNever) {
+    return false;
+  }
+  return true;
+}
+
+void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
+
+  // Generate an `_InternalParse` that starts the tail-calling loop.
+  format(
+      "const char* $classname$::_InternalParse(\n"
+      "    const char* ptr, ::_pbi::ParseContext* ctx) {\n"
+      "$annotate_deserialize$"
+      "  ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, "
+      "&_table_.header);\n");
+  format(
+      "  return ptr;\n"
+      "}\n\n");
+}
+
+void ParseFunctionGenerator::GenerateTailcallFallbackFunction(
+    Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
+  format(
+      "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n"
+      "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr\n");
+  format.Indent();
+  format("auto* typed_msg = static_cast<$classname$*>(msg);\n");
+
+  if (num_hasbits_ > 0) {
+    // Sync hasbits
+    format("typed_msg->_impl_._has_bits_[0] = hasbits;\n");
+  }
+  format("uint32_t tag = data.tag();\n");
+
+  format.Set("msg", "typed_msg->");
+  format.Set("this", "typed_msg");
+  format.Set("has_bits", "typed_msg->_impl_._has_bits_");
+  format.Set("next_tag", "goto next_tag");
+  GenerateParseIterationBody(format, descriptor_,
+                             tc_table_info_->fallback_fields);
+
+  format.Outdent();
+  format(
+      "next_tag:\n"
+      "message_done:\n"
+      "  return ptr;\n"
+      "#undef CHK_\n"
+      "}\n");
+}
+
+struct SkipEntry16 {
+  uint16_t skipmap;
+  uint16_t field_entry_offset;
+};
+struct SkipEntryBlock {
+  uint32_t first_fnum;
+  std::vector<SkipEntry16> entries;
+};
+struct NumToEntryTable {
+  uint32_t skipmap32;  // for fields #1 - #32
+  std::vector<SkipEntryBlock> blocks;
+  // Compute the number of uint16_t required to represent this table.
+  int size16() const {
+    int size = 2;  // for the termination field#
+    for (const auto& block : blocks) {
+      // 2 for the field#, 1 for a count of skip entries, 2 for each entry.
+      size += 3 + block.entries.size() * 2;
+    }
+    return size;
+  }
+};
+
+static NumToEntryTable MakeNumToEntryTable(
+    const std::vector<const FieldDescriptor*>& field_descriptors);
+
+void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) {
+  if (!should_generate_tctable()) {
+    return;
+  }
+  Formatter format(printer, variables_);
+  if (should_generate_guarded_tctable()) {
+    format.Outdent();
+    format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+    format.Indent();
+  }
+  auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_);
+  format(
+      "static const ::$proto_ns$::internal::"
+      "TcParseTable<$1$, $2$, $3$, $4$, $5$> _table_;\n",
+      tc_table_info_->table_size_log2, ordered_fields_.size(),
+      tc_table_info_->aux_entries.size(), CalculateFieldNamesSize(),
+      field_num_to_entry_table.size16());
+  if (should_generate_guarded_tctable()) {
+    format.Outdent();
+    format("#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+    format.Indent();
+  }
+}
+
+void ParseFunctionGenerator::GenerateDataDefinitions(io::Printer* printer) {
+  if (!should_generate_tctable()) {
+    return;
+  }
+  Formatter format(printer, variables_);
+  if (should_generate_guarded_tctable()) {
+    format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+  }
+  GenerateTailCallTable(format);
+  if (should_generate_guarded_tctable()) {
+    format("#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+  }
+}
+
+void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) {
+  format(
+      "const char* $classname$::_InternalParse(const char* ptr, "
+      "::_pbi::ParseContext* ctx) {\n"
+      "$annotate_deserialize$"
+      "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n");
+  format.Indent();
+  format.Set("msg", "");
+  format.Set("this", "this");
+  int hasbits_size = 0;
+  if (num_hasbits_ > 0) {
+    hasbits_size = (num_hasbits_ + 31) / 32;
+  }
+  // For now only optimize small hasbits.
+  if (hasbits_size != 1) hasbits_size = 0;
+  if (hasbits_size) {
+    format("_Internal::HasBits has_bits{};\n");
+    format.Set("has_bits", "has_bits");
+  } else {
+    format.Set("has_bits", "_impl_._has_bits_");
+  }
+  format.Set("next_tag", "continue");
+  format("while (!ctx->Done(&ptr)) {\n");
+  format.Indent();
+
+  format(
+      "uint32_t tag;\n"
+      "ptr = ::_pbi::ReadTag(ptr, &tag);\n");
+  GenerateParseIterationBody(format, descriptor_, ordered_fields_);
+
+  format.Outdent();
+  format("}  // while\n");
+
+  format.Outdent();
+  format("message_done:\n");
+  if (hasbits_size) format("  _impl_._has_bits_.Or(has_bits);\n");
+
+  format(
+      "  return ptr;\n"
+      "failure:\n"
+      "  ptr = nullptr;\n"
+      "  goto message_done;\n"
+      "#undef CHK_\n"
+      "}\n");
+}
+
+static NumToEntryTable MakeNumToEntryTable(
+    const std::vector<const FieldDescriptor*>& field_descriptors) {
+  NumToEntryTable num_to_entry_table;
+  num_to_entry_table.skipmap32 = static_cast<uint32_t>(-1);
+
+  // skip_entry_block is the current block of SkipEntries that we're
+  // appending to.  cur_block_first_fnum is the number of the first
+  // field represented by the block.
+  uint16_t field_entry_index = 0;
+  uint16_t N = field_descriptors.size();
+  // First, handle field numbers 1-32, which affect only the initial
+  // skipmap32 and don't generate additional skip-entry blocks.
+  for (; field_entry_index != N; ++field_entry_index) {
+    auto* field_descriptor = field_descriptors[field_entry_index];
+    if (field_descriptor->number() > 32) break;
+    auto skipmap32_index = field_descriptor->number() - 1;
+    num_to_entry_table.skipmap32 -= 1 << skipmap32_index;
+  }
+  // If all the field numbers were less than or equal to 32, we will have
+  // no further entries to process, and we are already done.
+  if (field_entry_index == N) return num_to_entry_table;
+
+  SkipEntryBlock* block = nullptr;
+  bool start_new_block = true;
+  // To determine sparseness, track the field number corresponding to
+  // the start of the most recent skip entry.
+  uint32_t last_skip_entry_start = 0;
+  for (; field_entry_index != N; ++field_entry_index) {
+    auto* field_descriptor = field_descriptors[field_entry_index];
+    uint32_t fnum = field_descriptor->number();
+    GOOGLE_CHECK_GT(fnum, last_skip_entry_start);
+    if (start_new_block == false) {
+      // If the next field number is within 15 of the last_skip_entry_start, we
+      // continue writing just to that entry.  If it's between 16 and 31 more,
+      // then we just extend the current block by one. If it's more than 31
+      // more, we have to add empty skip entries in order to continue using the
+      // existing block.  Obviously it's just 32 more, it doesn't make sense to
+      // start a whole new block, since new blocks mean having to write out
+      // their starting field number, which is 32 bits, as well as the size of
+      // the additional block, which is 16... while an empty SkipEntry16 only
+      // costs 32 bits.  So if it was 48 more, it's a slight space win; we save
+      // 16 bits, but probably at the cost of slower run time.  We're choosing
+      // 96 for now.
+      if (fnum - last_skip_entry_start > 96) start_new_block = true;
+    }
+    if (start_new_block) {
+      num_to_entry_table.blocks.push_back(SkipEntryBlock{fnum});
+      block = &num_to_entry_table.blocks.back();
+      start_new_block = false;
+    }
+
+    auto skip_entry_num = (fnum - block->first_fnum) / 16;
+    auto skip_entry_index = (fnum - block->first_fnum) % 16;
+    while (skip_entry_num >= block->entries.size())
+      block->entries.push_back({0xFFFF, field_entry_index});
+    block->entries[skip_entry_num].skipmap -= 1 << (skip_entry_index);
+
+    last_skip_entry_start = fnum - skip_entry_index;
+  }
+  return num_to_entry_table;
+}
+
+void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
+  // All entries without a fast-path parsing function need a fallback.
+  std::string fallback;
+  if (tc_table_info_->use_generated_fallback) {
+    fallback = ClassName(descriptor_) + "::Tct_ParseFallback";
+  } else {
+    fallback = "::_pbi::TcParser::GenericFallback";
+    if (GetOptimizeFor(descriptor_->file(), options_) ==
+        FileOptions::LITE_RUNTIME) {
+      fallback += "Lite";
+    }
+  }
+
+  // For simplicity and speed, the table is not covering all proto
+  // configurations. This model uses a fallback to cover all situations that
+  // the table can't accommodate, together with unknown fields or extensions.
+  // These are number of fields over 32, fields with 3 or more tag bytes,
+  // maps, weak fields, lazy, more than 1 extension range. In the cases
+  // the table is sufficient we can use a generic routine, that just handles
+  // unknown fields and potentially an extension range.
+  auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_);
+  format(
+      "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\n"
+      "const ::_pbi::TcParseTable<$1$, $2$, $3$, $4$, $5$> "
+      "$classname$::_table_ = "
+      "{\n",
+      tc_table_info_->table_size_log2, ordered_fields_.size(),
+      tc_table_info_->aux_entries.size(), CalculateFieldNamesSize(),
+      field_num_to_entry_table.size16());
+  {
+    auto table_scope = format.ScopedIndent();
+    format("{\n");
+    {
+      auto header_scope = format.ScopedIndent();
+      if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) {
+        format("PROTOBUF_FIELD_OFFSET($classname$, _impl_._has_bits_),\n");
+      } else {
+        format("0,  // no _has_bits_\n");
+      }
+      if (descriptor_->extension_range_count() == 1) {
+        format(
+            "PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n"
+            "$1$, $2$,  // extension_range_{low,high}\n",
+            descriptor_->extension_range(0)->start,
+            descriptor_->extension_range(0)->end);
+      } else {
+        format("0, 0, 0,  // no _extensions_\n");
+      }
+      format("$1$, $2$,  // max_field_number, fast_idx_mask\n",
+             (ordered_fields_.empty() ? 0 : ordered_fields_.back()->number()),
+             (((1 << tc_table_info_->table_size_log2) - 1) << 3));
+      format(
+          "offsetof(decltype(_table_), field_lookup_table),\n"
+          "$1$,  // skipmap\n",
+          field_num_to_entry_table.skipmap32);
+      if (ordered_fields_.empty()) {
+        format(
+            "offsetof(decltype(_table_), field_names),  // no field_entries\n");
+      } else {
+        format("offsetof(decltype(_table_), field_entries),\n");
+      }
+
+      format(
+          "$1$,  // num_field_entries\n"
+          "$2$,  // num_aux_entries\n",
+          ordered_fields_.size(), tc_table_info_->aux_entries.size());
+      if (tc_table_info_->aux_entries.empty()) {
+        format(
+            "offsetof(decltype(_table_), field_names),  // no aux_entries\n");
+      } else {
+        format("offsetof(decltype(_table_), aux_entries),\n");
+      }
+      format(
+          "&$1$._instance,\n"
+          "$2$,  // fallback\n"
+          "",
+          DefaultInstanceName(descriptor_, options_), fallback);
+    }
+    format("}, {{\n");
+    {
+      // fast_entries[]
+      auto fast_scope = format.ScopedIndent();
+      GenerateFastFieldEntries(format);
+    }
+    format("}}, {{\n");
+    {
+      // field_lookup_table[]
+      auto field_lookup_scope = format.ScopedIndent();
+      int line_entries = 0;
+      for (int i = 0, N = field_num_to_entry_table.blocks.size(); i < N; ++i) {
+        SkipEntryBlock& entry_block = field_num_to_entry_table.blocks[i];
+        format("$1$, $2$, $3$,\n", entry_block.first_fnum & 65535,
+               entry_block.first_fnum / 65536, entry_block.entries.size());
+        for (auto se16 : entry_block.entries) {
+          if (line_entries == 0) {
+            format("$1$, $2$,", se16.skipmap, se16.field_entry_offset);
+            ++line_entries;
+          } else if (line_entries < 5) {
+            format(" $1$, $2$,", se16.skipmap, se16.field_entry_offset);
+            ++line_entries;
+          } else {
+            format(" $1$, $2$,\n", se16.skipmap, se16.field_entry_offset);
+            line_entries = 0;
+          }
+        }
+      }
+      if (line_entries) format("\n");
+      format("65535, 65535\n");
+    }
+    if (ordered_fields_.empty()) {
+      GOOGLE_LOG_IF(DFATAL, !tc_table_info_->aux_entries.empty())
+          << "Invalid message: " << descriptor_->full_name() << " has "
+          << tc_table_info_->aux_entries.size()
+          << " auxiliary field entries, but no fields";
+      format(
+          "}},\n"
+          "// no field_entries, or aux_entries\n"
+          "{{\n");
+    } else {
+      format("}}, {{\n");
+      {
+        // field_entries[]
+        auto field_scope = format.ScopedIndent();
+        GenerateFieldEntries(format);
+      }
+      if (tc_table_info_->aux_entries.empty()) {
+        format(
+            "}},\n"
+            "// no aux_entries\n"
+            "{{\n");
+      } else {
+        format("}}, {{\n");
+        {
+          // aux_entries[]
+          auto aux_scope = format.ScopedIndent();
+          for (const std::string& aux_entry : tc_table_info_->aux_entries) {
+            format("{$1$},\n", aux_entry);
+          }
+        }
+        format("}}, {{\n");
+      }
+    }  // ordered_fields_.empty()
+    {
+      // field_names[]
+      auto field_name_scope = format.ScopedIndent();
+      GenerateFieldNames(format);
+    }
+    format("}},\n");
+  }
+  format("};\n\n");  // _table_
+}
+
+void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) {
+  for (const auto& info : tc_table_info_->fast_path_fields) {
+    if (info.field != nullptr) {
+      PrintFieldComment(format, info.field);
+    }
+    if (info.func_name.empty()) {
+      format("{::_pbi::TcParser::MiniParse, {}},\n");
+    } else {
+      bool cold = ShouldSplit(info.field, options_);
+      format(
+          "{$1$,\n"
+          " {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$$5$, $6$)}},\n",
+          info.func_name, info.coded_tag, info.hasbit_idx, info.aux_idx,
+          cold ? "::Impl_::Split" : "",
+          cold ? FieldName(info.field) + "_"
+               : FieldMemberName(info.field, /*cold=*/false));
+    }
+  }
+}
+
+static void FormatFieldKind(Formatter& format,
+                            const TailCallTableInfo::FieldEntryInfo& entry,
+                            const Options& options,
+                            MessageSCCAnalyzer* scc_analyzer) {
+  const FieldDescriptor* field = entry.field;
+  // Spell the field kind in proto language declaration order, starting with
+  // cardinality:
+  format("(::_fl::kFc");
+  if (HasHasbit(field)) {
+    format("Optional");
+  } else if (field->is_repeated()) {
+    format("Repeated");
+  } else if (field->real_containing_oneof()) {
+    format("Oneof");
+  } else {
+    format("Singular");
+  }
+
+  // The rest of the type uses convenience aliases:
+  format(" | ::_fl::k");
+  if (field->is_repeated() && field->is_packed()) {
+    format("Packed");
+  }
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+      format("Double");
+      break;
+    case FieldDescriptor::TYPE_FLOAT:
+      format("Float");
+      break;
+    case FieldDescriptor::TYPE_FIXED32:
+      format("Fixed32");
+      break;
+    case FieldDescriptor::TYPE_SFIXED32:
+      format("SFixed32");
+      break;
+    case FieldDescriptor::TYPE_FIXED64:
+      format("Fixed64");
+      break;
+    case FieldDescriptor::TYPE_SFIXED64:
+      format("SFixed64");
+      break;
+    case FieldDescriptor::TYPE_BOOL:
+      format("Bool");
+      break;
+    case FieldDescriptor::TYPE_ENUM:
+      if (HasPreservingUnknownEnumSemantics(field)) {
+        // No validation is required.
+        format("OpenEnum");
+      } else if (entry.is_enum_range) {
+        // Validation is done by range check (start/length in FieldAux).
+        format("EnumRange");
+      } else {
+        // Validation uses the generated _IsValid function.
+        format("Enum");
+      }
+      break;
+    case FieldDescriptor::TYPE_UINT32:
+      format("UInt32");
+      break;
+    case FieldDescriptor::TYPE_SINT32:
+      format("SInt32");
+      break;
+    case FieldDescriptor::TYPE_INT32:
+      format("Int32");
+      break;
+    case FieldDescriptor::TYPE_UINT64:
+      format("UInt64");
+      break;
+    case FieldDescriptor::TYPE_SINT64:
+      format("SInt64");
+      break;
+    case FieldDescriptor::TYPE_INT64:
+      format("Int64");
+      break;
+
+    case FieldDescriptor::TYPE_BYTES:
+      format("Bytes");
+      break;
+    case FieldDescriptor::TYPE_STRING: {
+      auto mode = GetUtf8CheckMode(field, options);
+      switch (mode) {
+        case Utf8CheckMode::kStrict:
+          format("Utf8String");
+          break;
+        case Utf8CheckMode::kVerify:
+          format("RawString");
+          break;
+        case Utf8CheckMode::kNone:
+          // Treat LITE_RUNTIME strings as bytes.
+          format("Bytes");
+          break;
+        default:
+          GOOGLE_LOG(FATAL) << "Invalid Utf8CheckMode (" << static_cast<int>(mode)
+                     << ") for " << field->DebugString();
+      }
+      break;
+    }
+
+    case FieldDescriptor::TYPE_GROUP:
+      format("Message | ::_fl::kRepGroup");
+      break;
+    case FieldDescriptor::TYPE_MESSAGE:
+      if (field->is_map()) {
+        format("Map");
+      } else {
+        format("Message");
+        if (IsLazy(field, options, scc_analyzer)) {
+          format(" | ::_fl::kRepLazy");
+        } else if (IsImplicitWeakField(field, options, scc_analyzer)) {
+          format(" | ::_fl::kRepIWeak");
+        }
+      }
+      break;
+  }
+
+  // Fill in extra information about string and bytes field representations.
+  if (field->type() == FieldDescriptor::TYPE_BYTES ||
+      field->type() == FieldDescriptor::TYPE_STRING) {
+    if (field->is_repeated()) {
+      format(" | ::_fl::kRepSString");
+    } else {
+      format(" | ::_fl::kRepAString");
+    }
+  }
+
+  format(")");
+}
+
+void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) {
+  for (const auto& entry : tc_table_info_->field_entries) {
+    const FieldDescriptor* field = entry.field;
+    PrintFieldComment(format, field);
+    format("{");
+    if (IsWeak(field, options_)) {
+      // Weak fields are handled by the generated fallback function.
+      // (These are handled by legacy Google-internal logic.)
+      format("/* weak */ 0, 0, 0, 0");
+    } else {
+      const OneofDescriptor* oneof = field->real_containing_oneof();
+      bool cold = ShouldSplit(field, options_);
+      format("PROTOBUF_FIELD_OFFSET($classname$$1$, $2$), $3$, $4$,\n ",
+             cold ? "::Impl_::Split" : "",
+             cold ? FieldName(field) + "_"
+                  : FieldMemberName(field, /*cold=*/false),
+             (oneof ? oneof->index() : entry.hasbit_idx), entry.aux_idx);
+      FormatFieldKind(format, entry, options_, scc_analyzer_);
+    }
+    format("},\n");
+  }
+}
+
+static constexpr int kMaxNameLength = 255;
+
+int ParseFunctionGenerator::CalculateFieldNamesSize() const {
+  // The full name of the message appears first.
+  int size = std::min(static_cast<int>(descriptor_->full_name().size()),
+                      kMaxNameLength);
+  int lengths_size = 1;
+  for (const auto& entry : tc_table_info_->field_entries) {
+    const FieldDescriptor* field = entry.field;
+    GOOGLE_CHECK_LE(field->name().size(), kMaxNameLength);
+    size += field->name().size();
+    lengths_size += 1;
+  }
+  // align to an 8-byte boundary
+  lengths_size = (lengths_size + 7) & -8;
+  return size + lengths_size + 1;
+}
+
+static void FormatOctal(Formatter& format, int size) {
+  int octal_size = ((size >> 6) & 3) * 100 +  //
+                   ((size >> 3) & 7) * 10 +   //
+                   ((size >> 0) & 7);
+  format("\\$1$", octal_size);
+}
+
+void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) {
+  // First, we output the size of each string, as an unsigned byte. The first
+  // string is the message name.
+  int count = 1;
+  format("\"");
+  FormatOctal(format,
+              std::min(static_cast<int>(descriptor_->full_name().size()), 255));
+  for (const auto& entry : tc_table_info_->field_entries) {
+    FormatOctal(format, entry.field->name().size());
+    ++count;
+  }
+  while (count & 7) {  // align to an 8-byte boundary
+    format("\\0");
+    ++count;
+  }
+  format("\"\n");
+  // The message name is stored at the beginning of the string
+  std::string message_name = descriptor_->full_name();
+  if (message_name.size() > kMaxNameLength) {
+    static constexpr int kNameHalfLength = (kMaxNameLength - 3) / 2;
+    message_name = StrCat(
+        message_name.substr(0, kNameHalfLength), "...",
+        message_name.substr(message_name.size() - kNameHalfLength));
+  }
+  format("\"$1$\"\n", message_name);
+  // Then we output the actual field names
+  for (const auto& entry : tc_table_info_->field_entries) {
+    const FieldDescriptor* field = entry.field;
+    format("\"$1$\"\n", field->name());
+  }
+}
+
+void ParseFunctionGenerator::GenerateArenaString(Formatter& format,
+                                                 const FieldDescriptor* field) {
+  if (HasHasbit(field)) {
+    format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field));
+  }
+  format(
+      "if (arena != nullptr) {\n"
+      "  ptr = ctx->ReadArenaString(ptr, &$msg$$field$, arena");
+  if (IsStringInlined(field, options_)) {
+    GOOGLE_DCHECK(!inlined_string_indices_.empty());
+    int inlined_string_index = inlined_string_indices_[field->index()];
+    GOOGLE_DCHECK_GT(inlined_string_index, 0);
+    format(", &$msg$$inlined_string_donated_array$[0], $1$, $this$",
+           inlined_string_index);
+  } else {
+    GOOGLE_DCHECK(field->default_value_string().empty());
+  }
+  format(
+      ");\n"
+      "} else {\n"
+      "  ptr = ::_pbi::InlineGreedyStringParser("
+      "$msg$$field$.MutableNoCopy(nullptr), ptr, ctx);\n"
+      "}\n"
+      "const std::string* str = &$msg$$field$.Get(); (void)str;\n");
+}
+
+void ParseFunctionGenerator::GenerateStrings(Formatter& format,
+                                             const FieldDescriptor* field,
+                                             bool check_utf8) {
+  FieldOptions::CType ctype = FieldOptions::STRING;
+  if (!options_.opensource_runtime) {
+    // Open source doesn't support other ctypes;
+    ctype = field->options().ctype();
+  }
+  if (!field->is_repeated() && !options_.opensource_runtime &&
+      GetOptimizeFor(field->file(), options_) != FileOptions::LITE_RUNTIME &&
+      // For now only use arena string for strings with empty defaults.
+      field->default_value_string().empty() &&
+      !field->real_containing_oneof() && ctype == FieldOptions::STRING) {
+    GenerateArenaString(format, field);
+  } else {
+    std::string parser_name;
+    switch (ctype) {
+      case FieldOptions::STRING:
+        parser_name = "GreedyStringParser";
+        break;
+      case FieldOptions::CORD:
+        parser_name = "CordParser";
+        break;
+      case FieldOptions::STRING_PIECE:
+        parser_name = "StringPieceParser";
+        break;
+    }
+    format(
+        "auto str = $msg$$1$$2$_$name$();\n"
+        "ptr = ::_pbi::Inline$3$(str, ptr, ctx);\n",
+        HasInternalAccessors(ctype) ? "_internal_" : "",
+        field->is_repeated() && !field->is_packable() ? "add" : "mutable",
+        parser_name);
+  }
+  // It is intentionally placed before VerifyUTF8 because it doesn't make sense
+  // to verify UTF8 when we already know parsing failed.
+  format("CHK_(ptr);\n");
+  if (!check_utf8) return;  // return if this is a bytes field
+  auto level = GetUtf8CheckMode(field, options_);
+  switch (level) {
+    case Utf8CheckMode::kNone:
+      return;
+    case Utf8CheckMode::kVerify:
+      format("#ifndef NDEBUG\n");
+      break;
+    case Utf8CheckMode::kStrict:
+      format("CHK_(");
+      break;
+  }
+  std::string field_name;
+  field_name = "nullptr";
+  if (HasDescriptorMethods(field->file(), options_)) {
+    field_name = StrCat("\"", field->full_name(), "\"");
+  }
+  format("::_pbi::VerifyUTF8(str, $1$)", field_name);
+  switch (level) {
+    case Utf8CheckMode::kNone:
+      return;
+    case Utf8CheckMode::kVerify:
+      format(
+          ";\n"
+          "#endif  // !NDEBUG\n");
+      break;
+    case Utf8CheckMode::kStrict:
+      format(");\n");
+      break;
+  }
+}
+
+void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format,
+                                                 const FieldDescriptor* field) {
+  if (field->is_packable()) {
+    if (field->type() == FieldDescriptor::TYPE_ENUM &&
+        !HasPreservingUnknownEnumSemantics(field)) {
+      std::string enum_type = QualifiedClassName(field->enum_type(), options_);
+      format(
+          "ptr = "
+          "::$proto_ns$::internal::Packed$1$Parser<$unknown_fields_type$>("
+          "$msg$_internal_mutable_$name$(), ptr, ctx, $2$_IsValid, "
+          "&$msg$_internal_metadata_, $3$);\n",
+          DeclaredTypeMethodName(field->type()), enum_type, field->number());
+    } else {
+      format(
+          "ptr = ::$proto_ns$::internal::Packed$1$Parser("
+          "$msg$_internal_mutable_$name$(), ptr, ctx);\n",
+          DeclaredTypeMethodName(field->type()));
+    }
+    format("CHK_(ptr);\n");
+  } else {
+    auto field_type = field->type();
+    switch (field_type) {
+      case FieldDescriptor::TYPE_STRING:
+        GenerateStrings(format, field, true /* utf8 */);
+        break;
+      case FieldDescriptor::TYPE_BYTES:
+        GenerateStrings(format, field, false /* utf8 */);
+        break;
+      case FieldDescriptor::TYPE_MESSAGE: {
+        if (field->is_map()) {
+          const FieldDescriptor* val = field->message_type()->map_value();
+          GOOGLE_CHECK(val);
+          if (val->type() == FieldDescriptor::TYPE_ENUM &&
+              !HasPreservingUnknownEnumSemantics(field)) {
+            format(
+                "auto object = "
+                "::$proto_ns$::internal::InitEnumParseWrapper<"
+                "$unknown_fields_type$>(&$msg$$field$, $1$_IsValid, "
+                "$2$, &$msg$_internal_metadata_);\n"
+                "ptr = ctx->ParseMessage(&object, ptr);\n",
+                QualifiedClassName(val->enum_type(), options_),
+                field->number());
+          } else {
+            format("ptr = ctx->ParseMessage(&$msg$$field$, ptr);\n");
+          }
+        } else if (IsLazy(field, options_, scc_analyzer_)) {
+          bool eager_verify =
+              IsEagerlyVerifiedLazy(field, options_, scc_analyzer_);
+          if (ShouldVerify(descriptor_, options_, scc_analyzer_)) {
+            format(
+                "ctx->set_lazy_eager_verify_func($1$);\n",
+                eager_verify
+                    ? StrCat("&", ClassName(field->message_type(), true),
+                                   "::InternalVerify")
+                    : "nullptr");
+          }
+          if (field->real_containing_oneof()) {
+            format(
+                "if (!$msg$_internal_has_$name$()) {\n"
+                "  $msg$clear_$1$();\n"
+                "  $msg$$field$ = ::$proto_ns$::Arena::CreateMessage<\n"
+                "      ::$proto_ns$::internal::LazyField>("
+                "$msg$GetArenaForAllocation());\n"
+                "  $msg$set_has_$name$();\n"
+                "}\n"
+                "auto* lazy_field = $msg$$field$;\n",
+                field->containing_oneof()->name());
+          } else if (HasHasbit(field)) {
+            format(
+                "_Internal::set_has_$name$(&$has_bits$);\n"
+                "auto* lazy_field = &$msg$$field$;\n");
+          } else {
+            format("auto* lazy_field = &$msg$$field$;\n");
+          }
+          format(
+              "::$proto_ns$::internal::LazyFieldParseHelper<\n"
+              "  ::$proto_ns$::internal::LazyField> parse_helper(\n"
+              "    $1$::default_instance(),\n"
+              "    $msg$GetArenaForAllocation(),\n"
+              "    ::google::protobuf::internal::LazyVerifyOption::$2$,\n"
+              "    lazy_field);\n"
+              "ptr = ctx->ParseMessage(&parse_helper, ptr);\n",
+              FieldMessageTypeName(field, options_),
+              eager_verify ? "kEager" : "kLazy");
+          if (ShouldVerify(descriptor_, options_, scc_analyzer_) &&
+              eager_verify) {
+            format("ctx->set_lazy_eager_verify_func(nullptr);\n");
+          }
+        } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
+          if (!field->is_repeated()) {
+            format(
+                "ptr = ctx->ParseMessage(_Internal::mutable_$name$($this$), "
+                "ptr);\n");
+          } else {
+            format(
+                "ptr = ctx->ParseMessage($msg$$field$.AddWeak("
+                "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)"
+                "), ptr);\n",
+                QualifiedDefaultInstanceName(field->message_type(), options_));
+          }
+        } else if (IsWeak(field, options_)) {
+          format(
+              "{\n"
+              "  auto* default_ = &reinterpret_cast<const Message&>($1$);\n"
+              "  ptr = ctx->ParseMessage($msg$$weak_field_map$.MutableMessage("
+              "$2$, default_), ptr);\n"
+              "}\n",
+              QualifiedDefaultInstanceName(field->message_type(), options_),
+              field->number());
+        } else {
+          format(
+              "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), "
+              "ptr);\n");
+        }
+        format("CHK_(ptr);\n");
+        break;
+      }
+      default:
+        GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype "
+                   << " filed type is " << field->type();
+    }
+  }
+}
+
+static bool ShouldRepeat(const FieldDescriptor* descriptor,
+                         WireFormatLite::WireType wiretype) {
+  constexpr int kMaxTwoByteFieldNumber = 16 * 128;
+  return descriptor->number() < kMaxTwoByteFieldNumber &&
+         descriptor->is_repeated() &&
+         (!descriptor->is_packable() ||
+          wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+}
+
+void ParseFunctionGenerator::GenerateFieldBody(
+    Formatter& format, WireFormatLite::WireType wiretype,
+    const FieldDescriptor* field) {
+  Formatter::SaveState formatter_state(&format);
+  format.AddMap(
+      {{"name", FieldName(field)},
+       {"primitive_type", PrimitiveTypeName(options_, field->cpp_type())}});
+  if (field->is_repeated()) {
+    format.AddMap({{"put_field", StrCat("add_", FieldName(field))},
+                   {"mutable_field", StrCat("add_", FieldName(field))}});
+  } else {
+    format.AddMap(
+        {{"put_field", StrCat("set_", FieldName(field))},
+         {"mutable_field", StrCat("mutable_", FieldName(field))}});
+  }
+  uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype);
+  switch (wiretype) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      std::string type = PrimitiveTypeName(options_, field->cpp_type());
+      if (field->type() == FieldDescriptor::TYPE_ENUM) {
+        format.Set("enum_type",
+                   QualifiedClassName(field->enum_type(), options_));
+        format(
+            "$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n"
+            "CHK_(ptr);\n");
+        if (!HasPreservingUnknownEnumSemantics(field)) {
+          format("if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n");
+          format.Indent();
+        }
+        format("$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n");
+        if (!HasPreservingUnknownEnumSemantics(field)) {
+          format.Outdent();
+          format(
+              "} else {\n"
+              "  ::$proto_ns$::internal::WriteVarint("
+              "$1$, val, $msg$mutable_unknown_fields());\n"
+              "}\n",
+              field->number());
+        }
+      } else {
+        std::string size = (field->type() == FieldDescriptor::TYPE_INT32 ||
+                            field->type() == FieldDescriptor::TYPE_SINT32 ||
+                            field->type() == FieldDescriptor::TYPE_UINT32)
+                               ? "32"
+                               : "64";
+        std::string zigzag;
+        if ((field->type() == FieldDescriptor::TYPE_SINT32 ||
+             field->type() == FieldDescriptor::TYPE_SINT64)) {
+          zigzag = "ZigZag";
+        }
+        if (field->is_repeated() || field->real_containing_oneof()) {
+          format(
+              "$msg$_internal_$put_field$("
+              "::$proto_ns$::internal::ReadVarint$1$$2$(&ptr));\n"
+              "CHK_(ptr);\n",
+              zigzag, size);
+        } else {
+          if (HasHasbit(field)) {
+            format("_Internal::set_has_$name$(&$has_bits$);\n");
+          }
+          format(
+              "$msg$$field$ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n"
+              "CHK_(ptr);\n",
+              zigzag, size);
+        }
+      }
+      break;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32:
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      if (field->is_repeated() || field->real_containing_oneof()) {
+        format(
+            "$msg$_internal_$put_field$("
+            "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n"
+            "ptr += sizeof($primitive_type$);\n");
+      } else {
+        if (HasHasbit(field)) {
+          format("_Internal::set_has_$name$(&$has_bits$);\n");
+        }
+        format(
+            "$msg$$field$ = "
+            "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n"
+            "ptr += sizeof($primitive_type$);\n");
+      }
+      break;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      GenerateLengthDelim(format, field);
+      break;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      format(
+          "ptr = ctx->ParseGroup($msg$_internal_$mutable_field$(), ptr, $1$);\n"
+          "CHK_(ptr);\n",
+          tag);
+      break;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      GOOGLE_LOG(FATAL) << "Can't have end group field\n";
+      break;
+    }
+  }  // switch (wire_type)
+}
+
+// Returns the tag for this field and in case of repeated packable fields,
+// sets a fallback tag in fallback_tag_ptr.
+static uint32_t ExpectedTag(const FieldDescriptor* field,
+                            uint32_t* fallback_tag_ptr) {
+  uint32_t expected_tag;
+  if (field->is_packable()) {
+    auto expected_wiretype = WireFormat::WireTypeForFieldType(field->type());
+    expected_tag = WireFormatLite::MakeTag(field->number(), expected_wiretype);
+    GOOGLE_CHECK(expected_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+    auto fallback_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+    uint32_t fallback_tag =
+        WireFormatLite::MakeTag(field->number(), fallback_wiretype);
+
+    if (field->is_packed()) std::swap(expected_tag, fallback_tag);
+    *fallback_tag_ptr = fallback_tag;
+  } else {
+    auto expected_wiretype = WireFormat::WireTypeForField(field);
+    expected_tag = WireFormatLite::MakeTag(field->number(), expected_wiretype);
+  }
+  return expected_tag;
+}
+
+// These variables are used by the generated parse iteration, and must already
+// be defined in the generated code:
+// - `const char* ptr`: the input buffer.
+// - `ParseContext* ctx`: the associated context for `ptr`.
+// - implicit `this`: i.e., we must be in a non-static member function.
+//
+// The macro `CHK_(x)` must be defined. It should return an error condition if
+// the macro parameter is false.
+//
+// Whenever an END_GROUP tag was read, or tag 0 was read, the generated code
+// branches to the label `message_done`.
+//
+// These formatter variables are used:
+// - `next_tag`: a single statement to begin parsing the next tag.
+//
+// At the end of the generated code, the enclosing function should proceed to
+// parse the next tag in the stream.
+void ParseFunctionGenerator::GenerateParseIterationBody(
+    Formatter& format, const Descriptor* descriptor,
+    const std::vector<const FieldDescriptor*>& fields) {
+  if (!fields.empty()) {
+    GenerateFieldSwitch(format, fields);
+    // Each field `case` only considers field number. Field numbers that are
+    // not defined in the message, or tags with an incompatible wire type, are
+    // considered "unusual" cases. They will be handled by the logic below.
+    format.Outdent();
+    format("handle_unusual:\n");
+    format.Indent();
+  }
+
+  // Unusual/extension/unknown case:
+  format(
+      "if ((tag == 0) || ((tag & 7) == 4)) {\n"
+      "  CHK_(ptr);\n"
+      "  ctx->SetLastTag(tag);\n"
+      "  goto message_done;\n"
+      "}\n");
+  if (IsMapEntryMessage(descriptor)) {
+    format("$next_tag$;\n");
+  } else {
+    if (descriptor->extension_range_count() > 0) {
+      format("if (");
+      for (int i = 0; i < descriptor->extension_range_count(); i++) {
+        const Descriptor::ExtensionRange* range =
+            descriptor->extension_range(i);
+        if (i > 0) format(" ||\n    ");
+
+        uint32_t start_tag = WireFormatLite::MakeTag(
+            range->start, static_cast<WireFormatLite::WireType>(0));
+        uint32_t end_tag = WireFormatLite::MakeTag(
+            range->end, static_cast<WireFormatLite::WireType>(0));
+
+        if (range->end > FieldDescriptor::kMaxNumber) {
+          format("($1$u <= tag)", start_tag);
+        } else {
+          format("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
+        }
+      }
+      format(
+          ") {\n"
+          "  ptr = $msg$$extensions$.ParseField(tag, ptr, "
+          "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n"
+          "  CHK_(ptr != nullptr);\n"
+          "  $next_tag$;\n"
+          "}\n");
+    }
+    format(
+        "ptr = UnknownFieldParse(\n"
+        "    tag,\n"
+        "    $msg$_internal_metadata_.mutable_unknown_fields<"
+        "$unknown_fields_type$>(),\n"
+        "    ptr, ctx);\n"
+        "CHK_(ptr != nullptr);\n");
+  }
+}
+
+void ParseFunctionGenerator::GenerateFieldSwitch(
+    Formatter& format, const std::vector<const FieldDescriptor*>& fields) {
+  format("switch (tag >> 3) {\n");
+  format.Indent();
+
+  for (const auto* field : fields) {
+    bool cold = ShouldSplit(field, options_);
+    format.Set("field", FieldMemberName(field, cold));
+    PrintFieldComment(format, field);
+    format("case $1$:\n", field->number());
+    format.Indent();
+    uint32_t fallback_tag = 0;
+    uint32_t expected_tag = ExpectedTag(field, &fallback_tag);
+    format("if (PROTOBUF_PREDICT_TRUE(static_cast<$uint8$>(tag) == $1$)) {\n",
+           expected_tag & 0xFF);
+    format.Indent();
+    if (cold) {
+      format("$msg$PrepareSplitMessageForWrite();\n");
+    }
+    auto wiretype = WireFormatLite::GetTagWireType(expected_tag);
+    uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype);
+    int tag_size = io::CodedOutputStream::VarintSize32(tag);
+    bool is_repeat = ShouldRepeat(field, wiretype);
+    if (is_repeat) {
+      format(
+          "ptr -= $1$;\n"
+          "do {\n"
+          "  ptr += $1$;\n",
+          tag_size);
+      format.Indent();
+    }
+    GenerateFieldBody(format, wiretype, field);
+    if (is_repeat) {
+      format.Outdent();
+      format(
+          "  if (!ctx->DataAvailable(ptr)) break;\n"
+          "} while (::$proto_ns$::internal::ExpectTag<$1$>(ptr));\n",
+          tag);
+    }
+    format.Outdent();
+    if (fallback_tag) {
+      format("} else if (static_cast<$uint8$>(tag) == $1$) {\n",
+             fallback_tag & 0xFF);
+      format.Indent();
+      GenerateFieldBody(format, WireFormatLite::GetTagWireType(fallback_tag),
+                        field);
+      format.Outdent();
+    }
+    format(
+        "} else\n"
+        "  goto handle_unusual;\n"
+        "$next_tag$;\n");
+    format.Outdent();
+  }  // for loop over ordered fields
+
+  format(
+      "default:\n"
+      "  goto handle_unusual;\n");
+  format.Outdent();
+  format("}  // switch\n");
+}
+
+namespace {
+
+std::string FieldParseFunctionName(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options) {
+  const FieldDescriptor* field = entry.field;
+  std::string name = "::_pbi::TcParser::Fast";
+
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_FLOAT:
+      name.append("F32");
+      break;
+
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_DOUBLE:
+      name.append("F64");
+      break;
+
+    case FieldDescriptor::TYPE_BOOL:
+      name.append("V8");
+      break;
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_UINT32:
+      name.append("V32");
+      break;
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+      name.append("V64");
+      break;
+
+    case FieldDescriptor::TYPE_ENUM:
+      if (HasPreservingUnknownEnumSemantics(field)) {
+        name.append("V32");
+        break;
+      }
+      if (field->is_repeated() && field->is_packed()) {
+        GOOGLE_LOG(DFATAL) << "Enum validation not handled: " << field->DebugString();
+        return "";
+      }
+      name.append(entry.is_enum_range ? "Er" : "Ev");
+      break;
+
+    case FieldDescriptor::TYPE_SINT32:
+      name.append("Z32");
+      break;
+    case FieldDescriptor::TYPE_SINT64:
+      name.append("Z64");
+      break;
+
+    case FieldDescriptor::TYPE_BYTES:
+      name.append("B");
+      if (IsStringInlined(field, options)) {
+        name.append("i");
+      }
+      break;
+    case FieldDescriptor::TYPE_STRING:
+      switch (GetUtf8CheckMode(field, options)) {
+        case Utf8CheckMode::kNone:
+          name.append("B");
+          break;
+        case Utf8CheckMode::kVerify:
+          name.append("S");
+          break;
+        case Utf8CheckMode::kStrict:
+          name.append("U");
+          break;
+        default:
+          GOOGLE_LOG(DFATAL) << "Mode not handled: "
+                      << static_cast<int>(GetUtf8CheckMode(field, options));
+          return "";
+      }
+      if (IsStringInlined(field, options)) {
+        name.append("i");
+      }
+      break;
+
+    case FieldDescriptor::TYPE_MESSAGE:
+      name.append("M");
+      break;
+    case FieldDescriptor::TYPE_GROUP:
+      name.append("G");
+      break;
+
+    default:
+      GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString();
+      return "";
+  }
+
+  // The field implementation functions are prefixed by cardinality:
+  //   `S` for optional or implicit fields.
+  //   `R` for non-packed repeated.
+  //   `P` for packed repeated.
+  name.append(field->is_packed()               ? "P"
+              : field->is_repeated()           ? "R"
+              : field->real_containing_oneof() ? "O"
+                                               : "S");
+
+  // Append the tag length. Fast parsing only handles 1- or 2-byte tags.
+  name.append(TagSize(field->number()) == 1 ? "1" : "2");
+
+  return name;
+}
+
+}  // namespace
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.h b/src/google/protobuf/compiler/cpp/parse_function_generator.h
new file mode 100644
index 0000000..542a15a
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/parse_function_generator.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Helper class for generating tailcall parsing functions.
+struct TailCallTableInfo {
+  TailCallTableInfo(const Descriptor* descriptor, const Options& options,
+                    const std::vector<const FieldDescriptor*>& ordered_fields,
+                    const std::vector<int>& has_bit_indices,
+                    const std::vector<int>& inlined_string_indices,
+                    MessageSCCAnalyzer* scc_analyzer);
+
+  // Fields parsed by the table fast-path.
+  struct FastFieldInfo {
+    std::string func_name;
+    const FieldDescriptor* field;
+    uint16_t coded_tag;
+    uint8_t hasbit_idx;
+    uint8_t aux_idx;
+  };
+  std::vector<FastFieldInfo> fast_path_fields;
+
+  // Fields parsed by mini parsing routines.
+  struct FieldEntryInfo {
+    const FieldDescriptor* field;
+    int hasbit_idx;
+    int inlined_string_idx;
+    uint16_t aux_idx;
+    // True for enums entirely covered by the start/length fields of FieldAux:
+    bool is_enum_range;
+  };
+  std::vector<FieldEntryInfo> field_entries;
+  std::vector<std::string> aux_entries;
+
+  // Fields parsed by generated fallback function.
+  std::vector<const FieldDescriptor*> fallback_fields;
+
+  // Table size.
+  int table_size_log2;
+  // Mask for has-bits of required fields.
+  uint32_t has_hasbits_required_mask;
+  // True if a generated fallback function is required instead of generic.
+  bool use_generated_fallback;
+};
+
+// ParseFunctionGenerator generates the _InternalParse function for a message
+// (and any associated supporting members).
+class ParseFunctionGenerator {
+ public:
+  ParseFunctionGenerator(const Descriptor* descriptor, int max_has_bit_index,
+                         const std::vector<int>& has_bit_indices,
+                         const std::vector<int>& inlined_string_indices,
+                         const Options& options,
+                         MessageSCCAnalyzer* scc_analyzer,
+                         const std::map<std::string, std::string>& vars);
+
+  // Emits class-level method declarations to `printer`:
+  void GenerateMethodDecls(io::Printer* printer);
+
+  // Emits out-of-class method implementation definitions to `printer`:
+  void GenerateMethodImpls(io::Printer* printer);
+
+  // Emits class-level data member declarations to `printer`:
+  void GenerateDataDecls(io::Printer* printer);
+
+  // Emits out-of-class data member definitions to `printer`:
+  void GenerateDataDefinitions(io::Printer* printer);
+
+ private:
+  // Returns true if tailcall table code should be generated.
+  bool should_generate_tctable() const;
+
+  // Returns true if tailcall table code should be generated, but inside an
+  // #ifdef guard.
+  bool should_generate_guarded_tctable() const {
+    return should_generate_tctable() &&
+           options_.tctable_mode == Options::kTCTableGuarded;
+  }
+
+  // Generates a tail-calling `_InternalParse` function.
+  void GenerateTailcallParseFunction(Formatter& format);
+
+  // Generates a fallback function for tailcall table-based parsing.
+  void GenerateTailcallFallbackFunction(Formatter& format);
+
+  // Generates a looping `_InternalParse` function.
+  void GenerateLoopingParseFunction(Formatter& format);
+
+  // Generates the tail-call table definition.
+  void GenerateTailCallTable(Formatter& format);
+  void GenerateFastFieldEntries(Formatter& format);
+  void GenerateFieldEntries(Formatter& format);
+  int CalculateFieldNamesSize() const;
+  void GenerateFieldNames(Formatter& format);
+
+  // Generates parsing code for an `ArenaString` field.
+  void GenerateArenaString(Formatter& format, const FieldDescriptor* field);
+
+  // Generates parsing code for a string-typed field.
+  void GenerateStrings(Formatter& format, const FieldDescriptor* field,
+                       bool check_utf8);
+
+  // Generates parsing code for a length-delimited field (strings, messages,
+  // etc.).
+  void GenerateLengthDelim(Formatter& format, const FieldDescriptor* field);
+
+  // Generates the parsing code for a known field.
+  void GenerateFieldBody(Formatter& format,
+                         google::protobuf::internal::WireFormatLite::WireType wiretype,
+                         const FieldDescriptor* field);
+
+  // Generates code to parse the next field from the input stream.
+  void GenerateParseIterationBody(
+      Formatter& format, const Descriptor* descriptor,
+      const std::vector<const FieldDescriptor*>& fields);
+
+  // Generates a `switch` statement to parse each of `fields`.
+  void GenerateFieldSwitch(Formatter& format,
+                           const std::vector<const FieldDescriptor*>& fields);
+
+  const Descriptor* descriptor_;
+  MessageSCCAnalyzer* scc_analyzer_;
+  const Options& options_;
+  std::map<std::string, std::string> variables_;
+  std::unique_ptr<TailCallTableInfo> tc_table_info_;
+  std::vector<int> inlined_string_indices_;
+  const std::vector<const FieldDescriptor*> ordered_fields_;
+  int num_hasbits_;
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/cpp/plugin_unittest.cc b/src/google/protobuf/compiler/cpp/plugin_unittest.cc
new file mode 100644
index 0000000..f023dcf
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/plugin_unittest.cc
@@ -0,0 +1,235 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)
+//
+// TODO(kenton):  Share code with the versions of this test in other languages?
+//   It seemed like parameterizing it would add more complexity than it is
+//   worth.
+
+#include <memory>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/cpp/generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+namespace {
+
+class TestGenerator : public CodeGenerator {
+ public:
+  TestGenerator() {}
+  ~TestGenerator() override {}
+
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
+    TryInsert("test.pb.h", "includes", context);
+    TryInsert("test.pb.h", "namespace_scope", context);
+    TryInsert("test.pb.h", "global_scope", context);
+    TryInsert("test.pb.h", "class_scope:foo.Bar", context);
+    TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context);
+
+    TryInsert("test.pb.cc", "includes", context);
+    TryInsert("test.pb.cc", "namespace_scope", context);
+    TryInsert("test.pb.cc", "global_scope", context);
+
+    // Check field accessors for an optional int32:
+    TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
+
+    // Check field accessors for a repeated int32:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
+
+    // Check field accessors for a required string:
+    TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
+              context);
+
+    // Check field accessors for a repeated string:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
+
+    // Check field accessors for an int inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
+
+    // Check field accessors for a string inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
+
+    // Check field accessors for an optional message:
+    TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
+
+    // Check field accessors for a repeated message:
+    TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
+              context);
+
+    // Check field accessors for a message inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
+    TryInsert("test.pb.cc", "field_set_allocated:foo.Bar.oneOfMessage",
+              context);
+
+    // Check field accessors for an optional enum:
+    TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
+
+    // Check field accessors for a repeated enum:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
+
+    // Check field accessors for an enum inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
+
+    // Check field accessors for a required cord:
+    TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
+
+    // Check field accessors for a repeated cord:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
+
+    // Check field accessors for a cord inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
+
+    return true;
+  }
+
+  void TryInsert(const std::string& filename,
+                 const std::string& insertion_point,
+                 GeneratorContext* context) const {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        context->OpenForInsert(filename, insertion_point));
+    io::Printer printer(output.get(), '$');
+    printer.Print("// inserted $name$\n", "name", insertion_point);
+  }
+};
+
+// This test verifies that all the expected insertion points exist.  It does
+// not verify that they are correctly-placed; that would require actually
+// compiling the output which is a bit more than I care to do for this test.
+TEST(CppPluginTest, PluginTest) {
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
+                             "syntax = \"proto2\";\n"
+                             "package foo;\n"
+                             "\n"
+                             "enum Thud { VALUE = 0; }\n"
+                             "\n"
+                             "message Bar {\n"
+                             "  message Baz {}\n"
+                             "  optional int32 optInt = 1;\n"
+                             "  repeated int32 repeatedInt = 2;\n"
+                             "\n"
+                             "  required string requiredString = 3;\n"
+                             "  repeated string repeatedString = 4;\n"
+                             "\n"
+                             "  optional Baz optMessage = 6;\n"
+                             "  repeated Baz repeatedMessage = 7;\n"
+                             "\n"
+                             "  optional Thud optEnum = 8;\n"
+                             "  repeated Thud repeatedEnum = 9;\n"
+                             "\n"
+                             "  required string requiredCord = 10 [\n"
+                             "    ctype = CORD\n"
+                             "  ];\n"
+                             "  repeated string repeatedCord = 11 [\n"
+                             "    ctype = CORD\n"
+                             "  ];\n"
+                             "\n"
+                             "  oneof Moo {\n"
+                             "    int64 oneOfInt = 20;\n"
+                             "    string oneOfString = 21;\n"
+                             "    Baz oneOfMessage = 22;\n"
+                             "    Thud oneOfEnum = 23;"
+                             "    string oneOfCord = 24 [\n"
+                             "      ctype = CORD\n"
+                             "    ];\n"
+                             "  }\n"
+                             "}\n",
+                             true));
+
+  CommandLineInterface cli;
+  cli.SetInputsAreProtoPathRelative(true);
+
+  CppGenerator cpp_generator;
+  TestGenerator test_generator;
+  cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
+  cli.RegisterGenerator("--test_out", &test_generator, "");
+
+  std::string proto_path = "-I" + TestTempDir();
+  std::string cpp_out = "--cpp_out=" + TestTempDir();
+  std::string test_out = "--test_out=" + TestTempDir();
+
+  const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(),
+                        test_out.c_str(), "test.proto"};
+
+  EXPECT_EQ(0, cli.Run(5, argv));
+}
+
+}  // namespace
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/primitive_field.cc b/src/google/protobuf/compiler/cpp/primitive_field.cc
new file mode 100644
index 0000000..6c92ede
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/primitive_field.cc
@@ -0,0 +1,539 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/primitive_field.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+using internal::WireFormatLite;
+
+namespace {
+
+// For encodings with fixed sizes, returns that size in bytes.  Otherwise
+// returns -1.
+int FixedSize(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 WireFormatLite::kFixed32Size;
+    case FieldDescriptor::TYPE_FIXED64:
+      return WireFormatLite::kFixed64Size;
+    case FieldDescriptor::TYPE_SFIXED32:
+      return WireFormatLite::kSFixed32Size;
+    case FieldDescriptor::TYPE_SFIXED64:
+      return WireFormatLite::kSFixed64Size;
+    case FieldDescriptor::TYPE_FLOAT:
+      return WireFormatLite::kFloatSize;
+    case FieldDescriptor::TYPE_DOUBLE:
+      return WireFormatLite::kDoubleSize;
+
+    case FieldDescriptor::TYPE_BOOL:
+      return 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;
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           std::map<std::string, std::string>* variables,
+                           const Options& options) {
+  SetCommonFieldVariables(descriptor, variables, options);
+  (*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type());
+  (*variables)["default"] = DefaultValue(options, descriptor);
+  (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
+  bool cold = ShouldSplit(descriptor, options);
+  (*variables)["cached_byte_size_field"] =
+      MakeVarintCachedSizeFieldName(descriptor, cold);
+  (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor));
+  int fixed_size = FixedSize(descriptor->type());
+  if (fixed_size != -1) {
+    (*variables)["fixed_size"] = StrCat(fixed_size);
+  }
+  (*variables)["wire_format_field_type"] = FieldDescriptorProto_Type_Name(
+      static_cast<FieldDescriptorProto_Type>(descriptor->type()));
+  (*variables)["full_name"] = descriptor->full_name();
+}
+
+}  // namespace
+
+// ===================================================================
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(descriptor, options) {
+  SetPrimitiveVariables(descriptor, &variables_, options);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+void PrimitiveFieldGenerator::GeneratePrivateMembers(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$type$ $name$_;\n");
+}
+
+void PrimitiveFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
+      "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n"
+      "private:\n"
+      "$type$ ${1$_internal_$name$$}$() const;\n"
+      "void ${1$_internal_set_$name$$}$($type$ value);\n"
+      "public:\n",
+      descriptor_);
+}
+
+void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$ $classname$::_internal_$name$() const {\n"
+      "  return $field$;\n"
+      "}\n"
+      "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline void $classname$::_internal_set_$name$($type$ value) {\n"
+      "  $set_hasbit$\n"
+      "  $field$ = value;\n"
+      "}\n"
+      "inline void $classname$::set_$name$($type$ value) {\n"
+      "$maybe_prepare_split_message$"
+      "  _internal_set_$name$(value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$ = $default$;\n");
+}
+
+void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->_internal_set_$name$(from._internal_$name$());\n");
+}
+
+void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("swap($field$, other->$field$);\n");
+}
+
+void PrimitiveFieldGenerator::GenerateCopyConstructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->$field$ = from.$field$;\n");
+}
+
+void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "target = stream->EnsureSpace(target);\n"
+      "target = "
+      "::_pbi::WireFormatLite::Write$declared_type$ToArray("
+      "$number$, this->_internal_$name$(), target);\n");
+}
+
+void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  int fixed_size = FixedSize(descriptor_->type());
+  if (fixed_size == -1) {
+    if (internal::WireFormat::TagSize(descriptor_->number(),
+                                      descriptor_->type()) == 1) {
+      // Adding one is very common and it turns out it can be done for
+      // free inside of WireFormatLite, so we can save an instruction here.
+      format(
+          "total_size += ::_pbi::WireFormatLite::"
+          "$declared_type$SizePlusOne(this->_internal_$name$());\n");
+    } else {
+      format(
+          "total_size += $tag_size$ +\n"
+          "  ::_pbi::WireFormatLite::$declared_type$Size(\n"
+          "    this->_internal_$name$());\n");
+    }
+  } else {
+    format("total_size += $tag_size$ + $fixed_size$;\n");
+  }
+}
+
+void PrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("/*decltype($field$)*/$default$");
+}
+
+void PrimitiveFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    format("decltype(Impl_::Split::$name$_){$default$}");
+    return;
+  }
+  format("decltype($field$){$default$}");
+}
+
+void PrimitiveFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){}");
+}
+
+// ===================================================================
+
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : PrimitiveFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
+
+void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$ $classname$::_internal_$name$() const {\n"
+      "  if (_internal_has_$name$()) {\n"
+      "    return $field$;\n"
+      "  }\n"
+      "  return $default$;\n"
+      "}\n"
+      "inline void $classname$::_internal_set_$name$($type$ value) {\n"
+      "  if (!_internal_has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "  }\n"
+      "  $field$ = value;\n"
+      "}\n"
+      "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline void $classname$::set_$name$($type$ value) {\n"
+      "  _internal_set_$name$(value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$ = $default$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void PrimitiveOneofFieldGenerator::GenerateConstructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n");
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(descriptor, options) {
+  SetPrimitiveVariables(descriptor, &variables_, options);
+
+  if (descriptor->is_packed()) {
+    variables_["packed_reader"] = "ReadPackedPrimitive";
+    variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
+  } else {
+    variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
+    variables_["repeated_reader"] = "ReadRepeatedPrimitive";
+  }
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n");
+  if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    format("mutable std::atomic<int> $cached_byte_size_name$;\n");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "private:\n"
+      "$type$ ${1$_internal_$name$$}$(int index) const;\n"
+      "const ::$proto_ns$::RepeatedField< $type$ >&\n"
+      "    ${1$_internal_$name$$}$() const;\n"
+      "void ${1$_internal_add_$name$$}$($type$ value);\n"
+      "::$proto_ns$::RepeatedField< $type$ >*\n"
+      "    ${1$_internal_mutable_$name$$}$();\n"
+      "public:\n"
+      "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
+      "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
+      "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
+      "$deprecated_attr$const ::$proto_ns$::RepeatedField< $type$ >&\n"
+      "    ${1$$name$$}$() const;\n"
+      "$deprecated_attr$::$proto_ns$::RepeatedField< $type$ >*\n"
+      "    ${1$mutable_$name$$}$();\n",
+      descriptor_);
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline $type$ $classname$::_internal_$name$(int index) const {\n"
+      "  return $field$.Get(index);\n"
+      "}\n"
+      "inline $type$ $classname$::$name$(int index) const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$(index);\n"
+      "}\n"
+      "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+      "$annotate_set$"
+      "  $field$.Set(index, value);\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline void $classname$::_internal_add_$name$($type$ value) {\n"
+      "  $field$.Add(value);\n"
+      "}\n"
+      "inline void $classname$::add_$name$($type$ value) {\n"
+      "  _internal_add_$name$(value);\n"
+      "$annotate_add$"
+      "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "}\n"
+      "inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
+      "$classname$::_internal_$name$() const {\n"
+      "  return $field$;\n"
+      "}\n"
+      "inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
+      "$classname$::$name$() const {\n"
+      "$annotate_list$"
+      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline ::$proto_ns$::RepeatedField< $type$ >*\n"
+      "$classname$::_internal_mutable_$name$() {\n"
+      "  return &$field$;\n"
+      "}\n"
+      "inline ::$proto_ns$::RepeatedField< $type$ >*\n"
+      "$classname$::mutable_$name$() {\n"
+      "$annotate_mutable_list$"
+      "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
+      "  return _internal_mutable_$name$();\n"
+      "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.Clear();\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->$field$.MergeFrom(from.$field$);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.InternalSwap(&other->$field$);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateDestructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.~RepeatedField();\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (descriptor_->is_packed()) {
+    if (FixedSize(descriptor_->type()) == -1) {
+      format(
+          "{\n"
+          "  int byte_size = "
+          "$cached_byte_size_field$.load(std::memory_order_relaxed);\n"
+          "  if (byte_size > 0) {\n"
+          "    target = stream->Write$declared_type$Packed(\n"
+          "        $number$, _internal_$name$(), byte_size, target);\n"
+          "  }\n"
+          "}\n");
+    } else {
+      format(
+          "if (this->_internal_$name$_size() > 0) {\n"
+          "  target = stream->WriteFixedPacked($number$, _internal_$name$(), "
+          "target);\n"
+          "}\n");
+    }
+  } else {
+    format(
+        "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
+        "  target = stream->EnsureSpace(target);\n"
+        "  target = ::_pbi::WireFormatLite::"
+        "Write$declared_type$ToArray($number$, this->_internal_$name$(i), "
+        "target);\n"
+        "}\n");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateByteSize(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("{\n");
+  format.Indent();
+  int fixed_size = FixedSize(descriptor_->type());
+  if (fixed_size == -1) {
+    format(
+        "size_t data_size = ::_pbi::WireFormatLite::\n"
+        "  $declared_type$Size(this->$field$);\n");
+  } else {
+    format(
+        "unsigned int count = static_cast<unsigned "
+        "int>(this->_internal_$name$_size());\n"
+        "size_t data_size = $fixed_size$UL * count;\n");
+  }
+
+  if (descriptor_->is_packed()) {
+    format(
+        "if (data_size > 0) {\n"
+        "  total_size += $tag_size$ +\n"
+        "    "
+        "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
+        "}\n");
+    if (FixedSize(descriptor_->type()) == -1) {
+      format(
+          "int cached_size = ::_pbi::ToCachedSize(data_size);\n"
+          "$cached_byte_size_field$.store(cached_size,\n"
+          "                                std::memory_order_relaxed);\n");
+    }
+    format("total_size += data_size;\n");
+  } else {
+    format(
+        "total_size += $tag_size$ *\n"
+        "              "
+        "::_pbi::FromIntSize(this->_internal_$name$_size());\n"
+        "total_size += data_size;\n");
+  }
+  format.Outdent();
+  format("}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("/*decltype($field$)*/{}");
+  if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    format("\n, /*decltype($cached_byte_size_field$)*/{0}");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){arena}");
+  if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    // std::atomic has no move constructor, which prevents explicit aggregate
+    // initialization pre-C++17.
+    format("\n, /*decltype($cached_byte_size_field$)*/{0}");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+
+  Formatter format(printer, variables_);
+  format("decltype($field$){from.$field$}");
+  if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
+    // std::atomic has no move constructor.
+    format("\n, /*decltype($cached_byte_size_field$)*/{0}");
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/primitive_field.h b/src/google/protobuf/compiler/cpp/primitive_field.h
new file mode 100644
index 0000000..bb8a08a
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/primitive_field.h
@@ -0,0 +1,126 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_CPP_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class PrimitiveFieldGenerator : public FieldGenerator {
+ public:
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options);
+  ~PrimitiveFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override {}
+  void GenerateCopyConstructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+  PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                               const Options& options);
+  ~PrimitiveOneofFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+  RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                  const Options& options);
+  ~RepeatedPrimitiveFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override {}
+  void GenerateCopyConstructorCode(io::Printer*  /*printer*/) const override {
+    GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
+  }
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/service.cc b/src/google/protobuf/compiler/cpp/service.cc
new file mode 100644
index 0000000..7a0d480
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/service.cc
@@ -0,0 +1,328 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/cpp/service.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+void InitMethodVariables(const MethodDescriptor* method, const Options& options,
+                         Formatter* format) {
+  format->Set("name", method->name());
+  format->Set("input_type", QualifiedClassName(method->input_type(), options));
+  format->Set("output_type",
+              QualifiedClassName(method->output_type(), options));
+}
+
+}  // namespace
+
+ServiceGenerator::ServiceGenerator(
+    const ServiceDescriptor* descriptor,
+    const std::map<std::string, std::string>& vars, const Options& options)
+    : descriptor_(descriptor), vars_(vars), options_(options) {
+  vars_["classname"] = descriptor_->name();
+  vars_["full_name"] = descriptor_->full_name();
+}
+
+ServiceGenerator::~ServiceGenerator() {}
+
+void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
+  Formatter format(printer, vars_);
+  // Forward-declare the stub type.
+  format(
+      "class $classname$_Stub;\n"
+      "\n");
+
+  GenerateInterface(printer);
+  GenerateStubDefinition(printer);
+}
+
+void ServiceGenerator::GenerateInterface(io::Printer* printer) {
+  Formatter format(printer, vars_);
+  format(
+      "class $dllexport_decl $$classname$ : public ::$proto_ns$::Service {\n"
+      " protected:\n"
+      "  // This class should be treated as an abstract interface.\n"
+      "  inline $classname$() {};\n"
+      " public:\n"
+      "  virtual ~$classname$();\n");
+  printer->Indent();
+
+  format(
+      "\n"
+      "typedef $classname$_Stub Stub;\n"
+      "\n"
+      "static const ::$proto_ns$::ServiceDescriptor* descriptor();\n"
+      "\n");
+
+  GenerateMethodSignatures(VIRTUAL, printer);
+
+  format(
+      "\n"
+      "// implements Service ----------------------------------------------\n"
+      "\n"
+      "const ::$proto_ns$::ServiceDescriptor* GetDescriptor();\n"
+      "void CallMethod(const ::$proto_ns$::MethodDescriptor* method,\n"
+      "                ::$proto_ns$::RpcController* controller,\n"
+      "                const ::$proto_ns$::Message* request,\n"
+      "                ::$proto_ns$::Message* response,\n"
+      "                ::google::protobuf::Closure* done);\n"
+      "const ::$proto_ns$::Message& GetRequestPrototype(\n"
+      "  const ::$proto_ns$::MethodDescriptor* method) const;\n"
+      "const ::$proto_ns$::Message& GetResponsePrototype(\n"
+      "  const ::$proto_ns$::MethodDescriptor* method) const;\n");
+
+  printer->Outdent();
+  format(
+      "\n"
+      " private:\n"
+      "  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
+      "};\n"
+      "\n");
+}
+
+void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
+  Formatter format(printer, vars_);
+  format(
+      "class $dllexport_decl $$classname$_Stub : public $classname$ {\n"
+      " public:\n");
+
+  printer->Indent();
+
+  format(
+      "$classname$_Stub(::$proto_ns$::RpcChannel* channel);\n"
+      "$classname$_Stub(::$proto_ns$::RpcChannel* channel,\n"
+      "                 ::$proto_ns$::Service::ChannelOwnership ownership);\n"
+      "~$classname$_Stub();\n"
+      "\n"
+      "inline ::$proto_ns$::RpcChannel* channel() { return channel_; }\n"
+      "\n"
+      "// implements $classname$ ------------------------------------------\n"
+      "\n");
+
+  GenerateMethodSignatures(NON_VIRTUAL, printer);
+
+  printer->Outdent();
+  format(
+      " private:\n"
+      "  ::$proto_ns$::RpcChannel* channel_;\n"
+      "  bool owns_channel_;\n"
+      "  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n"
+      "};\n"
+      "\n");
+}
+
+void ServiceGenerator::GenerateMethodSignatures(VirtualOrNon virtual_or_non,
+                                                io::Printer* printer) {
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    Formatter format(printer, vars_);
+    InitMethodVariables(method, options_, &format);
+    format.Set("virtual", virtual_or_non == VIRTUAL ? "virtual " : "");
+    format(
+        "$virtual$void $name$(::$proto_ns$::RpcController* controller,\n"
+        "                     const $input_type$* request,\n"
+        "                     $output_type$* response,\n"
+        "                     ::google::protobuf::Closure* done);\n");
+  }
+}
+
+// ===================================================================
+
+void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
+  Formatter format(printer, vars_);
+  format(
+      "$classname$::~$classname$() {}\n"
+      "\n"
+      "const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() {\n"
+      "  "
+      "::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n"
+      "  return $file_level_service_descriptors$[$1$];\n"
+      "}\n"
+      "\n"
+      "const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() {\n"
+      "  return descriptor();\n"
+      "}\n"
+      "\n",
+      index_in_metadata_);
+
+  // Generate methods of the interface.
+  GenerateNotImplementedMethods(printer);
+  GenerateCallMethod(printer);
+  GenerateGetPrototype(REQUEST, printer);
+  GenerateGetPrototype(RESPONSE, printer);
+
+  // Generate stub implementation.
+  format(
+      "$classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel)\n"
+      "  : channel_(channel), owns_channel_(false) {}\n"
+      "$classname$_Stub::$classname$_Stub(\n"
+      "    ::$proto_ns$::RpcChannel* channel,\n"
+      "    ::$proto_ns$::Service::ChannelOwnership ownership)\n"
+      "  : channel_(channel),\n"
+      "    owns_channel_(ownership == "
+      "::$proto_ns$::Service::STUB_OWNS_CHANNEL) "
+      "{}\n"
+      "$classname$_Stub::~$classname$_Stub() {\n"
+      "  if (owns_channel_) delete channel_;\n"
+      "}\n"
+      "\n");
+
+  GenerateStubMethods(printer);
+}
+
+void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    Formatter format(printer, vars_);
+    InitMethodVariables(method, options_, &format);
+    format(
+        "void $classname$::$name$(::$proto_ns$::RpcController* controller,\n"
+        "                         const $input_type$*,\n"
+        "                         $output_type$*,\n"
+        "                         ::google::protobuf::Closure* done) {\n"
+        "  controller->SetFailed(\"Method $name$() not implemented.\");\n"
+        "  done->Run();\n"
+        "}\n"
+        "\n");
+  }
+}
+
+void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
+  Formatter format(printer, vars_);
+  format(
+      "void $classname$::CallMethod(const ::$proto_ns$::MethodDescriptor* "
+      "method,\n"
+      "                             ::$proto_ns$::RpcController* controller,\n"
+      "                             const ::$proto_ns$::Message* request,\n"
+      "                             ::$proto_ns$::Message* response,\n"
+      "                             ::google::protobuf::Closure* done) {\n"
+      "  GOOGLE_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$1$]);\n"
+      "  switch(method->index()) {\n",
+      index_in_metadata_);
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    Formatter format_method(printer, vars_);
+    InitMethodVariables(method, options_, &format_method);
+
+    // Note:  down_cast does not work here because it only works on pointers,
+    //   not references.
+    format_method(
+        "    case $1$:\n"
+        "      $name$(controller,\n"
+        "             ::$proto_ns$::internal::DownCast<const $input_type$*>(\n"
+        "                 request),\n"
+        "             ::$proto_ns$::internal::DownCast<$output_type$*>(\n"
+        "                 response),\n"
+        "             done);\n"
+        "      break;\n",
+        i);
+  }
+
+  format(
+      "    default:\n"
+      "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
+      "      break;\n"
+      "  }\n"
+      "}\n"
+      "\n");
+}
+
+void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
+                                            io::Printer* printer) {
+  Formatter format(printer, vars_);
+  if (which == REQUEST) {
+    format("const ::$proto_ns$::Message& $classname$::GetRequestPrototype(\n");
+  } else {
+    format("const ::$proto_ns$::Message& $classname$::GetResponsePrototype(\n");
+  }
+
+  format(
+      "    const ::$proto_ns$::MethodDescriptor* method) const {\n"
+      "  GOOGLE_DCHECK_EQ(method->service(), descriptor());\n"
+      "  switch(method->index()) {\n");
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    const Descriptor* type =
+        (which == REQUEST) ? method->input_type() : method->output_type();
+
+    format(
+        "    case $1$:\n"
+        "      return $2$::default_instance();\n",
+        i, QualifiedClassName(type, options_));
+  }
+
+  format(
+      "    default:\n"
+      "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
+      "      return *::$proto_ns$::MessageFactory::generated_factory()\n"
+      "          ->GetPrototype(method->$1$_type());\n"
+      "  }\n"
+      "}\n"
+      "\n",
+      which == REQUEST ? "input" : "output");
+}
+
+void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    Formatter format(printer, vars_);
+    InitMethodVariables(method, options_, &format);
+    format(
+        "void $classname$_Stub::$name$(::$proto_ns$::RpcController* "
+        "controller,\n"
+        "                              const $input_type$* request,\n"
+        "                              $output_type$* response,\n"
+        "                              ::google::protobuf::Closure* done) {\n"
+        "  channel_->CallMethod(descriptor()->method($1$),\n"
+        "                       controller, request, response, done);\n"
+        "}\n",
+        i);
+  }
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/service.h b/src/google/protobuf/compiler/cpp/service.h
new file mode 100644
index 0000000..b3bd2d7
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/service.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/options.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class ServiceGenerator {
+ public:
+  // See generator.cc for the meaning of dllexport_decl.
+  explicit ServiceGenerator(const ServiceDescriptor* descriptor,
+                            const std::map<std::string, std::string>& vars,
+                            const Options& options);
+  ~ServiceGenerator();
+
+  // Header stuff.
+
+  // Generate the class definitions for the service's interface and the
+  // stub implementation.
+  void GenerateDeclarations(io::Printer* printer);
+
+  // Source file stuff.
+
+  // Generate implementations of everything declared by
+  // GenerateDeclarations().
+  void GenerateImplementation(io::Printer* printer);
+
+ private:
+  enum RequestOrResponse { REQUEST, RESPONSE };
+  enum VirtualOrNon { VIRTUAL, NON_VIRTUAL };
+
+  // Header stuff.
+
+  // Generate the service abstract interface.
+  void GenerateInterface(io::Printer* printer);
+
+  // Generate the stub class definition.
+  void GenerateStubDefinition(io::Printer* printer);
+
+  // Prints signatures for all methods in the
+  void GenerateMethodSignatures(VirtualOrNon virtual_or_non,
+                                io::Printer* printer);
+
+  // Source file stuff.
+
+  // Generate the default implementations of the service methods, which
+  // produce a "not implemented" error.
+  void GenerateNotImplementedMethods(io::Printer* printer);
+
+  // Generate the CallMethod() method of the service.
+  void GenerateCallMethod(io::Printer* printer);
+
+  // Generate the Get{Request,Response}Prototype() methods.
+  void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
+
+  // Generate the stub's implementations of the service methods.
+  void GenerateStubMethods(io::Printer* printer);
+
+  const ServiceDescriptor* descriptor_;
+  std::map<std::string, std::string> vars_;
+  const Options& options_;
+
+  int index_in_metadata_;
+
+  friend class FileGenerator;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
diff --git a/src/google/protobuf/compiler/cpp/string_field.cc b/src/google/protobuf/compiler/cpp/string_field.cc
new file mode 100644
index 0000000..9e7c96d
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/string_field.cc
@@ -0,0 +1,957 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/cpp/string_field.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+void SetStringVariables(const FieldDescriptor* descriptor,
+                        std::map<std::string, std::string>* variables,
+                        const Options& options) {
+  SetCommonFieldVariables(descriptor, variables, options);
+
+  const std::string kNS = "::" + (*variables)["proto_ns"] + "::internal::";
+  const std::string kArenaStringPtr = kNS + "ArenaStringPtr";
+
+  (*variables)["default"] = DefaultValue(options, descriptor);
+  (*variables)["default_length"] =
+      StrCat(descriptor->default_value_string().length());
+  (*variables)["default_variable_name"] = MakeDefaultName(descriptor);
+  (*variables)["default_variable_field"] = MakeDefaultFieldName(descriptor);
+
+  if (descriptor->default_value_string().empty()) {
+    (*variables)["default_string"] = kNS + "GetEmptyStringAlreadyInited()";
+    (*variables)["default_value"] = "&" + (*variables)["default_string"];
+    (*variables)["lazy_variable_args"] = "";
+  } else {
+    (*variables)["lazy_variable"] =
+        StrCat(QualifiedClassName(descriptor->containing_type(), options),
+                     "::", MakeDefaultFieldName(descriptor));
+
+    (*variables)["default_string"] = (*variables)["lazy_variable"] + ".get()";
+    (*variables)["default_value"] = "nullptr";
+    (*variables)["lazy_variable_args"] = (*variables)["lazy_variable"] + ", ";
+  }
+
+  (*variables)["pointer_type"] =
+      descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
+  (*variables)["setter"] =
+      descriptor->type() == FieldDescriptor::TYPE_BYTES ? "SetBytes" : "Set";
+  (*variables)["null_check"] = (*variables)["DCHK"] + "(value != nullptr);\n";
+  // NOTE: Escaped here to unblock proto1->proto2 migration.
+  // TODO(liujisi): Extend this to apply for other conflicting methods.
+  (*variables)["release_name"] =
+      SafeFunctionName(descriptor->containing_type(), descriptor, "release_");
+  (*variables)["full_name"] = descriptor->full_name();
+
+  if (options.opensource_runtime) {
+    (*variables)["string_piece"] = "::std::string";
+  } else {
+    (*variables)["string_piece"] = "::StringPiece";
+  }
+}
+
+}  // namespace
+
+// ===================================================================
+
+StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
+                                           const Options& options)
+    : FieldGenerator(descriptor, options),
+      inlined_(IsStringInlined(descriptor, options)) {
+  SetStringVariables(descriptor, &variables_, options);
+}
+
+StringFieldGenerator::~StringFieldGenerator() {}
+
+void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (!inlined_) {
+    format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
+  } else {
+    // Skips the automatic destruction; rather calls it explicitly if
+    // allocating arena is null. This is required to support message-owned
+    // arena (go/path-to-arenas) where a root proto is destroyed but
+    // InlinedStringField may have arena-allocated memory.
+    format("::$proto_ns$::internal::InlinedStringField $name$_;\n");
+  }
+}
+
+void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (!descriptor_->default_value_string().empty()) {
+    format(
+        "static const ::$proto_ns$::internal::LazyString"
+        " $default_variable_name$;\n");
+  }
+  if (inlined_) {
+    // `_init_inline_xxx` is used for initializing default instances.
+    format("static std::true_type _init_inline_$name$_;\n");
+  }
+}
+
+void StringFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  // If we're using StringFieldGenerator for a field with a ctype, it's
+  // because that ctype isn't actually implemented.  In particular, this is
+  // true of ctype=CORD and ctype=STRING_PIECE in the open source release.
+  // We aren't releasing Cord because it has too many Google-specific
+  // dependencies and we aren't releasing StringPiece because it's hardly
+  // useful outside of Google and because it would get confusing to have
+  // multiple instances of the StringPiece class in different libraries (PCRE
+  // already includes it for their C++ bindings, which came from Google).
+  //
+  // In any case, we make all the accessors private while still actually
+  // using a string to represent the field internally.  This way, we can
+  // guarantee that if we do ever implement the ctype, it won't break any
+  // existing users who might be -- for whatever reason -- already using .proto
+  // files that applied the ctype.  The field can still be accessed via the
+  // reflection interface since the reflection interface is independent of
+  // the string's underlying representation.
+
+  bool unknown_ctype = descriptor_->options().ctype() !=
+                       EffectiveStringCType(descriptor_, options_);
+
+  if (unknown_ctype) {
+    format.Outdent();
+    format(
+        " private:\n"
+        "  // Hidden due to unknown ctype option.\n");
+    format.Indent();
+  }
+
+  format(
+      "$deprecated_attr$const std::string& ${1$$name$$}$() const;\n"
+      "template <typename ArgT0 = const std::string&, typename... ArgT>\n"
+      "$deprecated_attr$void ${1$set_$name$$}$(ArgT0&& arg0, ArgT... args);\n",
+      descriptor_);
+  format(
+      "$deprecated_attr$std::string* ${1$mutable_$name$$}$();\n"
+      "PROTOBUF_NODISCARD $deprecated_attr$std::string* "
+      "${1$$release_name$$}$();\n"
+      "$deprecated_attr$void ${1$set_allocated_$name$$}$(std::string* "
+      "$name$);\n",
+      descriptor_);
+  format(
+      "private:\n"
+      "const std::string& _internal_$name$() const;\n"
+      "inline PROTOBUF_ALWAYS_INLINE void "
+      "_internal_set_$name$(const std::string& value);\n"
+      "std::string* _internal_mutable_$name$();\n");
+  if (inlined_) {
+    format(
+        "inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() "
+        "const;\n");
+  }
+  format("public:\n");
+
+  if (unknown_ctype) {
+    format.Outdent();
+    format(" public:\n");
+    format.Indent();
+  }
+}
+
+void StringFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline const std::string& $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n");
+  if (!descriptor_->default_value_string().empty()) {
+    format(
+        "  if ($field$.IsDefault()) return "
+        "$default_variable_field$.get();\n");
+  }
+  format(
+      "  return _internal_$name$();\n"
+      "}\n");
+  if (!inlined_) {
+    format(
+        "template <typename ArgT0, typename... ArgT>\n"
+        "inline PROTOBUF_ALWAYS_INLINE\n"
+        "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
+        "$maybe_prepare_split_message$"
+        " $set_hasbit$\n"
+        " $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
+        " args..., GetArenaForAllocation());\n"
+        "$annotate_set$"
+        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+        "}\n");
+  } else {
+    format(
+        "template <typename ArgT0, typename... ArgT>\n"
+        "inline PROTOBUF_ALWAYS_INLINE\n"
+        "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
+        "$maybe_prepare_split_message$"
+        " $set_hasbit$\n"
+        " $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
+        " args..., GetArenaForAllocation(), _internal_$name$_donated(), "
+        "&$donating_states_word$, $mask_for_undonate$, this);\n"
+        "$annotate_set$"
+        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+        "}\n"
+        "inline bool $classname$::_internal_$name$_donated() const {\n"
+        "  bool value = $inlined_string_donated$\n"
+        "  return value;\n"
+        "}\n");
+  }
+  format(
+      "inline std::string* $classname$::mutable_$name$() {\n"
+      "$maybe_prepare_split_message$"
+      "  std::string* _s = _internal_mutable_$name$();\n"
+      "$annotate_mutable$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return _s;\n"
+      "}\n"
+      "inline const std::string& $classname$::_internal_$name$() const {\n"
+      "  return $field$.Get();\n"
+      "}\n"
+      "inline void $classname$::_internal_set_$name$(const std::string& "
+      "value) {\n"
+      "  $set_hasbit$\n");
+  if (!inlined_) {
+    format(
+        "  $field$.Set(value, GetArenaForAllocation());\n"
+        "}\n");
+  } else {
+    format(
+        "  $field$.Set(value, GetArenaForAllocation(),\n"
+        "    _internal_$name$_donated(), &$donating_states_word$, "
+        "$mask_for_undonate$, this);\n"
+        "}\n");
+  }
+  format(
+      "inline std::string* $classname$::_internal_mutable_$name$() {\n"
+      "  $set_hasbit$\n");
+  if (!inlined_) {
+    format(
+        "  return $field$.Mutable($lazy_variable_args$"
+        "GetArenaForAllocation());\n"
+        "}\n");
+  } else {
+    format(
+        "  return $field$.Mutable($lazy_variable_args$"
+        "GetArenaForAllocation(), _internal_$name$_donated(), "
+        "&$donating_states_word$, $mask_for_undonate$, this);\n"
+        "}\n");
+  }
+  format(
+      "inline std::string* $classname$::$release_name$() {\n"
+      "$annotate_release$"
+      "$maybe_prepare_split_message$"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n");
+
+  if (HasHasbit(descriptor_)) {
+    format(
+        "  if (!_internal_has_$name$()) {\n"
+        "    return nullptr;\n"
+        "  }\n"
+        "  $clear_hasbit$\n");
+    if (!inlined_) {
+      format("  auto* p = $field$.Release();\n");
+      if (descriptor_->default_value_string().empty()) {
+        format(
+            "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
+            "  if ($field$.IsDefault()) {\n"
+            "    $field$.Set(\"\", GetArenaForAllocation());\n"
+            "  }\n"
+            "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
+      }
+      format("  return p;\n");
+    } else {
+      format(
+          "  return $field$.Release(GetArenaForAllocation(), "
+          "_internal_$name$_donated());\n");
+    }
+  } else {
+    format("  return $field$.Release();\n");
+  }
+
+  format(
+      "}\n"
+      "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
+      "$maybe_prepare_split_message$"
+      "  if ($name$ != nullptr) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n");
+  if (!inlined_) {
+    format("  $field$.SetAllocated($name$, GetArenaForAllocation());\n");
+    if (descriptor_->default_value_string().empty()) {
+      format(
+          "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
+          "  if ($field$.IsDefault()) {\n"
+          "    $field$.Set(\"\", GetArenaForAllocation());\n"
+          "  }\n"
+          "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
+    }
+  } else {
+    // Currently, string fields with default value can't be inlined.
+    format(
+        "    $field$.SetAllocated(nullptr, $name$, GetArenaForAllocation(), "
+        "_internal_$name$_donated(), &$donating_states_word$, "
+        "$mask_for_undonate$, this);\n");
+  }
+  format(
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+}
+
+void StringFieldGenerator::GenerateNonInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (!descriptor_->default_value_string().empty()) {
+    format(
+        "const ::$proto_ns$::internal::LazyString "
+        "$classname$::$default_variable_field$"
+        "{{{$default$, $default_length$}}, {nullptr}};\n");
+  }
+}
+
+void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (descriptor_->default_value_string().empty()) {
+    format("$field$.ClearToEmpty();\n");
+  } else {
+    GOOGLE_DCHECK(!inlined_);
+    format(
+        "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n");
+  }
+}
+
+void StringFieldGenerator::GenerateMessageClearingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  // Two-dimension specialization here: supporting arenas, field presence, or
+  // not, and default value is the empty string or not. Complexity here ensures
+  // the minimal number of branches / amount of extraneous code at runtime
+  // (given that the below methods are inlined one-liners)!
+
+  // If we have a hasbit, then the Clear() method of the protocol buffer
+  // will have checked that this field is set.  If so, we can avoid redundant
+  // checks against the default variable.
+  const bool must_be_present = HasHasbit(descriptor_);
+
+  if (inlined_ && must_be_present) {
+    // Calling mutable_$name$() gives us a string reference and sets the has bit
+    // for $name$ (in proto2).  We may get here when the string field is inlined
+    // but the string's contents have not been changed by the user, so we cannot
+    // make an assertion about the contents of the string and could never make
+    // an assertion about the string instance.
+    //
+    // For non-inlined strings, we distinguish from non-default by comparing
+    // instances, rather than contents.
+    format("$DCHK$(!$field$.IsDefault());\n");
+  }
+
+  if (descriptor_->default_value_string().empty()) {
+    if (must_be_present) {
+      format("$field$.ClearNonDefaultToEmpty();\n");
+    } else {
+      format("$field$.ClearToEmpty();\n");
+    }
+  } else {
+    // Clear to a non-empty default is more involved, as we try to use the
+    // Arena if one is present and may need to reallocate the string.
+    format(
+        "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n ");
+  }
+}
+
+void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  // TODO(gpike): improve this
+  format("_this->_internal_set_$name$(from._internal_$name$());\n");
+}
+
+void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (!inlined_) {
+    format(
+        "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
+        "    &$field$, lhs_arena,\n"
+        "    &other->$field$, rhs_arena\n"
+        ");\n");
+  } else {
+    format(
+        "::$proto_ns$::internal::InlinedStringField::InternalSwap(\n"
+        "  &$field$, lhs_arena, "
+        "($inlined_string_donated_array$[0] & 0x1u) == 0, this,\n"
+        "  &other->$field$, rhs_arena, "
+        "(other->$inlined_string_donated_array$[0] & 0x1u) == 0, other);\n");
+  }
+}
+
+void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (inlined_ && descriptor_->default_value_string().empty()) {
+    return;
+  }
+  GOOGLE_DCHECK(!inlined_);
+  format("$field$.InitDefault();\n");
+  if (IsString(descriptor_, options_) &&
+      descriptor_->default_value_string().empty()) {
+    format(
+        "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
+        "  $field$.Set(\"\", GetArenaForAllocation());\n"
+        "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
+  }
+}
+
+void StringFieldGenerator::GenerateCreateSplitMessageCode(
+    io::Printer* printer) const {
+  GOOGLE_CHECK(ShouldSplit(descriptor_, options_));
+  GOOGLE_CHECK(!inlined_);
+  Formatter format(printer, variables_);
+  format("ptr->$name$_.InitDefault();\n");
+  if (IsString(descriptor_, options_) &&
+      descriptor_->default_value_string().empty()) {
+    format(
+        "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
+        "  ptr->$name$_.Set(\"\", GetArenaForAllocation());\n"
+        "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
+  }
+}
+
+void StringFieldGenerator::GenerateCopyConstructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  GenerateConstructorCode(printer);
+  if (inlined_) {
+    format("new (&_this->$field$) ::_pbi::InlinedStringField();\n");
+  }
+
+  if (HasHasbit(descriptor_)) {
+    format("if (from._internal_has_$name$()) {\n");
+  } else {
+    format("if (!from._internal_$name$().empty()) {\n");
+  }
+
+  format.Indent();
+
+  if (!inlined_) {
+    format(
+        "_this->$field$.Set(from._internal_$name$(), \n"
+        "  _this->GetArenaForAllocation());\n");
+  } else {
+    format(
+        "_this->$field$.Set(from._internal_$name$(),\n"
+        "  _this->GetArenaForAllocation(), _this->_internal_$name$_donated(), "
+        "&_this->$donating_states_word$, $mask_for_undonate$, _this);\n");
+  }
+
+  format.Outdent();
+  format("}\n");
+}
+
+void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (!inlined_) {
+    if (ShouldSplit(descriptor_, options_)) {
+      format("$cached_split_ptr$->$name$_.Destroy();\n");
+      return;
+    }
+    format("$field$.Destroy();\n");
+    return;
+  }
+  // Explicitly calls ~InlinedStringField as its automatic call is disabled.
+  // Destructor has been implicitly skipped as a union, and even the
+  // message-owned arena is enabled, arena could still be missing for
+  // Arena::CreateMessage(nullptr).
+  GOOGLE_DCHECK(!ShouldSplit(descriptor_, options_));
+  format("$field$.~InlinedStringField();\n");
+}
+
+ArenaDtorNeeds StringFieldGenerator::NeedsArenaDestructor() const {
+  return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone;
+}
+
+void StringFieldGenerator::GenerateArenaDestructorCode(
+    io::Printer* printer) const {
+  if (!inlined_) return;
+  Formatter format(printer, variables_);
+  // _this is the object being destructed (we are inside a static method here).
+  format(
+      "if (!_this->_internal_$name$_donated()) {\n"
+      "  _this->$field$.~InlinedStringField();\n"
+      "}\n");
+}
+
+void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, false,
+        "this->_internal_$name$().data(), "
+        "static_cast<int>(this->_internal_$name$().length()),\n",
+        format);
+  }
+  format(
+      "target = stream->Write$declared_type$MaybeAliased(\n"
+      "    $number$, this->_internal_$name$(), target);\n");
+}
+
+void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "total_size += $tag_size$ +\n"
+      "  ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+      "    this->_internal_$name$());\n");
+}
+
+void StringFieldGenerator::GenerateConstexprAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (inlined_) {
+    format("/*decltype($field$)*/{nullptr, false}");
+    return;
+  }
+  if (descriptor_->default_value_string().empty()) {
+    format(
+        "/*decltype($field$)*/{&::_pbi::fixed_address_empty_string, "
+        "::_pbi::ConstantInitialized{}}");
+  } else {
+    format("/*decltype($field$)*/{nullptr, ::_pbi::ConstantInitialized{}}");
+  }
+}
+
+void StringFieldGenerator::GenerateAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  if (ShouldSplit(descriptor_, options_)) {
+    GOOGLE_CHECK(!inlined_);
+    format("decltype(Impl_::Split::$name$_){}");
+    return;
+  }
+  if (!inlined_) {
+    format("decltype($field$){}");
+  } else {
+    format("decltype($field$)(arena)");
+  }
+}
+
+void StringFieldGenerator::GenerateCopyAggregateInitializer(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("decltype($field$){}");
+}
+
+// ===================================================================
+
+StringOneofFieldGenerator::StringOneofFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : StringFieldGenerator(descriptor, options) {
+  SetCommonOneofFieldVariables(descriptor, &variables_);
+  variables_["field_name"] = UnderscoresToCamelCase(descriptor->name(), true);
+  variables_["oneof_index"] =
+      StrCat(descriptor->containing_oneof()->index());
+}
+
+StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
+
+void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline const std::string& $classname$::$name$() const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "template <typename ArgT0, typename... ArgT>\n"
+      "inline void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
+      "  if (!_internal_has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $field$.InitDefault();\n"
+      "  }\n"
+      "  $field$.$setter$("
+      " static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline std::string* $classname$::mutable_$name$() {\n"
+      "  std::string* _s = _internal_mutable_$name$();\n"
+      "$annotate_mutable$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return _s;\n"
+      "}\n"
+      "inline const std::string& $classname$::_internal_$name$() const {\n"
+      "  if (_internal_has_$name$()) {\n"
+      "    return $field$.Get();\n"
+      "  }\n"
+      "  return $default_string$;\n"
+      "}\n"
+      "inline void $classname$::_internal_set_$name$(const std::string& "
+      "value) {\n"
+      "  if (!_internal_has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $field$.InitDefault();\n"
+      "  }\n"
+      "  $field$.Set(value, GetArenaForAllocation());\n"
+      "}\n");
+  format(
+      "inline std::string* $classname$::_internal_mutable_$name$() {\n"
+      "  if (!_internal_has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $field$.InitDefault();\n"
+      "  }\n"
+      "  return $field$.Mutable($lazy_variable_args$"
+      "      GetArenaForAllocation());\n"
+      "}\n"
+      "inline std::string* $classname$::$release_name$() {\n"
+      "$annotate_release$"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  if (_internal_has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    return $field$.Release();\n"
+      "  } else {\n"
+      "    return nullptr;\n"
+      "  }\n"
+      "}\n"
+      "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
+      "  if (has_$oneof_name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "  }\n"
+      "  if ($name$ != nullptr) {\n"
+      "    set_has_$name$();\n"
+      "    $field$.InitAllocated($name$, GetArenaForAllocation());\n"
+      "  }\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+}
+
+void StringOneofFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.Destroy();\n");
+}
+
+void StringOneofFieldGenerator::GenerateMessageClearingCode(
+    io::Printer* printer) const {
+  return GenerateClearingCode(printer);
+}
+
+void StringOneofFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void StringOneofFieldGenerator::GenerateConstructorCode(
+    io::Printer* printer) const {
+  // Nothing required here.
+}
+
+// ===================================================================
+
+RepeatedStringFieldGenerator::RepeatedStringFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(descriptor, options) {
+  SetStringVariables(descriptor, &variables_, options);
+}
+
+RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
+
+void RepeatedStringFieldGenerator::GeneratePrivateMembers(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("::$proto_ns$::RepeatedPtrField<std::string> $name$_;\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateAccessorDeclarations(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  // See comment above about unknown ctypes.
+  bool unknown_ctype = descriptor_->options().ctype() !=
+                       EffectiveStringCType(descriptor_, options_);
+
+  if (unknown_ctype) {
+    format.Outdent();
+    format(
+        " private:\n"
+        "  // Hidden due to unknown ctype option.\n");
+    format.Indent();
+  }
+
+  format(
+      "$deprecated_attr$const std::string& ${1$$name$$}$(int index) const;\n"
+      "$deprecated_attr$std::string* ${1$mutable_$name$$}$(int index);\n"
+      "$deprecated_attr$void ${1$set_$name$$}$(int index, const "
+      "std::string& value);\n"
+      "$deprecated_attr$void ${1$set_$name$$}$(int index, std::string&& "
+      "value);\n"
+      "$deprecated_attr$void ${1$set_$name$$}$(int index, const "
+      "char* value);\n",
+      descriptor_);
+  if (!options_.opensource_runtime) {
+    format(
+        "$deprecated_attr$void ${1$set_$name$$}$(int index, "
+        "StringPiece value);\n",
+        descriptor_);
+  }
+  format(
+      "$deprecated_attr$void ${1$set_$name$$}$("
+      "int index, const $pointer_type$* value, size_t size);\n"
+      "$deprecated_attr$std::string* ${1$add_$name$$}$();\n"
+      "$deprecated_attr$void ${1$add_$name$$}$(const std::string& value);\n"
+      "$deprecated_attr$void ${1$add_$name$$}$(std::string&& value);\n"
+      "$deprecated_attr$void ${1$add_$name$$}$(const char* value);\n",
+      descriptor_);
+  if (!options_.opensource_runtime) {
+    format(
+        "$deprecated_attr$void ${1$add_$name$$}$(StringPiece value);\n",
+        descriptor_);
+  }
+  format(
+      "$deprecated_attr$void ${1$add_$name$$}$(const $pointer_type$* "
+      "value, size_t size)"
+      ";\n"
+      "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField<std::string>& "
+      "${1$$name$$}$() "
+      "const;\n"
+      "$deprecated_attr$::$proto_ns$::RepeatedPtrField<std::string>* "
+      "${1$mutable_$name$$}$()"
+      ";\n"
+      "private:\n"
+      "const std::string& ${1$_internal_$name$$}$(int index) const;\n"
+      "std::string* _internal_add_$name$();\n"
+      "public:\n",
+      descriptor_);
+
+  if (unknown_ctype) {
+    format.Outdent();
+    format(" public:\n");
+    format.Indent();
+  }
+}
+
+void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "inline std::string* $classname$::add_$name$() {\n"
+      "  std::string* _s = _internal_add_$name$();\n"
+      "$annotate_add_mutable$"
+      "  // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
+      "  return _s;\n"
+      "}\n");
+  if (options_.safe_boundary_check) {
+    format(
+        "inline const std::string& $classname$::_internal_$name$(int index) "
+        "const {\n"
+        "  return $field$.InternalCheckedGet(\n"
+        "      index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n"
+        "}\n");
+  } else {
+    format(
+        "inline const std::string& $classname$::_internal_$name$(int index) "
+        "const {\n"
+        "  return $field$.Get(index);\n"
+        "}\n");
+  }
+  format(
+      "inline const std::string& $classname$::$name$(int index) const {\n"
+      "$annotate_get$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$(index);\n"
+      "}\n"
+      "inline std::string* $classname$::mutable_$name$(int index) {\n"
+      "$annotate_mutable$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $field$.Mutable(index);\n"
+      "}\n"
+      "inline void $classname$::set_$name$(int index, const std::string& "
+      "value) "
+      "{\n"
+      "  $field$.Mutable(index)->assign(value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline void $classname$::set_$name$(int index, std::string&& value) {\n"
+      "  $field$.Mutable(index)->assign(std::move(value));\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline void $classname$::set_$name$(int index, const char* value) {\n"
+      "  $null_check$"
+      "  $field$.Mutable(index)->assign(value);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+      "}\n");
+  if (!options_.opensource_runtime) {
+    format(
+        "inline void "
+        "$classname$::set_$name$(int index, StringPiece value) {\n"
+        "  $field$.Mutable(index)->assign(value.data(), value.size());\n"
+        "$annotate_set$"
+        "  // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
+        "}\n");
+  }
+  format(
+      "inline void "
+      "$classname$::set_$name$"
+      "(int index, const $pointer_type$* value, size_t size) {\n"
+      "  $field$.Mutable(index)->assign(\n"
+      "    reinterpret_cast<const char*>(value), size);\n"
+      "$annotate_set$"
+      "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+      "}\n"
+      "inline std::string* $classname$::_internal_add_$name$() {\n"
+      "  return $field$.Add();\n"
+      "}\n"
+      "inline void $classname$::add_$name$(const std::string& value) {\n"
+      "  $field$.Add()->assign(value);\n"
+      "$annotate_add$"
+      "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "}\n"
+      "inline void $classname$::add_$name$(std::string&& value) {\n"
+      "  $field$.Add(std::move(value));\n"
+      "$annotate_add$"
+      "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "}\n"
+      "inline void $classname$::add_$name$(const char* value) {\n"
+      "  $null_check$"
+      "  $field$.Add()->assign(value);\n"
+      "$annotate_add$"
+      "  // @@protoc_insertion_point(field_add_char:$full_name$)\n"
+      "}\n");
+  if (!options_.opensource_runtime) {
+    format(
+        "inline void $classname$::add_$name$(StringPiece value) {\n"
+        "  $field$.Add()->assign(value.data(), value.size());\n"
+        "$annotate_add$"
+        "  // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n"
+        "}\n");
+  }
+  format(
+      "inline void "
+      "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
+      "  $field$.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
+      "$annotate_add$"
+      "  // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
+      "}\n"
+      "inline const ::$proto_ns$::RepeatedPtrField<std::string>&\n"
+      "$classname$::$name$() const {\n"
+      "$annotate_list$"
+      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+      "  return $field$;\n"
+      "}\n"
+      "inline ::$proto_ns$::RepeatedPtrField<std::string>*\n"
+      "$classname$::mutable_$name$() {\n"
+      "$annotate_mutable_list$"
+      "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
+      "  return &$field$;\n"
+      "}\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateClearingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.Clear();\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("_this->$field$.MergeFrom(from.$field$);\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateSwappingCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.InternalSwap(&other->$field$);\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateDestructorCode(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format("$field$.~RepeatedPtrField();\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
+      "  const auto& s = this->_internal_$name$(i);\n");
+  // format("for (const std::string& s : this->$name$()) {\n");
+  format.Indent();
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(descriptor_, options_, false,
+                                   "s.data(), static_cast<int>(s.length()),\n",
+                                   format);
+  }
+  format.Outdent();
+  format(
+      "  target = stream->Write$declared_type$($number$, s, target);\n"
+      "}\n");
+}
+
+void RepeatedStringFieldGenerator::GenerateByteSize(
+    io::Printer* printer) const {
+  Formatter format(printer, variables_);
+  format(
+      "total_size += $tag_size$ *\n"
+      "    ::$proto_ns$::internal::FromIntSize($field$.size());\n"
+      "for (int i = 0, n = $field$.size(); i < n; i++) {\n"
+      "  total_size += "
+      "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+      "    $field$.Get(i));\n"
+      "}\n");
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/string_field.h b/src/google/protobuf/compiler/cpp/string_field.h
new file mode 100644
index 0000000..db5f18b
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/string_field.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class StringFieldGenerator : public FieldGenerator {
+ public:
+  StringFieldGenerator(const FieldDescriptor* descriptor,
+                       const Options& options);
+  ~StringFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateStaticMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateNonInlineAccessorDefinitions(
+      io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMessageClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+  void GenerateCreateSplitMessageCode(io::Printer* printer) const override;
+  void GenerateCopyConstructorCode(io::Printer* printer) const override;
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateArenaDestructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+  void GenerateConstexprAggregateInitializer(
+      io::Printer* printer) const override;
+  void GenerateAggregateInitializer(io::Printer* printer) const override;
+  void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
+  bool IsInlined() const override { return inlined_; }
+  ArenaDtorNeeds NeedsArenaDestructor() const override;
+
+ private:
+  bool inlined_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
+};
+
+class StringOneofFieldGenerator : public StringFieldGenerator {
+ public:
+  StringOneofFieldGenerator(const FieldDescriptor* descriptor,
+                            const Options& options);
+  ~StringOneofFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+
+  // StringFieldGenerator, from which we inherit, overrides this so we need to
+  // override it as well.
+  void GenerateMessageClearingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
+};
+
+class RepeatedStringFieldGenerator : public FieldGenerator {
+ public:
+  RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+                               const Options& options);
+  ~RepeatedStringFieldGenerator() override;
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const override;
+  void GenerateAccessorDeclarations(io::Printer* printer) const override;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+  void GenerateClearingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateSwappingCode(io::Printer* printer) const override;
+  void GenerateConstructorCode(io::Printer* printer) const override {}
+  void GenerateCopyConstructorCode(io::Printer*  /*printer*/) const override {
+    GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
+  }
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateSerializeWithCachedSizesToArray(
+      io::Printer* printer) const override;
+  void GenerateByteSize(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/test_bad_identifiers.proto
new file mode 100644
index 0000000..466a841
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/test_bad_identifiers.proto
@@ -0,0 +1,184 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file tests that various identifiers work as field and type names even
+// though the same identifiers are used internally by the C++ code generator.
+
+// LINT: LEGACY_NAMES
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;  // auto-added
+
+// 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.
+package protobuf_unittest;
+
+// Test that fields can have names like "input" and "i" which are also used
+// internally by the code generator for local variables.
+message TestConflictingSymbolNames {
+  message BuildDescriptors {}
+  message TypeTraits {}
+
+  optional int32 input = 1;
+  optional int32 output = 2;
+  optional string length = 3;
+  repeated int32 i = 4;
+  repeated string new_element = 5 [ctype = STRING_PIECE];
+  optional int32 total_size = 6;
+  optional int32 tag = 7;
+
+  enum TestEnum { FOO = 0; }
+  message Data1 {
+    repeated int32 data = 1;
+  }
+  message Data2 {
+    repeated TestEnum data = 1;
+  }
+  message Data3 {
+    repeated string data = 1;
+  }
+  message Data4 {
+    repeated Data4 data = 1;
+  }
+  message Data5 {
+    repeated string data = 1 [ctype = STRING_PIECE];
+  }
+  message Data6 {
+    repeated string data = 1 [ctype = CORD];
+  }
+
+  optional int32 source = 8;
+  optional int32 value = 9;
+  optional int32 file = 10;
+  optional int32 from = 11;
+  optional int32 handle_uninterpreted = 12;
+  repeated int32 index = 13;
+  optional int32 controller = 14;
+  optional int32 already_here = 15;
+
+  optional uint32 uint32 = 16;
+  optional uint64 uint64 = 17;
+  optional string string = 18;
+  optional int32 memset = 19;
+  optional int32 int32 = 20;
+  optional int64 int64 = 21;
+
+  optional uint32 cached_size = 22;
+  optional uint32 extensions = 23;
+  optional uint32 bit = 24;
+  optional uint32 bits = 25;
+  optional uint32 offsets = 26;
+  optional uint32 reflection = 27;
+
+  message Cord {}
+  optional string some_cord = 28 [ctype = CORD];
+
+  message StringPiece {}
+  optional string some_string_piece = 29 [ctype = STRING_PIECE];
+
+  // Some keywords.
+  optional uint32 int = 30;
+  optional uint32 friend = 31;
+  optional uint32 class = 37;
+  optional uint32 typedecl = 39;
+  optional uint32 auto = 40;
+
+  // The generator used to #define a macro called "DO" inside the .cc file.
+  message DO {}
+  optional DO do = 32;
+
+  // Some template parameter names for extensions.
+  optional int32 field_type = 33;
+  optional bool is_packed = 34;
+
+  // test conflicting release_$name$. "length" and "do" field in this message
+  // must remain string or message fields to make the test valid.
+  optional string release_length = 35;
+  // A more extreme case, the field name "do" here is a keyword, which will be
+  // escaped to "do_" already. Test there is no conflict even with escaped field
+  // names.
+  optional DO release_do = 36;
+
+  // For clashing local variables in Serialize and ByteSize calculation.
+  optional string target = 38;
+
+  extensions 1000 to max;  // NO_PROTO3
+}
+
+message TestConflictingSymbolNamesExtension {                      // NO_PROTO3
+  extend TestConflictingSymbolNames {                              // NO_PROTO3
+    repeated int32 repeated_int32_ext = 20423638 [packed = true];  // NO_PROTO3
+  }                                                                // NO_PROTO3
+}  // NO_PROTO3
+
+message TestConflictingEnumNames {  // NO_PROTO3
+  enum while {                      // NO_PROTO3
+    default = 0;                    // 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 while conflicting_enum = 1;  // NO_PROTO3
+}  // NO_PROTO3
+
+enum bool {      // NO_PROTO3
+  default = 0;   // NO_PROTO3
+  NOT_EQ = 1;    // NO_PROTO3
+  volatile = 2;  // NO_PROTO3
+  return = 3;    // NO_PROTO3
+}  // NO_PROTO3
+
+message DummyMessage {}
+
+message NULL {
+  optional int32 int = 1;
+}
+
+extend TestConflictingSymbolNames {  // NO_PROTO3
+  optional int32 void = 314253;      // NO_PROTO3
+}  // NO_PROTO3
+
+// Message names that could conflict.
+message Shutdown {}
+message TableStruct {}
+
+service TestConflictingMethodNames {
+  rpc Closure(DummyMessage) returns (DummyMessage);
+}
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
new file mode 100644
index 0000000..cb6ca1b
--- /dev/null
+++ b/src/google/protobuf/compiler/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/unittest.cc b/src/google/protobuf/compiler/cpp/unittest.cc
new file mode 100644
index 0000000..e2730d7
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/unittest.cc
@@ -0,0 +1,133 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// To test the code generator, we actually use it to generate code for
+// net/proto2/internal/unittest.proto, then test that.  This means that we
+// are actually testing the parser and other parts of the system at the same
+// time, and that problems in the generator may show up as compile-time errors
+// rather than unittest failures, which may be surprising.  However, testing
+// the output of the C++ generator directly would be very hard.  We can't very
+// well just check it against golden files since those files would have to be
+// updated for any small change; such a test would be very brittle and probably
+// not very helpful.  What we really want to test is that the code compiles
+// correctly and produces the interfaces we expect, which is why this test
+// is written this way.
+
+#include <google/protobuf/compiler/cpp/unittest.h>
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_embed_optimize_for.pb.h>
+#include <google/protobuf/unittest_optimize_for.pb.h>
+#include <google/protobuf/test_util.h>
+
+#define MESSAGE_TEST_NAME MessageTest
+#define GENERATED_DESCRIPTOR_TEST_NAME GeneratedDescriptorTest
+#define GENERATED_MESSAGE_TEST_NAME GeneratedMessageTest
+#define GENERATED_ENUM_TEST_NAME GeneratedEnumTest
+#define GENERATED_SERVICE_TEST_NAME GeneratedServiceTest
+#define HELPERS_TEST_NAME HelpersTest
+#define DESCRIPTOR_INIT_TEST_NAME DescriptorInitializationTest
+
+#define UNITTEST_PROTO_PATH "net/proto2/internal/unittest.proto"
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+
+// Must include after the above macros.
+#include <google/protobuf/compiler/cpp/unittest.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace cpp_unittest {
+
+namespace protobuf_unittest = ::protobuf_unittest;
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingSymbolNames) {
+  // test_bad_identifiers.proto successfully compiled, then it works.  The
+  // following is just a token usage to insure that the code is, in fact,
+  // being compiled and linked.
+
+  protobuf_unittest::TestConflictingSymbolNames message;
+  message.set_uint32(1);
+  EXPECT_EQ(3, message.ByteSizeLong());
+
+  message.set_friend_(5);
+  EXPECT_EQ(5, message.friend_());
+
+  message.set_class_(6);
+  EXPECT_EQ(6, message.class_());
+
+  // Instantiate extension template functions to test conflicting template
+  // parameter names.
+  typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage;
+  message.AddExtension(ExtensionMessage::repeated_int32_ext, 123);
+  EXPECT_EQ(123, message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingEnumNames) {
+  protobuf_unittest::TestConflictingEnumNames message;
+  message.set_conflicting_enum(
+      protobuf_unittest::TestConflictingEnumNames_while_and_);
+  EXPECT_EQ(1, message.conflicting_enum());
+  message.set_conflicting_enum(
+      protobuf_unittest::TestConflictingEnumNames_while_XOR);
+  EXPECT_EQ(5, message.conflicting_enum());
+
+  protobuf_unittest::bool_ conflicting_enum;
+  conflicting_enum = protobuf_unittest::NOT_EQ;
+  EXPECT_EQ(1, conflicting_enum);
+  conflicting_enum = protobuf_unittest::return_;
+  EXPECT_EQ(3, conflicting_enum);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingMessageNames) {
+  protobuf_unittest::NULL_ message;
+  message.set_int_(123);
+  EXPECT_EQ(message.int_(), 123);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingExtension) {
+  protobuf_unittest::TestConflictingSymbolNames message;
+  message.SetExtension(protobuf_unittest::void_, 123);
+  EXPECT_EQ(123, message.GetExtension(protobuf_unittest::void_));
+}
+
+}  // namespace cpp_unittest
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/unittest.h b/src/google/protobuf/compiler/cpp/unittest.h
new file mode 100644
index 0000000..c5dc767
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/unittest.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.
+
+// This header declares the namespace google::protobuf::protobuf_unittest in order to expose
+// any problems with the generated class names. We use this header to ensure
+// unittest.cc will declare the namespace prior to other includes, while obeying
+// normal include ordering.
+//
+// When generating a class name of "foo.Bar" we must ensure we prefix the class
+// name with "::", in case the namespace google::protobuf::foo exists. We intentionally
+// trigger that case here by declaring google::protobuf::protobuf_unittest.
+//
+// See ClassName in helpers.h for more details.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
+
+namespace google {
+namespace protobuf {
+namespace protobuf_unittest {}
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
diff --git a/src/google/protobuf/compiler/cpp/unittest.inc b/src/google/protobuf/compiler/cpp/unittest.inc
new file mode 100644
index 0000000..0b47176
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/unittest.inc
@@ -0,0 +1,2226 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// To test the code generator, we actually use it to generate code for
+// net/proto2/internal/unittest.proto, then test that.  This means that we
+// are actually testing the parser and other parts of the system at the same
+// time, and that problems in the generator may show up as compile-time errors
+// rather than unittest failures, which may be surprising.  However, testing
+// the output of the C++ generator directly would be very hard.  We can't very
+// well just check it against golden files since those files would have to be
+// updated for any small change; such a test would be very brittle and probably
+// not very helpful.  What we really want to test is that the code compiles
+// correctly and produces the interfaces we expect, which is why this test
+// is written this way.
+
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/compiler/cpp/unittest.h>
+#include <google/protobuf/stubs/strutil.h>
+#ifndef _MSC_VER
+// We exclude this large proto 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/compiler/cpp/helpers.h>
+#include <google/protobuf/compiler/cpp/test_bad_identifiers.pb.h>
+#include <google/protobuf/unittest_no_generic_services.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/test_util2.h>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace cpp_unittest {
+
+
+void DoNothing() {}
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() override {}
+
+  std::string text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const std::string& filename, int line, int column,
+                const std::string& message) override {
+    strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
+                              message);
+  }
+};
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+// Test that generated code has proper descriptors:
+// Parse a descriptor directly (using google::protobuf::compiler::Importer) and
+// compare it to the one that was produced by generated code.
+TEST(GENERATED_DESCRIPTOR_TEST_NAME, IdenticalDescriptors) {
+  const FileDescriptor* generated_descriptor =
+    UNITTEST::TestAllTypes::descriptor()->file();
+
+  // Set up the Importer.
+  MockErrorCollector error_collector;
+  DiskSourceTree source_tree;
+  source_tree.MapPath("", TestUtil::TestSourceDir());
+  Importer importer(&source_tree, &error_collector);
+
+  // Import (parse) unittest.proto.
+  const FileDescriptor* parsed_descriptor =
+      importer.Import(TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH));
+  EXPECT_EQ("", error_collector.text_);
+  ASSERT_TRUE(parsed_descriptor != nullptr);
+
+  // Test that descriptors are generated correctly by converting them to
+  // FileDescriptorProtos and comparing.
+  FileDescriptorProto generated_descriptor_proto, parsed_descriptor_proto;
+  generated_descriptor->CopyTo(&generated_descriptor_proto);
+  parsed_descriptor->CopyTo(&parsed_descriptor_proto);
+
+  EXPECT_EQ(parsed_descriptor_proto.DebugString(),
+            generated_descriptor_proto.DebugString());
+}
+
+#ifndef _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(GENERATED_DESCRIPTOR_TEST_NAME, EnormousDescriptor) {
+  const Descriptor* generated_descriptor =
+    ::protobuf_unittest::TestEnormousDescriptor::descriptor();
+
+  EXPECT_TRUE(generated_descriptor != nullptr);
+}
+#endif
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+// ===================================================================
+
+TEST(GENERATED_MESSAGE_TEST_NAME, Defaults) {
+  // Check that all default values are set correctly in the initial message.
+  UNITTEST::TestAllTypes message;
+
+  TestUtil::ExpectClear(message);
+
+  // Messages should return pointers to default instances until first use.
+  // (This is not checked by ExpectClear() since it is not actually true after
+  // the fields have been set and then cleared.)
+  EXPECT_EQ(&UNITTEST::TestAllTypes::OptionalGroup::default_instance(),
+            &message.optionalgroup());
+  EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(),
+            &message.optional_nested_message());
+  EXPECT_EQ(&UNITTEST::ForeignMessage::default_instance(),
+            &message.optional_foreign_message());
+  EXPECT_EQ(&UNITTEST_IMPORT::ImportMessage::default_instance(),
+            &message.optional_import_message());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, FloatingPointDefaults) {
+  const UNITTEST::TestExtremeDefaultValues& extreme_default =
+      UNITTEST::TestExtremeDefaultValues::default_instance();
+
+  EXPECT_EQ(0.0f, extreme_default.zero_float());
+  EXPECT_EQ(1.0f, extreme_default.one_float());
+  EXPECT_EQ(1.5f, extreme_default.small_float());
+  EXPECT_EQ(-1.0f, extreme_default.negative_one_float());
+  EXPECT_EQ(-1.5f, extreme_default.negative_float());
+  EXPECT_EQ(2.0e8f, extreme_default.large_float());
+  EXPECT_EQ(-8e-28f, extreme_default.small_negative_float());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(),
+            extreme_default.inf_double());
+  EXPECT_EQ(-std::numeric_limits<double>::infinity(),
+            extreme_default.neg_inf_double());
+  EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double());
+  EXPECT_EQ(std::numeric_limits<float>::infinity(),
+            extreme_default.inf_float());
+  EXPECT_EQ(-std::numeric_limits<float>::infinity(),
+            extreme_default.neg_inf_float());
+  EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, Trigraph) {
+  const UNITTEST::TestExtremeDefaultValues& extreme_default =
+      UNITTEST::TestExtremeDefaultValues::default_instance();
+
+  EXPECT_EQ("? ? ?? ?? ??? ?\?/ ?\?-", extreme_default.cpp_trigraph());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ExtremeSmallIntegerDefault) {
+  const UNITTEST::TestExtremeDefaultValues& extreme_default =
+      UNITTEST::TestExtremeDefaultValues::default_instance();
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(),
+            extreme_default.really_small_int32());
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+            extreme_default.really_small_int64());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, Accessors) {
+  // Set every field to a unique value then go back and check all those
+  // values.
+  UNITTEST::TestAllTypes message;
+
+  TestUtil::SetAllFields(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+
+  TestUtil::ModifyRepeatedFields(&message);
+  TestUtil::ExpectRepeatedFieldsModified(message);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, MutableStringDefault) {
+  // mutable_foo() for a string should return a string initialized to its
+  // default value.
+  UNITTEST::TestAllTypes message;
+
+  EXPECT_EQ("hello", *message.mutable_default_string());
+
+  // Note that the first time we call mutable_foo(), we get a newly-allocated
+  // string, but if we clear it and call it again, we get the same object again.
+  // We should verify that it has its default value in both cases.
+  message.set_default_string("blah");
+  message.Clear();
+
+  EXPECT_EQ("hello", *message.mutable_default_string());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, StringDefaults) {
+  UNITTEST::TestExtremeDefaultValues message;
+  // Check if '\000' can be used in default string value.
+  EXPECT_EQ(std::string("hel\000lo", 6), message.string_with_zero());
+  EXPECT_EQ(std::string("wor\000ld", 6), message.bytes_with_zero());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseString) {
+  // Check that release_foo() starts out nullptr, and gives us a value
+  // that we can delete after it's been set.
+  UNITTEST::TestAllTypes message;
+
+  EXPECT_EQ(nullptr, message.release_default_string());
+  EXPECT_FALSE(message.has_default_string());
+  EXPECT_EQ("hello", message.default_string());
+
+  message.set_default_string("blah");
+  EXPECT_TRUE(message.has_default_string());
+  std::unique_ptr<std::string> str(message.release_default_string());
+  EXPECT_FALSE(message.has_default_string());
+  ASSERT_TRUE(str != nullptr);
+  EXPECT_EQ("blah", *str);
+
+  EXPECT_EQ(nullptr, message.release_default_string());
+  EXPECT_FALSE(message.has_default_string());
+  EXPECT_EQ("hello", message.default_string());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseMessage) {
+  // Check that release_foo() starts out nullptr, and gives us a value
+  // that we can delete after it's been set.
+  UNITTEST::TestAllTypes message;
+
+  EXPECT_EQ(nullptr, message.release_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_nested_message());
+
+  message.mutable_optional_nested_message()->set_bb(1);
+  std::unique_ptr<UNITTEST::TestAllTypes::NestedMessage> nest(
+      message.release_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_nested_message());
+  ASSERT_TRUE(nest != nullptr);
+  EXPECT_EQ(1, nest->bb());
+
+  EXPECT_EQ(nullptr, message.release_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_nested_message());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, SetAllocatedString) {
+  // Check that set_allocated_foo() works for strings.
+  UNITTEST::TestAllTypes message;
+
+  EXPECT_FALSE(message.has_optional_string());
+  const std::string kHello("hello");
+  message.set_optional_string(kHello);
+  EXPECT_TRUE(message.has_optional_string());
+
+  message.set_allocated_optional_string(nullptr);
+  EXPECT_FALSE(message.has_optional_string());
+  EXPECT_EQ("", message.optional_string());
+
+  message.set_allocated_optional_string(new std::string(kHello));
+  EXPECT_TRUE(message.has_optional_string());
+  EXPECT_EQ(kHello, message.optional_string());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, SetAllocatedMessage) {
+  // Check that set_allocated_foo() can be called in all cases.
+  UNITTEST::TestAllTypes message;
+
+  EXPECT_FALSE(message.has_optional_nested_message());
+
+  message.mutable_optional_nested_message()->set_bb(1);
+  EXPECT_TRUE(message.has_optional_nested_message());
+
+  message.set_allocated_optional_nested_message(nullptr);
+  EXPECT_FALSE(message.has_optional_nested_message());
+  EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(),
+            &message.optional_nested_message());
+
+  message.mutable_optional_nested_message()->set_bb(1);
+  UNITTEST::TestAllTypes::NestedMessage* nest =
+      message.release_optional_nested_message();
+  ASSERT_TRUE(nest != nullptr);
+  EXPECT_FALSE(message.has_optional_nested_message());
+
+  message.set_allocated_optional_nested_message(nest);
+  EXPECT_TRUE(message.has_optional_nested_message());
+  EXPECT_EQ(1, message.optional_nested_message().bb());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, Clear) {
+  // Set every field to a unique value, clear the message, then check that
+  // it is cleared.
+  UNITTEST::TestAllTypes message;
+
+  TestUtil::SetAllFields(&message);
+  message.Clear();
+  TestUtil::ExpectClear(message);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, EmbeddedNullsInBytesCharStar) {
+  UNITTEST::TestAllTypes message;
+
+  const char* value = "\0lalala\0\0";
+  message.set_optional_bytes(value, 9);
+  ASSERT_EQ(9, message.optional_bytes().size());
+  EXPECT_EQ(0, memcmp(value, message.optional_bytes().data(), 9));
+
+  message.add_repeated_bytes(value, 9);
+  ASSERT_EQ(9, message.repeated_bytes(0).size());
+  EXPECT_EQ(0, memcmp(value, message.repeated_bytes(0).data(), 9));
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ClearOneField) {
+  // Set every field to a unique value, then clear one value and insure that
+  // only that one value is cleared.
+  UNITTEST::TestAllTypes message;
+
+  TestUtil::SetAllFields(&message);
+  int64_t original_value = message.optional_int64();
+
+  // Clear the field and make sure it shows up as cleared.
+  message.clear_optional_int64();
+  EXPECT_FALSE(message.has_optional_int64());
+  EXPECT_EQ(0, message.optional_int64());
+
+  // Other adjacent fields should not be cleared.
+  EXPECT_TRUE(message.has_optional_int32());
+  EXPECT_TRUE(message.has_optional_uint32());
+
+  // Make sure if we set it again, then all fields are set.
+  message.set_optional_int64(original_value);
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, StringCharStarLength) {
+  // Verify that we can use a char*,length to set one of the string fields.
+  UNITTEST::TestAllTypes message;
+  message.set_optional_string("abcdef", 3);
+  EXPECT_EQ("abc", message.optional_string());
+
+  // Verify that we can use a char*,length to add to a repeated string field.
+  message.add_repeated_string("abcdef", 3);
+  EXPECT_EQ(1, message.repeated_string_size());
+  EXPECT_EQ("abc", message.repeated_string(0));
+
+  // Verify that we can use a char*,length to set a repeated string field.
+  message.set_repeated_string(0, "wxyz", 2);
+  EXPECT_EQ("wx", message.repeated_string(0));
+}
+
+
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || defined(NDEBUG)
+TEST(GENERATED_MESSAGE_TEST_NAME, CopyFrom) {
+  UNITTEST::TestAllTypes message1, message2;
+
+  TestUtil::SetAllFields(&message1);
+  message2.CopyFrom(message1);
+  TestUtil::ExpectAllFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  message2.CopyFrom(message2);
+  TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, CopyAssignmentOperator) {
+  UNITTEST::TestAllTypes message1;
+  TestUtil::SetAllFields(&message1);
+
+  UNITTEST::TestAllTypes message2;
+  message2 = message1;
+  TestUtil::ExpectAllFieldsSet(message2);
+
+  // Make sure that self-assignment does something sane.
+  message2.operator=(message2);
+  TestUtil::ExpectAllFieldsSet(message2);
+}
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS || NDEBUG
+
+
+TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithEmpty) {
+  UNITTEST::TestAllTypes message1, message2;
+  TestUtil::SetAllFields(&message1);
+
+  TestUtil::ExpectAllFieldsSet(message1);
+  TestUtil::ExpectClear(message2);
+  message1.Swap(&message2);
+  TestUtil::ExpectAllFieldsSet(message2);
+  TestUtil::ExpectClear(message1);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithSelf) {
+  UNITTEST::TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+  message.Swap(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
+  UNITTEST::TestAllTypes message1, message2;
+
+  message1.set_optional_int32(123);
+  message1.set_optional_string("abc");
+  message1.mutable_optional_nested_message()->set_bb(1);
+  message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO);
+  message1.add_repeated_int32(1);
+  message1.add_repeated_int32(2);
+  message1.add_repeated_string("a");
+  message1.add_repeated_string("b");
+  message1.add_repeated_nested_message()->set_bb(7);
+  message1.add_repeated_nested_message()->set_bb(8);
+  message1.add_repeated_nested_enum(UNITTEST::TestAllTypes::FOO);
+  message1.add_repeated_nested_enum(UNITTEST::TestAllTypes::BAR);
+
+  message2.set_optional_int32(456);
+  message2.set_optional_string("def");
+  message2.mutable_optional_nested_message()->set_bb(2);
+  message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR);
+  message2.add_repeated_int32(3);
+  message2.add_repeated_string("c");
+  message2.add_repeated_nested_message()->set_bb(9);
+  message2.add_repeated_nested_enum(UNITTEST::TestAllTypes::BAZ);
+
+  message1.Swap(&message2);
+
+  EXPECT_EQ(456, message1.optional_int32());
+  EXPECT_EQ("def", message1.optional_string());
+  EXPECT_EQ(2, message1.optional_nested_message().bb());
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum());
+  ASSERT_EQ(1, message1.repeated_int32_size());
+  EXPECT_EQ(3, message1.repeated_int32(0));
+  ASSERT_EQ(1, message1.repeated_string_size());
+  EXPECT_EQ("c", message1.repeated_string(0));
+  ASSERT_EQ(1, message1.repeated_nested_message_size());
+  EXPECT_EQ(9, message1.repeated_nested_message(0).bb());
+  ASSERT_EQ(1, message1.repeated_nested_enum_size());
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, message1.repeated_nested_enum(0));
+
+  EXPECT_EQ(123, message2.optional_int32());
+  EXPECT_EQ("abc", message2.optional_string());
+  EXPECT_EQ(1, message2.optional_nested_message().bb());
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum());
+  ASSERT_EQ(2, message2.repeated_int32_size());
+  EXPECT_EQ(1, message2.repeated_int32(0));
+  EXPECT_EQ(2, message2.repeated_int32(1));
+  ASSERT_EQ(2, message2.repeated_string_size());
+  EXPECT_EQ("a", message2.repeated_string(0));
+  EXPECT_EQ("b", message2.repeated_string(1));
+  ASSERT_EQ(2, message2.repeated_nested_message_size());
+  EXPECT_EQ(7, message2.repeated_nested_message(0).bb());
+  EXPECT_EQ(8, message2.repeated_nested_message(1).bb());
+  ASSERT_EQ(2, message2.repeated_nested_enum_size());
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.repeated_nested_enum(0));
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message2.repeated_nested_enum(1));
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ADLSwap) {
+  UNITTEST::TestAllTypes message1, message2;
+  TestUtil::SetAllFields(&message1);
+
+  // Note the address of one of the repeated fields, to verify it was swapped
+  // rather than copied.
+  const int32_t* addr = &message1.repeated_int32().Get(0);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  const int32_t value = *addr;
+#endif
+
+  using std::swap;
+  swap(message1, message2);
+
+  TestUtil::ExpectAllFieldsSet(message2);
+  TestUtil::ExpectClear(message1);
+
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  EXPECT_NE(addr, &message2.repeated_int32().Get(0));
+  EXPECT_EQ(value, message2.repeated_int32().Get(0));
+#else
+  EXPECT_EQ(addr, &message2.repeated_int32().Get(0));
+#endif
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, CopyConstructor) {
+  // All set.
+  {
+    UNITTEST::TestAllTypes message1;
+    TestUtil::SetAllFields(&message1);
+
+    UNITTEST::TestAllTypes message2(message1);
+    TestUtil::ExpectAllFieldsSet(message2);
+  }
+
+  // None set.
+  {
+    UNITTEST::TestAllTypes message1;
+    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
+    UNITTEST::TestAllTypes message2(message1);
+
+    EXPECT_FALSE(message1.has_optional_string());
+    EXPECT_FALSE(message2.has_optional_string());
+    EXPECT_EQ(message1.optional_string(), message2.optional_string());
+
+    EXPECT_FALSE(message1.has_optional_bytes());
+    EXPECT_FALSE(message2.has_optional_bytes());
+    EXPECT_EQ(message1.optional_bytes(), message2.optional_bytes());
+
+    EXPECT_FALSE(message1.has_optional_nested_message());
+    EXPECT_FALSE(message2.has_optional_nested_message());
+    EXPECT_EQ(&message1.optional_nested_message(),
+              &message2.optional_nested_message());
+
+    EXPECT_FALSE(message1.has_optional_foreign_message());
+    EXPECT_FALSE(message2.has_optional_foreign_message());
+    EXPECT_EQ(&message1.optional_foreign_message(),
+              &message2.optional_foreign_message());
+
+    EXPECT_FALSE(message1.has_optional_import_message());
+    EXPECT_FALSE(message2.has_optional_import_message());
+    EXPECT_EQ(&message1.optional_import_message(),
+              &message2.optional_import_message());
+
+    EXPECT_FALSE(message1.has_optional_public_import_message());
+    EXPECT_FALSE(message2.has_optional_public_import_message());
+    EXPECT_EQ(&message1.optional_public_import_message(),
+              &message2.optional_public_import_message());
+
+    EXPECT_FALSE(message1.has_optional_lazy_message());
+    EXPECT_FALSE(message2.has_optional_lazy_message());
+    EXPECT_EQ(&message1.optional_lazy_message(),
+              &message2.optional_lazy_message());
+  }
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, CopyConstructorWithArenas) {
+  Arena arena;
+  UNITTEST::TestAllTypes* message1 =
+      Arena::CreateMessage<UNITTEST::TestAllTypes>(&arena);
+  TestUtil::SetAllFields(message1);
+
+  UNITTEST::TestAllTypes message2_stack(*message1);
+  TestUtil::ExpectAllFieldsSet(message2_stack);
+
+  std::unique_ptr<UNITTEST::TestAllTypes> message2_heap(
+      new UNITTEST::TestAllTypes(*message1));
+  TestUtil::ExpectAllFieldsSet(*message2_heap);
+
+  arena.Reset();
+
+  // Verify that the copies are still intact.
+  TestUtil::ExpectAllFieldsSet(message2_stack);
+  TestUtil::ExpectAllFieldsSet(*message2_heap);
+}
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+TEST(GENERATED_MESSAGE_TEST_NAME, UpcastCopyFrom) {
+  // Test the CopyFrom method that takes in the generic const Message&
+  // parameter.
+  UNITTEST::TestAllTypes message1, message2;
+
+  TestUtil::SetAllFields(&message1);
+
+  const Message* source = implicit_cast<const Message*>(&message1);
+  message2.CopyFrom(*source);
+
+  TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, DynamicMessageCopyFrom) {
+  // Test copying from a DynamicMessage, which must fall back to using
+  // reflection.
+  UNITTEST::TestAllTypes message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(
+                     UNITTEST::TestAllTypes::descriptor())->New());
+
+  TestUtil::ReflectionTester reflection_tester(
+    UNITTEST::TestAllTypes::descriptor());
+  reflection_tester.SetAllFieldsViaReflection(message1.get());
+
+  message2.CopyFrom(*message1);
+
+  TestUtil::ExpectAllFieldsSet(message2);
+}
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GENERATED_MESSAGE_TEST_NAME, NonEmptyMergeFrom) {
+  // Test merging with a non-empty message. Code is a modified form
+  // of that found in net/proto2/internal/reflection_ops_unittest.cc.
+  UNITTEST::TestAllTypes message1, message2;
+
+  TestUtil::SetAllFields(&message1);
+
+  // This field will test merging into an empty spot.
+  message2.set_optional_int32(message1.optional_int32());
+  message1.clear_optional_int32();
+
+  // This tests overwriting.
+  message2.set_optional_string(message1.optional_string());
+  message1.set_optional_string("something else");
+
+  // This tests concatenating.
+  message2.add_repeated_int32(message1.repeated_int32(1));
+  int32_t i = message1.repeated_int32(0);
+  message1.clear_repeated_int32();
+  message1.add_repeated_int32(i);
+
+  message1.MergeFrom(message2);
+
+  TestUtil::ExpectAllFieldsSet(message1);
+}
+
+
+// Test the generated SerializeWithCachedSizesToArray(),
+TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToArray) {
+  UNITTEST::TestAllTypes message1, message2;
+  std::string data;
+  TestUtil::SetAllFields(&message1);
+  int size = message1.ByteSizeLong();
+  data.resize(size);
+  uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+  EXPECT_EQ(size, end - start);
+  EXPECT_TRUE(message2.ParseFromString(data));
+  TestUtil::ExpectAllFieldsSet(message2);
+
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToArray) {
+  UNITTEST::TestPackedTypes packed_message1, packed_message2;
+  std::string packed_data;
+  TestUtil::SetPackedFields(&packed_message1);
+  int packed_size = packed_message1.ByteSizeLong();
+  packed_data.resize(packed_size);
+  uint8_t* start =
+      reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&packed_data));
+  uint8_t* end = packed_message1.SerializeWithCachedSizesToArray(start);
+  EXPECT_EQ(packed_size, end - start);
+  EXPECT_TRUE(packed_message2.ParseFromString(packed_data));
+  TestUtil::ExpectPackedFieldsSet(packed_message2);
+}
+
+// Test the generated SerializeWithCachedSizes() by forcing the buffer to write
+// one byte at a time.
+TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToStream) {
+  UNITTEST::TestAllTypes message1, message2;
+  TestUtil::SetAllFields(&message1);
+  int size = message1.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  {
+    // Allow the output stream to buffer only one byte at a time.
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message1.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_TRUE(message2.ParseFromString(data));
+  TestUtil::ExpectAllFieldsSet(message2);
+
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToStream) {
+  UNITTEST::TestPackedTypes message1, message2;
+  TestUtil::SetPackedFields(&message1);
+  int size = message1.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  {
+    // Allow the output stream to buffer only one byte at a time.
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message1.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_TRUE(message2.ParseFromString(data));
+  TestUtil::ExpectPackedFieldsSet(message2);
+}
+
+
+TEST(GENERATED_MESSAGE_TEST_NAME, Required) {
+  // Test that IsInitialized() returns false if required fields are missing.
+  UNITTEST::TestRequired message;
+
+  EXPECT_FALSE(message.IsInitialized());
+  message.set_a(1);
+  EXPECT_FALSE(message.IsInitialized());
+  message.set_b(2);
+  EXPECT_FALSE(message.IsInitialized());
+  message.set_c(3);
+  EXPECT_TRUE(message.IsInitialized());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, RequiredForeign) {
+  // Test that IsInitialized() returns false if required fields in nested
+  // messages are missing.
+  UNITTEST::TestRequiredForeign message;
+
+  EXPECT_TRUE(message.IsInitialized());
+
+  message.mutable_optional_message();
+  EXPECT_FALSE(message.IsInitialized());
+
+  message.mutable_optional_message()->set_a(1);
+  message.mutable_optional_message()->set_b(2);
+  message.mutable_optional_message()->set_c(3);
+  EXPECT_TRUE(message.IsInitialized());
+
+  message.add_repeated_message();
+  EXPECT_FALSE(message.IsInitialized());
+
+  message.mutable_repeated_message(0)->set_a(1);
+  message.mutable_repeated_message(0)->set_b(2);
+  message.mutable_repeated_message(0)->set_c(3);
+  EXPECT_TRUE(message.IsInitialized());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ForeignNested) {
+  // Test that TestAllTypes::NestedMessage can be embedded directly into
+  // another message.
+  UNITTEST::TestForeignNested message;
+
+  // If this compiles and runs without crashing, it must work.  We have
+  // nothing more to test.
+  UNITTEST::TestAllTypes::NestedMessage* nested =
+    message.mutable_foreign_nested();
+  nested->set_bb(1);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ReallyLargeTagNumber) {
+  // Test that really large tag numbers don't break anything.
+  UNITTEST::TestReallyLargeTagNumber message1, message2;
+  std::string data;
+
+  // For the most part, if this compiles and runs then we're probably good.
+  // (The most likely cause for failure would be if something were attempting
+  // to allocate a lookup table of some sort using tag numbers as the index.)
+  // We'll try serializing just for fun.
+  message1.set_a(1234);
+  message1.set_bb(5678);
+  message1.SerializeToString(&data);
+  EXPECT_TRUE(message2.ParseFromString(data));
+  EXPECT_EQ(1234, message2.a());
+  EXPECT_EQ(5678, message2.bb());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, MutualRecursion) {
+  // Test that mutually-recursive message types work.
+  UNITTEST::TestMutualRecursionA message;
+  UNITTEST::TestMutualRecursionA* nested = message.mutable_bb()->mutable_a();
+  UNITTEST::TestMutualRecursionA* nested2 = nested->mutable_bb()->mutable_a();
+
+  // Again, if the above compiles and runs, that's all we really have to
+  // test, but just for run we'll check that the system didn't somehow come
+  // up with a pointer loop...
+  EXPECT_NE(&message, nested);
+  EXPECT_NE(&message, nested2);
+  EXPECT_NE(nested, nested2);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, CamelCaseFieldNames) {
+  // This test is mainly checking that the following compiles, which verifies
+  // that the field names were coerced to lower-case.
+  //
+  // Protocol buffers standard style is to use lowercase-with-underscores for
+  // field names.  Some old proto1 .protos unfortunately used camel-case field
+  // names.  In proto1, these names were forced to lower-case.  So, we do the
+  // same thing in proto2.
+
+  UNITTEST::TestCamelCaseFieldNames message;
+
+  message.set_primitivefield(2);
+  message.set_stringfield("foo");
+  message.set_enumfield(UNITTEST::FOREIGN_FOO);
+  message.mutable_messagefield()->set_c(6);
+
+  message.add_repeatedprimitivefield(8);
+  message.add_repeatedstringfield("moo");
+  message.add_repeatedenumfield(UNITTEST::FOREIGN_BAR);
+  message.add_repeatedmessagefield()->set_c(15);
+
+  EXPECT_EQ(2, message.primitivefield());
+  EXPECT_EQ("foo", message.stringfield());
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.enumfield());
+  EXPECT_EQ(6, message.messagefield().c());
+
+  EXPECT_EQ(8, message.repeatedprimitivefield(0));
+  EXPECT_EQ("moo", message.repeatedstringfield(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeatedenumfield(0));
+  EXPECT_EQ(15, message.repeatedmessagefield(0).c());
+}
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestOptimizedForSize) {
+  // We rely on the tests in reflection_ops_unittest and wire_format_unittest
+  // to really test that reflection-based methods work.  Here we are mostly
+  // just making sure that TestOptimizedForSize actually builds and seems to
+  // function.
+
+  UNITTEST::TestOptimizedForSize message, message2;
+  message.set_i(1);
+  message.mutable_msg()->set_c(2);
+  message2.CopyFrom(message);
+  EXPECT_EQ(1, message2.i());
+  EXPECT_EQ(2, message2.msg().c());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestEmbedOptimizedForSize) {
+  // Verifies that something optimized for speed can contain something optimized
+  // for size.
+
+  UNITTEST::TestEmbedOptimizedForSize message, message2;
+  message.mutable_optional_message()->set_i(1);
+  message.add_repeated_message()->mutable_msg()->set_c(2);
+  std::string data;
+  message.SerializeToString(&data);
+  ASSERT_TRUE(message2.ParseFromString(data));
+  EXPECT_EQ(1, message2.optional_message().i());
+  EXPECT_EQ(2, message2.repeated_message(0).msg().c());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestSpaceUsed) {
+  // Allocate explicitly on the heap to prevent arena creation.
+  std::unique_ptr<UNITTEST::TestAllTypes> message1(
+    Arena::CreateMessage<UNITTEST::TestAllTypes>(nullptr));
+  // sizeof provides a lower bound on SpaceUsedLong().
+  EXPECT_LE(sizeof(UNITTEST::TestAllTypes), message1->SpaceUsedLong());
+  const size_t empty_message_size = message1->SpaceUsedLong();
+
+  // Setting primitive types shouldn't affect the space used.
+  message1->set_optional_int32(123);
+  message1->set_optional_int64(12345);
+  message1->set_optional_uint32(123);
+  message1->set_optional_uint64(12345);
+  EXPECT_EQ(empty_message_size, message1->SpaceUsedLong());
+
+  // On some STL implementations, setting the string to a small value should
+  // only increase SpaceUsedLong() by the size of a string object, though this
+  // is not true everywhere.
+  message1->set_optional_string("abc");
+  EXPECT_LE(empty_message_size + message1->optional_string().size(),
+            message1->SpaceUsedLong());
+
+  // Setting a string to a value larger than the string object itself should
+  // increase SpaceUsedLong(), because it cannot store the value internally.
+  message1->set_optional_string(std::string(sizeof(std::string) + 1, 'x'));
+  int min_expected_increase = message1->optional_string().capacity();
+  EXPECT_LE(empty_message_size + min_expected_increase,
+            message1->SpaceUsedLong());
+
+  size_t previous_size = message1->SpaceUsedLong();
+  // Adding an optional message should increase the size by the size of the
+  // nested message type. NestedMessage is simple enough (1 int field) that it
+  // is equal to sizeof(NestedMessage)
+  message1->mutable_optional_nested_message();
+  ASSERT_EQ(sizeof(UNITTEST::TestAllTypes::NestedMessage),
+            message1->optional_nested_message().SpaceUsedLong());
+  EXPECT_EQ(previous_size +
+            sizeof(UNITTEST::TestAllTypes::NestedMessage),
+            message1->SpaceUsedLong());
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestOneofSpaceUsed) {
+  // Allocate explicitly on the heap to prevent arena creation.
+  std::unique_ptr<UNITTEST::TestOneof2> message1(
+    Arena::CreateMessage<UNITTEST::TestOneof2>(nullptr));
+  EXPECT_LE(sizeof(UNITTEST::TestOneof2), message1->SpaceUsedLong());
+
+  const size_t empty_message_size = message1->SpaceUsedLong();
+  // Setting primitive types shouldn't affect the space used.
+  message1->set_foo_int(123);
+  message1->set_bar_int(12345);
+  EXPECT_EQ(empty_message_size, message1->SpaceUsedLong());
+
+  // Setting a string in oneof to a small value should only increase
+  // SpaceUsedLong() by the size of a string object.
+  message1->set_foo_string("abc");
+  EXPECT_LE(empty_message_size + sizeof(std::string), message1->SpaceUsedLong());
+
+  // Setting a string in oneof to a value larger than the string object itself
+  // should increase SpaceUsedLong(), because it cannot store the value
+  // internally.
+  message1->set_foo_string(std::string(sizeof(std::string) + 1, 'x'));
+  int min_expected_increase =
+      message1->foo_string().capacity() + sizeof(std::string);
+  EXPECT_LE(empty_message_size + min_expected_increase,
+            message1->SpaceUsedLong());
+
+  // Setting a message in oneof should delete the other fields and increase the
+  // size by the size of the nested message type. NestedMessage is simple enough
+  // that it is equal to sizeof(NestedMessage). It may be backed by LazyField,
+  // increasing space used by LazyField and backing Cord.
+  message1->mutable_foo_message();
+  ASSERT_EQ(sizeof(UNITTEST::TestOneof2::NestedMessage),
+            message1->foo_message().SpaceUsedLong());
+  EXPECT_LE(empty_message_size + sizeof(UNITTEST::TestOneof2::NestedMessage),
+            message1->SpaceUsedLong());
+}
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GENERATED_MESSAGE_TEST_NAME, FieldConstantValues) {
+  UNITTEST::TestRequired message;
+  EXPECT_EQ(UNITTEST::TestAllTypes_NestedMessage::kBbFieldNumber, 1);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalInt32FieldNumber, 1);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalgroupFieldNumber, 16);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalNestedMessageFieldNumber, 18);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kOptionalNestedEnumFieldNumber, 21);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedInt32FieldNumber, 31);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedgroupFieldNumber, 46);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48);
+  EXPECT_EQ(UNITTEST::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ExtensionConstantValues) {
+  EXPECT_EQ(UNITTEST::TestRequired::kSingleFieldNumber, 1000);
+  EXPECT_EQ(UNITTEST::TestRequired::kMultiFieldNumber, 1001);
+  EXPECT_EQ(UNITTEST::kOptionalInt32ExtensionFieldNumber, 1);
+  EXPECT_EQ(UNITTEST::kOptionalgroupExtensionFieldNumber, 16);
+  EXPECT_EQ(UNITTEST::kOptionalNestedMessageExtensionFieldNumber, 18);
+  EXPECT_EQ(UNITTEST::kOptionalNestedEnumExtensionFieldNumber, 21);
+  EXPECT_EQ(UNITTEST::kRepeatedInt32ExtensionFieldNumber, 31);
+  EXPECT_EQ(UNITTEST::kRepeatedgroupExtensionFieldNumber, 46);
+  EXPECT_EQ(UNITTEST::kRepeatedNestedMessageExtensionFieldNumber, 48);
+  EXPECT_EQ(UNITTEST::kRepeatedNestedEnumExtensionFieldNumber, 51);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, ParseFromTruncated) {
+  const std::string long_string = std::string(128, 'q');
+  FileDescriptorProto p;
+  p.add_extension()->set_name(long_string);
+  const std::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(GENERATED_ENUM_TEST_NAME, EnumValuesAsSwitchCases) {
+  // Test that our nested enum values can be used as switch cases.  This test
+  // doesn't actually do anything, the proof that it works is that it
+  // compiles.
+  int i =0;
+  UNITTEST::TestAllTypes::NestedEnum a = UNITTEST::TestAllTypes::BAR;
+  switch (a) {
+    case UNITTEST::TestAllTypes::FOO:
+      i = 1;
+      break;
+    case UNITTEST::TestAllTypes::BAR:
+      i = 2;
+      break;
+    case UNITTEST::TestAllTypes::BAZ:
+      i = 3;
+      break;
+    case UNITTEST::TestAllTypes::NEG:
+      i = -1;
+      break;
+    // no default case:  We want to make sure the compiler recognizes that
+    //   all cases are covered.  (GCC warns if you do not cover all cases of
+    //   an enum in a switch.)
+  }
+
+  // Token check just for fun.
+  EXPECT_EQ(2, i);
+}
+
+TEST(GENERATED_ENUM_TEST_NAME, IsValidValue) {
+  // Test enum IsValidValue.
+  EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(1));
+  EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(2));
+  EXPECT_TRUE(UNITTEST::TestAllTypes::NestedEnum_IsValid(3));
+
+  EXPECT_FALSE(UNITTEST::TestAllTypes::NestedEnum_IsValid(0));
+  EXPECT_FALSE(UNITTEST::TestAllTypes::NestedEnum_IsValid(4));
+
+  // Make sure it also works when there are dups.
+  EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(1));
+  EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(2));
+  EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_IsValid(3));
+
+  EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_IsValid(0));
+  EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_IsValid(4));
+}
+
+TEST(GENERATED_ENUM_TEST_NAME, MinAndMax) {
+  EXPECT_EQ(UNITTEST::TestAllTypes::NEG,
+            UNITTEST::TestAllTypes::NestedEnum_MIN);
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ,
+            UNITTEST::TestAllTypes::NestedEnum_MAX);
+  EXPECT_EQ(4, UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE);
+
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO, UNITTEST::ForeignEnum_MIN);
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ, UNITTEST::ForeignEnum_MAX);
+  EXPECT_EQ(7, UNITTEST::ForeignEnum_ARRAYSIZE);
+
+  EXPECT_EQ(1, UNITTEST::TestEnumWithDupValue_MIN);
+  EXPECT_EQ(3, UNITTEST::TestEnumWithDupValue_MAX);
+  EXPECT_EQ(4, UNITTEST::TestEnumWithDupValue_ARRAYSIZE);
+
+  EXPECT_EQ(UNITTEST::SPARSE_E, UNITTEST::TestSparseEnum_MIN);
+  EXPECT_EQ(UNITTEST::SPARSE_C, UNITTEST::TestSparseEnum_MAX);
+  EXPECT_EQ(12589235, UNITTEST::TestSparseEnum_ARRAYSIZE);
+
+  // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE.
+  EXPECT_NE(nullptr, &UNITTEST::TestAllTypes::NestedEnum_MIN);
+  EXPECT_NE(nullptr, &UNITTEST::TestAllTypes::NestedEnum_MAX);
+  EXPECT_NE(nullptr, &UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE);
+
+  EXPECT_NE(nullptr, &UNITTEST::ForeignEnum_MIN);
+  EXPECT_NE(nullptr, &UNITTEST::ForeignEnum_MAX);
+  EXPECT_NE(nullptr, &UNITTEST::ForeignEnum_ARRAYSIZE);
+
+  // Make sure we can use _MIN and _MAX as switch cases.
+  switch (UNITTEST::SPARSE_A) {
+    case UNITTEST::TestSparseEnum_MIN:
+    case UNITTEST::TestSparseEnum_MAX:
+      break;
+    default:
+      break;
+  }
+}
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GENERATED_ENUM_TEST_NAME, Name) {
+  // "Names" in the presence of dup values map to the first alias.
+  EXPECT_EQ("FOO1", UNITTEST::TestEnumWithDupValue_Name(UNITTEST::FOO1));
+  EXPECT_EQ("FOO1", UNITTEST::TestEnumWithDupValue_Name(UNITTEST::FOO2));
+
+  EXPECT_EQ("SPARSE_A", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_A));
+  EXPECT_EQ("SPARSE_B", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_B));
+  EXPECT_EQ("SPARSE_C", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_C));
+  EXPECT_EQ("SPARSE_D", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_D));
+  EXPECT_EQ("SPARSE_E", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_E));
+  EXPECT_EQ("SPARSE_F", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_F));
+  EXPECT_EQ("SPARSE_G", UNITTEST::TestSparseEnum_Name(UNITTEST::SPARSE_G));
+}
+
+TEST(GENERATED_ENUM_TEST_NAME, Parse) {
+  UNITTEST::TestEnumWithDupValue dup_value = UNITTEST::FOO1;
+  EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_Parse("FOO1", &dup_value));
+  EXPECT_EQ(UNITTEST::FOO1, dup_value);
+  EXPECT_TRUE(UNITTEST::TestEnumWithDupValue_Parse("FOO2", &dup_value));
+  EXPECT_EQ(UNITTEST::FOO2, dup_value);
+  EXPECT_FALSE(UNITTEST::TestEnumWithDupValue_Parse("FOO", &dup_value));
+}
+
+TEST(GENERATED_ENUM_TEST_NAME, GetEnumDescriptor) {
+  EXPECT_EQ(UNITTEST::TestAllTypes::NestedEnum_descriptor(),
+            GetEnumDescriptor<UNITTEST::TestAllTypes::NestedEnum>());
+  EXPECT_EQ(UNITTEST::ForeignEnum_descriptor(),
+            GetEnumDescriptor<UNITTEST::ForeignEnum>());
+  EXPECT_EQ(UNITTEST::TestEnumWithDupValue_descriptor(),
+            GetEnumDescriptor<UNITTEST::TestEnumWithDupValue>());
+  EXPECT_EQ(UNITTEST::TestSparseEnum_descriptor(),
+            GetEnumDescriptor<UNITTEST::TestSparseEnum>());
+}
+
+enum NonProtoEnum {
+  kFoo = 1,
+};
+
+TEST(GENERATED_ENUM_TEST_NAME, IsProtoEnumTypeTrait) {
+  EXPECT_TRUE(is_proto_enum<UNITTEST::TestAllTypes::NestedEnum>::value);
+  EXPECT_TRUE(is_proto_enum<UNITTEST::ForeignEnum>::value);
+  EXPECT_TRUE(is_proto_enum<UNITTEST::TestEnumWithDupValue>::value);
+  EXPECT_TRUE(is_proto_enum<UNITTEST::TestSparseEnum>::value);
+
+  EXPECT_FALSE(is_proto_enum<int>::value);
+  EXPECT_FALSE(is_proto_enum<NonProtoEnum>::value);
+}
+
+#endif  // PROTOBUF_TEST_NO_DESCRIPTORS
+
+// ===================================================================
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+// Support code for testing services.
+class GENERATED_SERVICE_TEST_NAME : public testing::Test {
+ protected:
+  class MockTestService : public UNITTEST::TestService {
+   public:
+    MockTestService()
+        : called_(false),
+          method_(""),
+          controller_(nullptr),
+          request_(nullptr),
+          response_(nullptr),
+          done_(nullptr) {}
+
+    ~MockTestService() override {}
+
+    void Reset() { called_ = false; }
+
+    // implements TestService ----------------------------------------
+
+    void Foo(RpcController* controller, const UNITTEST::FooRequest* request,
+             UNITTEST::FooResponse* response, Closure* done) override {
+      ASSERT_FALSE(called_);
+      called_ = true;
+      method_ = "Foo";
+      controller_ = controller;
+      request_ = request;
+      response_ = response;
+      done_ = done;
+    }
+
+    void Bar(RpcController* controller, const UNITTEST::BarRequest* request,
+             UNITTEST::BarResponse* response, Closure* done) override {
+      ASSERT_FALSE(called_);
+      called_ = true;
+      method_ = "Bar";
+      controller_ = controller;
+      request_ = request;
+      response_ = response;
+      done_ = done;
+    }
+
+    // ---------------------------------------------------------------
+
+    bool called_;
+    std::string method_;
+    RpcController* controller_;
+    const Message* request_;
+    Message* response_;
+    Closure* done_;
+  };
+
+  class MockRpcChannel : public RpcChannel {
+   public:
+    MockRpcChannel()
+        : called_(false),
+          method_(nullptr),
+          controller_(nullptr),
+          request_(nullptr),
+          response_(nullptr),
+          done_(nullptr),
+          destroyed_(nullptr) {}
+
+    ~MockRpcChannel() override {
+      if (destroyed_ != nullptr) *destroyed_ = true;
+    }
+
+    void Reset() { called_ = false; }
+
+    // implements TestService ----------------------------------------
+
+    void CallMethod(const MethodDescriptor* method, RpcController* controller,
+                    const Message* request, Message* response,
+                    Closure* done) override {
+      ASSERT_FALSE(called_);
+      called_ = true;
+      method_ = method;
+      controller_ = controller;
+      request_ = request;
+      response_ = response;
+      done_ = done;
+    }
+
+    // ---------------------------------------------------------------
+
+    bool called_;
+    const MethodDescriptor* method_;
+    RpcController* controller_;
+    const Message* request_;
+    Message* response_;
+    Closure* done_;
+    bool* destroyed_;
+  };
+
+  class MockController : public RpcController {
+   public:
+    void Reset() override {
+      ADD_FAILURE() << "Reset() not expected during this test.";
+    }
+    bool Failed() const override {
+      ADD_FAILURE() << "Failed() not expected during this test.";
+      return false;
+    }
+    std::string ErrorText() const override {
+      ADD_FAILURE() << "ErrorText() not expected during this test.";
+      return "";
+    }
+    void StartCancel() override {
+      ADD_FAILURE() << "StartCancel() not expected during this test.";
+    }
+    void SetFailed(const std::string& reason) override {
+      ADD_FAILURE() << "SetFailed() not expected during this test.";
+    }
+    bool IsCanceled() const override {
+      ADD_FAILURE() << "IsCanceled() not expected during this test.";
+      return false;
+    }
+    void NotifyOnCancel(Closure* callback) override {
+      ADD_FAILURE() << "NotifyOnCancel() not expected during this test.";
+    }
+  };
+
+  GENERATED_SERVICE_TEST_NAME()
+    : descriptor_(UNITTEST::TestService::descriptor()),
+      foo_(descriptor_->FindMethodByName("Foo")),
+      bar_(descriptor_->FindMethodByName("Bar")),
+      stub_(&mock_channel_),
+      done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(foo_ != nullptr);
+    ASSERT_TRUE(bar_ != nullptr);
+  }
+
+  const ServiceDescriptor* descriptor_;
+  const MethodDescriptor* foo_;
+  const MethodDescriptor* bar_;
+
+  MockTestService mock_service_;
+  MockController mock_controller_;
+
+  MockRpcChannel mock_channel_;
+  UNITTEST::TestService::Stub stub_;
+
+  // Just so we don't have to re-define these with every test.
+  UNITTEST::FooRequest foo_request_;
+  UNITTEST::FooResponse foo_response_;
+  UNITTEST::BarRequest bar_request_;
+  UNITTEST::BarResponse bar_response_;
+  std::unique_ptr<Closure> done_;
+};
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, GetDescriptor) {
+  // Test that GetDescriptor() works.
+
+  EXPECT_EQ(descriptor_, mock_service_.GetDescriptor());
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, GetChannel) {
+  EXPECT_EQ(&mock_channel_, stub_.channel());
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, OwnsChannel) {
+  MockRpcChannel* channel = new MockRpcChannel;
+  bool destroyed = false;
+  channel->destroyed_ = &destroyed;
+
+  {
+    UNITTEST::TestService::Stub owning_stub(channel,
+                                            Service::STUB_OWNS_CHANNEL);
+    EXPECT_FALSE(destroyed);
+  }
+
+  EXPECT_TRUE(destroyed);
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, CallMethod) {
+  // Test that CallMethod() works.
+
+  // Call Foo() via CallMethod().
+  mock_service_.CallMethod(foo_, &mock_controller_,
+                           &foo_request_, &foo_response_, done_.get());
+
+  ASSERT_TRUE(mock_service_.called_);
+
+  EXPECT_EQ("Foo"            , mock_service_.method_    );
+  EXPECT_EQ(&mock_controller_, mock_service_.controller_);
+  EXPECT_EQ(&foo_request_    , mock_service_.request_   );
+  EXPECT_EQ(&foo_response_   , mock_service_.response_  );
+  EXPECT_EQ(done_.get()      , mock_service_.done_      );
+
+  // Try again, but call Bar() instead.
+  mock_service_.Reset();
+  mock_service_.CallMethod(bar_, &mock_controller_,
+                           &bar_request_, &bar_response_, done_.get());
+
+  ASSERT_TRUE(mock_service_.called_);
+  EXPECT_EQ("Bar", mock_service_.method_);
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, CallMethodTypeFailure) {
+  // Verify death if we call Foo() with Bar's message types.
+
+#ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet
+  EXPECT_DEBUG_DEATH(
+    mock_service_.CallMethod(foo_, &mock_controller_,
+                             &foo_request_, &bar_response_, done_.get()),
+    "dynamic_cast");
+
+  mock_service_.Reset();
+  EXPECT_DEBUG_DEATH(
+    mock_service_.CallMethod(foo_, &mock_controller_,
+                             &bar_request_, &foo_response_, done_.get()),
+    "dynamic_cast");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, GetPrototypes) {
+  // Test Get{Request,Response}Prototype() methods.
+
+  EXPECT_EQ(&UNITTEST::FooRequest::default_instance(),
+            &mock_service_.GetRequestPrototype(foo_));
+  EXPECT_EQ(&UNITTEST::BarRequest::default_instance(),
+            &mock_service_.GetRequestPrototype(bar_));
+
+  EXPECT_EQ(&UNITTEST::FooResponse::default_instance(),
+            &mock_service_.GetResponsePrototype(foo_));
+  EXPECT_EQ(&UNITTEST::BarResponse::default_instance(),
+            &mock_service_.GetResponsePrototype(bar_));
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, Stub) {
+  // Test that the stub class works.
+
+  // Call Foo() via the stub.
+  stub_.Foo(&mock_controller_, &foo_request_, &foo_response_, done_.get());
+
+  ASSERT_TRUE(mock_channel_.called_);
+
+  EXPECT_EQ(foo_             , mock_channel_.method_    );
+  EXPECT_EQ(&mock_controller_, mock_channel_.controller_);
+  EXPECT_EQ(&foo_request_    , mock_channel_.request_   );
+  EXPECT_EQ(&foo_response_   , mock_channel_.response_  );
+  EXPECT_EQ(done_.get()      , mock_channel_.done_      );
+
+  // Call Bar() via the stub.
+  mock_channel_.Reset();
+  stub_.Bar(&mock_controller_, &bar_request_, &bar_response_, done_.get());
+
+  ASSERT_TRUE(mock_channel_.called_);
+  EXPECT_EQ(bar_, mock_channel_.method_);
+}
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, NotImplemented) {
+  // Test that failing to implement a method of a service causes it to fail
+  // with a "not implemented" error message.
+
+  // A service which doesn't implement any methods.
+  class UnimplementedService : public UNITTEST::TestService {
+   public:
+    UnimplementedService() {}
+  };
+
+  UnimplementedService unimplemented_service;
+
+  // And a controller which expects to get a "not implemented" error.
+  class ExpectUnimplementedController : public MockController {
+   public:
+    ExpectUnimplementedController() : called_(false) {}
+
+    void SetFailed(const std::string& reason) override {
+      EXPECT_FALSE(called_);
+      called_ = true;
+      EXPECT_EQ("Method Foo() not implemented.", reason);
+    }
+
+    bool called_;
+  };
+
+  ExpectUnimplementedController controller;
+
+  // Call Foo.
+  unimplemented_service.Foo(&controller, &foo_request_, &foo_response_,
+                            done_.get());
+
+  EXPECT_TRUE(controller.called_);
+}
+
+// ===================================================================
+
+class OneofTest : public testing::Test {
+ protected:
+  void SetUp() override {}
+
+  void ExpectEnumCasesWork(const UNITTEST::TestOneof2 &message) {
+    switch (message.foo_case()) {
+      case UNITTEST::TestOneof2::kFooInt:
+        EXPECT_TRUE(message.has_foo_int());
+        break;
+      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;
+      case UNITTEST::TestOneof2::kFooEnum:
+        EXPECT_TRUE(message.has_foo_enum());
+        break;
+      case UNITTEST::TestOneof2::kFooMessage:
+        EXPECT_TRUE(message.has_foo_message());
+        break;
+      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;
+    }
+  }
+};
+
+TEST_F(OneofTest, SettingOneFieldClearsOthers) {
+  UNITTEST::TestOneof2 message;
+
+  message.set_foo_int(123);
+  EXPECT_TRUE(message.has_foo_int());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.set_foo_string("foo");
+  EXPECT_TRUE(message.has_foo_string());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+
+  message.set_foo_bytes("moo");
+  EXPECT_TRUE(message.has_foo_bytes());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.set_foo_enum(UNITTEST::TestOneof2::FOO);
+  EXPECT_TRUE(message.has_foo_enum());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.mutable_foo_message()->set_moo_int(234);
+  EXPECT_TRUE(message.has_foo_message());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+  message.mutable_foogroup()->set_a(345);
+  EXPECT_TRUE(message.has_foogroup());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+
+
+  // we repeat this because we didn't test if this properly clears other fields
+  // at the beginning.
+  message.set_foo_int(123);
+  EXPECT_TRUE(message.has_foo_int());
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message);
+}
+
+TEST_F(OneofTest, EnumCases) {
+  UNITTEST::TestOneof2 message;
+
+  message.set_foo_int(123);
+  ExpectEnumCasesWork(message);
+  message.set_foo_string("foo");
+  ExpectEnumCasesWork(message);
+  message.set_foo_bytes("moo");
+  ExpectEnumCasesWork(message);
+  message.set_foo_enum(UNITTEST::TestOneof2::FOO);
+  ExpectEnumCasesWork(message);
+  message.mutable_foo_message()->set_moo_int(234);
+  ExpectEnumCasesWork(message);
+  message.mutable_foogroup()->set_a(345);
+  ExpectEnumCasesWork(message);
+}
+
+TEST_F(OneofTest, PrimitiveType) {
+  UNITTEST::TestOneof2 message;
+  // Unset field returns default value
+  EXPECT_EQ(message.foo_int(), 0);
+
+  message.set_foo_int(123);
+  EXPECT_TRUE(message.has_foo_int());
+  EXPECT_EQ(message.foo_int(), 123);
+  message.clear_foo_int();
+  EXPECT_FALSE(message.has_foo_int());
+}
+
+TEST_F(OneofTest, EnumType) {
+  UNITTEST::TestOneof2 message;
+  // Unset field returns default value
+  EXPECT_EQ(message.foo_enum(), 1);
+
+  message.set_foo_enum(UNITTEST::TestOneof2::FOO);
+  EXPECT_TRUE(message.has_foo_enum());
+  EXPECT_EQ(message.foo_enum(), UNITTEST::TestOneof2::FOO);
+  message.clear_foo_enum();
+  EXPECT_FALSE(message.has_foo_enum());
+}
+
+TEST_F(OneofTest, SetString) {
+  // Check that setting a string field in various ways works
+  UNITTEST::TestOneof2 message;
+
+  // Unset field returns default value
+  EXPECT_EQ(message.foo_string(), "");
+
+  message.set_foo_string("foo");
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "foo");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.set_foo_string(std::string("bar"));
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "bar");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+
+  message.set_foo_string("moo", 3);
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "moo");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.mutable_foo_string()->assign("mooo");
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "mooo");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.set_foo_string("corge");
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "corge");
+  message.clear_foo_string();
+  EXPECT_FALSE(message.has_foo_string());
+}
+
+TEST_F(OneofTest, ReleaseString) {
+  // Check that release_foo() starts out nullptr, and gives us a value
+  // that we can delete after it's been set.
+  UNITTEST::TestOneof2 message;
+
+  EXPECT_EQ(nullptr, message.release_foo_string());
+  EXPECT_FALSE(message.has_foo_string());
+
+  message.set_foo_string("blah");
+  EXPECT_TRUE(message.has_foo_string());
+  std::unique_ptr<std::string> str(message.release_foo_string());
+  EXPECT_FALSE(message.has_foo_string());
+  ASSERT_TRUE(str != nullptr);
+  EXPECT_EQ("blah", *str);
+
+  EXPECT_EQ(nullptr, message.release_foo_string());
+  EXPECT_FALSE(message.has_foo_string());
+}
+
+TEST_F(OneofTest, SetAllocatedString) {
+  // Check that set_allocated_foo() works for strings.
+  UNITTEST::TestOneof2 message;
+
+  EXPECT_FALSE(message.has_foo_string());
+  const std::string kHello("hello");
+  message.set_foo_string(kHello);
+  EXPECT_TRUE(message.has_foo_string());
+
+  message.set_allocated_foo_string(nullptr);
+  EXPECT_FALSE(message.has_foo_string());
+  EXPECT_EQ("", message.foo_string());
+
+  message.set_allocated_foo_string(new std::string(kHello));
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(kHello, message.foo_string());
+}
+
+TEST_F(OneofTest, ArenaSetAllocatedString) {
+  // Check that set_allocated_foo() works for strings.
+  Arena arena;
+  UNITTEST::TestOneof2* message =
+      Arena::CreateMessage<UNITTEST::TestOneof2>(&arena);
+
+  EXPECT_FALSE(message->has_foo_string());
+  const std::string kHello("hello");
+  message->set_foo_string(kHello);
+  EXPECT_TRUE(message->has_foo_string());
+
+  message->set_allocated_foo_string(nullptr);
+  EXPECT_FALSE(message->has_foo_string());
+  EXPECT_EQ("", message->foo_string());
+
+  message->set_allocated_foo_string(new std::string(kHello));
+  EXPECT_TRUE(message->has_foo_string());
+  EXPECT_EQ(kHello, message->foo_string());
+}
+
+
+TEST_F(OneofTest, SetMessage) {
+  // Check that setting a message field works
+  UNITTEST::TestOneof2 message;
+
+  // Unset field returns default instance
+  EXPECT_EQ(&message.foo_message(),
+            &UNITTEST::TestOneof2_NestedMessage::default_instance());
+  EXPECT_EQ(message.foo_message().moo_int(), 0);
+
+  message.mutable_foo_message()->set_moo_int(234);
+  EXPECT_TRUE(message.has_foo_message());
+  EXPECT_EQ(message.foo_message().moo_int(), 234);
+  message.clear_foo_message();
+  EXPECT_FALSE(message.has_foo_message());
+}
+
+TEST_F(OneofTest, ReleaseMessage) {
+  // Check that release_foo() starts out nullptr, and gives us a value
+  // that we can delete after it's been set.
+  UNITTEST::TestOneof2 message;
+
+  EXPECT_EQ(nullptr, message.release_foo_message());
+  EXPECT_FALSE(message.has_foo_message());
+
+  message.mutable_foo_message()->set_moo_int(1);
+  EXPECT_TRUE(message.has_foo_message());
+  std::unique_ptr<UNITTEST::TestOneof2_NestedMessage> mes(
+      message.release_foo_message());
+  EXPECT_FALSE(message.has_foo_message());
+  ASSERT_TRUE(mes != nullptr);
+  EXPECT_EQ(1, mes->moo_int());
+
+  EXPECT_EQ(nullptr, message.release_foo_message());
+  EXPECT_FALSE(message.has_foo_message());
+}
+
+TEST_F(OneofTest, SetAllocatedMessage) {
+  // Check that set_allocated_foo() works for messages.
+  UNITTEST::TestOneof2 message;
+
+  EXPECT_FALSE(message.has_foo_message());
+
+  message.mutable_foo_message()->set_moo_int(1);
+  EXPECT_TRUE(message.has_foo_message());
+
+  message.set_allocated_foo_message(nullptr);
+  EXPECT_FALSE(message.has_foo_message());
+  EXPECT_EQ(&message.foo_message(),
+            &UNITTEST::TestOneof2_NestedMessage::default_instance());
+
+  message.mutable_foo_message()->set_moo_int(1);
+  UNITTEST::TestOneof2_NestedMessage* mes = message.release_foo_message();
+  ASSERT_TRUE(mes != nullptr);
+  EXPECT_FALSE(message.has_foo_message());
+
+  message.set_allocated_foo_message(mes);
+  EXPECT_TRUE(message.has_foo_message());
+  EXPECT_EQ(1, message.foo_message().moo_int());
+}
+
+
+TEST_F(OneofTest, Clear) {
+  UNITTEST::TestOneof2 message;
+
+  message.set_foo_int(1);
+  EXPECT_TRUE(message.has_foo_int());
+  message.clear_foo_int();
+  EXPECT_FALSE(message.has_foo_int());
+}
+
+TEST_F(OneofTest, Defaults) {
+  UNITTEST::TestOneof2 message;
+
+  EXPECT_FALSE(message.has_foo_int());
+  EXPECT_EQ(message.foo_int(), 0);
+
+  EXPECT_FALSE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "");
+
+
+  EXPECT_FALSE(message.has_foo_bytes());
+  EXPECT_EQ(message.foo_bytes(), "");
+
+  EXPECT_FALSE(message.has_foo_enum());
+  EXPECT_EQ(message.foo_enum(), 1);
+
+  EXPECT_FALSE(message.has_foo_message());
+  EXPECT_EQ(message.foo_message().moo_int(), 0);
+
+  EXPECT_FALSE(message.has_foogroup());
+  EXPECT_EQ(message.foogroup().a(), 0);
+
+
+  EXPECT_FALSE(message.has_bar_int());
+  EXPECT_EQ(message.bar_int(), 5);
+
+  EXPECT_FALSE(message.has_bar_string());
+  EXPECT_EQ(message.bar_string(), "STRING");
+
+
+  EXPECT_FALSE(message.has_bar_bytes());
+  EXPECT_EQ(message.bar_bytes(), "BYTES");
+
+  EXPECT_FALSE(message.has_bar_enum());
+  EXPECT_EQ(message.bar_enum(), 2);
+}
+
+TEST_F(OneofTest, SwapWithEmpty) {
+  UNITTEST::TestOneof2 message1, message2;
+  message1.set_foo_string("FOO");
+  EXPECT_TRUE(message1.has_foo_string());
+  message1.Swap(&message2);
+  EXPECT_FALSE(message1.has_foo_string());
+  EXPECT_TRUE(message2.has_foo_string());
+  EXPECT_EQ(message2.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, SwapWithSelf) {
+  UNITTEST::TestOneof2 message;
+  message.set_foo_string("FOO");
+  EXPECT_TRUE(message.has_foo_string());
+  message.Swap(&message);
+  EXPECT_TRUE(message.has_foo_string());
+  EXPECT_EQ(message.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, SwapBothHasFields) {
+  UNITTEST::TestOneof2 message1, message2;
+
+  message1.set_foo_string("FOO");
+  EXPECT_TRUE(message1.has_foo_string());
+  message2.mutable_foo_message()->set_moo_int(1);
+  EXPECT_TRUE(message2.has_foo_message());
+
+  message1.Swap(&message2);
+  EXPECT_FALSE(message1.has_foo_string());
+  EXPECT_FALSE(message2.has_foo_message());
+  EXPECT_TRUE(message1.has_foo_message());
+  EXPECT_EQ(message1.foo_message().moo_int(), 1);
+  EXPECT_TRUE(message2.has_foo_string());
+  EXPECT_EQ(message2.foo_string(), "FOO");
+}
+
+TEST_F(OneofTest, CopyConstructor) {
+  UNITTEST::TestOneof2 message1;
+  message1.set_foo_bytes("FOO");
+
+  UNITTEST::TestOneof2 message2(message1);
+  EXPECT_TRUE(message2.has_foo_bytes());
+  EXPECT_EQ(message2.foo_bytes(), "FOO");
+}
+
+TEST_F(OneofTest, CopyFrom) {
+  UNITTEST::TestOneof2 message1, message2;
+  message1.set_foo_enum(UNITTEST::TestOneof2::BAR);
+  EXPECT_TRUE(message1.has_foo_enum());
+
+  message2.CopyFrom(message1);
+  EXPECT_TRUE(message2.has_foo_enum());
+  EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::BAR);
+
+  // Copying from self should be a no-op.
+  message2.CopyFrom(message2);
+  EXPECT_TRUE(message2.has_foo_enum());
+  EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::BAR);
+}
+
+TEST_F(OneofTest, CopyAssignmentOperator) {
+  UNITTEST::TestOneof2 message1;
+  message1.mutable_foo_message()->set_moo_int(123);
+  EXPECT_TRUE(message1.has_foo_message());
+
+  UNITTEST::TestOneof2 message2;
+  message2 = message1;
+  EXPECT_EQ(message2.foo_message().moo_int(), 123);
+
+  // Make sure that self-assignment does something sane.
+  message2 = *&message2;  // Avoid -Wself-assign.
+  EXPECT_EQ(message2.foo_message().moo_int(), 123);
+}
+
+TEST_F(OneofTest, UpcastCopyFrom) {
+  // Test the CopyFrom method that takes in the generic const Message&
+  // parameter.
+  UNITTEST::TestOneof2 message1, message2;
+  message1.mutable_foogroup()->set_a(123);
+  EXPECT_TRUE(message1.has_foogroup());
+
+  const Message* source = implicit_cast<const Message*>(&message1);
+  message2.CopyFrom(*source);
+
+  EXPECT_TRUE(message2.has_foogroup());
+  EXPECT_EQ(message2.foogroup().a(), 123);
+}
+
+// Test the generated SerializeWithCachedSizesToArray(),
+// This indirectly tests MergePartialFromCodedStream()
+// We have to test each field type separately because we cannot set them at the
+// same time
+TEST_F(OneofTest, SerializationToArray) {
+  // Primitive type
+  {
+    UNITTEST::TestOneof2 message1, message2;
+std::string data;
+message1.set_foo_int(123);
+int size = message1.ByteSizeLong();
+data.resize(size);
+uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+EXPECT_EQ(size, end - start);
+EXPECT_TRUE(message2.ParseFromString(data));
+EXPECT_EQ(message2.foo_int(), 123);
+  }
+
+  // String
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.set_foo_string("foo");
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+    uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+    uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_string(), "foo");
+  }
+
+
+  // Bytes
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.set_foo_bytes("moo");
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+    uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+    uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_bytes(), "moo");
+  }
+
+  // Enum
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.set_foo_enum(UNITTEST::TestOneof2::FOO);
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+    uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+    uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO);
+  }
+
+  // Message
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.mutable_foo_message()->set_moo_int(234);
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+    uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+    uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_message().moo_int(), 234);
+  }
+
+  // Group
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.mutable_foogroup()->set_a(345);
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+    uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+    uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foogroup().a(), 345);
+  }
+
+}
+
+// Test the generated SerializeWithCachedSizes() by forcing the buffer to write
+// one byte at a time.
+// This indirectly tests MergePartialFromCodedStream()
+// We have to test each field type separately because we cannot set them at the
+// same time
+TEST_F(OneofTest, SerializationToStream) {
+  // Primitive type
+  {
+    UNITTEST::TestOneof2 message1, message2;
+std::string data;
+message1.set_foo_int(123);
+int size = message1.ByteSizeLong();
+data.resize(size);
+
+{
+  // Allow the output stream to buffer only one byte at a time.
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+  io::CodedOutputStream output_stream(&array_stream);
+  message1.SerializeWithCachedSizes(&output_stream);
+  EXPECT_FALSE(output_stream.HadError());
+  EXPECT_EQ(size, output_stream.ByteCount());
+}
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_int(), 123);
+  }
+
+  // String
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.set_foo_string("foo");
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_string(), "foo");
+  }
+
+
+  // Bytes
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.set_foo_bytes("moo");
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_bytes(), "moo");
+  }
+
+  // Enum
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.set_foo_enum(UNITTEST::TestOneof2::FOO);
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO);
+  }
+
+  // Message
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.mutable_foo_message()->set_moo_int(234);
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foo_message().moo_int(), 234);
+  }
+
+  // Group
+  {
+    UNITTEST::TestOneof2 message1, message2;
+    std::string data;
+    message1.mutable_foogroup()->set_a(345);
+    int size = message1.ByteSizeLong();
+    data.resize(size);
+
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+
+    EXPECT_TRUE(message2.ParseFromString(data));
+    EXPECT_EQ(message2.foogroup().a(), 345);
+  }
+
+}
+
+TEST_F(OneofTest, MergeFrom) {
+  UNITTEST::TestOneof2 message1, message2;
+
+  message1.set_foo_int(123);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_int());
+  EXPECT_EQ(message2.foo_int(), 123);
+
+  message1.set_foo_string("foo");
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_string());
+  EXPECT_EQ(message2.foo_string(), "foo");
+
+
+  message1.set_foo_bytes("moo");
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_bytes());
+  EXPECT_EQ(message2.foo_bytes(), "moo");
+
+  message1.set_foo_enum(UNITTEST::TestOneof2::FOO);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_enum());
+  EXPECT_EQ(message2.foo_enum(), UNITTEST::TestOneof2::FOO);
+
+  message1.mutable_foo_message()->set_moo_int(234);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foo_message());
+  EXPECT_EQ(message2.foo_message().moo_int(), 234);
+
+  message1.mutable_foogroup()->set_a(345);
+  message2.MergeFrom(message1);
+  TestUtil::ExpectAtMostOneFieldSetInOneof(message2);
+  EXPECT_TRUE(message2.has_foogroup());
+  EXPECT_EQ(message2.foogroup().a(), 345);
+
+}
+
+TEST(HELPERS_TEST_NAME, TestSCC) {
+  UNITTEST::TestMutualRecursionA a;
+  MessageSCCAnalyzer scc_analyzer((Options()));
+  const SCC* scc = scc_analyzer.GetSCC(a.GetDescriptor());
+  std::vector<std::string> names;
+  names.reserve(scc->descriptors.size());
+  for (int i = 0; i < scc->descriptors.size(); i++) {
+    names.push_back(scc->descriptors[i]->full_name());
+  }
+  std::string package = a.GetDescriptor()->file()->package();
+  ASSERT_EQ(names.size(), 4);
+  std::sort(names.begin(), names.end());
+  EXPECT_EQ(names[0], package + ".TestMutualRecursionA");
+  EXPECT_EQ(names[1], package + ".TestMutualRecursionA.SubGroup");
+  EXPECT_EQ(names[2], package + ".TestMutualRecursionA.SubMessage");
+  EXPECT_EQ(names[3], package + ".TestMutualRecursionB");
+
+  MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+  EXPECT_EQ(result.is_recursive, true);
+  EXPECT_EQ(result.contains_required, false);
+  EXPECT_EQ(result.contains_cord, true);  // TestAllTypes
+  EXPECT_EQ(result.contains_extension, false);  // TestAllTypes
+}
+
+TEST(HELPERS_TEST_NAME, TestSCCAnalysis) {
+  {
+    UNITTEST::TestRecursiveMessage msg;
+    MessageSCCAnalyzer scc_analyzer((Options()));
+    const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor());
+    MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+    EXPECT_EQ(result.is_recursive, true);
+    EXPECT_EQ(result.contains_required, false);
+    EXPECT_EQ(result.contains_cord, false);
+    EXPECT_EQ(result.contains_extension, false);
+  }
+  {
+    UNITTEST::TestAllExtensions msg;
+    MessageSCCAnalyzer scc_analyzer((Options()));
+    const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor());
+    MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+    EXPECT_EQ(result.is_recursive, false);
+    EXPECT_EQ(result.contains_required, false);
+    EXPECT_EQ(result.contains_cord, false);
+    EXPECT_EQ(result.contains_extension, true);
+  }
+  {
+    UNITTEST::TestRequired msg;
+    MessageSCCAnalyzer scc_analyzer((Options()));
+    const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor());
+    MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+    EXPECT_EQ(result.is_recursive, false);
+    EXPECT_EQ(result.contains_required, true);
+    EXPECT_EQ(result.contains_cord, false);
+    EXPECT_EQ(result.contains_extension, false);
+  }
+}
+
+}  // namespace cpp_unittest
+}  // namespace cpp
+}  // namespace compiler
+
+namespace no_generic_services_test {
+  // Verify that no class called "TestService" was defined in
+  // unittest_no_generic_services.pb.h by defining a different type by the same
+  // name.  If such a service was generated, this will not compile.
+  struct TestService {
+    int i;
+  };
+}
+
+namespace compiler {
+namespace cpp {
+namespace cpp_unittest {
+
+TEST_F(GENERATED_SERVICE_TEST_NAME, NoGenericServices) {
+  // Verify that non-services in unittest_no_generic_services.proto were
+  // generated.
+  ::protobuf_unittest::no_generic_services_test::TestMessage message;
+  message.set_a(1);
+  message.SetExtension(
+      ::protobuf_unittest::no_generic_services_test::test_extension, 123);
+  ::protobuf_unittest::no_generic_services_test::TestEnum e =
+      ::protobuf_unittest::no_generic_services_test::FOO;
+  EXPECT_EQ(e, 1);
+
+  // Verify that a ServiceDescriptor is generated for the service even if the
+  // class itself is not.
+  const FileDescriptor* file =
+      ::google::protobuf::unittest::no_generic_services_test::TestMessage::descriptor()
+          ->file();
+
+  ASSERT_EQ(1, file->service_count());
+  EXPECT_EQ("TestService", file->service(0)->name());
+  ASSERT_EQ(1, file->service(0)->method_count());
+  EXPECT_EQ("Foo", file->service(0)->method(0)->name());
+}
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+// ===================================================================
+
+// This test must run last.  It verifies that descriptors were or were not
+// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined.
+// When this is defined, we skip all tests which are expected to trigger
+// descriptor initialization.  This verifies that everything else still works
+// if descriptors are not initialized.
+TEST(DESCRIPTOR_INIT_TEST_NAME, Initialized) {
+#ifdef PROTOBUF_TEST_NO_DESCRIPTORS
+  bool should_have_descriptors = false;
+#else
+  bool should_have_descriptors = true;
+#endif
+
+  EXPECT_EQ(should_have_descriptors,
+            DescriptorPool::generated_pool()->InternalIsFileLoaded(
+                TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH)));
+}
+
+}  // namespace cpp_unittest
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
new file mode 100644
index 0000000..84aacca
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
@@ -0,0 +1,195 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This test insures that
+// csharp/src/Google.Protobuf/Reflection/Descriptor.cs  match exactly
+// what would be generated by the protocol compiler.  The file is not
+// generated automatically at build time.
+//
+// If this test fails, run the script
+// "generate_descriptor_proto.sh" and add the changed files under
+// csharp/src/ to your changelist.
+
+#include <map>
+
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+namespace {
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() {}
+
+  std::string text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const std::string& filename, int line, int column,
+                const std::string& message) {
+    strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
+                                 filename, line, column, message);
+  }
+};
+
+class MockGeneratorContext : public GeneratorContext {
+ public:
+  void ExpectFileMatches(const std::string& virtual_filename,
+                         const std::string& physical_filename) {
+    auto it = files_.find(virtual_filename);
+    ASSERT_TRUE(it != files_.end())
+      << "Generator failed to generate file: " << virtual_filename;
+    std::string expected_contents = *it->second;
+
+    std::string actual_contents;
+    GOOGLE_CHECK_OK(
+        File::GetContentsAsText(TestSourceDir() + "/" + physical_filename,
+                          &actual_contents, true))
+        << "Unable to get " << physical_filename;
+    EXPECT_TRUE(actual_contents == expected_contents)
+      << physical_filename << " needs to be regenerated.  Please run "
+         "generate_descriptor_proto.sh. Then add this file "
+         "to your CL.";
+  }
+
+  // implements GeneratorContext --------------------------------------
+
+  virtual io::ZeroCopyOutputStream* Open(const std::string& filename) {
+    auto& map_slot = files_[filename];
+    map_slot.reset(new std::string);
+    return new io::StringOutputStream(map_slot.get());
+  }
+
+ private:
+  std::map<std::string, std::unique_ptr<std::string>> files_;
+};
+
+class GenerateAndTest {
+ public:
+  GenerateAndTest() {}
+  void Run(const FileDescriptor* proto_file, std::string file1,
+           std::string file2) {
+    ASSERT_TRUE(proto_file != NULL) << TestSourceDir();
+    ASSERT_TRUE(generator_.Generate(proto_file, parameter_,
+                                    &context_, &error_));
+    context_.ExpectFileMatches(file1, file2);
+  }
+  void SetParameter(std::string parameter) {
+    parameter_ = parameter;
+  }
+
+ private:
+  Generator generator_;
+  MockGeneratorContext context_;
+  std::string error_;
+  std::string parameter_;
+};
+
+TEST(CsharpBootstrapTest, GeneratedCsharpDescriptorMatches) {
+  // Skip this whole test if the csharp directory doesn't exist (i.e., a C++11
+  // only distribution).
+  std::string descriptor_file_name =
+      "../csharp/src/Google.Protobuf/Reflection/Descriptor.cs";
+  if (!File::Exists(TestSourceDir() + "/" + descriptor_file_name)) {
+    return;
+  }
+
+  MockErrorCollector error_collector;
+  DiskSourceTree source_tree;
+  Importer importer(&source_tree, &error_collector);
+  GenerateAndTest generate_test;
+
+  generate_test.SetParameter("base_namespace=Google.Protobuf");
+  source_tree.MapPath("", TestSourceDir());
+  generate_test.Run(importer.Import("google/protobuf/descriptor.proto"),
+                    "Reflection/Descriptor.cs",
+                    "../csharp/src/Google.Protobuf/Reflection/Descriptor.cs");
+  generate_test.Run(importer.Import("google/protobuf/any.proto"),
+                    "WellKnownTypes/Any.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Any.cs");
+  generate_test.Run(importer.Import("google/protobuf/api.proto"),
+                    "WellKnownTypes/Api.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Api.cs");
+  generate_test.Run(importer.Import("google/protobuf/duration.proto"),
+                    "WellKnownTypes/Duration.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs");
+  generate_test.Run(importer.Import("google/protobuf/empty.proto"),
+                    "WellKnownTypes/Empty.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs");
+  generate_test.Run(importer.Import("google/protobuf/field_mask.proto"),
+                    "WellKnownTypes/FieldMask.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs");
+  generate_test.Run(importer.Import("google/protobuf/source_context.proto"),
+                    "WellKnownTypes/SourceContext.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs");
+  generate_test.Run(importer.Import("google/protobuf/struct.proto"),
+                    "WellKnownTypes/Struct.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs");
+  generate_test.Run(importer.Import("google/protobuf/timestamp.proto"),
+                    "WellKnownTypes/Timestamp.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs");
+  generate_test.Run(importer.Import("google/protobuf/type.proto"),
+                    "WellKnownTypes/Type.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Type.cs");
+  generate_test.Run(importer.Import("google/protobuf/wrappers.proto"),
+                    "WellKnownTypes/Wrappers.cs",
+                    "../csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs");
+
+  generate_test.SetParameter("");
+  source_tree.MapPath("", TestSourceDir() + "/../conformance");
+  generate_test.Run(importer.Import("conformance.proto"),
+                    "Conformance.cs",
+                    "../csharp/src/Google.Protobuf.Conformance/Conformance.cs");
+
+  EXPECT_EQ("", error_collector.text_);
+}
+
+}  // namespace
+
+}  // namespace csharp
+}  // 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..225d6dc
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
@@ -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.
+
+// 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) {
+    std::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);
+    std::vector<std::string> lines;
+    lines = Split(comments, "\n", false);
+    // 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<std::string>::iterator it = lines.begin();
+         it != lines.end(); ++it) {
+      std::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..73679ca
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) :
+    SourceGeneratorBase(options),
+    descriptor_(descriptor) {
+}
+
+EnumGenerator::~EnumGenerator() {
+}
+
+void EnumGenerator::Generate(io::Printer* printer) {
+  WriteEnumDocComment(printer, descriptor_);
+  printer->Print("$access_level$ enum $name$ {\n",
+                 "access_level", class_access_level(),
+                 "name", descriptor_->name());
+  printer->Indent();
+  std::set<std::string> used_names;
+  std::set<int> used_number;
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+      WriteEnumValueDocComment(printer, descriptor_->value(i));
+      std::string original_name = descriptor_->value(i)->name();
+      std::string name =
+          GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name());
+      // Make sure we don't get any duplicate names due to prefix removal.
+      while (!used_names.insert(name).second) {
+        // It's possible we'll end up giving this warning multiple times, but that's better than not at all.
+        GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name
+          << ") in " << descriptor_->name() << "; adding underscore to distinguish";
+        name += "_";
+      }
+      int number = descriptor_->value(i)->number();
+      if (!used_number.insert(number).second) {
+          printer->Print("[pbr::OriginalName(\"$original_name$\", PreferredAlias = false)] $name$ = $number$,\n",
+             "original_name", original_name,
+             "name", name,
+             "number", StrCat(number));
+      } else {
+          printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n",
+             "original_name", original_name,
+             "name", name,
+             "number", StrCat(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..e409c2e
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.h
@@ -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.
+
+#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>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class EnumGenerator : public SourceGeneratorBase {
+ public:
+  EnumGenerator(const EnumDescriptor* descriptor, const Options* options);
+  ~EnumGenerator();
+
+  EnumGenerator(const EnumGenerator&) = delete;
+  EnumGenerator& operator=(const EnumGenerator&) = delete;
+
+  void Generate(io::Printer* printer);
+
+ private:
+  const EnumDescriptor* descriptor_;
+};
+
+}  // 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..55fb60c
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
@@ -0,0 +1,135 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       int presenceIndex, const Options *options)
+    : PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {
+}
+
+void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$property_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, $default_value$)");
+}
+
+void EnumFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::Extension<$extended_type$, $type_name$>($number$, ");
+  GenerateCodecCode(printer);
+  printer->Print(");\n");
+}
+
+EnumOneofFieldGenerator::EnumOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
+  : PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options) {
+}
+
+EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
+}
+
+void EnumOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
+}
+
+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.$oneof_case_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..0c6b023
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+
+#include <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 presenceIndex,
+                     const Options *options);
+  ~EnumFieldGenerator();
+
+  EnumFieldGenerator(const EnumFieldGenerator&) = delete;
+  EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete;
+
+  virtual void GenerateCodecCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+};
+
+class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
+ public:
+  EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                          int presenceIndex,
+                          const Options *options);
+  ~EnumOneofFieldGenerator();
+
+  EnumOneofFieldGenerator(const EnumOneofFieldGenerator&) = delete;
+  EnumOneofFieldGenerator& operator=(const EnumOneofFieldGenerator&) = delete;
+
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+};
+
+}  // 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..17847e3
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -0,0 +1,464 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cmath>
+#include <limits>
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.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/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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+void FieldGeneratorBase::SetCommonFieldVariables(
+    std::map<std::string, std::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());
+  int part_tag_size = tag_size;
+  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+    part_tag_size /= 2;
+  }
+  uint tag = internal::WireFormat::MakeTag(descriptor_);
+  uint8_t tag_array[5];
+  io::CodedOutputStream::WriteTagToArray(tag, tag_array);
+  std::string tag_bytes = StrCat(tag_array[0]);
+  for (int i = 1; i < part_tag_size; i++) {
+    tag_bytes += ", " + StrCat(tag_array[i]);
+  }
+
+  (*variables)["tag"] = StrCat(tag);
+  (*variables)["tag_size"] = StrCat(tag_size);
+  (*variables)["tag_bytes"] = tag_bytes;
+
+  if (descriptor_->type() == FieldDescriptor::Type::TYPE_GROUP) {
+    tag = internal::WireFormatLite::MakeTag(
+        descriptor_->number(),
+        internal::WireFormatLite::WIRETYPE_END_GROUP);
+    io::CodedOutputStream::WriteTagToArray(tag, tag_array);
+    tag_bytes = StrCat(tag_array[0]);
+    for (int i = 1; i < part_tag_size; i++) {
+        tag_bytes += ", " + StrCat(tag_array[i]);
+    }
+
+    variables_["end_tag"] = StrCat(tag);
+    variables_["end_tag_bytes"] = tag_bytes;
+  }
+
+  (*variables)["access_level"] = "public";
+
+  (*variables)["property_name"] = property_name();
+  (*variables)["type_name"] = type_name();
+  (*variables)["extended_type"] = GetClassName(descriptor_->containing_type());
+  (*variables)["name"] = name();
+  (*variables)["descriptor_name"] = descriptor_->name();
+  (*variables)["default_value"] = default_value();
+  (*variables)["capitalized_type_name"] = capitalized_type_name();
+  (*variables)["number"] = number();
+  if (has_default_value() && !SupportsPresenceApi(descriptor_)) {
+    (*variables)["name_def_message"] =
+      (*variables)["name"] + "_ = " + (*variables)["default_value"];
+  } else {
+    (*variables)["name_def_message"] = (*variables)["name"] + "_";
+  }
+  if (SupportsPresenceApi(descriptor_)) {
+    (*variables)["has_property_check"] = "Has" + (*variables)["property_name"];
+    (*variables)["other_has_property_check"] = "other.Has" + (*variables)["property_name"];
+    (*variables)["has_not_property_check"] = "!" + (*variables)["has_property_check"];
+    (*variables)["other_has_not_property_check"] = "!" + (*variables)["other_has_property_check"];
+    if (presenceIndex_ != -1) {
+      std::string hasBitsNumber = StrCat(presenceIndex_ / 32);
+      std::string hasBitsMask = StrCat(1 << (presenceIndex_ % 32));
+      (*variables)["has_field_check"] = "(_hasBits" + hasBitsNumber + " & " + hasBitsMask + ") != 0";
+      (*variables)["set_has_field"] = "_hasBits" + hasBitsNumber + " |= " + hasBitsMask;
+      (*variables)["clear_has_field"] = "_hasBits" + hasBitsNumber + " &= ~" + hasBitsMask;
+    }
+  } else {
+    (*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(
+    std::map<std::string, std::string>* variables) {
+  (*variables)["oneof_name"] = oneof_name();
+  if (SupportsPresenceApi(descriptor_)) {
+    (*variables)["has_property_check"] = "Has" + property_name();
+  } else {
+    (*variables)["has_property_check"] =
+      oneof_name() + "Case_ == " + oneof_property_name() +
+      "OneofCase." + oneof_case_name();
+  }
+  (*variables)["oneof_case_name"] = oneof_case_name();
+  (*variables)["oneof_property_name"] = oneof_property_name();
+}
+
+FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
+                                       int presenceIndex, const Options* options)
+    : SourceGeneratorBase(options),
+      descriptor_(descriptor),
+      presenceIndex_(presenceIndex) {
+  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::GenerateExtensionCode(io::Printer* printer) {
+  // No-op: only message fields, enum fields, primitives, 
+  // and repeated fields need this default is to not generate any code
+}
+
+void FieldGeneratorBase::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  // for some field types the value of "use_parse_context" doesn't matter,
+  // so we fallback to the default implementation.
+  GenerateParsingCode(printer);
+}
+
+void FieldGeneratorBase::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  // for some field types the value of "use_write_context" doesn't matter,
+  // so we fallback to the default implementation.
+  GenerateSerializationCode(printer);
+}
+
+void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
+  if (descriptor_->options().deprecated()) {
+    printer->Print("[global::System.ObsoleteAttribute]\n");
+  } else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE &&
+           descriptor_->message_type()->options().deprecated()) {
+    printer->Print("[global::System.ObsoleteAttribute]\n");
+  }
+}
+
+void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
+  AddDeprecatedFlag(printer);
+  WriteGeneratedCodeAttributes(printer);
+}
+
+std::string FieldGeneratorBase::oneof_case_name() {
+  return GetOneofCaseName(descriptor_);
+}
+
+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);
+        std::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 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(const FieldDescriptor* descriptor) {
+    if (descriptor->default_value_string().empty())
+        return "\"\"";
+    else
+      return "global::System.Text.Encoding.UTF8.GetString(global::System."
+             "Convert.FromBase64String(\"" +
+             StringToBase64(descriptor->default_value_string()) + "\"), 0, " + StrCat(descriptor->default_value_string().length()) + ")";
+}
+
+std::string FieldGeneratorBase::GetBytesDefaultValueInternal(const FieldDescriptor* descriptor) {
+    if (descriptor->default_value_string().empty())
+        return "pb::ByteString.Empty";
+    else
+        return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor->default_value_string()) + "\")";
+}
+
+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 GetClassName(descriptor->default_value_enum()->type()) + "." +
+        GetEnumValueName(descriptor->default_value_enum()->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 == std::numeric_limits<double>::infinity()) {
+        return "double.PositiveInfinity";
+      } else if (value == -std::numeric_limits<double>::infinity()) {
+        return "double.NegativeInfinity";
+      } else if (std::isnan(value)) {
+        return "double.NaN";
+      }
+      return StrCat(value) + "D";
+    }
+    case FieldDescriptor::TYPE_FLOAT: {
+      float value = descriptor->default_value_float();
+      if (value == std::numeric_limits<float>::infinity()) {
+        return "float.PositiveInfinity";
+      } else if (value == -std::numeric_limits<float>::infinity()) {
+        return "float.NegativeInfinity";
+      } else if (std::isnan(value)) {
+        return "float.NaN";
+      }
+      return StrCat(value) + "F";
+    }
+    case FieldDescriptor::TYPE_INT64:
+      return StrCat(descriptor->default_value_int64()) + "L";
+    case FieldDescriptor::TYPE_UINT64:
+      return StrCat(descriptor->default_value_uint64()) + "UL";
+    case FieldDescriptor::TYPE_INT32:
+      return StrCat(descriptor->default_value_int32());
+    case FieldDescriptor::TYPE_FIXED64:
+      return StrCat(descriptor->default_value_uint64()) + "UL";
+    case FieldDescriptor::TYPE_FIXED32:
+      return StrCat(descriptor->default_value_uint32());
+    case FieldDescriptor::TYPE_BOOL:
+      if (descriptor->default_value_bool()) {
+        return "true";
+      } else {
+        return "false";
+      }
+    case FieldDescriptor::TYPE_STRING:
+      return GetStringDefaultValueInternal(descriptor);
+    case FieldDescriptor::TYPE_BYTES:
+      return GetBytesDefaultValueInternal(descriptor);
+    case FieldDescriptor::TYPE_UINT32:
+      return StrCat(descriptor->default_value_uint32());
+    case FieldDescriptor::TYPE_SFIXED32:
+      return StrCat(descriptor->default_value_int32());
+    case FieldDescriptor::TYPE_SFIXED64:
+      return StrCat(descriptor->default_value_int64()) + "L";
+    case FieldDescriptor::TYPE_SINT32:
+      return StrCat(descriptor->default_value_int32());
+    case FieldDescriptor::TYPE_SINT64:
+      return StrCat(descriptor->default_value_int64()) + "L";
+    default:
+      GOOGLE_LOG(FATAL)<< "Unknown field type.";
+      return "";
+  }
+}
+
+std::string FieldGeneratorBase::number() {
+  return StrCat(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..c7b7469
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h
@@ -0,0 +1,112 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase : public SourceGeneratorBase {
+ public:
+  FieldGeneratorBase(const FieldDescriptor* descriptor,
+                     int presenceIndex,
+                     const Options* options);
+  ~FieldGeneratorBase();
+
+  FieldGeneratorBase(const FieldGeneratorBase&) = delete;
+  FieldGeneratorBase& operator=(const FieldGeneratorBase&) = delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) = 0;
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateCodecCode(io::Printer* printer);
+  virtual void GenerateExtensionCode(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 GenerateParsingCode(io::Printer* printer, bool use_parse_context);
+  virtual void GenerateSerializationCode(io::Printer* printer) = 0;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context);
+  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 presenceIndex_;
+  std::map<std::string, std::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(
+      std::map<std::string, std::string>* variables);
+
+  std::string oneof_property_name();
+  std::string oneof_case_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();
+  std::string default_value();
+  std::string default_value(const FieldDescriptor* descriptor);
+  std::string number();
+  std::string capitalized_type_name();
+
+ private:
+  void SetCommonFieldVariables(std::map<std::string, std::string>* variables);
+  std::string GetStringDefaultValueInternal(const FieldDescriptor* descriptor);
+  std::string GetBytesDefaultValueInternal(const FieldDescriptor* descriptor);
+};
+
+}  // 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..5ce0651
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -0,0 +1,112 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+Generator::Generator() {}
+Generator::~Generator() {}
+
+uint64_t Generator::GetSupportedFeatures() const {
+  return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
+}
+
+void GenerateFile(const FileDescriptor* file, io::Printer* printer,
+                  const Options* options) {
+  ReflectionClassGenerator reflectionClassGenerator(file, options);
+  reflectionClassGenerator.Generate(printer);
+}
+
+bool Generator::Generate(const FileDescriptor* file,
+                         const std::string& parameter,
+                         GeneratorContext* generator_context,
+                         std::string* error) const {
+  std::vector<std::pair<std::string, std::string> > options;
+  ParseGeneratorParameter(parameter, &options);
+
+  struct Options cli_options;
+
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "file_extension") {
+      cli_options.file_extension = options[i].second;
+    } else if (options[i].first == "base_namespace") {
+      cli_options.base_namespace = options[i].second;
+      cli_options.base_namespace_specified = true;
+    } else if (options[i].first == "internal_access") {
+      cli_options.internal_access = true;
+    } else if (options[i].first == "serializable") {
+      cli_options.serializable = true;
+    } else {
+      *error = "Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  std::string filename_error = "";
+  std::string filename = GetOutputFile(file,
+      cli_options.file_extension,
+      cli_options.base_namespace_specified,
+      cli_options.base_namespace,
+      &filename_error);
+
+  if (filename.empty()) {
+    *error = filename_error;
+    return false;
+  }
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '$');
+
+  GenerateFile(file, &printer, &cli_options);
+
+  return true;
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.h b/src/google/protobuf/compiler/csharp/csharp_generator.h
new file mode 100644
index 0000000..f41f9b8
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Generates C# code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// CodeGenerator implementation which generates a C# source file and
+// header.  If you create your own protocol compiler binary and you want
+// it to support C# output, you can do so by registering an instance of this
+// CodeGenerator with the CommandLineInterface in your main() function.
+class PROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+  Generator();
+  ~Generator();
+  bool Generate(
+    const FileDescriptor* file,
+    const std::string& parameter,
+    GeneratorContext* generator_context,
+    std::string* error) const override;
+  uint64_t GetSupportedFeatures() const override;
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..e21eff1
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
@@ -0,0 +1,81 @@
+// 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/any.pb.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+namespace {
+
+TEST(CSharpEnumValue, PascalCasedPrefixStripping) {
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR"));
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz"));
+  EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR"));
+  EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR"));
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
+  EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO"));
+  EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___"));
+  // Identifiers can't start with digits
+  EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR"));
+  EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2"));
+}
+
+TEST(DescriptorProtoHelpers, IsDescriptorProto) {
+  EXPECT_TRUE(IsDescriptorProto(DescriptorProto::descriptor()->file()));
+  EXPECT_FALSE(IsDescriptorProto(google::protobuf::Any::descriptor()->file()));
+}
+
+TEST(DescriptorProtoHelpers, IsDescriptorOptionMessage) {
+  EXPECT_TRUE(IsDescriptorOptionMessage(FileOptions::descriptor()));
+  EXPECT_FALSE(IsDescriptorOptionMessage(google::protobuf::Any::descriptor()));
+  EXPECT_FALSE(IsDescriptorOptionMessage(DescriptorProto::descriptor()));
+}
+
+}  // 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..73ca868
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -0,0 +1,599 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <limits>
+#include <vector>
+#include <sstream>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.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/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
+#include <google/protobuf/compiler/csharp/csharp_map_field.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+CSharpType GetCSharpType(FieldDescriptor::Type type) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT32:
+      return CSHARPTYPE_INT32;
+    case FieldDescriptor::TYPE_INT64:
+      return CSHARPTYPE_INT64;
+    case FieldDescriptor::TYPE_UINT32:
+      return CSHARPTYPE_UINT32;
+    case FieldDescriptor::TYPE_UINT64:
+      return CSHARPTYPE_UINT32;
+    case FieldDescriptor::TYPE_SINT32:
+      return CSHARPTYPE_INT32;
+    case FieldDescriptor::TYPE_SINT64:
+      return CSHARPTYPE_INT64;
+    case FieldDescriptor::TYPE_FIXED32:
+      return CSHARPTYPE_UINT32;
+    case FieldDescriptor::TYPE_FIXED64:
+      return CSHARPTYPE_UINT64;
+    case FieldDescriptor::TYPE_SFIXED32:
+      return CSHARPTYPE_INT32;
+    case FieldDescriptor::TYPE_SFIXED64:
+      return CSHARPTYPE_INT64;
+    case FieldDescriptor::TYPE_FLOAT:
+      return CSHARPTYPE_FLOAT;
+    case FieldDescriptor::TYPE_DOUBLE:
+      return CSHARPTYPE_DOUBLE;
+    case FieldDescriptor::TYPE_BOOL:
+      return CSHARPTYPE_BOOL;
+    case FieldDescriptor::TYPE_ENUM:
+      return CSHARPTYPE_ENUM;
+    case FieldDescriptor::TYPE_STRING:
+      return CSHARPTYPE_STRING;
+    case FieldDescriptor::TYPE_BYTES:
+      return CSHARPTYPE_BYTESTRING;
+    case FieldDescriptor::TYPE_GROUP:
+      return CSHARPTYPE_MESSAGE;
+    case FieldDescriptor::TYPE_MESSAGE:
+      return CSHARPTYPE_MESSAGE;
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  return (CSharpType) -1;
+}
+
+std::string StripDotProto(const std::string& proto_file) {
+  int lastindex = proto_file.find_last_of(".");
+  return proto_file.substr(0, lastindex);
+}
+
+std::string GetFileNamespace(const FileDescriptor* descriptor) {
+  if (descriptor->options().has_csharp_namespace()) {
+    return descriptor->options().csharp_namespace();
+  }
+  return UnderscoresToCamelCase(descriptor->package(), true, true);
+}
+
+// Returns the Pascal-cased last part of the proto file. For example,
+// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
+std::string GetFileNameBase(const FileDescriptor* descriptor) {
+    std::string proto_file = descriptor->name();
+    int lastslash = proto_file.find_last_of("/");
+    std::string base = proto_file.substr(lastslash + 1);
+    return UnderscoresToPascalCase(StripDotProto(base));
+}
+
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
+  // TODO: Detect collisions with existing messages,
+  // and append an underscore if necessary.
+  return GetFileNameBase(descriptor) + "Reflection";
+}
+
+std::string GetExtensionClassUnqualifiedName(const FileDescriptor* descriptor) {
+  // TODO: Detect collisions with existing messages,
+  // and append an underscore if necessary.
+  return GetFileNameBase(descriptor) + "Extensions";
+}
+
+// TODO(jtattermusch): can we reuse a utility function?
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter,
+                                   bool preserve_period) {
+  std::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.size() > 0 && input[input.size() - 1] == '#') {
+    result += '_';
+  }
+  return result;
+}
+
+std::string UnderscoresToPascalCase(const std::string& input) {
+  return UnderscoresToCamelCase(input, true);
+}
+
+// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty)
+// into a PascalCase string. Precise rules implemented:
+
+// Previous input character      Current character         Case
+// Any                           Non-alphanumeric          Skipped
+// None - first char of input    Alphanumeric              Upper
+// Non-letter (e.g. _ or 1)      Alphanumeric              Upper
+// Numeric                       Alphanumeric              Upper
+// Lower letter                  Alphanumeric              Same as current
+// Upper letter                  Alphanumeric              Lower
+std::string ShoutyToPascalCase(const std::string& input) {
+  std::string result;
+  // Simple way of implementing "always start with upper"
+  char previous = '_';
+  for (int i = 0; i < input.size(); i++) {
+    char current = input[i];
+    if (!ascii_isalnum(current)) {
+      previous = current;
+      continue;
+    }
+    if (!ascii_isalnum(previous)) {
+      result += ascii_toupper(current);
+    } else if (ascii_isdigit(previous)) {
+      result += ascii_toupper(current);
+    } else if (ascii_islower(previous)) {
+      result += current;
+    } else {
+      result += ascii_tolower(current);
+    }
+    previous = current;
+  }
+  return result;
+}
+
+// Attempt to remove a prefix from a value, ignoring casing and skipping underscores.
+// (foo, foo_bar) => bar - underscore after prefix is skipped
+// (FOO, foo_bar) => bar - casing is ignored
+// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored
+// (foobar, foo_barbaz) => baz - underscore in value is ignored
+// (foo, bar) => bar - prefix isn't matched; return original value
+std::string TryRemovePrefix(const std::string& prefix, const std::string& value) {
+  // First normalize to a lower-case no-underscores prefix to match against
+  std::string prefix_to_match = "";
+  for (size_t i = 0; i < prefix.size(); i++) {
+    if (prefix[i] != '_') {
+      prefix_to_match += ascii_tolower(prefix[i]);
+    }
+  }
+
+  // This keeps track of how much of value we've consumed
+  size_t prefix_index, value_index;
+  for (prefix_index = 0, value_index = 0;
+      prefix_index < prefix_to_match.size() && value_index < value.size();
+      value_index++) {
+    // Skip over underscores in the value
+    if (value[value_index] == '_') {
+      continue;
+    }
+    if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) {
+      // Failed to match the prefix - bail out early.
+      return value;
+    }
+  }
+
+  // If we didn't finish looking through the prefix, we can't strip it.
+  if (prefix_index < prefix_to_match.size()) {
+    return value;
+  }
+
+  // Step over any underscores after the prefix
+  while (value_index < value.size() && value[value_index] == '_') {
+    value_index++;
+  }
+
+  // If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip.
+  if (value_index == value.size()) {
+    return value;
+  }
+
+  return value.substr(value_index);
+}
+
+// Format the enum value name in a pleasant way for C#:
+// - Strip the enum name as a prefix if possible
+// - Convert to PascalCase.
+// For example, an enum called Color with a value of COLOR_BLUE should
+// result in an enum value in C# called just Blue
+std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) {
+  std::string stripped = TryRemovePrefix(enum_name, enum_value_name);
+  std::string result = ShoutyToPascalCase(stripped);
+  // Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned
+  // string is a valid identifier.
+  if (ascii_isdigit(result[0])) {
+    result = "_" + result;
+  }
+  return result;
+}
+
+uint GetGroupEndTag(const Descriptor* descriptor) {
+  const Descriptor* containing_type = descriptor->containing_type();
+  if (containing_type != NULL) {
+    const FieldDescriptor* field;
+    for (int i = 0; i < containing_type->field_count(); i++) {
+      field = containing_type->field(i);
+      if (field->type() == FieldDescriptor::Type::TYPE_GROUP &&
+          field->message_type() == descriptor) {
+        return internal::WireFormatLite::MakeTag(
+            field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP);
+      }
+    }
+    for (int i = 0; i < containing_type->extension_count(); i++) {
+      field = containing_type->extension(i);
+      if (field->type() == FieldDescriptor::Type::TYPE_GROUP &&
+          field->message_type() == descriptor) {
+        return internal::WireFormatLite::MakeTag(
+            field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP);
+      }
+    }
+  } else {
+    const FileDescriptor* containing_file = descriptor->file();
+    if (containing_file != NULL) {
+      const FieldDescriptor* field;
+      for (int i = 0; i < containing_file->extension_count(); i++) {
+        field = containing_file->extension(i);
+        if (field->type() == FieldDescriptor::Type::TYPE_GROUP &&
+            field->message_type() == descriptor) {
+          return internal::WireFormatLite::MakeTag(
+              field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP);
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
+  std::string result = GetFileNamespace(file);
+  if (!result.empty()) {
+    result += '.';
+  }
+  std::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 GetFullExtensionName(const FieldDescriptor* descriptor) {
+  if (descriptor->extension_scope()) {
+    return GetClassName(descriptor->extension_scope()) + ".Extensions." + GetPropertyName(descriptor);
+  }
+  else {
+    return GetExtensionClassUnqualifiedName(descriptor->file())  + "." + GetPropertyName(descriptor);
+  }
+}
+
+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 GetOneofCaseName(const FieldDescriptor* descriptor) {
+  // The name in a oneof case enum is the same as for the property, but as we always have a "None"
+  // value as well, we need to reserve that by appending an underscore.
+  std::string property_name = GetPropertyName(descriptor);
+  return property_name == "None" ? "None_" : property_name;
+}
+
+std::string GetOutputFile(const FileDescriptor* descriptor,
+                          const std::string file_extension,
+                          const bool generate_directories,
+                          const std::string base_namespace,
+                          std::string* error) {
+  std::string relative_filename = GetFileNameBase(descriptor) + file_extension;
+  if (!generate_directories) {
+    return relative_filename;
+  }
+  std::string ns = GetFileNamespace(descriptor);
+  std::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.
+    std::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);
+    }
+  }
+
+  std::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 presenceIndex,
+                                         const Options* options) {
+  switch (descriptor->type()) {
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      if (descriptor->is_repeated()) {
+        if (descriptor->is_map()) {
+          return new MapFieldGenerator(descriptor, presenceIndex, options);
+        } else {
+          return new RepeatedMessageFieldGenerator(descriptor, presenceIndex, options);
+        }
+      } else {
+        if (IsWrapperType(descriptor)) {
+          if (descriptor->real_containing_oneof()) {
+            return new WrapperOneofFieldGenerator(descriptor, presenceIndex, options);
+          } else {
+            return new WrapperFieldGenerator(descriptor, presenceIndex, options);
+          }
+        } else {
+          if (descriptor->real_containing_oneof()) {
+            return new MessageOneofFieldGenerator(descriptor, presenceIndex, options);
+          } else {
+            return new MessageFieldGenerator(descriptor, presenceIndex, options);
+          }
+        }
+      }
+    case FieldDescriptor::TYPE_ENUM:
+      if (descriptor->is_repeated()) {
+        return new RepeatedEnumFieldGenerator(descriptor, presenceIndex, options);
+      } else {
+        if (descriptor->real_containing_oneof()) {
+          return new EnumOneofFieldGenerator(descriptor, presenceIndex, options);
+        } else {
+          return new EnumFieldGenerator(descriptor, presenceIndex, options);
+        }
+      }
+    default:
+      if (descriptor->is_repeated()) {
+        return new RepeatedPrimitiveFieldGenerator(descriptor, presenceIndex, options);
+      } else {
+        if (descriptor->real_containing_oneof()) {
+          return new PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options);
+        } else {
+          return new PrimitiveFieldGenerator(descriptor, presenceIndex, options);
+        }
+      }
+  }
+}
+
+bool IsNullable(const FieldDescriptor* descriptor) {
+  if (descriptor->is_repeated()) {
+    return true;
+  }
+
+  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;
+  }
+}
+
+}  // 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..836bd5d
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -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.
+
+// 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/port.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+class FieldGeneratorBase;
+
+// TODO: start using this enum.
+enum CSharpType {
+  CSHARPTYPE_INT32 = 1,
+  CSHARPTYPE_INT64 = 2,
+  CSHARPTYPE_UINT32 = 3,
+  CSHARPTYPE_UINT64 = 4,
+  CSHARPTYPE_FLOAT = 5,
+  CSHARPTYPE_DOUBLE = 6,
+  CSHARPTYPE_BOOL = 7,
+  CSHARPTYPE_STRING = 8,
+  CSHARPTYPE_BYTESTRING = 9,
+  CSHARPTYPE_MESSAGE = 10,
+  CSHARPTYPE_ENUM = 11,
+  MAX_CSHARPTYPE = 11
+};
+
+// Converts field type to corresponding C# type.
+CSharpType GetCSharpType(FieldDescriptor::Type type);
+
+std::string StripDotProto(const std::string& proto_file);
+
+// Gets unqualified name of the reflection class
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
+// Gets unqualified name of the extension class
+std::string GetExtensionClassUnqualifiedName(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);
+
+std::string GetOneofCaseName(const FieldDescriptor* descriptor);
+
+int GetFixedSize(FieldDescriptor::Type type);
+
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter,
+                                   bool preserve_period);
+
+inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
+  return UnderscoresToCamelCase(input, cap_next_letter, false);
+}
+
+std::string UnderscoresToPascalCase(const std::string& input);
+
+// Note that we wouldn't normally want to export this (we're not expecting
+// it to be used outside libprotoc itself) but this exposes it for testing.
+std::string PROTOC_EXPORT GetEnumValueName(const std::string& enum_name,
+                                           const std::string& enum_value_name);
+
+// TODO(jtattermusch): perhaps we could move this to strutil
+std::string StringToBase64(const std::string& input);
+
+std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
+
+FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
+                                         int presenceIndex,
+                                         const Options* options);
+
+std::string GetFullExtensionName(const FieldDescriptor* descriptor);
+
+bool IsNullable(const FieldDescriptor* descriptor);
+
+// 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();
+}
+
+// Checks if this descriptor is for a group and gets its end tag or 0 if it's not a group
+uint GetGroupEndTag(const Descriptor* descriptor);
+
+// 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" ||
+         descriptor->name() == "net/proto2/proto/descriptor.proto";
+}
+
+// Determines whether the given message is an options message within descriptor.proto.
+inline bool IsDescriptorOptionMessage(const Descriptor* descriptor) {
+  if (!IsDescriptorProto(descriptor->file())) {
+    return false;
+  }
+  const std::string name = descriptor->name();
+  return name == "FileOptions" ||
+      name == "MessageOptions" ||
+      name == "FieldOptions" ||
+      name == "OneofOptions" ||
+      name == "EnumOptions" ||
+      name == "EnumValueOptions" ||
+      name == "ServiceOptions" ||
+      name == "MethodOptions";
+}
+
+inline bool IsWrapperType(const FieldDescriptor* descriptor) {
+  return descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
+      descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
+}
+
+inline bool IsProto2(const FileDescriptor* descriptor) {
+  return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
+inline bool SupportsPresenceApi(const FieldDescriptor* descriptor) {
+  // Unlike most languages, we don't generate Has/Clear members for message
+  // types, because they can always be set to null in C#. They're not really
+  // needed for oneof fields in proto2 either, as everything can be done via
+  // oneof case, but we follow the convention from other languages. Proto3
+  // oneof fields never have Has/Clear members - but will also never have
+  // the explicit optional keyword either.
+  //
+  // None of the built-in helpers (descriptor->has_presence() etc) describe
+  // quite the behavior we want, so the rules are explicit below.
+
+  if (descriptor->is_repeated() ||
+      descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
+    return false;
+  }
+  // has_optional_keyword() has more complex rules for proto2, but that
+  // doesn't matter given the first part of this condition.
+  return IsProto2(descriptor->file()) || descriptor->has_optional_keyword();
+}
+
+inline bool RequiresPresenceBit(const FieldDescriptor* descriptor) {
+  return SupportsPresenceApi(descriptor) &&
+    !IsNullable(descriptor) &&
+    !descriptor->is_extension() &&
+    !descriptor->real_containing_oneof();
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..a13b995
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -0,0 +1,152 @@
+// 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/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 presenceIndex,
+                                     const Options* options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+}
+
+MapFieldGenerator::~MapFieldGenerator() {
+}
+
+void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
+  const FieldDescriptor* key_descriptor =
+      descriptor_->message_type()->map_key();
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->map_value();
+  variables_["key_type_name"] = type_name(key_descriptor);
+  variables_["value_type_name"] = type_name(value_descriptor);
+  std::unique_ptr<FieldGeneratorBase> key_generator(
+      CreateFieldGenerator(key_descriptor, 1, this->options()));
+  std::unique_ptr<FieldGeneratorBase> value_generator(
+      CreateFieldGenerator(value_descriptor, 2, this->options()));
+
+  printer->Print(
+    variables_,
+    "private static readonly pbc::MapField<$key_type_name$, $value_type_name$>.Codec _map_$name$_codec\n"
+    "    = new pbc::MapField<$key_type_name$, $value_type_name$>.Codec(");
+  key_generator->GenerateCodecCode(printer);
+  printer->Print(", ");
+  value_generator->GenerateCodecCode(printer);
+  printer->Print(
+    variables_,
+    ", $tag$);\n"
+    "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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) {
+  GenerateParsingCode(printer, true);
+}
+
+void MapFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  printer->Print(
+    variables_,
+    use_parse_context
+    ? "$name$_.AddEntriesFrom(ref input, _map_$name$_codec);\n"
+    : "$name$_.AddEntriesFrom(input, _map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  GenerateSerializationCode(printer, true);
+}
+
+void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  printer->Print(
+    variables_,
+    use_write_context
+    ? "$name$_.WriteTo(ref output, _map_$name$_codec);\n"
+    : "$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..23b3619
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+
+#include <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 presenceIndex,
+                    const Options* options);
+  ~MapFieldGenerator();
+
+  MapFieldGenerator(const MapFieldGenerator&) = delete;
+  MapFieldGenerator& operator=(const MapFieldGenerator&) = delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateFreezingCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+};
+
+}  // 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..a119bdd
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -0,0 +1,779 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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_options.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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
+  return d1->number() < d2->number();
+}
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor,
+                                   const Options* options)
+    : SourceGeneratorBase(options),
+      descriptor_(descriptor),
+      has_bit_field_count_(0),
+      end_tag_(GetGroupEndTag(descriptor)),
+      has_extension_ranges_(descriptor->extension_range_count() > 0) {
+  // 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);
+
+  int presence_bit_count = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (RequiresPresenceBit(field)) {
+      presence_bit_count++;
+      if (has_bit_field_count_ == 0 || (presence_bit_count % 32) == 0) {
+        has_bit_field_count_++;
+      }
+    }
+  }
+}
+
+MessageGenerator::~MessageGenerator() {
+}
+
+std::string MessageGenerator::class_name() {
+  return descriptor_->name();
+}
+
+std::string MessageGenerator::full_class_name() {
+  return GetClassName(descriptor_);
+}
+
+const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
+  return fields_by_number_;
+}
+
+void MessageGenerator::AddDeprecatedFlag(io::Printer* printer) {
+  if (descriptor_->options().deprecated()) {
+    printer->Print("[global::System.ObsoleteAttribute]\n");
+  }
+}
+
+void MessageGenerator::AddSerializableAttribute(io::Printer* printer) {
+  if (this->options()->serializable) {
+    printer->Print("[global::System.SerializableAttribute]\n");
+  }
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+  std::map<std::string, std::string> vars;
+  vars["class_name"] = class_name();
+  vars["access_level"] = class_access_level();
+
+  WriteMessageDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  AddSerializableAttribute(printer);
+
+  printer->Print(
+    vars,
+    "$access_level$ sealed partial class $class_name$ : ");
+
+  if (has_extension_ranges_) {
+    printer->Print(vars, "pb::IExtendableMessage<$class_name$>\n");
+  }
+  else {
+    printer->Print(vars, "pb::IMessage<$class_name$>\n");
+  }
+  printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
+  printer->Print("    , pb::IBufferMessage\n");
+  printer->Print("#endif\n");
+  printer->Print("{\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");
+
+  printer->Print(
+      "private pb::UnknownFieldSet _unknownFields;\n");
+
+  if (has_extension_ranges_) {
+    if (IsDescriptorProto(descriptor_->file())) {
+      printer->Print(vars, "internal pb::ExtensionSet<$class_name$> _extensions;\n"); // CustomOptions compatibility
+    } else {
+      printer->Print(vars, "private pb::ExtensionSet<$class_name$> _extensions;\n");
+    }
+
+    // a read-only property for fast
+    // retrieval of the set in IsInitialized
+    printer->Print(vars,
+                   "private pb::ExtensionSet<$class_name$> _Extensions { get { "
+                   "return _extensions; } }\n");
+  }
+
+  for (int i = 0; i < has_bit_field_count_; i++) {
+    // don't use arrays since all arrays are heap allocated, saving allocations
+    // use ints instead of bytes since bytes lack bitwise operators, saving casts
+    printer->Print("private int _hasBits$i$;\n", "i", StrCat(i));
+  }
+
+  WriteGeneratedCodeAttributes(printer);
+
+  printer->Print(
+      vars,
+      "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[" + StrCat(descriptor_->index()) + "]";
+  } else {
+    vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
+        + ".Descriptor.NestedTypes[" + StrCat(descriptor_->index()) + "]";
+  }
+
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print(
+    vars,
+    "public static pbr::MessageDescriptor Descriptor {\n"
+    "  get { return $descriptor_accessor$; }\n"
+    "}\n"
+    "\n");
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print(
+    vars,
+    "pbr::MessageDescriptor pb::IMessage.Descriptor {\n"
+    "  get { return Descriptor; }\n"
+    "}\n"
+    "\n");
+
+  // Parameterless constructor and partial OnConstruction method.
+  WriteGeneratedCodeAttributes(printer);
+  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", StrCat(fieldDescriptor->number()));
+    std::unique_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(fieldDescriptor));
+    generator->GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  // oneof properties (for real oneofs, which come before synthetic ones)
+  for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    vars["name"] = UnderscoresToCamelCase(oneof->name(), false);
+    vars["property_name"] = UnderscoresToCamelCase(oneof->name(), true);
+    vars["original_name"] = oneof->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 < oneof->field_count(); j++) {
+      const FieldDescriptor* field = oneof->field(j);
+      printer->Print("$oneof_case_name$ = $index$,\n",
+                     "oneof_case_name", GetOneofCaseName(field),
+                     "index", StrCat(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");
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print(
+      vars,
+      "public $property_name$OneofCase $property_name$Case {\n"
+      "  get { return $name$Case_; }\n"
+      "}\n\n");
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print(
+      vars,
+      "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);
+
+  if (has_extension_ranges_) {
+    printer->Print(
+        vars,
+        "public TValue GetExtension<TValue>(pb::Extension<$class_name$, "
+        "TValue> extension) {\n"
+        "  return pb::ExtensionSet.Get(ref _extensions, extension);\n"
+        "}\n"
+        "public pbc::RepeatedField<TValue> "
+        "GetExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> "
+        "extension) {\n"
+        "  return pb::ExtensionSet.Get(ref _extensions, extension);\n"
+        "}\n"
+        "public pbc::RepeatedField<TValue> "
+        "GetOrInitializeExtension<TValue>(pb::RepeatedExtension<$class_name$, "
+        "TValue> extension) {\n"
+        "  return pb::ExtensionSet.GetOrInitialize(ref _extensions, "
+        "extension);\n"
+        "}\n"
+        "public void SetExtension<TValue>(pb::Extension<$class_name$, TValue> "
+        "extension, TValue value) {\n"
+        "  pb::ExtensionSet.Set(ref _extensions, extension, value);\n"
+        "}\n"
+        "public bool HasExtension<TValue>(pb::Extension<$class_name$, TValue> "
+        "extension) {\n"
+        "  return pb::ExtensionSet.Has(ref _extensions, extension);\n"
+        "}\n"
+        "public void ClearExtension<TValue>(pb::Extension<$class_name$, "
+        "TValue> extension) {\n"
+        "  pb::ExtensionSet.Clear(ref _extensions, extension);\n"
+        "}\n"
+        "public void "
+        "ClearExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> "
+        "extension) {\n"
+        "  pb::ExtensionSet.Clear(ref _extensions, extension);\n"
+        "}\n\n");
+  }
+
+  // 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");
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print("public static partial class Types {\n");
+    printer->Indent();
+    for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+      EnumGenerator enumGenerator(descriptor_->enum_type(i), this->options());
+      enumGenerator.Generate(printer);
+    }
+    for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+      // Don't generate nested types for maps...
+      if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
+        MessageGenerator messageGenerator(
+            descriptor_->nested_type(i), this->options());
+        messageGenerator.Generate(printer);
+      }
+    }
+    printer->Outdent();
+    printer->Print("}\n"
+                   "#endregion\n"
+                   "\n");
+  }
+
+  if (descriptor_->extension_count() > 0) {
+    printer->Print(
+      vars,
+      "#region Extensions\n"
+      "/// <summary>Container for extensions for other messages declared in the $class_name$ message type.</summary>\n");
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print("public static partial class Extensions {\n");
+    printer->Indent();
+    for (int i = 0; i < descriptor_->extension_count(); i++) {
+      std::unique_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(descriptor_->extension(i)));
+      generator->GenerateExtensionCode(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) {
+  std::map<std::string, std::string> vars;
+  WriteGeneratedCodeAttributes(printer);
+  vars["class_name"] = class_name();
+    printer->Print(
+    vars,
+    "public $class_name$($class_name$ other) : this() {\n");
+  printer->Indent();
+  for (int i = 0; i < has_bit_field_count_; i++) {
+    printer->Print("_hasBits$i$ = other._hasBits$i$;\n", "i", StrCat(i));
+  }
+  // Clone non-oneof fields first (treating optional proto3 fields as non-oneof)
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->real_containing_oneof()) {
+      continue;
+    }
+    std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
+    generator->GenerateCloningCode(printer);
+  }
+  // Clone just the right field for each real oneof
+  for (int i = 0; i < descriptor_->real_oneof_decl_count(); ++i) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    vars["name"] = UnderscoresToCamelCase(oneof->name(), false);
+    vars["property_name"] = UnderscoresToCamelCase(oneof->name(), true);
+    printer->Print(vars, "switch (other.$property_name$Case) {\n");
+    printer->Indent();
+    for (int j = 0; j < oneof->field_count(); j++) {
+      const FieldDescriptor* field = oneof->field(j);
+      std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
+      vars["oneof_case_name"] = GetOneofCaseName(field);
+      printer->Print(
+          vars,
+          "case $property_name$OneofCase.$oneof_case_name$:\n");
+      printer->Indent();
+      generator->GenerateCloningCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Outdent();
+    printer->Print("}\n\n");
+  }
+  // Clone unknown fields
+  printer->Print(
+      "_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);\n");
+  if (has_extension_ranges_) {
+    printer->Print(
+        "_extensions = pb::ExtensionSet.Clone(other._extensions);\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+
+  WriteGeneratedCodeAttributes(printer);
+  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) {
+    std::map<std::string, std::string> vars;
+    vars["class_name"] = class_name();
+
+    // Equality
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print(
+        vars,
+        "public override bool Equals(object other) {\n"
+        "  return Equals(other as $class_name$);\n"
+        "}\n\n");
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print(
+        vars,
+        "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++) {
+      std::unique_ptr<FieldGeneratorBase> generator(
+            CreateFieldGeneratorInternal(descriptor_->field(i)));
+        generator->WriteEquals(printer);
+    }
+    for (int i = 0; i < descriptor_->real_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));
+    }
+    if (has_extension_ranges_) {
+      printer->Print(
+          "if (!Equals(_extensions, other._extensions)) {\n"
+          "  return false;\n"
+          "}\n");
+    }
+    printer->Outdent();
+    printer->Print(
+        "  return Equals(_unknownFields, other._unknownFields);\n"
+        "}\n\n");
+
+    // GetHashCode
+    // Start with a non-zero value to easily distinguish between null and "empty" messages.
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print(
+        "public override int GetHashCode() {\n"
+        "  int hash = 1;\n");
+    printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      std::unique_ptr<FieldGeneratorBase> generator(
+            CreateFieldGeneratorInternal(descriptor_->field(i)));
+        generator->WriteHash(printer);
+    }
+    for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
+      printer->Print("hash ^= (int) $name$Case_;\n",
+          "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false));
+    }
+    if (has_extension_ranges_) {
+      printer->Print(
+        "if (_extensions != null) {\n"
+        "  hash ^= _extensions.GetHashCode();\n"
+        "}\n");
+    }
+    printer->Print(
+        "if (_unknownFields != null) {\n"
+        "  hash ^= _unknownFields.GetHashCode();\n"
+        "}\n"
+        "return hash;\n");
+    printer->Outdent();
+    printer->Print("}\n\n");
+
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print(
+        "public override string ToString() {\n"
+        "  return pb::JsonFormatter.ToDiagnosticString(this);\n"
+        "}\n\n");
+}
+
+void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print(
+      "public void WriteTo(pb::CodedOutputStream output) {\n");
+  printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
+  printer->Indent();
+  printer->Print("output.WriteRawMessage(this);\n");
+  printer->Outdent();
+  printer->Print("#else\n");
+  printer->Indent();
+  GenerateWriteToBody(printer, false);
+  printer->Outdent();
+  printer->Print("#endif\n");
+  printer->Print("}\n\n");
+
+  printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print("void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {\n");
+  printer->Indent();
+  GenerateWriteToBody(printer, true);
+  printer->Outdent();
+  printer->Print("}\n");
+  printer->Print("#endif\n\n");
+
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print(
+    "public int CalculateSize() {\n");
+  printer->Indent();
+  printer->Print("int size = 0;\n");
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    std::unique_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(descriptor_->field(i)));
+    generator->GenerateSerializedSizeCode(printer);
+  }
+
+  if (has_extension_ranges_) {
+    printer->Print(
+      "if (_extensions != null) {\n"
+      "  size += _extensions.CalculateSize();\n"
+      "}\n");
+  }
+
+  printer->Print(
+    "if (_unknownFields != null) {\n"
+    "  size += _unknownFields.CalculateSize();\n"
+    "}\n");
+
+  printer->Print("return size;\n");
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void MessageGenerator::GenerateWriteToBody(io::Printer* printer, bool use_write_context) {
+  // Serialize all the fields
+  for (int i = 0; i < fields_by_number().size(); i++) {
+    std::unique_ptr<FieldGeneratorBase> generator(
+      CreateFieldGeneratorInternal(fields_by_number()[i]));
+    generator->GenerateSerializationCode(printer, use_write_context);
+  }
+
+  if (has_extension_ranges_) {
+    // Serialize extensions
+    printer->Print(
+      use_write_context
+      ? "if (_extensions != null) {\n"
+        "  _extensions.WriteTo(ref output);\n"
+        "}\n"
+      : "if (_extensions != null) {\n"
+        "  _extensions.WriteTo(output);\n"
+        "}\n");
+  }
+
+  // Serialize unknown fields
+  printer->Print(
+    use_write_context
+    ? "if (_unknownFields != null) {\n"
+      "  _unknownFields.WriteTo(ref output);\n"
+      "}\n"
+    : "if (_unknownFields != null) {\n"
+      "  _unknownFields.WriteTo(output);\n"
+      "}\n");
+
+  // TODO(jonskeet): Memoize size of frozen messages?
+}
+
+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.
+  std::map<std::string, std::string> vars;
+  vars["class_name"] = class_name();
+
+  WriteGeneratedCodeAttributes(printer);
+  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, treating optional proto3 fields as normal fields
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->real_containing_oneof()) {
+      continue;
+    }
+    std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
+    generator->GenerateMergingCode(printer);
+  }
+  // Merge oneof fields (for non-synthetic oneofs)
+  for (int i = 0; i < descriptor_->real_oneof_decl_count(); ++i) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    vars["name"] = UnderscoresToCamelCase(oneof->name(), false);
+    vars["property_name"] = UnderscoresToCamelCase(oneof->name(), true);
+    printer->Print(vars, "switch (other.$property_name$Case) {\n");
+    printer->Indent();
+    for (int j = 0; j < oneof->field_count(); j++) {
+      const FieldDescriptor* field = oneof->field(j);
+      vars["oneof_case_name"] = GetOneofCaseName(field);
+      printer->Print(
+        vars,
+        "case $property_name$OneofCase.$oneof_case_name$:\n");
+      printer->Indent();
+      std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
+      generator->GenerateMergingCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Outdent();
+    printer->Print("}\n\n");
+  }
+  // Merge extensions
+  if (has_extension_ranges_) {
+    printer->Print("pb::ExtensionSet.MergeFrom(ref _extensions, other._extensions);\n");
+  }
+
+  // Merge unknown fields.
+  printer->Print(
+      "_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);\n");
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n");
+  printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
+  printer->Indent();
+  printer->Print("input.ReadRawMessage(this);\n");
+  printer->Outdent();
+  printer->Print("#else\n");
+  printer->Indent();
+  GenerateMainParseLoop(printer, false);
+  printer->Outdent();
+  printer->Print("#endif\n");
+  printer->Print("}\n\n");
+
+  printer->Print("#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print("void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {\n");
+  printer->Indent();
+  GenerateMainParseLoop(printer, true);
+  printer->Outdent();
+  printer->Print("}\n"); // method
+  printer->Print("#endif\n\n");
+
+}
+
+void MessageGenerator::GenerateMainParseLoop(io::Printer* printer, bool use_parse_context) {
+  std::map<std::string, std::string> vars;
+  vars["maybe_ref_input"] = use_parse_context ? "ref input" : "input";
+
+  printer->Print(
+    "uint tag;\n"
+    "while ((tag = input.ReadTag()) != 0) {\n"
+    "  switch(tag) {\n");
+  printer->Indent();
+  printer->Indent();
+  if (end_tag_ != 0) {
+    printer->Print(
+        "case $end_tag$:\n"
+        "  return;\n",
+        "end_tag", StrCat(end_tag_));
+  }
+  if (has_extension_ranges_) {
+    printer->Print(vars,
+      "default:\n"
+      "  if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, $maybe_ref_input$)) {\n"
+      "    _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, $maybe_ref_input$);\n"
+      "  }\n"
+      "  break;\n");
+  } else {
+    printer->Print(vars,
+      "default:\n"
+      "  _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, $maybe_ref_input$);\n"
+      "  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_t 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",
+        StrCat(
+            internal::WireFormatLite::MakeTag(
+                field->number(),
+                internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
+    }
+
+    printer->Print("case $tag$: {\n", "tag", StrCat(tag));
+    printer->Indent();
+    std::unique_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(field));
+    generator->GenerateParsingCode(printer, use_parse_context);
+    printer->Print("break;\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+  printer->Outdent();
+  printer->Print("}\n"); // switch
+  printer->Outdent();
+  printer->Print("}\n"); // while
+}
+
+// it's a waste of space to track presence for all values, so we only track them if they're not nullable
+int MessageGenerator::GetPresenceIndex(const FieldDescriptor* descriptor) {
+  if (!RequiresPresenceBit(descriptor)) {
+    return -1;
+  }
+
+  int index = 0;
+  for (int i = 0; i < fields_by_number().size(); i++) {
+    const FieldDescriptor* field = fields_by_number()[i];
+    if (field == descriptor) {
+      return index;
+    }
+    if (RequiresPresenceBit(field)) {
+      index++;
+    }
+  }
+  GOOGLE_LOG(DFATAL)<< "Could not find presence index for field " << descriptor->name();
+  return -1;
+}
+
+FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
+    const FieldDescriptor* descriptor) {
+  return CreateFieldGenerator(descriptor, GetPresenceIndex(descriptor), this->options());
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h
new file mode 100644
index 0000000..d02767e
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_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_CSHARP_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase;
+
+class MessageGenerator : public SourceGeneratorBase {
+ public:
+  MessageGenerator(const Descriptor* descriptor, const Options* options);
+  ~MessageGenerator();
+
+  MessageGenerator(const MessageGenerator&) = delete;
+  MessageGenerator& operator=(const MessageGenerator&) = delete;
+
+  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<const FieldDescriptor*> fields_by_number_;
+  int has_bit_field_count_;
+  uint end_tag_;
+  bool has_extension_ranges_;
+
+  void GenerateMessageSerializationMethods(io::Printer* printer);
+  void GenerateWriteToBody(io::Printer* printer, bool use_write_context);
+  void GenerateMergingMethods(io::Printer* printer);
+  void GenerateMainParseLoop(io::Printer* printer, bool use_parse_context);
+
+  int GetPresenceIndex(const FieldDescriptor* descriptor);
+  FieldGeneratorBase* CreateFieldGeneratorInternal(
+      const FieldDescriptor* descriptor);
+
+  bool HasNestedGeneratedTypes();
+
+  void AddDeprecatedFlag(io::Printer* printer);
+  void AddSerializableAttribute(io::Printer* printer);
+
+  std::string class_name();
+  std::string full_class_name();
+
+  // field descriptors sorted by number
+  const std::vector<const FieldDescriptor*>& fields_by_number();
+};
+
+}  // 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..487d01d
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
@@ -0,0 +1,293 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/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_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             int presenceIndex,
+                                             const Options *options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+  if (!SupportsPresenceApi(descriptor_)) {
+    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_);
+  AddPublicMemberAttributes(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "  set {\n"
+    "    $name$_ = value;\n"
+    "  }\n"
+    "}\n");
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(
+      variables_,
+      "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ bool Has$property_name$ {\n"
+      "  get { return $name$_ != null; }\n"
+      "}\n");
+    printer->Print(
+      variables_,
+      "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ void Clear$property_name$() {\n"
+      "  $name$_ = null;\n"
+      "}\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if (other.$has_property_check$) {\n"
+    "  if ($has_not_property_check$) {\n"
+    "    $property_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"
+    "  $property_name$ = new $type_name$();\n"
+    "}\n");
+  if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
+    printer->Print(variables_, "input.ReadMessage($property_name$);\n");
+  } else {
+    printer->Print(variables_, "input.ReadGroup($property_name$);\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
+    printer->Print(
+      variables_,
+      "if ($has_property_check$) {\n"
+      "  output.WriteRawTag($tag_bytes$);\n"
+      "  output.WriteMessage($property_name$);\n"
+      "}\n");
+  } else {
+    printer->Print(
+      variables_,
+      "if ($has_property_check$) {\n"
+      "  output.WriteRawTag($tag_bytes$);\n"
+      "  output.WriteGroup($property_name$);\n"
+      "  output.WriteRawTag($end_tag_bytes$);\n"
+      "}\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
+    printer->Print(
+      variables_,
+      "if ($has_property_check$) {\n"
+      "  size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($property_name$);\n"
+      "}\n");
+  } else {
+    printer->Print(
+      variables_,
+      "if ($has_property_check$) {\n"
+      "  size += $tag_size$ + pb::CodedOutputStream.ComputeGroupSize($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::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::Extension<$extended_type$, $type_name$>($number$, ");
+  GenerateCodecCode(printer);
+  printer->Print(");\n");
+}
+void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = other.$has_property_check$ ? other.$name$_.Clone() : null;\n");
+}
+
+void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+  if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
+    printer->Print(
+      variables_,
+      "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)");
+  } else {
+    printer->Print(
+      variables_,
+      "pb::FieldCodec.ForGroup($tag$, $end_tag$, $type_name$.Parser)");
+  }
+}
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(
+    const FieldDescriptor* descriptor,
+	  int presenceIndex,
+    const Options *options)
+    : MessageFieldGenerator(descriptor, presenceIndex, options) {
+  SetCommonOneofFieldVariables(&variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {
+
+}
+
+void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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.$oneof_case_name$;\n"
+    "  }\n"
+    "}\n");
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(
+      variables_,
+      "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ bool Has$property_name$ {\n"
+      "  get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n"
+      "}\n");
+    printer->Print(
+      variables_,
+      "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ void Clear$property_name$() {\n"
+      "  if ($has_property_check$) {\n"
+      "    Clear$oneof_property_name$();\n"
+      "  }\n"
+      "}\n");
+  }
+}
+
+void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "if ($property_name$ == null) {\n"
+    "  $property_name$ = new $type_name$();\n"
+    "}\n"
+    "$property_name$.MergeFrom(other.$property_name$);\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");
+  if (descriptor_->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
+    printer->Print("input.ReadMessage(subBuilder);\n");
+  } else {
+    printer->Print("input.ReadGroup(subBuilder);\n");
+  }
+  printer->Print(variables_, "$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..e76dfd2
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h
@@ -0,0 +1,91 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+
+#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 presenceIndex,
+                        const Options *options);
+  ~MessageFieldGenerator();
+
+  MessageFieldGenerator(const MessageFieldGenerator&) = delete;
+  MessageFieldGenerator& operator=(const MessageFieldGenerator&) = delete;
+
+  virtual void GenerateCodecCode(io::Printer* printer) override;
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateFreezingCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+};
+
+class MessageOneofFieldGenerator : public MessageFieldGenerator {
+ public:
+  MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             int presenceIndex,
+                             const Options *options);
+  ~MessageOneofFieldGenerator();
+
+  MessageOneofFieldGenerator(const MessageOneofFieldGenerator&) = delete;
+  MessageOneofFieldGenerator& operator=(const MessageOneofFieldGenerator&) =
+      delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+};
+
+}  // 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..67e53b6
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_names.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+
+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.
+std::string PROTOC_EXPORT GetFileNamespace(const FileDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified C# class name.
+std::string PROTOC_EXPORT 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.
+std::string PROTOC_EXPORT
+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.
+std::string PROTOC_EXPORT GetOutputFile(const FileDescriptor* descriptor,
+                                        const std::string file_extension,
+                                        const bool generate_directories,
+                                        const std::string base_namespace,
+                                        std::string* error);
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h
new file mode 100644
index 0000000..42ff6d8
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_options.h
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// Generator options (used by csharp_generator.cc):
+struct Options {
+  Options() :
+      file_extension(".cs"),
+      base_namespace(""),
+      base_namespace_specified(false),
+      internal_access(false),
+      serializable(false) {
+  }
+  // Extension of the generated file. Defaults to ".cs"
+  std::string file_extension;
+  // Base namespace to use to create directory hierarchy. Defaults to "".
+  // This option allows the simple creation of a conventional C# file layout,
+  // where directories are created relative to a project-specific base
+  // namespace. For example, in a project with a base namespace of PetShop, a
+  // proto of user.proto with a C# namespace of PetShop.Model.Shared would
+  // generate Model/Shared/User.cs underneath the specified --csharp_out
+  // directory.
+  //
+  // If no base namespace is specified, all files are generated in the
+  // --csharp_out directory, with no subdirectories created automatically.
+  std::string base_namespace;
+  // Whether the base namespace has been explicitly specified by the user.
+  // This is required as the base namespace can be explicitly set to the empty
+  // string, meaning "create a full directory hierarchy, starting from the first
+  // segment of the namespace."
+  bool base_namespace_specified;
+  // Whether the generated classes should have accessibility level of "internal".
+  // Defaults to false that generates "public" classes.
+  bool internal_access;
+  // Whether the generated classes should have a global::System.Serializable attribute added
+  // Defaults to false
+  bool serializable;
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
new file mode 100644
index 0000000..e7d5116
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -0,0 +1,349 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+  // TODO(jonskeet): Make this cleaner...
+  is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING
+      && descriptor->type() != FieldDescriptor::TYPE_BYTES;
+  if (!is_value_type && !SupportsPresenceApi(descriptor_)) {
+    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) {
+  
+  // Note: in multiple places, this code assumes that all fields
+  // that support presence are either nullable, or use a presence field bit.
+  // Fields which are oneof members are not generated here; they're generated in PrimitiveOneofFieldGenerator below.
+  // Extensions are not generated here either.
+
+
+  // Proto2 allows different default values to be specified. These are retained
+  // via static fields. They don't particularly need to be, but we don't need
+  // to change that. In Proto3 the default value we don't generate these
+  // fields, just using the literal instead.
+  if (IsProto2(descriptor_->file())) {
+    // Note: "private readonly static" isn't as idiomatic as
+    // "private static readonly", but changing this now would create a lot of
+    // churn in generated code with near-to-zero benefit.
+    printer->Print(
+      variables_,
+      "private readonly static $type_name$ $property_name$DefaultValue = $default_value$;\n\n");
+    variables_["default_value_access"] =
+      variables_["property_name"] + "DefaultValue";
+  } else {
+    variables_["default_value_access"] = variables_["default_value"];
+  }
+
+  // Declare the field itself.
+  printer->Print(
+    variables_,
+    "private $type_name$ $name_def_message$;\n");
+
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(printer);
+
+  // Most of the work is done in the property:
+  // Declare the property itself (the same for all options)
+  printer->Print(variables_, "$access_level$ $type_name$ $property_name$ {\n");
+
+  // Specify the "getter", which may need to check for a presence field.
+  if (SupportsPresenceApi(descriptor_)) {
+    if (IsNullable(descriptor_)) {
+      printer->Print(
+        variables_,
+        "  get { return $name$_ ?? $default_value_access$; }\n");
+    } else {
+      printer->Print(
+        variables_,
+        // Note: it's possible that this could be rewritten as a
+        // conditional ?: expression, but there's no significant benefit
+        // to changing it.
+        "  get { if ($has_field_check$) { return $name$_; } else { return $default_value_access$; } }\n");
+    }
+  } else {
+    printer->Print(
+      variables_,
+      "  get { return $name$_; }\n");
+  }
+
+  // Specify the "setter", which may need to set a field bit as well as the
+  // value.
+  printer->Print("  set {\n");
+  if (presenceIndex_ != -1) {
+    printer->Print(
+      variables_,
+      "    $set_has_field$;\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");
+
+  // The "HasFoo" property, where required.
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(variables_,
+      "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ bool Has$property_name$ {\n"
+      "  get { return ");
+    if (IsNullable(descriptor_)) {
+      printer->Print(
+        variables_,
+        "$name$_ != null; }\n}\n");
+    } else {
+      printer->Print(
+        variables_,
+        "$has_field_check$; }\n}\n");
+    }
+  }
+
+  // The "ClearFoo" method, where required.
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(variables_,
+      "/// <summary>Clears the value of the \"$descriptor_name$\" field</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ void Clear$property_name$() {\n");
+    if (IsNullable(descriptor_)) {
+      printer->Print(variables_, "  $name$_ = null;\n");
+    } else {
+      printer->Print(variables_, "  $clear_has_field$;\n");
+    }
+    printer->Print("}\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", StrCat(fixedSize),
+      "tag_size", variables_["tag_size"]);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
+  const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n";
+  if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) {
+    text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode($property_name$);\n";
+  } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) {
+    text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode($property_name$);\n";
+  }
+	printer->Print(variables_, text);
+}
+void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
+  const char *text = "if ($property_name$ != other.$property_name$) return false;\n";
+  if (descriptor_->type() == FieldDescriptor::TYPE_FLOAT) {
+    text = "if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
+  } else if (descriptor_->type() == FieldDescriptor::TYPE_DOUBLE) {
+    text = "if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
+  }
+  printer->Print(variables_, text);
+}
+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$, $default_value$)");
+}
+
+void PrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::Extension<$extended_type$, $type_name$>($number$, ");
+  GenerateCodecCode(printer);
+  printer->Print(");\n");
+}
+
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
+    : PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
+  SetCommonOneofFieldVariables(&variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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.$oneof_case_name$;\n"
+    "  }\n"
+    "}\n");
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(
+      variables_,
+      "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ bool Has$property_name$ {\n"
+      "  get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n"
+      "}\n");
+    printer->Print(
+      variables_,
+      "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ void Clear$property_name$() {\n"
+      "  if ($has_property_check$) {\n"
+      "    Clear$oneof_property_name$();\n"
+      "  }\n"
+      "}\n");
+  }
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(variables_, "$property_name$ = other.$property_name$;\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..6d495d5
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class PrimitiveFieldGenerator : public FieldGeneratorBase {
+ public:
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                          int presenceIndex,
+                          const Options *options);
+  ~PrimitiveFieldGenerator();
+
+  PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete;
+  PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete;
+
+  virtual void GenerateCodecCode(io::Printer* printer) override;
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+
+ protected:
+  bool is_value_type;
+};
+
+class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+  PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                               int presenceIndex,
+                               const Options *options);
+  ~PrimitiveOneofFieldGenerator();
+
+  PrimitiveOneofFieldGenerator(const PrimitiveOneofFieldGenerator&) = delete;
+  PrimitiveOneofFieldGenerator& operator=(const PrimitiveOneofFieldGenerator&) =
+      delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+};
+
+}  // 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..d9ab4b4
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
@@ -0,0 +1,330 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.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_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_message.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file,
+                                                   const Options* options)
+    : SourceGeneratorBase(options),
+      file_(file) {
+  namespace_ = GetFileNamespace(file);
+  reflectionClassname_ = GetReflectionClassUnqualifiedName(file);
+  extensionClassname_ = GetExtensionClassUnqualifiedName(file);
+}
+
+ReflectionClassGenerator::~ReflectionClassGenerator() {
+}
+
+void ReflectionClassGenerator::Generate(io::Printer* printer) {
+  WriteIntroduction(printer);
+
+  WriteDescriptor(printer);
+  // Close the class declaration.
+  printer->Outdent();
+  printer->Print("}\n");
+
+  if (file_->extension_count() > 0) {
+    printer->Print(
+        "/// <summary>Holder for extension identifiers generated from the top "
+        "level of $file_name$</summary>\n"
+        "$access_level$ static partial class $class_name$ {\n",
+        "access_level", class_access_level(), "class_name", extensionClassname_,
+        "file_name", file_->name());
+    printer->Indent();
+    for (int i = 0; i < file_->extension_count(); i++) {
+        std::unique_ptr<FieldGeneratorBase> generator(
+          CreateFieldGenerator(file_->extension(i), -1, this->options()));
+        generator->GenerateExtensionCode(printer);
+    }
+    printer->Outdent();
+    printer->Print(
+    "}\n"
+    "\n");
+  }
+
+  // write children: Enums
+  if (file_->enum_type_count() > 0) {
+    printer->Print("#region Enums\n");
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      EnumGenerator enumGenerator(file_->enum_type(i), this->options());
+      enumGenerator.Generate(printer);
+    }
+    printer->Print("#endregion\n");
+    printer->Print("\n");
+  }
+
+  // write children: Messages
+  if (file_->message_type_count() > 0) {
+    printer->Print("#region Messages\n");
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      MessageGenerator messageGenerator(file_->message_type(i), this->options());
+      messageGenerator.Generate(printer);
+    }
+    printer->Print("#endregion\n");
+    printer->Print("\n");
+  }
+
+  // TODO(jtattermusch): add insertion point for services.
+
+  if (!namespace_.empty()) {
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+  printer->Print("\n");
+  printer->Print("#endregion Designer generated code\n");
+}
+
+void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
+  printer->Print(
+    "// <auto-generated>\n"
+    "//     Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "//     source: $file_name$\n"
+    "// </auto-generated>\n"
+    "#pragma warning disable 1591, 0612, 3021, 8981\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"
+    "$access_level$ static partial class $reflection_class_name$ {\n"
+    "\n",
+    "file_name", file_->name(),
+    "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++) {
+      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_->extension_count() > 0) {
+    std::vector<std::string> extensions;
+    for (int i = 0; i < file_->extension_count(); i++) {
+      extensions.push_back(GetFullExtensionName(file_->extension(i)));
+    }
+    printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", Join(extensions, ", "));
+  }
+  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;
+      fields.reserve(descriptor->field_count());
+      for (int i = 0; i < descriptor->field_count(); i++) {
+          fields.push_back(GetPropertyName(descriptor->field(i)));
+      }
+      printer->Print("new[]{ \"$fields$\" }, ", "fields", Join(fields, "\", \""));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Oneofs
+  if (descriptor->oneof_decl_count() > 0) {
+      std::vector<std::string> oneofs;
+      oneofs.reserve(descriptor->oneof_decl_count());
+      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", Join(oneofs, "\", \""));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Nested enums
+  if (descriptor->enum_type_count() > 0) {
+      std::vector<std::string> enums;
+      enums.reserve(descriptor->enum_type_count());
+      for (int i = 0; i < descriptor->enum_type_count(); i++) {
+          enums.push_back(GetClassName(descriptor->enum_type(i)));
+      }
+      printer->Print("new[]{ typeof($enums$) }, ", "enums", Join(enums, "), typeof("));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Extensions
+  if (descriptor->extension_count() > 0) {
+    std::vector<std::string> extensions;
+    for (int i = 0; i < descriptor->extension_count(); i++) {
+      extensions.push_back(GetFullExtensionName(descriptor->extension(i)));
+    }
+    printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", Join(extensions, ", "));
+  }
+  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..9554727
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
@@ -0,0 +1,75 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_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>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class ReflectionClassGenerator : public SourceGeneratorBase {
+ public:
+  ReflectionClassGenerator(const FileDescriptor* file, const Options* options);
+  ~ReflectionClassGenerator();
+
+  ReflectionClassGenerator(const ReflectionClassGenerator&) = delete;
+  ReflectionClassGenerator& operator=(const ReflectionClassGenerator&) = delete;
+
+  void Generate(io::Printer* printer);
+
+ private:
+  const FileDescriptor* file_;
+
+  std::string namespace_;
+  std::string reflectionClassname_;
+  std::string extensionClassname_;
+
+  void WriteIntroduction(io::Printer* printer);
+  void WriteDescriptor(io::Printer* printer);
+  void WriteGeneratedCodeInfo(const Descriptor* descriptor,
+                              io::Printer* printer,
+                              bool last);
+};
+
+}  // 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..04bc7bb
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
@@ -0,0 +1,148 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.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 presenceIndex, const Options *options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {
+
+}
+
+void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+    "    = pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x);\n");
+  printer->Print(variables_,
+    "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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) {
+  GenerateParsingCode(printer, true);
+}
+
+void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  printer->Print(
+    variables_,
+    use_parse_context
+    ? "$name$_.AddEntriesFrom(ref input, _repeated_$name$_codec);\n"
+    : "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  GenerateSerializationCode(printer, true);
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  printer->Print(
+    variables_,
+    use_write_context
+    ? "$name$_.WriteTo(ref output, _repeated_$name$_codec);\n"
+    : "$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::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::RepeatedExtension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::RepeatedExtension<$extended_type$, $type_name$>($number$, "
+    "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x));\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..2379f38
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_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_REPEATED_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+
+#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 presenceIndex,
+                             const Options *options);
+  ~RepeatedEnumFieldGenerator();
+
+  RepeatedEnumFieldGenerator(const RepeatedEnumFieldGenerator&) = delete;
+  RepeatedEnumFieldGenerator& operator=(const RepeatedEnumFieldGenerator&) =
+      delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateFreezingCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+};
+
+}  // 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..8a93cd1
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.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 presenceIndex, const Options *options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {
+
+}
+
+void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+    "    = ");
+  // Don't want to duplicate the codec code here... maybe we should have a
+  // "create single field generator for this repeated field"
+  // function, but it doesn't seem worth it for just this.
+  if (IsWrapperType(descriptor_)) {
+    std::unique_ptr<FieldGeneratorBase> single_generator(
+      new WrapperFieldGenerator(descriptor_, presenceIndex_, this->options()));
+    single_generator->GenerateCodecCode(printer);
+  } else {
+    std::unique_ptr<FieldGeneratorBase> single_generator(
+      new MessageFieldGenerator(descriptor_, presenceIndex_, this->options()));
+    single_generator->GenerateCodecCode(printer);
+  }
+  printer->Print(";\n");
+  printer->Print(
+    variables_,
+    "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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) {
+  GenerateParsingCode(printer, true);
+}
+
+void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  printer->Print(
+    variables_,
+    use_parse_context
+    ? "$name$_.AddEntriesFrom(ref input, _repeated_$name$_codec);\n"
+    : "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  GenerateSerializationCode(printer, true);
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  printer->Print(
+    variables_,
+    use_write_context
+    ? "$name$_.WriteTo(ref output, _repeated_$name$_codec);\n"
+    : "$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) {
+}
+
+void RepeatedMessageFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::RepeatedExtension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::RepeatedExtension<$extended_type$, $type_name$>($number$, ");
+  if (IsWrapperType(descriptor_)) {
+    std::unique_ptr<FieldGeneratorBase> single_generator(
+      new WrapperFieldGenerator(descriptor_, -1, this->options()));
+    single_generator->GenerateCodecCode(printer);
+  } else {
+    std::unique_ptr<FieldGeneratorBase> single_generator(
+      new MessageFieldGenerator(descriptor_, -1, this->options()));
+    single_generator->GenerateCodecCode(printer);
+  }
+  printer->Print(");\n");
+}
+
+}  // 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..026efea
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_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_REPEATED_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class RepeatedMessageFieldGenerator : public FieldGeneratorBase {
+ public:
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                int presenceIndex,
+                                const Options *options);
+  ~RepeatedMessageFieldGenerator();
+
+  RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete;
+  RepeatedMessageFieldGenerator& operator=(
+      const RepeatedMessageFieldGenerator&) = delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateFreezingCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+};
+
+}  // 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..0eacf91
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
@@ -0,0 +1,145 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.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 presenceIndex, const Options *options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {
+
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+    "    = pb::FieldCodec.For$capitalized_type_name$($tag$);\n");
+  printer->Print(variables_,
+    "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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) {
+  GenerateParsingCode(printer, true);
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  printer->Print(
+    variables_,
+    use_parse_context
+    ? "$name$_.AddEntriesFrom(ref input, _repeated_$name$_codec);\n"
+    : "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  GenerateSerializationCode(printer, true);
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  printer->Print(
+    variables_,
+    use_write_context
+    ? "$name$_.WriteTo(ref output, _repeated_$name$_codec);\n"
+    : "$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) {
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::RepeatedExtension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::RepeatedExtension<$extended_type$, $type_name$>($number$, pb::FieldCodec.For$capitalized_type_name$($tag$));\n");
+}
+
+}  // 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..bdd12a0
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_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_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+
+#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 presenceIndex, const Options* options);
+  ~RepeatedPrimitiveFieldGenerator();
+
+  RepeatedPrimitiveFieldGenerator(const RepeatedPrimitiveFieldGenerator&) = delete;
+  RepeatedPrimitiveFieldGenerator& operator=(const RepeatedPrimitiveFieldGenerator&) = delete;
+
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateFreezingCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+};
+
+}  // 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..7157e6e
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
@@ -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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+SourceGeneratorBase::SourceGeneratorBase(
+    const Options *options) : options_(options) {
+}
+
+SourceGeneratorBase::~SourceGeneratorBase() {
+}
+
+void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) {
+  printer->Print("[global::System.Diagnostics.DebuggerNonUserCodeAttribute]\n");
+  // The second argument of the [GeneratedCode] attribute could be set to current protoc
+  // version, but that would cause excessive code churn in the pre-generated
+  // code in the repository every time the protobuf version number is updated.
+  printer->Print("[global::System.CodeDom.Compiler.GeneratedCode(\"protoc\", null)]\n");
+}
+
+std::string SourceGeneratorBase::class_access_level() {
+  return this->options()->internal_access ? "internal" : "public";
+}
+
+const Options* SourceGeneratorBase::options() {
+  return this->options_;
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
new file mode 100644
index 0000000..17a5269
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.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_SOURCE_GENERATOR_BASE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class SourceGeneratorBase {
+ protected:
+  SourceGeneratorBase(const Options* options);
+  virtual ~SourceGeneratorBase();
+
+  SourceGeneratorBase(const SourceGeneratorBase&) = delete;
+  SourceGeneratorBase& operator=(const SourceGeneratorBase&) = delete;
+
+  std::string class_access_level();
+  const Options* options();
+
+  // Write any attributes used to decorate generated function members (methods and properties).
+  // Should not be used to decorate types.
+  void WriteGeneratedCodeAttributes(io::Printer* printer);
+
+ private:
+  const Options *options_;
+};
+
+}  // 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..e638dd8
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -0,0 +1,308 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
+                                       int presenceIndex, const Options *options)
+    : FieldGeneratorBase(descriptor, presenceIndex, options) {
+  variables_["has_property_check"] = name() + "_ != null";
+  variables_["has_not_property_check"] = name() + "_ == null";
+  const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+  is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
+      wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
+  if (is_value_type) {
+    variables_["nonnullable_type_name"] = type_name(wrapped_field);
+  }
+}
+
+WrapperFieldGenerator::~WrapperFieldGenerator() {
+}
+
+void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+        variables_,
+        "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
+  GenerateCodecCode(printer);
+  printer->Print(
+    variables_,
+    ";\n"
+    "private $type_name$ $name$_;\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "  set {\n"
+    "    $name$_ = value;\n"
+    "  }\n"
+    "}\n\n");
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(
+      variables_,
+      "/// <summary>Gets whether the $descriptor_name$ field is set</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ bool Has$property_name$ {\n"
+      "  get { return $name$_ != null; }\n"
+      "}\n\n");
+    printer->Print(
+      variables_,
+      "/// <summary>Clears the value of the $descriptor_name$ field</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ void Clear$property_name$() {\n"
+      "  $name$_ = null;\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) {
+  GenerateParsingCode(printer, true);
+}
+
+void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  printer->Print(
+    variables_,
+    use_parse_context
+    ? "$type_name$ value = _single_$name$_codec.Read(ref input);\n"
+      "if ($has_not_property_check$ || value != $default_value$) {\n"
+      "  $property_name$ = value;\n"
+      "}\n"
+    : "$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) {
+  GenerateSerializationCode(printer, true);
+}
+
+void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  printer->Print(
+    variables_,
+    use_write_context
+    ? "if ($has_property_check$) {\n"
+      "  _single_$name$_codec.WriteTagAndValue(ref output, $property_name$);\n"
+      "}\n"
+    : "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) {
+  const char *text = "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n";
+  if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) {
+    text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.GetHashCode($property_name$);\n";
+  }
+  else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) {
+    text = "if ($has_property_check$) hash ^= pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.GetHashCode($property_name$);\n";
+  }
+  printer->Print(variables_, text);
+}
+
+void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
+  const char *text = "if ($property_name$ != other.$property_name$) return false;\n";
+  if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_FLOAT) {
+    text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableSingleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
+  }
+  else if (descriptor_->message_type()->field(0)->type() == FieldDescriptor::TYPE_DOUBLE) {
+    text = "if (!pbc::ProtobufEqualityComparers.BitwiseNullableDoubleEqualityComparer.Equals($property_name$, other.$property_name$)) return false;\n";
+  }
+  printer->Print(variables_, text);
+}
+
+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$)");
+  }
+}
+
+void WrapperFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
+    "  new pb::Extension<$extended_type$, $type_name$>($number$, ");
+  GenerateCodecCode(printer);
+  printer->Print(");\n");
+}
+
+WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
+    : WrapperFieldGenerator(descriptor, presenceIndex, options) {
+    SetCommonOneofFieldVariables(&variables_);
+}
+
+WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
+}
+
+void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
+  printer->Print(
+        variables_,
+        "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
+  GenerateCodecCode(printer);
+  printer->Print(";\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddPublicMemberAttributes(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.$oneof_case_name$;\n"
+    "  }\n"
+    "}\n");
+  if (SupportsPresenceApi(descriptor_)) {
+    printer->Print(
+      variables_,
+      "/// <summary>Gets whether the \"$descriptor_name$\" field is set</summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ bool Has$property_name$ {\n"
+      "  get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n"
+      "}\n");
+    printer->Print(
+      variables_,
+      "/// <summary> Clears the value of the oneof if it's currently set to \"$descriptor_name$\" </summary>\n");
+    AddPublicMemberAttributes(printer);
+    printer->Print(
+      variables_,
+      "$access_level$ void Clear$property_name$() {\n"
+      "  if ($has_property_check$) {\n"
+      "    Clear$oneof_property_name$();\n"
+      "  }\n"
+      "}\n");
+  }
+}
+
+void WrapperOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  GenerateParsingCode(printer, true);
+}
+
+void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
+  printer->Print(
+    variables_,
+    use_parse_context
+    ? "$property_name$ = _oneof_$name$_codec.Read(ref input);\n"
+    : "$property_name$ = _oneof_$name$_codec.Read(input);\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  GenerateSerializationCode(printer, true);
+}
+
+void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
+  // TODO: I suspect this is wrong...
+  printer->Print(
+    variables_,
+    use_write_context
+    ? "if ($has_property_check$) {\n"
+      "  _oneof_$name$_codec.WriteTagAndValue(ref output, ($type_name$) $oneof_name$_);\n"
+      "}\n"
+    : "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..cc8a313
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.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_CSHARP_WRAPPER_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class WrapperFieldGenerator : public FieldGeneratorBase {
+ public:
+  WrapperFieldGenerator(const FieldDescriptor* descriptor,
+                        int presenceIndex,
+                        const Options *options);
+  ~WrapperFieldGenerator();
+
+  WrapperFieldGenerator(const WrapperFieldGenerator&) = delete;
+  WrapperFieldGenerator& operator=(const WrapperFieldGenerator&) = delete;
+
+  virtual void GenerateCodecCode(io::Printer* printer) override;
+  virtual void GenerateCloningCode(io::Printer* printer) override;
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+  virtual void GenerateExtensionCode(io::Printer* printer) override;
+
+  virtual void WriteHash(io::Printer* printer) override;
+  virtual void WriteEquals(io::Printer* printer) override;
+  virtual void WriteToString(io::Printer* printer) override;
+
+ private:
+  bool is_value_type; // True for int32 etc; false for bytes and string
+};
+
+class WrapperOneofFieldGenerator : public WrapperFieldGenerator {
+ public:
+  WrapperOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             int presenceIndex,
+                             const Options *options);
+  ~WrapperOneofFieldGenerator();
+
+  WrapperOneofFieldGenerator(const WrapperOneofFieldGenerator&) = delete;
+  WrapperOneofFieldGenerator& operator=(const WrapperOneofFieldGenerator&) = delete;
+
+  virtual void GenerateMembers(io::Printer* printer) override;
+  virtual void GenerateMergingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer) override;
+  virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context) override;
+  virtual void GenerateSerializationCode(io::Printer* printer) override;
+  virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context) override;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
+};
+
+}  // 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
new file mode 100644
index 0000000..f1e26f8
--- /dev/null
+++ b/src/google/protobuf/compiler/importer.cc
@@ -0,0 +1,524 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+
+#ifdef _MSC_VER
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <memory>
+
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/compiler/parser.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/io/io_win32.h>
+
+#ifdef _WIN32
+#include <ctype.h>
+#endif
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#ifdef _WIN32
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::open;
+#endif
+
+// Returns true if the text looks like a Windows-style absolute path, starting
+// with a drive letter.  Example:  "C:\foo".  TODO(kenton):  Share this with
+// copy in command_line_interface.cc?
+static bool IsWindowsAbsolutePath(const std::string& text) {
+#if defined(_WIN32) || defined(__CYGWIN__)
+  return text.size() >= 3 && text[1] == ':' && isalpha(text[0]) &&
+         (text[2] == '/' || text[2] == '\\') && text.find_last_of(':') == 1;
+#else
+  return false;
+#endif
+}
+
+MultiFileErrorCollector::~MultiFileErrorCollector() {}
+
+// This class serves two purposes:
+// - It implements the ErrorCollector interface (used by Tokenizer and Parser)
+//   in terms of MultiFileErrorCollector, using a particular filename.
+// - It lets us check if any errors have occurred.
+class SourceTreeDescriptorDatabase::SingleFileErrorCollector
+    : public io::ErrorCollector {
+ public:
+  SingleFileErrorCollector(const std::string& filename,
+                           MultiFileErrorCollector* multi_file_error_collector)
+      : filename_(filename),
+        multi_file_error_collector_(multi_file_error_collector),
+        had_errors_(false) {}
+  ~SingleFileErrorCollector() override {}
+
+  bool had_errors() { return had_errors_; }
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(int line, int column, const std::string& message) override {
+    if (multi_file_error_collector_ != nullptr) {
+      multi_file_error_collector_->AddError(filename_, line, column, message);
+    }
+    had_errors_ = true;
+  }
+
+ private:
+  std::string filename_;
+  MultiFileErrorCollector* multi_file_error_collector_;
+  bool had_errors_;
+};
+
+// ===================================================================
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+    SourceTree* source_tree)
+    : source_tree_(source_tree),
+      fallback_database_(nullptr),
+      error_collector_(nullptr),
+      using_validation_error_collector_(false),
+      validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+    SourceTree* source_tree, DescriptorDatabase* fallback_database)
+    : source_tree_(source_tree),
+      fallback_database_(fallback_database),
+      error_collector_(nullptr),
+      using_validation_error_collector_(false),
+      validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
+
+bool SourceTreeDescriptorDatabase::FindFileByName(const std::string& filename,
+                                                  FileDescriptorProto* output) {
+  std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
+  if (input == nullptr) {
+    if (fallback_database_ != nullptr &&
+        fallback_database_->FindFileByName(filename, output)) {
+      return true;
+    }
+    if (error_collector_ != nullptr) {
+      error_collector_->AddError(filename, -1, 0,
+                                 source_tree_->GetLastErrorMessage());
+    }
+    return false;
+  }
+
+  // Set up the tokenizer and parser.
+  SingleFileErrorCollector file_error_collector(filename, error_collector_);
+  io::Tokenizer tokenizer(input.get(), &file_error_collector);
+
+  Parser parser;
+  if (error_collector_ != nullptr) {
+    parser.RecordErrorsTo(&file_error_collector);
+  }
+  if (using_validation_error_collector_) {
+    parser.RecordSourceLocationsTo(&source_locations_);
+  }
+
+  // Parse it.
+  output->set_name(filename);
+  return parser.Parse(&tokenizer, output) && !file_error_collector.had_errors();
+}
+
+bool SourceTreeDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  return false;
+}
+
+bool SourceTreeDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  return false;
+}
+
+// -------------------------------------------------------------------
+
+SourceTreeDescriptorDatabase::ValidationErrorCollector::
+    ValidationErrorCollector(SourceTreeDescriptorDatabase* owner)
+    : owner_(owner) {}
+
+SourceTreeDescriptorDatabase::ValidationErrorCollector::
+    ~ValidationErrorCollector() {}
+
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError(
+    const std::string& filename, const std::string& element_name,
+    const Message* descriptor, ErrorLocation location,
+    const std::string& message) {
+  if (owner_->error_collector_ == nullptr) return;
+
+  int line, column;
+  if (location == DescriptorPool::ErrorCollector::IMPORT) {
+    owner_->source_locations_.FindImport(descriptor, element_name, &line,
+                                         &column);
+  } else {
+    owner_->source_locations_.Find(descriptor, location, &line, &column);
+  }
+  owner_->error_collector_->AddError(filename, line, column, message);
+}
+
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning(
+    const std::string& filename, const std::string& element_name,
+    const Message* descriptor, ErrorLocation location,
+    const std::string& message) {
+  if (owner_->error_collector_ == nullptr) return;
+
+  int line, column;
+  if (location == DescriptorPool::ErrorCollector::IMPORT) {
+    owner_->source_locations_.FindImport(descriptor, element_name, &line,
+                                         &column);
+  } else {
+    owner_->source_locations_.Find(descriptor, location, &line, &column);
+  }
+  owner_->error_collector_->AddWarning(filename, line, column, message);
+}
+
+// ===================================================================
+
+Importer::Importer(SourceTree* source_tree,
+                   MultiFileErrorCollector* error_collector)
+    : database_(source_tree),
+      pool_(&database_, database_.GetValidationErrorCollector()) {
+  pool_.EnforceWeakDependencies(true);
+  database_.RecordErrorsTo(error_collector);
+}
+
+Importer::~Importer() {}
+
+const FileDescriptor* Importer::Import(const std::string& filename) {
+  return pool_.FindFileByName(filename);
+}
+
+void Importer::AddUnusedImportTrackFile(const std::string& file_name,
+                                        bool is_error) {
+  pool_.AddUnusedImportTrackFile(file_name, is_error);
+}
+
+void Importer::ClearUnusedImportTrackFiles() {
+  pool_.ClearUnusedImportTrackFiles();
+}
+
+
+// ===================================================================
+
+SourceTree::~SourceTree() {}
+
+std::string SourceTree::GetLastErrorMessage() { return "File not found."; }
+
+DiskSourceTree::DiskSourceTree() {}
+
+DiskSourceTree::~DiskSourceTree() {}
+
+static inline char LastChar(const std::string& str) {
+  return str[str.size() - 1];
+}
+
+// Given a path, returns an equivalent path with these changes:
+// - On Windows, any backslashes are replaced with forward slashes.
+// - Any instances of the directory "." are removed.
+// - Any consecutive '/'s are collapsed into a single slash.
+// Note that the resulting string may be empty.
+//
+// TODO(kenton):  It would be nice to handle "..", e.g. so that we can figure
+//   out that "foo/bar.proto" is inside "baz/../foo".  However, if baz is a
+//   symlink or doesn't exist, then things get complicated, and we can't
+//   actually determine this without investigating the filesystem, probably
+//   in non-portable ways.  So, we punt.
+//
+// TODO(kenton):  It would be nice to use realpath() here except that it
+//   resolves symbolic links.  This could cause problems if people place
+//   symbolic links in their source tree.  For example, if you executed:
+//     protoc --proto_path=foo foo/bar/baz.proto
+//   then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize
+//   to a path which does not appear to be under foo, and thus the compiler
+//   will complain that baz.proto is not inside the --proto_path.
+static std::string CanonicalizePath(std::string path) {
+#ifdef _WIN32
+  // The Win32 API accepts forward slashes as a path delimiter even though
+  // backslashes are standard.  Let's avoid confusion and use only forward
+  // slashes.
+  if (HasPrefixString(path, "\\\\")) {
+    // Avoid converting two leading backslashes.
+    path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true);
+  } else {
+    path = StringReplace(path, "\\", "/", true);
+  }
+#endif
+
+  std::vector<std::string> canonical_parts;
+  std::vector<std::string> parts = Split(
+      path, "/", true);  // Note:  Removes empty parts.
+  for (const std::string& part : parts) {
+    if (part == ".") {
+      // Ignore.
+    } else {
+      canonical_parts.push_back(part);
+    }
+  }
+  std::string result = Join(canonical_parts, "/");
+  if (!path.empty() && path[0] == '/') {
+    // Restore leading slash.
+    result = '/' + result;
+  }
+  if (!path.empty() && LastChar(path) == '/' && !result.empty() &&
+      LastChar(result) != '/') {
+    // Restore trailing slash.
+    result += '/';
+  }
+  return result;
+}
+
+static inline bool ContainsParentReference(const std::string& path) {
+  return path == ".." || HasPrefixString(path, "../") ||
+         HasSuffixString(path, "/..") || path.find("/../") != std::string::npos;
+}
+
+// Maps a file from an old location to a new one.  Typically, old_prefix is
+// a virtual path and new_prefix is its corresponding disk path.  Returns
+// false if the filename did not start with old_prefix, otherwise replaces
+// old_prefix with new_prefix and stores the result in *result.  Examples:
+//   string result;
+//   assert(ApplyMapping("foo/bar", "", "baz", &result));
+//   assert(result == "baz/foo/bar");
+//
+//   assert(ApplyMapping("foo/bar", "foo", "baz", &result));
+//   assert(result == "baz/bar");
+//
+//   assert(ApplyMapping("foo", "foo", "bar", &result));
+//   assert(result == "bar");
+//
+//   assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
+//   assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
+//   assert(!ApplyMapping("foobar", "foo", "baz", &result));
+static bool ApplyMapping(const std::string& filename,
+                         const std::string& old_prefix,
+                         const std::string& new_prefix, std::string* result) {
+  if (old_prefix.empty()) {
+    // old_prefix matches any relative path.
+    if (ContainsParentReference(filename)) {
+      // We do not allow the file name to use "..".
+      return false;
+    }
+    if (HasPrefixString(filename, "/") || IsWindowsAbsolutePath(filename)) {
+      // This is an absolute path, so it isn't matched by the empty string.
+      return false;
+    }
+    result->assign(new_prefix);
+    if (!result->empty()) result->push_back('/');
+    result->append(filename);
+    return true;
+  } else if (HasPrefixString(filename, old_prefix)) {
+    // old_prefix is a prefix of the filename.  Is it the whole filename?
+    if (filename.size() == old_prefix.size()) {
+      // Yep, it's an exact match.
+      *result = new_prefix;
+      return true;
+    } else {
+      // Not an exact match.  Is the next character a '/'?  Otherwise,
+      // this isn't actually a match at all.  E.g. the prefix "foo/bar"
+      // does not match the filename "foo/barbaz".
+      int after_prefix_start = -1;
+      if (filename[old_prefix.size()] == '/') {
+        after_prefix_start = old_prefix.size() + 1;
+      } else if (filename[old_prefix.size() - 1] == '/') {
+        // old_prefix is never empty, and canonicalized paths never have
+        // consecutive '/' characters.
+        after_prefix_start = old_prefix.size();
+      }
+      if (after_prefix_start != -1) {
+        // Yep.  So the prefixes are directories and the filename is a file
+        // inside them.
+        std::string after_prefix = filename.substr(after_prefix_start);
+        if (ContainsParentReference(after_prefix)) {
+          // We do not allow the file name to use "..".
+          return false;
+        }
+        result->assign(new_prefix);
+        if (!result->empty()) result->push_back('/');
+        result->append(after_prefix);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+void DiskSourceTree::MapPath(const std::string& virtual_path,
+                             const std::string& disk_path) {
+  mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path)));
+}
+
+DiskSourceTree::DiskFileToVirtualFileResult
+DiskSourceTree::DiskFileToVirtualFile(const std::string& disk_file,
+                                      std::string* virtual_file,
+                                      std::string* shadowing_disk_file) {
+  int mapping_index = -1;
+  std::string canonical_disk_file = CanonicalizePath(disk_file);
+
+  for (int i = 0; i < mappings_.size(); i++) {
+    // Apply the mapping in reverse.
+    if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path,
+                     mappings_[i].virtual_path, virtual_file)) {
+      // Success.
+      mapping_index = i;
+      break;
+    }
+  }
+
+  if (mapping_index == -1) {
+    return NO_MAPPING;
+  }
+
+  // Iterate through all mappings with higher precedence and verify that none
+  // of them map this file to some other existing file.
+  for (int i = 0; i < mapping_index; i++) {
+    if (ApplyMapping(*virtual_file, mappings_[i].virtual_path,
+                     mappings_[i].disk_path, shadowing_disk_file)) {
+      if (access(shadowing_disk_file->c_str(), F_OK) >= 0) {
+        // File exists.
+        return SHADOWED;
+      }
+    }
+  }
+  shadowing_disk_file->clear();
+
+  // Verify that we can open the file.  Note that this also has the side-effect
+  // of verifying that we are not canonicalizing away any non-existent
+  // directories.
+  std::unique_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
+  if (stream == nullptr) {
+    return CANNOT_OPEN;
+  }
+
+  return SUCCESS;
+}
+
+bool DiskSourceTree::VirtualFileToDiskFile(const std::string& virtual_file,
+                                           std::string* disk_file) {
+  std::unique_ptr<io::ZeroCopyInputStream> stream(
+      OpenVirtualFile(virtual_file, disk_file));
+  return stream != nullptr;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::Open(const std::string& filename) {
+  return OpenVirtualFile(filename, nullptr);
+}
+
+std::string DiskSourceTree::GetLastErrorMessage() {
+  return last_error_message_;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
+    const std::string& virtual_file, std::string* disk_file) {
+  if (virtual_file != CanonicalizePath(virtual_file) ||
+      ContainsParentReference(virtual_file)) {
+    // We do not allow importing of paths containing things like ".." or
+    // consecutive slashes since the compiler expects files to be uniquely
+    // identified by file name.
+    last_error_message_ =
+        "Backslashes, consecutive slashes, \".\", or \"..\" "
+        "are not allowed in the virtual path";
+    return nullptr;
+  }
+
+  for (const auto& mapping : mappings_) {
+    std::string temp_disk_file;
+    if (ApplyMapping(virtual_file, mapping.virtual_path, mapping.disk_path,
+                     &temp_disk_file)) {
+      io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file);
+      if (stream != nullptr) {
+        if (disk_file != nullptr) {
+          *disk_file = temp_disk_file;
+        }
+        return stream;
+      }
+
+      if (errno == EACCES) {
+        // The file exists but is not readable.
+        last_error_message_ =
+            "Read access is denied for file: " + temp_disk_file;
+        return nullptr;
+      }
+    }
+  }
+  last_error_message_ = "File not found.";
+  return nullptr;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile(
+    const std::string& filename) {
+  struct stat sb;
+  int ret = 0;
+  do {
+    ret = stat(filename.c_str(), &sb);
+  } while (ret != 0 && errno == EINTR);
+#if defined(_WIN32)
+  if (ret == 0 && sb.st_mode & S_IFDIR) {
+    last_error_message_ = "Input file is a directory.";
+    return nullptr;
+  }
+#else
+  if (ret == 0 && S_ISDIR(sb.st_mode)) {
+    last_error_message_ = "Input file is a directory.";
+    return nullptr;
+  }
+#endif
+  int file_descriptor;
+  do {
+    file_descriptor = open(filename.c_str(), O_RDONLY);
+  } while (file_descriptor < 0 && errno == EINTR);
+  if (file_descriptor >= 0) {
+    io::FileInputStream* result = new io::FileInputStream(file_descriptor);
+    result->SetCloseOnDelete(true);
+    return result;
+  } else {
+    return nullptr;
+  }
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
new file mode 100644
index 0000000..2fb88b9
--- /dev/null
+++ b/src/google/protobuf/compiler/importer.h
@@ -0,0 +1,338 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 is the public interface to the .proto file parser.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
+#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/compiler/parser.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class ZeroCopyInputStream;
+}
+
+namespace compiler {
+
+// Defined in this file.
+class Importer;
+class MultiFileErrorCollector;
+class SourceTree;
+class DiskSourceTree;
+
+// TODO(kenton):  Move all SourceTree stuff to a separate file?
+
+// An implementation of DescriptorDatabase which loads files from a SourceTree
+// and parses them.
+//
+// Note:  This class is not thread-safe since it maintains a table of source
+//   code locations for error reporting.  However, when a DescriptorPool wraps
+//   a DescriptorDatabase, it uses mutex locking to make sure only one method
+//   of the database is called at a time, even if the DescriptorPool is used
+//   from multiple threads.  Therefore, there is only a problem if you create
+//   multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase
+//   and use them from multiple threads.
+//
+// Note:  This class does not implement FindFileContainingSymbol() or
+//   FindFileContainingExtension(); these will always return false.
+class PROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase {
+ public:
+  SourceTreeDescriptorDatabase(SourceTree* source_tree);
+
+  // If non-NULL, fallback_database will be checked if a file doesn't exist in
+  // the specified source_tree.
+  SourceTreeDescriptorDatabase(SourceTree* source_tree,
+                               DescriptorDatabase* fallback_database);
+  ~SourceTreeDescriptorDatabase() override;
+
+  // Instructs the SourceTreeDescriptorDatabase to report any parse errors
+  // to the given MultiFileErrorCollector.  This should be called before
+  // parsing.  error_collector must remain valid until either this method
+  // is called again or the SourceTreeDescriptorDatabase is destroyed.
+  void RecordErrorsTo(MultiFileErrorCollector* error_collector) {
+    error_collector_ = error_collector;
+  }
+
+  // Gets a DescriptorPool::ErrorCollector which records errors to the
+  // MultiFileErrorCollector specified with RecordErrorsTo().  This collector
+  // has the ability to determine exact line and column numbers of errors
+  // from the information given to it by the DescriptorPool.
+  DescriptorPool::ErrorCollector* GetValidationErrorCollector() {
+    using_validation_error_collector_ = true;
+    return &validation_error_collector_;
+  }
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+
+ private:
+  class SingleFileErrorCollector;
+
+  SourceTree* source_tree_;
+  DescriptorDatabase* fallback_database_;
+  MultiFileErrorCollector* error_collector_;
+
+  class PROTOBUF_EXPORT ValidationErrorCollector
+      : public DescriptorPool::ErrorCollector {
+   public:
+    ValidationErrorCollector(SourceTreeDescriptorDatabase* owner);
+    ~ValidationErrorCollector() override;
+
+    // implements ErrorCollector ---------------------------------------
+    void AddError(const std::string& filename, const std::string& element_name,
+                  const Message* descriptor, ErrorLocation location,
+                  const std::string& message) override;
+
+    void AddWarning(const std::string& filename,
+                    const std::string& element_name, const Message* descriptor,
+                    ErrorLocation location,
+                    const std::string& message) override;
+
+   private:
+    SourceTreeDescriptorDatabase* owner_;
+  };
+  friend class ValidationErrorCollector;
+
+  bool using_validation_error_collector_;
+  SourceLocationTable source_locations_;
+  ValidationErrorCollector validation_error_collector_;
+};
+
+// Simple interface for parsing .proto files.  This wraps the process
+// of opening the file, parsing it with a Parser, recursively parsing all its
+// imports, and then cross-linking the results to produce a FileDescriptor.
+//
+// This is really just a thin wrapper around SourceTreeDescriptorDatabase.
+// You may find that SourceTreeDescriptorDatabase is more flexible.
+//
+// TODO(kenton):  I feel like this class is not well-named.
+class PROTOBUF_EXPORT Importer {
+ public:
+  Importer(SourceTree* source_tree, MultiFileErrorCollector* error_collector);
+  ~Importer();
+
+  // Import the given file and build a FileDescriptor representing it.  If
+  // the file is already in the DescriptorPool, the existing FileDescriptor
+  // will be returned.  The FileDescriptor is property of the DescriptorPool,
+  // and will remain valid until it is destroyed.  If any errors occur, they
+  // will be reported using the error collector and Import() will return NULL.
+  //
+  // A particular Importer object will only report errors for a particular
+  // file once.  All future attempts to import the same file will return NULL
+  // without reporting any errors.  The idea is that you might want to import
+  // a lot of files without seeing the same errors over and over again.  If
+  // you want to see errors for the same files repeatedly, you can use a
+  // separate Importer object to import each one (but use the same
+  // DescriptorPool so that they can be cross-linked).
+  const FileDescriptor* Import(const std::string& filename);
+
+  // The DescriptorPool in which all imported FileDescriptors and their
+  // contents are stored.
+  inline const DescriptorPool* pool() const { return &pool_; }
+
+  void AddUnusedImportTrackFile(const std::string& file_name,
+                                bool is_error = false);
+  void ClearUnusedImportTrackFiles();
+
+
+ private:
+  SourceTreeDescriptorDatabase database_;
+  DescriptorPool pool_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer);
+};
+
+// If the importer encounters problems while trying to import the proto files,
+// it reports them to a MultiFileErrorCollector.
+class PROTOBUF_EXPORT MultiFileErrorCollector {
+ public:
+  inline MultiFileErrorCollector() {}
+  virtual ~MultiFileErrorCollector();
+
+  // Line and column numbers are zero-based.  A line number of -1 indicates
+  // an error with the entire file (e.g. "not found").
+  virtual void AddError(const std::string& filename, int line, int column,
+                        const std::string& message) = 0;
+
+  virtual void AddWarning(const std::string& /* filename */, int /* line */,
+                          int /* column */, const std::string& /* message */) {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector);
+};
+
+// Abstract interface which represents a directory tree containing proto files.
+// Used by the default implementation of Importer to resolve import statements
+// Most users will probably want to use the DiskSourceTree implementation,
+// below.
+class PROTOBUF_EXPORT SourceTree {
+ public:
+  inline SourceTree() {}
+  virtual ~SourceTree();
+
+  // Open the given file and return a stream that reads it, or NULL if not
+  // found.  The caller takes ownership of the returned object.  The filename
+  // must be a path relative to the root of the source tree and must not
+  // contain "." or ".." components.
+  virtual io::ZeroCopyInputStream* Open(const std::string& filename) = 0;
+
+  // If Open() returns NULL, calling this method immediately will return an
+  // description of the error.
+  // Subclasses should implement this method and return a meaningful value for
+  // better error reporting.
+  // TODO(xiaofeng): change this to a pure virtual function.
+  virtual std::string GetLastErrorMessage();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree);
+};
+
+// An implementation of SourceTree which loads files from locations on disk.
+// Multiple mappings can be set up to map locations in the DiskSourceTree to
+// locations in the physical filesystem.
+class PROTOBUF_EXPORT DiskSourceTree : public SourceTree {
+ public:
+  DiskSourceTree();
+  ~DiskSourceTree() override;
+
+  // Map a path on disk to a location in the SourceTree.  The path may be
+  // either a file or a directory.  If it is a directory, the entire tree
+  // under it will be mapped to the given virtual location.  To map a directory
+  // to the root of the source tree, pass an empty string for virtual_path.
+  //
+  // If multiple mapped paths apply when opening a file, they will be searched
+  // in order.  For example, if you do:
+  //   MapPath("bar", "foo/bar");
+  //   MapPath("", "baz");
+  // and then you do:
+  //   Open("bar/qux");
+  // the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux,
+  // returning the first one that opens successfully.
+  //
+  // disk_path may be an absolute path or relative to the current directory,
+  // just like a path you'd pass to open().
+  void MapPath(const std::string& virtual_path, const std::string& disk_path);
+
+  // Return type for DiskFileToVirtualFile().
+  enum DiskFileToVirtualFileResult {
+    SUCCESS,
+    SHADOWED,
+    CANNOT_OPEN,
+    NO_MAPPING
+  };
+
+  // Given a path to a file on disk, find a virtual path mapping to that
+  // file.  The first mapping created with MapPath() whose disk_path contains
+  // the filename is used.  However, that virtual path may not actually be
+  // usable to open the given file.  Possible return values are:
+  // * SUCCESS: The mapping was found.  *virtual_file is filled in so that
+  //   calling Open(*virtual_file) will open the file named by disk_file.
+  // * SHADOWED: A mapping was found, but using Open() to open this virtual
+  //   path will end up returning some different file.  This is because some
+  //   other mapping with a higher precedence also matches this virtual path
+  //   and maps it to a different file that exists on disk.  *virtual_file
+  //   is filled in as it would be in the SUCCESS case.  *shadowing_disk_file
+  //   is filled in with the disk path of the file which would be opened if
+  //   you were to call Open(*virtual_file).
+  // * CANNOT_OPEN: The mapping was found and was not shadowed, but the
+  //   file specified cannot be opened.  When this value is returned,
+  //   errno will indicate the reason the file cannot be opened.  *virtual_file
+  //   will be set to the virtual path as in the SUCCESS case, even though
+  //   it is not useful.
+  // * NO_MAPPING: Indicates that no mapping was found which contains this
+  //   file.
+  DiskFileToVirtualFileResult DiskFileToVirtualFile(
+      const std::string& disk_file, std::string* virtual_file,
+      std::string* shadowing_disk_file);
+
+  // Given a virtual path, find the path to the file on disk.
+  // Return true and update disk_file with the on-disk path if the file exists.
+  // Return false and leave disk_file untouched if the file doesn't exist.
+  bool VirtualFileToDiskFile(const std::string& virtual_file,
+                             std::string* disk_file);
+
+  // implements SourceTree -------------------------------------------
+  io::ZeroCopyInputStream* Open(const std::string& filename) override;
+
+  std::string GetLastErrorMessage() override;
+
+ private:
+  struct Mapping {
+    std::string virtual_path;
+    std::string disk_path;
+
+    inline Mapping(const std::string& virtual_path_param,
+                   const std::string& disk_path_param)
+        : virtual_path(virtual_path_param), disk_path(disk_path_param) {}
+  };
+  std::vector<Mapping> mappings_;
+  std::string last_error_message_;
+
+  // Like Open(), but returns the on-disk path in disk_file if disk_file is
+  // non-NULL and the file could be successfully opened.
+  io::ZeroCopyInputStream* OpenVirtualFile(const std::string& virtual_file,
+                                           std::string* disk_file);
+
+  // Like Open() but given the actual on-disk path.
+  io::ZeroCopyInputStream* OpenDiskFile(const std::string& filename);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree);
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
new file mode 100644
index 0000000..d2810ad
--- /dev/null
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -0,0 +1,548 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/importer.h>
+
+#include <memory>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+namespace {
+
+bool FileExists(const std::string& path) {
+  return File::Exists(path);
+}
+
+#define EXPECT_SUBSTRING(needle, haystack) \
+  EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack))
+
+class MockErrorCollector : public MultiFileErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() override {}
+
+  std::string text_;
+  std::string warning_text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const std::string& filename, int line, int column,
+                const std::string& message) override {
+    strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
+                              message);
+  }
+
+  void AddWarning(const std::string& filename, int line, int column,
+                  const std::string& message) override {
+    strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n", filename, line,
+                              column, message);
+  }
+};
+
+// -------------------------------------------------------------------
+
+// A dummy implementation of SourceTree backed by a simple map.
+class MockSourceTree : public SourceTree {
+ public:
+  MockSourceTree() {}
+  ~MockSourceTree() override {}
+
+  void AddFile(const std::string& name, const char* contents) {
+    files_[name] = contents;
+  }
+
+  // implements SourceTree -------------------------------------------
+  io::ZeroCopyInputStream* Open(const std::string& filename) override {
+    const char* contents = FindPtrOrNull(files_, filename);
+    if (contents == nullptr) {
+      return nullptr;
+    } else {
+      return new io::ArrayInputStream(contents, strlen(contents));
+    }
+  }
+
+  std::string GetLastErrorMessage() override { return "File not found."; }
+
+ private:
+  std::unordered_map<std::string, const char*> files_;
+};
+
+// ===================================================================
+
+class ImporterTest : public testing::Test {
+ protected:
+  ImporterTest() : importer_(&source_tree_, &error_collector_) {}
+
+  void AddFile(const std::string& filename, const char* text) {
+    source_tree_.AddFile(filename, text);
+  }
+
+  // Return the collected error text
+  std::string warning() const { return error_collector_.warning_text_; }
+
+  MockErrorCollector error_collector_;
+  MockSourceTree source_tree_;
+  Importer importer_;
+};
+
+TEST_F(ImporterTest, Import) {
+  // Test normal importing.
+  AddFile("foo.proto",
+          "syntax = \"proto2\";\n"
+          "message Foo {}\n");
+
+  const FileDescriptor* file = importer_.Import("foo.proto");
+  EXPECT_EQ("", error_collector_.text_);
+  ASSERT_TRUE(file != nullptr);
+
+  ASSERT_EQ(1, file->message_type_count());
+  EXPECT_EQ("Foo", file->message_type(0)->name());
+
+  // Importing again should return same object.
+  EXPECT_EQ(file, importer_.Import("foo.proto"));
+}
+
+TEST_F(ImporterTest, ImportNested) {
+  // Test that importing a file which imports another file works.
+  AddFile("foo.proto",
+          "syntax = \"proto2\";\n"
+          "import \"bar.proto\";\n"
+          "message Foo {\n"
+          "  optional Bar bar = 1;\n"
+          "}\n");
+  AddFile("bar.proto",
+          "syntax = \"proto2\";\n"
+          "message Bar {}\n");
+
+  // Note that both files are actually parsed by the first call to Import()
+  // here, since foo.proto imports bar.proto.  The second call just returns
+  // the same ProtoFile for bar.proto which was constructed while importing
+  // foo.proto.  We test that this is the case below by checking that bar
+  // is among foo's dependencies (by pointer).
+  const FileDescriptor* foo = importer_.Import("foo.proto");
+  const FileDescriptor* bar = importer_.Import("bar.proto");
+  EXPECT_EQ("", error_collector_.text_);
+  ASSERT_TRUE(foo != nullptr);
+  ASSERT_TRUE(bar != nullptr);
+
+  // Check that foo's dependency is the same object as bar.
+  ASSERT_EQ(1, foo->dependency_count());
+  EXPECT_EQ(bar, foo->dependency(0));
+
+  // Check that foo properly cross-links bar.
+  ASSERT_EQ(1, foo->message_type_count());
+  ASSERT_EQ(1, bar->message_type_count());
+  ASSERT_EQ(1, foo->message_type(0)->field_count());
+  ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE,
+            foo->message_type(0)->field(0)->type());
+  EXPECT_EQ(bar->message_type(0),
+            foo->message_type(0)->field(0)->message_type());
+}
+
+TEST_F(ImporterTest, FileNotFound) {
+  // Error:  Parsing a file that doesn't exist.
+  EXPECT_TRUE(importer_.Import("foo.proto") == nullptr);
+  EXPECT_EQ("foo.proto:-1:0: File not found.\n", error_collector_.text_);
+}
+
+TEST_F(ImporterTest, ImportNotFound) {
+  // Error:  Importing a file that doesn't exist.
+  AddFile("foo.proto",
+          "syntax = \"proto2\";\n"
+          "import \"bar.proto\";\n");
+
+  EXPECT_TRUE(importer_.Import("foo.proto") == nullptr);
+  EXPECT_EQ(
+      "bar.proto:-1:0: File not found.\n"
+      "foo.proto:1:0: Import \"bar.proto\" was not found or had errors.\n",
+      error_collector_.text_);
+}
+
+TEST_F(ImporterTest, RecursiveImport) {
+  // Error:  Recursive import.
+  AddFile("recursive1.proto",
+          "syntax = \"proto2\";\n"
+          "\n"
+          "import \"recursive2.proto\";\n");
+  AddFile("recursive2.proto",
+          "syntax = \"proto2\";\n"
+          "import \"recursive1.proto\";\n");
+
+  EXPECT_TRUE(importer_.Import("recursive1.proto") == nullptr);
+  EXPECT_EQ(
+      "recursive1.proto:2:0: File recursively imports itself: "
+      "recursive1.proto "
+      "-> recursive2.proto -> recursive1.proto\n"
+      "recursive2.proto:1:0: Import \"recursive1.proto\" was not found "
+      "or had errors.\n"
+      "recursive1.proto:2:0: Import \"recursive2.proto\" was not found "
+      "or had errors.\n",
+      error_collector_.text_);
+}
+
+TEST_F(ImporterTest, RecursiveImportSelf) {
+  // Error:  Recursive import.
+  AddFile("recursive.proto",
+          "syntax = \"proto2\";\n"
+          "\n"
+          "import \"recursive.proto\";\n");
+
+  EXPECT_TRUE(importer_.Import("recursive.proto") == nullptr);
+  EXPECT_EQ(
+      "recursive.proto:2:0: File recursively imports itself: "
+      "recursive.proto -> recursive.proto\n",
+      error_collector_.text_);
+}
+
+TEST_F(ImporterTest, LiteRuntimeImport) {
+  // Error:  Recursive import.
+  AddFile("bar.proto",
+          "syntax = \"proto2\";\n"
+          "option optimize_for = LITE_RUNTIME;\n");
+  AddFile("foo.proto",
+          "syntax = \"proto2\";\n"
+          "import \"bar.proto\";\n");
+
+  EXPECT_TRUE(importer_.Import("foo.proto") == nullptr);
+  EXPECT_EQ(
+      "foo.proto:1:0: Files that do not use optimize_for = LITE_RUNTIME "
+      "cannot import files which do use this option.  This file is not "
+      "lite, but it imports \"bar.proto\" which is.\n",
+      error_collector_.text_);
+}
+
+
+// ===================================================================
+
+class DiskSourceTreeTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_1");
+    dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2");
+
+    for (int i = 0; i < dirnames_.size(); i++) {
+      if (FileExists(dirnames_[i])) {
+        File::DeleteRecursively(dirnames_[i], NULL, NULL);
+      }
+      GOOGLE_CHECK_OK(File::CreateDir(dirnames_[i], 0777));
+    }
+  }
+
+  void TearDown() override {
+    for (int i = 0; i < dirnames_.size(); i++) {
+      if (FileExists(dirnames_[i])) {
+        File::DeleteRecursively(dirnames_[i], NULL, NULL);
+      }
+    }
+  }
+
+  void AddFile(const std::string& filename, const char* contents) {
+    GOOGLE_CHECK_OK(File::SetContents(filename, contents, true));
+  }
+
+  void AddSubdir(const std::string& dirname) {
+    GOOGLE_CHECK_OK(File::CreateDir(dirname, 0777));
+  }
+
+  void ExpectFileContents(const std::string& filename,
+                          const char* expected_contents) {
+    std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+
+    ASSERT_FALSE(input == nullptr);
+
+    // Read all the data from the file.
+    std::string file_contents;
+    const void* data;
+    int size;
+    while (input->Next(&data, &size)) {
+      file_contents.append(reinterpret_cast<const char*>(data), size);
+    }
+
+    EXPECT_EQ(expected_contents, file_contents);
+  }
+
+  void ExpectCannotOpenFile(const std::string& filename,
+                            const std::string& error_message) {
+    std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+    EXPECT_TRUE(input == nullptr);
+    EXPECT_EQ(error_message, source_tree_.GetLastErrorMessage());
+  }
+
+  DiskSourceTree source_tree_;
+
+  // Paths of two on-disk directories to use during the test.
+  std::vector<std::string> dirnames_;
+};
+
+TEST_F(DiskSourceTreeTest, MapRoot) {
+  // Test opening a file in a directory that is mapped to the root of the
+  // source tree.
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  source_tree_.MapPath("", dirnames_[0]);
+
+  ExpectFileContents("foo", "Hello World!");
+  ExpectCannotOpenFile("bar", "File not found.");
+}
+
+TEST_F(DiskSourceTreeTest, MapDirectory) {
+  // Test opening a file in a directory that is mapped to somewhere other
+  // than the root of the source tree.
+
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  source_tree_.MapPath("baz", dirnames_[0]);
+
+  ExpectFileContents("baz/foo", "Hello World!");
+  ExpectCannotOpenFile("baz/bar", "File not found.");
+  ExpectCannotOpenFile("foo", "File not found.");
+  ExpectCannotOpenFile("bar", "File not found.");
+
+  // Non-canonical file names should not work.
+  ExpectCannotOpenFile("baz//foo",
+                       "Backslashes, consecutive slashes, \".\", or \"..\" are "
+                       "not allowed in the virtual path");
+  ExpectCannotOpenFile("baz/../baz/foo",
+                       "Backslashes, consecutive slashes, \".\", or \"..\" are "
+                       "not allowed in the virtual path");
+  ExpectCannotOpenFile("baz/./foo",
+                       "Backslashes, consecutive slashes, \".\", or \"..\" are "
+                       "not allowed in the virtual path");
+  ExpectCannotOpenFile("baz/foo/", "File not found.");
+}
+
+TEST_F(DiskSourceTreeTest, NoParent) {
+  // Test that we cannot open files in a parent of a mapped directory.
+
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  AddSubdir(dirnames_[0] + "/bar");
+  AddFile(dirnames_[0] + "/bar/baz", "Blah.");
+  source_tree_.MapPath("", dirnames_[0] + "/bar");
+
+  ExpectFileContents("baz", "Blah.");
+  ExpectCannotOpenFile("../foo",
+                       "Backslashes, consecutive slashes, \".\", or \"..\" are "
+                       "not allowed in the virtual path");
+  ExpectCannotOpenFile("../bar/baz",
+                       "Backslashes, consecutive slashes, \".\", or \"..\" are "
+                       "not allowed in the virtual path");
+}
+
+TEST_F(DiskSourceTreeTest, MapFile) {
+  // Test opening a file that is mapped directly into the source tree.
+
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  source_tree_.MapPath("foo", dirnames_[0] + "/foo");
+
+  ExpectFileContents("foo", "Hello World!");
+  ExpectCannotOpenFile("bar", "File not found.");
+}
+
+TEST_F(DiskSourceTreeTest, SearchMultipleDirectories) {
+  // Test mapping and searching multiple directories.
+
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
+  AddFile(dirnames_[1] + "/bar", "Goodbye World!");
+  source_tree_.MapPath("", dirnames_[0]);
+  source_tree_.MapPath("", dirnames_[1]);
+
+  ExpectFileContents("foo", "Hello World!");
+  ExpectFileContents("bar", "Goodbye World!");
+  ExpectCannotOpenFile("baz", "File not found.");
+}
+
+TEST_F(DiskSourceTreeTest, OrderingTrumpsSpecificity) {
+  // Test that directories are always searched in order, even when a latter
+  // directory is more-specific than a former one.
+
+  // Create the "bar" directory so we can put a file in it.
+  GOOGLE_CHECK_OK(File::CreateDir(dirnames_[0] + "/bar", 0777));
+
+  // Add files and map paths.
+  AddFile(dirnames_[0] + "/bar/foo", "Hello World!");
+  AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
+  source_tree_.MapPath("", dirnames_[0]);
+  source_tree_.MapPath("bar", dirnames_[1]);
+
+  // Check.
+  ExpectFileContents("bar/foo", "Hello World!");
+}
+
+TEST_F(DiskSourceTreeTest, DiskFileToVirtualFile) {
+  // Test DiskFileToVirtualFile.
+
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
+  source_tree_.MapPath("bar", dirnames_[0]);
+  source_tree_.MapPath("bar", dirnames_[1]);
+
+  std::string virtual_file;
+  std::string shadowing_disk_file;
+
+  EXPECT_EQ(DiskSourceTree::NO_MAPPING,
+            source_tree_.DiskFileToVirtualFile("/foo", &virtual_file,
+                                               &shadowing_disk_file));
+
+  EXPECT_EQ(DiskSourceTree::SHADOWED,
+            source_tree_.DiskFileToVirtualFile(
+                dirnames_[1] + "/foo", &virtual_file, &shadowing_disk_file));
+  EXPECT_EQ("bar/foo", virtual_file);
+  EXPECT_EQ(dirnames_[0] + "/foo", shadowing_disk_file);
+
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile(
+                dirnames_[1] + "/baz", &virtual_file, &shadowing_disk_file));
+  EXPECT_EQ("bar/baz", virtual_file);
+
+  EXPECT_EQ(DiskSourceTree::SUCCESS,
+            source_tree_.DiskFileToVirtualFile(
+                dirnames_[0] + "/foo", &virtual_file, &shadowing_disk_file));
+  EXPECT_EQ("bar/foo", virtual_file);
+}
+
+TEST_F(DiskSourceTreeTest, DiskFileToVirtualFileCanonicalization) {
+  // Test handling of "..", ".", etc. in DiskFileToVirtualFile().
+
+  source_tree_.MapPath("dir1", "..");
+  source_tree_.MapPath("dir2", "../../foo");
+  source_tree_.MapPath("dir3", "./foo/bar/.");
+  source_tree_.MapPath("dir4", ".");
+  source_tree_.MapPath("", "/qux");
+  source_tree_.MapPath("dir5", "/quux/");
+
+  std::string virtual_file;
+  std::string shadowing_disk_file;
+
+  // "../.." should not be considered to be under "..".
+  EXPECT_EQ(DiskSourceTree::NO_MAPPING,
+            source_tree_.DiskFileToVirtualFile("../../baz", &virtual_file,
+                                               &shadowing_disk_file));
+
+  // "/foo" is not mapped (it should not be misinterpreted as being under ".").
+  EXPECT_EQ(DiskSourceTree::NO_MAPPING,
+            source_tree_.DiskFileToVirtualFile("/foo", &virtual_file,
+                                               &shadowing_disk_file));
+
+#ifdef WIN32
+  // "C:\foo" is not mapped (it should not be misinterpreted as being under
+  // ".").
+  EXPECT_EQ(DiskSourceTree::NO_MAPPING,
+            source_tree_.DiskFileToVirtualFile("C:\\foo", &virtual_file,
+                                               &shadowing_disk_file));
+#endif  // WIN32
+
+  // But "../baz" should be.
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile("../baz", &virtual_file,
+                                               &shadowing_disk_file));
+  EXPECT_EQ("dir1/baz", virtual_file);
+
+  // "../../foo/baz" is under "../../foo".
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile("../../foo/baz", &virtual_file,
+                                               &shadowing_disk_file));
+  EXPECT_EQ("dir2/baz", virtual_file);
+
+  // "foo/./bar/baz" is under "./foo/bar/.".
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile("foo/bar/baz", &virtual_file,
+                                               &shadowing_disk_file));
+  EXPECT_EQ("dir3/baz", virtual_file);
+
+  // "bar" is under ".".
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile("bar", &virtual_file,
+                                               &shadowing_disk_file));
+  EXPECT_EQ("dir4/bar", virtual_file);
+
+  // "/qux/baz" is under "/qux".
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile("/qux/baz", &virtual_file,
+                                               &shadowing_disk_file));
+  EXPECT_EQ("baz", virtual_file);
+
+  // "/quux/bar" is under "/quux".
+  EXPECT_EQ(DiskSourceTree::CANNOT_OPEN,
+            source_tree_.DiskFileToVirtualFile("/quux/bar", &virtual_file,
+                                               &shadowing_disk_file));
+  EXPECT_EQ("dir5/bar", virtual_file);
+}
+
+TEST_F(DiskSourceTreeTest, VirtualFileToDiskFile) {
+  // Test VirtualFileToDiskFile.
+
+  AddFile(dirnames_[0] + "/foo", "Hello World!");
+  AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
+  AddFile(dirnames_[1] + "/quux", "This file should not be hidden.");
+  source_tree_.MapPath("bar", dirnames_[0]);
+  source_tree_.MapPath("bar", dirnames_[1]);
+
+  // Existent files, shadowed and non-shadowed case.
+  std::string disk_file;
+  EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", &disk_file));
+  EXPECT_EQ(dirnames_[0] + "/foo", disk_file);
+  EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/quux", &disk_file));
+  EXPECT_EQ(dirnames_[1] + "/quux", disk_file);
+
+  // Nonexistent file in existent directory and vice versa.
+  std::string not_touched = "not touched";
+  EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("bar/baz", &not_touched));
+  EXPECT_EQ("not touched", not_touched);
+  EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", &not_touched));
+  EXPECT_EQ("not touched", not_touched);
+
+  // Accept NULL as output parameter.
+  EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", nullptr));
+  EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", nullptr));
+}
+
+}  // namespace
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/context.cc b/src/google/protobuf/compiler/java/context.cc
new file mode 100644
index 0000000..cdc0d44
--- /dev/null
+++ b/src/google/protobuf/compiler/java/context.cc
@@ -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.
+
+#include <google/protobuf/compiler/java/context.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/field.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+Context::Context(const FileDescriptor* file, const Options& options)
+    : name_resolver_(new ClassNameResolver), options_(options) {
+  InitializeFieldGeneratorInfo(file);
+}
+
+Context::~Context() {}
+
+ClassNameResolver* Context::GetNameResolver() const {
+  return name_resolver_.get();
+}
+
+namespace {
+// Whether two fields have conflicting accessors (assuming name1 and name2
+// are different). name1 and name2 are field1 and field2's camel-case name
+// respectively.
+bool IsConflicting(const FieldDescriptor* field1, const std::string& name1,
+                   const FieldDescriptor* field2, const std::string& name2,
+                   std::string* info) {
+  if (field1->is_repeated()) {
+    if (field2->is_repeated()) {
+      // Both fields are repeated.
+      return false;
+    } else {
+      // field1 is repeated, and field2 is not.
+      if (name1 + "Count" == name2) {
+        *info = "both repeated field \"" + field1->name() + "\" and singular " +
+                "field \"" + field2->name() + "\" generate the method \"" +
+                "get" + name1 + "Count()\"";
+        return true;
+      }
+      if (name1 + "List" == name2) {
+        *info = "both repeated field \"" + field1->name() + "\" and singular " +
+                "field \"" + field2->name() + "\" generate the method \"" +
+                "get" + name1 + "List()\"";
+        return true;
+      }
+      // Well, there are obviously many more conflicting cases, but it probably
+      // doesn't worth the effort to exhaust all of them because they rarely
+      // happen and as we are continuing adding new methods/changing existing
+      // methods the number of different conflicting cases will keep growing.
+      // We can just add more cases here when they are found in the real world.
+      return false;
+    }
+  } else {
+    if (field2->is_repeated()) {
+      return IsConflicting(field2, name2, field1, name1, info);
+    } else {
+      // None of the two fields are repeated.
+      return false;
+    }
+  }
+}
+}  // namespace
+
+void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    InitializeFieldGeneratorInfoForMessage(file->message_type(i));
+  }
+}
+
+void Context::InitializeFieldGeneratorInfoForMessage(
+    const Descriptor* message) {
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    InitializeFieldGeneratorInfoForMessage(message->nested_type(i));
+  }
+  std::vector<const FieldDescriptor*> fields;
+  fields.reserve(message->field_count());
+  for (int i = 0; i < message->field_count(); ++i) {
+    fields.push_back(message->field(i));
+  }
+  InitializeFieldGeneratorInfoForFields(fields);
+
+  for (int i = 0; i < message->oneof_decl_count(); ++i) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    OneofGeneratorInfo info;
+    info.name = UnderscoresToCamelCase(oneof->name(), false);
+    info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true);
+    oneof_generator_info_map_[oneof] = info;
+  }
+}
+
+void Context::InitializeFieldGeneratorInfoForFields(
+    const std::vector<const FieldDescriptor*>& fields) {
+  // Find out all fields that conflict with some other field in the same
+  // message.
+  std::vector<bool> is_conflict(fields.size());
+  std::vector<std::string> conflict_reason(fields.size());
+  for (int i = 0; i < fields.size(); ++i) {
+    const FieldDescriptor* field = fields[i];
+    const std::string& name = UnderscoresToCapitalizedCamelCase(field);
+    for (int j = i + 1; j < fields.size(); ++j) {
+      const FieldDescriptor* other = fields[j];
+      const std::string& other_name = UnderscoresToCapitalizedCamelCase(other);
+      if (name == other_name) {
+        is_conflict[i] = is_conflict[j] = true;
+        conflict_reason[i] = conflict_reason[j] =
+            "capitalized name of field \"" + field->name() +
+            "\" conflicts with field \"" + other->name() + "\"";
+      } else if (IsConflicting(field, name, other, other_name,
+                               &conflict_reason[j])) {
+        is_conflict[i] = is_conflict[j] = true;
+        conflict_reason[i] = conflict_reason[j];
+      }
+    }
+    if (is_conflict[i]) {
+      GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting "
+                   << "with another field: " << conflict_reason[i];
+    }
+  }
+  for (int i = 0; i < fields.size(); ++i) {
+    const FieldDescriptor* field = fields[i];
+    FieldGeneratorInfo info;
+    info.name = CamelCaseFieldName(field);
+    info.capitalized_name = UnderscoresToCapitalizedCamelCase(field);
+    // For fields conflicting with some other fields, we append the field
+    // number to their field names in generated code to avoid conflicts.
+    if (is_conflict[i]) {
+      info.name += StrCat(field->number());
+      info.capitalized_name += StrCat(field->number());
+      info.disambiguated_reason = conflict_reason[i];
+    }
+    field_generator_info_map_[field] = info;
+  }
+}
+
+const FieldGeneratorInfo* Context::GetFieldGeneratorInfo(
+    const FieldDescriptor* field) const {
+  const FieldGeneratorInfo* result =
+      FindOrNull(field_generator_info_map_, field);
+  if (result == NULL) {
+    GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: "
+               << field->full_name();
+  }
+  return result;
+}
+
+const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
+    const OneofDescriptor* oneof) const {
+  const OneofGeneratorInfo* result =
+      FindOrNull(oneof_generator_info_map_, oneof);
+  if (result == NULL) {
+    GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: "
+               << oneof->name();
+  }
+  return result;
+}
+
+// Does this message class have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
+  return options_.enforce_lite ||
+         descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/context.h b/src/google/protobuf/compiler/java/context.h
new file mode 100644
index 0000000..c224ab7
--- /dev/null
+++ b/src/google/protobuf/compiler/java/context.h
@@ -0,0 +1,113 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_CONTEXT_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/options.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class Descriptor;
+class EnumDescriptor;
+namespace compiler {
+namespace java {
+class ClassNameResolver;  // name_resolver.h
+}
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+struct FieldGeneratorInfo;
+struct OneofGeneratorInfo;
+// A context object holds the information that is shared among all code
+// generators.
+class Context {
+ public:
+  Context(const FileDescriptor* file, const Options& options);
+  ~Context();
+
+  // Get the name resolver associated with this context. The resolver
+  // can be used to map descriptors to Java class names.
+  ClassNameResolver* GetNameResolver() const;
+
+  // Get the FieldGeneratorInfo for a given field.
+  const FieldGeneratorInfo* GetFieldGeneratorInfo(
+      const FieldDescriptor* field) const;
+
+  // Get the OneofGeneratorInfo for a given oneof.
+  const OneofGeneratorInfo* GetOneofGeneratorInfo(
+      const OneofDescriptor* oneof) const;
+
+  const Options& options() const { return options_; }
+
+  // Enforces all the files (including transitive dependencies) to use
+  // LiteRuntime.
+
+  bool EnforceLite() const { return options_.enforce_lite; }
+
+  // Does this message class have generated parsing, serialization, and other
+  // standard methods for which reflection-based fallback implementations exist?
+  bool HasGeneratedMethods(const Descriptor* descriptor) const;
+
+ private:
+  void InitializeFieldGeneratorInfo(const FileDescriptor* file);
+  void InitializeFieldGeneratorInfoForMessage(const Descriptor* message);
+  void InitializeFieldGeneratorInfoForFields(
+      const std::vector<const FieldDescriptor*>& fields);
+
+  std::unique_ptr<ClassNameResolver> name_resolver_;
+  std::map<const FieldDescriptor*, FieldGeneratorInfo>
+      field_generator_info_map_;
+  std::map<const OneofDescriptor*, OneofGeneratorInfo>
+      oneof_generator_info_map_;
+  Options options_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__
diff --git a/src/google/protobuf/compiler/java/doc_comment.cc b/src/google/protobuf/compiler/java/doc_comment.cc
new file mode 100644
index 0000000..066bff6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/doc_comment.cc
@@ -0,0 +1,444 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/doc_comment.h>
+
+#include <vector>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+std::string EscapeJavadoc(const std::string& input) {
+  std::string result;
+  result.reserve(input.size() * 2);
+
+  char prev = '*';
+
+  for (std::string::size_type i = 0; i < input.size(); i++) {
+    char c = input[i];
+    switch (c) {
+      case '*':
+        // Avoid "/*".
+        if (prev == '/') {
+          result.append("&#42;");
+        } else {
+          result.push_back(c);
+        }
+        break;
+      case '/':
+        // Avoid "*/".
+        if (prev == '*') {
+          result.append("&#47;");
+        } else {
+          result.push_back(c);
+        }
+        break;
+      case '@':
+        // '@' starts javadoc tags including the @deprecated tag, which will
+        // cause a compile-time error if inserted before a declaration that
+        // does not have a corresponding @Deprecated annotation.
+        result.append("&#64;");
+        break;
+      case '<':
+        // Avoid interpretation as HTML.
+        result.append("&lt;");
+        break;
+      case '>':
+        // Avoid interpretation as HTML.
+        result.append("&gt;");
+        break;
+      case '&':
+        // Avoid interpretation as HTML.
+        result.append("&amp;");
+        break;
+      case '\\':
+        // Java interprets Unicode escape sequences anywhere!
+        result.append("&#92;");
+        break;
+      default:
+        result.push_back(c);
+        break;
+    }
+
+    prev = c;
+  }
+
+  return result;
+}
+
+static void WriteDocCommentBodyForLocation(io::Printer* printer,
+                                           const SourceLocation& location) {
+  std::string comments = location.leading_comments.empty()
+                             ? location.trailing_comments
+                             : location.leading_comments;
+  if (!comments.empty()) {
+    // TODO(kenton):  Ideally we should parse the comment text as Markdown and
+    //   write it back as HTML, but this requires a Markdown parser.  For now
+    //   we just use <pre> to get fixed-width text formatting.
+
+    // If the comment itself contains block comment start or end markers,
+    // HTML-escape them so that they don't accidentally close the doc comment.
+    comments = EscapeJavadoc(comments);
+
+    std::vector<std::string> lines = Split(comments, "\n");
+    while (!lines.empty() && lines.back().empty()) {
+      lines.pop_back();
+    }
+
+    printer->Print(" * <pre>\n");
+    for (int i = 0; i < lines.size(); i++) {
+      // Most lines should start with a space.  Watch out for lines that start
+      // with a /, since putting that right after the leading asterisk will
+      // close the comment.
+      if (!lines[i].empty() && lines[i][0] == '/') {
+        printer->Print(" * $line$\n", "line", lines[i]);
+      } else {
+        printer->Print(" *$line$\n", "line", lines[i]);
+      }
+    }
+    printer->Print(
+        " * </pre>\n"
+        " *\n");
+  }
+}
+
+template <typename DescriptorType>
+static void WriteDocCommentBody(io::Printer* printer,
+                                const DescriptorType* descriptor) {
+  SourceLocation location;
+  if (descriptor->GetSourceLocation(&location)) {
+    WriteDocCommentBodyForLocation(printer, location);
+  }
+}
+
+static std::string FirstLineOf(const std::string& value) {
+  std::string result = value;
+
+  std::string::size_type pos = result.find_first_of('\n');
+  if (pos != std::string::npos) {
+    result.erase(pos);
+  }
+
+  // If line ends in an opening brace, make it "{ ... }" so it looks nice.
+  if (!result.empty() && result[result.size() - 1] == '{') {
+    result.append(" ... }");
+  }
+
+  return result;
+}
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, message);
+  printer->Print(
+      " * Protobuf type {@code $fullname$}\n"
+      " */\n",
+      "fullname", EscapeJavadoc(message->full_name()));
+}
+
+void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
+  // We start the comment with the main body based on the comments from the
+  // .proto file (if present). We then continue with the field declaration,
+  // e.g.:
+  //   optional string foo = 5;
+  // And then we end with the javadoc tags if applicable.
+  // If the field is a group, the debug string might end with {.
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, field);
+  printer->Print(" * <code>$def$</code>\n", "def",
+                 EscapeJavadoc(FirstLineOf(field->DebugString())));
+  printer->Print(" */\n");
+}
+
+void WriteDeprecatedJavadoc(io::Printer* printer, const FieldDescriptor* field,
+                            const FieldAccessorType type) {
+  if (!field->options().deprecated()) {
+    return;
+  }
+
+  // Lite codegen does not annotate set & clear methods with @Deprecated.
+  if (field->file()->options().optimize_for() == FileOptions::LITE_RUNTIME &&
+      (type == SETTER || type == CLEARER)) {
+    return;
+  }
+
+  std::string startLine = "0";
+  SourceLocation location;
+  if (field->GetSourceLocation(&location)) {
+    startLine = std::to_string(location.start_line);
+  }
+
+  printer->Print(" * @deprecated $name$ is deprecated.\n", "name",
+                 field->full_name());
+  printer->Print(" *     See $file$;l=$line$\n", "file", field->file()->name(),
+                 "line", startLine);
+}
+
+void WriteFieldAccessorDocComment(io::Printer* printer,
+                                  const FieldDescriptor* field,
+                                  const FieldAccessorType type,
+                                  const bool builder) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, field);
+  printer->Print(" * <code>$def$</code>\n", "def",
+                 EscapeJavadoc(FirstLineOf(field->DebugString())));
+  WriteDeprecatedJavadoc(printer, field, type);
+  switch (type) {
+    case HAZZER:
+      printer->Print(" * @return Whether the $name$ field is set.\n", "name",
+                     field->camelcase_name());
+      break;
+    case GETTER:
+      printer->Print(" * @return The $name$.\n", "name",
+                     field->camelcase_name());
+      break;
+    case SETTER:
+      printer->Print(" * @param value The $name$ to set.\n", "name",
+                     field->camelcase_name());
+      break;
+    case CLEARER:
+      // Print nothing
+      break;
+    // Repeated
+    case LIST_COUNT:
+      printer->Print(" * @return The count of $name$.\n", "name",
+                     field->camelcase_name());
+      break;
+    case LIST_GETTER:
+      printer->Print(" * @return A list containing the $name$.\n", "name",
+                     field->camelcase_name());
+      break;
+    case LIST_INDEXED_GETTER:
+      printer->Print(" * @param index The index of the element to return.\n");
+      printer->Print(" * @return The $name$ at the given index.\n", "name",
+                     field->camelcase_name());
+      break;
+    case LIST_INDEXED_SETTER:
+      printer->Print(" * @param index The index to set the value at.\n");
+      printer->Print(" * @param value The $name$ to set.\n", "name",
+                     field->camelcase_name());
+      break;
+    case LIST_ADDER:
+      printer->Print(" * @param value The $name$ to add.\n", "name",
+                     field->camelcase_name());
+      break;
+    case LIST_MULTI_ADDER:
+      printer->Print(" * @param values The $name$ to add.\n", "name",
+                     field->camelcase_name());
+      break;
+  }
+  if (builder) {
+    printer->Print(" * @return This builder for chaining.\n");
+  }
+  printer->Print(" */\n");
+}
+
+void WriteFieldEnumValueAccessorDocComment(io::Printer* printer,
+                                           const FieldDescriptor* field,
+                                           const FieldAccessorType type,
+                                           const bool builder) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, field);
+  printer->Print(" * <code>$def$</code>\n", "def",
+                 EscapeJavadoc(FirstLineOf(field->DebugString())));
+  WriteDeprecatedJavadoc(printer, field, type);
+  switch (type) {
+    case HAZZER:
+      // Should never happen
+      break;
+    case GETTER:
+      printer->Print(
+          " * @return The enum numeric value on the wire for $name$.\n", "name",
+          field->camelcase_name());
+      break;
+    case SETTER:
+      printer->Print(
+          " * @param value The enum numeric value on the wire for $name$ to "
+          "set.\n",
+          "name", field->camelcase_name());
+      break;
+    case CLEARER:
+      // Print nothing
+      break;
+    // Repeated
+    case LIST_COUNT:
+      // Should never happen
+      break;
+    case LIST_GETTER:
+      printer->Print(
+          " * @return A list containing the enum numeric values on the wire "
+          "for $name$.\n",
+          "name", field->camelcase_name());
+      break;
+    case LIST_INDEXED_GETTER:
+      printer->Print(" * @param index The index of the value to return.\n");
+      printer->Print(
+          " * @return The enum numeric value on the wire of $name$ at the "
+          "given index.\n",
+          "name", field->camelcase_name());
+      break;
+    case LIST_INDEXED_SETTER:
+      printer->Print(" * @param index The index to set the value at.\n");
+      printer->Print(
+          " * @param value The enum numeric value on the wire for $name$ to "
+          "set.\n",
+          "name", field->camelcase_name());
+      break;
+    case LIST_ADDER:
+      printer->Print(
+          " * @param value The enum numeric value on the wire for $name$ to "
+          "add.\n",
+          "name", field->camelcase_name());
+      break;
+    case LIST_MULTI_ADDER:
+      printer->Print(
+          " * @param values The enum numeric values on the wire for $name$ to "
+          "add.\n",
+          "name", field->camelcase_name());
+      break;
+  }
+  if (builder) {
+    printer->Print(" * @return This builder for chaining.\n");
+  }
+  printer->Print(" */\n");
+}
+
+void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
+                                             const FieldDescriptor* field,
+                                             const FieldAccessorType type,
+                                             const bool builder) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, field);
+  printer->Print(" * <code>$def$</code>\n", "def",
+                 EscapeJavadoc(FirstLineOf(field->DebugString())));
+  WriteDeprecatedJavadoc(printer, field, type);
+  switch (type) {
+    case HAZZER:
+      // Should never happen
+      break;
+    case GETTER:
+      printer->Print(" * @return The bytes for $name$.\n", "name",
+                     field->camelcase_name());
+      break;
+    case SETTER:
+      printer->Print(" * @param value The bytes for $name$ to set.\n", "name",
+                     field->camelcase_name());
+      break;
+    case CLEARER:
+      // Print nothing
+      break;
+    // Repeated
+    case LIST_COUNT:
+      // Should never happen
+      break;
+    case LIST_GETTER:
+      printer->Print(" * @return A list containing the bytes for $name$.\n",
+                     "name", field->camelcase_name());
+      break;
+    case LIST_INDEXED_GETTER:
+      printer->Print(" * @param index The index of the value to return.\n");
+      printer->Print(" * @return The bytes of the $name$ at the given index.\n",
+                     "name", field->camelcase_name());
+      break;
+    case LIST_INDEXED_SETTER:
+      printer->Print(" * @param index The index to set the value at.\n");
+      printer->Print(" * @param value The bytes of the $name$ to set.\n",
+                     "name", field->camelcase_name());
+      break;
+    case LIST_ADDER:
+      printer->Print(" * @param value The bytes of the $name$ to add.\n",
+                     "name", field->camelcase_name());
+      break;
+    case LIST_MULTI_ADDER:
+      printer->Print(" * @param values The bytes of the $name$ to add.\n",
+                     "name", field->camelcase_name());
+      break;
+  }
+  if (builder) {
+    printer->Print(" * @return This builder for chaining.\n");
+  }
+  printer->Print(" */\n");
+}
+
+// Enum
+
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, enum_);
+  printer->Print(
+      " * Protobuf enum {@code $fullname$}\n"
+      " */\n",
+      "fullname", EscapeJavadoc(enum_->full_name()));
+}
+
+void WriteEnumValueDocComment(io::Printer* printer,
+                              const EnumValueDescriptor* value) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, value);
+  printer->Print(
+      " * <code>$def$</code>\n"
+      " */\n",
+      "def", EscapeJavadoc(FirstLineOf(value->DebugString())));
+}
+
+void WriteServiceDocComment(io::Printer* printer,
+                            const ServiceDescriptor* service) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, service);
+  printer->Print(
+      " * Protobuf service {@code $fullname$}\n"
+      " */\n",
+      "fullname", EscapeJavadoc(service->full_name()));
+}
+
+void WriteMethodDocComment(io::Printer* printer,
+                           const MethodDescriptor* method) {
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, method);
+  printer->Print(
+      " * <code>$def$</code>\n"
+      " */\n",
+      "def", EscapeJavadoc(FirstLineOf(method->DebugString())));
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/doc_comment.h b/src/google/protobuf/compiler/java/doc_comment.h
new file mode 100644
index 0000000..7f68778
--- /dev/null
+++ b/src/google/protobuf/compiler/java/doc_comment.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
+
+#include <google/protobuf/descriptor.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+enum FieldAccessorType {
+  HAZZER,
+  GETTER,
+  SETTER,
+  CLEARER,
+  // Repeated
+  LIST_COUNT,
+  LIST_GETTER,
+  LIST_INDEXED_GETTER,
+  LIST_INDEXED_SETTER,
+  LIST_ADDER,
+  LIST_MULTI_ADDER
+};
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
+void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field);
+void WriteFieldAccessorDocComment(io::Printer* printer,
+                                  const FieldDescriptor* field,
+                                  const FieldAccessorType type,
+                                  const bool builder = false);
+void WriteFieldEnumValueAccessorDocComment(io::Printer* printer,
+                                           const FieldDescriptor* field,
+                                           const FieldAccessorType type,
+                                           const bool builder = false);
+void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
+                                             const FieldDescriptor* field,
+                                             const FieldAccessorType type,
+                                             const bool builder = false);
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_);
+void WriteEnumValueDocComment(io::Printer* printer,
+                              const EnumValueDescriptor* value);
+void WriteServiceDocComment(io::Printer* printer,
+                            const ServiceDescriptor* service);
+void WriteMethodDocComment(io::Printer* printer,
+                           const MethodDescriptor* method);
+
+// Exposed for testing only.
+PROTOC_EXPORT std::string EscapeJavadoc(const std::string& input);
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
diff --git a/src/google/protobuf/compiler/java/doc_comment_unittest.cc b/src/google/protobuf/compiler/java/doc_comment_unittest.cc
new file mode 100644
index 0000000..3fcdf07
--- /dev/null
+++ b/src/google/protobuf/compiler/java/doc_comment_unittest.cc
@@ -0,0 +1,56 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/compiler/java/doc_comment.h>
+
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+namespace {
+
+TEST(JavaDocCommentTest, Escaping) {
+  EXPECT_EQ("foo /&#42; bar *&#47; baz", EscapeJavadoc("foo /* bar */ baz"));
+  EXPECT_EQ("foo /&#42;&#47; baz", EscapeJavadoc("foo /*/ baz"));
+  EXPECT_EQ("{&#64;foo}", EscapeJavadoc("{@foo}"));
+  EXPECT_EQ("&lt;i&gt;&amp;&lt;/i&gt;", EscapeJavadoc("<i>&</i>"));
+  EXPECT_EQ("foo&#92;u1234bar", EscapeJavadoc("foo\\u1234bar"));
+  EXPECT_EQ("&#64;deprecated", EscapeJavadoc("@deprecated"));
+}
+
+}  // namespace
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/enum.cc b/src/google/protobuf/compiler/java/enum.cc
new file mode 100644
index 0000000..0cab93c
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum.cc
@@ -0,0 +1,397 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/enum.h>
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
+                             bool immutable_api, Context* context)
+    : descriptor_(descriptor),
+      immutable_api_(immutable_api),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    const EnumValueDescriptor* value = descriptor_->value(i);
+    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);
+    }
+  }
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::Generate(io::Printer* printer) {
+  WriteEnumDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
+  printer->Print(
+      "$deprecation$public enum $classname$\n"
+      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
+      "classname", descriptor_->name(), "deprecation",
+      descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "");
+  printer->Annotate("classname", descriptor_);
+  printer->Indent();
+
+  bool ordinal_is_index = true;
+  std::string index_text = "ordinal()";
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    if (canonical_values_[i]->index() != i) {
+      ordinal_is_index = false;
+      index_text = "index";
+      break;
+    }
+  }
+
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    std::map<std::string, std::string> vars;
+    vars["name"] = canonical_values_[i]->name();
+    vars["index"] = StrCat(canonical_values_[i]->index());
+    vars["number"] = StrCat(canonical_values_[i]->number());
+    WriteEnumValueDocComment(printer, canonical_values_[i]);
+    if (canonical_values_[i]->options().deprecated()) {
+      printer->Print("@java.lang.Deprecated\n");
+    }
+    if (ordinal_is_index) {
+      printer->Print(vars, "$name$($number$),\n");
+    } else {
+      printer->Print(vars, "$name$($index$, $number$),\n");
+    }
+    printer->Annotate("name", canonical_values_[i]);
+  }
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    if (ordinal_is_index) {
+      printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", "");
+    } else {
+      printer->Print("${$UNRECOGNIZED$}$(-1, -1),\n", "{", "", "}", "");
+    }
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  printer->Print(
+      ";\n"
+      "\n");
+
+  // -----------------------------------------------------------------
+
+  for (int i = 0; i < aliases_.size(); i++) {
+    std::map<std::string, std::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");
+    printer->Annotate("name", aliases_[i].value);
+  }
+
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    std::map<std::string, std::string> vars;
+    vars["name"] = descriptor_->value(i)->name();
+    vars["number"] = StrCat(descriptor_->value(i)->number());
+    vars["{"] = "";
+    vars["}"] = "";
+    vars["deprecation"] = descriptor_->value(i)->options().deprecated()
+                              ? "@java.lang.Deprecated "
+                              : "";
+    WriteEnumValueDocComment(printer, descriptor_->value(i));
+    printer->Print(vars,
+                   "$deprecation$public static final int ${$$name$_VALUE$}$ = "
+                   "$number$;\n");
+    printer->Annotate("{", "}", descriptor_->value(i));
+  }
+  printer->Print("\n");
+
+  // -----------------------------------------------------------------
+
+  printer->Print(
+      "\n"
+      "public final int getNumber() {\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    if (ordinal_is_index) {
+      printer->Print(
+          "  if (this == UNRECOGNIZED) {\n"
+          "    throw new java.lang.IllegalArgumentException(\n"
+          "        \"Can't get the number of an unknown enum value.\");\n"
+          "  }\n");
+    } else {
+      printer->Print(
+          "  if (index == -1) {\n"
+          "    throw new java.lang.IllegalArgumentException(\n"
+          "        \"Can't get the number of an unknown enum value.\");\n"
+          "  }\n");
+    }
+  }
+  printer->Print(
+      "  return value;\n"
+      "}\n"
+      "\n"
+      "/**\n"
+      " * @param value The numeric wire value of the corresponding enum "
+      "entry.\n"
+      " * @return The enum associated with the given numeric wire value.\n"
+      " * @deprecated Use {@link #forNumber(int)} instead.\n"
+      " */\n"
+      "@java.lang.Deprecated\n"
+      "public static $classname$ valueOf(int value) {\n"
+      "  return forNumber(value);\n"
+      "}\n"
+      "\n"
+      "/**\n"
+      " * @param value The numeric wire value of the corresponding enum "
+      "entry.\n"
+      " * @return The enum associated with the given numeric wire value.\n"
+      " */\n"
+      "public static $classname$ forNumber(int value) {\n"
+      "  switch (value) {\n",
+      "classname", descriptor_->name());
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    printer->Print("case $number$: return $name$;\n", "name",
+                   canonical_values_[i]->name(), "number",
+                   StrCat(canonical_values_[i]->number()));
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+      "    default: return null;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
+      "    internalGetValueMap() {\n"
+      "  return internalValueMap;\n"
+      "}\n"
+      "private static final com.google.protobuf.Internal.EnumLiteMap<\n"
+      "    $classname$> internalValueMap =\n"
+      "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
+      "        public $classname$ findValueByNumber(int number) {\n"
+      "          return $classname$.forNumber(number);\n"
+      "        }\n"
+      "      };\n"
+      "\n",
+      "classname", descriptor_->name());
+
+  // -----------------------------------------------------------------
+  // Reflection
+
+  if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
+    printer->Print(
+        "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
+        "    getValueDescriptor() {\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      if (ordinal_is_index) {
+        printer->Print(
+            "  if (this == UNRECOGNIZED) {\n"
+            "    throw new java.lang.IllegalStateException(\n"
+            "        \"Can't get the descriptor of an unrecognized enum "
+            "value.\");\n"
+            "  }\n");
+      } else {
+        printer->Print(
+            "  if (index == -1) {\n"
+            "    throw new java.lang.IllegalStateException(\n"
+            "        \"Can't get the descriptor of an unrecognized enum "
+            "value.\");\n"
+            "  }\n");
+      }
+    }
+    printer->Print(
+        "  return getDescriptor().getValues().get($index_text$);\n"
+        "}\n"
+        "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
+        "    getDescriptorForType() {\n"
+        "  return getDescriptor();\n"
+        "}\n"
+        "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
+        "    getDescriptor() {\n",
+        "index_text", index_text);
+
+    // TODO(kenton):  Cache statically?  Note that we can't access descriptors
+    //   at module init time because it wouldn't work with descriptor.proto, but
+    //   we can cache the value the first time getDescriptor() is called.
+    if (descriptor_->containing_type() == NULL) {
+      // The class generated for the File fully populates the descriptor with
+      // extensions in both the mutable and immutable cases. (In the mutable api
+      // this is accomplished by attempting to load the immutable outer class).
+      printer->Print(
+          "  return $file$.getDescriptor().getEnumTypes().get($index$);\n",
+          "file",
+          name_resolver_->GetClassName(descriptor_->file(), immutable_api_),
+          "index", StrCat(descriptor_->index()));
+    } else {
+      printer->Print(
+          "  return $parent$.$descriptor$.getEnumTypes().get($index$);\n",
+          "parent",
+          name_resolver_->GetClassName(descriptor_->containing_type(),
+                                       immutable_api_),
+          "descriptor",
+          descriptor_->containing_type()
+                  ->options()
+                  .no_standard_descriptor_accessor()
+              ? "getDefaultInstance().getDescriptorForType()"
+              : "getDescriptor()",
+          "index", StrCat(descriptor_->index()));
+    }
+
+    printer->Print(
+        "}\n"
+        "\n"
+        "private static final $classname$[] VALUES = ",
+        "classname", descriptor_->name());
+
+    if (CanUseEnumValues()) {
+      // If the constants we are going to output are exactly the ones we
+      // have declared in the Java enum in the same order, then we can use
+      // the values() method that the Java compiler automatically generates
+      // for every enum.
+      printer->Print("values();\n");
+    } else {
+      printer->Print("getStaticValuesArray();\n");
+      printer->Print("private static $classname$[] getStaticValuesArray() {\n",
+                     "classname", descriptor_->name());
+      printer->Indent();
+      printer->Print(
+          "return new $classname$[] {\n"
+          "  ",
+          "classname", descriptor_->name());
+      for (int i = 0; i < descriptor_->value_count(); i++) {
+        printer->Print("$name$, ", "name", descriptor_->value(i)->name());
+      }
+      printer->Print(
+          "\n"
+          "};\n");
+      printer->Outdent();
+      printer->Print("}");
+    }
+
+    printer->Print(
+        "\n"
+        "public static $classname$ valueOf(\n"
+        "    com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
+        "  if (desc.getType() != getDescriptor()) {\n"
+        "    throw new java.lang.IllegalArgumentException(\n"
+        "      \"EnumValueDescriptor is not for this type.\");\n"
+        "  }\n",
+        "classname", descriptor_->name());
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          "  if (desc.getIndex() == -1) {\n"
+          "    return UNRECOGNIZED;\n"
+          "  }\n");
+    }
+    printer->Print(
+        "  return VALUES[desc.getIndex()];\n"
+        "}\n"
+        "\n");
+
+    if (!ordinal_is_index) {
+      printer->Print("private final int index;\n");
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  printer->Print("private final int value;\n\n");
+
+  if (ordinal_is_index) {
+    printer->Print("private $classname$(int value) {\n", "classname",
+                   descriptor_->name());
+  } else {
+    printer->Print("private $classname$(int index, int value) {\n", "classname",
+                   descriptor_->name());
+  }
+  if (HasDescriptorMethods(descriptor_, context_->EnforceLite()) &&
+      !ordinal_is_index) {
+    printer->Print("  this.index = index;\n");
+  }
+  printer->Print(
+      "  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 EnumGenerator::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
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/enum.h b/src/google/protobuf/compiler/java/enum.h
new file mode 100644
index 0000000..0a2c363
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum.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.
+
+// 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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_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 java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class EnumGenerator {
+ public:
+  EnumGenerator(const EnumDescriptor* descriptor, bool immutable_api,
+                Context* context);
+  ~EnumGenerator();
+
+  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.
+  std::vector<const EnumValueDescriptor*> canonical_values_;
+
+  struct Alias {
+    const EnumValueDescriptor* value;
+    const EnumValueDescriptor* canonical_value;
+  };
+  std::vector<Alias> aliases_;
+
+  bool immutable_api_;
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  bool CanUseEnumValues();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
diff --git a/src/google/protobuf/compiler/java/enum_field.cc b/src/google/protobuf/compiler/java/enum_field.cc
new file mode 100644
index 0000000..8e8a28d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum_field.cc
@@ -0,0 +1,1157 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/enum_field.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
+                      int builderBitIndex, const FieldGeneratorInfo* info,
+                      ClassNameResolver* name_resolver,
+                      std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->enum_type());
+  (*variables)["kt_type"] = (*variables)["type"];
+  (*variables)["mutable_type"] =
+      name_resolver->GetMutableClassName(descriptor->enum_type());
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_number"] =
+      StrCat(descriptor->default_value_enum()->number());
+  (*variables)["tag"] = StrCat(
+      static_cast<int32_t>(internal::WireFormat::MakeTag(descriptor)));
+  (*variables)["tag_size"] = StrCat(
+      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)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["on_changed"] = "onChanged();";
+  // Use deprecated valueOf() method to be compatible with old generated code
+  // for v2.5.0/v2.6.1.
+  // TODO(xiaofeng): Use "forNumber" when we no longer support compatibility
+  // with v2.5.0/v2.6.1, and remove the @SuppressWarnings annotations.
+  (*variables)["for_number"] = "valueOf";
+
+  if (HasHasbit(descriptor)) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+    (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["set_has_field_bit_builder"] =
+        GenerateSetBit(builderBitIndex) + ";";
+    (*variables)["clear_has_field_bit_builder"] =
+        GenerateClearBit(builderBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["set_has_field_bit_builder"] = "";
+    (*variables)["clear_has_field_bit_builder"] = "";
+
+    (*variables)["is_field_present_message"] =
+        (*variables)["name"] + "_ != " + (*variables)["default"] +
+        ".getNumber()";
+  }
+
+  // For repeated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*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
+
+// ===================================================================
+
+ImmutableEnumFieldGenerator::ImmutableEnumFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+                   context->GetFieldGeneratorInfo(descriptor), name_resolver_,
+                   &variables_);
+}
+
+ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() {}
+
+int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+int ImmutableEnumFieldGenerator::GetNumBitsForBuilder() const {
+  return GetNumBitsForMessage();
+}
+
+void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(variables_,
+                   "$deprecation$int get$capitalized_name$Value();\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_, "private int $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "@java.lang.Override $deprecation$public boolean "
+                   "${$has$capitalized_name$$}$() {\n"
+                   "  return $get_has_field_bit_message$;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override $deprecation$public int "
+                   "${$get$capitalized_name$Value$}$() {\n"
+                   "  return $name$_;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override $deprecation$public $type$ "
+                 "${$get$capitalized_name$$}$() {\n"
+                 "  @SuppressWarnings(\"deprecation\")\n"
+                 "  $type$ result = $type$.$for_number$($name$_);\n"
+                 "  return result == null ? $unknown$ : result;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private int $name$_ = $default_number$;\n");
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "@java.lang.Override $deprecation$public boolean "
+                   "${$has$capitalized_name$$}$() {\n"
+                   "  return $get_has_field_bit_builder$;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override $deprecation$public int "
+                   "${$get$capitalized_name$Value$}$() {\n"
+                   "  return $name$_;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+    printer->Print(variables_,
+                   "$deprecation$public Builder "
+                   "${$set$capitalized_name$Value$}$(int value) {\n"
+                   "  $set_has_field_bit_builder$\n"
+                   "  $name$_ = value;\n"
+                   "  $on_changed$\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  @SuppressWarnings(\"deprecation\")\n"
+                 "  $type$ result = $type$.$for_number$($name$_);\n"
+                 "  return result == null ? $unknown$ : result;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "  if (value == null) {\n"
+                 "    throw new NullPointerException();\n"
+                 "  }\n"
+                 "  $set_has_field_bit_builder$\n"
+                 "  $name$_ = value.getNumber();\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  $clear_has_field_bit_builder$\n"
+      "  $name$_ = $default_number$;\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ var $kt_name$: $kt_type$\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+        "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+        "}\n");
+  }
+}
+
+void ImmutableEnumFieldGenerator::GenerateFieldBuilderInitializationCode(
+    io::Printer* printer) const {
+  // noop for enums
+}
+
+void ImmutableEnumFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default_number$;\n");
+}
+
+void ImmutableEnumFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = $default_number$;\n"
+                 "$clear_has_field_bit_builder$\n");
+}
+
+void ImmutableEnumFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    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 ImmutableEnumFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    printer->Print(variables_,
+                   "if ($get_has_field_bit_from_local$) {\n"
+                   "  $set_has_field_bit_to_local$;\n"
+                   "}\n");
+  }
+  printer->Print(variables_, "result.$name$_ = $name$_;\n");
+}
+
+void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+                   "$name$_ = input.readEnum();\n"
+                   "$set_has_field_bit_builder$\n");
+  } else {
+    printer->Print(variables_,
+                   "int tmpRaw = input.readEnum();\n"
+                   "$type$ tmpValue =\n"
+                   "    $type$.forNumber(tmpRaw);\n"
+                   "if (tmpValue == null) {\n"
+                   "  mergeUnknownVarintField($number$, tmpRaw);\n"
+                   "} else {\n"
+                   "  $name$_ = tmpRaw;\n"
+                   "  $set_has_field_bit_builder$\n"
+                   "}\n");
+  }
+}
+
+void ImmutableEnumFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($is_field_present_message$) {\n"
+                 "  output.writeEnum($number$, $name$_);\n"
+                 "}\n");
+}
+
+void ImmutableEnumFieldGenerator::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 ImmutableEnumFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "if ($name$_ != other.$name$_) return false;\n");
+}
+
+void ImmutableEnumFieldGenerator::GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+                 "hash = (37 * hash) + $constant_name$;\n"
+                 "hash = (53 * hash) + $name$_;\n");
+}
+
+std::string ImmutableEnumFieldGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+// ===================================================================
+
+ImmutableEnumOneofFieldGenerator::ImmutableEnumOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : ImmutableEnumFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
+                                  context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableEnumOneofFieldGenerator::~ImmutableEnumOneofFieldGenerator() {}
+
+void ImmutableEnumOneofFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    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");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    @SuppressWarnings(\"deprecation\")\n"
+                 "    $type$ result = $type$.$for_number$(\n"
+                 "        (java.lang.Integer) $oneof_name$_);\n"
+                 "    return result == null ? $unknown$ : result;\n"
+                 "  }\n"
+                 "  return $default$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
+        "  if ($has_oneof_case_message$) {\n"
+        "    return ((java.lang.Integer) $oneof_name$_).intValue();\n"
+        "  }\n"
+        "  return $default_number$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+    printer->Print(variables_,
+                   "$deprecation$public Builder "
+                   "${$set$capitalized_name$Value$}$(int value) {\n"
+                   "  $set_oneof_case_message$;\n"
+                   "  $oneof_name$_ = value;\n"
+                   "  $on_changed$\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    @SuppressWarnings(\"deprecation\")\n"
+                 "    $type$ result = $type$.$for_number$(\n"
+                 "        (java.lang.Integer) $oneof_name$_);\n"
+                 "    return result == null ? $unknown$ : result;\n"
+                 "  }\n"
+                 "  return $default$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$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"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    $clear_oneof_case_message$;\n"
+      "    $oneof_name$_ = null;\n"
+      "    $on_changed$\n"
+      "  }\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableEnumOneofFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  // No-op: Enum fields in oneofs are correctly cleared by clearing the oneof
+}
+
+void ImmutableEnumOneofFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  result.$oneof_name$_ = $oneof_name$_;\n"
+                 "}\n");
+}
+
+void ImmutableEnumOneofFieldGenerator::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 ImmutableEnumOneofFieldGenerator::GenerateBuilderParsingCode(
+    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 =\n"
+                   "    $type$.forNumber(rawValue);\n"
+                   "if (value == null) {\n"
+                   "  mergeUnknownVarintField($number$, rawValue);\n"
+                   "} else {\n"
+                   "  $set_oneof_case_message$;\n"
+                   "  $oneof_name$_ = rawValue;\n"
+                   "}\n");
+  }
+}
+
+void ImmutableEnumOneofFieldGenerator::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 ImmutableEnumOneofFieldGenerator::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 ImmutableEnumOneofFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(
+        variables_,
+        "if (get$capitalized_name$Value()\n"
+        "    != other.get$capitalized_name$Value()) return false;\n");
+  } else {
+    printer->Print(
+        variables_,
+        "if (!get$capitalized_name$()\n"
+        "    .equals(other.get$capitalized_name$())) return false;\n");
+  }
+}
+
+void ImmutableEnumOneofFieldGenerator::GenerateHashCode(
+    io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+                   "hash = (37 * hash) + $constant_name$;\n"
+                   "hash = (53 * hash) + get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(
+        variables_,
+        "hash = (37 * hash) + $constant_name$;\n"
+        "hash = (53 * hash) + get$capitalized_name$().getNumber();\n");
+  }
+}
+
+// ===================================================================
+
+RepeatedImmutableEnumFieldGenerator::RepeatedImmutableEnumFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+                   context->GetFieldGeneratorInfo(descriptor), name_resolver_,
+                   &variables_);
+}
+
+RepeatedImmutableEnumFieldGenerator::~RepeatedImmutableEnumFieldGenerator() {}
+
+int RepeatedImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableEnumFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(variables_,
+                 "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
+    printer->Print(variables_,
+                   "$deprecation$java.util.List<java.lang.Integer>\n"
+                   "get$capitalized_name$ValueList();\n");
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+    printer->Print(variables_,
+                   "$deprecation$int get$capitalized_name$Value(int index);\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private java.util.List<java.lang.Integer> $name$_;\n"
+      "private static final "
+      "com.google.protobuf.Internal.ListAdapter.Converter<\n"
+      "    java.lang.Integer, $type$> $name$_converter_ =\n"
+      "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
+      "            java.lang.Integer, $type$>() {\n"
+      "          public $type$ convert(java.lang.Integer from) {\n"
+      "            @SuppressWarnings(\"deprecation\")\n"
+      "            $type$ result = $type$.$for_number$(from);\n"
+      "            return result == null ? $unknown$ : result;\n"
+      "          }\n"
+      "        };\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $name$_converter_.convert($name$_.get(index));\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$public java.util.List<java.lang.Integer>\n"
+                   "${$get$capitalized_name$ValueList$}$() {\n"
+                   "  return $name$_;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$public int "
+                   "${$get$capitalized_name$Value$}$(int index) {\n"
+                   "  return $name$_.get(index);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  if (descriptor_->is_packed()) {
+    printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      // One field is the list and the other field keeps track of whether the
+      // list is immutable. If it's immutable, the invariant is that it must
+      // either an instance of Collections.emptyList() or it's an ArrayList
+      // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+      // a reference to the underlying ArrayList. This invariant allows us to
+      // share instances of lists between protocol buffers avoiding expensive
+      // memory allocations. Note, immutable is a strong guarantee here -- not
+      // just that the list cannot be modified via the reference but that the
+      // list can never be modified.
+      "private java.util.List<java.lang.Integer> $name$_ =\n"
+      "  java.util.Collections.emptyList();\n"
+
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      "  if (!$get_mutable_bit_builder$) {\n"
+      "    $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n"
+      "    $set_mutable_bit_builder$;\n"
+      "  }\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      // Note:  We return an unmodifiable list because otherwise the caller
+      //   could hold on to the returned list and modify it after the message
+      //   has been built, thus mutating the message which is supposed to be
+      //   immutable.
+      "$deprecation$public java.util.List<$type$> "
+      "${$get$capitalized_name$List$}$() {\n"
+      "  return new com.google.protobuf.Internal.ListAdapter<\n"
+      "      java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $name$_converter_.convert($name$_.get(index));\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$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.getNumber());\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$add$capitalized_name$$}$($type$ value) {\n"
+                 "  if (value == null) {\n"
+                 "    throw new NullPointerException();\n"
+                 "  }\n"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.add(value.getNumber());\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n"
+                 "    java.lang.Iterable<? extends $type$> values) {\n"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  for ($type$ value : values) {\n"
+                 "    $name$_.add(value.getNumber());\n"
+                 "  }\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  $name$_ = java.util.Collections.emptyList();\n"
+      "  $clear_mutable_bit_builder$;\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
+    printer->Print(variables_,
+                   "$deprecation$public java.util.List<java.lang.Integer>\n"
+                   "${$get$capitalized_name$ValueList$}$() {\n"
+                   "  return java.util.Collections.unmodifiableList($name$_);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+    printer->Print(variables_,
+                   "$deprecation$public int "
+                   "${$get$capitalized_name$Value$}$(int index) {\n"
+                   "  return $name$_.get(index);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_SETTER,
+                                          /* builder */ true);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder ${$set$capitalized_name$Value$}$(\n"
+        "    int index, int value) {\n"
+        "  ensure$capitalized_name$IsMutable();\n"
+        "  $name$_.set(index, value);\n"
+        "  $on_changed$\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                                          /* builder */ true);
+    printer->Print(variables_,
+                   "$deprecation$public Builder "
+                   "${$add$capitalized_name$Value$}$(int value) {\n"
+                   "  ensure$capitalized_name$IsMutable();\n"
+                   "  $name$_.add(value);\n"
+                   "  $on_changed$\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_MULTI_ADDER, /* builder */ true);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder ${$addAll$capitalized_name$Value$}$(\n"
+        "    java.lang.Iterable<java.lang.Integer> values) {\n"
+        "  ensure$capitalized_name$IsMutable();\n"
+        "  for (int value : values) {\n"
+        "    $name$_.add(value);\n"
+        "  }\n"
+        "  $on_changed$\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void RepeatedImmutableEnumFieldGenerator::
+    GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+  // noop for enums
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = java.util.Collections.emptyList();\n"
+                 "$clear_mutable_bit_builder$;\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::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"
+                 "    $clear_mutable_bit_builder$;\n"
+                 "  } else {\n"
+                 "    ensure$capitalized_name$IsMutable();\n"
+                 "    $name$_.addAll(other.$name$_);\n"
+                 "  }\n"
+                 "  $on_changed$\n"
+                 "}\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  // The code below ensures that the result has an immutable list. If our
+  // list is immutable, we can just reuse it. If not, we make it immutable.
+  printer->Print(
+      variables_,
+      "if ($get_mutable_bit_builder$) {\n"
+      "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+      "  $clear_mutable_bit_builder$;\n"
+      "}\n"
+      "result.$name$_ = $name$_;\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  // Read and store the enum
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+                   "int tmpRaw = input.readEnum();\n"
+                   "ensure$capitalized_name$IsMutable();\n"
+                   "$name$_.add(tmpRaw);\n");
+  } else {
+    printer->Print(variables_,
+                   "int tmpRaw = input.readEnum();\n"
+                   "$type$ tmpValue =\n"
+                   "    $type$.forNumber(tmpRaw);\n"
+                   "if (tmpValue == null) {\n"
+                   "  mergeUnknownVarintField($number$, tmpRaw);\n"
+                   "} else {\n"
+                   "  ensure$capitalized_name$IsMutable();\n"
+                   "  $name$_.add(tmpRaw);\n"
+                   "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCodeFromPacked(
+    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();
+
+  GenerateBuilderParsingCode(printer);
+
+  printer->Outdent();
+  printer->Print(variables_,
+                 "}\n"
+                 "input.popLimit(oldLimit);\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  if (descriptor_->is_packed()) {
+    printer->Print(variables_,
+                   "if (get$capitalized_name$List().size() > 0) {\n"
+                   "  output.writeUInt32NoTag($tag$);\n"
+                   "  output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
+                   "}\n"
+                   "for (int i = 0; i < $name$_.size(); i++) {\n"
+                   "  output.writeEnumNoTag($name$_.get(i));\n"
+                   "}\n");
+  } else {
+    printer->Print(variables_,
+                   "for (int i = 0; i < $name$_.size(); i++) {\n"
+                   "  output.writeEnum($number$, $name$_.get(i));\n"
+                   "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldGenerator::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$_.get(i));\n"
+                 "}\n");
+  printer->Print("size += dataSize;\n");
+  if (descriptor_->is_packed()) {
+    printer->Print(variables_,
+                   "if (!get$capitalized_name$List().isEmpty()) {"
+                   "  size += $tag_size$;\n"
+                   "  size += com.google.protobuf.CodedOutputStream\n"
+                   "    .computeUInt32SizeNoTag(dataSize);\n"
+                   "}");
+  } else {
+    printer->Print(variables_, "size += $tag_size$ * $name$_.size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->is_packed()) {
+    printer->Print(variables_, "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if (!$name$_.equals(other.$name$_)) return false;\n");
+}
+
+void RepeatedImmutableEnumFieldGenerator::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");
+}
+
+void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: $kt_type$) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: $kt_type$) {\n"
+                 "  add(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+                 "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+      "  addAll(values)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: $kt_type$) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}");
+}
+
+std::string RepeatedImmutableEnumFieldGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/enum_field.h b/src/google/protobuf/compiler/java/enum_field.h
new file mode 100644
index 0000000..df9ee98
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum_field.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.
+
+// 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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit ImmutableEnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex, int builderBitIndex,
+                                       Context* context);
+  ~ImmutableEnumFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator
+  // ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldGenerator);
+};
+
+class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
+ public:
+  ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                   int messageBitIndex, int builderBitIndex,
+                                   Context* context);
+  ~ImmutableEnumOneofFieldGenerator() override;
+
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator);
+};
+
+class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit RepeatedImmutableEnumFieldGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableEnumFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCodeFromPacked(
+      io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/enum_field_lite.cc b/src/google/protobuf/compiler/java/enum_field_lite.cc
new file mode 100644
index 0000000..6fe683f
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum_field_lite.cc
@@ -0,0 +1,923 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/enum_field_lite.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+bool EnableExperimentalRuntimeForLite() {
+#ifdef PROTOBUF_EXPERIMENT
+  return PROTOBUF_EXPERIMENT;
+#else   // PROTOBUF_EXPERIMENT
+  return false;
+#endif  // !PROTOBUF_EXPERIMENT
+}
+
+void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
+                      int builderBitIndex, const FieldGeneratorInfo* info,
+                      ClassNameResolver* name_resolver,
+                      std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->enum_type());
+  (*variables)["kt_type"] = (*variables)["type"];
+  (*variables)["mutable_type"] =
+      name_resolver->GetMutableClassName(descriptor->enum_type());
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_number"] =
+      StrCat(descriptor->default_value_enum()->number());
+  (*variables)["tag"] = StrCat(
+      static_cast<int32_t>(internal::WireFormat::MakeTag(descriptor)));
+  (*variables)["tag_size"] = StrCat(
+      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)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["required"] = descriptor->is_required() ? "true" : "false";
+
+  if (HasHasbit(descriptor)) {
+    // 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()";
+  }
+
+  (*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"];
+  }
+
+  // We use `x.getClass()` as a null check because it generates less bytecode
+  // than an `if (x == null) { throw ... }` statement.
+  (*variables)["null_check"] = "value.getClass();\n";
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableEnumFieldLiteGenerator::ImmutableEnumFieldLiteGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, Context* context)
+    : descriptor_(descriptor),
+      messageBitIndex_(messageBitIndex),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, 0,
+                   context->GetFieldGeneratorInfo(descriptor), name_resolver_,
+                   &variables_);
+}
+
+ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+void ImmutableEnumFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(variables_,
+                   "$deprecation$int get$capitalized_name$Value();\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  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 (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
+        "  return $name$_;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  $type$ result = $type$.forNumber($name$_);\n"
+                 "  return result == null ? $unknown$ : result;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Generate private setters for the builder to proxy into.
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER);
+    printer->Print(variables_,
+                   "private void set$capitalized_name$Value(int value) {\n"
+                   "  $set_has_field_bit_message$"
+                   "  $name$_ = value;\n"
+                   "}\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$($type$ value) {\n"
+                 "  $name$_ = value.getNumber();\n"
+                 "  $set_has_field_bit_message$\n"
+                 "}\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  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 (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return instance.has$capitalized_name$();\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
+        "  return instance.get$capitalized_name$Value();\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                                 /* builder */ true);
+    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");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return instance.get$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
+                                        /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.set$capitalized_name$(value);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: $kt_type$\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+        "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+        "}\n");
+  }
+}
+
+void ImmutableEnumFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  if (!IsDefaultValueJavaDefault(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $default_number$;\n");
+  }
+}
+
+void ImmutableEnumFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  if (HasHasbit(descriptor_)) {
+    WriteIntToUtf16CharSequence(messageBitIndex_, output);
+  }
+  printer->Print(variables_, "\"$name$_\",\n");
+  if (!SupportUnknownEnumValue((descriptor_))) {
+    PrintEnumVerifierLogic(printer, descriptor_, variables_,
+                           /*var_name=*/"$type$",
+                           /*terminating_string=*/",\n",
+                           /*enforce_lite=*/context_->EnforceLite());
+  }
+}
+
+std::string ImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+// ===================================================================
+
+ImmutableEnumOneofFieldLiteGenerator::ImmutableEnumOneofFieldLiteGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, Context* context)
+    : ImmutableEnumFieldLiteGenerator(descriptor, messageBitIndex, 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);
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$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");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    $type$ result = $type$.forNumber((java.lang.Integer) "
+                 "$oneof_name$_);\n"
+                 "    return result == null ? $unknown$ : result;\n"
+                 "  }\n"
+                 "  return $default$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Generate private setters for the builder to proxy into.
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER);
+    printer->Print(variables_,
+                   "private void set$capitalized_name$Value(int value) {\n"
+                   "  $set_oneof_case_message$;\n"
+                   "  $oneof_name$_ = value;\n"
+                   "}\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$($type$ value) {\n"
+                 "  $oneof_name$_ = value.getNumber();\n"
+                 "  $set_oneof_case_message$;\n"
+                 "}\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  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::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output);
+  if (!SupportUnknownEnumValue(descriptor_)) {
+    PrintEnumVerifierLogic(printer, descriptor_, variables_,
+                           /*var_name=*/"$type$",
+                           /*terminating_string=*/",\n",
+                           /*enforce_lite=*/context_->EnforceLite());
+  }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return instance.has$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public int ${$get$capitalized_name$Value$}$() {\n"
+        "  return instance.get$capitalized_name$Value();\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+    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");
+    printer->Annotate("{", "}", descriptor_);
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return instance.get$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.set$capitalized_name$(value);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+// ===================================================================
+
+RepeatedImmutableEnumFieldLiteGenerator::
+    RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                            int messageBitIndex,
+                                            Context* context)
+    : descriptor_(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, 0,
+                   context->GetFieldGeneratorInfo(descriptor), name_resolver_,
+                   &variables_);
+}
+
+RepeatedImmutableEnumFieldLiteGenerator::
+    ~RepeatedImmutableEnumFieldLiteGenerator() {}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(variables_,
+                 "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
+    printer->Print(variables_,
+                   "$deprecation$java.util.List<java.lang.Integer>\n"
+                   "get$capitalized_name$ValueList();\n");
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+    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"
+      "          @java.lang.Override\n"
+      "          public $type$ convert(java.lang.Integer from) {\n"
+      "            $type$ result = $type$.forNumber(from);\n"
+      "            return result == null ? $unknown$ : result;\n"
+      "          }\n"
+      "        };\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      // NB: Do not use the "$name$_converter_" field; the usage of generics
+      // (and requisite upcasts to Object) prevent optimizations.  Even
+      // without any optimizations, the below code is cheaper because it
+      // avoids boxing an int and a checkcast from the generics.
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  $type$ result = $type$.forNumber($name$_.getInt(index));\n"
+      "  return result == null ? $unknown$ : result;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$public java.util.List<java.lang.Integer>\n"
+                   "${$get$capitalized_name$ValueList$}$() {\n"
+                   "  return $name$_;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$public int "
+                   "${$get$capitalized_name$Value$}$(int index) {\n"
+                   "  return $name$_.getInt(index);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  if (!EnableExperimentalRuntimeForLite() && descriptor_->is_packed() &&
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n");
+  }
+
+  // Generate private setters for the builder to proxy into.
+  printer->Print(
+      variables_,
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  com.google.protobuf.Internal.IntList tmp = $name$_;\n"
+      "  if (!tmp.isModifiable()) {\n"
+      "    $name$_ =\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
+      "  }\n"
+      "}\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$(\n"
+                 "    int index, $type$ value) {\n"
+                 "  $null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.setInt(index, value.getNumber());\n"
+                 "}\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER);
+  printer->Print(variables_,
+                 "private void add$capitalized_name$($type$ value) {\n"
+                 "  $null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.addInt(value.getNumber());\n"
+                 "}\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  printer->Print(variables_,
+                 "private void clear$capitalized_name$() {\n"
+                 "  $name$_ = emptyIntList();\n"
+                 "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER);
+    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");
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER);
+    printer->Print(variables_,
+                   "private void add$capitalized_name$Value(int value) {\n"
+                   "  ensure$capitalized_name$IsMutable();\n"
+                   "  $name$_.addInt(value);\n"
+                   "}\n");
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_MULTI_ADDER);
+    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::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  printer->Print(variables_, "\"$name$_\",\n");
+  if (!SupportUnknownEnumValue(descriptor_->file())) {
+    PrintEnumVerifierLogic(printer, descriptor_, variables_,
+                           /*var_name=*/"$type$",
+                           /*terminating_string=*/",\n",
+                           /*enforce_lite=*/context_->EnforceLite());
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<$type$> "
+                 "${$get$capitalized_name$List$}$() {\n"
+                 "  return instance.get$capitalized_name$List();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return instance.get$capitalized_name$Count();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return instance.get$capitalized_name$(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$add$capitalized_name$$}$($type$ value) {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.add$capitalized_name$(value);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$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");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$public int "
+                   "${$get$capitalized_name$Value$}$(int index) {\n"
+                   "  return instance.get$capitalized_name$Value(index);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_SETTER,
+                                          /* builder */ true);
+    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");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                                          /* builder */ true);
+    printer->Print(variables_,
+                   "$deprecation$public Builder "
+                   "${$add$capitalized_name$Value$}$(int value) {\n"
+                   "  instance.add$capitalized_name$Value(value);\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
+                                          LIST_MULTI_ADDER,
+                                          /* builder */ true);
+    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");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = emptyIntList();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: $kt_type$) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: $kt_type$) {\n"
+                 "  add(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+                 "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+      "  addAll(values)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: $kt_type$) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}");
+}
+
+std::string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/enum_field_lite.h b/src/google/protobuf/compiler/java/enum_field_lite.h
new file mode 100644
index 0000000..492b268
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum_field_lite.h
@@ -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.
+
+// 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 <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                           int messageBitIndex,
+                                           Context* context);
+  ~ImmutableEnumFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator
+  // ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  const int messageBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldLiteGenerator);
+};
+
+class ImmutableEnumOneofFieldLiteGenerator
+    : public ImmutableEnumFieldLiteGenerator {
+ public:
+  ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex, Context* context);
+  ~ImmutableEnumOneofFieldLiteGenerator() override;
+
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableEnumFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableEnumFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex, Context* context);
+  ~RepeatedImmutableEnumFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  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/enum_lite.cc b/src/google/protobuf/compiler/java/enum_lite.cc
new file mode 100644
index 0000000..4387090
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum_lite.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/enum_lite.h>
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor,
+                                     bool immutable_api, Context* context)
+    : descriptor_(descriptor),
+      immutable_api_(immutable_api),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    const EnumValueDescriptor* value = descriptor_->value(i);
+    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_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
+  printer->Print(
+      "$deprecation$public enum $classname$\n"
+      "    implements com.google.protobuf.Internal.EnumLite {\n",
+      "classname", descriptor_->name(), "deprecation",
+      descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "");
+  printer->Annotate("classname", descriptor_);
+  printer->Indent();
+
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    std::map<std::string, std::string> vars;
+    vars["name"] = canonical_values_[i]->name();
+    vars["number"] = StrCat(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");
+    printer->Annotate("name", canonical_values_[i]);
+  }
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", "");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  printer->Print(
+      ";\n"
+      "\n");
+
+  // -----------------------------------------------------------------
+
+  for (int i = 0; i < aliases_.size(); i++) {
+    std::map<std::string, std::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");
+    printer->Annotate("name", aliases_[i].value);
+  }
+
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    std::map<std::string, std::string> vars;
+    vars["name"] = descriptor_->value(i)->name();
+    vars["number"] = StrCat(descriptor_->value(i)->number());
+    vars["{"] = "";
+    vars["}"] = "";
+    vars["deprecation"] = descriptor_->value(i)->options().deprecated()
+                              ? "@java.lang.Deprecated "
+                              : "";
+    WriteEnumValueDocComment(printer, descriptor_->value(i));
+    printer->Print(vars,
+                   "$deprecation$public static final int ${$$name$_VALUE$}$ = "
+                   "$number$;\n");
+    printer->Annotate("{", "}", descriptor_->value(i));
+  }
+  printer->Print("\n");
+
+  // -----------------------------------------------------------------
+
+  printer->Print(
+      "\n"
+      "@java.lang.Override\n"
+      "public final int getNumber() {\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(
+        "  if (this == UNRECOGNIZED) {\n"
+        "    throw new java.lang.IllegalArgumentException(\n"
+        "        \"Can't get the number of an unknown enum value.\");\n"
+        "  }\n");
+  }
+  printer->Print(
+      "  return value;\n"
+      "}\n"
+      "\n"
+      "/**\n"
+      " * @param value The number of the enum to look for.\n"
+      " * @return The enum associated with the given number.\n"
+      " * @deprecated Use {@link #forNumber(int)} instead.\n"
+      " */\n"
+      "@java.lang.Deprecated\n"
+      "public static $classname$ valueOf(int value) {\n"
+      "  return forNumber(value);\n"
+      "}\n"
+      "\n"
+      "public static $classname$ forNumber(int value) {\n"
+      "  switch (value) {\n",
+      "classname", descriptor_->name());
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    printer->Print("case $number$: return $name$;\n", "name",
+                   canonical_values_[i]->name(), "number",
+                   StrCat(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"
+      "        @java.lang.Override\n"
+      "        public $classname$ findValueByNumber(int number) {\n"
+      "          return $classname$.forNumber(number);\n"
+      "        }\n"
+      "      };\n"
+      "\n"
+      "public static com.google.protobuf.Internal.EnumVerifier \n"
+      "    internalGetVerifier() {\n"
+      "  return $classname$Verifier.INSTANCE;\n"
+      "}\n"
+      "\n"
+      "private static final class $classname$Verifier implements \n"
+      "     com.google.protobuf.Internal.EnumVerifier { \n"
+      "        static final com.google.protobuf.Internal.EnumVerifier "
+      "          INSTANCE = new $classname$Verifier();\n"
+      "        @java.lang.Override\n"
+      "        public boolean isInRange(int number) {\n"
+      "          return $classname$.forNumber(number) != null;\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");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/enum_lite.h b/src/google/protobuf/compiler/java/enum_lite.h
new file mode 100644
index 0000000..50f3fe7
--- /dev/null
+++ b/src/google/protobuf/compiler/java/enum_lite.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.
+
+// 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 java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class EnumLiteGenerator {
+ public:
+  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.
+  std::vector<const EnumValueDescriptor*> canonical_values_;
+
+  struct Alias {
+    const EnumValueDescriptor* value;
+    const EnumValueDescriptor* canonical_value;
+  };
+  std::vector<Alias> aliases_;
+
+  bool immutable_api_;
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  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/extension.cc b/src/google/protobuf/compiler/java/extension.cc
new file mode 100644
index 0000000..8b93eb1
--- /dev/null
+++ b/src/google/protobuf/compiler/java/extension.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/extension.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableExtensionGenerator::ImmutableExtensionGenerator(
+    const FieldDescriptor* descriptor, Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  if (descriptor_->extension_scope() != NULL) {
+    scope_ =
+        name_resolver_->GetImmutableClassName(descriptor_->extension_scope());
+  } else {
+    scope_ = name_resolver_->GetImmutableClassName(descriptor_->file());
+  }
+}
+
+ImmutableExtensionGenerator::~ImmutableExtensionGenerator() {}
+
+// Initializes the vars referenced in the generated code templates.
+void ExtensionGenerator::InitTemplateVars(
+    const FieldDescriptor* descriptor, const std::string& scope, bool immutable,
+    ClassNameResolver* name_resolver,
+    std::map<std::string, std::string>* vars_pointer) {
+  std::map<std::string, std::string>& vars = *vars_pointer;
+  vars["scope"] = scope;
+  vars["name"] = UnderscoresToCamelCaseCheckReserved(descriptor);
+  vars["containing_type"] =
+      name_resolver->GetClassName(descriptor->containing_type(), immutable);
+  vars["number"] = StrCat(descriptor->number());
+  vars["constant_name"] = FieldConstantName(descriptor);
+  vars["index"] = StrCat(descriptor->index());
+  vars["default"] = descriptor->is_repeated()
+                        ? ""
+                        : DefaultValue(descriptor, immutable, name_resolver);
+  vars["type_constant"] = FieldTypeName(GetType(descriptor));
+  vars["packed"] = descriptor->is_packed() ? "true" : "false";
+  vars["enum_map"] = "null";
+  vars["prototype"] = "null";
+
+  JavaType java_type = GetJavaType(descriptor);
+  std::string singular_type;
+  switch (java_type) {
+    case JAVATYPE_MESSAGE:
+      singular_type =
+          name_resolver->GetClassName(descriptor->message_type(), immutable);
+      vars["prototype"] = singular_type + ".getDefaultInstance()";
+      break;
+    case JAVATYPE_ENUM:
+      singular_type =
+          name_resolver->GetClassName(descriptor->enum_type(), immutable);
+      vars["enum_map"] = singular_type + ".internalGetValueMap()";
+      break;
+    case JAVATYPE_STRING:
+      singular_type = "java.lang.String";
+      break;
+    case JAVATYPE_BYTES:
+      singular_type = immutable ? "com.google.protobuf.ByteString" : "byte[]";
+      break;
+    default:
+      singular_type = BoxedPrimitiveTypeName(java_type);
+      break;
+  }
+  vars["type"] = descriptor->is_repeated()
+                     ? "java.util.List<" + singular_type + ">"
+                     : singular_type;
+  vars["singular_type"] = singular_type;
+}
+
+void ImmutableExtensionGenerator::Generate(io::Printer* printer) {
+  std::map<std::string, std::string> vars;
+  const bool kUseImmutableNames = true;
+  InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_,
+                   &vars);
+  printer->Print(vars, "public static final int $constant_name$ = $number$;\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  if (descriptor_->extension_scope() == NULL) {
+    // Non-nested
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+        "        .newFileScopedGeneratedExtension(\n"
+        "      $singular_type$.class,\n"
+        "      $prototype$);\n");
+  } else {
+    // Nested
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+        "        .newMessageScopedGeneratedExtension(\n"
+        "      $scope$.getDefaultInstance(),\n"
+        "      $index$,\n"
+        "      $singular_type$.class,\n"
+        "      $prototype$);\n");
+  }
+  printer->Annotate("name", descriptor_);
+}
+
+int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
+    io::Printer* printer) {
+  int bytecode_estimate = 0;
+  if (descriptor_->extension_scope() == NULL) {
+    // Only applies to non-nested extensions.
+    printer->Print(
+        "$name$.internalInit(descriptor.getExtensions().get($index$));\n",
+        "name", UnderscoresToCamelCaseCheckReserved(descriptor_), "index",
+        StrCat(descriptor_->index()));
+    bytecode_estimate += 21;
+  }
+  return bytecode_estimate;
+}
+
+int ImmutableExtensionGenerator::GenerateRegistrationCode(
+    io::Printer* printer) {
+  printer->Print("registry.add($scope$.$name$);\n", "scope", scope_, "name",
+                 UnderscoresToCamelCaseCheckReserved(descriptor_));
+  return 7;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/extension.h b/src/google/protobuf/compiler/java/extension.h
new file mode 100644
index 0000000..318cfa4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/extension.h
@@ -0,0 +1,115 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_EXTENSION_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class FieldDescriptor;  // descriptor.h
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generates code for an extension, which may be within the scope of some
+// message or may be at file scope.  This is much simpler than FieldGenerator
+// since extensions are just simple identifiers with interesting types.
+class ExtensionGenerator {
+ public:
+  explicit ExtensionGenerator() {}
+  virtual ~ExtensionGenerator() {}
+
+  virtual void Generate(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, const std::string& scope,
+      bool immutable, ClassNameResolver* name_resolver,
+      std::map<std::string, std::string>* vars_pointer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+class ImmutableExtensionGenerator : public ExtensionGenerator {
+ public:
+  explicit ImmutableExtensionGenerator(const FieldDescriptor* descriptor,
+                                       Context* context);
+  ~ImmutableExtensionGenerator() override;
+
+  void Generate(io::Printer* printer) override;
+  int GenerateNonNestedInitializationCode(io::Printer* printer) override;
+  int GenerateRegistrationCode(io::Printer* printer) override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  ClassNameResolver* name_resolver_;
+  std::string scope_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__
diff --git a/src/google/protobuf/compiler/java/extension_lite.cc b/src/google/protobuf/compiler/java/extension_lite.cc
new file mode 100644
index 0000000..bffb1d6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/extension_lite.cc
@@ -0,0 +1,120 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/extension_lite.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator(
+    const FieldDescriptor* descriptor, Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  if (descriptor_->extension_scope() != NULL) {
+    scope_ =
+        name_resolver_->GetImmutableClassName(descriptor_->extension_scope());
+  } else {
+    scope_ = name_resolver_->GetImmutableClassName(descriptor_->file());
+  }
+}
+
+ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {}
+
+void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) {
+  std::map<std::string, std::string> vars;
+  const bool kUseImmutableNames = true;
+  InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_,
+                   &vars);
+  printer->Print(vars, "public static final int $constant_name$ = $number$;\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  if (descriptor_->is_repeated()) {
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+        "        .newRepeatedGeneratedExtension(\n"
+        "      $containing_type$.getDefaultInstance(),\n"
+        "      $prototype$,\n"
+        "      $enum_map$,\n"
+        "      $number$,\n"
+        "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+        "      $packed$,\n"
+        "      $singular_type$.class);\n");
+  } else {
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+        "        .newSingularGeneratedExtension(\n"
+        "      $containing_type$.getDefaultInstance(),\n"
+        "      $default$,\n"
+        "      $prototype$,\n"
+        "      $enum_map$,\n"
+        "      $number$,\n"
+        "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+        "      $singular_type$.class);\n");
+  }
+  printer->Annotate("name", descriptor_);
+}
+
+int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode(
+    io::Printer* printer) {
+  return 0;
+}
+
+int ImmutableExtensionLiteGenerator::GenerateRegistrationCode(
+    io::Printer* printer) {
+  printer->Print("registry.add($scope$.$name$);\n", "scope", scope_, "name",
+                 UnderscoresToCamelCaseCheckReserved(descriptor_));
+  return 7;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/extension_lite.h b/src/google/protobuf/compiler/java/extension_lite.h
new file mode 100644
index 0000000..264230c
--- /dev/null
+++ b/src/google/protobuf/compiler/java/extension_lite.h
@@ -0,0 +1,75 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/extension.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generates code for a lite extension, which may be within the scope of some
+// message or may be at file scope.  This is much simpler than FieldGenerator
+// since extensions are just simple identifiers with interesting types.
+class ImmutableExtensionLiteGenerator : public ExtensionGenerator {
+ public:
+  explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor,
+                                           Context* context);
+  ~ImmutableExtensionLiteGenerator() override;
+
+  void Generate(io::Printer* printer) override;
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  int GenerateNonNestedInitializationCode(io::Printer* printer) override;
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  int GenerateRegistrationCode(io::Printer* printer) override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  ClassNameResolver* name_resolver_;
+  std::string scope_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
diff --git a/src/google/protobuf/compiler/java/field.cc b/src/google/protobuf/compiler/java/field.cc
new file mode 100644
index 0000000..3dd528f
--- /dev/null
+++ b/src/google/protobuf/compiler/java/field.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/field.h>
+
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/enum_field.h>
+#include <google/protobuf/compiler/java/enum_field_lite.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/map_field.h>
+#include <google/protobuf/compiler/java/map_field_lite.h>
+#include <google/protobuf/compiler/java/message_field.h>
+#include <google/protobuf/compiler/java/message_field_lite.h>
+#include <google/protobuf/compiler/java/primitive_field.h>
+#include <google/protobuf/compiler/java/primitive_field_lite.h>
+#include <google/protobuf/compiler/java/string_field.h>
+#include <google/protobuf/compiler/java/string_field_lite.h>
+
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+ImmutableFieldGenerator* MakeImmutableGenerator(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 ImmutableMapFieldGenerator(field, messageBitIndex,
+                                                builderBitIndex, context);
+        } else {
+          return new RepeatedImmutableMessageFieldGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        }
+      case JAVATYPE_ENUM:
+        return new RepeatedImmutableEnumFieldGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+      case JAVATYPE_STRING:
+        return new RepeatedImmutableStringFieldGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+      default:
+        return new RepeatedImmutablePrimitiveFieldGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+    }
+  } else {
+    if (IsRealOneof(field)) {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          return new ImmutableMessageOneofFieldGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumOneofFieldGenerator(field, messageBitIndex,
+                                                      builderBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringOneofFieldGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        default:
+          return new ImmutablePrimitiveOneofFieldGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+      }
+    } else {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          return new ImmutableMessageFieldGenerator(field, messageBitIndex,
+                                                    builderBitIndex, context);
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumFieldGenerator(field, messageBitIndex,
+                                                 builderBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringFieldGenerator(field, messageBitIndex,
+                                                   builderBitIndex, context);
+        default:
+          return new ImmutablePrimitiveFieldGenerator(field, messageBitIndex,
+                                                      builderBitIndex, context);
+      }
+    }
+  }
+}
+
+ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
+    const FieldDescriptor* field, int messageBitIndex, Context* context) {
+  if (field->is_repeated()) {
+    switch (GetJavaType(field)) {
+      case JAVATYPE_MESSAGE:
+        if (IsMapEntry(field->message_type())) {
+          return new ImmutableMapFieldLiteGenerator(field, messageBitIndex,
+                                                    context);
+        } else {
+          return new RepeatedImmutableMessageFieldLiteGenerator(
+              field, messageBitIndex, context);
+        }
+      case JAVATYPE_ENUM:
+        return new RepeatedImmutableEnumFieldLiteGenerator(
+            field, messageBitIndex, context);
+      case JAVATYPE_STRING:
+        return new RepeatedImmutableStringFieldLiteGenerator(
+            field, messageBitIndex, context);
+      default:
+        return new RepeatedImmutablePrimitiveFieldLiteGenerator(
+            field, messageBitIndex, context);
+    }
+  } else {
+    if (IsRealOneof(field)) {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          return new ImmutableMessageOneofFieldLiteGenerator(
+              field, messageBitIndex, context);
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumOneofFieldLiteGenerator(
+              field, messageBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringOneofFieldLiteGenerator(
+              field, messageBitIndex, context);
+        default:
+          return new ImmutablePrimitiveOneofFieldLiteGenerator(
+              field, messageBitIndex, context);
+      }
+    } else {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          return new ImmutableMessageFieldLiteGenerator(field, messageBitIndex,
+                                                        context);
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumFieldLiteGenerator(field, messageBitIndex,
+                                                     context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringFieldLiteGenerator(field, messageBitIndex,
+                                                       context);
+        default:
+          return new ImmutablePrimitiveFieldLiteGenerator(
+              field, messageBitIndex, context);
+      }
+    }
+  }
+}
+
+
+static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
+  // Reaching here indicates a bug. Cases are:
+  //   - This FieldGenerator should support packing,
+  //     but this method should be overridden.
+  //   - This FieldGenerator doesn't support packing, and this method
+  //     should never have been called.
+  GOOGLE_LOG(FATAL) << "GenerateBuilderParsingCodeFromPacked() "
+             << "called on field generator that does not support packing.";
+}
+
+}  // namespace
+
+ImmutableFieldGenerator::~ImmutableFieldGenerator() {}
+
+void ImmutableFieldGenerator::GenerateBuilderParsingCodeFromPacked(
+    io::Printer* printer) const {
+  ReportUnexpectedPackedFieldsCall(printer);
+}
+
+ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {}
+
+// ===================================================================
+
+template <>
+FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap(
+    const Descriptor* descriptor, Context* context)
+    : descriptor_(descriptor), field_generators_(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++) {
+    ImmutableFieldGenerator* generator = MakeImmutableGenerator(
+        descriptor->field(i), messageBitIndex, builderBitIndex, context);
+    field_generators_[i].reset(generator);
+    messageBitIndex += generator->GetNumBitsForMessage();
+    builderBitIndex += generator->GetNumBitsForBuilder();
+  }
+}
+
+template <>
+FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {}
+
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap(
+    const Descriptor* descriptor, Context* context)
+    : descriptor_(descriptor), field_generators_(descriptor->field_count()) {
+  // Construct all the FieldGenerators and assign them bit indices for their
+  // bit fields.
+  int messageBitIndex = 0;
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator(
+        descriptor->field(i), messageBitIndex, context);
+    field_generators_[i].reset(generator);
+    messageBitIndex += generator->GetNumBitsForMessage();
+  }
+}
+
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap() {}
+
+
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             const FieldGeneratorInfo* info,
+                             std::map<std::string, std::string>* variables) {
+  (*variables)["field_name"] = descriptor->name();
+  (*variables)["name"] = info->name;
+  (*variables)["classname"] = descriptor->containing_type()->name();
+  (*variables)["capitalized_name"] = info->capitalized_name;
+  (*variables)["disambiguated_reason"] = info->disambiguated_reason;
+  (*variables)["constant_name"] = FieldConstantName(descriptor);
+  (*variables)["number"] = StrCat(descriptor->number());
+  (*variables)["kt_dsl_builder"] = "_builder";
+  // These variables are placeholders to pick out the beginning and ends of
+  // identifiers for annotations (when doing so with existing variables would
+  // be ambiguous or impossible). They should never be set to anything but the
+  // empty string.
+  (*variables)["{"] = "";
+  (*variables)["}"] = "";
+  (*variables)["kt_name"] =
+      IsForbiddenKotlin(info->name) ? info->name + "_" : info->name;
+  (*variables)["kt_capitalized_name"] = IsForbiddenKotlin(info->name)
+                                            ? info->capitalized_name + "_"
+                                            : info->capitalized_name;
+  if (!descriptor->is_repeated()) {
+    (*variables)["annotation_field_type"] = FieldTypeName(descriptor->type());
+  } else if (GetJavaType(descriptor) == JAVATYPE_MESSAGE &&
+             IsMapEntry(descriptor->message_type())) {
+    (*variables)["annotation_field_type"] =
+        std::string(FieldTypeName(descriptor->type())) + "MAP";
+  } else {
+    (*variables)["annotation_field_type"] =
+        std::string(FieldTypeName(descriptor->type())) + "_LIST";
+    if (descriptor->is_packed()) {
+      (*variables)["annotation_field_type"] =
+          (*variables)["annotation_field_type"] + "_PACKED";
+    }
+  }
+}
+
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+                             const OneofGeneratorInfo* info,
+                             std::map<std::string, std::string>* variables) {
+  (*variables)["oneof_name"] = info->name;
+  (*variables)["oneof_capitalized_name"] = info->capitalized_name;
+  (*variables)["oneof_index"] =
+      StrCat(descriptor->containing_oneof()->index());
+  (*variables)["oneof_stored_type"] = GetOneofStoredType(descriptor);
+  (*variables)["set_oneof_case_message"] =
+      info->name + "Case_ = " + StrCat(descriptor->number());
+  (*variables)["clear_oneof_case_message"] = info->name + "Case_ = 0";
+  (*variables)["has_oneof_case_message"] =
+      info->name + "Case_ == " + StrCat(descriptor->number());
+}
+
+void PrintExtraFieldInfo(const std::map<std::string, std::string>& variables,
+                         io::Printer* printer) {
+  const std::map<std::string, std::string>::const_iterator it =
+      variables.find("disambiguated_reason");
+  if (it != variables.end() && !it->second.empty()) {
+    printer->Print(
+        variables,
+        "// An alternative name is used for field \"$field_name$\" because:\n"
+        "//     $disambiguated_reason$\n");
+  }
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/field.h b/src/google/protobuf/compiler/java/field.h
new file mode 100644
index 0000000..a9125f1
--- /dev/null
+++ b/src/google/protobuf/compiler/java/field.h
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableFieldGenerator {
+ public:
+  ImmutableFieldGenerator() {}
+  virtual ~ImmutableFieldGenerator();
+
+  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 GenerateBuilderClearCode(io::Printer* printer) const = 0;
+  virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+  virtual void GenerateBuildingCode(io::Printer* printer) const = 0;
+  virtual void GenerateBuilderParsingCode(io::Printer* printer) const = 0;
+  virtual void GenerateBuilderParsingCodeFromPacked(io::Printer* printer) const;
+  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 GenerateKotlinDslMembers(io::Printer* printer) const = 0;
+
+  virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+  virtual void GenerateHashCode(io::Printer* printer) const = 0;
+
+  virtual std::string GetBoxedType() const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator);
+};
+
+class ImmutableFieldLiteGenerator {
+ public:
+  ImmutableFieldLiteGenerator() {}
+  virtual ~ImmutableFieldLiteGenerator();
+
+  virtual int GetNumBitsForMessage() 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 GenerateFieldInfo(io::Printer* printer,
+                                 std::vector<uint16_t>* output) const = 0;
+  virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
+
+  virtual std::string GetBoxedType() const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldLiteGenerator);
+};
+
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+template <typename FieldGeneratorType>
+class FieldGeneratorMap {
+ public:
+  explicit FieldGeneratorMap(const Descriptor* descriptor, Context* context);
+  ~FieldGeneratorMap();
+
+  const FieldGeneratorType& get(const FieldDescriptor* field) const;
+
+ private:
+  const Descriptor* descriptor_;
+  std::vector<std::unique_ptr<FieldGeneratorType>> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+
+template <typename FieldGeneratorType>
+inline const FieldGeneratorType& FieldGeneratorMap<FieldGeneratorType>::get(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+  return *field_generators_[field->index()];
+}
+
+// Instantiate template for mutable and immutable maps.
+template <>
+FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap(
+    const Descriptor* descriptor, Context* context);
+
+template <>
+FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap();
+
+
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap(
+    const Descriptor* descriptor, Context* context);
+
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap();
+
+
+// Field information used in FieldGenerators.
+struct FieldGeneratorInfo {
+  std::string name;
+  std::string capitalized_name;
+  std::string disambiguated_reason;
+};
+
+// Oneof information used in OneofFieldGenerators.
+struct OneofGeneratorInfo {
+  std::string name;
+  std::string capitalized_name;
+};
+
+// Set some common variables used in variable FieldGenerators.
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             const FieldGeneratorInfo* info,
+                             std::map<std::string, std::string>* variables);
+
+// Set some common oneof variables used in OneofFieldGenerators.
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+                             const OneofGeneratorInfo* info,
+                             std::map<std::string, std::string>* variables);
+
+// Print useful comments before a field's accessors.
+void PrintExtraFieldInfo(const std::map<std::string, std::string>& variables,
+                         io::Printer* printer);
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/file.cc b/src/google/protobuf/compiler/java/file.cc
new file mode 100644
index 0000000..cf27703
--- /dev/null
+++ b/src/google/protobuf/compiler/java/file.cc
@@ -0,0 +1,739 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/file.h>
+
+#include <memory>
+#include <set>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/enum.h>
+#include <google/protobuf/compiler/java/enum_lite.h>
+#include <google/protobuf/compiler/java/extension.h>
+#include <google/protobuf/compiler/java/generator_factory.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/message.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/compiler/java/service.h>
+#include <google/protobuf/compiler/java/shared_code_generator.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+struct FieldDescriptorCompare {
+  bool operator()(const FieldDescriptor* f1, const FieldDescriptor* f2) const {
+    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
+// appended in to the extensions parameter.
+// 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, FieldDescriptorSet* extensions) {
+  const Reflection* reflection = message.GetReflection();
+
+  // There are unknown fields that could be extensions, thus this call fails.
+  if (reflection->GetUnknownFields(message).field_count() > 0) return false;
+
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(message, &fields);
+
+  for (int i = 0; i < fields.size(); i++) {
+    if (fields[i]->is_extension()) {
+      extensions->insert(fields[i]);
+    }
+
+    if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
+      if (fields[i]->is_repeated()) {
+        int size = reflection->FieldSize(message, fields[i]);
+        for (int j = 0; j < size; j++) {
+          const Message& sub_message =
+              reflection->GetRepeatedMessage(message, fields[i], j);
+          if (!CollectExtensions(sub_message, extensions)) return false;
+        }
+      } else {
+        const Message& sub_message = reflection->GetMessage(message, fields[i]);
+        if (!CollectExtensions(sub_message, extensions)) return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+// Finds all extensions in the given message and its sub-messages.  If the
+// message contains unknown fields (which could be extensions), then those
+// extensions are defined in alternate_pool.
+// The message will be converted to a DynamicMessage backed by alternate_pool
+// in order to handle this case.
+void CollectExtensions(const FileDescriptorProto& file_proto,
+                       const DescriptorPool& alternate_pool,
+                       FieldDescriptorSet* extensions,
+                       const std::string& file_data) {
+  if (!CollectExtensions(file_proto, extensions)) {
+    // There are unknown fields in the file_proto, which are probably
+    // extensions. We need to parse the data into a dynamic message based on the
+    // builder-pool to find out all extensions.
+    const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName(
+        file_proto.GetDescriptor()->full_name());
+    GOOGLE_CHECK(file_proto_desc)
+        << "Find unknown fields in FileDescriptorProto when building "
+        << file_proto.name()
+        << ". It's likely that those fields are custom options, however, "
+           "descriptor.proto is not in the transitive dependencies. "
+           "This normally should not happen. Please report a bug.";
+    DynamicMessageFactory factory;
+    std::unique_ptr<Message> dynamic_file_proto(
+        factory.GetPrototype(file_proto_desc)->New());
+    GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
+    GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
+
+    // Collect the extensions again from the dynamic message. There should be no
+    // more unknown fields this time, i.e. all the custom options should be
+    // parsed as extensions now.
+    extensions->clear();
+    GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
+        << "Find unknown fields in FileDescriptorProto when building "
+        << file_proto.name()
+        << ". It's likely that those fields are custom options, however, "
+           "those options cannot be recognized in the builder pool. "
+           "This normally should not happen. Please report a bug.";
+  }
+}
+
+// Our static initialization methods can become very, very large.
+// So large that if we aren't careful we end up blowing the JVM's
+// 64K bytes of bytecode/method. Fortunately, since these static
+// methods are executed only once near the beginning of a program,
+// there's usually plenty of stack space available and we can
+// extend our methods by simply chaining them to another method
+// with a tail call. This inserts the sequence call-next-method,
+// end this one, begin-next-method as needed.
+void MaybeRestartJavaMethod(io::Printer* printer, int* bytecode_estimate,
+                            int* method_num, const char* chain_statement,
+                            const char* method_decl) {
+  // The goal here is to stay under 64K bytes of jvm bytecode/method,
+  // since otherwise we hit a hardcoded limit in the jvm and javac will
+  // then fail with the error "code too large". This limit lets our
+  // estimates be off by a factor of two and still we're okay.
+  static const int bytesPerMethod = kMaxStaticSize;
+
+  if ((*bytecode_estimate) > bytesPerMethod) {
+    ++(*method_num);
+    printer->Print(chain_statement, "method_num", StrCat(*method_num));
+    printer->Outdent();
+    printer->Print("}\n");
+    printer->Print(method_decl, "method_num", StrCat(*method_num));
+    printer->Indent();
+    *bytecode_estimate = 0;
+  }
+}
+}  // namespace
+
+FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options,
+                             bool immutable_api)
+    : file_(file),
+      java_package_(FileJavaPackage(file, immutable_api)),
+      message_generators_(file->message_type_count()),
+      extension_generators_(file->extension_count()),
+      context_(new Context(file, options)),
+      name_resolver_(context_->GetNameResolver()),
+      options_(options),
+      immutable_api_(immutable_api) {
+  classname_ = name_resolver_->GetFileClassName(file, immutable_api);
+  generator_factory_.reset(new ImmutableGeneratorFactory(context_.get()));
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    message_generators_[i].reset(
+        generator_factory_->NewMessageGenerator(file_->message_type(i)));
+  }
+  for (int i = 0; i < file_->extension_count(); ++i) {
+    extension_generators_[i].reset(
+        generator_factory_->NewExtensionGenerator(file_->extension(i)));
+  }
+}
+
+FileGenerator::~FileGenerator() {}
+
+bool FileGenerator::Validate(std::string* error) {
+  // Check that no class name matches the file's class name.  This is a common
+  // problem that leads to Java compile errors that can be hard to understand.
+  // It's especially bad when using the java_multiple_files, since we would
+  // end up overwriting the outer class with one of the inner ones.
+  if (name_resolver_->HasConflictingClassName(file_, classname_,
+                                              NameEquality::EXACT_EQUAL)) {
+    error->assign(file_->name());
+    error->append(
+        ": Cannot generate Java output because the file's outer class name, "
+        "\"");
+    error->append(classname_);
+    error->append(
+        "\", matches the name of one of the types declared inside it.  "
+        "Please either rename the type or use the java_outer_classname "
+        "option to specify a different outer class name for the .proto file.");
+    return false;
+  }
+  // Similar to the check above, but ignore the case this time. This is not a
+  // problem on Linux, but will lead to Java compile errors on Windows / Mac
+  // because filenames are case-insensitive on those platforms.
+  if (name_resolver_->HasConflictingClassName(
+          file_, classname_, NameEquality::EQUAL_IGNORE_CASE)) {
+    GOOGLE_LOG(WARNING)
+        << file_->name() << ": The file's outer class name, \"" << classname_
+        << "\", matches the name of one of the types declared inside it when "
+        << "case is ignored. This can cause compilation issues on Windows / "
+        << "MacOS. Please either rename the type or use the "
+        << "java_outer_classname option to specify a different outer class "
+        << "name for the .proto file to be safe.";
+  }
+
+  // Print a warning if optimize_for = LITE_RUNTIME is used.
+  if (file_->options().optimize_for() == FileOptions::LITE_RUNTIME &&
+      !options_.enforce_lite) {
+    GOOGLE_LOG(WARNING)
+        << "The optimize_for = LITE_RUNTIME option is no longer supported by "
+        << "protobuf Java code generator and is ignored--protoc will always "
+        << "generate full runtime code for Java. To use Java Lite runtime, "
+        << "users should use the Java Lite plugin instead. See:\n"
+        << "  "
+           "https://github.com/protocolbuffers/protobuf/blob/main/java/"
+           "lite.md";
+  }
+  return true;
+}
+
+void FileGenerator::Generate(io::Printer* printer) {
+  // We don't import anything because we refer to all classes by their
+  // fully-qualified names in the generated source.
+  printer->Print(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n",
+      "filename", file_->name());
+  if (!java_package_.empty()) {
+    printer->Print(
+        "package $package$;\n"
+        "\n",
+        "package", java_package_);
+  }
+  PrintGeneratedAnnotation(
+      printer, '$', options_.annotate_code ? classname_ + ".java.pb.meta" : "");
+
+  printer->Print(
+      "$deprecation$public final class $classname$ {\n"
+      "  private $ctor$() {}\n",
+      "deprecation",
+      file_->options().deprecated() ? "@java.lang.Deprecated " : "",
+      "classname", classname_, "ctor", classname_);
+  printer->Annotate("classname", file_->name());
+  printer->Indent();
+
+  // -----------------------------------------------------------------
+
+  printer->Print(
+      "public static void registerAllExtensions(\n"
+      "    com.google.protobuf.ExtensionRegistryLite registry) {\n");
+
+  printer->Indent();
+
+  for (int i = 0; i < file_->extension_count(); i++) {
+    extension_generators_[i]->GenerateRegistrationCode(printer);
+  }
+
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->GenerateExtensionRegistrationCode(printer);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+  if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+    // Overload registerAllExtensions for the non-lite usage to
+    // redundantly maintain the original signature (this is
+    // redundant because ExtensionRegistryLite now invokes
+    // ExtensionRegistry in the non-lite usage). Intent is
+    // to remove this in the future.
+    printer->Print(
+        "\n"
+        "public static void registerAllExtensions(\n"
+        "    com.google.protobuf.ExtensionRegistry registry) {\n"
+        "  registerAllExtensions(\n"
+        "      (com.google.protobuf.ExtensionRegistryLite) registry);\n"
+        "}\n");
+  }
+
+  // -----------------------------------------------------------------
+
+  if (!MultipleJavaFiles(file_, immutable_api_)) {
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+        EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
+            .Generate(printer);
+      } else {
+        EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get())
+            .Generate(printer);
+      }
+    }
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateInterface(printer);
+      message_generators_[i]->Generate(printer);
+    }
+    if (HasGenericServices(file_, context_->EnforceLite())) {
+      for (int i = 0; i < file_->service_count(); i++) {
+        std::unique_ptr<ServiceGenerator> generator(
+            generator_factory_->NewServiceGenerator(file_->service(i)));
+        generator->Generate(printer);
+      }
+    }
+  }
+
+  // Extensions must be generated in the outer class since they are values,
+  // not classes.
+  for (int i = 0; i < file_->extension_count(); i++) {
+    extension_generators_[i]->Generate(printer);
+  }
+
+  // Static variables. We'd like them to be final if possible, but due to
+  // the JVM's 64k size limit on static blocks, we have to initialize some
+  // of them in methods; thus they cannot be final.
+  int static_block_bytecode_estimate = 0;
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->GenerateStaticVariables(
+        printer, &static_block_bytecode_estimate);
+  }
+
+  printer->Print("\n");
+
+  if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+    if (immutable_api_) {
+      GenerateDescriptorInitializationCodeForImmutable(printer);
+    } else {
+      GenerateDescriptorInitializationCodeForMutable(printer);
+    }
+  } else {
+    printer->Print("static {\n");
+    printer->Indent();
+    int bytecode_estimate = 0;
+    int method_num = 0;
+
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      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();
+    printer->Print("}\n");
+  }
+
+  printer->Print(
+      "\n"
+      "// @@protoc_insertion_point(outer_class_scope)\n");
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
+    io::Printer* printer) {
+  printer->Print(
+      "public static com.google.protobuf.Descriptors.FileDescriptor\n"
+      "    getDescriptor() {\n"
+      "  return descriptor;\n"
+      "}\n"
+      "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n"
+      "    descriptor;\n"
+      "static {\n",
+      // TODO(dweis): Mark this as final.
+      "final", "");
+  printer->Indent();
+
+  SharedCodeGenerator shared_code_generator(file_, options_);
+  shared_code_generator.GenerateDescriptors(printer);
+
+  int bytecode_estimate = 0;
+  int method_num = 0;
+
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    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++) {
+    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
+  // generate, when processing the ".proto" files. We call this DescriptorPool
+  // the parsed pool (a.k.a. file_->pool()).
+  //
+  // Note that when users try to extend the (.*)DescriptorProto in their
+  // ".proto" files, it does not affect the pre-built FileDescriptorProto class
+  // in proto compiler. When we put the descriptor data in the file_proto, those
+  // extensions become unknown fields.
+  //
+  // Now we need to find out all the extension value to the (.*)DescriptorProto
+  // in the file_proto message, and prepare an ExtensionRegistry to return.
+  //
+  // To find those extensions, we need to parse the data into a dynamic message
+  // of the FileDescriptor based on the builder-pool, then we can use
+  // reflections to find all extension fields
+  FileDescriptorProto file_proto;
+  file_->CopyTo(&file_proto);
+  std::string file_data;
+  file_proto.SerializeToString(&file_data);
+  FieldDescriptorSet extensions;
+  CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
+
+  if (extensions.size() > 0) {
+    // Must construct an ExtensionRegistry containing all existing extensions
+    // and use it to parse the descriptor data again to recognize extensions.
+    printer->Print(
+        "com.google.protobuf.ExtensionRegistry registry =\n"
+        "    com.google.protobuf.ExtensionRegistry.newInstance();\n");
+    FieldDescriptorSet::iterator it;
+    for (it = extensions.begin(); it != extensions.end(); it++) {
+      std::unique_ptr<ExtensionGenerator> generator(
+          generator_factory_->NewExtensionGenerator(*it));
+      bytecode_estimate += generator->GenerateRegistrationCode(printer);
+      MaybeRestartJavaMethod(
+          printer, &bytecode_estimate, &method_num,
+          "_clinit_autosplit_dinit_$method_num$(registry);\n",
+          "private static void _clinit_autosplit_dinit_$method_num$(\n"
+          "    com.google.protobuf.ExtensionRegistry registry) {\n");
+    }
+    printer->Print(
+        "com.google.protobuf.Descriptors.FileDescriptor\n"
+        "    .internalUpdateFileDescriptor(descriptor, registry);\n");
+  }
+
+  // Force descriptor initialization of all dependencies.
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    if (ShouldIncludeDependency(file_->dependency(i), true)) {
+      std::string dependency =
+          name_resolver_->GetImmutableClassName(file_->dependency(i));
+      printer->Print("$dependency$.getDescriptor();\n", "dependency",
+                     dependency);
+    }
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void FileGenerator::GenerateDescriptorInitializationCodeForMutable(
+    io::Printer* printer) {
+  printer->Print(
+      "public static com.google.protobuf.Descriptors.FileDescriptor\n"
+      "    getDescriptor() {\n"
+      "  return descriptor;\n"
+      "}\n"
+      "private static final com.google.protobuf.Descriptors.FileDescriptor\n"
+      "    descriptor;\n"
+      "static {\n");
+  printer->Indent();
+
+  printer->Print(
+      "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n",
+      "immutable_package", FileJavaPackage(file_, true), "descriptor_classname",
+      name_resolver_->GetDescriptorClassName(file_));
+
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->GenerateStaticVariableInitializers(printer);
+  }
+  for (int i = 0; i < file_->extension_count(); i++) {
+    extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
+  }
+
+  // Check if custom options exist. If any, try to load immutable classes since
+  // custom options are only represented with immutable messages.
+  FileDescriptorProto file_proto;
+  file_->CopyTo(&file_proto);
+  std::string file_data;
+  file_proto.SerializeToString(&file_data);
+  FieldDescriptorSet extensions;
+  CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
+
+  if (extensions.size() > 0) {
+    // Try to load immutable messages' outer class. Its initialization code
+    // will take care of interpreting custom options.
+    printer->Print(
+        "try {\n"
+        // Note that we have to load the immutable class dynamically here as
+        // we want the mutable code to be independent from the immutable code
+        // at compile time. It is required to implement dual-compile for
+        // mutable and immutable API in blaze.
+        "  java.lang.Class<?> immutableClass = java.lang.Class.forName(\n"
+        "      \"$immutable_classname$\");\n"
+        "} catch (java.lang.ClassNotFoundException e) {\n",
+        "immutable_classname", name_resolver_->GetImmutableClassName(file_));
+    printer->Indent();
+
+    // The immutable class can not be found. We try our best to collect all
+    // custom option extensions to interpret the custom options.
+    printer->Print(
+        "com.google.protobuf.ExtensionRegistry registry =\n"
+        "    com.google.protobuf.ExtensionRegistry.newInstance();\n"
+        "com.google.protobuf.MessageLite defaultExtensionInstance = null;\n");
+    FieldDescriptorSet::iterator it;
+    for (it = extensions.begin(); it != extensions.end(); it++) {
+      const FieldDescriptor* field = *it;
+      std::string scope;
+      if (field->extension_scope() != NULL) {
+        scope = name_resolver_->GetMutableClassName(field->extension_scope()) +
+                ".getDescriptor()";
+      } else {
+        scope = FileJavaPackage(field->file(), true) + "." +
+                name_resolver_->GetDescriptorClassName(field->file()) +
+                ".descriptor";
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        printer->Print(
+            "defaultExtensionInstance = com.google.protobuf.Internal\n"
+            "    .getDefaultInstance(\"$class$\");\n"
+            "if (defaultExtensionInstance != null) {\n"
+            "  registry.add(\n"
+            "      $scope$.getExtensions().get($index$),\n"
+            "      (com.google.protobuf.Message) defaultExtensionInstance);\n"
+            "}\n",
+            "scope", scope, "index", StrCat(field->index()), "class",
+            name_resolver_->GetImmutableClassName(field->message_type()));
+      } else {
+        printer->Print("registry.add($scope$.getExtensions().get($index$));\n",
+                       "scope", scope, "index", StrCat(field->index()));
+      }
+    }
+    printer->Print(
+        "com.google.protobuf.Descriptors.FileDescriptor\n"
+        "    .internalUpdateFileDescriptor(descriptor, registry);\n");
+
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
+  // Force descriptor initialization of all dependencies.
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    if (ShouldIncludeDependency(file_->dependency(i), false)) {
+      std::string dependency =
+          name_resolver_->GetMutableClassName(file_->dependency(i));
+      printer->Print("$dependency$.getDescriptor();\n", "dependency",
+                     dependency);
+    }
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+template <typename GeneratorClass, typename DescriptorClass>
+static void GenerateSibling(
+    const std::string& package_dir, const std::string& java_package,
+    const DescriptorClass* descriptor, GeneratorContext* context,
+    std::vector<std::string>* file_list, bool annotate_code,
+    std::vector<std::string>* annotation_list, const std::string& name_suffix,
+    GeneratorClass* generator,
+    void (GeneratorClass::*pfn)(io::Printer* printer)) {
+  std::string filename =
+      package_dir + descriptor->name() + name_suffix + ".java";
+  file_list->push_back(filename);
+  std::string info_full_path = filename + ".pb.meta";
+  GeneratedCodeInfo annotations;
+  io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+      &annotations);
+
+  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  io::Printer printer(output.get(), '$',
+                      annotate_code ? &annotation_collector : NULL);
+
+  printer.Print(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n",
+      "filename", descriptor->file()->name());
+  if (!java_package.empty()) {
+    printer.Print(
+        "package $package$;\n"
+        "\n",
+        "package", java_package);
+  }
+
+  (generator->*pfn)(&printer);
+
+  if (annotate_code) {
+    std::unique_ptr<io::ZeroCopyOutputStream> info_output(
+        context->Open(info_full_path));
+    annotations.SerializeToZeroCopyStream(info_output.get());
+    annotation_list->push_back(info_full_path);
+  }
+}
+
+void FileGenerator::GenerateSiblings(
+    const std::string& package_dir, GeneratorContext* context,
+    std::vector<std::string>* file_list,
+    std::vector<std::string>* annotation_list) {
+  if (MultipleJavaFiles(file_, immutable_api_)) {
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+        EnumGenerator generator(file_->enum_type(i), immutable_api_,
+                                context_.get());
+        GenerateSibling<EnumGenerator>(
+            package_dir, java_package_, file_->enum_type(i), context, file_list,
+            options_.annotate_code, annotation_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,
+            options_.annotate_code, annotation_list, "", &generator,
+            &EnumLiteGenerator::Generate);
+      }
+    }
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      if (immutable_api_) {
+        GenerateSibling<MessageGenerator>(
+            package_dir, java_package_, file_->message_type(i), context,
+            file_list, options_.annotate_code, annotation_list, "OrBuilder",
+            message_generators_[i].get(), &MessageGenerator::GenerateInterface);
+      }
+      GenerateSibling<MessageGenerator>(
+          package_dir, java_package_, file_->message_type(i), context,
+          file_list, options_.annotate_code, annotation_list, "",
+          message_generators_[i].get(), &MessageGenerator::Generate);
+    }
+    if (HasGenericServices(file_, context_->EnforceLite())) {
+      for (int i = 0; i < file_->service_count(); i++) {
+        std::unique_ptr<ServiceGenerator> generator(
+            generator_factory_->NewServiceGenerator(file_->service(i)));
+        GenerateSibling<ServiceGenerator>(
+            package_dir, java_package_, file_->service(i), context, file_list,
+            options_.annotate_code, annotation_list, "", generator.get(),
+            &ServiceGenerator::Generate);
+      }
+    }
+  }
+}
+
+std::string FileGenerator::GetKotlinClassname() {
+  return name_resolver_->GetFileClassName(file_, immutable_api_, true);
+}
+
+void FileGenerator::GenerateKotlinSiblings(
+    const std::string& package_dir, GeneratorContext* context,
+    std::vector<std::string>* file_list,
+    std::vector<std::string>* annotation_list) {
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    const Descriptor* descriptor = file_->message_type(i);
+    MessageGenerator* generator = message_generators_[i].get();
+    auto open_file = [context](const std::string& filename) {
+      return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename));
+    };
+    std::string filename = package_dir + descriptor->name() + "Kt.kt";
+    file_list->push_back(filename);
+    std::string info_full_path = filename + ".pb.meta";
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    auto output = open_file(filename);
+    io::Printer printer(
+        output.get(), '$',
+        options_.annotate_code ? &annotation_collector : nullptr);
+
+    printer.Print(
+        "//Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+        "// source: $filename$\n"
+        "\n",
+        "filename", descriptor->file()->name());
+    if (!java_package_.empty()) {
+      printer.Print(
+          "package $package$;\n"
+          "\n",
+          "package", java_package_);
+    }
+
+    generator->GenerateKotlinMembers(&printer);
+    generator->GenerateTopLevelKotlinMembers(&printer);
+
+    if (options_.annotate_code) {
+      auto info_output = open_file(info_full_path);
+      annotations.SerializeToZeroCopyStream(info_output.get());
+      annotation_list->push_back(info_full_path);
+    }
+  }
+}
+
+bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor,
+                                            bool immutable_api) {
+  return true;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/file.h b/src/google/protobuf/compiler/java/file.h
new file mode 100644
index 0000000..b2e0373
--- /dev/null
+++ b/src/google/protobuf/compiler/java/file.h
@@ -0,0 +1,126 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/options.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor;  // descriptor.h
+namespace io {
+class Printer;  // printer.h
+}
+namespace compiler {
+class GeneratorContext;  // code_generator.h
+namespace java {
+class Context;             // context.h
+class MessageGenerator;    // message.h
+class GeneratorFactory;    // generator_factory.h
+class ExtensionGenerator;  // extension.h
+class ClassNameResolver;   // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class FileGenerator {
+ public:
+  FileGenerator(const FileDescriptor* file, const Options& options,
+                bool immutable_api = true);
+  ~FileGenerator();
+
+  // Checks for problems that would otherwise lead to cryptic compile errors.
+  // Returns true if there are no problems, or writes an error description to
+  // the given string and returns false otherwise.
+  bool Validate(std::string* error);
+
+  void Generate(io::Printer* printer);
+
+  std::string GetKotlinClassname();
+  void GenerateKotlinSiblings(const std::string& package_dir,
+                              GeneratorContext* generator_context,
+                              std::vector<std::string>* file_list,
+                              std::vector<std::string>* annotation_list);
+
+  // If we aren't putting everything into one file, this will write all the
+  // files other than the outer file (i.e. one for each message, enum, and
+  // service type).
+  void GenerateSiblings(const std::string& package_dir,
+                        GeneratorContext* generator_context,
+                        std::vector<std::string>* file_list,
+                        std::vector<std::string>* annotation_list);
+
+  const std::string& java_package() { return java_package_; }
+  const std::string& classname() { return classname_; }
+
+ private:
+  void GenerateDescriptorInitializationCodeForImmutable(io::Printer* printer);
+  void GenerateDescriptorInitializationCodeForMutable(io::Printer* printer);
+
+  bool ShouldIncludeDependency(const FileDescriptor* descriptor,
+                               bool immutable_api_);
+
+  const FileDescriptor* file_;
+  std::string java_package_;
+  std::string classname_;
+
+  std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
+  std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_;
+  std::unique_ptr<GeneratorFactory> generator_factory_;
+  std::unique_ptr<Context> context_;
+  ClassNameResolver* name_resolver_;
+  const Options options_;
+  bool immutable_api_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
diff --git a/src/google/protobuf/compiler/java/generator.cc b/src/google/protobuf/compiler/java/generator.cc
new file mode 100644
index 0000000..85e3991
--- /dev/null
+++ b/src/google/protobuf/compiler/java/generator.cc
@@ -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: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/generator.h>
+
+
+#include <memory>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/compiler/java/file.h>
+#include <google/protobuf/compiler/java/generator_factory.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/compiler/java/options.h>
+#include <google/protobuf/compiler/java/shared_code_generator.h>
+#include <google/protobuf/descriptor.pb.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+
+JavaGenerator::JavaGenerator() {}
+JavaGenerator::~JavaGenerator() {}
+
+uint64_t JavaGenerator::GetSupportedFeatures() const {
+  return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
+}
+
+bool JavaGenerator::Generate(const FileDescriptor* file,
+                             const std::string& parameter,
+                             GeneratorContext* context,
+                             std::string* error) const {
+  // -----------------------------------------------------------------
+  // parse generator options
+
+  std::vector<std::pair<std::string, std::string> > options;
+  ParseGeneratorParameter(parameter, &options);
+  Options file_options;
+
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "output_list_file") {
+      file_options.output_list_file = options[i].second;
+    } else if (options[i].first == "immutable") {
+      file_options.generate_immutable_code = true;
+    } else if (options[i].first == "mutable") {
+      file_options.generate_mutable_code = true;
+    } else if (options[i].first == "shared") {
+      file_options.generate_shared_code = true;
+    } else if (options[i].first == "lite") {
+      // Note: Java Lite does not guarantee API/ABI stability. We may choose to
+      // break existing API in order to boost performance / reduce code size.
+      file_options.enforce_lite = true;
+    } else if (options[i].first == "annotate_code") {
+      file_options.annotate_code = true;
+    } else if (options[i].first == "annotation_list_file") {
+      file_options.annotation_list_file = options[i].second;
+    } else {
+      *error = "Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  if (file_options.enforce_lite && file_options.generate_mutable_code) {
+    *error = "lite runtime generator option cannot be used with mutable API.";
+    return false;
+  }
+
+  // By default we generate immutable code and shared code for immutable API.
+  if (!file_options.generate_immutable_code &&
+      !file_options.generate_mutable_code &&
+      !file_options.generate_shared_code) {
+    file_options.generate_immutable_code = true;
+    file_options.generate_shared_code = true;
+  }
+
+  // -----------------------------------------------------------------
+
+
+  std::vector<std::string> all_files;
+  std::vector<std::string> all_annotations;
+
+
+  std::vector<FileGenerator*> file_generators;
+  if (file_options.generate_immutable_code) {
+    file_generators.push_back(new FileGenerator(file, file_options,
+                                                /* immutable = */ true));
+  }
+  if (file_options.generate_mutable_code) {
+    file_generators.push_back(new FileGenerator(file, file_options,
+                                                /* mutable = */ false));
+  }
+
+  for (int i = 0; i < file_generators.size(); ++i) {
+    if (!file_generators[i]->Validate(error)) {
+      for (int j = 0; j < file_generators.size(); ++j) {
+        delete file_generators[j];
+      }
+      return false;
+    }
+  }
+
+  for (int i = 0; i < file_generators.size(); ++i) {
+    FileGenerator* file_generator = file_generators[i];
+
+    std::string package_dir = JavaPackageToDir(file_generator->java_package());
+
+    std::string java_filename = package_dir;
+    java_filename += file_generator->classname();
+    java_filename += ".java";
+    all_files.push_back(java_filename);
+    std::string info_full_path = java_filename + ".pb.meta";
+    if (file_options.annotate_code) {
+      all_annotations.push_back(info_full_path);
+    }
+
+    // Generate main java file.
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        context->Open(java_filename));
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    io::Printer printer(
+        output.get(), '$',
+        file_options.annotate_code ? &annotation_collector : NULL);
+
+    file_generator->Generate(&printer);
+
+    // Generate sibling files.
+    file_generator->GenerateSiblings(package_dir, context, &all_files,
+                                     &all_annotations);
+
+    if (file_options.annotate_code) {
+      std::unique_ptr<io::ZeroCopyOutputStream> info_output(
+          context->Open(info_full_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
+  }
+
+
+  for (int i = 0; i < file_generators.size(); ++i) {
+    delete file_generators[i];
+  }
+  file_generators.clear();
+
+  // Generate output list if requested.
+  if (!file_options.output_list_file.empty()) {
+    // Generate output list.  This is just a simple text file placed in a
+    // deterministic location which lists the .java files being generated.
+    std::unique_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+        context->Open(file_options.output_list_file));
+    io::Printer srclist_printer(srclist_raw_output.get(), '$');
+    for (int i = 0; i < all_files.size(); i++) {
+      srclist_printer.Print("$filename$\n", "filename", all_files[i]);
+    }
+  }
+
+  if (!file_options.annotation_list_file.empty()) {
+    // Generate output list.  This is just a simple text file placed in a
+    // deterministic location which lists the .java files being generated.
+    std::unique_ptr<io::ZeroCopyOutputStream> annotation_list_raw_output(
+        context->Open(file_options.annotation_list_file));
+    io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
+    for (int i = 0; i < all_annotations.size(); i++) {
+      annotation_list_printer.Print("$filename$\n", "filename",
+                                    all_annotations[i]);
+    }
+  }
+
+  return true;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/generator.h b/src/google/protobuf/compiler/java/generator.h
new file mode 100644
index 0000000..bbc7170
--- /dev/null
+++ b/src/google/protobuf/compiler/java/generator.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Generates Java code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// CodeGenerator implementation which generates Java code.  If you create your
+// own protocol compiler binary and you want it to support Java output, you
+// can do so by registering an instance of this CodeGenerator with the
+// CommandLineInterface in your main() function.
+class PROTOC_EXPORT JavaGenerator : public CodeGenerator {
+ public:
+  JavaGenerator();
+  ~JavaGenerator() override;
+
+  // implements CodeGenerator ----------------------------------------
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/java/generator_factory.cc b/src/google/protobuf/compiler/java/generator_factory.cc
new file mode 100644
index 0000000..dd526ba
--- /dev/null
+++ b/src/google/protobuf/compiler/java/generator_factory.cc
@@ -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: liujisi@google.com (Pherl Liu)
+
+#include <google/protobuf/compiler/java/generator_factory.h>
+
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/enum_field.h>
+#include <google/protobuf/compiler/java/extension.h>
+#include <google/protobuf/compiler/java/extension_lite.h>
+#include <google/protobuf/compiler/java/field.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/message.h>
+#include <google/protobuf/compiler/java/message_lite.h>
+#include <google/protobuf/compiler/java/service.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+GeneratorFactory::GeneratorFactory() {}
+GeneratorFactory::~GeneratorFactory() {}
+
+// ===================================================================
+
+ImmutableGeneratorFactory::ImmutableGeneratorFactory(Context* context)
+    : context_(context) {}
+ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {}
+
+MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
+    const Descriptor* descriptor) const {
+  if (HasDescriptorMethods(descriptor, context_->EnforceLite())) {
+    return new ImmutableMessageGenerator(descriptor, context_);
+  } else {
+    return new ImmutableMessageLiteGenerator(descriptor, context_);
+  }
+}
+
+ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
+    const FieldDescriptor* descriptor) const {
+  if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) {
+    return new ImmutableExtensionGenerator(descriptor, context_);
+  } else {
+    return new ImmutableExtensionLiteGenerator(descriptor, context_);
+  }
+}
+
+ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator(
+    const ServiceDescriptor* descriptor) const {
+  return new ImmutableServiceGenerator(descriptor, context_);
+}
+
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/generator_factory.h b/src/google/protobuf/compiler/java/generator_factory.h
new file mode 100644
index 0000000..807bca3
--- /dev/null
+++ b/src/google/protobuf/compiler/java/generator_factory.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: liujisi@google.com (Pherl Liu)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class FieldDescriptor;    // descriptor.h
+class Descriptor;         // descriptor.h
+class ServiceDescriptor;  // descriptor.h
+namespace compiler {
+namespace java {
+class MessageGenerator;    // message.h
+class ExtensionGenerator;  // extension.h
+class ServiceGenerator;    // service.h
+class Context;             // context.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class GeneratorFactory {
+ public:
+  GeneratorFactory();
+  virtual ~GeneratorFactory();
+
+  virtual MessageGenerator* NewMessageGenerator(
+      const Descriptor* descriptor) const = 0;
+
+  virtual ExtensionGenerator* NewExtensionGenerator(
+      const FieldDescriptor* descriptor) const = 0;
+
+  virtual ServiceGenerator* NewServiceGenerator(
+      const ServiceDescriptor* descriptor) const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorFactory);
+};
+
+// Factory that creates generators for immutable-default messages.
+class ImmutableGeneratorFactory : public GeneratorFactory {
+ public:
+  ImmutableGeneratorFactory(Context* context);
+  ~ImmutableGeneratorFactory() override;
+
+  MessageGenerator* NewMessageGenerator(
+      const Descriptor* descriptor) const override;
+
+  ExtensionGenerator* NewExtensionGenerator(
+      const FieldDescriptor* descriptor) const override;
+
+  ServiceGenerator* NewServiceGenerator(
+      const ServiceDescriptor* descriptor) const override;
+
+ private:
+  Context* context_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableGeneratorFactory);
+};
+
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
diff --git a/src/google/protobuf/compiler/java/helpers.cc b/src/google/protobuf/compiler/java/helpers.cc
new file mode 100644
index 0000000..15ee8f5
--- /dev/null
+++ b/src/google/protobuf/compiler/java/helpers.cc
@@ -0,0 +1,1115 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/helpers.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/compiler/java/names.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/hash.h>  // for hash<T *>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+const char kThickSeparator[] =
+    "// ===================================================================\n";
+const char kThinSeparator[] =
+    "// -------------------------------------------------------------------\n";
+
+namespace {
+
+const char* kDefaultPackage = "";
+
+// Names that should be avoided (in UpperCamelCase format).
+// Using them will cause the compiler to generate accessors whose names
+// collide with methods defined in base classes.
+// Keep this list in sync with specialFieldNames in
+// java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
+const char* kForbiddenWordList[] = {
+    // java.lang.Object:
+    "Class",
+    // com.google.protobuf.MessageLiteOrBuilder:
+    "DefaultInstanceForType",
+    // com.google.protobuf.MessageLite:
+    "ParserForType",
+    "SerializedSize",
+    // com.google.protobuf.MessageOrBuilder:
+    "AllFields",
+    "DescriptorForType",
+    "InitializationErrorString",
+    "UnknownFields",
+    // obsolete. kept for backwards compatibility of generated code
+    "CachedSize",
+};
+
+const std::unordered_set<std::string>* kReservedNames =
+    new std::unordered_set<std::string>({
+        "abstract",   "assert",       "boolean",   "break",      "byte",
+        "case",       "catch",        "char",      "class",      "const",
+        "continue",   "default",      "do",        "double",     "else",
+        "enum",       "extends",      "final",     "finally",    "float",
+        "for",        "goto",         "if",        "implements", "import",
+        "instanceof", "int",          "interface", "long",       "native",
+        "new",        "package",      "private",   "protected",  "public",
+        "return",     "short",        "static",    "strictfp",   "super",
+        "switch",     "synchronized", "this",      "throw",      "throws",
+        "transient",  "try",          "void",      "volatile",   "while",
+    });
+
+bool IsForbidden(const std::string& field_name) {
+  for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) {
+    if (UnderscoresToCamelCase(field_name, true) == kForbiddenWordList[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+std::string FieldName(const FieldDescriptor* field) {
+  std::string field_name;
+  // Groups are hacky:  The name of the field is just the lower-cased name
+  // of the group type.  In Java, though, we would like to retain the original
+  // capitalization of the type name.
+  if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
+    field_name = field->message_type()->name();
+  } else {
+    field_name = field->name();
+  }
+  if (IsForbidden(field_name)) {
+    // Append a trailing "#" to indicate that the name should be decorated to
+    // avoid collision with other names.
+    field_name += "#";
+  }
+  return field_name;
+}
+
+
+}  // namespace
+
+void PrintGeneratedAnnotation(io::Printer* printer, char delimiter,
+                              const std::string& annotation_file) {
+  if (annotation_file.empty()) {
+    return;
+  }
+  std::string ptemplate =
+      "@javax.annotation.Generated(value=\"protoc\", comments=\"annotations:";
+  ptemplate.push_back(delimiter);
+  ptemplate.append("annotation_file");
+  ptemplate.push_back(delimiter);
+  ptemplate.append("\")\n");
+  printer->Print(ptemplate.c_str(), "annotation_file", annotation_file);
+}
+
+void PrintEnumVerifierLogic(io::Printer* printer,
+                            const FieldDescriptor* descriptor,
+                            const std::map<std::string, std::string>& variables,
+                            const char* var_name,
+                            const char* terminating_string, bool enforce_lite) {
+  std::string enum_verifier_string =
+      enforce_lite ? StrCat(var_name, ".internalGetVerifier()")
+                   : StrCat(
+                         "new com.google.protobuf.Internal.EnumVerifier() {\n"
+                         "        @java.lang.Override\n"
+                         "        public boolean isInRange(int number) {\n"
+                         "          return ",
+                         var_name,
+                         ".forNumber(number) != null;\n"
+                         "        }\n"
+                         "      }");
+  printer->Print(
+      variables,
+      StrCat(enum_verifier_string, terminating_string).c_str());
+}
+
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter) {
+  GOOGLE_CHECK(!input.empty());
+  std::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;
+    }
+  }
+  // Add a trailing "_" if the name should be altered.
+  if (input[input.size() - 1] == '#') {
+    result += '_';
+  }
+  return result;
+}
+
+std::string ToCamelCase(const std::string& input, bool lower_first) {
+  bool capitalize_next = !lower_first;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char i : input) {
+    if (i == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpperCh(i));
+      capitalize_next = false;
+    } else {
+      result.push_back(i);
+    }
+  }
+
+  // Lower-case the first letter.
+  if (lower_first && !result.empty()) {
+    result[0] = ToLowerCh(result[0]);
+  }
+
+  return result;
+}
+
+char ToUpperCh(char ch) {
+  return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
+}
+
+char ToLowerCh(char ch) {
+  return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
+}
+
+std::string UnderscoresToCamelCase(const FieldDescriptor* field) {
+  return UnderscoresToCamelCase(FieldName(field), false);
+}
+
+std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
+  return UnderscoresToCamelCase(FieldName(field), true);
+}
+
+std::string CapitalizedFieldName(const FieldDescriptor* field) {
+  return UnderscoresToCapitalizedCamelCase(field);
+}
+
+std::string UnderscoresToCamelCase(const MethodDescriptor* method) {
+  return UnderscoresToCamelCase(method->name(), false);
+}
+
+std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field) {
+  std::string name = UnderscoresToCamelCase(field);
+  if (kReservedNames->find(name) != kReservedNames->end()) {
+    return name + "_";
+  }
+  return name;
+}
+
+// Names that should be avoided as field names in Kotlin.
+// All Kotlin hard keywords are in this list.
+const std::unordered_set<std::string>* kKotlinForbiddenNames =
+    new std::unordered_set<std::string>({
+        "as",    "as?",   "break", "class",  "continue",  "do",     "else",
+        "false", "for",   "fun",   "if",     "in",        "!in",    "interface",
+        "is",    "!is",   "null",  "object", "package",   "return", "super",
+        "this",  "throw", "true",  "try",    "typealias", "typeof", "val",
+        "var",   "when",  "while",
+    });
+
+bool IsForbiddenKotlin(const std::string& field_name) {
+  return kKotlinForbiddenNames->find(field_name) !=
+         kKotlinForbiddenNames->end();
+}
+
+std::string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
+  return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
+}
+
+std::string CamelCaseFieldName(const FieldDescriptor* field) {
+  std::string fieldName = UnderscoresToCamelCase(field);
+  if ('0' <= fieldName[0] && fieldName[0] <= '9') {
+    return '_' + fieldName;
+  }
+  return fieldName;
+}
+
+std::string FileClassName(const FileDescriptor* file, bool immutable) {
+  ClassNameResolver name_resolver;
+  return name_resolver.GetFileClassName(file, immutable);
+}
+
+std::string FileJavaPackage(const FileDescriptor* file, bool immutable) {
+  std::string result;
+
+  if (file->options().has_java_package()) {
+    result = file->options().java_package();
+  } else {
+    result = kDefaultPackage;
+    if (!file->package().empty()) {
+      if (!result.empty()) result += '.';
+      result += file->package();
+    }
+  }
+
+  return result;
+}
+
+std::string FileJavaPackage(const FileDescriptor* file) {
+  return FileJavaPackage(file, true /* immutable */);
+}
+
+std::string JavaPackageToDir(std::string package_name) {
+  std::string package_dir = StringReplace(package_name, ".", "/", true);
+  if (!package_dir.empty()) package_dir += "/";
+  return package_dir;
+}
+
+std::string ClassName(const Descriptor* descriptor) {
+  ClassNameResolver name_resolver;
+  return name_resolver.GetClassName(descriptor, true);
+}
+
+std::string ClassName(const EnumDescriptor* descriptor) {
+  ClassNameResolver name_resolver;
+  return name_resolver.GetClassName(descriptor, true);
+}
+
+std::string ClassName(const ServiceDescriptor* descriptor) {
+  ClassNameResolver name_resolver;
+  return name_resolver.GetClassName(descriptor, true);
+}
+
+std::string ClassName(const FileDescriptor* descriptor) {
+  ClassNameResolver name_resolver;
+  return name_resolver.GetClassName(descriptor, true);
+}
+
+
+std::string ExtraMessageInterfaces(const Descriptor* descriptor) {
+  std::string interfaces = "// @@protoc_insertion_point(message_implements:" +
+                           descriptor->full_name() + ")";
+  return interfaces;
+}
+
+
+std::string ExtraBuilderInterfaces(const Descriptor* descriptor) {
+  std::string interfaces = "// @@protoc_insertion_point(builder_implements:" +
+                           descriptor->full_name() + ")";
+  return interfaces;
+}
+
+std::string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor) {
+  std::string interfaces = "// @@protoc_insertion_point(interface_extends:" +
+                           descriptor->full_name() + ")";
+  return interfaces;
+}
+
+std::string FieldConstantName(const FieldDescriptor* field) {
+  std::string name = field->name() + "_FIELD_NUMBER";
+  ToUpper(&name);
+  return name;
+}
+
+FieldDescriptor::Type GetType(const FieldDescriptor* field) {
+  return field->type();
+}
+
+JavaType GetJavaType(const FieldDescriptor* field) {
+  switch (GetType(field)) {
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_SFIXED32:
+      return JAVATYPE_INT;
+
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+      return JAVATYPE_LONG;
+
+    case FieldDescriptor::TYPE_FLOAT:
+      return JAVATYPE_FLOAT;
+
+    case FieldDescriptor::TYPE_DOUBLE:
+      return JAVATYPE_DOUBLE;
+
+    case FieldDescriptor::TYPE_BOOL:
+      return JAVATYPE_BOOLEAN;
+
+    case FieldDescriptor::TYPE_STRING:
+      return JAVATYPE_STRING;
+
+    case FieldDescriptor::TYPE_BYTES:
+      return JAVATYPE_BYTES;
+
+    case FieldDescriptor::TYPE_ENUM:
+      return JAVATYPE_ENUM;
+
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      return JAVATYPE_MESSAGE;
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return JAVATYPE_INT;
+}
+
+const char* PrimitiveTypeName(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT:
+      return "int";
+    case JAVATYPE_LONG:
+      return "long";
+    case JAVATYPE_FLOAT:
+      return "float";
+    case JAVATYPE_DOUBLE:
+      return "double";
+    case JAVATYPE_BOOLEAN:
+      return "boolean";
+    case JAVATYPE_STRING:
+      return "java.lang.String";
+    case JAVATYPE_BYTES:
+      return "com.google.protobuf.ByteString";
+    case JAVATYPE_ENUM:
+      return NULL;
+    case JAVATYPE_MESSAGE:
+      return NULL;
+
+      // No default because we want the compiler to complain if any new
+      // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+const char* PrimitiveTypeName(const FieldDescriptor* descriptor) {
+  return PrimitiveTypeName(GetJavaType(descriptor));
+}
+
+const char* BoxedPrimitiveTypeName(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT:
+      return "java.lang.Integer";
+    case JAVATYPE_LONG:
+      return "java.lang.Long";
+    case JAVATYPE_FLOAT:
+      return "java.lang.Float";
+    case JAVATYPE_DOUBLE:
+      return "java.lang.Double";
+    case JAVATYPE_BOOLEAN:
+      return "java.lang.Boolean";
+    case JAVATYPE_STRING:
+      return "java.lang.String";
+    case JAVATYPE_BYTES:
+      return "com.google.protobuf.ByteString";
+    case JAVATYPE_ENUM:
+      return NULL;
+    case JAVATYPE_MESSAGE:
+      return NULL;
+
+      // No default because we want the compiler to complain if any new
+      // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+const char* BoxedPrimitiveTypeName(const FieldDescriptor* descriptor) {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor));
+}
+
+const char* KotlinTypeName(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT:
+      return "kotlin.Int";
+    case JAVATYPE_LONG:
+      return "kotlin.Long";
+    case JAVATYPE_FLOAT:
+      return "kotlin.Float";
+    case JAVATYPE_DOUBLE:
+      return "kotlin.Double";
+    case JAVATYPE_BOOLEAN:
+      return "kotlin.Boolean";
+    case JAVATYPE_STRING:
+      return "kotlin.String";
+    case JAVATYPE_BYTES:
+      return "com.google.protobuf.ByteString";
+    case JAVATYPE_ENUM:
+      return NULL;
+    case JAVATYPE_MESSAGE:
+      return NULL;
+
+      // No default because we want the compiler to complain if any new
+      // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+std::string GetOneofStoredType(const FieldDescriptor* field) {
+  const JavaType javaType = GetJavaType(field);
+  switch (javaType) {
+    case JAVATYPE_ENUM:
+      return "java.lang.Integer";
+    case JAVATYPE_MESSAGE:
+      return ClassName(field->message_type());
+    default:
+      return BoxedPrimitiveTypeName(javaType);
+  }
+}
+
+const char* FieldTypeName(FieldDescriptor::Type field_type) {
+  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";
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+bool AllAscii(const std::string& text) {
+  for (int i = 0; i < text.size(); i++) {
+    if ((text[i] & 0x80) != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+std::string DefaultValue(const FieldDescriptor* field, bool immutable,
+                         ClassNameResolver* name_resolver) {
+  // Switch on CppType since we need to know which default_value_* method
+  // of FieldDescriptor to call.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return StrCat(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      // Need to print as a signed int since Java has no unsigned.
+      return StrCat(static_cast<int32_t>(field->default_value_uint32()));
+    case FieldDescriptor::CPPTYPE_INT64:
+      return StrCat(field->default_value_int64()) + "L";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return StrCat(static_cast<int64_t>(field->default_value_uint64())) +
+             "L";
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value = field->default_value_double();
+      if (value == std::numeric_limits<double>::infinity()) {
+        return "Double.POSITIVE_INFINITY";
+      } else if (value == -std::numeric_limits<double>::infinity()) {
+        return "Double.NEGATIVE_INFINITY";
+      } else if (value != value) {
+        return "Double.NaN";
+      } else {
+        return SimpleDtoa(value) + "D";
+      }
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value = field->default_value_float();
+      if (value == std::numeric_limits<float>::infinity()) {
+        return "Float.POSITIVE_INFINITY";
+      } else if (value == -std::numeric_limits<float>::infinity()) {
+        return "Float.NEGATIVE_INFINITY";
+      } else if (value != value) {
+        return "Float.NaN";
+      } else {
+        return SimpleFtoa(value) + "F";
+      }
+    }
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (GetType(field) == FieldDescriptor::TYPE_BYTES) {
+        if (field->has_default_value()) {
+          // See comments in Internal.java for gory details.
+          return strings::Substitute(
+              "com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
+              CEscape(field->default_value_string()));
+        } else {
+          return "com.google.protobuf.ByteString.EMPTY";
+        }
+      } else {
+        if (AllAscii(field->default_value_string())) {
+          // All chars are ASCII.  In this case CEscape() works fine.
+          return "\"" + CEscape(field->default_value_string()) + "\"";
+        } else {
+          // See comments in Internal.java for gory details.
+          return strings::Substitute(
+              "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
+              CEscape(field->default_value_string()));
+        }
+      }
+
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return name_resolver->GetClassName(field->enum_type(), immutable) + "." +
+             field->default_value_enum()->name();
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return name_resolver->GetClassName(field->message_type(), immutable) +
+             ".getDefaultInstance()";
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return "";
+}
+
+bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
+  // Switch on CppType since we need to know which default_value_* method
+  // of FieldDescriptor to call.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return field->default_value_int32() == 0;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return field->default_value_uint32() == 0;
+    case FieldDescriptor::CPPTYPE_INT64:
+      return field->default_value_int64() == 0L;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return field->default_value_uint64() == 0L;
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return field->default_value_double() == 0.0;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return field->default_value_float() == 0.0;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() == false;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return field->default_value_enum()->number() == 0;
+    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return false;
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field) {
+  return GetJavaType(field) == JAVATYPE_BYTES &&
+         field->default_value_string() != "";
+}
+
+const char* bit_masks[] = {
+    "0x00000001", "0x00000002", "0x00000004", "0x00000008",
+    "0x00000010", "0x00000020", "0x00000040", "0x00000080",
+
+    "0x00000100", "0x00000200", "0x00000400", "0x00000800",
+    "0x00001000", "0x00002000", "0x00004000", "0x00008000",
+
+    "0x00010000", "0x00020000", "0x00040000", "0x00080000",
+    "0x00100000", "0x00200000", "0x00400000", "0x00800000",
+
+    "0x01000000", "0x02000000", "0x04000000", "0x08000000",
+    "0x10000000", "0x20000000", "0x40000000", "0x80000000",
+};
+
+std::string GetBitFieldName(int index) {
+  std::string varName = "bitField";
+  varName += StrCat(index);
+  varName += "_";
+  return varName;
+}
+
+std::string GetBitFieldNameForBit(int bitIndex) {
+  return GetBitFieldName(bitIndex / 32);
+}
+
+namespace {
+
+std::string GenerateGetBitInternal(const std::string& prefix, int bitIndex) {
+  std::string varName = prefix + GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  std::string mask = bit_masks[bitInVarIndex];
+  std::string result = "((" + varName + " & " + mask + ") != 0)";
+  return result;
+}
+
+std::string GenerateSetBitInternal(const std::string& prefix, int bitIndex) {
+  std::string varName = prefix + GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  std::string mask = bit_masks[bitInVarIndex];
+  std::string result = varName + " |= " + mask;
+  return result;
+}
+
+}  // namespace
+
+std::string GenerateGetBit(int bitIndex) {
+  return GenerateGetBitInternal("", bitIndex);
+}
+
+std::string GenerateSetBit(int bitIndex) {
+  return GenerateSetBitInternal("", bitIndex);
+}
+
+std::string GenerateClearBit(int bitIndex) {
+  std::string varName = GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  std::string mask = bit_masks[bitInVarIndex];
+  std::string result = varName + " = (" + varName + " & ~" + mask + ")";
+  return result;
+}
+
+std::string GenerateGetBitFromLocal(int bitIndex) {
+  return GenerateGetBitInternal("from_", bitIndex);
+}
+
+std::string GenerateSetBitToLocal(int bitIndex) {
+  return GenerateSetBitInternal("to_", bitIndex);
+}
+
+std::string GenerateGetBitMutableLocal(int bitIndex) {
+  return GenerateGetBitInternal("mutable_", bitIndex);
+}
+
+std::string GenerateSetBitMutableLocal(int bitIndex) {
+  return GenerateSetBitInternal("mutable_", bitIndex);
+}
+
+bool IsReferenceType(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT:
+      return false;
+    case JAVATYPE_LONG:
+      return false;
+    case JAVATYPE_FLOAT:
+      return false;
+    case JAVATYPE_DOUBLE:
+      return false;
+    case JAVATYPE_BOOLEAN:
+      return false;
+    case JAVATYPE_STRING:
+      return true;
+    case JAVATYPE_BYTES:
+      return true;
+    case JAVATYPE_ENUM:
+      return true;
+    case JAVATYPE_MESSAGE:
+      return true;
+
+      // No default because we want the compiler to complain if any new
+      // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable) {
+  switch (GetType(field)) {
+    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";
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+// For encodings with fixed sizes, returns that size in bytes.  Otherwise
+// returns -1.
+int FixedSize(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 WireFormatLite::kFixed32Size;
+    case FieldDescriptor::TYPE_FIXED64:
+      return WireFormatLite::kFixed64Size;
+    case FieldDescriptor::TYPE_SFIXED32:
+      return WireFormatLite::kSFixed32Size;
+    case FieldDescriptor::TYPE_SFIXED64:
+      return WireFormatLite::kSFixed64Size;
+    case FieldDescriptor::TYPE_FLOAT:
+      return WireFormatLite::kFloatSize;
+    case FieldDescriptor::TYPE_DOUBLE:
+      return WireFormatLite::kDoubleSize;
+
+    case FieldDescriptor::TYPE_BOOL:
+      return 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;
+}
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it. The caller should delete the returned array.
+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);
+  }
+  std::sort(fields, fields + descriptor->field_count(),
+            FieldOrderingByNumber());
+  return fields;
+}
+
+// Returns true if the message type has any required fields.  If it doesn't,
+// we can optimize out calls to its isInitialized() method.
+//
+// already_seen is used to avoid checking the same type multiple times
+// (and also to protect against recursion).
+bool HasRequiredFields(const Descriptor* type,
+                       std::unordered_set<const Descriptor*>* already_seen) {
+  if (already_seen->count(type) > 0) {
+    // The type is already in cache.  This means that either:
+    // a. The type has no required fields.
+    // b. We are in the midst of checking if the type has required fields,
+    //    somewhere up the stack.  In this case, we know that if the type
+    //    has any required fields, they'll be found when we return to it,
+    //    and the whole call to HasRequiredFields() will return true.
+    //    Therefore, we don't have to check if this type has required fields
+    //    here.
+    return false;
+  }
+  already_seen->insert(type);
+
+  // If the type has extensions, an extension with message type could contain
+  // required fields, so we have to be conservative and assume such an
+  // extension exists.
+  if (type->extension_range_count() > 0) return true;
+
+  for (int i = 0; i < type->field_count(); i++) {
+    const FieldDescriptor* field = type->field(i);
+    if (field->is_required()) {
+      return true;
+    }
+    if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+      if (HasRequiredFields(field->message_type(), already_seen)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool HasRequiredFields(const Descriptor* type) {
+  std::unordered_set<const Descriptor*> already_seen;
+  return HasRequiredFields(type, &already_seen);
+}
+
+bool HasRepeatedFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (field->is_repeated()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Encode an unsigned 32-bit value into a sequence of UTF-16 characters.
+//
+// If the value is in [0x0000, 0xD7FF], we encode it with a single character
+// with the same numeric value.
+//
+// If the value is larger than 0xD7FF, we encode its lowest 13 bits into a
+// character in the range [0xE000, 0xFFFF] by combining these 13 bits with
+// 0xE000 using logic-or. Then we shift the value to the right by 13 bits, and
+// encode the remaining value by repeating this same process until we get to
+// a value in [0x0000, 0xD7FF] where we will encode it using a character with
+// the same numeric value.
+//
+// Note that we only use code points in [0x0000, 0xD7FF] and [0xE000, 0xFFFF].
+// There will be no surrogate pairs in the encoded character sequence.
+void WriteUInt32ToUtf16CharSequence(uint32_t number,
+                                    std::vector<uint16_t>* output) {
+  // For values in [0x0000, 0xD7FF], only use one char to encode it.
+  if (number < 0xD800) {
+    output->push_back(static_cast<uint16_t>(number));
+    return;
+  }
+  // Encode into multiple chars. All except the last char will be in the range
+  // [0xE000, 0xFFFF], and the last char will be in the range [0x0000, 0xD7FF].
+  // Note that we don't use any value in range [0xD800, 0xDFFF] because they
+  // have to come in pairs and the encoding is just more space-efficient w/o
+  // them.
+  while (number >= 0xD800) {
+    // [0xE000, 0xFFFF] can represent 13 bits of info.
+    output->push_back(static_cast<uint16_t>(0xE000 | (number & 0x1FFF)));
+    number >>= 13;
+  }
+  output->push_back(static_cast<uint16_t>(number));
+}
+
+int GetExperimentalJavaFieldTypeForSingular(const FieldDescriptor* field) {
+  // j/c/g/protobuf/FieldType.java lists field types in a slightly different
+  // order from FieldDescriptor::Type so we can't do a simple cast.
+  //
+  // TODO(xiaofeng): Make j/c/g/protobuf/FieldType.java follow the same order.
+  int result = field->type();
+  if (result == FieldDescriptor::TYPE_GROUP) {
+    return 17;
+  } else if (result < FieldDescriptor::TYPE_GROUP) {
+    return result - 1;
+  } else {
+    return result - 2;
+  }
+}
+
+int GetExperimentalJavaFieldTypeForRepeated(const FieldDescriptor* field) {
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    return 49;
+  } else {
+    return GetExperimentalJavaFieldTypeForSingular(field) + 18;
+  }
+}
+
+int GetExperimentalJavaFieldTypeForPacked(const FieldDescriptor* field) {
+  int result = field->type();
+  if (result < FieldDescriptor::TYPE_STRING) {
+    return result + 34;
+  } else if (result > FieldDescriptor::TYPE_BYTES) {
+    return result + 30;
+  } else {
+    GOOGLE_LOG(FATAL) << field->full_name() << " can't be packed.";
+    return 0;
+  }
+}
+
+int GetExperimentalJavaFieldType(const FieldDescriptor* field) {
+  static const int kMapFieldType = 50;
+  static const int kOneofFieldTypeOffset = 51;
+  static const int kRequiredBit = 0x100;
+  static const int kUtf8CheckBit = 0x200;
+  static const int kCheckInitialized = 0x400;
+  static const int kMapWithProto2EnumValue = 0x800;
+  static const int kHasHasBit = 0x1000;
+  int extra_bits = field->is_required() ? kRequiredBit : 0;
+  if (field->type() == FieldDescriptor::TYPE_STRING && CheckUtf8(field)) {
+    extra_bits |= kUtf8CheckBit;
+  }
+  if (field->is_required() || (GetJavaType(field) == JAVATYPE_MESSAGE &&
+                               HasRequiredFields(field->message_type()))) {
+    extra_bits |= kCheckInitialized;
+  }
+  if (HasHasbit(field)) {
+    extra_bits |= kHasHasBit;
+  }
+
+  if (field->is_map()) {
+    if (!SupportUnknownEnumValue(field)) {
+      const FieldDescriptor* value = field->message_type()->map_value();
+      if (GetJavaType(value) == JAVATYPE_ENUM) {
+        extra_bits |= kMapWithProto2EnumValue;
+      }
+    }
+    return kMapFieldType | extra_bits;
+  } else if (field->is_packed()) {
+    return GetExperimentalJavaFieldTypeForPacked(field);
+  } else if (field->is_repeated()) {
+    return GetExperimentalJavaFieldTypeForRepeated(field) | extra_bits;
+  } else if (IsRealOneof(field)) {
+    return (GetExperimentalJavaFieldTypeForSingular(field) +
+            kOneofFieldTypeOffset) |
+           extra_bits;
+  } else {
+    return GetExperimentalJavaFieldTypeForSingular(field) | extra_bits;
+  }
+}
+
+// Escape a UTF-16 character to be embedded in a Java string.
+void EscapeUtf16ToString(uint16_t code, std::string* output) {
+  if (code == '\t') {
+    output->append("\\t");
+  } else if (code == '\b') {
+    output->append("\\b");
+  } else if (code == '\n') {
+    output->append("\\n");
+  } else if (code == '\r') {
+    output->append("\\r");
+  } else if (code == '\f') {
+    output->append("\\f");
+  } else if (code == '\'') {
+    output->append("\\'");
+  } else if (code == '\"') {
+    output->append("\\\"");
+  } else if (code == '\\') {
+    output->append("\\\\");
+  } else if (code >= 0x20 && code <= 0x7f) {
+    output->push_back(static_cast<char>(code));
+  } else {
+    output->append(StringPrintf("\\u%04x", code));
+  }
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/helpers.h b/src/google/protobuf/compiler/java/helpers.h
new file mode 100644
index 0000000..9f1a557
--- /dev/null
+++ b/src/google/protobuf/compiler/java/helpers.h
@@ -0,0 +1,474 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
+
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Commonly-used separator comments.  Thick is a line of '=', thin is a line
+// of '-'.
+extern const char kThickSeparator[];
+extern const char kThinSeparator[];
+
+bool IsForbiddenKotlin(const std::string& field_name);
+
+// If annotation_file is non-empty, prints a javax.annotation.Generated
+// annotation to the given Printer. annotation_file will be referenced in the
+// annotation's comments field. delimiter should be the Printer's delimiter
+// character. annotation_file will be included verbatim into a Java literal
+// string, so it should not contain quotes or invalid Java escape sequences;
+// however, these are unlikely to appear in practice, as the value of
+// annotation_file should be generated from the filename of the source file
+// being annotated (which in turn must be a Java identifier plus ".java").
+void PrintGeneratedAnnotation(io::Printer* printer, char delimiter = '$',
+                              const std::string& annotation_file = "");
+
+// If a GeneratedMessageLite contains non-lite enums, then its verifier
+// must be instantiated inline, rather than retrieved from the enum class.
+void PrintEnumVerifierLogic(io::Printer* printer,
+                            const FieldDescriptor* descriptor,
+                            const std::map<std::string, std::string>& variables,
+                            const char* var_name,
+                            const char* terminating_string, bool enforce_lite);
+
+// Converts a name to camel-case. If cap_first_letter is true, capitalize the
+// first letter.
+std::string ToCamelCase(const std::string& input, bool lower_first);
+
+char ToUpperCh(char ch);
+char ToLowerCh(char ch);
+
+// Converts a name to camel-case. If cap_first_letter is true, capitalize the
+// first letter.
+std::string UnderscoresToCamelCase(const std::string& name,
+                                   bool cap_first_letter);
+// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
+// "fooBarBaz" or "FooBarBaz", respectively.
+std::string UnderscoresToCamelCase(const FieldDescriptor* field);
+std::string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
+
+// Similar, but for method names.  (Typically, this merely has the effect
+// of lower-casing the first letter of the name.)
+std::string UnderscoresToCamelCase(const MethodDescriptor* method);
+
+// Same as UnderscoresToCamelCase, but checks for reserved keywords
+std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field);
+
+// Similar to UnderscoresToCamelCase, but guarantees that the result is a
+// complete Java identifier by adding a _ if needed.
+std::string CamelCaseFieldName(const FieldDescriptor* field);
+
+// Get an identifier that uniquely identifies this type within the file.
+// This is used to declare static variables related to this type at the
+// outermost file scope.
+std::string UniqueFileScopeIdentifier(const Descriptor* descriptor);
+
+// Gets the unqualified class name for the file.  For each .proto file, there
+// will be one Java class containing all the immutable messages and another
+// Java class containing all the mutable messages.
+// TODO(xiaofeng): remove the default value after updating client code.
+std::string FileClassName(const FileDescriptor* file, bool immutable = true);
+
+// Returns the file's Java package name.
+std::string FileJavaPackage(const FileDescriptor* file, bool immutable);
+
+// Returns output directory for the given package name.
+std::string JavaPackageToDir(std::string package_name);
+
+// Comma-separate list of option-specified interfaces implemented by the
+// Message, to follow the "implements" declaration of the Message definition.
+std::string ExtraMessageInterfaces(const Descriptor* descriptor);
+// Comma-separate list of option-specified interfaces implemented by the
+// MutableMessage, to follow the "implements" declaration of the MutableMessage
+// definition.
+std::string ExtraMutableMessageInterfaces(const Descriptor* descriptor);
+// Comma-separate list of option-specified interfaces implemented by the
+// Builder, to follow the "implements" declaration of the Builder definition.
+std::string ExtraBuilderInterfaces(const Descriptor* descriptor);
+// Comma-separate list of option-specified interfaces extended by the
+// MessageOrBuilder, to follow the "extends" declaration of the
+// MessageOrBuilder definition.
+std::string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor);
+
+// Get the unqualified Java class name for mutable messages. i.e. without
+// package or outer classnames.
+inline std::string ShortMutableJavaClassName(const Descriptor* descriptor) {
+  return descriptor->name();
+}
+
+// Whether the given descriptor is for one of the core descriptor protos. We
+// cannot currently use the new runtime with core protos since there is a
+// bootstrapping problem with obtaining their descriptors.
+inline bool IsDescriptorProto(const Descriptor* descriptor) {
+  return descriptor->file()->name() == "net/proto2/proto/descriptor.proto" ||
+         descriptor->file()->name() == "google/protobuf/descriptor.proto";
+}
+
+// Returns the stored type string used by the experimental runtime for oneof
+// fields.
+std::string GetOneofStoredType(const FieldDescriptor* field);
+
+// We use either the proto1 enums if the enum is generated, otherwise fall back
+// to use integers.
+enum class Proto1EnumRepresentation {
+  kEnum,
+  kInteger,
+};
+
+// Returns which representation we should use.
+inline Proto1EnumRepresentation GetProto1EnumRepresentation(
+    const EnumDescriptor* descriptor) {
+  if (descriptor->containing_type() != nullptr) {
+    return Proto1EnumRepresentation::kEnum;
+  }
+  return Proto1EnumRepresentation::kInteger;
+}
+
+// Whether we should generate multiple java files for messages.
+inline bool MultipleJavaFiles(const FileDescriptor* descriptor,
+                              bool immutable) {
+  (void)immutable;
+  return descriptor->options().java_multiple_files();
+}
+
+
+// Returns true if `descriptor` will be written to its own .java file.
+// `immutable` should be set to true if we're generating for the immutable API.
+template <typename Descriptor>
+bool IsOwnFile(const Descriptor* descriptor, bool immutable) {
+  return descriptor->containing_type() == NULL &&
+         MultipleJavaFiles(descriptor->file(), immutable);
+}
+
+template <>
+inline bool IsOwnFile(const ServiceDescriptor* descriptor, bool immutable) {
+  return MultipleJavaFiles(descriptor->file(), immutable);
+}
+
+// If `descriptor` describes an object with its own .java file,
+// returns the name (relative to that .java file) of the file that stores
+// annotation data for that descriptor. `suffix` is usually empty, but may
+// (e.g.) be "OrBuilder" for some generated interfaces.
+template <typename Descriptor>
+std::string AnnotationFileName(const Descriptor* descriptor,
+                               const std::string& suffix) {
+  return descriptor->name() + suffix + ".java.pb.meta";
+}
+
+template <typename Descriptor>
+void MaybePrintGeneratedAnnotation(Context* context, io::Printer* printer,
+                                   Descriptor* descriptor, bool immutable,
+                                   const std::string& suffix = "") {
+  if (IsOwnFile(descriptor, immutable)) {
+    PrintGeneratedAnnotation(printer, '$',
+                             context->options().annotate_code
+                                 ? AnnotationFileName(descriptor, suffix)
+                                 : "");
+  }
+}
+
+// Get the unqualified name that should be used for a field's field
+// number constant.
+std::string FieldConstantName(const FieldDescriptor* field);
+
+// Returns the type of the FieldDescriptor.
+// This does nothing interesting for the open source release, but is used for
+// hacks that improve compatibility with version 1 protocol buffers at Google.
+FieldDescriptor::Type GetType(const FieldDescriptor* field);
+
+enum JavaType {
+  JAVATYPE_INT,
+  JAVATYPE_LONG,
+  JAVATYPE_FLOAT,
+  JAVATYPE_DOUBLE,
+  JAVATYPE_BOOLEAN,
+  JAVATYPE_STRING,
+  JAVATYPE_BYTES,
+  JAVATYPE_ENUM,
+  JAVATYPE_MESSAGE
+};
+
+JavaType GetJavaType(const FieldDescriptor* field);
+
+const char* PrimitiveTypeName(JavaType type);
+
+// Get the fully-qualified class name for a boxed primitive type, e.g.
+// "java.lang.Integer" for JAVATYPE_INT.  Returns NULL for enum and message
+// types.
+const char* BoxedPrimitiveTypeName(JavaType type);
+
+// Kotlin source does not distinguish between primitives and non-primitives,
+// but does use Kotlin-specific qualified types for them.
+const char* KotlinTypeName(JavaType type);
+
+// Get the name of the java enum constant representing this type. E.g.,
+// "INT32" for FieldDescriptor::TYPE_INT32. The enum constant's full
+// name is "com.google.protobuf.WireFormat.FieldType.INT32".
+const char* FieldTypeName(const FieldDescriptor::Type field_type);
+
+class ClassNameResolver;
+std::string DefaultValue(const FieldDescriptor* field, bool immutable,
+                         ClassNameResolver* name_resolver);
+inline std::string ImmutableDefaultValue(const FieldDescriptor* field,
+                                         ClassNameResolver* name_resolver) {
+  return DefaultValue(field, true, name_resolver);
+}
+bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
+bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field);
+
+// Does this message class have descriptor and reflection methods?
+inline bool HasDescriptorMethods(const Descriptor* /* descriptor */,
+                                 bool enforce_lite) {
+  return !enforce_lite;
+}
+inline bool HasDescriptorMethods(const EnumDescriptor* /* descriptor */,
+                                 bool enforce_lite) {
+  return !enforce_lite;
+}
+inline bool HasDescriptorMethods(const FileDescriptor* /* descriptor */,
+                                 bool enforce_lite) {
+  return !enforce_lite;
+}
+
+// Should we generate generic services for this file?
+inline bool HasGenericServices(const FileDescriptor* file, bool enforce_lite) {
+  return file->service_count() > 0 &&
+         HasDescriptorMethods(file, enforce_lite) &&
+         file->options().java_generic_services();
+}
+
+// Methods for shared bitfields.
+
+// Gets the name of the shared bitfield for the given index.
+std::string GetBitFieldName(int index);
+
+// Gets the name of the shared bitfield for the given bit index.
+// Effectively, GetBitFieldName(bitIndex / 32)
+std::string GetBitFieldNameForBit(int bitIndex);
+
+// Generates the java code for the expression that returns the boolean value
+// of the bit of the shared bitfields for the given bit index.
+// Example: "((bitField1_ & 0x04) == 0x04)"
+std::string GenerateGetBit(int bitIndex);
+
+// Generates the java code for the expression that sets the bit of the shared
+// bitfields for the given bit index.
+// Example: "bitField1_ = (bitField1_ | 0x04)"
+std::string GenerateSetBit(int bitIndex);
+
+// Generates the java code for the expression that clears the bit of the shared
+// bitfields for the given bit index.
+// Example: "bitField1_ = (bitField1_ & ~0x04)"
+std::string GenerateClearBit(int bitIndex);
+
+// Does the same as GenerateGetBit but operates on the bit field on a local
+// variable. This is used by the builder to copy the value in the builder to
+// the message.
+// Example: "((from_bitField1_ & 0x04) == 0x04)"
+std::string GenerateGetBitFromLocal(int bitIndex);
+
+// Does the same as GenerateSetBit but operates on the bit field on a local
+// variable. This is used by the builder to copy the value in the builder to
+// the message.
+// Example: "to_bitField1_ = (to_bitField1_ | 0x04)"
+std::string GenerateSetBitToLocal(int bitIndex);
+
+// Does the same as GenerateGetBit but operates on the bit field on a local
+// variable. This is used by the parsing constructor to record if a repeated
+// field is mutable.
+// Example: "((mutable_bitField1_ & 0x04) == 0x04)"
+std::string GenerateGetBitMutableLocal(int bitIndex);
+
+// Does the same as GenerateSetBit but operates on the bit field on a local
+// variable. This is used by the parsing constructor to record if a repeated
+// field is mutable.
+// Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)"
+std::string GenerateSetBitMutableLocal(int bitIndex);
+
+// Returns whether the JavaType is a reference type.
+bool IsReferenceType(JavaType type);
+
+// Returns the capitalized name for calling relative functions in
+// CodedInputStream
+const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable);
+
+// For encodings with fixed sizes, returns that size in bytes.  Otherwise
+// returns -1.
+int FixedSize(FieldDescriptor::Type type);
+
+// Comparators used to sort fields in MessageGenerator
+struct FieldOrderingByNumber {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    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. The caller should delete the returned array.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor);
+
+// Does this message class have any packed fields?
+inline bool HasPackedFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    if (descriptor->field(i)->is_packed()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Check a message type and its sub-message types recursively to see if any of
+// them has a required field. Return true if a required field is found.
+bool HasRequiredFields(const Descriptor* descriptor);
+
+inline bool IsProto2(const FileDescriptor* descriptor) {
+  return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
+inline bool IsRealOneof(const FieldDescriptor* descriptor) {
+  return descriptor->containing_oneof() &&
+         !descriptor->containing_oneof()->is_synthetic();
+}
+
+inline bool HasHazzer(const FieldDescriptor* descriptor) {
+  return !descriptor->is_repeated() &&
+         (descriptor->message_type() || descriptor->has_optional_keyword() ||
+          IsProto2(descriptor->file()) || IsRealOneof(descriptor));
+}
+
+inline bool HasHasbit(const FieldDescriptor* descriptor) {
+  // Note that currently message fields inside oneofs have hasbits. This is
+  // surprising, as the oneof case should avoid any need for a hasbit. But if
+  // you change this method to remove hasbits for oneofs, a few tests fail.
+  // TODO(b/124347790): remove hasbits for oneofs
+  return !descriptor->is_repeated() &&
+         (descriptor->has_optional_keyword() || IsProto2(descriptor->file()));
+}
+
+// Whether generate classes expose public PARSER instances.
+inline bool ExposePublicParser(const FileDescriptor* descriptor) {
+  // TODO(liujisi): Mark the PARSER private in 3.1.x releases.
+  return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
+// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet
+// but in the message and can be queried using additional getters that return
+// ints.
+inline bool SupportUnknownEnumValue(const FileDescriptor* descriptor) {
+  return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool SupportUnknownEnumValue(const FieldDescriptor* field) {
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+// Check whether a message has repeated fields.
+bool HasRepeatedFields(const Descriptor* descriptor);
+
+inline bool IsMapEntry(const Descriptor* descriptor) {
+  return descriptor->options().map_entry();
+}
+
+inline bool IsMapField(const FieldDescriptor* descriptor) {
+  return descriptor->is_map();
+}
+
+inline bool IsAnyMessage(const Descriptor* descriptor) {
+  return descriptor->full_name() == "google.protobuf.Any";
+}
+
+inline bool IsWrappersProtoFile(const FileDescriptor* descriptor) {
+  return descriptor->name() == "google/protobuf/wrappers.proto";
+}
+
+inline bool CheckUtf8(const FieldDescriptor* descriptor) {
+  return descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ||
+         descriptor->file()->options().java_string_check_utf8();
+}
+
+inline std::string GeneratedCodeVersionSuffix() {
+  return "V3";
+}
+
+void WriteUInt32ToUtf16CharSequence(uint32_t number,
+                                    std::vector<uint16_t>* output);
+
+inline void WriteIntToUtf16CharSequence(int value,
+                                        std::vector<uint16_t>* output) {
+  WriteUInt32ToUtf16CharSequence(static_cast<uint32_t>(value), output);
+}
+
+// Escape a UTF-16 character so it can be embedded in a Java string literal.
+void EscapeUtf16ToString(uint16_t code, std::string* output);
+
+// Only the lowest two bytes of the return value are used. The lowest byte
+// is the integer value of a j/c/g/protobuf/FieldType enum. For the other
+// byte:
+//    bit 0: whether the field is required.
+//    bit 1: whether the field requires UTF-8 validation.
+//    bit 2: whether the field needs isInitialized check.
+//    bit 3: whether the field is a map field with proto2 enum value.
+//    bits 4-7: unused
+int GetExperimentalJavaFieldType(const FieldDescriptor* field);
+
+// To get the total number of entries need to be built for experimental runtime
+// and the first field number that are not in the table part
+std::pair<int, int> GetTableDrivenNumberOfEntriesAndLookUpStartFieldNumber(
+    const FieldDescriptor** fields, int count);
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
diff --git a/src/google/protobuf/compiler/java/java_generator.h b/src/google/protobuf/compiler/java/java_generator.h
new file mode 100644
index 0000000..294b1bd
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_generator.h
@@ -0,0 +1,6 @@
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_JAVA_GENERATOR_H_
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_JAVA_GENERATOR_H_
+
+#include <google/protobuf/compiler/java/generator.h>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_JAVA_GENERATOR_H_
diff --git a/src/google/protobuf/compiler/java/kotlin_generator.cc b/src/google/protobuf/compiler/java/kotlin_generator.cc
new file mode 100644
index 0000000..1af548a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/kotlin_generator.cc
@@ -0,0 +1,158 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/kotlin_generator.h>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/java/file.h>
+#include <google/protobuf/compiler/java/generator.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+KotlinGenerator::KotlinGenerator() {}
+KotlinGenerator::~KotlinGenerator() {}
+
+uint64_t KotlinGenerator::GetSupportedFeatures() const {
+  return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
+}
+
+bool KotlinGenerator::Generate(const FileDescriptor* file,
+                               const std::string& parameter,
+                               GeneratorContext* context,
+                               std::string* error) const {
+  // -----------------------------------------------------------------
+  // parse generator options
+
+  std::vector<std::pair<std::string, std::string> > options;
+  ParseGeneratorParameter(parameter, &options);
+  Options file_options;
+
+  for (auto& option : options) {
+    if (option.first == "output_list_file") {
+      file_options.output_list_file = option.second;
+    } else if (option.first == "immutable") {
+      // Note: the option is considered always set regardless of the input.
+      file_options.generate_immutable_code = true;
+    } else if (option.first == "mutable") {
+      *error = "Mutable not supported by Kotlin generator";
+      return false;
+    } else if (option.first == "shared") {
+      // Note: the option is considered always set regardless of the input.
+      file_options.generate_shared_code = true;
+    } else if (option.first == "lite") {
+      file_options.enforce_lite = true;
+    } else if (option.first == "annotate_code") {
+      file_options.annotate_code = true;
+    } else if (option.first == "annotation_list_file") {
+      file_options.annotation_list_file = option.second;
+    } else {
+      *error = "Unknown generator option: " + option.first;
+      return false;
+    }
+  }
+
+  // We only support generation of immutable code so we do it.
+  file_options.generate_immutable_code = true;
+  file_options.generate_shared_code = true;
+
+  std::vector<std::string> all_files;
+  std::vector<std::string> all_annotations;
+
+  std::unique_ptr<FileGenerator> file_generator(
+        new FileGenerator(file, file_options, /* immutable_api = */ true));
+
+  if (!file_generator || !file_generator->Validate(error)) {
+    return false;
+  }
+
+  auto open_file = [context](const std::string& filename) {
+    return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename));
+  };
+  std::string package_dir = JavaPackageToDir(file_generator->java_package());
+  std::string kotlin_filename = package_dir;
+  kotlin_filename += file_generator->GetKotlinClassname();
+  kotlin_filename += ".kt";
+  all_files.push_back(kotlin_filename);
+  std::string info_full_path = kotlin_filename + ".pb.meta";
+  if (file_options.annotate_code) {
+    all_annotations.push_back(info_full_path);
+  }
+
+  // Generate main kotlin file.
+  auto output = open_file(kotlin_filename);
+  GeneratedCodeInfo annotations;
+  io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+      &annotations);
+  io::Printer printer(
+      output.get(), '$',
+      file_options.annotate_code ? &annotation_collector : nullptr);
+
+  file_generator->GenerateKotlinSiblings(package_dir, context, &all_files,
+                                         &all_annotations);
+
+  if (file_options.annotate_code) {
+    auto info_output = open_file(info_full_path);
+    annotations.SerializeToZeroCopyStream(info_output.get());
+  }
+
+  // Generate output list if requested.
+  if (!file_options.output_list_file.empty()) {
+    // Generate output list.  This is just a simple text file placed in a
+    // deterministic location which lists the .kt files being generated.
+    auto srclist_raw_output = open_file(file_options.output_list_file);
+    io::Printer srclist_printer(srclist_raw_output.get(), '$');
+    for (auto& all_file : all_files) {
+      srclist_printer.Print("$filename$\n", "filename", all_file);
+    }
+  }
+
+  if (!file_options.annotation_list_file.empty()) {
+    // Generate output list.  This is just a simple text file placed in a
+    // deterministic location which lists the .kt files being generated.
+    auto annotation_list_raw_output =
+        open_file(file_options.annotation_list_file);
+    io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
+    for (auto& all_annotation : all_annotations) {
+      annotation_list_printer.Print("$filename$\n", "filename", all_annotation);
+    }
+  }
+
+  return true;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/kotlin_generator.h b/src/google/protobuf/compiler/java/kotlin_generator.h
new file mode 100644
index 0000000..ccd9688
--- /dev/null
+++ b/src/google/protobuf/compiler/java/kotlin_generator.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.
+
+// Generates Kotlin code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// CodeGenerator implementation which generates Kotlin code.  If you create your
+// own protocol compiler binary and you want it to support Kotlin output, you
+// can do so by registering an instance of this CodeGenerator with the
+// CommandLineInterface in your main() function.
+class PROTOC_EXPORT KotlinGenerator : public CodeGenerator {
+ public:
+  KotlinGenerator();
+  ~KotlinGenerator() override;
+
+  // implements CodeGenerator ----------------------------------------
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(KotlinGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/java/map_field.cc b/src/google/protobuf/compiler/java/map_field.cc
new file mode 100644
index 0000000..89abbab
--- /dev/null
+++ b/src/google/protobuf/compiler/java/map_field.cc
@@ -0,0 +1,874 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/map_field.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+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->map_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->map_value();
+}
+
+std::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));
+  }
+}
+
+std::string KotlinTypeName(const FieldDescriptor* field,
+                           ClassNameResolver* name_resolver) {
+  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 KotlinTypeName(GetJavaType(field));
+  }
+}
+
+std::string WireType(const FieldDescriptor* field) {
+  return "com.google.protobuf.WireFormat.FieldType." +
+         std::string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
+                         int builderBitIndex, const FieldGeneratorInfo* info,
+                         Context* context,
+                         std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+  ClassNameResolver* name_resolver = context->GetNameResolver();
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  const FieldDescriptor* key = KeyField(descriptor);
+  const FieldDescriptor* value = ValueField(descriptor);
+  const JavaType keyJavaType = GetJavaType(key);
+  const JavaType valueJavaType = GetJavaType(value);
+
+  std::string pass_through_nullness = "/* nullable */\n";
+
+  (*variables)["key_type"] = TypeName(key, name_resolver, false);
+  std::string boxed_key_type = TypeName(key, name_resolver, true);
+  (*variables)["boxed_key_type"] = boxed_key_type;
+  (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
+  (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver);
+  // Used for calling the serialization function.
+  (*variables)["short_key_type"] =
+      boxed_key_type.substr(boxed_key_type.rfind('.') + 1);
+  (*variables)["key_wire_type"] = WireType(key);
+  (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+  (*variables)["key_null_check"] =
+      IsReferenceType(keyJavaType)
+          ? "if (key == null) { throw new NullPointerException(\"map key\"); }"
+          : "";
+  (*variables)["value_null_check"] =
+      valueJavaType != JAVATYPE_ENUM && IsReferenceType(valueJavaType)
+          ? "if (value == null) {\n"
+            "  throw new NullPointerException(\"map value\");\n"
+            "}\n"
+          : "";
+  if (valueJavaType == 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);
+
+    (*variables)["value_enum_type_pass_through_nullness"] =
+        pass_through_nullness + (*variables)["value_enum_type"];
+
+    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)["value_type_pass_through_nullness"] =
+        (IsReferenceType(valueJavaType) ? pass_through_nullness : "") +
+        (*variables)["value_type"];
+
+    (*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)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["on_changed"] = "onChanged();";
+
+  (*variables)["default_entry"] =
+      (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry";
+  (*variables)["map_field_parameter"] = (*variables)["default_entry"];
+  (*variables)["descriptor"] =
+      name_resolver->GetImmutableClassName(descriptor->file()) + ".internal_" +
+      UniqueFileScopeIdentifier(descriptor->message_type()) + "_descriptor, ";
+  (*variables)["ver"] = GeneratedCodeVersionSuffix();
+}
+
+}  // namespace
+
+ImmutableMapFieldGenerator::ImmutableMapFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      context->GetFieldGeneratorInfo(descriptor), context,
+                      &variables_);
+}
+
+ImmutableMapFieldGenerator::~ImmutableMapFieldGenerator() {}
+
+int ImmutableMapFieldGenerator::GetNumBitsForMessage() const { return 0; }
+
+int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const { return 1; }
+
+void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$int ${$get$capitalized_name$Count$}$();\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$boolean ${$contains$capitalized_name$$}$(\n"
+                 "    $key_type$ key);\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Deprecated\n"
+                   "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "${$get$capitalized_name$Map$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$$value_enum_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_enum_type_pass_through_nullness$ "
+                   "        defaultValue);\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+        "    $key_type$ key);\n");
+    printer->Annotate("{", "}", descriptor_);
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "java.util.Map<$type_parameters$>\n"
+          "${$get$capitalized_name$Value$}$();\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+                     "$deprecation$java.util.Map<$type_parameters$>\n"
+                     "${$get$capitalized_name$ValueMap$}$();\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+                     "$deprecation$\n"
+                     "$value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n"
+                     "    $key_type$ key,\n"
+                     "    $value_type$ defaultValue);\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+                     "$deprecation$\n"
+                     "$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
+                     "    $key_type$ key);\n");
+      printer->Annotate("{", "}", descriptor_);
+    }
+  } else {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Deprecated\n"
+                   "java.util.Map<$type_parameters$>\n"
+                   "${$get$capitalized_name$$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$java.util.Map<$type_parameters$>\n"
+                   "${$get$capitalized_name$Map$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$\n"
+                   "$value_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_type_pass_through_nullness$ defaultValue);\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$\n"
+                   "$value_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+                   "    $key_type$ key);\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private static final class $capitalized_name$DefaultEntryHolder {\n"
+      "  static final com.google.protobuf.MapEntry<\n"
+      "      $type_parameters$> defaultEntry =\n"
+      "          com.google.protobuf.MapEntry\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<\n"
+                 "    $type_parameters$> $name$_;\n"
+                 "private com.google.protobuf.MapField<$type_parameters$>\n"
+                 "internalGet$capitalized_name$() {\n"
+                 "  if ($name$_ == null) {\n"
+                 "    return com.google.protobuf.MapField.emptyMapField(\n"
+                 "        $map_field_parameter$);\n"
+                 "  }\n"
+                 "  return $name$_;\n"
+                 "}\n");
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "private static final\n"
+        "com.google.protobuf.Internal.MapAdapter.Converter<\n"
+        "    java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
+        "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
+        "            $value_enum_type$.internalGetValueMap(),\n"
+        "            $unrecognized_value$);\n");
+    printer->Print(
+        variables_,
+        "private static final java.util.Map<$boxed_key_type$, "
+        "$value_enum_type$>\n"
+        "internalGetAdapted$capitalized_name$Map(\n"
+        "    java.util.Map<$boxed_key_type$, $boxed_value_type$> map) {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          map, $name$ValueConverter);\n"
+        "}\n");
+  }
+  GenerateMapGetters(printer);
+}
+
+void ImmutableMapFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "private com.google.protobuf.MapField<\n"
+                 "    $type_parameters$> $name$_;\n"
+                 "private com.google.protobuf.MapField<$type_parameters$>\n"
+                 "internalGet$capitalized_name$() {\n"
+                 "  if ($name$_ == null) {\n"
+                 "    return com.google.protobuf.MapField.emptyMapField(\n"
+                 "        $map_field_parameter$);\n"
+                 "  }\n"
+                 "  return $name$_;\n"
+                 "}\n"
+                 "private com.google.protobuf.MapField<$type_parameters$>\n"
+                 "internalGetMutable$capitalized_name$() {\n"
+                 "  $on_changed$;\n"
+                 "  if ($name$_ == null) {\n"
+                 "    $name$_ = com.google.protobuf.MapField.newMapField(\n"
+                 "        $map_field_parameter$);\n"
+                 "  }\n"
+                 "  if (!$name$_.isMutable()) {\n"
+                 "    $name$_ = $name$_.copy();\n"
+                 "  }\n"
+                 "  return $name$_;\n"
+                 "}\n");
+  GenerateMapGetters(printer);
+  printer->Print(variables_,
+                 "$deprecation$\n"
+                 "public Builder ${$clear$capitalized_name$$}$() {\n"
+                 "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+                 "      .clear();\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$\n"
+                 "public Builder ${$remove$capitalized_name$$}$(\n"
+                 "    $key_type$ key) {\n"
+                 "  $key_null_check$\n"
+                 "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+                 "      .remove(key);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use alternate mutation accessors instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "${$getMutable$capitalized_name$$}$() {\n"
+        "  return internalGetAdapted$capitalized_name$Map(\n"
+        "       internalGetMutable$capitalized_name$().getMutableMap());\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_enum_type$ value) {\n"
+                   "  $key_null_check$\n"
+                   "  $value_null_check$\n"
+                   "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+                   "      .put(key, $name$ValueConverter.doBackward(value));\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
+        "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
+        "  internalGetAdapted$capitalized_name$Map(\n"
+        "      internalGetMutable$capitalized_name$().getMutableMap())\n"
+        "          .putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use alternate mutation accessors instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$getMutable$capitalized_name$Value$}$() {\n"
+          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ value) {\n"
+          "  $key_null_check$\n"
+          "  $value_null_check$\n"
+          "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+          "      .put(key, value);\n"
+          "  return this;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      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"
+          "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+          "      .putAll(values);\n"
+          "  return this;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+    }
+  } else {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use alternate mutation accessors instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public java.util.Map<$type_parameters$>\n"
+        "${$getMutable$capitalized_name$$}$() {\n"
+        "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$"
+                   "public Builder ${$put$capitalized_name$$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_type$ value) {\n"
+                   "  $key_null_check$\n"
+                   "  $value_null_check$\n"
+                   "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+                   "      .put(key, value);\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$\n"
+                   "public Builder ${$putAll$capitalized_name$$}$(\n"
+                   "    java.util.Map<$type_parameters$> values) {\n"
+                   "  internalGetMutable$capitalized_name$().getMutableMap()\n"
+                   "      .putAll(values);\n"
+                   "  return this;\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void ImmutableMapFieldGenerator::GenerateMapGetters(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$deprecation$\n"
+                 "public int ${$get$capitalized_name$Count$}$() {\n"
+                 "  return internalGet$capitalized_name$().getMap().size();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "@java.lang.Override\n"
+      "public boolean ${$contains$capitalized_name$$}$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  return internalGet$capitalized_name$().getMap().containsKey(key);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Override\n"
+                   "@java.lang.Deprecated\n"
+                   "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$$}$() {\n"
+                   "  return get$capitalized_name$Map();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$Map$}$() {\n"
+                   "  return internalGetAdapted$capitalized_name$Map(\n"
+                   "      internalGet$capitalized_name$().getMap());"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_enum_type_pass_through_nullness$ "
+        "${$get$capitalized_name$OrDefault$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type_pass_through_nullness$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  return map.containsKey(key)\n"
+        "         ? $name$ValueConverter.doForward(map.get(key))\n"
+        "         : defaultValue;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return $name$ValueConverter.doForward(map.get(key));\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Override\n"
+          "@java.lang.Deprecated\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$get$capitalized_name$Value$}$() {\n"
+          "  return get$capitalized_name$ValueMap();\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$get$capitalized_name$ValueMap$}$() {\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public $value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$().getMap();\n"
+          "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public $value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
+          "    $key_type$ key) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$().getMap();\n"
+          "  if (!map.containsKey(key)) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  return map.get(key);\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+    }
+  } else {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Override\n"
+                   "@java.lang.Deprecated\n"
+                   "public java.util.Map<$type_parameters$> "
+                   "${$get$capitalized_name$$}$() {\n"
+                   "  return get$capitalized_name$Map();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public java.util.Map<$type_parameters$> "
+                   "${$get$capitalized_name$Map$}$() {\n"
+                   "  return internalGet$capitalized_name$().getMap();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public $value_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+                   "    $key_type$ key) {\n"
+                   "  $key_null_check$\n"
+                   "  java.util.Map<$type_parameters$> map =\n"
+                   "      internalGet$capitalized_name$().getMap();\n"
+                   "  if (!map.containsKey(key)) {\n"
+                   "    throw new java.lang.IllegalArgumentException();\n"
+                   "  }\n"
+                   "  return map.get(key);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void ImmutableMapFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$kt_deprecation$ val $kt_name$: "
+      "com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  @kotlin.jvm.JvmSynthetic\n"
+      "  @JvmName(\"get$kt_capitalized_name$Map\")\n"
+      "  get() = com.google.protobuf.kotlin.DslMap(\n"
+      "    $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n"
+      "  )\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@JvmName(\"put$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .put(key: $kt_key_type$, value: $kt_value_type$) {\n"
+      "     $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"set$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .set(key: $kt_key_type$, value: $kt_value_type$) {\n"
+      "     put(key, value)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"remove$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .remove(key: $kt_key_type$) {\n"
+      "     $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"putAll$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) "
+      "{\n"
+      "     $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"clear$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .clear() {\n"
+      "     $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+      "   }\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateFieldBuilderInitializationCode(
+    io::Printer* printer) const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "internalGetMutable$capitalized_name$().clear();\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "internalGetMutable$capitalized_name$().mergeFrom(\n"
+                 "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "result.$name$_ = internalGet$capitalized_name$();\n"
+                 "result.$name$_.makeImmutable();\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (!SupportUnknownEnumValue(descriptor_->file()) &&
+      GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.ByteString bytes = input.readBytes();\n"
+        "com.google.protobuf.MapEntry<$type_parameters$>\n"
+        "$name$__ = $default_entry$.getParserForType().parseFrom(bytes);\n"
+        "if ($value_enum_type$.forNumber($name$__.getValue()) == null) {\n"
+        "  mergeUnknownLengthDelimitedField($number$, bytes);\n"
+        "} else {\n"
+        "  internalGetMutable$capitalized_name$().getMutableMap().put(\n"
+        "      $name$__.getKey(), $name$__.getValue());\n"
+        "}\n");
+  } else {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.MapEntry<$type_parameters$>\n"
+        "$name$__ = input.readMessage(\n"
+        "    $default_entry$.getParserForType(), extensionRegistry);\n"
+        "internalGetMutable$capitalized_name$().getMutableMap().put(\n"
+        "    $name$__.getKey(), $name$__.getValue());\n");
+  }
+}
+
+void ImmutableMapFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "com.google.protobuf.GeneratedMessage$ver$\n"
+                 "  .serialize$short_key_type$MapTo(\n"
+                 "    output,\n"
+                 "    internalGet$capitalized_name$(),\n"
+                 "    $default_entry$,\n"
+                 "    $number$);\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateSerializedSizeCode(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry<$type_parameters$>\n"
+      "  $name$__ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeMessageSize($number$, $name$__);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if (!internalGet$capitalized_name$().equals(\n"
+                 "    other.internalGet$capitalized_name$())) return false;\n");
+}
+
+void ImmutableMapFieldGenerator::GenerateHashCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+      "  hash = (37 * hash) + $constant_name$;\n"
+      "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
+      "}\n");
+}
+
+std::string ImmutableMapFieldGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/map_field.h b/src/google/protobuf/compiler/java/map_field.h
new file mode 100644
index 0000000..3d699aa
--- /dev/null
+++ b/src/google/protobuf/compiler/java/map_field.h
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
+                                      int messageBitIndex, int builderBitIndex,
+                                      Context* context);
+  ~ImmutableMapFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+  void GenerateMapGetters(io::Printer* printer) const;
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/map_field_lite.cc b/src/google/protobuf/compiler/java/map_field_lite.cc
new file mode 100644
index 0000000..4f2766e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/map_field_lite.cc
@@ -0,0 +1,927 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/map_field_lite.h>
+
+#include <cstdint>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+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->map_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->map_value();
+}
+
+std::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));
+  }
+}
+
+std::string KotlinTypeName(const FieldDescriptor* field,
+                           ClassNameResolver* name_resolver) {
+  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 KotlinTypeName(GetJavaType(field));
+  }
+}
+
+std::string WireType(const FieldDescriptor* field) {
+  return "com.google.protobuf.WireFormat.FieldType." +
+         std::string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
+                         int builderBitIndex, const FieldGeneratorInfo* info,
+                         Context* context,
+                         std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  ClassNameResolver* name_resolver = context->GetNameResolver();
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  const FieldDescriptor* key = KeyField(descriptor);
+  const FieldDescriptor* value = ValueField(descriptor);
+  const JavaType keyJavaType = GetJavaType(key);
+  const JavaType valueJavaType = GetJavaType(value);
+
+  std::string pass_through_nullness = "/* nullable */\n";
+
+  (*variables)["key_type"] = TypeName(key, name_resolver, false);
+  (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+  (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
+  (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver);
+  (*variables)["key_wire_type"] = WireType(key);
+  (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+  // We use `x.getClass()` as a null check because it generates less bytecode
+  // than an `if (x == null) { throw ... }` statement.
+  (*variables)["key_null_check"] =
+      IsReferenceType(keyJavaType)
+          ? "java.lang.Class<?> keyClass = key.getClass();"
+          : "";
+  (*variables)["value_null_check"] =
+      IsReferenceType(valueJavaType)
+          ? "java.lang.Class<?> valueClass = value.getClass();"
+          : "";
+
+  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);
+
+    (*variables)["value_enum_type_pass_through_nullness"] =
+        pass_through_nullness + (*variables)["value_enum_type"];
+
+    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)["value_type_pass_through_nullness"] =
+        (IsReferenceType(valueJavaType) ? pass_through_nullness : "") +
+        (*variables)["value_type"];
+
+    (*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)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+
+  (*variables)["default_entry"] =
+      (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry";
+}
+
+}  // namespace
+
+ImmutableMapFieldLiteGenerator::ImmutableMapFieldLiteGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, Context* context)
+    : descriptor_(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
+  SetMessageVariables(descriptor, messageBitIndex, 0,
+                      context->GetFieldGeneratorInfo(descriptor), context,
+                      &variables_);
+}
+
+ImmutableMapFieldLiteGenerator::~ImmutableMapFieldLiteGenerator() {}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const { return 0; }
+
+void ImmutableMapFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$int ${$get$capitalized_name$Count$}$();\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$boolean ${$contains$capitalized_name$$}$(\n"
+                 "    $key_type$ key);\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Deprecated\n"
+                   "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "${$get$capitalized_name$Map$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$$value_enum_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_enum_type_pass_through_nullness$ "
+                   "        defaultValue);\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+        "    $key_type$ key);\n");
+    printer->Annotate("{", "}", descriptor_);
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "java.util.Map<$type_parameters$>\n"
+          "${$get$capitalized_name$Value$}$();\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+                     "$deprecation$java.util.Map<$type_parameters$>\n"
+                     "${$get$capitalized_name$ValueMap$}$();\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+                     "$deprecation$\n"
+                     "$value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n"
+                     "    $key_type$ key,\n"
+                     "    $value_type$ defaultValue);\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+                     "$deprecation$\n"
+                     "$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
+                     "    $key_type$ key);\n");
+      printer->Annotate("{", "}", descriptor_);
+    }
+  } else {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Deprecated\n"
+                   "java.util.Map<$type_parameters$>\n"
+                   "${$get$capitalized_name$$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$java.util.Map<$type_parameters$>\n"
+                   "${$get$capitalized_name$Map$}$();\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$\n"
+                   "$value_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_type_pass_through_nullness$ defaultValue);\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "$deprecation$\n"
+                   "$value_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+                   "    $key_type$ key);\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private static final class $capitalized_name$DefaultEntryHolder {\n"
+      "  static final com.google.protobuf.MapEntryLite<\n"
+      "      $type_parameters$> defaultEntry =\n"
+      "          com.google.protobuf.MapEntryLite\n"
+      "          .<$type_parameters$>newDefaultInstance(\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.MapFieldLite<\n"
+                 "    $type_parameters$> $name$_ =\n"
+                 "        com.google.protobuf.MapFieldLite.emptyMapField();\n"
+                 "private com.google.protobuf.MapFieldLite<$type_parameters$>\n"
+                 "internalGet$capitalized_name$() {\n"
+                 "  return $name$_;\n"
+                 "}\n"
+                 "private com.google.protobuf.MapFieldLite<$type_parameters$>\n"
+                 "internalGetMutable$capitalized_name$() {\n"
+                 "  if (!$name$_.isMutable()) {\n"
+                 "    $name$_ = $name$_.mutableCopy();\n"
+                 "  }\n"
+                 "  return $name$_;\n"
+                 "}\n");
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$\n"
+                 "public int ${$get$capitalized_name$Count$}$() {\n"
+                 "  return internalGet$capitalized_name$().size();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$\n"
+                 "public boolean ${$contains$capitalized_name$$}$(\n"
+                 "    $key_type$ key) {\n"
+                 "  $key_null_check$\n"
+                 "  return internalGet$capitalized_name$().containsKey(key);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  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");
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Deprecated\n"
+                   "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$$}$() {\n"
+                   "  return get$capitalized_name$Map();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "${$get$capitalized_name$Map$}$() {\n"
+        "  return java.util.Collections.unmodifiableMap(\n"
+        "      new com.google.protobuf.Internal.MapAdapter<\n"
+        "        $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "            internalGet$capitalized_name$(),\n"
+        "            $name$ValueConverter));\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  return map.containsKey(key)\n"
+        "         ? $name$ValueConverter.doForward(map.get(key))\n"
+        "         : defaultValue;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return $name$ValueConverter.doForward(map.get(key));\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Override\n"
+          "@java.lang.Deprecated\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$get$capitalized_name$Value$}$() {\n"
+          "  return get$capitalized_name$ValueMap();\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$get$capitalized_name$ValueMap$}$() {\n"
+          "  return java.util.Collections.unmodifiableMap(\n"
+          "      internalGet$capitalized_name$());\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public $value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$();\n"
+          "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public $value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
+          "    $key_type$ key) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$();\n"
+          "  if (!map.containsKey(key)) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  return map.get(key);\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+    }
+  } else {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Override\n"
+                   "@java.lang.Deprecated\n"
+                   "public java.util.Map<$type_parameters$> "
+                   "${$get$capitalized_name$$}$() {\n"
+                   "  return get$capitalized_name$Map();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public java.util.Map<$type_parameters$> "
+                   "${$get$capitalized_name$Map$}$() {\n"
+                   "  return java.util.Collections.unmodifiableMap(\n"
+                   "      internalGet$capitalized_name$());\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public $value_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+                   "    $key_type$ key) {\n"
+                   "  $key_null_check$\n"
+                   "  java.util.Map<$type_parameters$> map =\n"
+                   "      internalGet$capitalized_name$();\n"
+                   "  if (!map.containsKey(key)) {\n"
+                   "    throw new java.lang.IllegalArgumentException();\n"
+                   "  }\n"
+                   "  return map.get(key);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  // 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$Map() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGetMutable$capitalized_name$(),\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$ValueMap() {\n"
+          "  return internalGetMutable$capitalized_name$();\n"
+          "}\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "private java.util.Map<$type_parameters$>\n"
+                   "getMutable$capitalized_name$Map() {\n"
+                   "  return internalGetMutable$capitalized_name$();\n"
+                   "}\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  printer->Print(variables_,
+                 "\"$name$_\",\n"
+                 "$default_entry$,\n");
+  if (!SupportUnknownEnumValue(descriptor_) &&
+      GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    PrintEnumVerifierLogic(printer, ValueField(descriptor_), variables_,
+                           /*var_name=*/"$value_enum_type$",
+                           /*terminating_string=*/",\n",
+                           /*enforce_lite=*/context_->EnforceLite());
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$\n"
+                 "public int ${$get$capitalized_name$Count$}$() {\n"
+                 "  return instance.get$capitalized_name$Map().size();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$\n"
+      "public boolean ${$contains$capitalized_name$$}$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  return instance.get$capitalized_name$Map().containsKey(key);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$\n"
+                 "public Builder ${$clear$capitalized_name$$}$() {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.getMutable$capitalized_name$Map().clear();\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$\n"
+                 "public Builder ${$remove$capitalized_name$$}$(\n"
+                 "    $key_type$ key) {\n"
+                 "  $key_null_check$\n"
+                 "  copyOnWrite();\n"
+                 "  instance.getMutable$capitalized_name$Map().remove(key);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Deprecated\n"
+                   "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$$}$() {\n"
+                   "  return get$capitalized_name$Map();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+                   "${$get$capitalized_name$Map$}$() {\n"
+                   "  return java.util.Collections.unmodifiableMap(\n"
+                   "      instance.get$capitalized_name$Map());\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_enum_type_pass_through_nullness$ "
+        "${$get$capitalized_name$OrDefault$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type_pass_through_nullness$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  return map.containsKey(key)\n"
+        "         ? map.get(key)\n"
+        "         : defaultValue;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return map.get(key);\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ value) {\n"
+        "  $key_null_check$\n"
+        "  $value_null_check$\n"
+        "  copyOnWrite();\n"
+        "  instance.getMutable$capitalized_name$Map().put(key, value);\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
+        "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
+        "  copyOnWrite();\n"
+        "  instance.getMutable$capitalized_name$Map().putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Override\n"
+          "@java.lang.Deprecated\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$get$capitalized_name$Value$}$() {\n"
+          "  return get$capitalized_name$ValueMap();\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "${$get$capitalized_name$ValueMap$}$() {\n"
+          "  return java.util.Collections.unmodifiableMap(\n"
+          "      instance.get$capitalized_name$ValueMap());\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public $value_type$ ${$get$capitalized_name$ValueOrDefault$}$(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      instance.get$capitalized_name$ValueMap();\n"
+          "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "@java.lang.Override\n"
+          "$deprecation$\n"
+          "public $value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
+          "    $key_type$ key) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      instance.get$capitalized_name$ValueMap();\n"
+          "  if (!map.containsKey(key)) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  return map.get(key);\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ value) {\n"
+          "  $key_null_check$\n"
+          "  copyOnWrite();\n"
+          "  instance.getMutable$capitalized_name$ValueMap().put(key, value);\n"
+          "  return this;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+      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"
+          "  copyOnWrite();\n"
+          "  instance.getMutable$capitalized_name$ValueMap().putAll(values);\n"
+          "  return this;\n"
+          "}\n");
+      printer->Annotate("{", "}", descriptor_);
+    }
+  } else {
+    printer->Print(variables_,
+                   "/**\n"
+                   " * Use {@link #get$capitalized_name$Map()} instead.\n"
+                   " */\n"
+                   "@java.lang.Override\n"
+                   "@java.lang.Deprecated\n"
+                   "public java.util.Map<$type_parameters$> "
+                   "${$get$capitalized_name$$}$() {\n"
+                   "  return get$capitalized_name$Map();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$"
+                   "public java.util.Map<$type_parameters$> "
+                   "${$get$capitalized_name$Map$}$() {\n"
+                   "  return java.util.Collections.unmodifiableMap(\n"
+                   "      instance.get$capitalized_name$Map());\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$\n"
+        "public $value_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$\n"
+                   "public $value_type$ ${$get$capitalized_name$OrThrow$}$(\n"
+                   "    $key_type$ key) {\n"
+                   "  $key_null_check$\n"
+                   "  java.util.Map<$type_parameters$> map =\n"
+                   "      instance.get$capitalized_name$Map();\n"
+                   "  if (!map.containsKey(key)) {\n"
+                   "    throw new java.lang.IllegalArgumentException();\n"
+                   "  }\n"
+                   "  return map.get(key);\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$"
+        "public Builder ${$put$capitalized_name$$}$(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ value) {\n"
+        "  $key_null_check$\n"
+        "  $value_null_check$\n"
+        "  copyOnWrite();\n"
+        "  instance.getMutable$capitalized_name$Map().put(key, value);\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$"
+        "public Builder ${$putAll$capitalized_name$$}$(\n"
+        "    java.util.Map<$type_parameters$> values) {\n"
+        "  copyOnWrite();\n"
+        "  instance.getMutable$capitalized_name$Map().putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$kt_deprecation$ val $kt_name$: "
+      "com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  @kotlin.jvm.JvmSynthetic\n"
+      "  @JvmName(\"get$kt_capitalized_name$Map\")\n"
+      "  get() = com.google.protobuf.kotlin.DslMap(\n"
+      "    $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n"
+      "  )\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@JvmName(\"put$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .put(key: $kt_key_type$, value: $kt_value_type$) {\n"
+      "     $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"set$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .set(key: $kt_key_type$, value: $kt_value_type$) {\n"
+      "     put(key, value)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"remove$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .remove(key: $kt_key_type$) {\n"
+      "     $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"putAll$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) "
+      "{\n"
+      "     $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n"
+      "   }\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@JvmName(\"clear$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslMap"
+      "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "  .clear() {\n"
+      "     $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+      "   }\n");
+}
+
+void ImmutableMapFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  // Nothing to initialize.
+}
+
+std::string ImmutableMapFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/map_field_lite.h b/src/google/protobuf/compiler/java/map_field_lite.h
new file mode 100644
index 0000000..964f098
--- /dev/null
+++ b/src/google/protobuf/compiler/java/map_field_lite.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_JAVA_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+
+#include <cstdint>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                          int messageBitIndex,
+                                          Context* context);
+  ~ImmutableMapFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  Context* context_;
+  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/message.cc b/src/google/protobuf/compiler/java/message.cc
new file mode 100644
index 0000000..464cbe2
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message.cc
@@ -0,0 +1,1603 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/message.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/enum.h>
+#include <google/protobuf/compiler/java/extension.h>
+#include <google/protobuf/compiler/java/generator_factory.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/message_builder.h>
+#include <google/protobuf/compiler/java/message_builder_lite.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+std::string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                        ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->map_value();
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+// ===================================================================
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor)
+    : descriptor_(descriptor) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (IsRealOneof(descriptor_->field(i))) {
+      oneofs_.insert(descriptor_->field(i)->containing_oneof());
+    }
+  }
+}
+
+MessageGenerator::~MessageGenerator() {}
+
+// ===================================================================
+ImmutableMessageGenerator::ImmutableMessageGenerator(
+    const Descriptor* descriptor, Context* context)
+    : MessageGenerator(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()),
+      field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A non-lite message generator is used to "
+         "generate lite messages.";
+}
+
+ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
+
+void ImmutableMessageGenerator::GenerateStaticVariables(
+    io::Printer* printer, int* bytecode_estimate) {
+  // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
+  // used in the construction of descriptors, we have a tricky bootstrapping
+  // problem.  To help control static initialization order, we make sure all
+  // descriptors and other static data that depends on them are members of
+  // the outermost class in the file.  This way, they will be initialized in
+  // a deterministic order.
+
+  std::map<std::string, std::string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  vars["index"] = StrCat(descriptor_->index());
+  vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+  if (descriptor_->containing_type() != NULL) {
+    vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type());
+  }
+  if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
+    // We can only make these package-private since the classes that use them
+    // are in separate files.
+    vars["private"] = "";
+  } else {
+    vars["private"] = "private ";
+  }
+  if (*bytecode_estimate <= kMaxStaticSize) {
+    vars["final"] = "final ";
+  } else {
+    vars["final"] = "";
+  }
+
+  // The descriptor for this type.
+  printer->Print(
+      vars,
+      // TODO(teboring): final needs to be added back. The way to fix it is to
+      // generate methods that can construct the types, and then still declare
+      // the types, and then init them in clinit with the new method calls.
+      "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n"
+      "  internal_$identifier$_descriptor;\n");
+  *bytecode_estimate += 30;
+
+  // And the FieldAccessorTable.
+  GenerateFieldAccessorTable(printer, bytecode_estimate);
+
+  // Generate static members for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+        .GenerateStaticVariables(printer, bytecode_estimate);
+  }
+}
+
+int ImmutableMessageGenerator::GenerateStaticVariableInitializers(
+    io::Printer* printer) {
+  int bytecode_estimate = 0;
+  std::map<std::string, std::string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  vars["index"] = StrCat(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?
+    bytecode_estimate +=
+        ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+            .GenerateStaticVariableInitializers(printer);
+  }
+  return bytecode_estimate;
+}
+
+void ImmutableMessageGenerator::GenerateFieldAccessorTable(
+    io::Printer* printer, int* bytecode_estimate) {
+  std::map<std::string, std::string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
+    // We can only make these package-private since the classes that use them
+    // are in separate files.
+    vars["private"] = "";
+  } else {
+    vars["private"] = "private ";
+  }
+  if (*bytecode_estimate <= kMaxStaticSize) {
+    vars["final"] = "final ";
+  } else {
+    vars["final"] = "";
+  }
+  vars["ver"] = GeneratedCodeVersionSuffix();
+  printer->Print(
+      vars,
+      "$private$static $final$\n"
+      "  com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n"
+      "    internal_$identifier$_fieldAccessorTable;\n");
+
+  // The following bytecode_estimate calculation logic must stay in sync with
+  // the similar logic in the GenerateFieldAccessorTableInitializer method below
+  // to make sure that the generated static final fields are initialized  in the
+  // static initialization block directly.
+  //
+  // 6 bytes per field and oneof
+  *bytecode_estimate +=
+      10 + 6 * descriptor_->field_count() + 6 * descriptor_->oneof_decl_count();
+}
+
+int ImmutableMessageGenerator::GenerateFieldAccessorTableInitializer(
+    io::Printer* printer) {
+  int bytecode_estimate = 10;
+  printer->Print(
+      "internal_$identifier$_fieldAccessorTable = new\n"
+      "  com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable(\n"
+      "    internal_$identifier$_descriptor,\n"
+      "    new java.lang.String[] { ",
+      "identifier", UniqueFileScopeIdentifier(descriptor_), "ver",
+      GeneratedCodeVersionSuffix());
+  // All the bytecode_estimate calculation logic in this method must stay in
+  // sync with the similar logic in the GenerateFieldAccessorTable method
+  // above. See the corresponding comment in GenerateFieldAccessorTable for
+  // details.
+  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);
+  }
+  // We reproduce synthetic oneofs here since proto reflection needs these.
+  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) {
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true, "OrBuilder");
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        "$deprecation$public interface ${$$classname$OrBuilder$}$ extends\n"
+        "    $extra_interfaces$\n"
+        "    com.google.protobuf.GeneratedMessage$ver$.\n"
+        "        ExtendableMessageOrBuilder<$classname$> {\n",
+        "deprecation",
+        descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(), "{", "", "}", "", "ver",
+        GeneratedCodeVersionSuffix());
+  } else {
+    printer->Print(
+        "$deprecation$public interface ${$$classname$OrBuilder$}$ extends\n"
+        "    $extra_interfaces$\n"
+        "    com.google.protobuf.MessageOrBuilder {\n",
+        "deprecation",
+        descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(), "{", "", "}", "");
+  }
+  printer->Annotate("{", "}", descriptor_);
+
+  printer->Indent();
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+        .GenerateInterfaceMembers(printer);
+  }
+  for (auto oneof : oneofs_) {
+    printer->Print(
+        "\n"
+        "public $classname$.$oneof_capitalized_name$Case "
+        "get$oneof_capitalized_name$Case();\n",
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "classname",
+        context_->GetNameResolver()->GetImmutableClassName(descriptor_));
+  }
+  printer->Outdent();
+
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageGenerator::Generate(io::Printer* printer) {
+  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
+
+  std::map<std::string, std::string> variables;
+  variables["static"] = is_own_file ? "" : "static ";
+  variables["classname"] = descriptor_->name();
+  variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+  variables["ver"] = GeneratedCodeVersionSuffix();
+  variables["deprecation"] =
+      descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "";
+
+  WriteMessageDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true);
+  // The builder_type stores the super type name of the nested Builder class.
+  std::string builder_type;
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        variables,
+        "$deprecation$public $static$final class $classname$ extends\n");
+    printer->Annotate("classname", descriptor_);
+    printer->Print(
+        variables,
+        "    com.google.protobuf.GeneratedMessage$ver$.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_),
+        GeneratedCodeVersionSuffix());
+  } else {
+    printer->Print(
+        variables,
+        "$deprecation$public $static$final class $classname$ extends\n");
+    printer->Annotate("classname", descriptor_);
+    printer->Print(variables,
+                   "    com.google.protobuf.GeneratedMessage$ver$ implements\n"
+                   "    $extra_interfaces$\n"
+                   "    $classname$OrBuilder {\n");
+    builder_type =
+        strings::Substitute("com.google.protobuf.GeneratedMessage$0.Builder<?>",
+                         GeneratedCodeVersionSuffix());
+  }
+  printer->Print("private static final long serialVersionUID = 0L;\n");
+
+  printer->Indent();
+  // 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");
+
+  printer->Print(variables,
+                 "@java.lang.Override\n"
+                 "@SuppressWarnings({\"unused\"})\n"
+                 "protected java.lang.Object newInstance(\n"
+                 "    UnusedPrivateParameter unused) {\n"
+                 "  return new $classname$();\n"
+                 "}\n"
+                 "\n");
+
+  // TODO(b/248149118): Remove this superfluous override.
+  printer->Print(
+      "@java.lang.Override\n"
+      "public final com.google.protobuf.UnknownFieldSet\n"
+      "getUnknownFields() {\n"
+      "  return this.unknownFields;\n"
+      "}\n");
+
+  GenerateDescriptorMethods(printer);
+
+  // Nested types
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumGenerator(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;
+    ImmutableMessageGenerator messageGenerator(descriptor_->nested_type(i),
+                                               context_);
+    messageGenerator.GenerateInterface(printer);
+    messageGenerator.Generate(printer);
+  }
+
+  // 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
+  std::map<std::string, std::string> vars;
+  for (auto oneof : oneofs_) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name;
+    vars["oneof_capitalized_name"] =
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name;
+    vars["oneof_index"] = StrCat((oneof)->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"
+        // TODO(dweis): Remove EnumLite when we want to break compatibility with
+        // 3.x users
+        "    implements com.google.protobuf.Internal.EnumLite,\n"
+        "        com.google.protobuf.AbstractMessage.InternalOneOfEnum {\n");
+    printer->Indent();
+    for (int j = 0; j < (oneof)->field_count(); j++) {
+      const FieldDescriptor* field = (oneof)->field(j);
+      printer->Print(
+          "$deprecation$$field_name$($field_number$),\n", "deprecation",
+          field->options().deprecated() ? "@java.lang.Deprecated " : "",
+          "field_name", ToUpper(field->name()), "field_number",
+          StrCat(field->number()));
+    }
+    printer->Print("$cap_oneof_name$_NOT_SET(0);\n", "cap_oneof_name",
+                   ToUpper(vars["oneof_name"]));
+    printer->Print(vars,
+                   "private final int value;\n"
+                   "private $oneof_capitalized_name$Case(int value) {\n"
+                   "  this.value = value;\n"
+                   "}\n");
+    printer->Print(
+        vars,
+        "/**\n"
+        " * @param value The number of the enum to look for.\n"
+        " * @return The enum associated with the given number.\n"
+        " * @deprecated Use {@link #forNumber(int)} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+        "  return forNumber(value);\n"
+        "}\n"
+        "\n"
+        "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
+        "  switch (value) {\n");
+    for (int j = 0; j < (oneof)->field_count(); j++) {
+      const FieldDescriptor* field = (oneof)->field(j);
+      printer->Print("    case $field_number$: return $field_name$;\n",
+                     "field_number", StrCat(field->number()),
+                     "field_name", ToUpper(field->name()));
+    }
+    printer->Print(
+        "    case 0: return $cap_oneof_name$_NOT_SET;\n"
+        "    default: return null;\n"
+        "  }\n"
+        "}\n"
+        "public int getNumber() {\n"
+        "  return this.value;\n"
+        "}\n",
+        "cap_oneof_name", ToUpper(vars["oneof_name"]));
+    printer->Outdent();
+    printer->Print("};\n\n");
+    // oneofCase()
+    printer->Print(vars,
+                   "public $oneof_capitalized_name$Case\n"
+                   "get$oneof_capitalized_name$Case() {\n"
+                   "  return $oneof_capitalized_name$Case.forNumber(\n"
+                   "      $oneof_name$Case_);\n"
+                   "}\n"
+                   "\n");
+  }
+
+  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",
+                   "constant_name", FieldConstantName(descriptor_->field(i)),
+                   "number", StrCat(descriptor_->field(i)->number()));
+    printer->Annotate("constant_name", descriptor_->field(i));
+    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  if (context_->HasGeneratedMethods(descriptor_)) {
+    GenerateIsInitialized(printer);
+    GenerateMessageSerializationMethods(printer);
+    GenerateEqualsAndHashCode(printer);
+  }
+
+
+  GenerateParseFromMethods(printer);
+  GenerateBuilder(printer);
+
+  printer->Print(
+      "\n"
+      "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+      "full_name", descriptor_->full_name());
+
+  // Carefully initialize the default instance in such a way that it doesn't
+  // conflict with other initialization.
+  printer->Print("private static final $classname$ DEFAULT_INSTANCE;\n",
+                 "classname",
+                 name_resolver_->GetImmutableClassName(descriptor_));
+  printer->Print(
+      "static {\n"
+      "  DEFAULT_INSTANCE = new $classname$();\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+      "public static $classname$ getDefaultInstance() {\n"
+      "  return DEFAULT_INSTANCE;\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // 'of' method for Wrappers
+  if (IsWrappersProtoFile(descriptor_->file())) {
+    printer->Print(
+        "public static $classname$ of($field_type$ value) {\n"
+        "  return newBuilder().setValue(value).build();\n"
+        "}\n"
+        "\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_),
+        "field_type", PrimitiveTypeName(GetJavaType(descriptor_->field(0))));
+  }
+
+  GenerateParser(printer);
+
+  printer->Print(
+      "@java.lang.Override\n"
+      "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);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageGenerator::GenerateMessageSerializationMethods(
+    io::Printer* printer) {
+  std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
+      SortFieldsByNumber(descriptor_));
+
+  std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
+  sorted_extensions.reserve(descriptor_->extension_range_count());
+  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(
+      "@java.lang.Override\n"
+      "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.GeneratedMessage$ver$\n"
+          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+          "    extensionWriter = newMessageSetExtensionWriter();\n",
+          "classname", name_resolver_->GetImmutableClassName(descriptor_),
+          "ver", GeneratedCodeVersionSuffix());
+    } else {
+      printer->Print(
+          "com.google.protobuf.GeneratedMessage$ver$\n"
+          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+          "    extensionWriter = newExtensionWriter();\n",
+          "classname", name_resolver_->GetImmutableClassName(descriptor_),
+          "ver", GeneratedCodeVersionSuffix());
+    }
+  }
+
+  // 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 (descriptor_->options().message_set_wire_format()) {
+    printer->Print("getUnknownFields().writeAsMessageSetTo(output);\n");
+  } else {
+    printer->Print("getUnknownFields().writeTo(output);\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+      "}\n"
+      "\n"
+      "@java.lang.Override\n"
+      "public int getSerializedSize() {\n"
+      "  int size = memoizedSize;\n"
+      "  if (size != -1) return size;\n"
+      "\n");
+  printer->Indent();
+
+  printer->Print("size = 0;\n");
+
+  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 (descriptor_->options().message_set_wire_format()) {
+    printer->Print(
+        "size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
+  } else {
+    printer->Print("size += getUnknownFields().getSerializedSize();\n");
+  }
+
+  printer->Print(
+      "memoizedSize = size;\n"
+      "return size;\n");
+
+  printer->Outdent();
+  printer->Print(
+      "}\n"
+      "\n");
+}
+
+void ImmutableMessageGenerator::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"
+      "    java.nio.ByteBuffer data)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return PARSER.parseFrom(data);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    java.nio.ByteBuffer 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(\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 com.google.protobuf.GeneratedMessage$ver$\n"
+      "      .parseWithIOException(PARSER, input);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    java.io.InputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessage$ver$\n"
+      "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseDelimitedFrom(java.io.InputStream "
+      "input)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessage$ver$\n"
+      "      .parseDelimitedWithIOException(PARSER, input);\n"
+      "}\n"
+      "public static $classname$ parseDelimitedFrom(\n"
+      "    java.io.InputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessage$ver$\n"
+      "      .parseDelimitedWithIOException(PARSER, input, "
+      "extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    com.google.protobuf.CodedInputStream input)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessage$ver$\n"
+      "      .parseWithIOException(PARSER, input);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    com.google.protobuf.CodedInputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessage$ver$\n"
+      "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_), "ver",
+      GeneratedCodeVersionSuffix());
+}
+
+void ImmutableMessageGenerator::GenerateSerializeOneField(
+    io::Printer* printer, const FieldDescriptor* field) {
+  field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange(
+    io::Printer* printer, const Descriptor::ExtensionRange* range) {
+  printer->Print("extensionWriter.writeUntil($end$, output);\n", "end",
+                 StrCat(range->end));
+}
+
+// ===================================================================
+
+void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
+  // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+  printer->Print(
+      "@java.lang.Override\n"
+      "public Builder newBuilderForType() { return newBuilder(); }\n");
+
+  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"
+      "@java.lang.Override\n"
+      "public Builder toBuilder() {\n"
+      "  return this == DEFAULT_INSTANCE\n"
+      "      ? new Builder() : new Builder().mergeFrom(this);\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+      "@java.lang.Override\n"
+      "protected Builder newBuilderForType(\n"
+      "    com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n"
+      "  Builder builder = new Builder(parent);\n"
+      "  return builder;\n"
+      "}\n",
+      "ver", GeneratedCodeVersionSuffix());
+
+  MessageBuilderGenerator builderGenerator(descriptor_, context_);
+  builderGenerator.Generate(printer);
+}
+
+void ImmutableMessageGenerator::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_));
+  }
+  std::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"
+        "@java.lang.Override\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", StrCat(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(
+      "@java.lang.Override\n"
+      "protected com.google.protobuf.GeneratedMessage$ver$.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_), "ver",
+      GeneratedCodeVersionSuffix());
+}
+
+// ===================================================================
+
+void ImmutableMessageGenerator::GenerateIsInitialized(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(
+      "@java.lang.Override\n"
+      "public final boolean isInitialized() {\n");
+  printer->Indent();
+
+  // 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
+  //   "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"
+          "  memoizedIsInitialized = 0;\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"
+              "  memoizedIsInitialized = 0;\n"
+              "  return false;\n"
+              "}\n",
+              "type",
+              name_resolver_->GetImmutableClassName(field->message_type()),
+              "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_OPTIONAL:
+          printer->Print(
+              "if (has$name$()) {\n"
+              "  if (!get$name$().isInitialized()) {\n"
+              "    memoizedIsInitialized = 0;\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$Map().values()) {\n"
+                "  if (!item.isInitialized()) {\n"
+                "    memoizedIsInitialized = 0;\n"
+                "    return false;\n"
+                "  }\n"
+                "}\n",
+                "type",
+                MapValueImmutableClassdName(field->message_type(),
+                                            name_resolver_),
+                "name", info->capitalized_name);
+          } else {
+            printer->Print(
+                "for (int i = 0; i < get$name$Count(); i++) {\n"
+                "  if (!get$name$(i).isInitialized()) {\n"
+                "    memoizedIsInitialized = 0;\n"
+                "    return false;\n"
+                "  }\n"
+                "}\n",
+                "type",
+                name_resolver_->GetImmutableClassName(field->message_type()),
+                "name", info->capitalized_name);
+          }
+          break;
+      }
+    }
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        "if (!extensionsAreInitialized()) {\n"
+        "  memoizedIsInitialized = 0;\n"
+        "  return false;\n"
+        "}\n");
+  }
+
+  printer->Outdent();
+
+  printer->Print("  memoizedIsInitialized = 1;\n");
+
+  printer->Print(
+      "  return true;\n"
+      "}\n"
+      "\n");
+}
+
+// ===================================================================
+
+namespace {
+bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) {
+  if (field->is_repeated()) {
+    return false;
+  }
+  if (HasHasbit(field)) {
+    return true;
+  }
+  return GetJavaType(field) == JAVATYPE_MESSAGE && !IsRealOneof(field);
+}
+}  // namespace
+
+void ImmutableMessageGenerator::GenerateEqualsAndHashCode(
+    io::Printer* printer) {
+  printer->Print(
+      "@java.lang.Override\n"
+      "public boolean equals(");
+  printer->Print("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_));
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!IsRealOneof(field)) {
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+      if (check_has_bits) {
+        printer->Print(
+            "if (has$name$() != other.has$name$()) return false;\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 (auto oneof : oneofs_) {
+    printer->Print(
+        "if (!get$oneof_capitalized_name$Case().equals("
+        "other.get$oneof_capitalized_name$Case())) return false;\n",
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name);
+    printer->Print("switch ($oneof_name$Case_) {\n", "oneof_name",
+                   context_->GetOneofGeneratorInfo(oneof)->name);
+    printer->Indent();
+    for (int j = 0; j < (oneof)->field_count(); j++) {
+      const FieldDescriptor* field = (oneof)->field(j);
+      printer->Print("case $field_number$:\n", "field_number",
+                     StrCat(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");
+  }
+
+  // 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(
+      "if (!getUnknownFields().equals(other.getUnknownFields())) return "
+      "false;\n");
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        "if (!getExtensionFields().equals(other.getExtensionFields()))\n"
+        "  return false;\n");
+  }
+  printer->Print("return true;\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");
+
+  // If we output a getDescriptor() method, use that as it is more efficient.
+  if (descriptor_->options().no_standard_descriptor_accessor()) {
+    printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
+  } else {
+    printer->Print("hash = (19 * hash) + getDescriptor().hashCode();\n");
+  }
+
+  // hashCode non-oneofs.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!IsRealOneof(field)) {
+      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");
+      }
+    }
+  }
+
+  // hashCode oneofs.
+  for (auto oneof : oneofs_) {
+    printer->Print("switch ($oneof_name$Case_) {\n", "oneof_name",
+                   context_->GetOneofGeneratorInfo(oneof)->name);
+    printer->Indent();
+    for (int j = 0; j < (oneof)->field_count(); j++) {
+      const FieldDescriptor* field = (oneof)->field(j);
+      printer->Print("case $field_number$:\n", "field_number",
+                     StrCat(field->number()));
+      printer->Indent();
+      field_generators_.get(field).GenerateHashCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Print(
+        "case 0:\n"
+        "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print("hash = hashFields(hash, getExtensionFields());\n");
+  }
+
+  printer->Print("hash = (29 * hash) + getUnknownFields().hashCode();\n");
+  printer->Print(
+      "memoizedHashCode = hash;\n"
+      "return hash;\n");
+  printer->Outdent();
+  printer->Print(
+      "}\n"
+      "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageGenerator::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++) {
+    ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+        .GenerateExtensionRegistrationCode(printer);
+  }
+}
+
+// ===================================================================
+void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
+  printer->Print(
+      "$visibility$ static final com.google.protobuf.Parser<$classname$>\n"
+      "    PARSER = new com.google.protobuf.AbstractParser<$classname$>() {\n"
+      "  @java.lang.Override\n"
+      "  public $classname$ parsePartialFrom(\n"
+      "      com.google.protobuf.CodedInputStream input,\n"
+      "      com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "      throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "    Builder builder = newBuilder();\n"
+      "    try {\n"
+      "      builder.mergeFrom(input, extensionRegistry);\n"
+      "    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+      "      throw e.setUnfinishedMessage(builder.buildPartial());\n"
+      "    } catch (com.google.protobuf.UninitializedMessageException e) {\n"
+      "      throw "
+      "e.asInvalidProtocolBufferException().setUnfinishedMessage(builder."
+      "buildPartial());\n"
+      "    } catch (java.io.IOException e) {\n"
+      "      throw new com.google.protobuf.InvalidProtocolBufferException(e)\n"
+      "          .setUnfinishedMessage(builder.buildPartial());\n"
+      "    }\n"
+      "    return builder.buildPartial();\n"
+      "  }\n"
+      "};\n"
+      "\n"
+      "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",
+      "visibility",
+      ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public"
+                                              : "private",
+      "classname", descriptor_->name());
+}
+
+// ===================================================================
+void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!IsRealOneof(descriptor_->field(i))) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateInitializationCode(printer);
+    }
+  }
+}
+
+// ===================================================================
+void ImmutableMessageGenerator::GenerateMutableCopy(io::Printer* printer) {
+  printer->Print(
+      "protected com.google.protobuf.MutableMessage\n"
+      "    internalMutableDefault() {\n"
+      "  return MutableDefaultLoader.get();\n"
+      "}\n"
+      "\n"
+      "private static final class MutableDefaultLoader {\n"
+      "  private static final java.lang.Object defaultOrRuntimeException;\n"
+      "  static {\n"
+      "    java.lang.Object local;\n"
+      "    try {\n"
+      "      local = internalMutableDefault(\"$mutable_name$\");\n"
+      "    } catch (java.lang.RuntimeException e) {\n"
+      "      local = e;\n"
+      "    }\n"
+      "    defaultOrRuntimeException = local;\n"
+      "  }\n"
+      "\n"
+      "  private MutableDefaultLoader() {}\n"
+      "\n"
+      "  public static com.google.protobuf.MutableMessage get() {\n"
+      "    if (defaultOrRuntimeException\n"
+      "         instanceof java.lang.RuntimeException) {\n"
+      "      throw (java.lang.RuntimeException) defaultOrRuntimeException;\n"
+      "    }\n"
+      "    return\n"
+      "        (com.google.protobuf.MutableMessage) "
+      "defaultOrRuntimeException;\n"
+      "  }\n"
+      "}\n",
+      "mutable_name", name_resolver_->GetJavaMutableClassName(descriptor_));
+}
+
+void ImmutableMessageGenerator::GenerateKotlinDsl(io::Printer* printer) const {
+  printer->Print(
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "@com.google.protobuf.kotlin.ProtoDslMarker\n");
+  printer->Print(
+      "class Dsl private constructor(\n"
+      "  private val _builder: $message$.Builder\n"
+      ") {\n"
+      "  companion object {\n"
+      "    @kotlin.jvm.JvmSynthetic\n"
+      "    @kotlin.PublishedApi\n"
+      "    internal fun _create(builder: $message$.Builder): Dsl = "
+      "Dsl(builder)\n"
+      "  }\n"
+      "\n"
+      "  @kotlin.jvm.JvmSynthetic\n"
+      "  @kotlin.PublishedApi\n"
+      "  internal fun _build(): $message$ = _builder.build()\n",
+      "message", name_resolver_->GetClassName(descriptor_, true));
+
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+        .GenerateKotlinDslMembers(printer);
+  }
+
+  for (auto oneof : oneofs_) {
+    printer->Print(
+        "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
+        "  @JvmName(\"get$oneof_capitalized_name$Case\")\n"
+        "  get() = _builder.get$oneof_capitalized_name$Case()\n\n"
+        "fun clear$oneof_capitalized_name$() {\n"
+        "  _builder.clear$oneof_capitalized_name$()\n"
+        "}\n",
+        "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name,
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message",
+        name_resolver_->GetClassName(descriptor_, true));
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    GenerateKotlinExtensions(printer);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableMessageGenerator::GenerateKotlinMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      "@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n"
+      "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
+      "kotlin.Unit): "
+      "$message$ "
+      "=\n"
+      "  $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
+      "}._build()\n",
+      "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
+      "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_),
+      "message", name_resolver_->GetClassName(descriptor_, true));
+
+  printer->Print("object $name$Kt {\n", "name", descriptor_->name());
+  printer->Indent();
+  GenerateKotlinDsl(printer);
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+        .GenerateKotlinMembers(printer);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableMessageGenerator::GenerateTopLevelKotlinMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "inline fun $message$.copy(block: $message_kt$.Dsl.() -> "
+      "kotlin.Unit): "
+      "$message$ =\n"
+      "  $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
+      "}._build()\n\n",
+      "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
+      name_resolver_->GetKotlinExtensionsClassName(descriptor_));
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+        .GenerateTopLevelKotlinMembers(printer);
+  }
+
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->has_presence() && GetJavaType(field) == JAVATYPE_MESSAGE) {
+      printer->Print(
+          "val $full_classname$OrBuilder.$camelcase_name$OrNull: $full_name$?\n"
+          "  get() = if (has$name$()) get$name$() else null\n\n",
+          "full_classname", name_resolver_->GetClassName(descriptor_, true),
+          "camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
+          "full_name",
+          name_resolver_->GetImmutableClassName(field->message_type()), "name",
+          context_->GetFieldGeneratorInfo(field)->capitalized_name);
+    }
+  }
+}
+
+void ImmutableMessageGenerator::GenerateKotlinExtensions(
+    io::Printer* printer) const {
+  std::string message_name = name_resolver_->GetClassName(descriptor_, true);
+
+  printer->Print(
+      "@Suppress(\"UNCHECKED_CAST\")\n"
+      "@kotlin.jvm.JvmSynthetic\n"
+      "operator fun <T : kotlin.Any> get(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
+      "  return if (extension.isRepeated) {\n"
+      "    get(extension as com.google.protobuf.ExtensionLite<$message$, "
+      "List<*>>) as T\n"
+      "  } else {\n"
+      "    _builder.getExtension(extension)\n"
+      "  }\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
+      "operator fun <E : kotlin.Any> get(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n"
+      "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
+      "  return com.google.protobuf.kotlin.ExtensionList(extension, "
+      "_builder.getExtension(extension))\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "operator fun contains(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, *>): "
+      "Boolean {\n"
+      "  return _builder.hasExtension(extension)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "fun clear(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, *>) "
+      "{\n"
+      "  _builder.clearExtension(extension)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.PublishedApi\n"
+      "internal fun <T : kotlin.Any> setExtension(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, T>, "
+      "value: T) {\n"
+      "  _builder.setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <T : Comparable<T>> set(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+      "  value: T\n"
+      ") {\n"
+      "  setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun set(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, "
+      "com.google.protobuf.ByteString>,\n"
+      "  value: com.google.protobuf.ByteString\n"
+      ") {\n"
+      "  setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <T : com.google.protobuf.MessageLite> set(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+      "  value: T\n"
+      ") {\n"
+      "  setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "fun <E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.add(value: E) {\n"
+      "  _builder.addExtension(this.extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <E : kotlin.Any> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.plusAssign"
+      "(value: E) {\n"
+      "  add(value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "fun <E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.addAll(values: Iterable<E>) {\n"
+      "  for (value in values) {\n"
+      "    add(value)\n"
+      "  }\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <E : kotlin.Any> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.plusAssign(values: "
+      "Iterable<E>) {\n"
+      "  addAll(values)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "operator fun <E : kotlin.Any> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.set(index: Int, value: "
+      "E) {\n"
+      "  _builder.setExtension(this.extension, index, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline fun com.google.protobuf.kotlin.ExtensionList<*, "
+      "$message$>.clear() {\n"
+      "  clear(extension)\n"
+      "}\n\n",
+      "message", message_name);
+}
+
+void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
+  printer->Print(
+      "private static String getTypeUrl(\n"
+      "    java.lang.String typeUrlPrefix,\n"
+      "    com.google.protobuf.Descriptors.Descriptor descriptor) {\n"
+      "  return typeUrlPrefix.endsWith(\"/\")\n"
+      "      ? typeUrlPrefix + descriptor.getFullName()\n"
+      "      : typeUrlPrefix + \"/\" + descriptor.getFullName();\n"
+      "}\n"
+      "\n"
+      "private static String getTypeNameFromTypeUrl(\n"
+      "    java.lang.String typeUrl) {\n"
+      "  int pos = typeUrl.lastIndexOf('/');\n"
+      "  return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n"
+      "}\n"
+      "\n"
+      "public static <T extends com.google.protobuf.Message> Any pack(\n"
+      "    T message) {\n"
+      "  return Any.newBuilder()\n"
+      "      .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n"
+      "                             message.getDescriptorForType()))\n"
+      "      .setValue(message.toByteString())\n"
+      "      .build();\n"
+      "}\n"
+      "\n"
+      "/**\n"
+      " * Packs a message using the given type URL prefix. The type URL will\n"
+      " * be constructed by concatenating the message type's full name to the\n"
+      " * prefix with an optional \"/\" separator if the prefix doesn't end\n"
+      " * with \"/\" already.\n"
+      " */\n"
+      "public static <T extends com.google.protobuf.Message> Any pack(\n"
+      "    T message, java.lang.String typeUrlPrefix) {\n"
+      "  return Any.newBuilder()\n"
+      "      .setTypeUrl(getTypeUrl(typeUrlPrefix,\n"
+      "                             message.getDescriptorForType()))\n"
+      "      .setValue(message.toByteString())\n"
+      "      .build();\n"
+      "}\n"
+      "\n"
+      "public <T extends com.google.protobuf.Message> boolean is(\n"
+      "    java.lang.Class<T> clazz) {\n"
+      "  T defaultInstance =\n"
+      "      com.google.protobuf.Internal.getDefaultInstance(clazz);\n"
+      "  return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n"
+      "      defaultInstance.getDescriptorForType().getFullName());\n"
+      "}\n"
+      "\n"
+      "private volatile com.google.protobuf.Message cachedUnpackValue;\n"
+      "\n"
+      "@java.lang.SuppressWarnings(\"unchecked\")\n"
+      "public <T extends com.google.protobuf.Message> T unpack(\n"
+      "    java.lang.Class<T> clazz)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  boolean invalidClazz = false;\n"
+      "  if (cachedUnpackValue != null) {\n"
+      "    if (cachedUnpackValue.getClass() == clazz) {\n"
+      "      return (T) cachedUnpackValue;\n"
+      "    }\n"
+      "    invalidClazz = true;\n"
+      "  }\n"
+      "  if (invalidClazz || !is(clazz)) {\n"
+      "    throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+      "        \"Type of the Any message does not match the given class.\");\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
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/message.h b/src/google/protobuf/compiler/java/message.h
new file mode 100644
index 0000000..2dbd0dd
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message.h
@@ -0,0 +1,155 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+static const int kMaxStaticSize = 1 << 15;  // aka 32k
+
+class MessageGenerator {
+ public:
+  explicit MessageGenerator(const Descriptor* descriptor);
+  virtual ~MessageGenerator();
+
+  // All static variables have to be declared at the top-level of the file
+  // so that we can control initialization order, which is important for
+  // DescriptorProto bootstrapping to work.
+  virtual void GenerateStaticVariables(io::Printer* printer,
+                                       int* bytecode_estimate) = 0;
+
+  // Output code which initializes the static variables generated by
+  // 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;
+
+  // Generates the base interface that both the class and its builder
+  // implement
+  virtual void GenerateInterface(io::Printer* printer) = 0;
+
+  // Generate code to register all contained extensions with an
+  // ExtensionRegistry.
+  virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0;
+  virtual void GenerateKotlinDsl(io::Printer* printer) const = 0;
+  virtual void GenerateKotlinMembers(io::Printer* printer) const = 0;
+  virtual void GenerateTopLevelKotlinMembers(io::Printer* printer) const = 0;
+
+ protected:
+  const Descriptor* descriptor_;
+  std::set<const OneofDescriptor*> oneofs_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+class ImmutableMessageGenerator : public MessageGenerator {
+ public:
+  ImmutableMessageGenerator(const Descriptor* descriptor, Context* context);
+  ~ImmutableMessageGenerator() override;
+
+  void Generate(io::Printer* printer) override;
+  void GenerateInterface(io::Printer* printer) override;
+  void GenerateExtensionRegistrationCode(io::Printer* printer) override;
+  void GenerateStaticVariables(io::Printer* printer,
+                               int* bytecode_estimate) override;
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  int GenerateStaticVariableInitializers(io::Printer* printer) override;
+  void GenerateKotlinDsl(io::Printer* printer) const override;
+  void GenerateKotlinMembers(io::Printer* printer) const override;
+  void GenerateTopLevelKotlinMembers(io::Printer* printer) const override;
+
+ private:
+  void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  int GenerateFieldAccessorTableInitializer(io::Printer* printer);
+
+  void GenerateMessageSerializationMethods(io::Printer* printer);
+  void GenerateParseFromMethods(io::Printer* printer);
+  void GenerateSerializeOneField(io::Printer* printer,
+                                 const FieldDescriptor* field);
+  void GenerateSerializeOneExtensionRange(
+      io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+  void GenerateBuilder(io::Printer* printer);
+  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 GenerateMutableCopy(io::Printer* printer);
+  void GenerateKotlinExtensions(io::Printer* printer) const;
+  void GenerateKotlinOrNull(io::Printer* printer) const;
+  void GenerateAnyMethods(io::Printer* printer);
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/java/message_builder.cc b/src/google/protobuf/compiler/java/message_builder.cc
new file mode 100644
index 0000000..27e11ae
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_builder.cc
@@ -0,0 +1,810 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/message_builder.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.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/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/enum.h>
+#include <google/protobuf/compiler/java/extension.h>
+#include <google/protobuf/compiler/java/generator_factory.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+std::string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                        ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->map_value();
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+MessageBuilderGenerator::MessageBuilderGenerator(const Descriptor* descriptor,
+                                                 Context* context)
+    : descriptor_(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()),
+      field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A non-lite message generator is used to "
+         "generate lite messages.";
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (IsRealOneof(descriptor_->field(i))) {
+      oneofs_.insert(descriptor_->field(i)->containing_oneof());
+    }
+  }
+}
+
+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$ver$.ExtendableBuilder<\n"
+        "      $classname$, Builder> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_),
+        "extra_interfaces", ExtraBuilderInterfaces(descriptor_), "ver",
+        GeneratedCodeVersionSuffix());
+  } else {
+    printer->Print(
+        "public static final class Builder extends\n"
+        "    com.google.protobuf.GeneratedMessage$ver$.Builder<Builder> "
+        "implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_),
+        "extra_interfaces", ExtraBuilderInterfaces(descriptor_), "ver",
+        GeneratedCodeVersionSuffix());
+  }
+  printer->Indent();
+
+  GenerateDescriptorMethods(printer);
+  GenerateCommonBuilderMethods(printer);
+
+  if (context_->HasGeneratedMethods(descriptor_)) {
+    GenerateIsInitialized(printer);
+    GenerateBuilderParsingMethods(printer);
+  }
+
+  // oneof
+  std::map<std::string, std::string> vars;
+  for (auto oneof : oneofs_) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name;
+    vars["oneof_capitalized_name"] =
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name;
+    vars["oneof_index"] = StrCat(oneof->index());
+    // oneofCase_ and oneof_
+    printer->Print(vars,
+                   "private int $oneof_name$Case_ = 0;\n"
+                   "private java.lang.Object $oneof_name$_;\n");
+    // oneofCase() and clearOneof()
+    printer->Print(vars,
+                   "public $oneof_capitalized_name$Case\n"
+                   "    get$oneof_capitalized_name$Case() {\n"
+                   "  return $oneof_capitalized_name$Case.forNumber(\n"
+                   "      $oneof_name$Case_);\n"
+                   "}\n"
+                   "\n"
+                   "public Builder clear$oneof_capitalized_name$() {\n"
+                   "  $oneof_name$Case_ = 0;\n"
+                   "  $oneof_name$_ = null;\n");
+    printer->Print("  onChanged();\n");
+    printer->Print(
+        "  return this;\n"
+        "}\n"
+        "\n");
+  }
+
+  // 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);
+  }
+
+  // Override methods declared in GeneratedMessage to return the concrete
+  // generated type so callsites won't depend on GeneratedMessage. This
+  // is needed to keep binary compatibility when we change generated code
+  // to subclass a different GeneratedMessage class (e.g., in v3.0.0 release
+  // we changed all generated code to subclass GeneratedMessageV3).
+  printer->Print(
+      "@java.lang.Override\n"
+      "public final Builder setUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return super.setUnknownFields(unknownFields);\n"
+      "}\n"
+      "\n"
+      "@java.lang.Override\n"
+      "public final Builder mergeUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return super.mergeUnknownFields(unknownFields);\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_));
+  }
+  std::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", StrCat(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", StrCat(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(
+      "@java.lang.Override\n"
+      "protected com.google.protobuf.GeneratedMessage$ver$.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_), "ver",
+      GeneratedCodeVersionSuffix());
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::GenerateCommonBuilderMethods(
+    io::Printer* printer) {
+  // Decide if we really need to have the "maybeForceBuilderInitialization()"
+  // method.
+  // TODO(b/249158148): Remove the need for this entirely
+  bool need_maybe_force_builder_init = false;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (descriptor_->field(i)->message_type() != nullptr &&
+        !IsRealOneof(descriptor_->field(i)) &&
+        HasHasbit(descriptor_->field(i))) {
+      need_maybe_force_builder_init = true;
+      break;
+    }
+  }
+
+  const char* force_builder_init = need_maybe_force_builder_init
+                                       ? "  maybeForceBuilderInitialization();"
+                                       : "";
+
+  printer->Print(
+      "// Construct using $classname$.newBuilder()\n"
+      "private Builder() {\n"
+      "$force_builder_init$\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_),
+      "force_builder_init", force_builder_init);
+
+  printer->Print(
+      "private Builder(\n"
+      "    com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n"
+      "  super(parent);\n"
+      "$force_builder_init$\n"
+      "}\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_), "ver",
+      GeneratedCodeVersionSuffix(), "force_builder_init", force_builder_init);
+
+  if (need_maybe_force_builder_init) {
+    printer->Print(
+        "private void maybeForceBuilderInitialization() {\n"
+        "  if (com.google.protobuf.GeneratedMessage$ver$\n"
+        "          .alwaysUseFieldBuilders) {\n",
+        "ver", GeneratedCodeVersionSuffix());
+
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      if (!IsRealOneof(descriptor_->field(i))) {
+        field_generators_.get(descriptor_->field(i))
+            .GenerateFieldBuilderInitializationCode(printer);
+      }
+    }
+    printer->Outdent();
+    printer->Outdent();
+
+    printer->Print(
+        "  }\n"
+        "}\n");
+  }
+
+  printer->Print(
+      "@java.lang.Override\n"
+      "public Builder clear() {\n"
+      "  super.clear();\n");
+
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i))
+        .GenerateBuilderClearCode(printer);
+  }
+
+  for (auto oneof : oneofs_) {
+    printer->Print(
+        "$oneof_name$Case_ = 0;\n"
+        "$oneof_name$_ = null;\n",
+        "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name);
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+      "  return this;\n"
+      "}\n"
+      "\n");
+
+  printer->Print(
+      "@java.lang.Override\n"
+      "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(
+      "@java.lang.Override\n"
+      "public $classname$ getDefaultInstanceForType() {\n"
+      "  return $classname$.getDefaultInstance();\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+      "@java.lang.Override\n"
+      "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(
+      "@java.lang.Override\n"
+      "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;
+
+  // 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);
+  }
+
+  // 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 (auto oneof : oneofs_) {
+    printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
+                   "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name);
+  }
+
+  printer->Outdent();
+
+  printer->Print("  onBuilt();\n");
+
+  printer->Print(
+      "  return result;\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // Override methods declared in GeneratedMessage to return the concrete
+  // generated type so callsites won't depend on GeneratedMessage. This
+  // is needed to keep binary compatibility when we change generated code
+  // to subclass a different GeneratedMessage class (e.g., in v3.0.0 release
+  // we changed all generated code to subclass GeneratedMessageV3).
+  printer->Print(
+      "@java.lang.Override\n"
+      "public Builder clone() {\n"
+      "  return super.clone();\n"
+      "}\n"
+      "@java.lang.Override\n"
+      "public Builder setField(\n"
+      "    com.google.protobuf.Descriptors.FieldDescriptor field,\n"
+      "    java.lang.Object value) {\n"
+      "  return super.setField(field, value);\n"
+      "}\n"
+      "@java.lang.Override\n"
+      "public Builder clearField(\n"
+      "    com.google.protobuf.Descriptors.FieldDescriptor field) {\n"
+      "  return super.clearField(field);\n"
+      "}\n"
+      "@java.lang.Override\n"
+      "public Builder clearOneof(\n"
+      "    com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n"
+      "  return super.clearOneof(oneof);\n"
+      "}\n"
+      "@java.lang.Override\n"
+      "public Builder setRepeatedField(\n"
+      "    com.google.protobuf.Descriptors.FieldDescriptor field,\n"
+      "    int index, java.lang.Object value) {\n"
+      "  return super.setRepeatedField(field, index, value);\n"
+      "}\n"
+      "@java.lang.Override\n"
+      "public Builder addRepeatedField(\n"
+      "    com.google.protobuf.Descriptors.FieldDescriptor field,\n"
+      "    java.lang.Object value) {\n"
+      "  return super.addRepeatedField(field, value);\n"
+      "}\n");
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        "@java.lang.Override\n"
+        "public <Type> Builder setExtension(\n"
+        "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "        $classname$, Type> extension,\n"
+        "    Type value) {\n"
+        "  return super.setExtension(extension, value);\n"
+        "}\n"
+        "@java.lang.Override\n"
+        "public <Type> Builder setExtension(\n"
+        "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "        $classname$, java.util.List<Type>> extension,\n"
+        "    int index, Type value) {\n"
+        "  return super.setExtension(extension, index, value);\n"
+        "}\n"
+        "@java.lang.Override\n"
+        "public <Type> Builder addExtension(\n"
+        "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "        $classname$, java.util.List<Type>> extension,\n"
+        "    Type value) {\n"
+        "  return super.addExtension(extension, value);\n"
+        "}\n"
+        "@java.lang.Override\n"
+        "public <Type> Builder clearExtension(\n"
+        "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "        $classname$, ?> extension) {\n"
+        "  return super.clearExtension(extension);\n"
+        "}\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  }
+
+  // -----------------------------------------------------------------
+
+  if (context_->HasGeneratedMethods(descriptor_)) {
+    printer->Print(
+        "@java.lang.Override\n"
+        "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 (!IsRealOneof(descriptor_->field(i))) {
+        field_generators_.get(descriptor_->field(i))
+            .GenerateMergingCode(printer);
+      }
+    }
+
+    // Merge oneof fields.
+    for (auto oneof : oneofs_) {
+      printer->Print("switch (other.get$oneof_capitalized_name$Case()) {\n",
+                     "oneof_capitalized_name",
+                     context_->GetOneofGeneratorInfo(oneof)->capitalized_name);
+      printer->Indent();
+      for (int j = 0; j < oneof->field_count(); j++) {
+        const FieldDescriptor* field = oneof->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(oneof)->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");
+    }
+
+    printer->Print("  this.mergeUnknownFields(other.getUnknownFields());\n");
+
+    printer->Print("  onChanged();\n");
+
+    printer->Print(
+        "  return this;\n"
+        "}\n"
+        "\n");
+  }
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::GenerateBuilderParsingMethods(
+    io::Printer* printer) {
+  printer->Print(
+      "@java.lang.Override\n"
+      "public Builder mergeFrom(\n"
+      "    com.google.protobuf.CodedInputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  if (extensionRegistry == null) {\n"
+      "    throw new java.lang.NullPointerException();\n"
+      "  }\n"
+      "  try {\n"
+      "    boolean done = false;\n"
+      "    while (!done) {\n"
+      "      int tag = input.readTag();\n"
+      "      switch (tag) {\n"
+      "        case 0:\n"  // zero signals EOF / limit reached
+      "          done = true;\n"
+      "          break;\n");
+  printer->Indent();  // method
+  printer->Indent();  // try
+  printer->Indent();  // while
+  printer->Indent();  // switch
+  GenerateBuilderFieldParsingCases(printer);
+  printer->Outdent();  // switch
+  printer->Outdent();  // while
+  printer->Outdent();  // try
+  printer->Outdent();  // method
+  printer->Print(
+      "        default: {\n"
+      "          if (!super.parseUnknownField(input, extensionRegistry, tag)) "
+      "{\n"
+      "            done = true; // was an endgroup tag\n"
+      "          }\n"
+      "          break;\n"
+      "        } // default:\n"
+      "      } // switch (tag)\n"
+      "    } // while (!done)\n"
+      "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+      "    throw e.unwrapIOException();\n"
+      "  } finally {\n"
+      "    onChanged();\n"
+      "  } // finally\n"
+      "  return this;\n"
+      "}\n");
+}
+
+void MessageBuilderGenerator::GenerateBuilderFieldParsingCases(
+    io::Printer* printer) {
+  std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
+      SortFieldsByNumber(descriptor_));
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = sorted_fields[i];
+    GenerateBuilderFieldParsingCase(printer, field);
+    if (field->is_packable()) {
+      GenerateBuilderPackedFieldParsingCase(printer, field);
+    }
+  }
+}
+
+void MessageBuilderGenerator::GenerateBuilderFieldParsingCase(
+    io::Printer* printer, const FieldDescriptor* field) {
+  uint32_t tag = WireFormatLite::MakeTag(
+      field->number(), WireFormat::WireTypeForFieldType(field->type()));
+  std::string tagString = StrCat(static_cast<int32_t>(tag));
+  printer->Print("case $tag$: {\n", "tag", tagString);
+  printer->Indent();
+
+  field_generators_.get(field).GenerateBuilderParsingCode(printer);
+
+  printer->Outdent();
+  printer->Print(
+      "  break;\n"
+      "} // case $tag$\n",
+      "tag", tagString);
+}
+
+void MessageBuilderGenerator::GenerateBuilderPackedFieldParsingCase(
+    io::Printer* printer, const FieldDescriptor* field) {
+  // To make packed = true wire compatible, we generate parsing code from a
+  // packed version of this field regardless of field->options().packed().
+  uint32_t tag = WireFormatLite::MakeTag(
+      field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+  std::string tagString = StrCat(static_cast<int32_t>(tag));
+  printer->Print("case $tag$: {\n", "tag", tagString);
+  printer->Indent();
+
+  field_generators_.get(field).GenerateBuilderParsingCodeFromPacked(printer);
+
+  printer->Outdent();
+  printer->Print(
+      "  break;\n"
+      "} // case $tag$\n",
+      "tag", tagString);
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::GenerateIsInitialized(io::Printer* printer) {
+  printer->Print(
+      "@java.lang.Override\n"
+      "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:
+          printer->Print(
+              "if (has$name$()) {\n"
+              "  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$Map().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
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/message_builder.h b/src/google/protobuf/compiler/java/message_builder.h
new file mode 100644
index 0000000..3b71b8c
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_builder.h
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: 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 <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+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 GenerateBuilderFieldParsingCases(io::Printer* printer);
+  void GenerateBuilderFieldParsingCase(io::Printer* printer,
+                                       const FieldDescriptor* field);
+  void GenerateBuilderPackedFieldParsingCase(io::Printer* printer,
+                                             const FieldDescriptor* field);
+  void GenerateIsInitialized(io::Printer* printer);
+
+  const Descriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldGenerator> field_generators_;
+  std::set<const OneofDescriptor*> oneofs_;
+
+  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/message_builder_lite.cc b/src/google/protobuf/compiler/java/message_builder_lite.cc
new file mode 100644
index 0000000..526f949
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_builder_lite.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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/message_builder_lite.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.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/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/enum.h>
+#include <google/protobuf/compiler/java/extension.h>
+#include <google/protobuf/compiler/java/generator_factory.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+MessageBuilderLiteGenerator::MessageBuilderLiteGenerator(
+    const Descriptor* descriptor, Context* context)
+    : descriptor_(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()),
+      field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A lite message generator is used to "
+         "generate non-lite messages.";
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (IsRealOneof(descriptor_->field(i))) {
+      oneofs_.insert(descriptor_->field(i)->containing_oneof());
+    }
+  }
+}
+
+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
+  std::map<std::string, std::string> vars;
+  for (auto oneof : oneofs_) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name;
+    vars["oneof_capitalized_name"] =
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name;
+    vars["oneof_index"] = StrCat(oneof->index());
+
+    // oneofCase() and clearOneof()
+    printer->Print(vars,
+                   "@java.lang.Override\n"
+                   "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");
+  }
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+        .GenerateBuilderMembers(printer);
+  }
+
+  printer->Print(
+      "\n"
+      "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+      "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderLiteGenerator::GenerateCommonBuilderMethods(
+    io::Printer* printer) {
+  printer->Print(
+      "// Construct using $classname$.newBuilder()\n"
+      "private Builder() {\n"
+      "  super(DEFAULT_INSTANCE);\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/message_builder_lite.h b/src/google/protobuf/compiler/java/message_builder_lite.h
new file mode 100644
index 0000000..0d895fc
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_builder_lite.h
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: 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 <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+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_;
+  std::set<const OneofDescriptor*> oneofs_;
+
+  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/message_field.cc b/src/google/protobuf/compiler/java/message_field.cc
new file mode 100644
index 0000000..1ec372e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_field.cc
@@ -0,0 +1,1481 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/message_field.h>
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
+                         int builderBitIndex, const FieldGeneratorInfo* info,
+                         ClassNameResolver* name_resolver,
+                         std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  (*variables)["kt_type"] = (*variables)["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)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["on_changed"] = "onChanged();";
+  (*variables)["ver"] = GeneratedCodeVersionSuffix();
+  (*variables)["get_parser"] =
+      ExposePublicParser(descriptor->message_type()->file()) ? "PARSER"
+                                                             : "parser()";
+
+  if (HasHasbit(descriptor)) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+    (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["set_has_field_bit_builder"] =
+        GenerateSetBit(builderBitIndex) + ";";
+    (*variables)["clear_has_field_bit_builder"] =
+        GenerateClearBit(builderBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["set_has_field_bit_builder"] = "";
+    (*variables)["clear_has_field_bit_builder"] = "";
+
+    (*variables)["is_field_present_message"] =
+        (*variables)["name"] + "_ != null";
+  }
+
+  // For repeated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableMessageFieldGenerator::ImmutableMessageFieldGenerator(
+    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_);
+}
+
+ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() {}
+
+int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+int ImmutableMessageFieldGenerator::GetNumBitsForBuilder() const {
+  return GetNumBitsForMessage();
+}
+
+void ImmutableMessageFieldGenerator::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.
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_, "$deprecation$boolean has$capitalized_name$();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
+}
+
+void ImmutableMessageFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private $type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (HasHasbit(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+        "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public $type$OrBuilder "
+        "${$get$capitalized_name$OrBuilder$}$() {\n"
+        "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  } else {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $name$_ != null;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+        "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+                   "@java.lang.Override\n"
+                   "$deprecation$public $type$OrBuilder "
+                   "${$get$capitalized_name$OrBuilder$}$() {\n"
+                   "  return get$capitalized_name$();\n"
+                   "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+}
+
+void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
+    io::Printer* printer, const char* regular_case,
+    const char* nested_builder_case) const {
+  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(
+    io::Printer* printer, const char* method_prototype,
+    const char* regular_case, const char* nested_builder_case,
+    const char* trailing_code) const {
+  printer->Print(variables_, method_prototype);
+  printer->Annotate("{", "}", descriptor_);
+  printer->Print(" {\n");
+  printer->Indent();
+  PrintNestedBuilderCondition(printer, regular_case, nested_builder_case);
+  if (trailing_code != NULL) {
+    printer->Print(variables_, trailing_code);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableMessageFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  // 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.
+
+  bool has_hasbit = HasHasbit(descriptor_);
+
+  printer->Print(variables_, "private $type$ $name$_;\n");
+
+  printer->Print(variables_,
+                 // If this builder is non-null, it is used and the other fields
+                 // are ignored.
+                 "private com.google.protobuf.SingleFieldBuilder$ver$<\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".
+
+  // boolean hasField()
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  if (has_hasbit) {
+    printer->Print(
+        variables_,
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_builder$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  } else {
+    printer->Print(
+        variables_,
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $name$Builder_ != null || $name$_ != null;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  // Field getField()
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  PrintNestedBuilderFunction(
+      printer, "$deprecation$public $type$ ${$get$capitalized_name$$}$()",
+      "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n",
+      "return $name$Builder_.getMessage();\n", NULL);
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$set$capitalized_name$$}$($type$ value)",
+
+      "if (value == null) {\n"
+      "  throw new NullPointerException();\n"
+      "}\n"
+      "$name$_ = value;\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.setMessage(value);\n",
+
+      "$set_has_field_bit_builder$\n"
+      "return this;\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+      "    $type$.Builder builderForValue)",
+
+      "$name$_ = builderForValue.build();\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.setMessage(builderForValue.build());\n",
+
+      "$set_has_field_bit_builder$\n"
+      "return this;\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$merge$capitalized_name$$}$($type$ value)",
+
+      has_hasbit
+          ? "if ($get_has_field_bit_builder$ &&\n"
+            "    $name$_ != null &&\n"
+            "    $name$_ != $type$.getDefaultInstance()) {\n"
+            "  $name$_ =\n"
+            "    $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+            "} else {\n"
+            "  $name$_ = value;\n"
+            "}\n"
+            "$on_changed$\n"
+          : "if ($name$_ != null) {\n"
+            "  $name$_ =\n"
+            "    $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+            "} else {\n"
+            "  $name$_ = value;\n"
+            "}\n"
+            "$on_changed$\n",
+
+      "$name$Builder_.mergeFrom(value);\n",
+
+      "$set_has_field_bit_builder$\n"
+      "return this;\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()",
+
+      "$name$_ = null;\n"
+      "$on_changed$\n",
+
+      has_hasbit ? "$name$Builder_.clear();\n"
+                 : "$name$_ = null;\n"
+                   "$name$Builder_ = null;\n",
+
+      "$clear_has_field_bit_builder$\n"
+      "return this;\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");
+  printer->Annotate("{", "}", descriptor_);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
+      "    $type$, $type$.Builder, $type$OrBuilder> \n"
+      "    get$capitalized_name$FieldBuilder() {\n"
+      "  if ($name$Builder_ == null) {\n"
+      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\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::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: $kt_type$\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(
+      variables_,
+      "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+      "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+      "}\n");
+
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageFieldGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  if (descriptor_->has_optional_keyword()) {
+    printer->Print(variables_,
+                   "val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n"
+                   "  get() = $kt_dsl_builder$.$name$OrNull\n");
+  }
+}
+
+void ImmutableMessageFieldGenerator::GenerateFieldBuilderInitializationCode(
+    io::Printer* printer) const {
+  if (HasHasbit(descriptor_)) {
+    printer->Print(variables_, "get$capitalized_name$FieldBuilder();\n");
+  }
+}
+
+void ImmutableMessageFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {}
+
+void ImmutableMessageFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  if (HasHasbit(descriptor_)) {
+    PrintNestedBuilderCondition(printer, "$name$_ = null;\n",
+
+                                "$name$Builder_.clear();\n");
+    printer->Print(variables_, "$clear_has_field_bit_builder$\n");
+  } else {
+    PrintNestedBuilderCondition(printer, "$name$_ = null;\n",
+
+                                "$name$_ = null;\n"
+                                "$name$Builder_ = null;\n");
+  }
+}
+
+void ImmutableMessageFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if (other.has$capitalized_name$()) {\n"
+                 "  merge$capitalized_name$(other.get$capitalized_name$());\n"
+                 "}\n");
+}
+
+void ImmutableMessageFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  if (HasHasbit(descriptor_)) {
+    printer->Print(variables_, "if ($get_has_field_bit_from_local$) {\n");
+    printer->Indent();
+    PrintNestedBuilderCondition(printer, "result.$name$_ = $name$_;\n",
+                                "result.$name$_ = $name$Builder_.build();\n");
+    printer->Outdent();
+    printer->Print(variables_,
+                   "  $set_has_field_bit_to_local$;\n"
+                   "}\n");
+  } else {
+    PrintNestedBuilderCondition(printer, "result.$name$_ = $name$_;\n",
+                                "result.$name$_ = $name$Builder_.build();\n");
+  }
+}
+
+void ImmutableMessageFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+                   "input.readGroup($number$,\n"
+                   "    get$capitalized_name$FieldBuilder().getBuilder(),\n"
+                   "    extensionRegistry);\n"
+                   "$set_has_field_bit_builder$\n");
+  } else {
+    printer->Print(variables_,
+                   "input.readMessage(\n"
+                   "    get$capitalized_name$FieldBuilder().getBuilder(),\n"
+                   "    extensionRegistry);\n"
+                   "$set_has_field_bit_builder$\n");
+  }
+}
+
+void ImmutableMessageFieldGenerator::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 ImmutableMessageFieldGenerator::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 ImmutableMessageFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if (!get$capitalized_name$()\n"
+                 "    .equals(other.get$capitalized_name$())) return false;\n");
+}
+
+void ImmutableMessageFieldGenerator::GenerateHashCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "hash = (37 * hash) + $constant_name$;\n"
+                 "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+std::string ImmutableMessageFieldGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+ImmutableMessageOneofFieldGenerator::ImmutableMessageOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : ImmutableMessageFieldGenerator(descriptor, messageBitIndex,
+                                     builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableMessageOneofFieldGenerator::~ImmutableMessageOneofFieldGenerator() {}
+
+void ImmutableMessageOneofFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "     return ($type$) $oneof_name$_;\n"
+                 "  }\n"
+                 "  return $type$.getDefaultInstance();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableMessageOneofFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  // 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.
+  printer->Print(variables_,
+                 // If this builder is non-null, it is used and the other fields
+                 // are ignored.
+                 "private com.google.protobuf.SingleFieldBuilder$ver$<\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".
+
+  // boolean hasField()
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Field getField()
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  PrintNestedBuilderFunction(
+      printer,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$()",
+
+      "if ($has_oneof_case_message$) {\n"
+      "  return ($type$) $oneof_name$_;\n"
+      "}\n"
+      "return $type$.getDefaultInstance();\n",
+
+      "if ($has_oneof_case_message$) {\n"
+      "  return $name$Builder_.getMessage();\n"
+      "}\n"
+      "return $type$.getDefaultInstance();\n",
+
+      NULL);
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$set$capitalized_name$$}$($type$ value)",
+
+      "if (value == null) {\n"
+      "  throw new NullPointerException();\n"
+      "}\n"
+      "$oneof_name$_ = value;\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.setMessage(value);\n",
+
+      "$set_oneof_case_message$;\n"
+      "return this;\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+      "    $type$.Builder builderForValue)",
+
+      "$oneof_name$_ = builderForValue.build();\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.setMessage(builderForValue.build());\n",
+
+      "$set_oneof_case_message$;\n"
+      "return this;\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$merge$capitalized_name$$}$($type$ value)",
+
+      "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"
+      "$on_changed$\n",
+
+      "if ($has_oneof_case_message$) {\n"
+      "  $name$Builder_.mergeFrom(value);\n"
+      "} else {\n"
+      "  $name$Builder_.setMessage(value);\n"
+      "}\n",
+
+      "$set_oneof_case_message$;\n"
+      "return this;\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()",
+
+      "if ($has_oneof_case_message$) {\n"
+      "  $clear_oneof_case_message$;\n"
+      "  $oneof_name$_ = null;\n"
+      "  $on_changed$\n"
+      "}\n",
+
+      "if ($has_oneof_case_message$) {\n"
+      "  $clear_oneof_case_message$;\n"
+      "  $oneof_name$_ = null;\n"
+      "}\n"
+      "$name$Builder_.clear();\n",
+
+      "return this;\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$deprecation$public $type$.Builder "
+                 "${$get$capitalized_name$Builder$}$() {\n"
+                 "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.SingleFieldBuilder$ver$<\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$ver$<\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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableMessageOneofFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  // Make sure the builder gets cleared.
+  printer->Print(variables_,
+                 "if ($name$Builder_ != null) {\n"
+                 "  $name$Builder_.clear();\n"
+                 "}\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "if ($has_oneof_case_message$) {\n");
+  printer->Indent();
+
+  PrintNestedBuilderCondition(
+      printer, "result.$oneof_name$_ = $oneof_name$_;\n",
+
+      "result.$oneof_name$_ = $name$Builder_.build();\n");
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "merge$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageOneofFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+                   "input.readGroup($number$,\n"
+                   "    get$capitalized_name$FieldBuilder().getBuilder(),\n"
+                   "    extensionRegistry);\n"
+                   "$set_oneof_case_message$;\n");
+  } else {
+    printer->Print(variables_,
+                   "input.readMessage(\n"
+                   "    get$capitalized_name$FieldBuilder().getBuilder(),\n"
+                   "    extensionRegistry);\n"
+                   "$set_oneof_case_message$;\n");
+  }
+}
+
+void ImmutableMessageOneofFieldGenerator::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 ImmutableMessageOneofFieldGenerator::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");
+}
+
+// ===================================================================
+
+RepeatedImmutableMessageFieldGenerator::RepeatedImmutableMessageFieldGenerator(
+    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_);
+}
+
+RepeatedImmutableMessageFieldGenerator::
+    ~RepeatedImmutableMessageFieldGenerator() {}
+
+int RepeatedImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableMessageFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedImmutableMessageFieldGenerator::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");
+
+  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::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private java.util.List<$type$> $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<$type$> "
+                 "${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_;\n"  // note:  unmodifiable list
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+      "    ${$get$capitalized_name$OrBuilderList$}$() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$OrBuilder "
+                 "${$get$capitalized_name$OrBuilder$}$(\n"
+                 "    int index) {\n"
+                 "  return $name$_.get(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
+    io::Printer* printer, const char* regular_case,
+    const char* nested_builder_case) const {
+  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(
+    io::Printer* printer, const char* method_prototype,
+    const char* regular_case, const char* nested_builder_case,
+    const char* trailing_code) const {
+  printer->Print(variables_, method_prototype);
+  printer->Annotate("{", "}", descriptor_);
+  printer->Print(" {\n");
+  printer->Indent();
+  PrintNestedBuilderCondition(printer, regular_case, nested_builder_case);
+  if (trailing_code != NULL) {
+    printer->Print(variables_, trailing_code);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  // 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.
+
+  printer->Print(
+      variables_,
+      // Used when the builder is null.
+      // One field is the list and the other field keeps track of whether the
+      // list is immutable. If it's immutable, the invariant is that it must
+      // either an instance of Collections.emptyList() or it's an ArrayList
+      // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+      // a reference to the underlying ArrayList. This invariant allows us to
+      // share instances of lists between protocol buffers avoiding expensive
+      // memory allocations. Note, immutable is a strong guarantee here -- not
+      // just that the list cannot be modified via the reference but that the
+      // list can never be modified.
+      "private java.util.List<$type$> $name$_ =\n"
+      "  java.util.Collections.emptyList();\n"
+
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      "  if (!$get_mutable_bit_builder$) {\n"
+      "    $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
+      "    $set_mutable_bit_builder$;\n"
+      "   }\n"
+      "}\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$ver$<\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".
+
+  // List<Field> getRepeatedFieldList()
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public java.util.List<$type$> "
+      "${$get$capitalized_name$List$}$()",
+
+      "return java.util.Collections.unmodifiableList($name$_);\n",
+      "return $name$Builder_.getMessageList();\n",
+
+      NULL);
+
+  // int getRepeatedFieldCount()
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer, "$deprecation$public int ${$get$capitalized_name$Count$}$()",
+
+      "return $name$_.size();\n", "return $name$Builder_.getCount();\n",
+
+      NULL);
+
+  // Field getRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index)",
+
+      "return $name$_.get(index);\n",
+
+      "return $name$Builder_.getMessage(index);\n",
+
+      NULL);
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+      "    int index, $type$ value)",
+      "if (value == null) {\n"
+      "  throw new NullPointerException();\n"
+      "}\n"
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.set(index, value);\n"
+      "$on_changed$\n",
+      "$name$Builder_.setMessage(index, value);\n", "return this;\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+      "    int index, $type$.Builder builderForValue)",
+
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.set(index, builderForValue.build());\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.setMessage(index, builderForValue.build());\n",
+
+      "return this;\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$add$capitalized_name$$}$($type$ value)",
+
+      "if (value == null) {\n"
+      "  throw new NullPointerException();\n"
+      "}\n"
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.add(value);\n"
+
+      "$on_changed$\n",
+
+      "$name$Builder_.addMessage(value);\n",
+
+      "return this;\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$add$capitalized_name$$}$(\n"
+      "    int index, $type$ value)",
+
+      "if (value == null) {\n"
+      "  throw new NullPointerException();\n"
+      "}\n"
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.add(index, value);\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.addMessage(index, value);\n",
+
+      "return this;\n");
+
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$add$capitalized_name$$}$(\n"
+      "    $type$.Builder builderForValue)",
+
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.add(builderForValue.build());\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.addMessage(builderForValue.build());\n",
+
+      "return this;\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$add$capitalized_name$$}$(\n"
+      "    int index, $type$.Builder builderForValue)",
+
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.add(index, builderForValue.build());\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.addMessage(index, builderForValue.build());\n",
+
+      "return this;\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n"
+      "    java.lang.Iterable<? extends $type$> values)",
+
+      "ensure$capitalized_name$IsMutable();\n"
+      "com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
+      "    values, $name$_);\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.addAllMessages(values);\n",
+
+      "return this;\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()",
+
+      "$name$_ = java.util.Collections.emptyList();\n"
+      "$clear_mutable_bit_builder$;\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.clear();\n",
+
+      "return this;\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  PrintNestedBuilderFunction(
+      printer,
+      "$deprecation$public Builder ${$remove$capitalized_name$$}$(int index)",
+
+      "ensure$capitalized_name$IsMutable();\n"
+      "$name$_.remove(index);\n"
+      "$on_changed$\n",
+
+      "$name$Builder_.remove(index);\n",
+
+      "return this;\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");
+  printer->Annotate("{", "}", descriptor_);
+
+  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");
+  printer->Annotate("{", "}", descriptor_);
+
+  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");
+  printer->Annotate("{", "}", descriptor_);
+
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  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$ver$<\n"
+      "    $type$, $type$.Builder, $type$OrBuilder> \n"
+      "    get$capitalized_name$FieldBuilder() {\n"
+      "  if ($name$Builder_ == null) {\n"
+      "    $name$Builder_ = new "
+      "com.google.protobuf.RepeatedFieldBuilder$ver$<\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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutableMessageFieldGenerator::
+    GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "get$capitalized_name$FieldBuilder();\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  PrintNestedBuilderCondition(printer,
+                              "$name$_ = java.util.Collections.emptyList();\n",
+
+                              "$name$_ = null;\n"
+                              "$name$Builder_.clear();\n");
+
+  printer->Print(variables_, "$clear_mutable_bit_builder$;\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::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.
+  PrintNestedBuilderCondition(
+      printer,
+      "if (!other.$name$_.isEmpty()) {\n"
+      "  if ($name$_.isEmpty()) {\n"
+      "    $name$_ = other.$name$_;\n"
+      "    $clear_mutable_bit_builder$;\n"
+      "  } else {\n"
+      "    ensure$capitalized_name$IsMutable();\n"
+      "    $name$_.addAll(other.$name$_);\n"
+      "  }\n"
+      "  $on_changed$\n"
+      "}\n",
+
+      "if (!other.$name$_.isEmpty()) {\n"
+      "  if ($name$Builder_.isEmpty()) {\n"
+      "    $name$Builder_.dispose();\n"
+      "    $name$Builder_ = null;\n"
+      "    $name$_ = other.$name$_;\n"
+      "    $clear_mutable_bit_builder$;\n"
+      "    $name$Builder_ = \n"
+      "      com.google.protobuf.GeneratedMessage$ver$.alwaysUseFieldBuilders "
+      "?\n"
+      "         get$capitalized_name$FieldBuilder() : null;\n"
+      "  } else {\n"
+      "    $name$Builder_.addAllMessages(other.$name$_);\n"
+      "  }\n"
+      "}\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  // The code below (non-nested builder case) ensures that the result has an
+  // immutable list. If our list is immutable, we can just reuse it. If not,
+  // we make it immutable.
+  PrintNestedBuilderCondition(
+      printer,
+      "if ($get_mutable_bit_builder$) {\n"
+      "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+      "  $clear_mutable_bit_builder$;\n"
+      "}\n"
+      "result.$name$_ = $name$_;\n",
+
+      "result.$name$_ = $name$Builder_.build();\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+                   "$type$ m =\n"
+                   "    input.readGroup($number$,\n"
+                   "        $type$.$get_parser$,\n"
+                   "        extensionRegistry);\n");
+  } else {
+    printer->Print(variables_,
+                   "$type$ m =\n"
+                   "    input.readMessage(\n"
+                   "        $type$.$get_parser$,\n"
+                   "        extensionRegistry);\n");
+  }
+  PrintNestedBuilderCondition(printer,
+                              "ensure$capitalized_name$IsMutable();\n"
+                              "$name$_.add(m);\n",
+                              "$name$Builder_.addMessage(m);\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::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 RepeatedImmutableMessageFieldGenerator::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 RepeatedImmutableMessageFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!get$capitalized_name$List()\n"
+      "    .equals(other.get$capitalized_name$List())) return false;\n");
+}
+
+void RepeatedImmutableMessageFieldGenerator::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");
+}
+
+std::string RepeatedImmutableMessageFieldGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: $kt_type$) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: $kt_type$) {\n"
+                 "  add(value)\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+                 "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+      "  addAll(values)\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: $kt_type$) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n\n");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/message_field.h b/src/google/protobuf/compiler/java/message_field.h
new file mode 100644
index 0000000..3ff53ab
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_field.h
@@ -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.
+
+// 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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit ImmutableMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                          int messageBitIndex,
+                                          int builderBitIndex,
+                                          Context* context);
+  ~ImmutableMessageFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator
+  // ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+  void PrintNestedBuilderCondition(io::Printer* printer,
+                                   const char* regular_case,
+                                   const char* nested_builder_case) const;
+  void PrintNestedBuilderFunction(io::Printer* printer,
+                                  const char* method_prototype,
+                                  const char* regular_case,
+                                  const char* nested_builder_case,
+                                  const char* trailing_code) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldGenerator);
+  void GenerateKotlinOrNull(io::Printer* printer) const;
+};
+
+class ImmutableMessageOneofFieldGenerator
+    : public ImmutableMessageFieldGenerator {
+ public:
+  ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                      int messageBitIndex, int builderBitIndex,
+                                      Context* context);
+  ~ImmutableMessageOneofFieldGenerator() override;
+
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldGenerator);
+};
+
+class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit RepeatedImmutableMessageFieldGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableMessageFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+  void PrintNestedBuilderCondition(io::Printer* printer,
+                                   const char* regular_case,
+                                   const char* nested_builder_case) const;
+  void PrintNestedBuilderFunction(io::Printer* printer,
+                                  const char* method_prototype,
+                                  const char* regular_case,
+                                  const char* nested_builder_case,
+                                  const char* trailing_code) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/message_field_lite.cc b/src/google/protobuf/compiler/java/message_field_lite.cc
new file mode 100644
index 0000000..eb37ca6
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_field_lite.cc
@@ -0,0 +1,898 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/message_field_lite.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
+                         int builderBitIndex, const FieldGeneratorInfo* info,
+                         ClassNameResolver* name_resolver,
+                         std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  (*variables)["kt_type"] = (*variables)["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)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["required"] = descriptor->is_required() ? "true" : "false";
+
+  if (HasHasbit(descriptor)) {
+    // 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";
+  }
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+
+  // We use `x.getClass()` as a null check because it generates less bytecode
+  // than an `if (x == null) { throw ... }` statement.
+  (*variables)["null_check"] = "value.getClass();\n";
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableMessageFieldLiteGenerator::ImmutableMessageFieldLiteGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, Context* context)
+    : descriptor_(descriptor),
+      messageBitIndex_(messageBitIndex),
+      name_resolver_(context->GetNameResolver()) {
+  SetMessageVariables(descriptor, messageBitIndex, 0,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      name_resolver_, &variables_);
+}
+
+ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+  // TODO(dweis): We don't need a has bit for messages as they have null
+  // sentinels and no user should be reflecting on this. We could save some
+  // bits by setting to 0 and updating the runtimes but this might come at a
+  // runtime performance cost since we can't memoize has-bit reads.
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+void ImmutableMessageFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_, "$deprecation$boolean has$capitalized_name$();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  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 (HasHasbit(descriptor_)) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+        "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $name$_ != null;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+        "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$($type$ value) {\n"
+                 "  $null_check$"
+                 "  $name$_ = value;\n"
+                 "  $set_has_field_bit_message$\n"
+                 "  }\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.SuppressWarnings({\"ReferenceEquality\"})\n"
+      "private void merge$capitalized_name$($type$ value) {\n"
+      "  $null_check$"
+      "  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_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return instance.has$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Field getField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return instance.get$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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.build());\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: $kt_type$\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(
+      variables_,
+      "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+      "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+      "}\n");
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageFieldLiteGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  if (descriptor_->has_optional_keyword()) {
+    printer->Print(variables_,
+                   "val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n"
+                   "  get() = $kt_dsl_builder$.$name$OrNull\n");
+  }
+}
+
+void ImmutableMessageFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  if (HasHasbit(descriptor_)) {
+    WriteIntToUtf16CharSequence(messageBitIndex_, output);
+  }
+  printer->Print(variables_, "\"$name$_\",\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {}
+
+std::string ImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+ImmutableMessageOneofFieldLiteGenerator::
+    ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                            int messageBitIndex,
+                                            Context* context)
+    : ImmutableMessageFieldLiteGenerator(descriptor, messageBitIndex, 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);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "     return ($type$) $oneof_name$_;\n"
+                 "  }\n"
+                 "  return $type$.getDefaultInstance();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$($type$ value) {\n"
+                 "  $null_check$"
+                 "  $oneof_name$_ = value;\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"
+      "  $null_check$"
+      "  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::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output);
+  printer->Print(variables_, "$oneof_stored_type$.class,\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".
+
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return instance.has$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Field getField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return instance.get$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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.build());\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+// ===================================================================
+
+RepeatedImmutableMessageFieldLiteGenerator::
+    RepeatedImmutableMessageFieldLiteGenerator(
+        const FieldDescriptor* descriptor, int messageBitIndex,
+        Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetMessageVariables(descriptor, messageBitIndex, 0,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      name_resolver_, &variables_);
+}
+
+RepeatedImmutableMessageFieldLiteGenerator::
+    ~RepeatedImmutableMessageFieldLiteGenerator() {}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() 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_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<$type$> "
+                 "${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_;\n"  // note:  unmodifiable list
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+      "    ${$get$capitalized_name$OrBuilderList$}$() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  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->Annotate("{", "}", descriptor_);
+
+  printer->Print(
+      variables_,
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  com.google.protobuf.Internal.ProtobufList<$type$> tmp = $name$_;\n"
+      "  if (!tmp.isModifiable()) {\n"
+      "    $name$_ =\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\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"
+                 "  $null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.set(index, value);\n"
+                 "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "private void add$capitalized_name$($type$ value) {\n"
+                 "  $null_check$"
+                 "  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"
+                 "  $null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.add(index, value);\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_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<$type$> "
+                 "${$get$capitalized_name$List$}$() {\n"
+                 "  return java.util.Collections.unmodifiableList(\n"
+                 "      instance.get$capitalized_name$List());\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // int getRepeatedFieldCount()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return instance.get$capitalized_name$Count();\n"
+      "}");
+  printer->Annotate("{", "}", descriptor_);
+
+  // Field getRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return instance.get$capitalized_name$(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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,\n"
+                 "      builderForValue.build());\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+  // 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.build());\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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,\n"
+                 "      builderForValue.build());\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+
+  // 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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  printer->Print(variables_,
+                 "\"$name$_\",\n"
+                 "$type$.class,\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+}
+
+std::string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: $kt_type$) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: $kt_type$) {\n"
+                 "  add(value)\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+                 "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+      "  addAll(values)\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: $kt_type$) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/message_field_lite.h b/src/google/protobuf/compiler/java/message_field_lite.h
new file mode 100644
index 0000000..4253acc
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_field_lite.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.
+
+// 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 <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                              int messageBitIndex,
+                                              Context* context);
+  ~ImmutableMessageFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator
+  // ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  const int messageBitIndex_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator);
+  void GenerateKotlinOrNull(io::Printer* printer) const;
+};
+
+class ImmutableMessageOneofFieldLiteGenerator
+    : public ImmutableMessageFieldLiteGenerator {
+ public:
+  ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                          int messageBitIndex,
+                                          Context* context);
+  ~ImmutableMessageOneofFieldLiteGenerator() override;
+
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableMessageFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex, Context* context);
+  ~RepeatedImmutableMessageFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  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/message_lite.cc b/src/google/protobuf/compiler/java/message_lite.cc
new file mode 100644
index 0000000..a42ae3f
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_lite.cc
@@ -0,0 +1,1003 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/message_lite.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.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/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/enum_lite.h>
+#include <google/protobuf/compiler/java/extension_lite.h>
+#include <google/protobuf/compiler/java/generator_factory.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/message_builder.h>
+#include <google/protobuf/compiler/java/message_builder_lite.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/descriptor.pb.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+// ===================================================================
+ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator(
+    const Descriptor* descriptor, Context* context)
+    : MessageGenerator(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()),
+      field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A lite message generator is used to "
+         "generate non-lite messages.";
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (IsRealOneof(descriptor_->field(i))) {
+      oneofs_.insert(descriptor_->field(i)->containing_oneof());
+    }
+  }
+}
+
+ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
+
+void ImmutableMessageLiteGenerator::GenerateStaticVariables(
+    io::Printer* printer, int* bytecode_estimate) {
+  // Generate static members for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+        .GenerateStaticVariables(printer, bytecode_estimate);
+  }
+}
+
+int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers(
+    io::Printer* printer) {
+  int bytecode_estimate = 0;
+  // Generate static member initializers for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    bytecode_estimate +=
+        ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+            .GenerateStaticVariableInitializers(printer);
+  }
+  return bytecode_estimate;
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true, "OrBuilder");
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        "$deprecation$public interface ${$$classname$OrBuilder$}$ extends \n"
+        "    $extra_interfaces$\n"
+        "     com.google.protobuf.GeneratedMessageLite.\n"
+        "          ExtendableMessageOrBuilder<\n"
+        "              $classname$, $classname$.Builder> {\n",
+        "deprecation",
+        descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(), "{", "", "}", "");
+  } else {
+    printer->Print(
+        "$deprecation$public interface ${$$classname$OrBuilder$}$ extends\n"
+        "    $extra_interfaces$\n"
+        "    com.google.protobuf.MessageLiteOrBuilder {\n",
+        "deprecation",
+        descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(), "{", "", "}", "");
+  }
+  printer->Annotate("{", "}", descriptor_);
+
+  printer->Indent();
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+        .GenerateInterfaceMembers(printer);
+  }
+  for (auto oneof : oneofs_) {
+    printer->Print(
+        "\n"
+        "public $classname$.$oneof_capitalized_name$Case "
+        "get$oneof_capitalized_name$Case();\n",
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "classname",
+        context_->GetNameResolver()->GetImmutableClassName(descriptor_));
+  }
+  printer->Outdent();
+
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
+  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
+
+  std::map<std::string, std::string> variables;
+  variables["static"] = is_own_file ? " " : " static ";
+  variables["classname"] = descriptor_->name();
+  variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+  variables["deprecation"] =
+      descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "";
+
+  WriteMessageDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true);
+
+
+  // The builder_type stores the super type name of the nested Builder class.
+  std::string builder_type;
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+        variables,
+        "$deprecation$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,
+        "$deprecation$public $static$final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessageLite<\n"
+        "        $classname$, $classname$.Builder> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
+
+    builder_type = "com.google.protobuf.GeneratedMessageLite.Builder";
+  }
+  printer->Indent();
+
+  GenerateConstructor(printer);
+
+  // Nested types
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumLiteGenerator(descriptor_->enum_type(i), true, context_)
+        .Generate(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // Don't generate Java classes for map entry messages.
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageLiteGenerator messageGenerator(descriptor_->nested_type(i),
+                                                   context_);
+    messageGenerator.GenerateInterface(printer);
+    messageGenerator.Generate(printer);
+  }
+
+  // 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
+  std::map<std::string, std::string> vars;
+  for (auto oneof : oneofs_) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(oneof)->name;
+    vars["oneof_capitalized_name"] =
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name;
+    vars["oneof_index"] = StrCat((oneof)->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");
+    printer->Indent();
+    for (int j = 0; j < (oneof)->field_count(); j++) {
+      const FieldDescriptor* field = (oneof)->field(j);
+      printer->Print("$field_name$($field_number$),\n", "field_name",
+                     ToUpper(field->name()), "field_number",
+                     StrCat(field->number()));
+    }
+    printer->Print("$cap_oneof_name$_NOT_SET(0);\n", "cap_oneof_name",
+                   ToUpper(vars["oneof_name"]));
+    printer->Print(vars,
+                   "private final int value;\n"
+                   "private $oneof_capitalized_name$Case(int value) {\n"
+                   "  this.value = value;\n"
+                   "}\n");
+    printer->Print(
+        vars,
+        "/**\n"
+        " * @deprecated Use {@link #forNumber(int)} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+        "  return forNumber(value);\n"
+        "}\n"
+        "\n"
+        "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
+        "  switch (value) {\n");
+    for (int j = 0; j < (oneof)->field_count(); j++) {
+      const FieldDescriptor* field = (oneof)->field(j);
+      printer->Print("    case $field_number$: return $field_name$;\n",
+                     "field_number", StrCat(field->number()),
+                     "field_name", ToUpper(field->name()));
+    }
+    printer->Print(
+        "    case 0: return $cap_oneof_name$_NOT_SET;\n"
+        "    default: return null;\n"
+        "  }\n"
+        "}\n"
+        // TODO(b/135620659): Rename this to "getFieldNumber" or something to
+        // disambiguate it from actual proto enums.
+        "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,
+                   "@java.lang.Override\n"
+                   "public $oneof_capitalized_name$Case\n"
+                   "get$oneof_capitalized_name$Case() {\n"
+                   "  return $oneof_capitalized_name$Case.forNumber(\n"
+                   "      $oneof_name$Case_);\n"
+                   "}\n"
+                   "\n"
+                   "private void clear$oneof_capitalized_name$() {\n"
+                   "  $oneof_name$Case_ = 0;\n"
+                   "  $oneof_name$_ = null;\n"
+                   "}\n"
+                   "\n");
+  }
+
+  // Fields
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("public static final int $constant_name$ = $number$;\n",
+                   "constant_name", FieldConstantName(descriptor_->field(i)),
+                   "number", StrCat(descriptor_->field(i)->number()));
+    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  GenerateParseFromMethods(printer);
+  GenerateBuilder(printer);
+
+  if (HasRequiredFields(descriptor_)) {
+    // Memoizes whether the protocol buffer is fully initialized (has all
+    // required fields). 0 means false, 1 means true, and all other values
+    // mean not yet computed.
+    printer->Print("private byte memoizedIsInitialized = 2;\n");
+  }
+
+  printer->Print(
+      "@java.lang.Override\n"
+      "@java.lang.SuppressWarnings({\"unchecked\", \"fallthrough\"})\n"
+      "protected final java.lang.Object dynamicMethod(\n"
+      "    com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n"
+      "    java.lang.Object arg0, java.lang.Object arg1) {\n"
+      "  switch (method) {\n"
+      "    case NEW_MUTABLE_INSTANCE: {\n"
+      "      return new $classname$();\n"
+      "    }\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Indent();
+  printer->Indent();
+
+  printer->Print("case NEW_BUILDER: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodNewBuilder(printer);
+  printer->Outdent();
+
+  printer->Print(
+      "}\n"
+      "case BUILD_MESSAGE_INFO: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodNewBuildMessageInfo(printer);
+  printer->Outdent();
+
+  printer->Print(
+      "}\n"
+      "// fall through\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.
+      //
+      // The "parser" temporary mirrors the "PARSER" field to eliminate a read
+      // at the final return statement.
+      "  com.google.protobuf.Parser<$classname$> parser = PARSER;\n"
+      "  if (parser == null) {\n"
+      "    synchronized ($classname$.class) {\n"
+      "      parser = PARSER;\n"
+      "      if (parser == null) {\n"
+      "        parser =\n"
+      "            new DefaultInstanceBasedParser<$classname$>(\n"
+      "                DEFAULT_INSTANCE);\n"
+      "        PARSER = parser;\n"
+      "      }\n"
+      "    }\n"
+      "  }\n"
+      "  return parser;\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Outdent();
+
+  if (HasRequiredFields(descriptor_)) {
+    printer->Print(
+        "}\n"
+        "case GET_MEMOIZED_IS_INITIALIZED: {\n"
+        "  return memoizedIsInitialized;\n"
+        "}\n"
+        "case SET_MEMOIZED_IS_INITIALIZED: {\n"
+        "  memoizedIsInitialized = (byte) (arg0 == null ? 0 : 1);\n"
+        "  return null;\n"
+        "}\n");
+  } else {
+    printer->Print(
+        "}\n"
+        "case GET_MEMOIZED_IS_INITIALIZED: {\n"
+        "  return (byte) 1;\n"
+        "}\n"
+        "case SET_MEMOIZED_IS_INITIALIZED: {\n"
+        "  return null;\n"
+        "}\n");
+  }
+
+  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"
+      "  $classname$ defaultInstance = new $classname$();\n"
+      "  // New instances are implicitly immutable so no need to make\n"
+      "  // immutable.\n"
+      "  DEFAULT_INSTANCE = defaultInstance;\n"
+      // Register the default instance in a map. This map will be used by
+      // experimental runtime to lookup default instance given a class instance
+      // without using Java reflection.
+      "  com.google.protobuf.GeneratedMessageLite.registerDefaultInstance(\n"
+      "    $classname$.class, defaultInstance);\n"
+      "}\n"
+      "\n",
+      "classname", descriptor_->name());
+
+  printer->Print(
+      "public static $classname$ getDefaultInstance() {\n"
+      "  return DEFAULT_INSTANCE;\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // 'of' method for Wrappers
+  if (IsWrappersProtoFile(descriptor_->file())) {
+    printer->Print(
+        "public static $classname$ of($field_type$ value) {\n"
+        "  return newBuilder().setValue(value).build();\n"
+        "}\n"
+        "\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_),
+        "field_type", PrimitiveTypeName(GetJavaType(descriptor_->field(0))));
+  }
+
+  GenerateParser(printer);
+
+  // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+  // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
+  // the outer class's FileDescriptor.
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
+        .Generate(printer);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuildMessageInfo(
+    io::Printer* printer) {
+  printer->Indent();
+
+  // Collect field info into a sequence of UTF-16 chars. It will be embedded
+  // as a Java string in the generated code.
+  std::vector<uint16_t> chars;
+
+  int flags = 0;
+  if (IsProto2(descriptor_->file())) {
+    flags |= 0x1;
+  }
+  if (descriptor_->options().message_set_wire_format()) {
+    flags |= 0x2;
+  }
+  WriteIntToUtf16CharSequence(flags, &chars);
+  WriteIntToUtf16CharSequence(descriptor_->field_count(), &chars);
+
+  if (descriptor_->field_count() == 0) {
+    printer->Print("java.lang.Object[] objects = null;");
+  } else {
+    // A single array of all fields (including oneof, oneofCase, hasBits).
+    printer->Print("java.lang.Object[] objects = new java.lang.Object[] {\n");
+    printer->Indent();
+
+    // Record the number of oneofs.
+    WriteIntToUtf16CharSequence(oneofs_.size(), &chars);
+    for (auto oneof : oneofs_) {
+      printer->Print(
+          "\"$oneof_name$_\",\n"
+          "\"$oneof_name$Case_\",\n",
+          "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name);
+    }
+
+    // Integers for bit fields.
+    int total_bits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      total_bits +=
+          field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage();
+    }
+    int total_ints = (total_bits + 31) / 32;
+    for (int i = 0; i < total_ints; i++) {
+      printer->Print("\"$bit_field_name$\",\n", "bit_field_name",
+                     GetBitFieldName(i));
+    }
+    WriteIntToUtf16CharSequence(total_ints, &chars);
+
+    int map_count = 0;
+    int repeated_count = 0;
+    std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
+        SortFieldsByNumber(descriptor_));
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = sorted_fields[i];
+      if (field->is_map()) {
+        map_count++;
+      } else if (field->is_repeated()) {
+        repeated_count++;
+      }
+    }
+
+    WriteIntToUtf16CharSequence(sorted_fields[0]->number(), &chars);
+    WriteIntToUtf16CharSequence(
+        sorted_fields[descriptor_->field_count() - 1]->number(), &chars);
+    WriteIntToUtf16CharSequence(descriptor_->field_count(), &chars);
+    WriteIntToUtf16CharSequence(map_count, &chars);
+    WriteIntToUtf16CharSequence(repeated_count, &chars);
+
+    std::vector<const FieldDescriptor*> fields_for_is_initialized_check;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      if (descriptor_->field(i)->is_required() ||
+          (GetJavaType(descriptor_->field(i)) == JAVATYPE_MESSAGE &&
+           HasRequiredFields(descriptor_->field(i)->message_type()))) {
+        fields_for_is_initialized_check.push_back(descriptor_->field(i));
+      }
+    }
+    WriteIntToUtf16CharSequence(fields_for_is_initialized_check.size(), &chars);
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = sorted_fields[i];
+      field_generators_.get(field).GenerateFieldInfo(printer, &chars);
+    }
+    printer->Outdent();
+    printer->Print("};\n");
+  }
+
+  printer->Print("java.lang.String info =\n");
+  std::string line;
+  for (size_t i = 0; i < chars.size(); i++) {
+    uint16_t code = chars[i];
+    EscapeUtf16ToString(code, &line);
+    if (line.size() >= 80) {
+      printer->Print("    \"$string$\" +\n", "string", line);
+      line.clear();
+    }
+  }
+  printer->Print("    \"$string$\";\n", "string", line);
+
+  printer->Print("return newMessageInfo(DEFAULT_INSTANCE, info, objects);\n");
+  printer->Outdent();
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateParseFromMethods(
+    io::Printer* printer) {
+  printer->Print(
+      "public static $classname$ parseFrom(\n"
+      "    java.nio.ByteBuffer data)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, data);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    java.nio.ByteBuffer data,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    com.google.protobuf.ByteString data)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, data);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    com.google.protobuf.ByteString data,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseFrom(byte[] data)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, data);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    byte[] data,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseFrom(java.io.InputStream input)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, input);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    java.io.InputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, input, extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseDelimitedFrom(java.io.InputStream "
+      "input)\n"
+      "    throws java.io.IOException {\n"
+      "  return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n"
+      "}\n"
+      "public static $classname$ parseDelimitedFrom(\n"
+      "    java.io.InputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  return parseDelimitedFrom(DEFAULT_INSTANCE, input, "
+      "extensionRegistry);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    com.google.protobuf.CodedInputStream input)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, input);\n"
+      "}\n"
+      "public static $classname$ parseFrom(\n"
+      "    com.google.protobuf.CodedInputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws java.io.IOException {\n"
+      "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+      "      DEFAULT_INSTANCE, input, extensionRegistry);\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateBuilder(io::Printer* printer) {
+  printer->Print(
+      "public static Builder newBuilder() {\n"
+      "  return (Builder) DEFAULT_INSTANCE.createBuilder();\n"
+      "}\n"
+      "public static Builder newBuilder($classname$ prototype) {\n"
+      "  return (Builder) DEFAULT_INSTANCE.createBuilder(prototype);\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  MessageBuilderLiteGenerator builderGenerator(descriptor_, context_);
+  builderGenerator.Generate(printer);
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder(
+    io::Printer* printer) {
+  printer->Print("return new Builder();\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateExtensionRegistrationCode(
+    io::Printer* printer) {
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
+        .GenerateRegistrationCode(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+        .GenerateExtensionRegistrationCode(printer);
+  }
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateConstructor(io::Printer* printer) {
+  printer->Print("private $classname$() {\n", "classname", descriptor_->name());
+  printer->Indent();
+
+  // Initialize all fields to default.
+  GenerateInitializers(printer);
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) {
+  printer->Print(
+      "private static volatile com.google.protobuf.Parser<$classname$> "
+      "PARSER;\n"
+      "\n"
+      "public static com.google.protobuf.Parser<$classname$> parser() {\n"
+      "  return DEFAULT_INSTANCE.getParserForType();\n"
+      "}\n",
+      "classname", descriptor_->name());
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!IsRealOneof(descriptor_->field(i))) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateInitializationCode(printer);
+    }
+  }
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinDsl(
+    io::Printer* printer) const {
+  printer->Print(
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "@com.google.protobuf.kotlin.ProtoDslMarker\n");
+  printer->Print(
+      "class Dsl private constructor(\n"
+      "  private val _builder: $message$.Builder\n"
+      ") {\n"
+      "  companion object {\n"
+      "    @kotlin.jvm.JvmSynthetic\n"
+      "    @kotlin.PublishedApi\n"
+      "    internal fun _create(builder: $message$.Builder): Dsl = "
+      "Dsl(builder)\n"
+      "  }\n"
+      "\n"
+      "  @kotlin.jvm.JvmSynthetic\n"
+      "  @kotlin.PublishedApi\n"
+      "  internal fun _build(): $message$ = _builder.build()\n",
+      "message", name_resolver_->GetClassName(descriptor_, true));
+
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+        .GenerateKotlinDslMembers(printer);
+  }
+
+  for (auto oneof : oneofs_) {
+    printer->Print(
+        "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
+        "  @JvmName(\"get$oneof_capitalized_name$Case\")\n"
+        "  get() = _builder.get$oneof_capitalized_name$Case()\n\n"
+        "fun clear$oneof_capitalized_name$() {\n"
+        "  _builder.clear$oneof_capitalized_name$()\n"
+        "}\n",
+        "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name,
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message",
+        name_resolver_->GetClassName(descriptor_, true));
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    GenerateKotlinExtensions(printer);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      "@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n"
+      "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
+      "kotlin.Unit): "
+      "$message$ =\n"
+      "  $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
+      "}._build()\n",
+      "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
+      "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_),
+      "message", name_resolver_->GetClassName(descriptor_, true));
+
+  printer->Print("object $name$Kt {\n", "name", descriptor_->name());
+  printer->Indent();
+  GenerateKotlinDsl(printer);
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+        .GenerateKotlinMembers(printer);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateTopLevelKotlinMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      "inline fun $message$.copy(block: $message_kt$.Dsl.() -> "
+      "kotlin.Unit): "
+      "$message$ =\n"
+      "  $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
+      "}._build()\n\n",
+      "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
+      name_resolver_->GetKotlinExtensionsClassName(descriptor_));
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+        .GenerateTopLevelKotlinMembers(printer);
+  }
+
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  // Generate getFieldOrNull getters for all optional message fields.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->has_presence() && GetJavaType(field) == JAVATYPE_MESSAGE) {
+      printer->Print(
+          "val $full_classname$OrBuilder.$camelcase_name$OrNull: "
+          "$full_name$?\n"
+          "  get() = if (has$name$()) get$name$() else null\n\n",
+          "full_classname", name_resolver_->GetClassName(descriptor_, true),
+          "camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
+          "full_name",
+          name_resolver_->GetImmutableClassName(field->message_type()), "name",
+          context_->GetFieldGeneratorInfo(field)->capitalized_name);
+    }
+  }
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinExtensions(
+    io::Printer* printer) const {
+  std::string message_name = name_resolver_->GetClassName(descriptor_, true);
+
+  printer->Print(
+      "@Suppress(\"UNCHECKED_CAST\")\n"
+      "@kotlin.jvm.JvmSynthetic\n"
+      "operator fun <T : kotlin.Any> get(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
+      "  return if (extension.isRepeated) {\n"
+      "    get(extension as com.google.protobuf.ExtensionLite<$message$, "
+      "List<*>>) as T\n"
+      "  } else {\n"
+      "    _builder.getExtension(extension)\n"
+      "  }\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
+      "operator fun <E : kotlin.Any> get(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n"
+      "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
+      "  return com.google.protobuf.kotlin.ExtensionList(extension, "
+      "_builder.getExtension(extension))\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "operator fun contains(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, *>): "
+      "Boolean {\n"
+      "  return _builder.hasExtension(extension)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "fun clear(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, *>) "
+      "{\n"
+      "  _builder.clearExtension(extension)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.PublishedApi\n"
+      "internal fun <T : kotlin.Any> setExtension(extension: "
+      "com.google.protobuf.ExtensionLite<$message$, T>, "
+      "value: T) {\n"
+      "  _builder.setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <T : Comparable<T>> set(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+      "  value: T\n"
+      ") {\n"
+      "  setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun set(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, "
+      "com.google.protobuf.ByteString>,\n"
+      "  value: com.google.protobuf.ByteString\n"
+      ") {\n"
+      "  setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <T : com.google.protobuf.MessageLite> set(\n"
+      "  extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+      "  value: T\n"
+      ") {\n"
+      "  setExtension(extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "fun<E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.add(value: E) {\n"
+      "  _builder.addExtension(this.extension, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <E : kotlin.Any> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.plusAssign"
+      "(value: E) {\n"
+      "  add(value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "fun<E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.addAll(values: Iterable<E>) {\n"
+      "  for (value in values) {\n"
+      "    add(value)\n"
+      "  }\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun <E : kotlin.Any> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.plusAssign(values: "
+      "Iterable<E>) {\n"
+      "  addAll(values)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "operator fun <E : kotlin.Any> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
+      "$message$>.set(index: Int, value: "
+      "E) {\n"
+      "  _builder.setExtension(this.extension, index, value)\n"
+      "}\n\n",
+      "message", message_name);
+
+  printer->Print(
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline fun com.google.protobuf.kotlin.ExtensionList<*, "
+      "$message$>.clear() {\n"
+      "  clear(extension)\n"
+      "}\n\n",
+      "message", message_name);
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/message_lite.h b/src/google/protobuf/compiler/java/message_lite.h
new file mode 100644
index 0000000..d1e4b68
--- /dev/null
+++ b/src/google/protobuf/compiler/java/message_lite.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.
+
+// 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 <google/protobuf/compiler/java/field.h>
+#include <google/protobuf/compiler/java/message.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageLiteGenerator : public MessageGenerator {
+ public:
+  ImmutableMessageLiteGenerator(const Descriptor* descriptor, Context* context);
+  ~ImmutableMessageLiteGenerator() override;
+
+  void Generate(io::Printer* printer) override;
+  void GenerateInterface(io::Printer* printer) override;
+  void GenerateExtensionRegistrationCode(io::Printer* printer) override;
+  void GenerateStaticVariables(io::Printer* printer,
+                               int* bytecode_estimate) override;
+  int GenerateStaticVariableInitializers(io::Printer* printer) override;
+  void GenerateKotlinDsl(io::Printer* printer) const override;
+  void GenerateKotlinMembers(io::Printer* printer) const override;
+  void GenerateTopLevelKotlinMembers(io::Printer* printer) const override;
+
+ private:
+  void GenerateParseFromMethods(io::Printer* printer);
+
+  void GenerateBuilder(io::Printer* printer);
+  void GenerateDynamicMethodNewBuilder(io::Printer* printer);
+  void GenerateInitializers(io::Printer* printer);
+  void GenerateParser(io::Printer* printer);
+  void GenerateConstructor(io::Printer* printer);
+  void GenerateDynamicMethodNewBuildMessageInfo(io::Printer* printer);
+  void GenerateKotlinExtensions(io::Printer* printer) const;
+  void GenerateKotlinOrNull(io::Printer* printer) const;
+
+  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/name_resolver.cc b/src/google/protobuf/compiler/java/name_resolver.cc
new file mode 100644
index 0000000..06a637e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/name_resolver.cc
@@ -0,0 +1,385 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/name_resolver.h>
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/names.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+// A suffix that will be appended to the file's outer class name if the name
+// conflicts with some other types defined in the file.
+const char* kOuterClassNameSuffix = "OuterClass";
+
+// Strip package name from a descriptor's full name.
+// For example:
+//   Full name   : foo.Bar.Baz
+//   Package name: foo
+//   After strip : Bar.Baz
+std::string StripPackageName(const std::string& full_name,
+                             const FileDescriptor* file) {
+  if (file->package().empty()) {
+    return full_name;
+  } else {
+    // Strip package name
+    return full_name.substr(file->package().size() + 1);
+  }
+}
+
+// Get the name of a message's Java class without package name prefix.
+std::string ClassNameWithoutPackage(const Descriptor* descriptor,
+                                    bool immutable) {
+  return StripPackageName(descriptor->full_name(), descriptor->file());
+}
+
+std::string ClassNameWithoutPackageKotlin(const Descriptor* descriptor) {
+  std::string result = descriptor->name();
+  const Descriptor* temp = descriptor->containing_type();
+
+  while (temp) {
+    result = temp->name() + "Kt." + result;
+    temp = temp->containing_type();
+  }
+  return result;
+}
+
+// Get the name of an enum's Java class without package name prefix.
+std::string ClassNameWithoutPackage(const EnumDescriptor* descriptor,
+                                    bool immutable) {
+  // Doesn't append "Mutable" for enum type's name.
+  const Descriptor* message_descriptor = descriptor->containing_type();
+  if (message_descriptor == NULL) {
+    return descriptor->name();
+  } else {
+    return ClassNameWithoutPackage(message_descriptor, immutable) + "." +
+           descriptor->name();
+  }
+}
+
+// Get the name of a service's Java class without package name prefix.
+std::string ClassNameWithoutPackage(const ServiceDescriptor* descriptor,
+                                    bool immutable) {
+  std::string full_name =
+      StripPackageName(descriptor->full_name(), descriptor->file());
+  // We don't allow nested service definitions.
+  GOOGLE_CHECK(full_name.find('.') == std::string::npos);
+  return full_name;
+}
+
+// Return true if a and b are equals (case insensitive).
+NameEquality CheckNameEquality(const std::string& a, const std::string& b) {
+  if (ToUpper(a) == ToUpper(b)) {
+    if (a == b) {
+      return NameEquality::EXACT_EQUAL;
+    }
+    return NameEquality::EQUAL_IGNORE_CASE;
+  }
+  return NameEquality::NO_MATCH;
+}
+
+// Check whether a given message or its nested types has the given class name.
+bool MessageHasConflictingClassName(const Descriptor* message,
+                                    const std::string& classname,
+                                    NameEquality equality_mode) {
+  if (CheckNameEquality(message->name(), classname) == equality_mode) {
+    return true;
+  }
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    if (MessageHasConflictingClassName(message->nested_type(i), classname,
+                                       equality_mode)) {
+      return true;
+    }
+  }
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    if (CheckNameEquality(message->enum_type(i)->name(), classname) ==
+        equality_mode) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+ClassNameResolver::ClassNameResolver() {}
+
+ClassNameResolver::~ClassNameResolver() {}
+
+std::string ClassNameResolver::GetFileDefaultImmutableClassName(
+    const FileDescriptor* file) {
+  std::string basename;
+  std::string::size_type last_slash = file->name().find_last_of('/');
+  if (last_slash == std::string::npos) {
+    basename = file->name();
+  } else {
+    basename = file->name().substr(last_slash + 1);
+  }
+  return UnderscoresToCamelCase(StripProto(basename), true);
+}
+
+std::string ClassNameResolver::GetFileImmutableClassName(
+    const FileDescriptor* file) {
+  std::string& class_name = file_immutable_outer_class_names_[file];
+  if (class_name.empty()) {
+    if (file->options().has_java_outer_classname()) {
+      class_name = file->options().java_outer_classname();
+    } else {
+      class_name = GetFileDefaultImmutableClassName(file);
+      if (HasConflictingClassName(file, class_name,
+                                  NameEquality::EXACT_EQUAL)) {
+        class_name += kOuterClassNameSuffix;
+      }
+    }
+  }
+  return class_name;
+}
+
+std::string ClassNameResolver::GetFileClassName(const FileDescriptor* file,
+                                                bool immutable) {
+  return GetFileClassName(file, immutable, false);
+}
+
+std::string ClassNameResolver::GetFileClassName(const FileDescriptor* file,
+                                                bool immutable, bool kotlin) {
+  if (kotlin) {
+    return GetFileImmutableClassName(file) + "Kt";
+  } else if (immutable) {
+    return GetFileImmutableClassName(file);
+  } else {
+    return "Mutable" + GetFileImmutableClassName(file);
+  }
+}
+
+// Check whether there is any type defined in the proto file that has
+// the given class name.
+bool ClassNameResolver::HasConflictingClassName(const FileDescriptor* file,
+                                                const std::string& classname,
+                                                NameEquality equality_mode) {
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    if (CheckNameEquality(file->enum_type(i)->name(), classname) ==
+        equality_mode) {
+      return true;
+    }
+  }
+  for (int i = 0; i < file->service_count(); i++) {
+    if (CheckNameEquality(file->service(i)->name(), classname) ==
+        equality_mode) {
+      return true;
+    }
+  }
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (MessageHasConflictingClassName(file->message_type(i), classname,
+                                       equality_mode)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+std::string ClassNameResolver::GetDescriptorClassName(
+    const FileDescriptor* descriptor) {
+  return GetFileImmutableClassName(descriptor);
+}
+
+std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
+                                            bool immutable) {
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
+                                            bool immutable, bool kotlin) {
+  std::string result = FileJavaPackage(descriptor, immutable);
+  if (!result.empty()) result += '.';
+  result += GetFileClassName(descriptor, immutable, kotlin);
+  return result;
+}
+
+// Get the full name of a Java class by prepending the Java package name
+// or outer class name.
+std::string ClassNameResolver::GetClassFullName(
+    const std::string& name_without_package, const FileDescriptor* file,
+    bool immutable, bool is_own_file) {
+  return GetClassFullName(name_without_package, file, immutable, is_own_file,
+                          false);
+}
+
+std::string ClassNameResolver::GetClassFullName(
+    const std::string& name_without_package, const FileDescriptor* file,
+    bool immutable, bool is_own_file, bool kotlin) {
+  std::string result;
+  if (is_own_file) {
+    result = FileJavaPackage(file, immutable);
+  } else {
+    result = GetClassName(file, immutable, kotlin);
+  }
+  if (!result.empty()) {
+    result += '.';
+  }
+  result += name_without_package;
+  if (kotlin) result += "Kt";
+  return result;
+}
+
+std::string ClassNameResolver::GetClassName(const Descriptor* descriptor,
+                                            bool immutable) {
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const Descriptor* descriptor,
+                                            bool immutable, bool kotlin) {
+  return GetClassFullName(
+      ClassNameWithoutPackage(descriptor, immutable), descriptor->file(),
+      immutable, MultipleJavaFiles(descriptor->file(), immutable), kotlin);
+}
+
+std::string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor,
+                                            bool immutable) {
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor,
+                                            bool immutable, bool kotlin) {
+  return GetClassFullName(
+      ClassNameWithoutPackage(descriptor, immutable), descriptor->file(),
+      immutable, MultipleJavaFiles(descriptor->file(), immutable), kotlin);
+}
+
+std::string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor,
+                                            bool immutable) {
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor,
+                                            bool immutable, bool kotlin) {
+  return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
+                          descriptor->file(), immutable,
+                          IsOwnFile(descriptor, immutable), kotlin);
+}
+
+// Get the Java Class style full name of a message.
+std::string ClassNameResolver::GetJavaClassFullName(
+    const std::string& name_without_package, const FileDescriptor* file,
+    bool immutable) {
+  return GetJavaClassFullName(name_without_package, file, immutable, false);
+}
+
+std::string ClassNameResolver::GetJavaClassFullName(
+    const std::string& name_without_package, const FileDescriptor* file,
+    bool immutable, bool kotlin) {
+  std::string result;
+  if (MultipleJavaFiles(file, immutable)) {
+    result = FileJavaPackage(file, immutable);
+    if (!result.empty()) result += '.';
+  } else {
+    result = GetClassName(file, immutable, kotlin);
+    if (!result.empty()) result += '$';
+  }
+  result += StringReplace(name_without_package, ".", "$", true);
+  return result;
+}
+
+std::string ClassNameResolver::GetExtensionIdentifierName(
+    const FieldDescriptor* descriptor, bool immutable) {
+  return GetExtensionIdentifierName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetExtensionIdentifierName(
+    const FieldDescriptor* descriptor, bool immutable, bool kotlin) {
+  return GetClassName(descriptor->containing_type(), immutable, kotlin) + "." +
+         descriptor->name();
+}
+
+std::string ClassNameResolver::GetKotlinFactoryName(
+    const Descriptor* descriptor) {
+  std::string name = ToCamelCase(descriptor->name(), /* lower_first = */ true);
+  return IsForbiddenKotlin(name) ? name + "_" : name;
+}
+
+std::string ClassNameResolver::GetJavaImmutableClassName(
+    const Descriptor* descriptor) {
+  return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, true),
+                              descriptor->file(), true);
+}
+
+std::string ClassNameResolver::GetJavaImmutableClassName(
+    const EnumDescriptor* descriptor) {
+  return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, true),
+                              descriptor->file(), true);
+}
+
+std::string ClassNameResolver::GetKotlinExtensionsClassName(
+    const Descriptor* descriptor) {
+  return GetClassFullName(ClassNameWithoutPackageKotlin(descriptor),
+                          descriptor->file(), true, true, true);
+}
+
+std::string ClassNameResolver::GetJavaMutableClassName(
+    const Descriptor* descriptor) {
+  return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, false),
+                              descriptor->file(), false);
+}
+
+std::string ClassNameResolver::GetJavaMutableClassName(
+    const EnumDescriptor* descriptor) {
+  return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, false),
+                              descriptor->file(), false);
+}
+
+std::string ClassNameResolver::GetDowngradedFileClassName(
+    const FileDescriptor* file) {
+  return "Downgraded" + GetFileClassName(file, false);
+}
+
+std::string ClassNameResolver::GetDowngradedClassName(
+    const Descriptor* descriptor) {
+  return FileJavaPackage(descriptor->file()) + "." +
+         GetDowngradedFileClassName(descriptor->file()) + "." +
+         ClassNameWithoutPackage(descriptor, false);
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/name_resolver.h b/src/google/protobuf/compiler/java/name_resolver.h
new file mode 100644
index 0000000..103cace
--- /dev/null
+++ b/src/google/protobuf/compiler/java/name_resolver.h
@@ -0,0 +1,159 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class FileDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace java {
+
+// Indicates how closely the two class names match.
+enum NameEquality { NO_MATCH, EXACT_EQUAL, EQUAL_IGNORE_CASE };
+
+// Used to get the Java class related names for a given descriptor. It caches
+// the results to avoid redundant calculation across multiple name queries.
+// Thread-safety note: This class is *not* thread-safe.
+class ClassNameResolver {
+ public:
+  ClassNameResolver();
+  ~ClassNameResolver();
+
+  // Gets the unqualified outer class name for the file.
+  std::string GetFileClassName(const FileDescriptor* file, bool immutable);
+  std::string GetFileClassName(const FileDescriptor* file, bool immutable,
+                               bool kotlin);
+  // Gets the unqualified immutable outer class name of a file.
+  std::string GetFileImmutableClassName(const FileDescriptor* file);
+  // Gets the unqualified default immutable outer class name of a file
+  // (converted from the proto file's name).
+  std::string GetFileDefaultImmutableClassName(const FileDescriptor* file);
+
+  // Check whether there is any type defined in the proto file that has
+  // the given class name.
+  bool HasConflictingClassName(const FileDescriptor* file,
+                               const std::string& classname,
+                               NameEquality equality_mode);
+
+  // Gets the name of the outer class that holds descriptor information.
+  // Descriptors are shared between immutable messages and mutable messages.
+  // Since both of them are generated optionally, the descriptors need to be
+  // put in another common place.
+  std::string GetDescriptorClassName(const FileDescriptor* file);
+
+  // Gets the fully-qualified class name corresponding to the given descriptor.
+  std::string GetClassName(const Descriptor* descriptor, bool immutable);
+  std::string GetClassName(const Descriptor* descriptor, bool immutable,
+                           bool kotlin);
+  std::string GetClassName(const EnumDescriptor* descriptor, bool immutable);
+  std::string GetClassName(const EnumDescriptor* descriptor, bool immutable,
+                           bool kotlin);
+  std::string GetClassName(const ServiceDescriptor* descriptor, bool immutable);
+  std::string GetClassName(const ServiceDescriptor* descriptor, bool immutable,
+                           bool kotlin);
+  std::string GetClassName(const FileDescriptor* descriptor, bool immutable);
+  std::string GetClassName(const FileDescriptor* descriptor, bool immutable,
+                           bool kotlin);
+
+  template <class DescriptorType>
+  std::string GetImmutableClassName(const DescriptorType* descriptor) {
+    return GetClassName(descriptor, true);
+  }
+  template <class DescriptorType>
+  std::string GetMutableClassName(const DescriptorType* descriptor) {
+    return GetClassName(descriptor, false);
+  }
+
+  // Gets the fully qualified name of an extension identifier.
+  std::string GetExtensionIdentifierName(const FieldDescriptor* descriptor,
+                                         bool immutable);
+  std::string GetExtensionIdentifierName(const FieldDescriptor* descriptor,
+                                         bool immutable, bool kotlin);
+
+  // Gets the fully qualified name for generated classes in Java convention.
+  // Nested classes will be separated using '$' instead of '.'
+  // For example:
+  //   com.package.OuterClass$OuterMessage$InnerMessage
+  std::string GetJavaImmutableClassName(const Descriptor* descriptor);
+  std::string GetJavaImmutableClassName(const EnumDescriptor* descriptor);
+  std::string GetKotlinFactoryName(const Descriptor* descriptor);
+  std::string GetKotlinExtensionsClassName(const Descriptor* descriptor);
+  std::string GetJavaMutableClassName(const Descriptor* descriptor);
+  std::string GetJavaMutableClassName(const EnumDescriptor* descriptor);
+  // Gets the outer class and the actual class for downgraded mutable messages.
+  std::string GetDowngradedFileClassName(const FileDescriptor* file);
+  std::string GetDowngradedClassName(const Descriptor* descriptor);
+
+  // Get the full name of a Java class by prepending the Java package name
+  // or outer class name.
+  std::string GetClassFullName(const std::string& name_without_package,
+                               const FileDescriptor* file, bool immutable,
+                               bool is_own_file);
+  std::string GetClassFullName(const std::string& name_without_package,
+                               const FileDescriptor* file, bool immutable,
+                               bool is_own_file, bool kotlin);
+
+ private:
+  // Get the Java Class style full name of a message.
+  std::string GetJavaClassFullName(const std::string& name_without_package,
+                                   const FileDescriptor* file, bool immutable);
+  std::string GetJavaClassFullName(const std::string& name_without_package,
+                                   const FileDescriptor* file, bool immutable,
+                                   bool kotlin);
+  // Caches the result to provide better performance.
+  std::map<const FileDescriptor*, std::string>
+      file_immutable_outer_class_names_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ClassNameResolver);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__
diff --git a/src/google/protobuf/compiler/java/names.h b/src/google/protobuf/compiler/java/names.h
new file mode 100644
index 0000000..313ace4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/names.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Provides a mechanism for mapping a descriptor to the
+// fully-qualified name of the corresponding Java class.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FileDescriptor;
+class FieldDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace java {
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+std::string ClassName(const Descriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+std::string ClassName(const EnumDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+std::string ClassName(const FileDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+std::string ClassName(const ServiceDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   Java package name.
+std::string FileJavaPackage(const FileDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+// Returns:
+//   Capitalized camel case name field name.
+std::string CapitalizedFieldName(const FieldDescriptor* descriptor);
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
diff --git a/src/google/protobuf/compiler/java/options.h b/src/google/protobuf/compiler/java/options.h
new file mode 100644
index 0000000..6c29be1
--- /dev/null
+++ b/src/google/protobuf/compiler/java/options.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_JAVA_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generator options
+struct Options {
+  Options()
+      : generate_immutable_code(false),
+        generate_mutable_code(false),
+        generate_shared_code(false),
+        enforce_lite(false),
+        annotate_code(false) {
+  }
+
+  bool generate_immutable_code;
+  bool generate_mutable_code;
+  bool generate_shared_code;
+  // When set, the protoc will generate the current files and all the transitive
+  // dependencies as lite runtime.
+  bool enforce_lite;
+  // If true, we should build .meta files and emit @Generated annotations into
+  // generated code.
+  bool annotate_code;
+  // Name of a file where we will write a list of generated .meta file names,
+  // one per line.
+  std::string annotation_list_file;
+  // Name of a file where we will write a list of generated file names, one
+  // per line.
+  std::string output_list_file;
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/java/plugin_unittest.cc b/src/google/protobuf/compiler/java/plugin_unittest.cc
new file mode 100644
index 0000000..8135f86
--- /dev/null
+++ b/src/google/protobuf/compiler/java/plugin_unittest.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <memory>
+#include <string>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/java/generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+namespace {
+
+class TestGenerator : public CodeGenerator {
+ public:
+  TestGenerator() {}
+  ~TestGenerator() override {}
+
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
+    std::string filename = "Test.java";
+    TryInsert(filename, "outer_class_scope", context);
+    TryInsert(filename, "class_scope:foo.Bar", context);
+    TryInsert(filename, "class_scope:foo.Bar.Baz", context);
+    TryInsert(filename, "builder_scope:foo.Bar", context);
+    TryInsert(filename, "builder_scope:foo.Bar.Baz", context);
+    TryInsert(filename, "enum_scope:foo.Qux", context);
+    return true;
+  }
+
+  void TryInsert(const std::string& filename,
+                 const std::string& insertion_point,
+                 GeneratorContext* context) const {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        context->OpenForInsert(filename, insertion_point));
+    io::Printer printer(output.get(), '$');
+    printer.Print("// inserted $name$\n", "name", insertion_point);
+  }
+};
+
+// This test verifies that all the expected insertion points exist.  It does
+// not verify that they are correctly-placed; that would require actually
+// compiling the output which is a bit more than I care to do for this test.
+TEST(JavaPluginTest, PluginTest) {
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
+                             "syntax = \"proto2\";\n"
+                             "package foo;\n"
+                             "option java_package = \"\";\n"
+                             "option java_outer_classname = \"Test\";\n"
+                             "message Bar {\n"
+                             "  message Baz {}\n"
+                             "}\n"
+                             "enum Qux { BLAH = 1; }\n",
+                             true));
+
+  CommandLineInterface cli;
+  cli.SetInputsAreProtoPathRelative(true);
+
+  JavaGenerator java_generator;
+  TestGenerator test_generator;
+  cli.RegisterGenerator("--java_out", &java_generator, "");
+  cli.RegisterGenerator("--test_out", &test_generator, "");
+
+  std::string proto_path = "-I" + TestTempDir();
+  std::string java_out = "--java_out=" + TestTempDir();
+  std::string test_out = "--test_out=" + TestTempDir();
+
+  const char* argv[] = {"protoc", proto_path.c_str(), java_out.c_str(),
+                        test_out.c_str(), "test.proto"};
+
+  EXPECT_EQ(0, cli.Run(5, argv));
+
+  // Loop over the lines of the generated code and verify that we find what we
+  // expect
+
+  std::string output;
+  GOOGLE_CHECK_OK(File::GetContents(TestTempDir() + "/Test.java", &output,
+                             true));
+  std::vector<std::string> lines = Split(output, "\n");
+  bool found_generated_annotation = false;
+  bool found_do_not_edit = false;
+  for (const auto& line : lines) {
+    if (line.find(" DO NOT EDIT!") != std::string::npos) {
+      found_do_not_edit = true;
+    }
+    if (line.find("@com.google.protobuf.Generated") != std::string::npos) {
+      found_generated_annotation = true;
+    }
+  }
+  EXPECT_TRUE(found_do_not_edit);
+  (void)found_generated_annotation;
+}
+
+}  // namespace
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/primitive_field.cc b/src/google/protobuf/compiler/java/primitive_field.cc
new file mode 100644
index 0000000..6ed47d7
--- /dev/null
+++ b/src/google/protobuf/compiler/java/primitive_field.cc
@@ -0,0 +1,1091 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/primitive_field.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex, int builderBitIndex,
+                           const FieldGeneratorInfo* info,
+                           ClassNameResolver* name_resolver,
+                           std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+  JavaType javaType = GetJavaType(descriptor);
+
+  (*variables)["type"] = PrimitiveTypeName(javaType);
+  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
+  (*variables)["kt_type"] = KotlinTypeName(javaType);
+  (*variables)["field_type"] = (*variables)["type"];
+
+  if (javaType == JAVATYPE_BOOLEAN || javaType == JAVATYPE_DOUBLE ||
+      javaType == JAVATYPE_FLOAT || javaType == JAVATYPE_INT ||
+      javaType == JAVATYPE_LONG) {
+    std::string capitalized_type = UnderscoresToCamelCase(
+        PrimitiveTypeName(javaType), /*cap_first_letter=*/true);
+    (*variables)["field_list_type"] =
+        "com.google.protobuf.Internal." + capitalized_type + "List";
+    (*variables)["empty_list"] = "empty" + capitalized_type + "List()";
+    (*variables)["create_list"] = "new" + capitalized_type + "List()";
+    (*variables)["mutable_copy_list"] =
+        "mutableCopy(" + (*variables)["name"] + "_)";
+    (*variables)["name_make_immutable"] =
+        (*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;
+  } else {
+    (*variables)["field_list_type"] =
+        "java.util.List<" + (*variables)["boxed_type"] + ">";
+    (*variables)["create_list"] =
+        "new java.util.ArrayList<" + (*variables)["boxed_type"] + ">()";
+    (*variables)["mutable_copy_list"] = "new java.util.ArrayList<" +
+                                        (*variables)["boxed_type"] + ">(" +
+                                        (*variables)["name"] + "_)";
+    (*variables)["empty_list"] = "java.util.Collections.emptyList()";
+    (*variables)["name_make_immutable"] =
+        (*variables)["name"] + "_ = java.util.Collections.unmodifiableList(" +
+        (*variables)["name"] + "_)";
+    (*variables)["repeated_get"] = (*variables)["name"] + "_.get";
+    (*variables)["repeated_add"] = (*variables)["name"] + "_.add";
+    (*variables)["repeated_set"] = (*variables)["name"] + "_.set";
+  }
+
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_init"] =
+      IsDefaultValueJavaDefault(descriptor)
+          ? ""
+          : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
+  (*variables)["capitalized_type"] =
+      GetCapitalizedType(descriptor, /* immutable = */ true);
+  (*variables)["tag"] =
+      StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor)));
+  (*variables)["tag_size"] = StrCat(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  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 " : "";
+  (*variables)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  int fixed_size = FixedSize(GetType(descriptor));
+  if (fixed_size != -1) {
+    (*variables)["fixed_size"] = StrCat(fixed_size);
+  }
+  (*variables)["on_changed"] = "onChanged();";
+
+  if (HasHasbit(descriptor)) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+    (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["set_has_field_bit_builder"] =
+        GenerateSetBit(builderBitIndex) + ";";
+    (*variables)["clear_has_field_bit_builder"] =
+        GenerateClearBit(builderBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["set_has_field_bit_builder"] = "";
+    (*variables)["clear_has_field_bit_builder"] = "";
+
+    switch (descriptor->type()) {
+      case FieldDescriptor::TYPE_BYTES:
+        (*variables)["is_field_present_message"] =
+            "!" + (*variables)["name"] + "_.isEmpty()";
+        break;
+      case FieldDescriptor::TYPE_FLOAT:
+        (*variables)["is_field_present_message"] =
+            "java.lang.Float.floatToRawIntBits(" + (*variables)["name"] +
+            "_) != 0";
+        break;
+      case FieldDescriptor::TYPE_DOUBLE:
+        (*variables)["is_field_present_message"] =
+            "java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] +
+            "_) != 0";
+        break;
+      default:
+        (*variables)["is_field_present_message"] =
+            (*variables)["name"] + "_ != " + (*variables)["default"];
+        break;
+    }
+  }
+
+  // For repeated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutablePrimitiveFieldGenerator::ImmutablePrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() {}
+
+int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+int ImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const {
+  return GetNumBitsForMessage();
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private $field_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return $name$_;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_builder$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return $name$_;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "$null_check$"
+                 "  $set_has_field_bit_builder$\n"
+                 "  $name$_ = value;\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  $clear_has_field_bit_builder$\n");
+  printer->Annotate("{", "}", descriptor_);
+  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_,
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: $kt_type$\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+        "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+        "}\n");
+  }
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateFieldBuilderInitializationCode(
+    io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  if (!IsDefaultValueJavaDefault(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $default$;\n");
+  }
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = $default$;\n"
+                 "$clear_has_field_bit_builder$\n");
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    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 ImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    if (IsDefaultValueJavaDefault(descriptor_)) {
+      printer->Print(variables_,
+                     "if ($get_has_field_bit_from_local$) {\n"
+                     "  result.$name$_ = $name$_;\n"
+                     "  $set_has_field_bit_to_local$;\n"
+                     "}\n");
+    } else {
+      printer->Print(variables_,
+                     "if ($get_has_field_bit_from_local$) {\n"
+                     "  $set_has_field_bit_to_local$;\n"
+                     "}\n"
+                     "result.$name$_ = $name$_;\n");
+    }
+  } else {
+    printer->Print(variables_, "result.$name$_ = $name$_;\n");
+  }
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = input.read$capitalized_type$();\n"
+                 "$set_has_field_bit_builder$\n");
+}
+
+void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($is_field_present_message$) {\n"
+                 "  output.write$capitalized_type$($number$, $name$_);\n"
+                 "}\n");
+}
+
+void ImmutablePrimitiveFieldGenerator::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 ImmutablePrimitiveFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  switch (GetJavaType(descriptor_)) {
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_BOOLEAN:
+      printer->Print(variables_,
+                     "if (get$capitalized_name$()\n"
+                     "    != other.get$capitalized_name$()) return false;\n");
+      break;
+
+    case JAVATYPE_FLOAT:
+      printer->Print(
+          variables_,
+          "if (java.lang.Float.floatToIntBits(get$capitalized_name$())\n"
+          "    != java.lang.Float.floatToIntBits(\n"
+          "        other.get$capitalized_name$())) return false;\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(
+          variables_,
+          "if (java.lang.Double.doubleToLongBits(get$capitalized_name$())\n"
+          "    != java.lang.Double.doubleToLongBits(\n"
+          "        other.get$capitalized_name$())) return false;\n");
+      break;
+
+    case JAVATYPE_STRING:
+    case JAVATYPE_BYTES:
+      printer->Print(
+          variables_,
+          "if (!get$capitalized_name$()\n"
+          "    .equals(other.get$capitalized_name$())) return false;\n");
+      break;
+
+    case JAVATYPE_ENUM:
+    case JAVATYPE_MESSAGE:
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      break;
+  }
+}
+
+void ImmutablePrimitiveFieldGenerator::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;
+  }
+}
+
+std::string ImmutablePrimitiveFieldGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+ImmutablePrimitiveOneofFieldGenerator::ImmutablePrimitiveOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : ImmutablePrimitiveFieldGenerator(descriptor, messageBitIndex,
+                                       builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutablePrimitiveOneofFieldGenerator::
+    ~ImmutablePrimitiveOneofFieldGenerator() {}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    return ($boxed_type$) $oneof_name$_;\n"
+                 "  }\n"
+                 "  return $default$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "$null_check$"
+                 "  $set_oneof_case_message$;\n"
+                 "  $oneof_name$_ = value;\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    $clear_oneof_case_message$;\n"
+      "    $oneof_name$_ = null;\n"
+      "    $on_changed$\n"
+      "  }\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  // No-Op: When a primitive field is in a oneof, clearing the oneof clears that
+  // field.
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  result.$oneof_name$_ = $oneof_name$_;\n"
+                 "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "set$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$oneof_name$_ = input.read$capitalized_type$();\n"
+                 "$set_oneof_case_message$;\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  output.write$capitalized_type$(\n");
+  // $type$ and $boxed_type$ is the same for bytes fields so we don't need to
+  // do redundant casts.
+  if (GetJavaType(descriptor_) == JAVATYPE_BYTES) {
+    printer->Print(variables_, "      $number$, ($type$) $oneof_name$_);\n");
+  } else {
+    printer->Print(
+        variables_,
+        "      $number$, ($type$)(($boxed_type$) $oneof_name$_));\n");
+  }
+  printer->Print("}\n");
+}
+
+void ImmutablePrimitiveOneofFieldGenerator::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");
+  // $type$ and $boxed_type$ is the same for bytes fields so we don't need to
+  // do redundant casts.
+  if (GetJavaType(descriptor_) == JAVATYPE_BYTES) {
+    printer->Print(variables_, "        $number$, ($type$) $oneof_name$_);\n");
+  } else {
+    printer->Print(
+        variables_,
+        "        $number$, ($type$)(($boxed_type$) $oneof_name$_));\n");
+  }
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutablePrimitiveFieldGenerator::
+    RepeatedImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                             int messageBitIndex,
+                                             int builderBitIndex,
+                                             Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutablePrimitiveFieldGenerator::
+    ~RepeatedImmutablePrimitiveFieldGenerator() {}
+
+int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$java.util.List<$boxed_type$> "
+                 "get$capitalized_name$List();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(variables_,
+                 "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$$type$ get$capitalized_name$(int index);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private $field_list_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<$boxed_type$>\n"
+                 "    ${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_;\n"  // note:  unmodifiable list
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $repeated_get$(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (descriptor_->is_packed()) {
+    printer->Print(variables_,
+                   "private int $name$MemoizedSerializedSize = -1;\n");
+  }
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  // One field is the list and the bit field keeps track of whether the
+  // list is immutable. If it's immutable, the invariant is that it must
+  // either an instance of Collections.emptyList() or it's an ArrayList
+  // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+  // a reference to the underlying ArrayList. This invariant allows us to
+  // share instances of lists between protocol buffers avoiding expensive
+  // memory allocations. Note, immutable is a strong guarantee here -- not
+  // just that the list cannot be modified via the reference but that the
+  // list can never be modified.
+  printer->Print(variables_,
+                 "private $field_list_type$ $name$_ = $empty_list$;\n");
+
+  printer->Print(variables_,
+                 "private void ensure$capitalized_name$IsMutable() {\n"
+                 "  if (!$get_mutable_bit_builder$) {\n"
+                 "    $name$_ = $mutable_copy_list$;\n"
+                 "    $set_mutable_bit_builder$;\n"
+                 "   }\n"
+                 "}\n");
+
+  // Note:  We return an unmodifiable list because otherwise the caller
+  //   could hold on to the returned list and modify it after the message
+  //   has been built, thus mutating the message which is supposed to be
+  //   immutable.
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$public java.util.List<$boxed_type$>\n"
+      "    ${$get$capitalized_name$List$}$() {\n"
+      "  return $get_mutable_bit_builder$ ?\n"
+      "           java.util.Collections.unmodifiableList($name$_) : $name$_;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $repeated_get$(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+                 "    int index, $type$ value) {\n"
+                 "$null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $repeated_set$(index, value);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$add$capitalized_name$$}$($type$ value) {\n"
+                 "$null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $repeated_add$(value);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n"
+                 "    java.lang.Iterable<? extends $boxed_type$> values) {\n"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
+                 "      values, $name$_);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  $name$_ = $empty_list$;\n"
+      "  $clear_mutable_bit_builder$;\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: $kt_type$) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: $kt_type$) {\n"
+                 "  add(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+                 "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+      "  addAll(values)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: $kt_type$) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::
+    GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = $empty_list$;\n"
+                 "$clear_mutable_bit_builder$;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::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"
+                 "    $clear_mutable_bit_builder$;\n"
+                 "  } else {\n"
+                 "    ensure$capitalized_name$IsMutable();\n"
+                 "    $name$_.addAll(other.$name$_);\n"
+                 "  }\n"
+                 "  $on_changed$\n"
+                 "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  // The code below ensures that the result has an immutable list. If our
+  // list is immutable, we can just reuse it. If not, we make it immutable.
+  printer->Print(variables_,
+                 "if ($get_mutable_bit_builder$) {\n"
+                 "  $name_make_immutable$;\n"
+                 "  $clear_mutable_bit_builder$;\n"
+                 "}\n"
+                 "result.$name$_ = $name$_;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$type$ v = input.read$capitalized_type$();\n"
+                 "ensure$capitalized_name$IsMutable();\n"
+                 "$repeated_add$(v);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::
+    GenerateBuilderParsingCodeFromPacked(io::Printer* printer) const {
+  printer->Print(variables_,
+                 "int length = input.readRawVarint32();\n"
+                 "int limit = input.pushLimit(length);\n"
+                 "ensure$capitalized_name$IsMutable();\n"
+                 "while (input.getBytesUntilLimit() > 0) {\n"
+                 "  $repeated_add$(input.read$capitalized_type$());\n"
+                 "}\n"
+                 "input.popLimit(limit);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  if (descriptor_->is_packed()) {
+    // We invoke getSerializedSize in writeTo for messages that have packed
+    // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+    // That makes it safe to rely on the memoized size here.
+    printer->Print(variables_,
+                   "if (get$capitalized_name$List().size() > 0) {\n"
+                   "  output.writeUInt32NoTag($tag$);\n"
+                   "  output.writeUInt32NoTag($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 RepeatedImmutablePrimitiveFieldGenerator::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_->is_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_->is_packed()) {
+    printer->Print(variables_, "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!get$capitalized_name$List()\n"
+      "    .equals(other.get$capitalized_name$List())) return false;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldGenerator::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");
+}
+
+std::string RepeatedImmutablePrimitiveFieldGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/primitive_field.h b/src/google/protobuf/compiler/java/primitive_field.h
new file mode 100644
index 0000000..d3a6c2a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/primitive_field.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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit ImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                            int messageBitIndex,
+                                            int builderBitIndex,
+                                            Context* context);
+  ~ImmutablePrimitiveFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator
+  // ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldGenerator);
+};
+
+class ImmutablePrimitiveOneofFieldGenerator
+    : public ImmutablePrimitiveFieldGenerator {
+ public:
+  ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                        int messageBitIndex,
+                                        int builderBitIndex, Context* context);
+  ~ImmutablePrimitiveOneofFieldGenerator() override;
+
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldGenerator);
+};
+
+class RepeatedImmutablePrimitiveFieldGenerator
+    : public ImmutableFieldGenerator {
+ public:
+  explicit RepeatedImmutablePrimitiveFieldGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutablePrimitiveFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCodeFromPacked(
+      io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/primitive_field_lite.cc b/src/google/protobuf/compiler/java/primitive_field_lite.cc
new file mode 100644
index 0000000..e323fef
--- /dev/null
+++ b/src/google/protobuf/compiler/java/primitive_field_lite.cc
@@ -0,0 +1,778 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/primitive_field_lite.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+bool EnableExperimentalRuntimeForLite() {
+#ifdef PROTOBUF_EXPERIMENT
+  return PROTOBUF_EXPERIMENT;
+#else   // PROTOBUF_EXPERIMENT
+  return false;
+#endif  // !PROTOBUF_EXPERIMENT
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex, int builderBitIndex,
+                           const FieldGeneratorInfo* info,
+                           ClassNameResolver* name_resolver,
+                           std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+  JavaType javaType = GetJavaType(descriptor);
+  (*variables)["type"] = PrimitiveTypeName(javaType);
+  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
+  (*variables)["kt_type"] = KotlinTypeName(javaType);
+  (*variables)["field_type"] = (*variables)["type"];
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["capitalized_type"] =
+      GetCapitalizedType(descriptor, /* immutable = */ true);
+  (*variables)["tag"] =
+      StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor)));
+  (*variables)["tag_size"] = StrCat(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  (*variables)["required"] = descriptor->is_required() ? "true" : "false";
+
+  std::string capitalized_type = UnderscoresToCamelCase(
+      PrimitiveTypeName(javaType), true /* cap_next_letter */);
+  switch (javaType) {
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_FLOAT:
+    case JAVATYPE_DOUBLE:
+    case JAVATYPE_BOOLEAN:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal." + capitalized_type + "List";
+      (*variables)["empty_list"] = "empty" + capitalized_type + "List()";
+      (*variables)["make_name_unmodifiable"] =
+          (*variables)["name"] + "_.makeImmutable()";
+      (*variables)["repeated_get"] =
+          (*variables)["name"] + "_.get" + capitalized_type;
+      (*variables)["repeated_add"] =
+          (*variables)["name"] + "_.add" + capitalized_type;
+      (*variables)["repeated_set"] =
+          (*variables)["name"] + "_.set" + capitalized_type;
+      (*variables)["visit_type"] = capitalized_type;
+      (*variables)["visit_type_list"] = "visit" + capitalized_type + "List";
+      break;
+    default:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal.ProtobufList<" +
+          (*variables)["boxed_type"] + ">";
+      (*variables)["empty_list"] = "emptyProtobufList()";
+      (*variables)["make_name_unmodifiable"] =
+          (*variables)["name"] + "_.makeImmutable()";
+      (*variables)["repeated_get"] = (*variables)["name"] + "_.get";
+      (*variables)["repeated_add"] = (*variables)["name"] + "_.add";
+      (*variables)["repeated_set"] = (*variables)["name"] + "_.set";
+      (*variables)["visit_type"] = "ByteString";
+      (*variables)["visit_type_list"] = "visitList";
+  }
+
+  if (javaType == JAVATYPE_BYTES) {
+    (*variables)["bytes_default"] =
+        ToUpper((*variables)["name"]) + "_DEFAULT_VALUE";
+  }
+
+  if (IsReferenceType(javaType)) {
+    // We use `x.getClass()` as a null check because it generates less bytecode
+    // than an `if (x == null) { throw ... }` statement.
+    (*variables)["null_check"] =
+        "  java.lang.Class<?> valueClass = value.getClass();\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 " : "";
+  (*variables)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  int fixed_size = FixedSize(GetType(descriptor));
+  if (fixed_size != -1) {
+    (*variables)["fixed_size"] = StrCat(fixed_size);
+  }
+
+  if (HasHasbit(descriptor)) {
+    // 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"] = "";
+
+    switch (descriptor->type()) {
+      case FieldDescriptor::TYPE_BYTES:
+        (*variables)["is_field_present_message"] =
+            "!" + (*variables)["name"] + "_.isEmpty()";
+        break;
+      case FieldDescriptor::TYPE_FLOAT:
+        (*variables)["is_field_present_message"] =
+            "java.lang.Float.floatToRawIntBits(" + (*variables)["name"] +
+            "_) != 0";
+        break;
+      case FieldDescriptor::TYPE_DOUBLE:
+        (*variables)["is_field_present_message"] =
+            "java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] +
+            "_) != 0";
+        break;
+      default:
+        (*variables)["is_field_present_message"] =
+            (*variables)["name"] + "_ != " + (*variables)["default"];
+        break;
+    }
+  }
+
+  (*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, Context* context)
+    : descriptor_(descriptor),
+      messageBitIndex_(messageBitIndex),
+      name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, 0,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  if (IsByteStringWithCustomDefaultValue(descriptor_)) {
+    // allocate this once statically since we know ByteStrings are immutable
+    // values that can be reused.
+    printer->Print(
+        variables_,
+        "private static final $field_type$ $bytes_default$ = $default$;\n");
+  }
+  printer->Print(variables_, "private $field_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return $name$_;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$($type$ value) {\n"
+                 "$null_check$"
+                 "  $set_has_field_bit_message$\n"
+                 "  $name$_ = value;\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  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 (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return instance.has$capitalized_name$();\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return instance.get$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.set$capitalized_name$(value);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: $kt_type$\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+        "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+        "}\n");
+  }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  if (HasHasbit(descriptor_)) {
+    WriteIntToUtf16CharSequence(messageBitIndex_, output);
+  }
+  printer->Print(variables_, "\"$name$_\",\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  if (IsByteStringWithCustomDefaultValue(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $bytes_default$;\n");
+  } else if (!IsDefaultValueJavaDefault(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $default$;\n");
+  }
+}
+
+std::string ImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+    ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                              int messageBitIndex,
+                                              Context* context)
+    : ImmutablePrimitiveFieldLiteGenerator(descriptor, messageBitIndex,
+                                           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);
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    return ($boxed_type$) $oneof_name$_;\n"
+                 "  }\n"
+                 "  return $default$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$($type$ value) {\n"
+                 "$null_check$"
+                 "  $set_oneof_case_message$;\n"
+                 "  $oneof_name$_ = value;\n"
+                 "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  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::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output);
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return instance.has$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
+                 "  return instance.get$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$set$capitalized_name$$}$($type$ value) {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.set$capitalized_name$(value);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+// ===================================================================
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+    RepeatedImmutablePrimitiveFieldLiteGenerator(
+        const FieldDescriptor* descriptor, int messageBitIndex,
+        Context* context)
+    : descriptor_(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, 0,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+    ~RepeatedImmutablePrimitiveFieldLiteGenerator() {}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$java.util.List<$boxed_type$> "
+                 "get$capitalized_name$List();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(variables_,
+                 "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  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);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<$boxed_type$>\n"
+                 "    ${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_;\n"  // note:  unmodifiable list
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return $repeated_get$(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  if (!EnableExperimentalRuntimeForLite() && descriptor_->is_packed() &&
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+                   "private int $name$MemoizedSerializedSize = -1;\n");
+  }
+
+  printer->Print(
+      variables_,
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  $field_list_type$ tmp = $name$_;\n"
+      "  if (!tmp.isModifiable()) {\n"
+      "    $name$_ =\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
+      "   }\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER);
+  printer->Print(variables_,
+                 "private void add$capitalized_name$($type$ value) {\n"
+                 "$null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $repeated_add$(value);\n"
+                 "}\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  printer->Print(variables_,
+                 "private void clear$capitalized_name$() {\n"
+                 "  $name$_ = $empty_list$;\n"
+                 "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return instance.get$capitalized_name$Count();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
+      "  return instance.get$capitalized_name$(index);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder "
+                 "${$add$capitalized_name$$}$($type$ value) {\n"
+                 "  copyOnWrite();\n"
+                 "  instance.add$capitalized_name$(value);\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: $kt_type$) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: $kt_type$) {\n"
+                 "  add(value)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+                 "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+                 "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+      "  addAll(values)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: $kt_type$) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  printer->Print(variables_, "\"$name$_\",\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+std::string RepeatedImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/primitive_field_lite.h b/src/google/protobuf/compiler/java/primitive_field_lite.h
new file mode 100644
index 0000000..2da0cd8
--- /dev/null
+++ b/src/google/protobuf/compiler/java/primitive_field_lite.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.
+
+// 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 <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutablePrimitiveFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutablePrimitiveFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex, Context* context);
+  ~ImmutablePrimitiveFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator
+  // ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  const int messageBitIndex_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldLiteGenerator);
+};
+
+class ImmutablePrimitiveOneofFieldLiteGenerator
+    : public ImmutablePrimitiveFieldLiteGenerator {
+ public:
+  ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                            int messageBitIndex,
+                                            Context* context);
+  ~ImmutablePrimitiveOneofFieldLiteGenerator() override;
+
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutablePrimitiveFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutablePrimitiveFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex, Context* context);
+  ~RepeatedImmutablePrimitiveFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  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/service.cc b/src/google/protobuf/compiler/java/service.cc
new file mode 100644
index 0000000..9e20620
--- /dev/null
+++ b/src/google/protobuf/compiler/java/service.cc
@@ -0,0 +1,479 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/java/service.h>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
+    : descriptor_(descriptor) {}
+
+ServiceGenerator::~ServiceGenerator() {}
+
+// ===================================================================
+ImmutableServiceGenerator::ImmutableServiceGenerator(
+    const ServiceDescriptor* descriptor, Context* context)
+    : ServiceGenerator(descriptor),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {}
+
+ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
+
+void ImmutableServiceGenerator::Generate(io::Printer* printer) {
+  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
+  WriteServiceDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true);
+  printer->Print(
+      "public $static$ abstract class $classname$\n"
+      "    implements com.google.protobuf.Service {\n",
+      "static", is_own_file ? "" : "static", "classname", descriptor_->name());
+  printer->Indent();
+
+  printer->Print("protected $classname$() {}\n\n", "classname",
+                 descriptor_->name());
+
+  GenerateInterface(printer);
+
+  GenerateNewReflectiveServiceMethod(printer);
+  GenerateNewReflectiveBlockingServiceMethod(printer);
+
+  GenerateAbstractMethods(printer);
+
+  // Generate getDescriptor() and getDescriptorForType().
+  printer->Print(
+      "public static final\n"
+      "    com.google.protobuf.Descriptors.ServiceDescriptor\n"
+      "    getDescriptor() {\n"
+      "  return $file$.getDescriptor().getServices().get($index$);\n"
+      "}\n",
+      "file", name_resolver_->GetImmutableClassName(descriptor_->file()),
+      "index", StrCat(descriptor_->index()));
+  GenerateGetDescriptorForType(printer);
+
+  // Generate more stuff.
+  GenerateCallMethod(printer);
+  GenerateGetPrototype(REQUEST, printer);
+  GenerateGetPrototype(RESPONSE, printer);
+  GenerateStub(printer);
+  GenerateBlockingStub(printer);
+
+  // Add an insertion point.
+  printer->Print(
+      "\n"
+      "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+      "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void ImmutableServiceGenerator::GenerateGetDescriptorForType(
+    io::Printer* printer) {
+  printer->Print(
+      "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
+      "    getDescriptorForType() {\n"
+      "  return getDescriptor();\n"
+      "}\n");
+}
+
+void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) {
+  printer->Print("public interface Interface {\n");
+  printer->Indent();
+  GenerateAbstractMethods(printer);
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod(
+    io::Printer* printer) {
+  printer->Print(
+      "public static com.google.protobuf.Service newReflectiveService(\n"
+      "    final Interface impl) {\n"
+      "  return new $classname$() {\n",
+      "classname", descriptor_->name());
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    printer->Print("@java.lang.Override\n");
+    GenerateMethodSignature(printer, method, IS_CONCRETE);
+    printer->Print(
+        " {\n"
+        "  impl.$method$(controller, request, done);\n"
+        "}\n\n",
+        "method", UnderscoresToCamelCase(method));
+  }
+
+  printer->Outdent();
+  printer->Print("};\n");
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
+    io::Printer* printer) {
+  printer->Print(
+      "public static com.google.protobuf.BlockingService\n"
+      "    newReflectiveBlockingService(final BlockingInterface impl) {\n"
+      "  return new com.google.protobuf.BlockingService() {\n");
+  printer->Indent();
+  printer->Indent();
+
+  GenerateGetDescriptorForType(printer);
+
+  GenerateCallBlockingMethod(printer);
+  GenerateGetPrototype(REQUEST, printer);
+  GenerateGetPrototype(RESPONSE, printer);
+
+  printer->Outdent();
+  printer->Print("};\n");
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    WriteMethodDocComment(printer, method);
+    GenerateMethodSignature(printer, method, IS_ABSTRACT);
+    printer->Print(";\n\n");
+  }
+}
+
+std::string ImmutableServiceGenerator::GetOutput(
+    const MethodDescriptor* method) {
+  return name_resolver_->GetImmutableClassName(method->output_type());
+}
+
+void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) {
+  printer->Print(
+      "\n"
+      "public final void callMethod(\n"
+      "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
+      "    com.google.protobuf.RpcController controller,\n"
+      "    com.google.protobuf.Message request,\n"
+      "    com.google.protobuf.RpcCallback<\n"
+      "      com.google.protobuf.Message> done) {\n"
+      "  if (method.getService() != getDescriptor()) {\n"
+      "    throw new java.lang.IllegalArgumentException(\n"
+      "      \"Service.callMethod() given method descriptor for wrong \" +\n"
+      "      \"service type.\");\n"
+      "  }\n"
+      "  switch(method.getIndex()) {\n");
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    std::map<std::string, std::string> vars;
+    vars["index"] = StrCat(i);
+    vars["method"] = UnderscoresToCamelCase(method);
+    vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
+    vars["output"] = GetOutput(method);
+    printer->Print(
+        vars,
+        "case $index$:\n"
+        "  this.$method$(controller, ($input$)request,\n"
+        "    com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n"
+        "      done));\n"
+        "  return;\n");
+  }
+
+  printer->Print(
+      "default:\n"
+      "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
+
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+      "  }\n"
+      "}\n"
+      "\n");
+}
+
+void ImmutableServiceGenerator::GenerateCallBlockingMethod(
+    io::Printer* printer) {
+  printer->Print(
+      "\n"
+      "public final com.google.protobuf.Message callBlockingMethod(\n"
+      "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
+      "    com.google.protobuf.RpcController controller,\n"
+      "    com.google.protobuf.Message request)\n"
+      "    throws com.google.protobuf.ServiceException {\n"
+      "  if (method.getService() != getDescriptor()) {\n"
+      "    throw new java.lang.IllegalArgumentException(\n"
+      "      \"Service.callBlockingMethod() given method descriptor for \" +\n"
+      "      \"wrong service type.\");\n"
+      "  }\n"
+      "  switch(method.getIndex()) {\n");
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    std::map<std::string, std::string> vars;
+    vars["index"] = StrCat(i);
+    vars["method"] = UnderscoresToCamelCase(method);
+    vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
+    vars["output"] = GetOutput(method);
+    printer->Print(vars,
+                   "case $index$:\n"
+                   "  return impl.$method$(controller, ($input$)request);\n");
+  }
+
+  printer->Print(
+      "default:\n"
+      "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
+
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+      "  }\n"
+      "}\n"
+      "\n");
+}
+
+void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
+                                                     io::Printer* printer) {
+  /*
+   * TODO(cpovirk): The exception message says "Service.foo" when it may be
+   * "BlockingService.foo."  Consider fixing.
+   */
+  printer->Print(
+      "public final com.google.protobuf.Message\n"
+      "    get$request_or_response$Prototype(\n"
+      "    com.google.protobuf.Descriptors.MethodDescriptor method) {\n"
+      "  if (method.getService() != getDescriptor()) {\n"
+      "    throw new java.lang.IllegalArgumentException(\n"
+      "      \"Service.get$request_or_response$Prototype() given method \" +\n"
+      "      \"descriptor for wrong service type.\");\n"
+      "  }\n"
+      "  switch(method.getIndex()) {\n",
+      "request_or_response", (which == REQUEST) ? "Request" : "Response");
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    std::map<std::string, std::string> vars;
+    vars["index"] = StrCat(i);
+    vars["type"] =
+        (which == REQUEST)
+            ? name_resolver_->GetImmutableClassName(method->input_type())
+            : GetOutput(method);
+    printer->Print(vars,
+                   "case $index$:\n"
+                   "  return $type$.getDefaultInstance();\n");
+  }
+
+  printer->Print(
+      "default:\n"
+      "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
+
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+      "  }\n"
+      "}\n"
+      "\n");
+}
+
+void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) {
+  printer->Print(
+      "public static Stub newStub(\n"
+      "    com.google.protobuf.RpcChannel channel) {\n"
+      "  return new Stub(channel);\n"
+      "}\n"
+      "\n"
+      "public static final class Stub extends $classname$ implements Interface "
+      "{"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  printer->Indent();
+
+  printer->Print(
+      "private Stub(com.google.protobuf.RpcChannel channel) {\n"
+      "  this.channel = channel;\n"
+      "}\n"
+      "\n"
+      "private final com.google.protobuf.RpcChannel channel;\n"
+      "\n"
+      "public com.google.protobuf.RpcChannel getChannel() {\n"
+      "  return channel;\n"
+      "}\n");
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    printer->Print("\n");
+    GenerateMethodSignature(printer, method, IS_CONCRETE);
+    printer->Print(" {\n");
+    printer->Indent();
+
+    std::map<std::string, std::string> vars;
+    vars["index"] = StrCat(i);
+    vars["output"] = GetOutput(method);
+    printer->Print(vars,
+                   "channel.callMethod(\n"
+                   "  getDescriptor().getMethods().get($index$),\n"
+                   "  controller,\n"
+                   "  request,\n"
+                   "  $output$.getDefaultInstance(),\n"
+                   "  com.google.protobuf.RpcUtil.generalizeCallback(\n"
+                   "    done,\n"
+                   "    $output$.class,\n"
+                   "    $output$.getDefaultInstance()));\n");
+
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+      "}\n"
+      "\n");
+}
+
+void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
+  printer->Print(
+      "public static BlockingInterface newBlockingStub(\n"
+      "    com.google.protobuf.BlockingRpcChannel channel) {\n"
+      "  return new BlockingStub(channel);\n"
+      "}\n"
+      "\n");
+
+  printer->Print("public interface BlockingInterface {");
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    GenerateBlockingMethodSignature(printer, method);
+    printer->Print(";\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+      "}\n"
+      "\n");
+
+  printer->Print(
+      "private static final class BlockingStub implements BlockingInterface "
+      "{\n");
+  printer->Indent();
+
+  printer->Print(
+      "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
+      "  this.channel = channel;\n"
+      "}\n"
+      "\n"
+      "private final com.google.protobuf.BlockingRpcChannel channel;\n");
+
+  for (int i = 0; i < descriptor_->method_count(); i++) {
+    const MethodDescriptor* method = descriptor_->method(i);
+    GenerateBlockingMethodSignature(printer, method);
+    printer->Print(" {\n");
+    printer->Indent();
+
+    std::map<std::string, std::string> vars;
+    vars["index"] = StrCat(i);
+    vars["output"] = GetOutput(method);
+    printer->Print(vars,
+                   "return ($output$) channel.callBlockingMethod(\n"
+                   "  getDescriptor().getMethods().get($index$),\n"
+                   "  controller,\n"
+                   "  request,\n"
+                   "  $output$.getDefaultInstance());\n");
+
+    printer->Outdent();
+    printer->Print(
+        "}\n"
+        "\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void ImmutableServiceGenerator::GenerateMethodSignature(
+    io::Printer* printer, const MethodDescriptor* method,
+    IsAbstract is_abstract) {
+  std::map<std::string, std::string> vars;
+  vars["name"] = UnderscoresToCamelCase(method);
+  vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
+  vars["output"] = GetOutput(method);
+  vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
+  printer->Print(vars,
+                 "public $abstract$ void $name$(\n"
+                 "    com.google.protobuf.RpcController controller,\n"
+                 "    $input$ request,\n"
+                 "    com.google.protobuf.RpcCallback<$output$> done)");
+}
+
+void ImmutableServiceGenerator::GenerateBlockingMethodSignature(
+    io::Printer* printer, const MethodDescriptor* method) {
+  std::map<std::string, std::string> vars;
+  vars["method"] = UnderscoresToCamelCase(method);
+  vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
+  vars["output"] = GetOutput(method);
+  printer->Print(vars,
+                 "\n"
+                 "public $output$ $method$(\n"
+                 "    com.google.protobuf.RpcController controller,\n"
+                 "    $input$ request)\n"
+                 "    throws com.google.protobuf.ServiceException");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/java/service.h b/src/google/protobuf/compiler/java/service.h
new file mode 100644
index 0000000..9cb9021
--- /dev/null
+++ b/src/google/protobuf/compiler/java/service.h
@@ -0,0 +1,139 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_SERVICE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_SERVICE_H__
+
+#include <map>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ServiceGenerator {
+ public:
+  explicit ServiceGenerator(const ServiceDescriptor* descriptor);
+  virtual ~ServiceGenerator();
+
+  virtual void Generate(io::Printer* printer) = 0;
+
+  enum RequestOrResponse { REQUEST, RESPONSE };
+  enum IsAbstract { IS_ABSTRACT, IS_CONCRETE };
+
+ protected:
+  const ServiceDescriptor* descriptor_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
+};
+
+class ImmutableServiceGenerator : public ServiceGenerator {
+ public:
+  ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
+                            Context* context);
+  ~ImmutableServiceGenerator() override;
+
+  void Generate(io::Printer* printer) override;
+
+ private:
+  // Generate the getDescriptorForType() method.
+  void GenerateGetDescriptorForType(io::Printer* printer);
+
+  // Generate a Java interface for the service.
+  void GenerateInterface(io::Printer* printer);
+
+  // Generate newReflectiveService() method.
+  void GenerateNewReflectiveServiceMethod(io::Printer* printer);
+
+  // Generate newReflectiveBlockingService() method.
+  void GenerateNewReflectiveBlockingServiceMethod(io::Printer* printer);
+
+  // Generate abstract method declarations for all methods.
+  void GenerateAbstractMethods(io::Printer* printer);
+
+  // Generate the implementation of Service.callMethod().
+  void GenerateCallMethod(io::Printer* printer);
+
+  // Generate the implementation of BlockingService.callBlockingMethod().
+  void GenerateCallBlockingMethod(io::Printer* printer);
+
+  // Generate the implementations of Service.get{Request,Response}Prototype().
+  void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
+
+  // Generate a stub implementation of the service.
+  void GenerateStub(io::Printer* printer);
+
+  // Generate a method signature, possibly abstract, without body or trailing
+  // semicolon.
+  void GenerateMethodSignature(io::Printer* printer,
+                               const MethodDescriptor* method,
+                               IsAbstract is_abstract);
+
+  // Generate a blocking stub interface and implementation of the service.
+  void GenerateBlockingStub(io::Printer* printer);
+
+  // Generate the method signature for one method of a blocking stub.
+  void GenerateBlockingMethodSignature(io::Printer* printer,
+                                       const MethodDescriptor* method);
+
+  // Return the output type of the method.
+  std::string GetOutput(const MethodDescriptor* method);
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableServiceGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // NET_PROTO2_COMPILER_JAVA_SERVICE_H__
diff --git a/src/google/protobuf/compiler/java/shared_code_generator.cc b/src/google/protobuf/compiler/java/shared_code_generator.cc
new file mode 100644
index 0000000..39b96ee
--- /dev/null
+++ b/src/google/protobuf/compiler/java/shared_code_generator.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.
+
+// Author: xiaofeng@google.com (Feng Xiao)
+
+#include <google/protobuf/compiler/java/shared_code_generator.h>
+
+#include <memory>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.h>
+#include <google/protobuf/compiler/java/names.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file,
+                                         const Options& options)
+    : name_resolver_(new ClassNameResolver), file_(file), options_(options) {}
+
+SharedCodeGenerator::~SharedCodeGenerator() {}
+
+void SharedCodeGenerator::Generate(
+    GeneratorContext* context, std::vector<std::string>* file_list,
+    std::vector<std::string>* annotation_file_list) {
+  std::string java_package = FileJavaPackage(file_);
+  std::string package_dir = JavaPackageToDir(java_package);
+
+  if (HasDescriptorMethods(file_, options_.enforce_lite)) {
+    // Generate descriptors.
+    std::string classname = name_resolver_->GetDescriptorClassName(file_);
+    std::string filename = package_dir + classname + ".java";
+    file_list->push_back(filename);
+    std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    std::unique_ptr<io::Printer> printer(
+        new io::Printer(output.get(), '$',
+                        options_.annotate_code ? &annotation_collector : NULL));
+    std::string info_relative_path = classname + ".java.pb.meta";
+    std::string info_full_path = filename + ".pb.meta";
+    printer->Print(
+        "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+        "// source: $filename$\n"
+        "\n",
+        "filename", file_->name());
+    if (!java_package.empty()) {
+      printer->Print(
+          "package $package$;\n"
+          "\n",
+          "package", java_package);
+    }
+    PrintGeneratedAnnotation(printer.get(), '$',
+                             options_.annotate_code ? info_relative_path : "");
+    printer->Print(
+        "public final class $classname$ {\n"
+        "  public static com.google.protobuf.Descriptors.FileDescriptor\n"
+        "      descriptor;\n"
+        "  static {\n",
+        "classname", classname);
+    printer->Annotate("classname", file_->name());
+    printer->Indent();
+    printer->Indent();
+    GenerateDescriptors(printer.get());
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
+
+    if (options_.annotate_code) {
+      std::unique_ptr<io::ZeroCopyOutputStream> info_output(
+          context->Open(info_full_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+      annotation_file_list->push_back(info_full_path);
+    }
+
+    printer.reset();
+    output.reset();
+  }
+}
+
+void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) {
+  // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
+  // and embed it as a string literal, which is parsed and built into real
+  // descriptors at initialization time.  We unfortunately have to put it in
+  // a string literal, not a byte array, because apparently using a literal
+  // byte array causes the Java compiler to generate *instructions* to
+  // initialize each and every byte of the array, e.g. as if you typed:
+  //   b[0] = 123; b[1] = 456; b[2] = 789;
+  // This makes huge bytecode files and can easily hit the compiler's internal
+  // code size limits (error "code to large").  String literals are apparently
+  // embedded raw, which is what we want.
+  FileDescriptorProto file_proto;
+  file_->CopyTo(&file_proto);
+
+  std::string file_data;
+  file_proto.SerializeToString(&file_data);
+
+  printer->Print("java.lang.String[] descriptorData = {\n");
+  printer->Indent();
+
+  // Limit the number of bytes per line.
+  static const int kBytesPerLine = 40;
+  // Limit the number of lines per string part.
+  static const int kLinesPerPart = 400;
+  // Every block of bytes, start a new string literal, in order to avoid the
+  // 64k length limit. Note that this value needs to be <64k.
+  static const int kBytesPerPart = kBytesPerLine * kLinesPerPart;
+  for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+    if (i > 0) {
+      if (i % kBytesPerPart == 0) {
+        printer->Print(",\n");
+      } else {
+        printer->Print(" +\n");
+      }
+    }
+    printer->Print("\"$data$\"", "data",
+                   CEscape(file_data.substr(i, kBytesPerLine)));
+  }
+
+  printer->Outdent();
+  printer->Print("\n};\n");
+
+  // -----------------------------------------------------------------
+  // Find out all dependencies.
+  std::vector<std::pair<std::string, std::string> > dependencies;
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    std::string filename = file_->dependency(i)->name();
+    std::string package = FileJavaPackage(file_->dependency(i));
+    std::string classname =
+        name_resolver_->GetDescriptorClassName(file_->dependency(i));
+    std::string full_name;
+    if (package.empty()) {
+      full_name = classname;
+    } else {
+      full_name = package + "." + classname;
+    }
+    dependencies.push_back(std::make_pair(filename, full_name));
+  }
+
+  // -----------------------------------------------------------------
+  // Invoke internalBuildGeneratedFileFrom() to build the file.
+  printer->Print(
+      "descriptor = com.google.protobuf.Descriptors.FileDescriptor\n"
+      "  .internalBuildGeneratedFileFrom(descriptorData,\n");
+  printer->Print(
+      "    new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
+
+  for (int i = 0; i < dependencies.size(); i++) {
+    const std::string& dependency = dependencies[i].second;
+    printer->Print("      $dependency$.getDescriptor(),\n", "dependency",
+                   dependency);
+  }
+
+  printer->Print("    });\n");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/shared_code_generator.h b/src/google/protobuf/compiler/java/shared_code_generator.h
new file mode 100644
index 0000000..b1f6eb3
--- /dev/null
+++ b/src/google/protobuf/compiler/java/shared_code_generator.h
@@ -0,0 +1,90 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: xiaofeng@google.com (Feng Xiao)
+//
+// Generators that generate shared code between immutable API and mutable API.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/options.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor;  // descriptor.h
+namespace compiler {
+class GeneratorContext;  // code_generator.h
+namespace java {
+class ClassNameResolver;  // name_resolver.h
+}
+}  // namespace compiler
+namespace io {
+class Printer;  // printer.h
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// A generator that generates code that are shared between immutable API
+// and mutable API. Currently only descriptors are shared.
+class SharedCodeGenerator {
+ public:
+  SharedCodeGenerator(const FileDescriptor* file, const Options& options);
+  ~SharedCodeGenerator();
+
+  void Generate(GeneratorContext* generator_context,
+                std::vector<std::string>* file_list,
+                std::vector<std::string>* annotation_file_list);
+
+  void GenerateDescriptors(io::Printer* printer);
+
+ private:
+  std::unique_ptr<ClassNameResolver> name_resolver_;
+  const FileDescriptor* file_;
+  const Options options_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/java/string_field.cc b/src/google/protobuf/compiler/java/string_field.cc
new file mode 100644
index 0000000..e77a8ee
--- /dev/null
+++ b/src/google/protobuf/compiler/java/string_field.cc
@@ -0,0 +1,1167 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <google/protobuf/compiler/java/string_field.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.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,
+                           std::map<std::string, std::string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY";
+
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_init"] =
+      "= " + ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["capitalized_type"] = "String";
+  (*variables)["tag"] =
+      StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor)));
+  (*variables)["tag_size"] = StrCat(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  (*variables)["null_check"] =
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n";
+  (*variables)["isStringEmpty"] = "com.google.protobuf.GeneratedMessage" +
+                                  GeneratedCodeVersionSuffix() +
+                                  ".isStringEmpty";
+  (*variables)["writeString"] = "com.google.protobuf.GeneratedMessage" +
+                                GeneratedCodeVersionSuffix() + ".writeString";
+  (*variables)["computeStringSize"] = "com.google.protobuf.GeneratedMessage" +
+                                      GeneratedCodeVersionSuffix() +
+                                      ".computeStringSize";
+
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] =
+      descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+  (*variables)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["on_changed"] = "onChanged();";
+
+  if (HasHasbit(descriptor)) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+    (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["set_has_field_bit_builder"] =
+        GenerateSetBit(builderBitIndex) + ";";
+    (*variables)["clear_has_field_bit_builder"] =
+        GenerateClearBit(builderBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["set_has_field_bit_builder"] = "";
+    (*variables)["clear_has_field_bit_builder"] = "";
+
+    (*variables)["is_field_present_message"] =
+        "!" + (*variables)["isStringEmpty"] + "(" + (*variables)["name"] + "_)";
+  }
+
+  // For repeated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableStringFieldGenerator::ImmutableStringFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {}
+
+int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 0;
+}
+
+int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const {
+  return GetNumBitsForMessage();
+}
+
+// A note about how strings are handled. This code used to just store a String
+// in the Message. This had two issues:
+//
+//  1. It wouldn't roundtrip byte arrays that were not valid 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.
+//
+// So now, the field for String is maintained as an Object reference which can
+// either store a String or a ByteString. The code uses an instanceof check
+// to see which one it has and converts to the other one if needed. It remembers
+// the last value requested (in a thread safe manner) as this is most likely
+// the one needed next. The thread safety is such that if two threads both
+// convert the field because the changes made by each thread were not visible to
+// the other, they may cause a conversion to happen more times than would
+// otherwise be necessary. This was deemed better than adding synchronization
+// overhead. It will not cause any corruption issues or affect the behavior of
+// the API. The instanceof check is also highly optimized in the JVM and we
+// decided it was better to reduce the memory overhead by not having two
+// separate fields but rather use dynamic type checking.
+//
+// For single fields, the logic for this is done inside the generated code. For
+// repeated fields, the logic is done in LazyStringArrayList and
+// UnmodifiableLazyStringList.
+void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "$deprecation$java.lang.String get$capitalized_name$();\n");
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "$deprecation$com.google.protobuf.ByteString\n"
+                 "    get$capitalized_name$Bytes();\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_, "private volatile java.lang.Object $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  java.lang.Object ref = $name$_;\n"
+      "  if (ref instanceof java.lang.String) {\n"
+      "    return (java.lang.String) ref;\n"
+      "  } else {\n"
+      "    com.google.protobuf.ByteString bs = \n"
+      "        (com.google.protobuf.ByteString) ref;\n"
+      "    java.lang.String s = bs.toStringUtf8();\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "    $name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+                   "    if (bs.isValidUtf8()) {\n"
+                   "      $name$_ = s;\n"
+                   "    }\n");
+  }
+  printer->Print(variables_,
+                 "    return s;\n"
+                 "  }\n"
+                 "}\n");
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$() {\n"
+                 "  java.lang.Object ref = $name$_;\n"
+                 "  if (ref instanceof java.lang.String) {\n"
+                 "    com.google.protobuf.ByteString b = \n"
+                 "        com.google.protobuf.ByteString.copyFromUtf8(\n"
+                 "            (java.lang.String) ref);\n"
+                 "    $name$_ = b;\n"
+                 "    return b;\n"
+                 "  } else {\n"
+                 "    return (com.google.protobuf.ByteString) ref;\n"
+                 "  }\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableStringFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "private java.lang.Object $name$_ $default_init$;\n");
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_builder$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  java.lang.Object ref = $name$_;\n"
+      "  if (!(ref instanceof java.lang.String)) {\n"
+      "    com.google.protobuf.ByteString bs =\n"
+      "        (com.google.protobuf.ByteString) ref;\n"
+      "    java.lang.String s = bs.toStringUtf8();\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "    $name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+                   "    if (bs.isValidUtf8()) {\n"
+                   "      $name$_ = s;\n"
+                   "    }\n");
+  }
+  printer->Print(variables_,
+                 "    return s;\n"
+                 "  } else {\n"
+                 "    return (java.lang.String) ref;\n"
+                 "  }\n"
+                 "}\n");
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$() {\n"
+                 "  java.lang.Object ref = $name$_;\n"
+                 "  if (ref instanceof String) {\n"
+                 "    com.google.protobuf.ByteString b = \n"
+                 "        com.google.protobuf.ByteString.copyFromUtf8(\n"
+                 "            (java.lang.String) ref);\n"
+                 "    $name$_ = b;\n"
+                 "    return b;\n"
+                 "  } else {\n"
+                 "    return (com.google.protobuf.ByteString) ref;\n"
+                 "  }\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+                 "    java.lang.String value) {\n"
+                 "$null_check$"
+                 "  $set_has_field_bit_builder$\n"
+                 "  $name$_ = value;\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  $clear_has_field_bit_builder$\n");
+  printer->Annotate("{", "}", descriptor_);
+  // 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");
+  printer->Print(variables_,
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n"
+      "    com.google.protobuf.ByteString value) {\n"
+      "$null_check$");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+                 "  $set_has_field_bit_builder$\n"
+                 "  $name$_ = value;\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: kotlin.String\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+        "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+        "}\n");
+  }
+}
+
+void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode(
+    io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutableStringFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = $default$;\n"
+                 "$clear_has_field_bit_builder$\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    // 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_builder$\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 ImmutableStringFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    printer->Print(variables_,
+                   "if ($get_has_field_bit_from_local$) {\n"
+                   "  $set_has_field_bit_to_local$;\n"
+                   "}\n");
+  }
+  printer->Print(variables_, "result.$name$_ = $name$_;\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+                   "$name$_ = input.readStringRequireUtf8();\n"
+                   "$set_has_field_bit_builder$\n");
+  } else {
+    printer->Print(variables_,
+                   "$name$_ = input.readBytes();\n"
+                   "$set_has_field_bit_builder$\n");
+  }
+}
+
+void ImmutableStringFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($is_field_present_message$) {\n"
+                 "  $writeString$(output, $number$, $name$_);\n"
+                 "}\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateSerializedSizeCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($is_field_present_message$) {\n"
+                 "  size += $computeStringSize$($number$, $name$_);\n"
+                 "}\n");
+}
+
+void ImmutableStringFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if (!get$capitalized_name$()\n"
+                 "    .equals(other.get$capitalized_name$())) return false;\n");
+}
+
+void ImmutableStringFieldGenerator::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");
+}
+
+std::string ImmutableStringFieldGenerator::GetBoxedType() const {
+  return "java.lang.String";
+}
+
+// ===================================================================
+
+ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : ImmutableStringFieldGenerator(descriptor, messageBitIndex,
+                                    builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableStringOneofFieldGenerator::~ImmutableStringOneofFieldGenerator() {}
+
+void ImmutableStringOneofFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  java.lang.Object ref $default_init$;\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    ref = $oneof_name$_;\n"
+      "  }\n"
+      "  if (ref instanceof java.lang.String) {\n"
+      "    return (java.lang.String) ref;\n"
+      "  } else {\n"
+      "    com.google.protobuf.ByteString bs = \n"
+      "        (com.google.protobuf.ByteString) ref;\n"
+      "    java.lang.String s = bs.toStringUtf8();\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+                   "    if ($has_oneof_case_message$) {\n"
+                   "      $oneof_name$_ = s;\n"
+                   "    }\n");
+  } else {
+    printer->Print(variables_,
+                   "    if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n"
+                   "      $oneof_name$_ = s;\n"
+                   "    }\n");
+  }
+  printer->Print(variables_,
+                 "    return s;\n"
+                 "  }\n"
+                 "}\n");
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+
+  printer->Print(variables_,
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$() {\n"
+                 "  java.lang.Object ref $default_init$;\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    ref = $oneof_name$_;\n"
+                 "  }\n"
+                 "  if (ref instanceof java.lang.String) {\n"
+                 "    com.google.protobuf.ByteString b = \n"
+                 "        com.google.protobuf.ByteString.copyFromUtf8(\n"
+                 "            (java.lang.String) ref);\n"
+                 "    if ($has_oneof_case_message$) {\n"
+                 "      $oneof_name$_ = b;\n"
+                 "    }\n"
+                 "    return b;\n"
+                 "  } else {\n"
+                 "    return (com.google.protobuf.ByteString) ref;\n"
+                 "  }\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  java.lang.Object ref $default_init$;\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    ref = $oneof_name$_;\n"
+      "  }\n"
+      "  if (!(ref instanceof java.lang.String)) {\n"
+      "    com.google.protobuf.ByteString bs =\n"
+      "        (com.google.protobuf.ByteString) ref;\n"
+      "    java.lang.String s = bs.toStringUtf8();\n"
+      "    if ($has_oneof_case_message$) {\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "      $oneof_name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+                   "      if (bs.isValidUtf8()) {\n"
+                   "        $oneof_name$_ = s;\n"
+                   "      }\n");
+  }
+  printer->Print(variables_,
+                 "    }\n"
+                 "    return s;\n"
+                 "  } else {\n"
+                 "    return (java.lang.String) ref;\n"
+                 "  }\n"
+                 "}\n");
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$() {\n"
+                 "  java.lang.Object ref $default_init$;\n"
+                 "  if ($has_oneof_case_message$) {\n"
+                 "    ref = $oneof_name$_;\n"
+                 "  }\n"
+                 "  if (ref instanceof String) {\n"
+                 "    com.google.protobuf.ByteString b = \n"
+                 "        com.google.protobuf.ByteString.copyFromUtf8(\n"
+                 "            (java.lang.String) ref);\n"
+                 "    if ($has_oneof_case_message$) {\n"
+                 "      $oneof_name$_ = b;\n"
+                 "    }\n"
+                 "    return b;\n"
+                 "  } else {\n"
+                 "    return (com.google.protobuf.ByteString) ref;\n"
+                 "  }\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+                 "    java.lang.String value) {\n"
+                 "$null_check$"
+                 "  $set_oneof_case_message$;\n"
+                 "  $oneof_name$_ = value;\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    $clear_oneof_case_message$;\n"
+      "    $oneof_name$_ = null;\n"
+      "    $on_changed$\n"
+      "  }\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n"
+      "    com.google.protobuf.ByteString value) {\n"
+      "$null_check$");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+                 "  $set_oneof_case_message$;\n"
+                 "  $oneof_name$_ = value;\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+}
+
+void ImmutableStringOneofFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  // No-Op: String fields in oneofs are correctly cleared by clearing the oneof
+}
+
+void ImmutableStringOneofFieldGenerator::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 ImmutableStringOneofFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  result.$oneof_name$_ = $oneof_name$_;\n"
+                 "}\n");
+}
+
+void ImmutableStringOneofFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+                   "java.lang.String s = input.readStringRequireUtf8();\n"
+                   "$set_oneof_case_message$;\n"
+                   "$oneof_name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+                   "com.google.protobuf.ByteString bs = input.readBytes();\n"
+                   "$set_oneof_case_message$;\n"
+                   "$oneof_name$_ = bs;\n");
+  }
+}
+
+void ImmutableStringOneofFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  $writeString$(output, $number$, $oneof_name$_);\n"
+                 "}\n");
+}
+
+void ImmutableStringOneofFieldGenerator::GenerateSerializedSizeCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  size += $computeStringSize$($number$, $oneof_name$_);\n"
+                 "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableStringFieldGenerator::RepeatedImmutableStringFieldGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
+    Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutableStringFieldGenerator::
+    ~RepeatedImmutableStringFieldGenerator() {}
+
+int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableStringFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      // NOTE: the same method in the implementation class actually returns
+      // com.google.protobuf.ProtocolStringList (a subclass of List). It's
+      // changed between protobuf 2.5.0 release and protobuf 2.6.1 release.
+      // To retain binary compatibility with both 2.5.0 and 2.6.1 generated
+      // code, we make this interface method return List so both methods
+      // with different return types exist in the compiled byte code.
+      "$deprecation$java.util.List<java.lang.String>\n"
+      "    get$capitalized_name$List();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(variables_,
+                 "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$java.lang.String get$capitalized_name$(int index);\n");
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$com.google.protobuf.ByteString\n"
+                 "    get$capitalized_name$Bytes(int index);\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateMembers(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "private com.google.protobuf.LazyStringList $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public com.google.protobuf.ProtocolStringList\n"
+                 "    ${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_;\n"  // note:  unmodifiable list
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public java.lang.String "
+                 "${$get$capitalized_name$$}$(int index) {\n"
+                 "  return $name$_.get(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$(int index) {\n"
+                 "  return $name$_.getByteString(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  // One field is the list and the bit field keeps track of whether the
+  // list is immutable. If it's immutable, the invariant is that it must
+  // either an instance of Collections.emptyList() or it's an ArrayList
+  // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+  // a reference to the underlying ArrayList. This invariant allows us to
+  // share instances of lists between protocol buffers avoiding expensive
+  // memory allocations. Note, immutable is a strong guarantee here -- not
+  // just that the list cannot be modified via the reference but that the
+  // list can never be modified.
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.LazyStringList $name$_ = $empty_list$;\n");
+
+  printer->Print(
+      variables_,
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      "  if (!$get_mutable_bit_builder$) {\n"
+      "    $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
+      "    $set_mutable_bit_builder$;\n"
+      "   }\n"
+      "}\n");
+
+  // Note:  We return an unmodifiable list because otherwise the caller
+  //   could hold on to the returned list and modify it after the message
+  //   has been built, thus mutating the message which is supposed to be
+  //   immutable.
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public com.google.protobuf.ProtocolStringList\n"
+                 "    ${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_.getUnmodifiableView();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public java.lang.String "
+                 "${$get$capitalized_name$$}$(int index) {\n"
+                 "  return $name$_.get(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$(int index) {\n"
+                 "  return $name$_.getByteString(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$set$capitalized_name$$}$(\n"
+                 "    int index, java.lang.String value) {\n"
+                 "$null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.set(index, value);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$add$capitalized_name$$}$(\n"
+                 "    java.lang.String value) {\n"
+                 "$null_check$"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.add(value);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ true);
+  printer->Print(variables_,
+                 "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n"
+                 "    java.lang.Iterable<java.lang.String> values) {\n"
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
+                 "      values, $name$_);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  $name$_ = $empty_list$;\n"
+      "  $clear_mutable_bit_builder$;\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                                          /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$add$capitalized_name$Bytes$}$(\n"
+      "    com.google.protobuf.ByteString value) {\n"
+      "$null_check$");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+                 "  ensure$capitalized_name$IsMutable();\n"
+                 "  $name$_.add(value);\n"
+                 "  $on_changed$\n"
+                 "  return this;\n"
+                 "}\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  // property for List<String>
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "$kt_deprecation$ val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
+
+  // List<String>.add(String)
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: kotlin.String) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}\n");
+
+  // List<String> += String
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: kotlin.String) {\n"
+                 "  add(value)\n"
+                 "}\n");
+
+  // List<String>.addAll(Iterable<String>)
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+      "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+      "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+      "}\n");
+
+  // List<String> += Iterable<String>
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+      "  addAll(values)\n"
+      "}\n");
+
+  // List<String>[Int] = String
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: kotlin.String) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}");
+}
+
+void RepeatedImmutableStringFieldGenerator::
+    GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateBuilderClearCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "$name$_ = $empty_list$;\n"
+                 "$clear_mutable_bit_builder$;\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::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"
+                 "    $clear_mutable_bit_builder$;\n"
+                 "  } else {\n"
+                 "    ensure$capitalized_name$IsMutable();\n"
+                 "    $name$_.addAll(other.$name$_);\n"
+                 "  }\n"
+                 "  $on_changed$\n"
+                 "}\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateBuildingCode(
+    io::Printer* printer) const {
+  // The code below ensures that the result has an immutable list. If our
+  // list is immutable, we can just reuse it. If not, we make it immutable.
+
+  printer->Print(variables_,
+                 "if ($get_mutable_bit_builder$) {\n"
+                 "  $name$_ = $name$_.getUnmodifiableView();\n"
+                 "  $clear_mutable_bit_builder$;\n"
+                 "}\n"
+                 "result.$name$_ = $name$_;\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateBuilderParsingCode(
+    io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+                   "java.lang.String s = input.readStringRequireUtf8();\n"
+                   "ensure$capitalized_name$IsMutable();\n"
+                   "$name$_.add(s);\n");
+  } else {
+    printer->Print(variables_,
+                   "com.google.protobuf.ByteString bs = input.readBytes();\n"
+                   "ensure$capitalized_name$IsMutable();\n"
+                   "$name$_.add(bs);\n");
+  }
+}
+
+void RepeatedImmutableStringFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+                 "for (int i = 0; i < $name$_.size(); i++) {\n"
+                 "  $writeString$(output, $number$, $name$_.getRaw(i));\n"
+                 "}\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::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 += computeStringSizeNoTag($name$_.getRaw(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 RepeatedImmutableStringFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!get$capitalized_name$List()\n"
+      "    .equals(other.get$capitalized_name$List())) return false;\n");
+}
+
+void RepeatedImmutableStringFieldGenerator::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");
+}
+
+std::string RepeatedImmutableStringFieldGenerator::GetBoxedType() const {
+  return "String";
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/string_field.h b/src/google/protobuf/compiler/java/string_field.h
new file mode 100644
index 0000000..8c2dc5f
--- /dev/null
+++ b/src/google/protobuf/compiler/java/string_field.h
@@ -0,0 +1,160 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit ImmutableStringFieldGenerator(const FieldDescriptor* descriptor,
+                                         int messageBitIndex,
+                                         int builderBitIndex, Context* context);
+  ~ImmutableStringFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator
+  // ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldGenerator);
+};
+
+class ImmutableStringOneofFieldGenerator
+    : public ImmutableStringFieldGenerator {
+ public:
+  ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                     int messageBitIndex, int builderBitIndex,
+                                     Context* context);
+  ~ImmutableStringOneofFieldGenerator() override;
+
+ private:
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldGenerator);
+};
+
+class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit RepeatedImmutableStringFieldGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableStringFieldGenerator() override;
+
+  // implements ImmutableFieldGenerator ---------------------------------------
+  int GetNumBitsForMessage() const override;
+  int GetNumBitsForBuilder() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateBuilderClearCode(io::Printer* printer) const override;
+  void GenerateMergingCode(io::Printer* printer) const override;
+  void GenerateBuildingCode(io::Printer* printer) const override;
+  void GenerateBuilderParsingCode(io::Printer* printer) const override;
+  void GenerateSerializationCode(io::Printer* printer) const override;
+  void GenerateSerializedSizeCode(io::Printer* printer) const override;
+  void GenerateFieldBuilderInitializationCode(
+      io::Printer* printer) const override;
+  void GenerateEqualsCode(io::Printer* printer) const override;
+  void GenerateHashCode(io::Printer* printer) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/string_field_lite.cc b/src/google/protobuf/compiler/java/string_field_lite.cc
new file mode 100644
index 0000000..8e5b230
--- /dev/null
+++ b/src/google/protobuf/compiler/java/string_field_lite.cc
@@ -0,0 +1,864 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <google/protobuf/compiler/java/string_field_lite.h>
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/context.h>
+#include <google/protobuf/compiler/java/doc_comment.h>
+#include <google/protobuf/compiler/java/helpers.h>
+#include <google/protobuf/compiler/java/name_resolver.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,
+                           std::map<std::string, std::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"] = "java.lang.String";
+  (*variables)["tag"] =
+      StrCat(static_cast<int32_t>(WireFormat::MakeTag(descriptor)));
+  (*variables)["tag_size"] = StrCat(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  // We use `x.getClass()` as a null check because it generates less bytecode
+  // than an `if (x == null) { throw ... }` statement.
+  (*variables)["null_check"] =
+      "  java.lang.Class<?> valueClass = value.getClass();\n";
+
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] =
+      descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+  (*variables)["kt_deprecation"] =
+      descriptor->options().deprecated()
+          ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+                " is deprecated\") "
+          : "";
+  (*variables)["required"] = descriptor->is_required() ? "true" : "false";
+
+  if (HasHasbit(descriptor)) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        "!" + (*variables)["name"] + "_.isEmpty()";
+  }
+
+  (*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, Context* context)
+    : descriptor_(descriptor),
+      messageBitIndex_(messageBitIndex),
+      name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, 0,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+  return HasHasbit(descriptor_) ? 1 : 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 valid 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 (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(variables_,
+                   "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "$deprecation$java.lang.String get$capitalized_name$();\n");
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  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 (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return $get_has_field_bit_message$;\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public com.google.protobuf.ByteString\n"
+      "    ${$get$capitalized_name$Bytes$}$() {\n"
+      "  return com.google.protobuf.ByteString.copyFromUtf8($name$_);\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  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");
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER);
+  printer->Print(variables_,
+                 "private void set$capitalized_name$Bytes(\n"
+                 "    com.google.protobuf.ByteString value) {\n");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+                 "  $name$_ = value.toStringUtf8();\n"
+                 "  $set_has_field_bit_message$\n"
+                 "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "@java.lang.Override\n"
+        "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+        "  return instance.has$capitalized_name$();\n"
+        "}\n");
+    printer->Annotate("{", "}", descriptor_);
+  }
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  return instance.get$capitalized_name$();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$() {\n"
+                 "  return instance.get$capitalized_name$Bytes();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+                 "$kt_deprecation$var $kt_name$: kotlin.String\n"
+                 "  @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+                 "  get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+                 "  @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+                 "  set(value) {\n"
+                 "    $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+                 "  }\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "fun ${$clear$kt_capitalized_name$$}$() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}\n");
+
+  if (HasHazzer(descriptor_)) {
+    WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+    printer->Print(
+        variables_,
+        "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+        "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+        "}\n");
+  }
+}
+
+void ImmutableStringFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  if (HasHasbit(descriptor_)) {
+    WriteIntToUtf16CharSequence(messageBitIndex_, output);
+  }
+  printer->Print(variables_, "\"$name$_\",\n");
+}
+
+void ImmutableStringFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+std::string ImmutableStringFieldLiteGenerator::GetBoxedType() const {
+  return "java.lang.String";
+}
+
+// ===================================================================
+
+ImmutableStringOneofFieldLiteGenerator::ImmutableStringOneofFieldLiteGenerator(
+    const FieldDescriptor* descriptor, int messageBitIndex, Context* context)
+    : ImmutableStringFieldLiteGenerator(descriptor, messageBitIndex, 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);
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return $has_oneof_case_message$;\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$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");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$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");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER);
+  printer->Print(variables_,
+                 "private void ${$set$capitalized_name$Bytes$}$(\n"
+                 "    com.google.protobuf.ByteString value) {\n");
+  printer->Annotate("{", "}", descriptor_);
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_, "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+                 "  $oneof_name$_ = value.toStringUtf8();\n"
+                 "  $set_oneof_case_message$;\n"
+                 "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  WriteIntToUtf16CharSequence(descriptor_->containing_oneof()->index(), output);
+}
+
+void ImmutableStringOneofFieldLiteGenerator::GenerateBuilderMembers(
+    io::Printer* printer) const {
+  GOOGLE_DCHECK(HasHazzer(descriptor_));
+  WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
+                 "  return instance.has$capitalized_name$();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n"
+      "  return instance.get$capitalized_name$();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$() {\n"
+                 "  return instance.get$capitalized_name$Bytes();\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
+                                          /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+// ===================================================================
+
+RepeatedImmutableStringFieldLiteGenerator::
+    RepeatedImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                              int messageBitIndex,
+                                              Context* context)
+    : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, 0,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutableStringFieldLiteGenerator::
+    ~RepeatedImmutableStringFieldLiteGenerator() {}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::GenerateInterfaceMembers(
+    io::Printer* printer) const {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "$deprecation$java.util.List<java.lang.String>\n"
+                 "    get$capitalized_name$List();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(variables_,
+                 "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(
+      variables_,
+      "$deprecation$java.lang.String get$capitalized_name$(int index);\n");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  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<java.lang.String> "
+      "$name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<java.lang.String> "
+                 "${$get$capitalized_name$List$}$() {\n"
+                 "  return $name$_;\n"  // note:  unmodifiable list
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return $name$_.size();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.lang.String "
+                 "${$get$capitalized_name$$}$(int index) {\n"
+                 "  return $name$_.get(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$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->Annotate("{", "}", descriptor_);
+
+  printer->Print(
+      variables_,
+      "private void ensure$capitalized_name$IsMutable() {\n"
+      // Use a temporary to avoid a redundant iget-object.
+      "  com.google.protobuf.Internal.ProtobufList<java.lang.String> tmp =\n"
+      "      $name$_;"
+      "  if (!tmp.isModifiable()) {\n"
+      "    $name$_ =\n"
+      "        com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp);\n"
+      "   }\n"
+      "}\n");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER);
+  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");
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER);
+  printer->Print(variables_,
+                 "private void clear$capitalized_name$() {\n"
+                 "  $name$_ = $empty_list$;\n"
+                 "}\n");
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER);
+  printer->Print(variables_,
+                 "private void add$capitalized_name$Bytes(\n"
+                 "    com.google.protobuf.ByteString value) {\n");
+  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 {
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.util.List<java.lang.String>\n"
+                 "    ${$get$capitalized_name$List$}$() {\n"
+                 "  return java.util.Collections.unmodifiableList(\n"
+                 "      instance.get$capitalized_name$List());\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
+  printer->Print(
+      variables_,
+      "@java.lang.Override\n"
+      "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
+      "  return instance.get$capitalized_name$Count();\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public java.lang.String "
+                 "${$get$capitalized_name$$}$(int index) {\n"
+                 "  return instance.get$capitalized_name$(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_,
+                                          LIST_INDEXED_GETTER);
+  printer->Print(variables_,
+                 "@java.lang.Override\n"
+                 "$deprecation$public com.google.protobuf.ByteString\n"
+                 "    ${$get$capitalized_name$Bytes$}$(int index) {\n"
+                 "  return instance.get$capitalized_name$Bytes(index);\n"
+                 "}\n");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ true);
+  printer->Print(
+      variables_,
+      "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$capitalized_name$();\n"
+      "  return this;\n"
+      "}\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                                          /* builder */ true);
+  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");
+  printer->Annotate("{", "}", descriptor_);
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers(
+    io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * An uninstantiable, behaviorless type to represent the field in\n"
+      " * generics.\n"
+      " */\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+      " : com.google.protobuf.kotlin.DslProxy()\n");
+
+  // property for List<String>
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+  printer->Print(
+      variables_,
+      "$kt_deprecation$ val $kt_name$: "
+      "com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
+      "@kotlin.OptIn"
+      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+      "  get() = com.google.protobuf.kotlin.DslList(\n"
+      "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+      "  )\n");
+
+  // List<String>.add(String)
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+                 "add(value: kotlin.String) {\n"
+                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "}\n");
+
+  // List<String> += String
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "inline operator fun com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+                 "plusAssign(value: kotlin.String) {\n"
+                 "  add(value)\n"
+                 "}\n");
+
+  // List<String>.addAll(Iterable<String>)
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+      "fun com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+      "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+      "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+      "}\n");
+
+  // List<String> += Iterable<String>
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "inline operator fun com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+      "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+      "  addAll(values)\n"
+      "}\n");
+
+  // List<String>[Int] = String
+  WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+                               /* builder */ false);
+  printer->Print(
+      variables_,
+      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+      "operator fun com.google.protobuf.kotlin.DslList"
+      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+      "set(index: kotlin.Int, value: kotlin.String) {\n"
+      "  $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+      "}");
+
+  WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+                               /* builder */ false);
+  printer->Print(variables_,
+                 "@kotlin.jvm.JvmSynthetic\n"
+                 "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+                 "fun com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+                 "clear() {\n"
+                 "  $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+                 "}");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::GenerateFieldInfo(
+    io::Printer* printer, std::vector<uint16_t>* output) const {
+  WriteIntToUtf16CharSequence(descriptor_->number(), output);
+  WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
+                              output);
+  printer->Print(variables_, "\"$name$_\",\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::GenerateInitializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+std::string RepeatedImmutableStringFieldLiteGenerator::GetBoxedType() const {
+  return "java.lang.String";
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/string_field_lite.h b/src/google/protobuf/compiler/java/string_field_lite.h
new file mode 100644
index 0000000..b6ad1ea
--- /dev/null
+++ b/src/google/protobuf/compiler/java/string_field_lite.h
@@ -0,0 +1,139 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+class Context;            // context.h
+class ClassNameResolver;  // name_resolver.h
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                             int messageBitIndex,
+                                             Context* context);
+  ~ImmutableStringFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator
+  // ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  const int messageBitIndex_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldLiteGenerator);
+};
+
+class ImmutableStringOneofFieldLiteGenerator
+    : public ImmutableStringFieldLiteGenerator {
+ public:
+  ImmutableStringOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                         int messageBitIndex, Context* context);
+  ~ImmutableStringOneofFieldLiteGenerator() override;
+
+ private:
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableStringFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableStringFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex, Context* context);
+  ~RepeatedImmutableStringFieldLiteGenerator() override;
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const override;
+  void GenerateInterfaceMembers(io::Printer* printer) const override;
+  void GenerateMembers(io::Printer* printer) const override;
+  void GenerateBuilderMembers(io::Printer* printer) const override;
+  void GenerateInitializationCode(io::Printer* printer) const override;
+  void GenerateFieldInfo(io::Printer* printer,
+                         std::vector<uint16_t>* output) const override;
+  void GenerateKotlinDslMembers(io::Printer* printer) const override;
+
+  std::string GetBoxedType() const override;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+  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/main.cc b/src/google/protobuf/compiler/main.cc
new file mode 100644
index 0000000..3960946
--- /dev/null
+++ b/src/google/protobuf/compiler/main.cc
@@ -0,0 +1,113 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/generator.h>
+#include <google/protobuf/compiler/java/generator.h>
+#include <google/protobuf/compiler/java/kotlin_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
+#include <google/protobuf/compiler/php/php_generator.h>
+#include <google/protobuf/compiler/python/generator.h>
+#include <google/protobuf/compiler/python/pyi_generator.h>
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+int ProtobufMain(int argc, char* argv[]) {
+
+  CommandLineInterface cli;
+  cli.AllowPlugins("protoc-");
+
+  // Proto2 C++
+  cpp::CppGenerator cpp_generator;
+  cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
+                        "Generate C++ header and source.");
+
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+  cpp_generator.set_opensource_runtime(true);
+  cpp_generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
+#endif
+
+  // Proto2 Java
+  java::JavaGenerator java_generator;
+  cli.RegisterGenerator("--java_out", "--java_opt", &java_generator,
+                        "Generate Java source file.");
+
+  // Proto2 Kotlin
+  java::KotlinGenerator kt_generator;
+  cli.RegisterGenerator("--kotlin_out", "--kotlin_opt", &kt_generator,
+                        "Generate Kotlin file.");
+
+
+  // Proto2 Python
+  python::Generator py_generator;
+  cli.RegisterGenerator("--python_out", "--python_opt", &py_generator,
+                        "Generate Python source file.");
+  // Python pyi
+  python::PyiGenerator pyi_generator;
+  cli.RegisterGenerator("--pyi_out", &pyi_generator,
+                        "Generate python pyi stub.");
+
+  // PHP
+  php::Generator php_generator;
+  cli.RegisterGenerator("--php_out", "--php_opt", &php_generator,
+                        "Generate PHP source file.");
+
+  // Ruby
+  ruby::Generator rb_generator;
+  cli.RegisterGenerator("--ruby_out", "--ruby_opt", &rb_generator,
+                        "Generate Ruby source file.");
+
+  // CSharp
+  csharp::Generator csharp_generator;
+  cli.RegisterGenerator("--csharp_out", "--csharp_opt", &csharp_generator,
+                        "Generate C# source file.");
+
+  // Objective-C
+  objectivec::ObjectiveCGenerator objc_generator;
+  cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator,
+                        "Generate Objective-C header and source.");
+
+  return cli.Run(argc, argv);
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+int main(int argc, char* argv[]) {
+  return PROTOBUF_NAMESPACE_ID::compiler::ProtobufMain(argc, argv);
+}
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
new file mode 100644
index 0000000..4d04511
--- /dev/null
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/compiler/mock_code_generator.h>
+
+#include <stdlib.h>
+
+#include <cstdint>
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/plugin.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/text_format.h>
+
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+// Returns the list of the names of files in all_files in the form of a
+// comma-separated string.
+std::string CommaSeparatedList(
+    const std::vector<const FileDescriptor*>& all_files) {
+  std::vector<std::string> names;
+  for (size_t i = 0; i < all_files.size(); i++) {
+    names.push_back(all_files[i]->name());
+  }
+  return Join(names, ",");
+}
+
+static const char* kFirstInsertionPointName = "first_mock_insertion_point";
+static const char* kSecondInsertionPointName = "second_mock_insertion_point";
+static const char* kFirstInsertionPoint =
+    "# @@protoc_insertion_point(first_mock_insertion_point) is here\n";
+static const char* kSecondInsertionPoint =
+    "  # @@protoc_insertion_point(second_mock_insertion_point) is here\n";
+
+MockCodeGenerator::MockCodeGenerator(const std::string& name) : name_(name) {}
+
+MockCodeGenerator::~MockCodeGenerator() {}
+
+uint64_t MockCodeGenerator::GetSupportedFeatures() const {
+  uint64_t all_features = CodeGenerator::FEATURE_PROTO3_OPTIONAL;
+  return all_features & ~suppressed_features_;
+}
+
+void MockCodeGenerator::SuppressFeatures(uint64_t features) {
+  suppressed_features_ = features;
+}
+
+void MockCodeGenerator::ExpectGenerated(
+    const std::string& name, const std::string& parameter,
+    const std::string& insertions, const std::string& file,
+    const std::string& first_message_name,
+    const std::string& first_parsed_file_name,
+    const std::string& output_directory) {
+  std::string content;
+  GOOGLE_CHECK_OK(
+      File::GetContents(output_directory + "/" + GetOutputFileName(name, file),
+                        &content, true));
+
+  std::vector<std::string> lines =
+      Split(content, "\n", true);
+
+  while (!lines.empty() && lines.back().empty()) {
+    lines.pop_back();
+  }
+  for (size_t i = 0; i < lines.size(); i++) {
+    lines[i] += "\n";
+  }
+
+  std::vector<std::string> insertion_list;
+  if (!insertions.empty()) {
+    insertion_list = Split(insertions, ",", true);
+  }
+
+  EXPECT_EQ(lines.size(), 3 + insertion_list.size() * 2);
+  EXPECT_EQ(GetOutputFileContent(name, parameter, file, first_parsed_file_name,
+                                 first_message_name),
+            lines[0]);
+
+  EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
+  EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]);
+
+  for (size_t i = 0; i < insertion_list.size(); i++) {
+    EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert", file,
+                                   file, first_message_name),
+              lines[1 + i]);
+    // Second insertion point is indented, so the inserted text should
+    // automatically be indented too.
+    EXPECT_EQ("  " + GetOutputFileContent(insertion_list[i], "second_insert",
+                                          file, file, first_message_name),
+              lines[2 + insertion_list.size() + i]);
+  }
+}
+
+namespace {
+void CheckSingleAnnotation(const std::string& expected_file,
+                           const std::string& expected_text,
+                           const std::string& file_content,
+                           const GeneratedCodeInfo::Annotation& annotation) {
+  EXPECT_EQ(expected_file, annotation.source_file());
+  ASSERT_GE(file_content.size(), annotation.begin());
+  ASSERT_GE(file_content.size(), annotation.end());
+  ASSERT_LE(annotation.begin(), annotation.end());
+  EXPECT_EQ(expected_text.size(), annotation.end() - annotation.begin());
+  EXPECT_EQ(expected_text,
+            file_content.substr(annotation.begin(), expected_text.size()));
+}
+}  // anonymous namespace
+
+void MockCodeGenerator::CheckGeneratedAnnotations(
+    const std::string& name, const std::string& file,
+    const std::string& output_directory) {
+  std::string file_content;
+  GOOGLE_CHECK_OK(
+      File::GetContents(output_directory + "/" + GetOutputFileName(name, file),
+                        &file_content, true));
+  std::string meta_content;
+  GOOGLE_CHECK_OK(File::GetContents(
+      output_directory + "/" + GetOutputFileName(name, file) + ".pb.meta",
+      &meta_content, true));
+  GeneratedCodeInfo annotations;
+  GOOGLE_CHECK(TextFormat::ParseFromString(meta_content, &annotations));
+  ASSERT_EQ(7, annotations.annotation_size());
+
+  CheckSingleAnnotation("first_annotation", "first", file_content,
+                        annotations.annotation(0));
+  CheckSingleAnnotation("first_path",
+                        "test_generator: first_insert,\n foo.proto,\n "
+                        "MockCodeGenerator_Annotate,\n foo.proto\n",
+                        file_content, annotations.annotation(1));
+  CheckSingleAnnotation("first_path",
+                        "test_plugin: first_insert,\n foo.proto,\n "
+                        "MockCodeGenerator_Annotate,\n foo.proto\n",
+                        file_content, annotations.annotation(2));
+  CheckSingleAnnotation("second_annotation", "second", file_content,
+                        annotations.annotation(3));
+  // This annotated text has changed because it was inserted at an indented
+  // insertion point.
+  CheckSingleAnnotation("second_path",
+                        "test_generator: second_insert,\n   foo.proto,\n   "
+                        "MockCodeGenerator_Annotate,\n   foo.proto\n",
+                        file_content, annotations.annotation(4));
+  CheckSingleAnnotation("second_path",
+                        "test_plugin: second_insert,\n   foo.proto,\n   "
+                        "MockCodeGenerator_Annotate,\n   foo.proto\n",
+                        file_content, annotations.annotation(5));
+  CheckSingleAnnotation("third_annotation", "third", file_content,
+                        annotations.annotation(6));
+}
+
+bool MockCodeGenerator::Generate(const FileDescriptor* file,
+                                 const std::string& parameter,
+                                 GeneratorContext* context,
+                                 std::string* error) const {
+  bool annotate = false;
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
+      std::string command = StripPrefixString(
+          file->message_type(i)->name(), "MockCodeGenerator_");
+      if (command == "Error") {
+        *error = "Saw message type MockCodeGenerator_Error.";
+        return false;
+      } else if (command == "Exit") {
+        std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl;
+        exit(123);
+      } else if (command == "Abort") {
+        std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl;
+        abort();
+      } else if (command == "HasSourceCodeInfo") {
+        FileDescriptorProto file_descriptor_proto;
+        file->CopySourceCodeInfoTo(&file_descriptor_proto);
+        bool has_source_code_info =
+            file_descriptor_proto.has_source_code_info() &&
+            file_descriptor_proto.source_code_info().location_size() > 0;
+        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 if (command == "Annotate") {
+        annotate = true;
+      } else if (command == "ShowVersionNumber") {
+        Version compiler_version;
+        context->GetCompilerVersion(&compiler_version);
+        std::cerr << "Saw compiler_version: "
+                  << compiler_version.major() * 1000000 +
+                         compiler_version.minor() * 1000 +
+                         compiler_version.patch()
+                  << " " << compiler_version.suffix() << std::endl;
+        abort();
+      } else {
+        GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
+      }
+    }
+  }
+
+  bool insert_endlines = HasPrefixString(parameter, "insert_endlines=");
+  if (insert_endlines || HasPrefixString(parameter, "insert=")) {
+    std::vector<std::string> insert_into = Split(
+        StripPrefixString(
+            parameter, insert_endlines ? "insert_endlines=" : "insert="),
+        ",", true);
+
+    for (size_t i = 0; i < insert_into.size(); i++) {
+      {
+        google::protobuf::GeneratedCodeInfo info;
+        std::string content =
+            GetOutputFileContent(name_, "first_insert", file, context);
+        if (insert_endlines) {
+          GlobalReplaceSubstring(",", ",\n", &content);
+        }
+        if (annotate) {
+          auto* annotation = info.add_annotation();
+          annotation->set_begin(0);
+          annotation->set_end(content.size());
+          annotation->set_source_file("first_path");
+        }
+        std::unique_ptr<io::ZeroCopyOutputStream> output(
+            context->OpenForInsertWithGeneratedCodeInfo(
+                GetOutputFileName(insert_into[i], file),
+                kFirstInsertionPointName, info));
+        io::Printer printer(output.get(), '$');
+        printer.PrintRaw(content);
+        if (printer.failed()) {
+          *error = "MockCodeGenerator detected write error.";
+          return false;
+        }
+      }
+
+      {
+        google::protobuf::GeneratedCodeInfo info;
+        std::string content =
+            GetOutputFileContent(name_, "second_insert", file, context);
+        if (insert_endlines) {
+          GlobalReplaceSubstring(",", ",\n", &content);
+        }
+        if (annotate) {
+          auto* annotation = info.add_annotation();
+          annotation->set_begin(0);
+          annotation->set_end(content.size());
+          annotation->set_source_file("second_path");
+        }
+        std::unique_ptr<io::ZeroCopyOutputStream> output(
+            context->OpenForInsertWithGeneratedCodeInfo(
+                GetOutputFileName(insert_into[i], file),
+                kSecondInsertionPointName, info));
+        io::Printer printer(output.get(), '$');
+        printer.PrintRaw(content);
+        if (printer.failed()) {
+          *error = "MockCodeGenerator detected write error.";
+          return false;
+        }
+      }
+    }
+  } else {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        context->Open(GetOutputFileName(name_, file)));
+
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    io::Printer printer(output.get(), '$',
+                        annotate ? &annotation_collector : nullptr);
+    printer.PrintRaw(GetOutputFileContent(name_, parameter, file, context));
+    std::string annotate_suffix = "_annotation";
+    if (annotate) {
+      printer.Print("$p$\n", "p", "first");
+      printer.Annotate("p", "first" + annotate_suffix);
+    }
+    printer.PrintRaw(kFirstInsertionPoint);
+    if (annotate) {
+      printer.Print("$p$\n", "p", "second");
+      printer.Annotate("p", "second" + annotate_suffix);
+    }
+    printer.PrintRaw(kSecondInsertionPoint);
+    if (annotate) {
+      printer.Print("$p$\n", "p", "third");
+      printer.Annotate("p", "third" + annotate_suffix);
+    }
+
+    if (printer.failed()) {
+      *error = "MockCodeGenerator detected write error.";
+      return false;
+    }
+    if (annotate) {
+      std::unique_ptr<io::ZeroCopyOutputStream> meta_output(
+          context->Open(GetOutputFileName(name_, file) + ".pb.meta"));
+      if (!TextFormat::Print(annotations, meta_output.get())) {
+        *error = "MockCodeGenerator couldn't write .pb.meta";
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+std::string MockCodeGenerator::GetOutputFileName(
+    const std::string& generator_name, const FileDescriptor* file) {
+  return GetOutputFileName(generator_name, file->name());
+}
+
+std::string MockCodeGenerator::GetOutputFileName(
+    const std::string& generator_name, const std::string& file) {
+  return file + ".MockCodeGenerator." + generator_name;
+}
+
+std::string MockCodeGenerator::GetOutputFileContent(
+    const std::string& generator_name, const std::string& parameter,
+    const FileDescriptor* file, GeneratorContext* context) {
+  std::vector<const FileDescriptor*> all_files;
+  context->ListParsedFiles(&all_files);
+  return GetOutputFileContent(
+      generator_name, parameter, file->name(), CommaSeparatedList(all_files),
+      file->message_type_count() > 0 ? file->message_type(0)->name()
+                                     : "(none)");
+}
+
+std::string MockCodeGenerator::GetOutputFileContent(
+    const std::string& generator_name, const std::string& parameter,
+    const std::string& file, const std::string& parsed_file_list,
+    const std::string& first_message_name) {
+  return strings::Substitute("$0: $1, $2, $3, $4\n", generator_name, parameter,
+                          file, first_message_name, parsed_file_list);
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
new file mode 100644
index 0000000..45d735a
--- /dev/null
+++ b/src/google/protobuf/compiler/mock_code_generator.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
+
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor;
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+// A mock CodeGenerator, used by command_line_interface_unittest.  This is in
+// its own file so that it can be used both directly and as a plugin.
+//
+// Generate() produces some output which can be checked by ExpectCalled().  The
+// generator can run in a different process (e.g. a plugin).
+//
+// If the parameter is "insert=NAMES", the MockCodeGenerator will insert lines
+// into the files generated by other MockCodeGenerators instead of creating
+// its own file.  NAMES is a comma-separated list of the names of those other
+// MockCodeGenerators.  If the parameter is "insert_endlines=NAMES", the
+// MockCodeGenerator will insert data guaranteed to contain more than one
+// endline into the files generated by NAMES.
+//
+// MockCodeGenerator will also modify its behavior slightly if the input file
+// contains a message type with one of the following names:
+//   MockCodeGenerator_Error:  Causes Generate() to return false and set the
+//     error message to "Saw message type MockCodeGenerator_Error."
+//   MockCodeGenerator_Exit:  Generate() prints "Saw message type
+//     MockCodeGenerator_Exit." to stderr and then calls exit(123).
+//   MockCodeGenerator_Abort:  Generate() prints "Saw message type
+//     MockCodeGenerator_Abort." to stderr and then calls abort().
+//   MockCodeGenerator_HasSourceCodeInfo:  Causes Generate() to abort after
+//     printing "Saw message type MockCodeGenerator_HasSourceCodeInfo: FOO." to
+//     stderr, where FOO is "1" if the supplied FileDescriptorProto has source
+//     code info, and "0" otherwise.
+//   MockCodeGenerator_Annotate:  Generate() will add annotations to its output
+//     that can later be verified with CheckGeneratedAnnotations.
+class MockCodeGenerator : public CodeGenerator {
+ public:
+  MockCodeGenerator(const std::string& name);
+  ~MockCodeGenerator() override;
+
+  // Expect (via gTest) that a MockCodeGenerator with the given name was called
+  // with the given parameters by inspecting the output location.
+  //
+  // |insertions| is a comma-separated list of names of MockCodeGenerators which
+  // should have inserted lines into this file.
+  // |parsed_file_list| is a comma-separated list of names of the files
+  // that are being compiled together in this run.
+  static void ExpectGenerated(const std::string& name,
+                              const std::string& parameter,
+                              const std::string& insertions,
+                              const std::string& file,
+                              const std::string& first_message_name,
+                              const std::string& parsed_file_list,
+                              const std::string& output_directory);
+
+  // Checks that the correct text ranges were annotated by the
+  // MockCodeGenerator_Annotate directive.
+  static void CheckGeneratedAnnotations(const std::string& name,
+                                        const std::string& file,
+                                        const std::string& output_directory);
+
+  // Get the name of the file which would be written by the given generator.
+  static std::string GetOutputFileName(const std::string& generator_name,
+                                       const FileDescriptor* file);
+  static std::string GetOutputFileName(const std::string& generator_name,
+                                       const std::string& file);
+
+  // implements CodeGenerator ----------------------------------------
+
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override;
+  void SuppressFeatures(uint64_t features);
+
+ private:
+  std::string name_;
+  uint64_t suppressed_features_ = 0;
+
+  static std::string GetOutputFileContent(const std::string& generator_name,
+                                          const std::string& parameter,
+                                          const FileDescriptor* file,
+                                          GeneratorContext* context);
+  static std::string GetOutputFileContent(
+      const std::string& generator_name, const std::string& parameter,
+      const std::string& file, const std::string& parsed_file_list,
+      const std::string& first_message_name);
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
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..ea8f394
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
@@ -0,0 +1,260 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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>
+#include <algorithm> // std::find()
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
+    : descriptor_(descriptor),
+      name_(EnumName(descriptor_)) {
+  // Track the names for the enum values, and if an alias overlaps a base
+  // value, skip making a name for it. Likewise if two alias overlap, the
+  // first one wins.
+  // The one gap in this logic is if two base values overlap, but for that
+  // to happen you have to have "Foo" and "FOO" or "FOO_BAR" and "FooBar",
+  // and if an enum has that, it is already going to be confusing and a
+  // compile error is just fine.
+  // The values are still tracked to support the reflection apis and
+  // TextFormat handing since they are different there.
+  std::set<std::string> value_names;
+
+  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);
+      value_names.insert(EnumValueName(value));
+    } else {
+      std::string value_name(EnumValueName(value));
+      if (value_names.find(value_name) != value_names.end()) {
+        alias_values_to_skip_.insert(value);
+      } else {
+        value_names.insert(value_name);
+      }
+    }
+    all_values_.push_back(value);
+  }
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::GenerateHeader(io::Printer* printer) {
+  std::string enum_comments;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    enum_comments = BuildCommentsString(location, true);
+  } else {
+    enum_comments = "";
+  }
+
+  printer->Print(
+      "#pragma mark - Enum $name$\n"
+      "\n",
+      "name", name_);
+
+  // Swift 5 included SE0192 "Handling Future Enum Cases"
+  //   https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
+  // Since a .proto file can get new values added to an enum at any time, they
+  // are effectively "non-frozen". Even in a proto3 syntax file where there is
+  // support for the unknown value, an edit to the file can always add a new
+  // value moving something from unknown to known. Since Swift is now ABI
+  // stable, it also means a binary could contain Swift compiled against one
+  // version of the .pbobjc.h file, but finally linked against an enum with
+  // more cases. So the Swift code will always have to treat ObjC Proto Enums
+  // as "non-frozen". The default behavior in SE0192 is for all objc enums to
+  // be "non-frozen" unless marked as otherwise, so this means this generation
+  // doesn't have to bother with the `enum_extensibility` attribute, as the
+  // default will be what is needed.
+
+  printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n",
+                 "comments", enum_comments,
+                 "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()),
+                 "name", name_);
+  printer->Indent();
+
+  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    // Include the unknown value.
+    printer->Print(
+      "/**\n"
+      " * Value used if any message's field encounters a value that is not defined\n"
+      " * by this enum. The message will also have C functions to get/set the rawValue\n"
+      " * of the field.\n"
+      " **/\n"
+      "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n",
+      "name", name_);
+  }
+  for (int i = 0; i < all_values_.size(); i++) {
+    if (alias_values_to_skip_.find(all_values_[i]) != alias_values_to_skip_.end()) {
+      continue;
+    }
+    if (all_values_[i]->GetSourceLocation(&location)) {
+      std::string comments = BuildCommentsString(location, true).c_str();
+      if (comments.length() > 0) {
+        if (i > 0) {
+          printer->Print("\n");
+        }
+        printer->Print(comments.c_str());
+      }
+    }
+
+    printer->Print(
+        "$name$$deprecated_attribute$ = $value$,\n",
+        "name", EnumValueName(all_values_[i]),
+        "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]),
+        "value", StrCat(all_values_[i]->number()));
+  }
+  printer->Outdent();
+  printer->Print(
+      "};\n"
+      "\n"
+      "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n"
+      "\n"
+      "/**\n"
+      " * Checks to see if the given value is defined by the enum or was not known at\n"
+      " * the time this source was generated.\n"
+      " **/\n"
+      "BOOL $name$_IsValidValue(int32_t value);\n"
+      "\n",
+      "name", name_);
+}
+
+void EnumGenerator::GenerateSource(io::Printer* printer) {
+  printer->Print(
+      "#pragma mark - Enum $name$\n"
+      "\n",
+      "name", name_);
+
+  // Note: For the TextFormat decode info, we can't use the enum value as
+  // the key because protocol buffer enums have 'allow_alias', which lets
+  // a value be used more than once. Instead, the index into the list of
+  // enum value descriptions is used. Note: start with -1 so the first one
+  // will be zero.
+  TextFormatDecodeData text_format_decode_data;
+  int enum_value_description_key = -1;
+  std::string text_blob;
+
+  for (int i = 0; i < all_values_.size(); i++) {
+    ++enum_value_description_key;
+    std::string short_name(EnumValueShortName(all_values_[i]));
+    text_blob += short_name + '\0';
+    if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) {
+      text_format_decode_data.AddString(enum_value_description_key, short_name,
+                                        all_values_[i]->name());
+    }
+  }
+
+  printer->Print(
+      "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n"
+      "  static _Atomic(GPBEnumDescriptor*) descriptor = nil;\n"
+      "  if (!descriptor) {\n",
+      "name", name_);
+
+  static const int kBytesPerLine = 40;  // allow for escaping
+  printer->Print(
+      "    static const char *valueNames =");
+  for (int i = 0; i < text_blob.size(); i += kBytesPerLine) {
+    printer->Print(
+        "\n        \"$data$\"",
+        "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine))));
+  }
+  printer->Print(
+      ";\n"
+      "    static const int32_t values[] = {\n");
+  for (int i = 0; i < all_values_.size(); i++) {
+    printer->Print("        $name$,\n",  "name", EnumValueName(all_values_[i]));
+  }
+  printer->Print("    };\n");
+
+  if (text_format_decode_data.num_entries() == 0) {
+    printer->Print(
+        "    GPBEnumDescriptor *worker =\n"
+        "        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+        "                                       valueNames:valueNames\n"
+        "                                           values:values\n"
+        "                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n"
+        "                                     enumVerifier:$name$_IsValidValue];\n",
+        "name", name_);
+    } else {
+      printer->Print(
+        "    static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
+        "    GPBEnumDescriptor *worker =\n"
+        "        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+        "                                       valueNames:valueNames\n"
+        "                                           values:values\n"
+        "                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n"
+        "                                     enumVerifier:$name$_IsValidValue\n"
+        "                              extraTextFormatInfo:extraTextFormatInfo];\n",
+        "name", name_,
+        "extraTextFormatInfo", CEscape(text_format_decode_data.Data()));
+    }
+    printer->Print(
+      "    GPBEnumDescriptor *expected = nil;\n"
+      "    if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {\n"
+      "      [worker release];\n"
+      "    }\n"
+      "  }\n"
+      "  return descriptor;\n"
+      "}\n\n");
+
+  printer->Print(
+      "BOOL $name$_IsValidValue(int32_t value__) {\n"
+      "  switch (value__) {\n",
+      "name", name_);
+
+  for (int i = 0; i < base_values_.size(); i++) {
+    printer->Print(
+        "    case $name$:\n",
+        "name", EnumValueName(base_values_[i]));
+  }
+
+  printer->Print(
+      "      return YES;\n"
+      "    default:\n"
+      "      return NO;\n"
+      "  }\n"
+      "}\n\n");
+}
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
new file mode 100644
index 0000000..1d5741a
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.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_OBJECTIVEC_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumGenerator {
+ public:
+  explicit EnumGenerator(const EnumDescriptor* descriptor);
+  ~EnumGenerator();
+
+  EnumGenerator(const EnumGenerator&) = delete;
+  EnumGenerator& operator=(const EnumGenerator&) = delete;
+
+  void GenerateHeader(io::Printer* printer);
+  void GenerateSource(io::Printer* printer);
+
+  const std::string& name() const { return name_; }
+
+ private:
+  const EnumDescriptor* descriptor_;
+  std::vector<const EnumValueDescriptor*> base_values_;
+  std::vector<const EnumValueDescriptor*> all_values_;
+  std::set<const EnumValueDescriptor*> alias_values_to_skip_;
+  const std::string name_;
+};
+
+}  // 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..6e0d69b
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
@@ -0,0 +1,151 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor,
+                      std::map<std::string, std::string>* variables) {
+  std::string type = EnumName(descriptor->enum_type());
+  (*variables)["storage_type"] = type;
+  // For non repeated fields, if it was defined in a different file, the
+  // property decls need to use "enum NAME" rather than just "NAME" to support
+  // the forward declaration of the enums.
+  if (!descriptor->is_repeated() &&
+      (descriptor->file() != descriptor->enum_type()->file())) {
+    (*variables)["property_type"] = "enum " + type;
+  }
+  (*variables)["enum_verifier"] = type + "_IsValidValue";
+  (*variables)["enum_desc_func"] = type + "_EnumDescriptor";
+
+  (*variables)["dataTypeSpecific_name"] = "enumDescFunc";
+  (*variables)["dataTypeSpecific_value"] = (*variables)["enum_desc_func"];
+
+  const Descriptor* msg_descriptor = descriptor->containing_type();
+  (*variables)["owning_message_class"] = ClassName(msg_descriptor);
+}
+}  // namespace
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor)
+    : SingleFieldGenerator(descriptor) {
+  SetEnumVariables(descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::GenerateCFunctionDeclarations(
+    io::Printer* printer) const {
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    return;
+  }
+
+  printer->Print(
+      variables_,
+      "/**\n"
+      " * Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n"
+      " * if the value was not defined by the enum at the time the code was generated.\n"
+      " **/\n"
+      "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n"
+      "/**\n"
+      " * Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n"
+      " * it to be set to a value that was not defined by the enum at the time the code\n"
+      " * was generated.\n"
+      " **/\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 GPBGetMessageRawEnumField(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"
+      "  GPBSetMessageRawEnumField(message, field, value);\n"
+      "}\n"
+      "\n");
+}
+
+void EnumFieldGenerator::DetermineForwardDeclarations(
+    std::set<std::string>* fwd_decls,
+    bool include_external_types) const {
+  SingleFieldGenerator::DetermineForwardDeclarations(
+      fwd_decls, include_external_types);
+  // If it is an enum defined in a different file (and not a WKT), 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 (include_external_types &&
+      descriptor_->file() != descriptor_->enum_type()->file() &&
+      !IsProtobufLibraryBundledProtoFile(descriptor_->enum_type()->file())) {
+    // Enum name is already in "storage_type".
+    const std::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::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  variables_["array_comment"] =
+      "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n";
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
new file mode 100644
index 0000000..f0d685c
--- /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);
+
+  EnumFieldGenerator(const EnumFieldGenerator&) = delete;
+  EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete;
+
+ public:
+  virtual void GenerateCFunctionDeclarations(
+      io::Printer* printer) const override;
+  virtual void GenerateCFunctionImplementations(
+      io::Printer* printer) const override;
+  virtual void DetermineForwardDeclarations(
+      std::set<std::string>* fwd_decls,
+      bool include_external_types) const override;
+
+ protected:
+  explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~EnumFieldGenerator();
+};
+
+class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ public:
+  virtual void FinishInitialization() override;
+
+ protected:
+  explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~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..9cebcb2
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.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 <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 std::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.
+    std::cerr << "error: Extension is a map<>!"
+         << " That used to be blocked by the compiler." << std::endl;
+    std::cerr.flush();
+    abort();
+  }
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) {
+  std::map<std::string, std::string> vars;
+  vars["method_name"] = method_name_;
+  if (IsRetainedName(method_name_)) {
+    vars["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
+  } else {
+    vars["storage_attribute"] = "";
+  }
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    vars["comments"] = BuildCommentsString(location, true);
+  } else {
+    vars["comments"] = "";
+  }
+  // Unlike normal message fields, check if the file for the extension was
+  // deprecated.
+  vars["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file());
+  printer->Print(vars,
+                 "$comments$"
+                 "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n");
+}
+
+void ExtensionGenerator::GenerateStaticVariablesInitialization(
+    io::Printer* printer) {
+  std::map<std::string, std::string> vars;
+  vars["root_class_and_method_name"] = root_class_and_method_name_;
+  const std::string containing_type = ClassName(descriptor_->containing_type());
+  vars["extended_type"] = ObjCClass(containing_type);
+  vars["number"] = StrCat(descriptor_->number());
+
+  std::vector<std::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(FLAGTYPE_EXTENSION, options);
+
+  ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
+  if (objc_type == OBJECTIVECTYPE_MESSAGE) {
+    std::string message_type = ClassName(descriptor_->message_type());
+    vars["type"] = ObjCClass(message_type);
+  } else {
+    vars["type"] = "Nil";
+  }
+
+  vars["default_name"] = GPBGenericValueFieldName(descriptor_);
+  if (descriptor_->is_repeated()) {
+    vars["default"] = "nil";
+  } else {
+    vars["default"] = DefaultValue(descriptor_);
+  }
+  std::string type = GetCapitalizedType(descriptor_);
+  vars["extension_type"] = std::string("GPBDataType") + type;
+
+  if (objc_type == OBJECTIVECTYPE_ENUM) {
+    vars["enum_desc_func_name"] =
+         EnumName(descriptor_->enum_type()) + "_EnumDescriptor";
+  } else {
+    vars["enum_desc_func_name"] = "NULL";
+  }
+
+  printer->Print(vars,
+                 "{\n"
+                 "  .defaultValue.$default_name$ = $default$,\n"
+                 "  .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n"
+                 "  .extendedClass.clazz = $extended_type$,\n"
+                 "  .messageOrGroupClass.clazz = $type$,\n"
+                 "  .enumDescriptorFunc = $enum_desc_func_name$,\n"
+                 "  .fieldNumber = $number$,\n"
+                 "  .dataType = $extension_type$,\n"
+                 "  .options = $options$,\n"
+                 "},\n");
+}
+
+void ExtensionGenerator::DetermineObjectiveCClassDefinitions(
+    std::set<std::string>* fwd_decls) {
+  std::string extended_type = ClassName(descriptor_->containing_type());
+  fwd_decls->insert(ObjCClassDeclaration(extended_type));
+  ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
+  if (objc_type == OBJECTIVECTYPE_MESSAGE) {
+    std::string message_type = ClassName(descriptor_->message_type());
+    fwd_decls->insert(ObjCClassDeclaration(message_type));
+  }
+}
+
+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..d412f4a
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class ExtensionGenerator {
+ public:
+  ExtensionGenerator(const std::string& root_class_name,
+                     const FieldDescriptor* descriptor);
+  ~ExtensionGenerator();
+
+  ExtensionGenerator(const ExtensionGenerator&) = delete;
+  ExtensionGenerator& operator=(const ExtensionGenerator&) = delete;
+
+  void GenerateMembersHeader(io::Printer* printer);
+  void GenerateStaticVariablesInitialization(io::Printer* printer);
+  void GenerateRegistrationSource(io::Printer* printer);
+  void DetermineObjectiveCClassDefinitions(std::set<std::string>* fwd_decls);
+
+ private:
+  std::string method_name_;
+  std::string root_class_and_method_name_;
+  const FieldDescriptor* descriptor_;
+};
+
+}  // 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..004ea19
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -0,0 +1,470 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <iostream>
+
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             std::map<std::string, std::string>* variables) {
+  std::string camel_case_name = FieldName(descriptor);
+  std::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 std::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, true);
+  } else {
+    (*variables)["comments"] = "\n";
+  }
+  const std::string& classname = ClassName(descriptor->containing_type());
+  (*variables)["classname"] = classname;
+  (*variables)["name"] = camel_case_name;
+  const std::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"] = StrCat(descriptor->number());
+  (*variables)["field_type"] = GetCapitalizedType(descriptor);
+  (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor);
+  std::vector<std::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");
+  }
+  // It will clear on a zero value if...
+  //  - not repeated/map
+  //  - doesn't have presence
+  bool clear_on_zero =
+      (!descriptor->is_repeated() && !descriptor->has_presence());
+  if (clear_on_zero) {
+    field_flags.push_back("GPBFieldClearHasIvarOnZero");
+  }
+
+  (*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
+
+  (*variables)["default"] = DefaultValue(descriptor);
+  (*variables)["default_name"] = GPBGenericValueFieldName(descriptor);
+
+  (*variables)["dataTypeSpecific_name"] = "clazz";
+  (*variables)["dataTypeSpecific_value"] = "Nil";
+
+  (*variables)["storage_offset_value"] =
+      "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")";
+  (*variables)["storage_offset_comment"] = "";
+
+  // Clear some common things so they can be set just when needed.
+  (*variables)["storage_attribute"] = "";
+}
+
+}  // namespace
+
+FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) {
+  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(
+    std::set<std::string>* fwd_decls,
+    bool include_external_types) const {
+  // Nothing
+}
+
+void FieldGenerator::DetermineObjectiveCClassDefinitions(
+    std::set<std::string>* fwd_decls) const {
+  // Nothing
+}
+
+void FieldGenerator::GenerateFieldDescription(
+    io::Printer* printer, bool include_default) const {
+  // Printed in the same order as the structure decl.
+  if (include_default) {
+    printer->Print(
+        variables_,
+        "{\n"
+        "  .defaultValue.$default_name$ = $default$,\n"
+        "  .core.name = \"$name$\",\n"
+        "  .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
+        "  .core.number = $field_number_name$,\n"
+        "  .core.hasIndex = $has_index$,\n"
+        "  .core.offset = $storage_offset_value$,$storage_offset_comment$\n"
+        "  .core.flags = $fieldflags$,\n"
+        "  .core.dataType = GPBDataType$field_type$,\n"
+        "},\n");
+  } else {
+    printer->Print(
+        variables_,
+        "{\n"
+        "  .name = \"$name$\",\n"
+        "  .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
+        "  .number = $field_number_name$,\n"
+        "  .hasIndex = $has_index$,\n"
+        "  .offset = $storage_offset_value$,$storage_offset_comment$\n"
+        "  .flags = $fieldflags$,\n"
+        "  .dataType = GPBDataType$field_type$,\n"
+        "},\n");
+  }
+}
+
+void FieldGenerator::SetRuntimeHasBit(int has_index) {
+  variables_["has_index"] = StrCat(has_index);
+}
+
+void FieldGenerator::SetNoHasBit(void) {
+  variables_["has_index"] = "GPBNoHasBit";
+}
+
+int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const {
+  return 0;
+}
+
+void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) {
+  // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+  // error cases, so it seems to be ok to use as a back door for errors.
+  std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." << std::endl;
+  std::cerr.flush();
+  abort();
+}
+
+void FieldGenerator::SetOneofIndexBase(int index_base) {
+  const OneofDescriptor* oneof = descriptor_->real_containing_oneof();
+  if (oneof != NULL) {
+    int index = oneof->index() + index_base;
+    // Flip the sign to mark it as a oneof.
+    variables_["has_index"] = StrCat(-index);
+  }
+}
+
+bool FieldGenerator::WantsHasProperty(void) const {
+  return descriptor_->has_presence() && !descriptor_->real_containing_oneof();
+}
+
+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$");
+  printer->Print(
+      variables_,
+      "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n"
+      "\n");
+  if (WantsHasProperty()) {
+    printer->Print(
+        variables_,
+        "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
+  }
+}
+
+void SingleFieldGenerator::GeneratePropertyImplementation(
+    io::Printer* printer) const {
+  if (WantsHasProperty()) {
+    printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n");
+  } else {
+    printer->Print(variables_, "@dynamic $name$;\n");
+  }
+}
+
+bool SingleFieldGenerator::RuntimeUsesHasBit(void) const {
+  if (descriptor_->real_containing_oneof()) {
+    // The oneof tracks what is set instead.
+    return false;
+  }
+  return true;
+}
+
+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$");
+  printer->Print(
+      variables_,
+      "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n");
+  if (WantsHasProperty()) {
+    printer->Print(
+        variables_,
+        "/** Test to see if @c $name$ has been set. */\n"
+        "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
+  }
+  if (IsInitName(variables_.find("name")->second)) {
+    // If property name starts with init we need to annotate it to get past ARC.
+    // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+    printer->Print(variables_,
+                   "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
+  }
+  printer->Print("\n");
+}
+
+RepeatedFieldGenerator::RepeatedFieldGenerator(
+    const FieldDescriptor* descriptor)
+    : ObjCObjFieldGenerator(descriptor) {
+  // Default to no comment and let the cases needing it fill it in.
+  variables_["array_comment"] = "";
+}
+
+RepeatedFieldGenerator::~RepeatedFieldGenerator() {}
+
+void RepeatedFieldGenerator::FinishInitialization(void) {
+  FieldGenerator::FinishInitialization();
+  if (variables_.find("array_property_type") == variables_.end()) {
+    variables_["array_property_type"] = variable("array_storage_type");
+  }
+}
+
+void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$array_storage_type$ *$name$;\n");
+}
+
+void RepeatedFieldGenerator::GeneratePropertyImplementation(
+    io::Printer* printer) const {
+  printer->Print(variables_, "@dynamic $name$, $name$_Count;\n");
+}
+
+void RepeatedFieldGenerator::GeneratePropertyDeclaration(
+    io::Printer* printer) const {
+
+  // Repeated fields don't need the has* properties, but they do expose a
+  // *Count (to check without autocreation).  So for the field property we need
+  // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for
+  // dealing with needing Objective C's rules around storage name conventions
+  // (init*, new*, etc.)
+
+  printer->Print(
+      variables_,
+      "$comments$"
+      "$array_comment$"
+      "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
+      "/** The number of items in @c $name$ without causing the array to be created. */\n"
+      "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
+  if (IsInitName(variables_.find("name")->second)) {
+    // If property name starts with init we need to annotate it to get past ARC.
+    // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+    printer->Print(variables_,
+                   "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
+  }
+  printer->Print("\n");
+}
+
+bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const {
+  return false;  // The array (or map/dict) having anything is what is used.
+}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+    : descriptor_(descriptor),
+      field_generators_(descriptor->field_count()),
+      extension_generators_(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];
+}
+
+int FieldGeneratorMap::CalculateHasBits(void) {
+  int total_bits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (field_generators_[i]->RuntimeUsesHasBit()) {
+      field_generators_[i]->SetRuntimeHasBit(total_bits);
+      ++total_bits;
+    } else {
+      field_generators_[i]->SetNoHasBit();
+    }
+    int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded();
+    if (extra_bits) {
+      field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits);
+      total_bits += extra_bits;
+    }
+  }
+  return total_bits;
+}
+
+void FieldGeneratorMap::SetOneofIndexBase(int index_base) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_[i]->SetOneofIndexBase(index_base);
+  }
+}
+
+bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (HasNonZeroDefaultValue(descriptor_->field(i))) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h
new file mode 100644
index 0000000..759ef80
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class FieldGenerator {
+ public:
+  static FieldGenerator* Make(const FieldDescriptor* field);
+
+  virtual ~FieldGenerator();
+
+  FieldGenerator(const FieldGenerator&) = delete;
+  FieldGenerator& operator=(const FieldGenerator&) = delete;
+
+  // Exposed for subclasses to fill in.
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0;
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0;
+
+  // Called by GenerateFieldDescription, exposed for classes that need custom
+  // generation.
+
+  // Exposed for subclasses to extend, base does nothing.
+  virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+  virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+
+  // Exposed for subclasses, should always call it on the parent class also.
+  virtual void DetermineForwardDeclarations(
+      std::set<std::string>* fwd_decls,
+      bool include_external_types) const;
+  virtual void DetermineObjectiveCClassDefinitions(
+      std::set<std::string>* fwd_decls) const;
+
+  // Used during generation, not intended to be extended by subclasses.
+  void GenerateFieldDescription(
+      io::Printer* printer, bool include_default) const;
+  void GenerateFieldNumberConstant(io::Printer* printer) const;
+
+  // Exposed to get and set the has bits information.
+  virtual bool RuntimeUsesHasBit(void) const = 0;
+  void SetRuntimeHasBit(int has_index);
+  void SetNoHasBit(void);
+  virtual int ExtraRuntimeHasBitsNeeded(void) const;
+  virtual void SetExtraRuntimeHasBitsBase(int index_base);
+  void SetOneofIndexBase(int index_base);
+
+  std::string variable(const char* key) const {
+    return variables_.find(key)->second;
+  }
+
+  bool needs_textformat_name_support() const {
+    const std::string& field_flags = variable("fieldflags");
+    return field_flags.find("GPBFieldTextFormatNameCustom") !=
+           std::string::npos;
+  }
+  std::string generated_objc_name() const { return variable("name"); }
+  std::string raw_field_name() const { return variable("raw_field_name"); }
+
+ protected:
+  explicit FieldGenerator(const FieldDescriptor* descriptor);
+
+  virtual void FinishInitialization(void);
+  bool WantsHasProperty(void) const;
+
+  const FieldDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+};
+
+class SingleFieldGenerator : public FieldGenerator {
+ public:
+  virtual ~SingleFieldGenerator();
+
+  SingleFieldGenerator(const SingleFieldGenerator&) = delete;
+  SingleFieldGenerator& operator=(const SingleFieldGenerator&) = delete;
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const override;
+
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const override;
+
+  virtual bool RuntimeUsesHasBit(void) const override;
+
+ protected:
+  explicit SingleFieldGenerator(const FieldDescriptor* descriptor);
+};
+
+// Subclass with common support for when the field ends up as an ObjC Object.
+class ObjCObjFieldGenerator : public SingleFieldGenerator {
+ public:
+  virtual ~ObjCObjFieldGenerator();
+
+  ObjCObjFieldGenerator(const ObjCObjFieldGenerator&) = delete;
+  ObjCObjFieldGenerator& operator=(const ObjCObjFieldGenerator&) = delete;
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const override;
+
+ protected:
+  explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor);
+};
+
+class RepeatedFieldGenerator : public ObjCObjFieldGenerator {
+ public:
+  virtual ~RepeatedFieldGenerator();
+
+  RepeatedFieldGenerator(const RepeatedFieldGenerator&) = delete;
+  RepeatedFieldGenerator& operator=(const RepeatedFieldGenerator&) = delete;
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const override;
+
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const override;
+
+  virtual bool RuntimeUsesHasBit(void) const override;
+
+ protected:
+  explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor);
+  virtual void FinishInitialization(void) override;
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+  explicit FieldGeneratorMap(const Descriptor* descriptor);
+  ~FieldGeneratorMap();
+
+  FieldGeneratorMap(const FieldGeneratorMap&) = delete;
+  FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete;
+
+  const FieldGenerator& get(const FieldDescriptor* field) const;
+  const FieldGenerator& get_extension(int index) const;
+
+  // Assigns the has bits and returns the number of bits needed.
+  int CalculateHasBits(void);
+
+  void SetOneofIndexBase(int index_base);
+
+  // Check if any field of this message has a non zero default.
+  bool DoesAnyFieldHaveNonZeroDefault(void) const;
+
+ private:
+  const Descriptor* descriptor_;
+  std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
+  std::vector<std::unique_ptr<FieldGenerator>> extension_generators_;
+};
+
+}  // 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..50b4285
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -0,0 +1,681 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_helpers.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 <algorithm> // std::find()
+#include <iostream>
+#include <sstream>
+
+// 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 {
+
+// This is also found in GPBBootstrap.h, and needs to be kept in sync.
+const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30004;
+
+const char* kHeaderExtension = ".pbobjc.h";
+
+std::string BundledFileName(const FileDescriptor* file) {
+  return "GPB" + FilePathBasename(file) + kHeaderExtension;
+}
+
+// Checks if a message contains any enums definitions (on the message or
+// a nested message under it).
+bool MessageContainsEnums(const Descriptor* message) {
+  if (message->enum_type_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    if (MessageContainsEnums(message->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Checks if a message contains any extension definitions (on the message or
+// a nested message under it).
+bool MessageContainsExtensions(const Descriptor* message) {
+  if (message->extension_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    if (MessageContainsExtensions(message->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Checks if the file contains any enum definitions (at the root or
+// nested under a message).
+bool FileContainsEnums(const FileDescriptor* file) {
+  if (file->enum_type_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (MessageContainsEnums(file->message_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Checks if the file contains any extensions definitions (at the root or
+// nested under a message).
+bool FileContainsExtensions(const FileDescriptor* file) {
+  if (file->extension_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (MessageContainsExtensions(file->message_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
+  for (int i = 0; i < file->dependency_count(); i++) {
+    if (dep == file->dependency(i)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+struct FileDescriptorsOrderedByName {
+  inline bool operator()(const FileDescriptor* a,
+                         const FileDescriptor* b) const {
+    return a->name() < b->name();
+  }
+};
+
+}  // namespace
+
+FileGenerator::CommonState::CommonState() { }
+
+const FileGenerator::CommonState::MinDepsEntry&
+FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal(
+    const FileDescriptor* file) {
+  auto it = deps_info_cache_.find(file);
+  if (it != deps_info_cache_.end()) {
+    return it->second;
+  }
+
+  std::set<const FileDescriptor*> min_deps_collector;
+  std::set<const FileDescriptor*> covered_deps_collector;
+  std::set<const FileDescriptor*> to_prune;
+  for (int i = 0; i < file->dependency_count(); i++) {
+    const FileDescriptor* dep = file->dependency(i);
+    MinDepsEntry dep_info =
+        CollectMinimalFileDepsContainingExtensionsInternal(dep);
+
+    // Everything the dep covered, this file will also cover.
+    covered_deps_collector.insert(dep_info.covered_deps.begin(), dep_info.covered_deps.end());
+    // Prune everything from the dep's covered list in case another dep lists it
+    // as a min dep.
+    to_prune.insert(dep_info.covered_deps.begin(), dep_info.covered_deps.end());
+
+    // Does the dep have any extensions...
+    if (dep_info.has_extensions) {
+      // Yes -> Add this file, prune its min_deps and add them to the covered deps.
+      min_deps_collector.insert(dep);
+      to_prune.insert(dep_info.min_deps.begin(), dep_info.min_deps.end());
+      covered_deps_collector.insert(dep_info.min_deps.begin(), dep_info.min_deps.end());
+    } else {
+      // No -> Just use its min_deps.
+      min_deps_collector.insert(dep_info.min_deps.begin(), dep_info.min_deps.end());
+    }
+  }
+
+  const bool file_has_exts = FileContainsExtensions(file);
+
+  // Fast path: if nothing to prune or there was only one dep, the prune work is
+  // a waste, skip it.
+  if (to_prune.empty() || file->dependency_count() == 1) {
+    return deps_info_cache_.insert(
+        {file, {file_has_exts, min_deps_collector, covered_deps_collector}}).first->second;
+  }
+
+  std::set<const FileDescriptor*> min_deps;
+  std::copy_if(min_deps_collector.begin(), min_deps_collector.end(),
+               std::inserter(min_deps, min_deps.end()),
+               [&](const FileDescriptor* value){
+    return to_prune.find(value) == to_prune.end();
+  });
+  return deps_info_cache_.insert(
+      {file, {file_has_exts, min_deps, covered_deps_collector}}).first->second;
+}
+
+// Collect the deps of the given file that contain extensions. This can be used to
+// create the chain of roots that need to be wired together.
+//
+// NOTE: If any changes are made to this and the supporting functions, you will
+// need to manually validate what the generated code is for the test files:
+//   objectivec/Tests/unittest_extension_chain_*.proto
+// There are comments about what the expected code should be line and limited
+// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
+// specifically).
+const std::vector<const FileDescriptor*>
+FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensions(
+    const FileDescriptor* file) {
+  std::set<const FileDescriptor*> min_deps =
+    CollectMinimalFileDepsContainingExtensionsInternal(file).min_deps;
+  // Sort the list since pointer order isn't stable across runs.
+  std::vector<const FileDescriptor*> result(min_deps.begin(), min_deps.end());
+  std::sort(result.begin(), result.end(), FileDescriptorsOrderedByName());
+  return result;
+}
+
+FileGenerator::FileGenerator(const FileDescriptor* file,
+                             const GenerationOptions& generation_options,
+                             CommonState& common_state)
+    : file_(file),
+      generation_options_(generation_options),
+      common_state_(common_state),
+      root_class_name_(FileClassName(file)),
+      is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)) {
+  for (int i = 0; i < file_->enum_type_count(); i++) {
+    EnumGenerator* generator = new EnumGenerator(file_->enum_type(i));
+    enum_generators_.emplace_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_.emplace_back(generator);
+  }
+  for (int i = 0; i < file_->extension_count(); i++) {
+    ExtensionGenerator* generator =
+        new ExtensionGenerator(root_class_name_, file_->extension(i));
+    extension_generators_.emplace_back(generator);
+  }
+}
+
+FileGenerator::~FileGenerator() {}
+
+void FileGenerator::GenerateHeader(io::Printer* printer) {
+  std::vector<std::string> headers;
+  // Generated files bundled with the library get minimal imports, everything
+  // else gets the wrapper so everything is usable.
+  if (is_bundled_proto_) {
+    headers.push_back("GPBDescriptor.h");
+    headers.push_back("GPBMessage.h");
+    headers.push_back("GPBRootObject.h");
+    for (int i = 0; i < file_->dependency_count(); i++) {
+      const std::string header_name = BundledFileName(file_->dependency(i));
+      headers.push_back(header_name);
+    }
+  } else {
+    headers.push_back("GPBProtocolBuffers.h");
+  }
+  PrintFileRuntimePreamble(printer, headers);
+
+  // Add some verification that the generated code matches the source the
+  // code is being compiled with.
+  // NOTE: This captures the raw numeric values at the time the generator was
+  // compiled, since that will be the versions for the ObjC runtime at that
+  // time.  The constants in the generated code will then get their values at
+  // at compile time (so checking against the headers being used to compile).
+  printer->Print(
+      "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n"
+      "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n"
+      "#endif\n"
+      "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n"
+      "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n"
+      "#endif\n"
+      "\n",
+      "google_protobuf_objc_version", StrCat(GOOGLE_PROTOBUF_OBJC_VERSION));
+
+  // The bundled protos (WKTs) don't use of forward declarations.
+  bool headers_use_forward_declarations =
+      generation_options_.headers_use_forward_declarations && !is_bundled_proto_;
+
+  {
+    ImportWriter import_writer(
+        generation_options_.generate_for_named_framework,
+        generation_options_.named_framework_to_proto_path_mappings_path,
+        generation_options_.runtime_import_prefix,
+        /* include_wkt_imports = */ false);
+    const std::string header_extension(kHeaderExtension);
+    if (headers_use_forward_declarations) {
+      // #import any headers for "public imports" in the proto file.
+      for (int i = 0; i < file_->public_dependency_count(); i++) {
+        import_writer.AddFile(file_->public_dependency(i), header_extension);
+      }
+    } else {
+      for (int i = 0; i < file_->dependency_count(); i++) {
+        import_writer.AddFile(file_->dependency(i), header_extension);
+      }
+    }
+    import_writer.Print(printer);
+  }
+
+  // Note:
+  //  deprecated-declarations suppression is only needed if some place in this
+  //    proto file is something deprecated or if it references something from
+  //    another file that is deprecated.
+  printer->Print(
+      "// @@protoc_insertion_point(imports)\n"
+      "\n"
+      "#pragma clang diagnostic push\n"
+      "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
+      "\n"
+      "CF_EXTERN_C_BEGIN\n"
+      "\n");
+
+  std::set<std::string> fwd_decls;
+  for (const auto& generator : message_generators_) {
+    generator->DetermineForwardDeclarations(
+        &fwd_decls,
+        /* include_external_types = */ headers_use_forward_declarations);
+  }
+  for (std::set<std::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 (const auto& generator : enum_generators_) {
+    generator->GenerateHeader(printer);
+  }
+
+  for (const auto& generator : message_generators_) {
+    generator->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"
+      "/**\n"
+      " * Exposes the extension registry for this file.\n"
+      " *\n"
+      " * The base class provides:\n"
+      " * @code\n"
+      " *   + (GPBExtensionRegistry *)extensionRegistry;\n"
+      " * @endcode\n"
+      " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
+      " * this file and all files that it depends on.\n"
+      " **/\n"
+      "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n"
+      "@end\n"
+      "\n",
+      "root_class_name", root_class_name_);
+
+  if (!extension_generators_.empty()) {
+    // 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 (const auto& generator : extension_generators_) {
+      generator->GenerateMembersHeader(printer);
+    }
+
+    printer->Print("@end\n\n");
+  }  // !extension_generators_.empty()
+
+  for (const auto& generator : message_generators_) {
+    generator->GenerateMessageHeader(printer);
+  }
+
+  printer->Print(
+      "NS_ASSUME_NONNULL_END\n"
+      "\n"
+      "CF_EXTERN_C_END\n"
+      "\n"
+      "#pragma clang diagnostic pop\n"
+      "\n"
+      "// @@protoc_insertion_point(global_scope)\n");
+}
+
+void FileGenerator::GenerateSource(io::Printer* printer) {
+  // #import the runtime support.
+  std::vector<std::string> headers;
+  headers.push_back("GPBProtocolBuffers_RuntimeSupport.h");
+  if (is_bundled_proto_) {
+    headers.push_back(BundledFileName(file_));
+  }
+  PrintFileRuntimePreamble(printer, headers);
+
+  // Enums use atomic in the generated code, so add the system import as needed.
+  if (FileContainsEnums(file_)) {
+    printer->Print(
+        "#import <stdatomic.h>\n"
+        "\n");
+  }
+
+  std::vector<const FileDescriptor*> deps_with_extensions =
+    common_state_.CollectMinimalFileDepsContainingExtensions(file_);
+
+  // The bundled protos (WKTs) don't use of forward declarations.
+  bool headers_use_forward_declarations =
+      generation_options_.headers_use_forward_declarations && !is_bundled_proto_;
+
+  {
+    ImportWriter import_writer(
+        generation_options_.generate_for_named_framework,
+        generation_options_.named_framework_to_proto_path_mappings_path,
+        generation_options_.runtime_import_prefix,
+        /* include_wkt_imports = */ false);
+    const std::string header_extension(kHeaderExtension);
+
+    // #import the header for this proto file.
+    import_writer.AddFile(file_, header_extension);
+
+    if (headers_use_forward_declarations) {
+      // #import the headers for anything that a plain dependency of this proto
+      // file (that means they were just an include, not a "public" include).
+      std::set<std::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 FileDescriptor *dep = file_->dependency(i);
+        bool public_import = (public_import_names.count(dep->name()) != 0);
+        if (!public_import) {
+          import_writer.AddFile(dep, header_extension);
+        }
+      }
+    }
+
+    // If any indirect dependency provided extensions, it needs to be directly
+    // imported so it can get merged into the root's extensions registry.
+    // See the Note by CollectMinimalFileDepsContainingExtensions before
+    // changing this.
+    for (std::vector<const FileDescriptor*>::iterator iter =
+             deps_with_extensions.begin();
+         iter != deps_with_extensions.end(); ++iter) {
+      if (!IsDirectDependency(*iter, file_)) {
+        import_writer.AddFile(*iter, header_extension);
+      }
+    }
+
+    import_writer.Print(printer);
+  }
+
+  bool includes_oneof = false;
+  for (const auto& generator : message_generators_) {
+    if (generator->IncludesOneOfDefinition()) {
+      includes_oneof = true;
+      break;
+    }
+  }
+
+  std::set<std::string> fwd_decls;
+  for (const auto& generator : message_generators_) {
+    generator->DetermineObjectiveCClassDefinitions(&fwd_decls);
+  }
+  for (const auto& generator : extension_generators_) {
+    generator->DetermineObjectiveCClassDefinitions(&fwd_decls);
+  }
+
+  // Note:
+  //  deprecated-declarations suppression is only needed if some place in this
+  //    proto file is something deprecated or if it references something from
+  //    another file that is deprecated.
+  //  dollar-in-identifier-extension is needed because we use references to
+  //    objc class names that have $ in identifiers.
+  printer->Print(
+      "// @@protoc_insertion_point(imports)\n"
+      "\n"
+      "#pragma clang diagnostic push\n"
+      "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n");
+  if (includes_oneof) {
+    // The generated code for oneof's uses direct ivar access, suppress the
+    // warning in case developer turn that on in the context they compile the
+    // generated code.
+    printer->Print(
+        "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n");
+  }
+  if (!fwd_decls.empty()) {
+    printer->Print(
+      "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n");
+  }
+  printer->Print(
+      "\n");
+  if (!fwd_decls.empty()) {
+    printer->Print(
+        "#pragma mark - Objective C Class declarations\n"
+        "// Forward declarations of Objective C classes that we can use as\n"
+        "// static values in struct initializers.\n"
+        "// We don't use [Foo class] because it is not a static value.\n");
+  }
+  for (const auto& i : fwd_decls) {
+    printer->Print("$value$\n", "value", i);
+  }
+  if (!fwd_decls.empty()) {
+    printer->Print("\n");
+  }
+  printer->Print(
+      "#pragma mark - $root_class_name$\n"
+      "\n"
+      "@implementation $root_class_name$\n\n",
+      "root_class_name", root_class_name_);
+
+  const bool file_contains_extensions = FileContainsExtensions(file_);
+
+  // If there were any extensions or this file has any dependencies, output
+  // a registry to override to create the file specific registry.
+  if (file_contains_extensions || !deps_with_extensions.empty()) {
+    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"
+        "    GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"
+        "    registry = [[GPBExtensionRegistry alloc] init];\n");
+
+    printer->Indent();
+    printer->Indent();
+
+    if (file_contains_extensions) {
+      printer->Print(
+          "static GPBExtensionDescription descriptions[] = {\n");
+      printer->Indent();
+      for (const auto& generator : extension_generators_) {
+        generator->GenerateStaticVariablesInitialization(printer);
+      }
+      for (const auto& generator : message_generators_) {
+        generator->GenerateStaticVariablesInitialization(printer);
+      }
+      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"
+          "                                                     usesClassRefs:YES];\n"
+          "  [registry addExtension:extension];\n"
+          "  [self globallyRegisterExtension:extension];\n"
+          "  [extension release];\n"
+          "}\n");
+    }
+
+    if (deps_with_extensions.empty()) {
+      printer->Print(
+          "// None of the imports (direct or indirect) defined extensions, so no need to add\n"
+          "// them to this registry.\n");
+    } else {
+      printer->Print(
+          "// Merge in the imports (direct or indirect) that defined extensions.\n");
+      for (std::vector<const FileDescriptor*>::iterator iter =
+               deps_with_extensions.begin();
+           iter != deps_with_extensions.end(); ++iter) {
+        const std::string root_class_name(FileClassName((*iter)));
+        printer->Print(
+            "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
+            "dependency", root_class_name);
+      }
+    }
+
+    printer->Outdent();
+    printer->Outdent();
+
+    printer->Print(
+        "  }\n"
+        "  return registry;\n"
+        "}\n");
+  } else {
+    if (file_->dependency_count() > 0) {
+      printer->Print(
+          "// No extensions in the file and none of the imports (direct or indirect)\n"
+          "// defined extensions, so no need to generate +extensionRegistry.\n");
+    } else {
+      printer->Print(
+          "// No extensions in the file and no imports, so no need to generate\n"
+          "// +extensionRegistry.\n");
+    }
+  }
+
+  printer->Print("\n@end\n\n");
+
+  // File descriptor only needed if there are messages to use it.
+  if (!message_generators_.empty()) {
+    std::map<std::string, std::string> vars;
+    vars["root_class_name"] = root_class_name_;
+    vars["package"] = file_->package();
+    vars["objc_prefix"] = FileClassPrefix(file_);
+    switch (file_->syntax()) {
+      case FileDescriptor::SYNTAX_UNKNOWN:
+        vars["syntax"] = "GPBFileSyntaxUnknown";
+        break;
+      case FileDescriptor::SYNTAX_PROTO2:
+        vars["syntax"] = "GPBFileSyntaxProto2";
+        break;
+      case FileDescriptor::SYNTAX_PROTO3:
+        vars["syntax"] = "GPBFileSyntaxProto3";
+        break;
+    }
+    printer->Print(vars,
+        "#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"
+        "    GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n");
+    if (!vars["objc_prefix"].empty()) {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                 objcPrefix:@\"$objc_prefix$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    } else {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    }
+    printer->Print(
+        "  }\n"
+        "  return descriptor;\n"
+        "}\n"
+        "\n");
+  }
+
+  for (const auto& generator : enum_generators_) {
+    generator->GenerateSource(printer);
+  }
+  for (const auto& generator : message_generators_) {
+    generator->GenerateSource(printer);
+  }
+
+  printer->Print(
+    "\n"
+    "#pragma clang diagnostic pop\n"
+    "\n"
+    "// @@protoc_insertion_point(global_scope)\n");
+}
+
+// Helper to print the import of the runtime support at the top of generated
+// files. This currently only supports the runtime coming from a framework
+// as defined by the official CocoaPod.
+void FileGenerator::PrintFileRuntimePreamble(
+    io::Printer* printer,
+    const std::vector<std::string>& headers_to_import) const {
+  printer->Print(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n",
+      "filename", file_->name());
+
+  if (is_bundled_proto_) {
+    // This is basically a clone of ImportWriter::PrintRuntimeImports() but
+    // without the CPP symbol gate, since within the bundled files, that isn't
+    // needed.
+    std::string import_prefix = generation_options_.runtime_import_prefix;
+    if (!import_prefix.empty()) {
+      import_prefix += "/";
+    }
+    for (const auto& header : headers_to_import) {
+      printer->Print(
+          "#import \"$import_prefix$$header$\"\n",
+          "import_prefix", import_prefix,
+          "header", header);
+    }
+  } else {
+    ImportWriter::PrintRuntimeImports(
+        printer, headers_to_import, generation_options_.runtime_import_prefix, true);
+  }
+
+  printer->Print("\n");
+}
+
+}  // 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..ef49cf8
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -0,0 +1,115 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumGenerator;
+class ExtensionGenerator;
+class MessageGenerator;
+
+class FileGenerator {
+ public:
+  struct GenerationOptions {
+    GenerationOptions()
+      // TODO(thomasvl): Eventually flip this default to false for better
+      // interop with Swift if proto usages span modules made from ObjC sources.
+      : headers_use_forward_declarations(true) {}
+    std::string generate_for_named_framework;
+    std::string named_framework_to_proto_path_mappings_path;
+    std::string runtime_import_prefix;
+    bool headers_use_forward_declarations;
+  };
+
+  // Wrapper for some common state that is shared between file generations to
+  // improve performance when more than one file is generated at a time.
+  struct CommonState {
+    CommonState();
+
+    const std::vector<const FileDescriptor*>
+    CollectMinimalFileDepsContainingExtensions(const FileDescriptor* file);
+
+   private:
+    struct MinDepsEntry {
+      bool has_extensions;
+      std::set<const FileDescriptor*> min_deps;
+      // `covered_deps` are the transtive deps of `min_deps_w_exts` that also
+      // have extensions.
+      std::set<const FileDescriptor*> covered_deps;
+    };
+    const MinDepsEntry& CollectMinimalFileDepsContainingExtensionsInternal(const FileDescriptor* file);
+    std::map<const FileDescriptor*, MinDepsEntry> deps_info_cache_;
+  };
+
+  FileGenerator(const FileDescriptor* file,
+                const GenerationOptions& generation_options,
+                CommonState& common_state);
+  ~FileGenerator();
+
+  FileGenerator(const FileGenerator&) = delete;
+  FileGenerator& operator=(const FileGenerator&) = delete;
+
+  void GenerateSource(io::Printer* printer);
+  void GenerateHeader(io::Printer* printer);
+
+ private:
+  const FileDescriptor* file_;
+  const GenerationOptions& generation_options_;
+  CommonState& common_state_;
+  std::string root_class_name_;
+  bool is_bundled_proto_;
+
+  std::vector<std::unique_ptr<EnumGenerator>> enum_generators_;
+  std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
+  std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_;
+
+  void PrintFileRuntimePreamble(
+      io::Printer* printer,
+      const std::vector<std::string>& headers_to_import) const;
+};
+
+}  // 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..9dccf14
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -0,0 +1,301 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <unordered_set>
+#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 {
+
+namespace {
+
+// Convert a string with "yes"/"no" (case insensitive) to a boolean, returning
+// true/false for if the input string was a valid value. If the input string is
+// invalid, `result` is unchanged.
+bool StringToBool(const std::string& value, bool* result) {
+  std::string upper_value(value);
+  UpperString(&upper_value);
+  if (upper_value == "NO") {
+    *result = false;
+    return true;
+  }
+  if (upper_value == "YES") {
+    *result = true;
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+ObjectiveCGenerator::ObjectiveCGenerator() {}
+
+ObjectiveCGenerator::~ObjectiveCGenerator() {}
+
+bool ObjectiveCGenerator::HasGenerateAll() const {
+  return true;
+}
+
+bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
+                                   const std::string& parameter,
+                                   GeneratorContext* context,
+                                   std::string* error) const {
+  *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
+  return false;
+}
+
+bool ObjectiveCGenerator::GenerateAll(
+    const std::vector<const FileDescriptor*>& files,
+    const std::string& parameter, GeneratorContext* context,
+    std::string* error) const {
+  // -----------------------------------------------------------------
+  // Parse generator options. These options are passed to the compiler using the
+  // --objc_opt flag. The options are passed as a comma separated list of
+  // options along with their values. If the option appears multiple times, only
+  // the last value will be considered.
+  //
+  // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework
+
+  Options validation_options;
+  FileGenerator::GenerationOptions generation_options;
+
+  std::vector<std::pair<std::string, std::string> > options;
+  ParseGeneratorParameter(parameter, &options);
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "expected_prefixes_path") {
+      // Path to find a file containing the expected prefixes
+      // (objc_class_prefix "PREFIX") for proto packages (package NAME). The
+      // generator will then issue warnings/errors if in the proto files being
+      // generated the option is not listed/wrong/etc in the file.
+      //
+      // The format of the file is:
+      //   - An entry is a line of "package=prefix".
+      //   - Comments start with "#".
+      //   - A comment can go on a line after a expected package/prefix pair.
+      //     (i.e. - "package=prefix # comment")
+      //   - For files that do NOT have a proto package (not recommended), an
+      //     entry can be made as "no_package:PATH=prefix", where PATH is the
+      //     path for the .proto file.
+      //
+      // There is no validation that the prefixes are good prefixes, it is
+      // assumed that they are when you create the file.
+      validation_options.expected_prefixes_path = options[i].second;
+    } else if (options[i].first == "expected_prefixes_suppressions") {
+      // A semicolon delimited string that lists the paths of .proto files to
+      // exclude from the package prefix validations (expected_prefixes_path).
+      // This is provided as an "out", to skip some files being checked.
+      for (StringPiece split_piece : Split(
+               options[i].second, ";", true)) {
+        validation_options.expected_prefixes_suppressions.push_back(
+            std::string(split_piece));
+      }
+    } else if (options[i].first == "prefixes_must_be_registered") {
+      // If objc prefix file option value must be registered to be used. This
+      // option has no meaning if an "expected_prefixes_path" isn't set. The
+      // available options are:
+      //   "no": They don't have to be registered.
+      //   "yes": They must be registered and an error will be raised if a files
+      //     tried to use a prefix that isn't registered.
+      // Default is "no".
+      if (!StringToBool(options[i].second,
+                        &validation_options.prefixes_must_be_registered)) {
+        *error = "error: Unknown value for prefixes_must_be_registered: " + options[i].second;
+        return false;
+      }
+    } else if (options[i].first == "require_prefixes") {
+      // If every file must have an objc prefix file option to be used. The
+      // available options are:
+      //   "no": Files can be generated without the prefix option.
+      //   "yes": Files must have the objc prefix option, and an error will be
+      //     raised if a files doesn't have one.
+      // Default is "no".
+      if (!StringToBool(options[i].second,
+                        &validation_options.require_prefixes)) {
+        *error = "error: Unknown value for require_prefixes: " + options[i].second;
+        return false;
+      }
+    } else if (options[i].first == "generate_for_named_framework") {
+      // The name of the framework that protos are being generated for. This
+      // will cause the #import statements to be framework based using this
+      // name (i.e. - "#import <NAME/proto.pbobjc.h>).
+      //
+      // NOTE: If this option is used with
+      // named_framework_to_proto_path_mappings_path, then this is effectively
+      // the "default" framework name used for everything that wasn't mapped by
+      // the mapping file.
+      generation_options.generate_for_named_framework = options[i].second;
+    } else if (options[i].first == "named_framework_to_proto_path_mappings_path") {
+      // Path to find a file containing the list of framework names and proto
+      // files. The generator uses this to decide if a proto file
+      // referenced should use a framework style import vs. a user level import
+      // (#import <FRAMEWORK/file.pbobjc.h> vs #import "dir/file.pbobjc.h").
+      //
+      // The format of the file is:
+      //   - An entry is a line of "frameworkName: file.proto, dir/file2.proto".
+      //   - Comments start with "#".
+      //   - A comment can go on a line after a expected package/prefix pair.
+      //     (i.e. - "frameworkName: file.proto # comment")
+      //
+      // Any number of files can be listed for a framework, just separate them
+      // with commas.
+      //
+      // There can be multiple lines listing the same frameworkName in case it
+      // has a lot of proto files included in it; having multiple lines makes
+      // things easier to read. If a proto file is not configured in the
+      // mappings file, it will use the default framework name if one was passed
+      // with generate_for_named_framework, or the relative path to it's include
+      // path otherwise.
+      generation_options.named_framework_to_proto_path_mappings_path = options[i].second;
+    } else if (options[i].first == "runtime_import_prefix") {
+      // Path to use as a prefix on #imports of runtime provided headers in the
+      // generated files. When integrating ObjC protos into a build system,
+      // this can be used to avoid having to add the runtime directory to the
+      // header search path since the generate #import will be more complete.
+      generation_options.runtime_import_prefix = StripSuffixString(options[i].second, "/");
+    } else if (options[i].first == "package_to_prefix_mappings_path") {
+      // Path to use for when loading the objc class prefix mappings to use.
+      // The `objc_class_prefix` file option is always honored first if one is present.
+      // This option also has precedent over the use_package_as_prefix option.
+      //
+      // The format of the file is:
+      //   - An entry is a line of "package=prefix".
+      //   - Comments start with "#".
+      //   - A comment can go on a line after a expected package/prefix pair.
+      //     (i.e. - "package=prefix # comment")
+      //   - For files that do NOT have a proto package (not recommended), an
+      //     entry can be made as "no_package:PATH=prefix", where PATH is the
+      //     path for the .proto file.
+      //
+      SetPackageToPrefixMappingsPath(options[i].second);
+    } else if (options[i].first == "use_package_as_prefix") {
+      // Controls how the symbols should be prefixed to avoid symbols
+      // collisions. The objc_class_prefix file option is always honored, this
+      // is just what to do if that isn't set. The available options are:
+      //   "no": Not prefixed (the existing mode).
+      //   "yes": Make a prefix out of the proto package.
+      bool value = false;
+      if (StringToBool(options[i].second, &value)) {
+        SetUseProtoPackageAsDefaultPrefix(value);
+      } else {
+        *error = "error: Unknown use_package_as_prefix: " + options[i].second;
+        return false;
+      }
+    } else if (options[i].first == "proto_package_prefix_exceptions_path") {
+      // Path to find a file containing the list of proto package names that are
+      // exceptions when use_package_as_prefix is enabled. This can be used to
+      // migrate packages one at a time to use_package_as_prefix since there
+      // are likely code updates needed with each one.
+      //
+      // The format of the file is:
+      //   - An entry is a line of "proto.package.name".
+      //   - Comments start with "#".
+      //   - A comment can go on a line after a expected package/prefix pair.
+      //     (i.e. - "some.proto.package # comment")
+      SetProtoPackagePrefixExceptionList(options[i].second);
+    } else if (options[i].first == "headers_use_forward_declarations") {
+      if (!StringToBool(options[i].second,
+                        &generation_options.headers_use_forward_declarations)) {
+        *error = "error: Unknown value for headers_use_forward_declarations: " + options[i].second;
+        return false;
+      }
+    } else {
+      *error = "error: Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  // These are not official generation options and could be removed/changed in
+  // the future and doing that won't count as a breaking change.
+  bool headers_only = getenv("GPB_OBJC_HEADERS_ONLY") != NULL;
+  std::unordered_set<std::string> skip_impls;
+  if (getenv("GPB_OBJC_SKIP_IMPLS_FILE") != NULL) {
+    std::ifstream skip_file(getenv("GPB_OBJC_SKIP_IMPLS_FILE"));
+    if (skip_file.is_open()) {
+      std::string line;
+      while (std::getline(skip_file, line)) {
+        skip_impls.insert(line);
+      }
+    } else {
+      *error = "error: Failed to open GPB_OBJC_SKIP_IMPLS_FILE file";
+      return false;
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  // Validate the objc prefix/package pairings.
+  if (!ValidateObjCClassPrefixes(files, validation_options, error)) {
+    // *error will have been filled in.
+    return false;
+  }
+
+  FileGenerator::CommonState state;
+  for (int i = 0; i < files.size(); i++) {
+    const FileDescriptor* file = files[i];
+    FileGenerator file_generator(file, generation_options, state);
+    std::string filepath = FilePath(file);
+
+    // Generate header.
+    {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          context->Open(filepath + ".pbobjc.h"));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateHeader(&printer);
+    }
+
+    // Generate m file.
+    if (!headers_only && skip_impls.count(file->name()) == 0) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          context->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..1dbc666
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.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.
+
+// 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>
+#include <google/protobuf/descriptor.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+// CodeGenerator implementation which generates a ObjectiveC source file and
+// header.  If you create your own protocol compiler binary and you want it to
+// support ObjectiveC output, you can do so by registering an instance of this
+// CodeGenerator with the CommandLineInterface in your main() function.
+class PROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator {
+ public:
+  ObjectiveCGenerator();
+  ~ObjectiveCGenerator();
+
+  ObjectiveCGenerator(const ObjectiveCGenerator&) = delete;
+  ObjectiveCGenerator& operator=(const ObjectiveCGenerator&) = delete;
+
+  // implements CodeGenerator ----------------------------------------
+  bool HasGenerateAll() const override;
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override;
+  bool GenerateAll(const std::vector<const FileDescriptor*>& files,
+                   const std::string& parameter, GeneratorContext* context,
+                   std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override {
+    return FEATURE_PROTO3_OPTIONAL;
+  }
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..b15f580
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -0,0 +1,2043 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 _MSC_VER
+#include <unistd.h>
+#endif
+#include <climits>
+#include <errno.h>
+#include <fcntl.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <stdlib.h>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_nsobject_methods.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_impl.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/port.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 {
+
+// <io.h> is transitively included in this file. Import the functions explicitly
+// in this port namespace to avoid ambiguous definition.
+namespace posix {
+#ifdef _WIN32
+using ::google::protobuf::io::win32::open;
+#else
+using ::open;
+#endif
+}  // namespace port
+
+namespace {
+
+bool BoolFromEnvVar(const char* env_var, bool default_value) {
+  const char* value = getenv(env_var);
+  if (value) {
+    return std::string("YES") == ToUpper(value);
+  }
+  return default_value;
+}
+
+class SimpleLineCollector : public LineConsumer {
+ public:
+  SimpleLineCollector(std::unordered_set<std::string>* inout_set)
+      : set_(inout_set) {}
+
+  virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override {
+    set_->insert(std::string(line));
+    return true;
+  }
+
+ private:
+  std::unordered_set<std::string>* set_;
+};
+
+class PackageToPrefixesCollector : public LineConsumer {
+ public:
+  PackageToPrefixesCollector(const std::string &usage,
+                             std::map<std::string, std::string>* inout_package_to_prefix_map)
+      : usage_(usage), prefix_map_(inout_package_to_prefix_map) {}
+
+  virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override;
+
+ private:
+  const std::string usage_;
+  std::map<std::string, std::string>* prefix_map_;
+};
+
+class PrefixModeStorage {
+ public:
+  PrefixModeStorage();
+
+  const std::string package_to_prefix_mappings_path() const { return package_to_prefix_mappings_path_; }
+  void set_package_to_prefix_mappings_path(const std::string& path) {
+    package_to_prefix_mappings_path_ = path;
+    package_to_prefix_map_.clear();
+  }
+
+  std::string prefix_from_proto_package_mappings(const FileDescriptor* file);
+
+  bool use_package_name() const { return use_package_name_; }
+  void set_use_package_name(bool on_or_off) { use_package_name_ = on_or_off; }
+
+  const std::string exception_path() const { return exception_path_; }
+  void set_exception_path(const std::string& path) {
+    exception_path_ = path;
+    exceptions_.clear();
+  }
+
+  bool is_package_exempted(const std::string& package);
+
+  // When using a proto package as the prefix, this should be added as the
+  // prefix in front of it.
+  const std::string& forced_package_prefix() const { return forced_prefix_; }
+
+ private:
+  bool use_package_name_;
+  std::map<std::string, std::string> package_to_prefix_map_;
+  std::string package_to_prefix_mappings_path_;
+  std::string exception_path_;
+  std::string forced_prefix_;
+  std::unordered_set<std::string> exceptions_;
+};
+
+PrefixModeStorage::PrefixModeStorage() {
+  // Even thought there are generation options, have an env back door since some
+  // of these helpers could be used in other plugins.
+
+  use_package_name_ = BoolFromEnvVar("GPB_OBJC_USE_PACKAGE_AS_PREFIX", false);
+
+  const char* exception_path = getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH");
+  if (exception_path) {
+    exception_path_ = exception_path;
+  }
+
+  // This one is a not expected to be common, so it doesn't get a generation
+  // option, just the env var.
+  const char* prefix = getenv("GPB_OBJC_USE_PACKAGE_AS_PREFIX_PREFIX");
+  if (prefix) {
+    forced_prefix_ = prefix;
+  }
+}
+
+std::string PrefixModeStorage::prefix_from_proto_package_mappings(const FileDescriptor* file) {
+  if (!file) {
+    return "";
+  }
+
+  if (package_to_prefix_map_.empty() && !package_to_prefix_mappings_path_.empty()) {
+    std::string error_str;
+    // Re use the same collector as we use for expected_prefixes_path since the file
+    // format is the same.
+    PackageToPrefixesCollector collector("Package to prefixes", &package_to_prefix_map_);
+    if (!ParseSimpleFile(package_to_prefix_mappings_path_, &collector, &error_str)) {
+      if (error_str.empty()) {
+        error_str = std::string("protoc:0: warning: Failed to parse")
+           + std::string(" prefix to proto package mappings file: ")
+           + package_to_prefix_mappings_path_;
+      }
+      std::cerr << error_str << std::endl;
+      std::cerr.flush();
+      package_to_prefix_map_.clear();
+    }
+  }
+
+  const std::string package = file->package();
+  // For files without packages, the can be registered as "no_package:PATH",
+  // allowing the expected prefixes file.
+  static const std::string no_package_prefix("no_package:");
+  const std::string lookup_key = package.empty() ? no_package_prefix + file->name() : package;
+
+  std::map<std::string, std::string>::const_iterator prefix_lookup =
+      package_to_prefix_map_.find(lookup_key);
+
+  if (prefix_lookup != package_to_prefix_map_.end()) {
+    return prefix_lookup->second;
+  }  
+
+  return "";
+}
+
+bool PrefixModeStorage::is_package_exempted(const std::string& package) {
+  if (exceptions_.empty() && !exception_path_.empty()) {
+    std::string error_str;
+    SimpleLineCollector collector(&exceptions_);
+    if (!ParseSimpleFile(exception_path_, &collector, &error_str)) {
+      if (error_str.empty()) {
+        error_str = std::string("protoc:0: warning: Failed to parse")
+           + std::string(" package prefix exceptions file: ")
+           + exception_path_;
+      }
+      std::cerr << error_str << std::endl;
+      std::cerr.flush();
+      exceptions_.clear();
+    }
+
+    // If the file was empty put something in it so it doesn't get reloaded over
+    // and over.
+    if (exceptions_.empty()) {
+      exceptions_.insert("<not a real package>");
+    }
+  }
+
+  return exceptions_.count(package) != 0;
+}
+
+PrefixModeStorage g_prefix_mode;
+
+}  // namespace
+
+std::string GetPackageToPrefixMappingsPath() {
+  return g_prefix_mode.package_to_prefix_mappings_path();
+}
+
+void SetPackageToPrefixMappingsPath(const std::string& file_path) {
+  g_prefix_mode.set_package_to_prefix_mappings_path(file_path);
+}
+
+bool UseProtoPackageAsDefaultPrefix() {
+  return g_prefix_mode.use_package_name();
+}
+
+void SetUseProtoPackageAsDefaultPrefix(bool on_or_off) {
+  g_prefix_mode.set_use_package_name(on_or_off);
+}
+
+std::string GetProtoPackagePrefixExceptionList() {
+  return g_prefix_mode.exception_path();
+}
+
+void SetProtoPackagePrefixExceptionList(const std::string& file_path) {
+  g_prefix_mode.set_exception_path(file_path);
+}
+
+Options::Options() {
+  // While there are generator options, also support env variables to help with
+  // build systems where it isn't as easy to hook in for add the generation
+  // options when invoking protoc.
+  const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
+  if (file_path) {
+    expected_prefixes_path = file_path;
+  }
+  const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS");
+  if (suppressions) {
+    expected_prefixes_suppressions =
+        Split(suppressions, ";", true);
+  }
+  prefixes_must_be_registered =
+      BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false);
+  require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false);
+}
+
+namespace {
+
+std::unordered_set<std::string> MakeWordsMap(const char* const words[],
+                                             size_t num_words) {
+  std::unordered_set<std::string> result;
+  for (int i = 0; i < num_words; i++) {
+    result.insert(words[i]);
+  }
+  return result;
+}
+
+const char* const kUpperSegmentsList[] = {"url", "http", "https"};
+
+std::unordered_set<std::string> kUpperSegments =
+    MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
+
+bool ascii_isnewline(char c) {
+  return c == '\n' || c == '\r';
+}
+
+// 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.
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool first_capitalized) {
+  std::vector<std::string> values;
+  std::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);
+
+  std::string result;
+  bool first_segment_forces_upper = false;
+  for (std::vector<std::string>::iterator i = values.begin(); i != values.end();
+       ++i) {
+    std::string value = *i;
+    bool all_upper = (kUpperSegments.count(value) > 0);
+    if (all_upper && (result.length() == 0)) {
+      first_segment_forces_upper = true;
+    }
+    for (int j = 0; j < value.length(); j++) {
+      if (j == 0 || all_upper) {
+        value[j] = ascii_toupper(value[j]);
+      } else {
+        // Nothing, already in lower.
+      }
+    }
+    result += value;
+  }
+  if ((result.length() != 0) &&
+      !first_capitalized &&
+      !first_segment_forces_upper) {
+    result[0] = ascii_tolower(result[0]);
+  }
+  return result;
+}
+
+const char* const kReservedWordList[] = {
+  // Note NSObject Methods:
+  // These are brought in from objectivec_nsobject_methods.h that is generated
+  // using method_dump.sh. See kNSObjectMethods below.
+
+  // Objective C "keywords" that aren't in C
+  // From
+  // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
+  // with some others added on.
+  "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
+  "self", "instancetype", "nullable", "nonnull", "nil", "Nil",
+  "YES", "NO", "weak",
+
+  // 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",
+
+  // GCC/Clang extension
+  "typeof",
+
+  // Not a keyword, but will break you
+  "NULL",
+
+  // C88+ specs call for these to be macros, so depending on what they are
+  // defined to be it can lead to odd errors for some Xcode/SDK versions.
+  "stdin", "stdout", "stderr",
+
+  // Objective-C Runtime typedefs
+  // From <obc/runtime.h>
+  "Category", "Ivar", "Method", "Protocol",
+
+  // 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", "initialized", "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",
+};
+
+// returns true is input starts with __ or _[A-Z] which are reserved identifiers
+// in C/ C++. All calls should go through UnderscoresToCamelCase before getting here
+// but this verifies and allows for future expansion if we decide to redefine what a
+// reserved C identifier is (for example the GNU list
+// https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html )
+bool IsReservedCIdentifier(const std::string& input) {
+  if (input.length() > 2) {
+    if (input.at(0) == '_') {
+      if (isupper(input.at(1)) || input.at(1) == '_') {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+std::string SanitizeNameForObjC(const std::string& prefix,
+                                const std::string& input,
+                                const std::string& extension,
+                                std::string* out_suffix_added) {
+  static const std::unordered_set<std::string> kReservedWords =
+      MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
+  static const std::unordered_set<std::string> kNSObjectMethods =
+      MakeWordsMap(kNSObjectMethodsList, GOOGLE_ARRAYSIZE(kNSObjectMethodsList));
+  std::string sanitized;
+  // We add the prefix in the cases where the string is missing a prefix.
+  // We define "missing a prefix" as where 'input':
+  // a) Doesn't start with the prefix or
+  // b) Isn't equivalent to the prefix or
+  // c) Has the prefix, but the letter after the prefix is lowercase
+  if (HasPrefixString(input, prefix)) {
+    if (input.length() == prefix.length() || !ascii_isupper(input[prefix.length()])) {
+      sanitized = prefix + input;
+    } else {
+      sanitized = input;
+    }
+  } else {
+    sanitized = prefix + input;
+  }
+  if (IsReservedCIdentifier(sanitized) ||
+      (kReservedWords.count(sanitized) > 0) ||
+      (kNSObjectMethods.count(sanitized) > 0)) {
+    if (out_suffix_added) *out_suffix_added = extension;
+    return sanitized + extension;
+  }
+  if (out_suffix_added) out_suffix_added->clear();
+  return sanitized;
+}
+
+std::string NameFromFieldDescriptor(const FieldDescriptor* field) {
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    return field->message_type()->name();
+  } else {
+    return field->name();
+  }
+}
+
+void PathSplit(const std::string& path, std::string* directory,
+               std::string* basename) {
+  std::string::size_type last_slash = path.rfind('/');
+  if (last_slash == std::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 std::string& name, const std::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;
+}
+
+std::string GetZeroEnumNameForFlagType(const FlagType flag_type) {
+  switch(flag_type) {
+    case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
+      return "GPBDescriptorInitializationFlag_None";
+    case FLAGTYPE_EXTENSION:
+      return "GPBExtensionNone";
+    case FLAGTYPE_FIELD:
+      return "GPBFieldNone";
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      return "0";
+  }
+}
+
+std::string GetEnumNameForFlagType(const FlagType flag_type) {
+  switch(flag_type) {
+    case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
+      return "GPBDescriptorInitializationFlags";
+    case FLAGTYPE_EXTENSION:
+      return "GPBExtensionOptions";
+    case FLAGTYPE_FIELD:
+      return "GPBFieldFlags";
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      return std::string();
+  }
+}
+
+void MaybeUnQuote(StringPiece* input) {
+  if ((input->length() >= 2) &&
+      ((*input->data() == '\'' || *input->data() == '"')) &&
+      ((*input)[input->length() - 1] == *input->data())) {
+    input->remove_prefix(1);
+    input->remove_suffix(1);
+  }
+}
+
+}  // namespace
+
+// Escape C++ trigraphs by escaping question marks to \?
+std::string EscapeTrigraphs(const std::string& to_escape) {
+  return StringReplace(to_escape, "?", "\\?", true);
+}
+
+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);
+  }
+}
+
+bool IsRetainedName(const std::string& name) {
+  // List of prefixes from
+  // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
+  static const std::string retained_names[] = {"new", "alloc", "copy",
+                                               "mutableCopy"};
+  return IsSpecialName(name, retained_names,
+                       sizeof(retained_names) / sizeof(retained_names[0]));
+}
+
+bool IsInitName(const std::string& name) {
+  static const std::string init_names[] = {"init"};
+  return IsSpecialName(name, init_names,
+                       sizeof(init_names) / sizeof(init_names[0]));
+}
+
+std::string BaseFileName(const FileDescriptor* file) {
+  std::string basename;
+  PathSplit(file->name(), NULL, &basename);
+  return basename;
+}
+
+std::string FileClassPrefix(const FileDescriptor* file) {
+  // Always honor the file option.
+  if (file->options().has_objc_class_prefix()) {
+    return file->options().objc_class_prefix();
+  }
+
+  // If package prefix is specified in an prefix to proto mappings file then use that.
+  std::string objc_class_prefix = g_prefix_mode.prefix_from_proto_package_mappings(file);
+  if (!objc_class_prefix.empty()) {
+    return objc_class_prefix;
+  }
+
+  // If package prefix isn't enabled, done.
+  if (!g_prefix_mode.use_package_name()) {
+    return "";
+  }
+
+  // If the package is in the exceptions list, done.
+  if (g_prefix_mode.is_package_exempted(file->package())) {
+    return "";
+  }
+
+  // Transform the package into a prefix: use the dot segments as part,
+  // camelcase each one and then join them with underscores, and add an
+  // underscore at the end.
+  std::string result;
+  const std::vector<std::string> segments = Split(file->package(), ".", true);
+  for (const auto& segment : segments) {
+    const std::string part = UnderscoresToCamelCase(segment, true);
+    if (part.empty()) {
+      continue;
+    }
+    if (!result.empty()) {
+      result.append("_");
+    }
+    result.append(part);
+  }
+  if (!result.empty()) {
+    result.append("_");
+  }
+  return g_prefix_mode.forced_package_prefix() + result;
+}
+
+std::string FilePath(const FileDescriptor* file) {
+  std::string output;
+  std::string basename;
+  std::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;
+}
+
+std::string FilePathBasename(const FileDescriptor* file) {
+  std::string output;
+  std::string basename;
+  std::string directory;
+  PathSplit(file->name(), &directory, &basename);
+  basename = StripProto(basename);
+
+  // CamelCase to be more ObjC friendly.
+  output = UnderscoresToCamelCase(basename, true);
+
+  return output;
+}
+
+std::string FileClassName(const FileDescriptor* file) {
+  const std::string prefix = FileClassPrefix(file);
+  const std::string name =
+      UnderscoresToCamelCase(StripProto(BaseFileName(file)), true) + "Root";
+  // There aren't really any reserved words that end in "Root", but playing
+  // it safe and checking.
+  return SanitizeNameForObjC(prefix, name, "_RootClass", NULL);
+}
+
+std::string ClassNameWorker(const Descriptor* descriptor) {
+  std::string name;
+  if (descriptor->containing_type() != NULL) {
+    name = ClassNameWorker(descriptor->containing_type());
+    name += "_";
+  }
+  return name + descriptor->name();
+}
+
+std::string ClassNameWorker(const EnumDescriptor* descriptor) {
+  std::string name;
+  if (descriptor->containing_type() != NULL) {
+    name = ClassNameWorker(descriptor->containing_type());
+    name += "_";
+  }
+  return name + descriptor->name();
+}
+
+std::string ClassName(const Descriptor* descriptor) {
+  return ClassName(descriptor, NULL);
+}
+
+std::string ClassName(const Descriptor* descriptor,
+                      std::string* out_suffix_added) {
+  // 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.
+  const std::string prefix = FileClassPrefix(descriptor->file());
+  const std::string name = ClassNameWorker(descriptor);
+  return SanitizeNameForObjC(prefix, name, "_Class", out_suffix_added);
+}
+
+std::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.
+  const std::string prefix = FileClassPrefix(descriptor->file());
+  const std::string name = ClassNameWorker(descriptor);
+  return SanitizeNameForObjC(prefix, name, "_Enum", NULL);
+}
+
+std::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 std::string class_name = EnumName(descriptor->type());
+  const std::string value_str =
+      UnderscoresToCamelCase(descriptor->name(), true);
+  const std::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", NULL);
+}
+
+std::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 std::string class_name = EnumName(descriptor->type());
+  const std::string long_name_prefix = class_name + "_";
+  const std::string long_name = EnumValueName(descriptor);
+  return StripPrefixString(long_name, long_name_prefix);
+}
+
+std::string UnCamelCaseEnumShortName(const std::string& name) {
+  std::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;
+}
+
+std::string ExtensionMethodName(const FieldDescriptor* descriptor) {
+  const std::string name = NameFromFieldDescriptor(descriptor);
+  const std::string result = UnderscoresToCamelCase(name, false);
+  return SanitizeNameForObjC("", result, "_Extension", NULL);
+}
+
+std::string FieldName(const FieldDescriptor* field) {
+  const std::string name = NameFromFieldDescriptor(field);
+  std::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", NULL);
+}
+
+std::string FieldNameCapitalized(const FieldDescriptor* field) {
+  // Want the same suffix handling, so upcase the first letter of the other
+  // name.
+  std::string result = FieldName(field);
+  if (result.length() > 0) {
+    result[0] = ascii_toupper(result[0]);
+  }
+  return result;
+}
+
+std::string OneofEnumName(const OneofDescriptor* descriptor) {
+  const Descriptor* fieldDescriptor = descriptor->containing_type();
+  std::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;
+}
+
+std::string OneofName(const OneofDescriptor* descriptor) {
+  std::string name = UnderscoresToCamelCase(descriptor->name(), false);
+  // No sanitize needed because it gets OneOfCase added and that shouldn't
+  // ever conflict.
+  return name;
+}
+
+std::string OneofNameCapitalized(const OneofDescriptor* descriptor) {
+  // Use the common handling and then up-case the first letter.
+  std::string result = OneofName(descriptor);
+  if (result.length() > 0) {
+    result[0] = ascii_toupper(result[0]);
+  }
+  return result;
+}
+
+std::string ObjCClass(const std::string& class_name) {
+  return std::string("GPBObjCClass(") + class_name + ")";
+}
+
+std::string ObjCClassDeclaration(const std::string& class_name) {
+  return std::string("GPBObjCClassDeclaration(") + class_name + ");";
+}
+
+std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* field) {
+  std::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 {
+    std::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;
+  }
+}
+
+std::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 std::string();
+}
+
+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 std::string HandleExtremeFloatingPoint(std::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(".") != std::string::npos ||
+                             val.find("e") != std::string::npos ||
+                             val.find("E") != std::string::npos)) {
+      val += "f";
+    }
+    return val;
+  }
+}
+
+std::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 std::string();
+}
+
+
+std::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 StrCat(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return StrCat(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 StrCat(field->default_value_int64()) + "LL";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return StrCat(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 std::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_t length = ghtonl(default_string.length());
+        std::string bytes((const char*)&length, sizeof(length));
+        bytes.append(default_string);
+        return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\"";
+      } else {
+        return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\"";
+      }
+    }
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return EnumValueName(field->default_value_enum());
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "nil";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return std::string();
+}
+
+bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
+  // Repeated fields don't have defaults.
+  if (field->is_repeated()) {
+    return false;
+  }
+
+  // As much as checking field->has_default_value() seems useful, it isn't
+  // because of enums. proto2 syntax allows the first item in an enum (the
+  // default) to be non zero. So checking field->has_default_value() would
+  // result in missing this non zero default.  See MessageWithOneBasedEnum in
+  // objectivec/Tests/unittest_objc.proto for a test Message to confirm this.
+
+  // Some proto file set the default to the zero value, so make sure the value
+  // isn't the zero case.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return field->default_value_int32() != 0;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return field->default_value_uint32() != 0U;
+    case FieldDescriptor::CPPTYPE_INT64:
+      return field->default_value_int64() != 0LL;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return field->default_value_uint64() != 0ULL;
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return field->default_value_double() != 0.0;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return field->default_value_float() != 0.0f;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool();
+    case FieldDescriptor::CPPTYPE_STRING: {
+      const std::string& default_string = field->default_value_string();
+      return default_string.length() != 0;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return field->default_value_enum()->number() != 0;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return false;
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+std::string BuildFlagsString(const FlagType flag_type,
+                             const std::vector<std::string>& strings) {
+  if (strings.empty()) {
+    return GetZeroEnumNameForFlagType(flag_type);
+  } else if (strings.size() == 1) {
+    return strings[0];
+  }
+  std::string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
+  for (size_t i = 0; i != strings.size(); ++i) {
+    if (i > 0) {
+      string.append(" | ");
+    }
+    string.append(strings[i]);
+  }
+  string.append(")");
+  return string;
+}
+
+std::string BuildCommentsString(const SourceLocation& location,
+                           bool prefer_single_line) {
+  const std::string& comments = location.leading_comments.empty()
+                               ? location.trailing_comments
+                               : location.leading_comments;
+  std::vector<std::string> lines;
+  lines = Split(comments, "\n", false);
+  while (!lines.empty() && lines.back().empty()) {
+    lines.pop_back();
+  }
+  // If there are no comments, just return an empty string.
+  if (lines.empty()) {
+    return "";
+  }
+
+  std::string prefix;
+  std::string suffix;
+  std::string final_comments;
+  std::string epilogue;
+
+  bool add_leading_space = false;
+
+  if (prefer_single_line && lines.size() == 1) {
+    prefix = "/** ";
+    suffix = " */\n";
+  } else {
+    prefix = "* ";
+    suffix = "\n";
+    final_comments += "/**\n";
+    epilogue = " **/\n";
+    add_leading_space = true;
+  }
+
+  for (int i = 0; i < lines.size(); i++) {
+    std::string line = StripPrefixString(lines[i], " ");
+    // HeaderDoc and appledoc use '\' and '@' for markers; escape them.
+    line = StringReplace(line, "\\", "\\\\", true);
+    line = StringReplace(line, "@", "\\@", true);
+    // Decouple / from * to not have inline comments inside comments.
+    line = StringReplace(line, "/*", "/\\*", true);
+    line = StringReplace(line, "*/", "*\\/", true);
+    line = prefix + line;
+    StripWhitespace(&line);
+    // If not a one line, need to add the first space before *, as
+    // StripWhitespace would have removed it.
+    line = (add_leading_space ? " " : "") + line;
+    final_comments += line + suffix;
+  }
+  final_comments += epilogue;
+  return final_comments;
+}
+
+// Making these a generator option for folks that don't use CocoaPods, but do
+// want to put the library in a framework is an interesting question. The
+// problem is it means changing sources shipped with the library to actually
+// use a different value; so it isn't as simple as a option.
+const char* const ProtobufLibraryFrameworkName = "Protobuf";
+
+std::string ProtobufFrameworkImportSymbol(const std::string& framework_name) {
+  // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS
+  std::string result = std::string("GPB_USE_");
+  result += ToUpper(framework_name);
+  result += "_FRAMEWORK_IMPORTS";
+  return result;
+}
+
+bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) {
+  // We don't check the name prefix or proto package because some files
+  // (descriptor.proto), aren't shipped generated by the library, so this
+  // seems to be the safest way to only catch the ones shipped.
+  const std::string name = file->name();
+  if (name == "google/protobuf/any.proto" ||
+      name == "google/protobuf/api.proto" ||
+      name == "google/protobuf/duration.proto" ||
+      name == "google/protobuf/empty.proto" ||
+      name == "google/protobuf/field_mask.proto" ||
+      name == "google/protobuf/source_context.proto" ||
+      name == "google/protobuf/struct.proto" ||
+      name == "google/protobuf/timestamp.proto" ||
+      name == "google/protobuf/type.proto" ||
+      name == "google/protobuf/wrappers.proto") {
+    return true;
+  }
+  return false;
+}
+
+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 RemoveComment(StringPiece* input) {
+  int offset = input->find('#');
+  if (offset != StringPiece::npos) {
+    input->remove_suffix(input->length() - offset);
+  }
+}
+
+namespace {
+
+bool PackageToPrefixesCollector::ConsumeLine(
+    const StringPiece& line, std::string* out_error) {
+  int offset = line.find('=');
+  if (offset == StringPiece::npos) {
+    *out_error = usage_ + " file line without equal sign: '" + StrCat(line) + "'.";
+    return false;
+  }
+  StringPiece package = line.substr(0, offset);
+  StringPiece prefix = line.substr(offset + 1);
+  TrimWhitespace(&package);
+  TrimWhitespace(&prefix);
+  MaybeUnQuote(&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_)[std::string(package)] = std::string(prefix);
+  return true;
+}
+
+bool LoadExpectedPackagePrefixes(const std::string& expected_prefixes_path,
+                                 std::map<std::string, std::string>* prefix_map,
+                                 std::string* out_error) {
+  if (expected_prefixes_path.empty()) {
+    return true;
+  }
+
+  PackageToPrefixesCollector collector("Expected prefixes", prefix_map);
+  return ParseSimpleFile(
+      expected_prefixes_path, &collector, out_error);
+}
+
+bool ValidateObjCClassPrefix(
+    const FileDescriptor* file, const std::string& expected_prefixes_path,
+    const std::map<std::string, std::string>& expected_package_prefixes,
+    bool prefixes_must_be_registered, bool require_prefixes,
+    std::string* out_error) {
+  // Reminder: An explicit prefix option of "" is valid in case the default
+  // prefixing is set to use the proto package and a file needs to be generated
+  // without any prefix at all (for legacy reasons).
+
+  bool has_prefix = file->options().has_objc_class_prefix();
+  bool have_expected_prefix_file = !expected_prefixes_path.empty();
+
+  const std::string prefix = file->options().objc_class_prefix();
+  const std::string package = file->package();
+  // For files without packages, the can be registered as "no_package:PATH",
+  // allowing the expected prefixes file.
+  static const std::string no_package_prefix("no_package:");
+  const std::string lookup_key =
+      package.empty() ? no_package_prefix + file->name() : 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.
+
+  // Check: Error - See if there was an expected prefix for the package and
+  // report if it doesn't match (wrong or missing).
+  std::map<std::string, std::string>::const_iterator package_match =
+      expected_package_prefixes.find(lookup_key);
+  if (package_match != expected_package_prefixes.end()) {
+    // There was an entry, and...
+    if (has_prefix && package_match->second == prefix) {
+      // ...it matches.  All good, out of here!
+      return true;
+    } else {
+      // ...it didn't match!
+      *out_error = "error: Expected 'option objc_class_prefix = \"" +
+                   package_match->second + "\";'";
+      if (!package.empty()) {
+        *out_error += " for package '" + package + "'";
+      }
+      *out_error += " in '" + file->name() + "'";
+      if (has_prefix) {
+        *out_error += "; but found '" + prefix + "' instead";
+      }
+      *out_error += ".";
+      return false;
+    }
+  }
+
+  // If there was no prefix option, we're done at this point.
+  if (!has_prefix) {
+    if (require_prefixes) {
+      *out_error =
+        "error: '" + file->name() + "' does not have a required 'option" +
+        " objc_class_prefix'.";
+      return false;
+    }
+    return true;
+  }
+
+  // When the prefix is non empty, check it against the expected entries.
+  if (!prefix.empty() && have_expected_prefix_file) {
+    // For a non empty prefix, look for any other package that uses the prefix.
+    std::string other_package_for_prefix;
+    for (std::map<std::string, std::string>::const_iterator i =
+             expected_package_prefixes.begin();
+         i != expected_package_prefixes.end(); ++i) {
+      if (i->second == prefix) {
+        other_package_for_prefix = i->first;
+        // Stop on the first real package listing, if it was a no_package file
+        // specific entry, keep looking to try and find a package one.
+        if (!HasPrefixString(other_package_for_prefix, no_package_prefix)) {
+          break;
+        }
+      }
+    }
+
+    // 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).
+    if (!other_package_for_prefix.empty()) {
+      *out_error =
+          "error: Found 'option objc_class_prefix = \"" + prefix +
+          "\";' in '" + file->name() + "'; that prefix is already used for ";
+      if (HasPrefixString(other_package_for_prefix, no_package_prefix)) {
+        *out_error += "file '" +
+          StripPrefixString(other_package_for_prefix, no_package_prefix) +
+          "'.";
+      } else {
+        *out_error += "'package " + other_package_for_prefix + ";'.";
+      }
+      *out_error +=
+        " It can only be reused by adding '" + lookup_key + " = " + prefix +
+        "' to the expected prefixes file (" + expected_prefixes_path + ").";
+      return false;  // Only report first usage of the prefix.
+    }
+  } // !prefix.empty() && have_expected_prefix_file
+
+  // 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 (!prefix.empty() && !ascii_isupper(prefix[0])) {
+    std::cerr
+         << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " it should start with a capital letter." << std::endl;
+    std::cerr.flush();
+  }
+  if (!prefix.empty() && 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.
+    std::cerr
+         << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " Apple recommends they should be at least 3 characters long."
+         << std::endl;
+    std::cerr.flush();
+  }
+
+  // Check: Error/Warning - If the given package/prefix pair wasn't expected,
+  // issue a error/warning to added to the file.
+  if (have_expected_prefix_file) {
+    if (prefixes_must_be_registered) {
+      *out_error =
+        "error: '" + file->name() + "' has 'option objc_class_prefix = \"" +
+        prefix + "\";', but it is not registered. Add '" + lookup_key + " = " +
+        (prefix.empty() ? "\"\"" : prefix) +
+        "' to the expected prefixes file (" + expected_prefixes_path + ").";
+      return false;
+    }
+
+    std::cerr
+         << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "'; consider adding '"
+         << lookup_key << " = " << (prefix.empty() ? "\"\"" : prefix)
+         << "' to the expected prefixes file (" << expected_prefixes_path
+         << ")." << std::endl;
+    std::cerr.flush();
+  }
+
+  return true;
+}
+
+}  // namespace
+
+bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files,
+                               std::string* out_error) {
+    // Options's ctor load from the environment.
+    Options options;
+    return ValidateObjCClassPrefixes(files, options, out_error);
+}
+
+bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files,
+                               const Options& generation_options,
+                               std::string* out_error) {
+  // Allow a '-' as the path for the expected prefixes to completely disable
+  // even the most basic of checks.
+  if (generation_options.expected_prefixes_path == "-") {
+    return true;
+  }
+
+  // Load the expected package prefixes, if available, to validate against.
+  std::map<std::string, std::string> expected_package_prefixes;
+  if (!LoadExpectedPackagePrefixes(generation_options.expected_prefixes_path,
+                                   &expected_package_prefixes,
+                                   out_error)) {
+    return false;
+  }
+
+  for (int i = 0; i < files.size(); i++) {
+    bool should_skip =
+      (std::find(generation_options.expected_prefixes_suppressions.begin(),
+                 generation_options.expected_prefixes_suppressions.end(),
+                 files[i]->name())
+          != generation_options.expected_prefixes_suppressions.end());
+    if (should_skip) {
+      continue;
+    }
+
+    bool is_valid =
+        ValidateObjCClassPrefix(files[i],
+                                generation_options.expected_prefixes_path,
+                                expected_package_prefixes,
+                                generation_options.prefixes_must_be_registered,
+                                generation_options.require_prefixes,
+                                out_error);
+    if (!is_valid) {
+      return false;
+    }
+  }
+  return true;
+}
+
+TextFormatDecodeData::TextFormatDecodeData() { }
+
+TextFormatDecodeData::~TextFormatDecodeData() { }
+
+void TextFormatDecodeData::AddString(int32_t key,
+                                     const std::string& input_for_decode,
+                                     const std::string& desired_output) {
+  for (std::vector<DataEntry>::const_iterator i = entries_.begin();
+       i != entries_.end(); ++i) {
+    if (i->first == key) {
+      std::cerr << "error: duplicate key (" << key
+           << ") making TextFormat data, input: \"" << input_for_decode
+           << "\", desired: \"" << desired_output << "\"." << std::endl;
+      std::cerr.flush();
+      abort();
+    }
+  }
+
+  const std::string& data = TextFormatDecodeData::DecodeDataForString(
+      input_for_decode, desired_output);
+  entries_.push_back(DataEntry(key, data));
+}
+
+std::string TextFormatDecodeData::Data() const {
+  std::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 (std::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;
+  }
+  std::string Finish() {
+    Push();
+    return decode_data_;
+  }
+
+ private:
+  static constexpr uint8_t kAddUnderscore = 0x80;
+
+  static constexpr uint8_t kOpAsIs = 0x00;
+  static constexpr uint8_t kOpFirstUpper = 0x40;
+  static constexpr uint8_t kOpFirstLower = 0x20;
+  static constexpr uint8_t kOpAllUpper = 0x60;
+
+  static constexpr int kMaxSegmentLen = 0x1f;
+
+  void AddChar(const char desired) {
+    ++segment_len_;
+    is_all_upper_ &= ascii_isupper(desired);
+  }
+
+  void Push() {
+    uint8_t 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_t op_;
+  int segment_len_;
+
+  std::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.
+std::string DirectDecodeString(const std::string& str) {
+  std::string result;
+  result += (char)'\0';  // Marker for full string.
+  result += str;
+  result += (char)'\0';  // End of string.
+  return result;
+}
+
+}  // namespace
+
+// static
+std::string TextFormatDecodeData::DecodeDataForString(
+    const std::string& input_for_decode, const std::string& desired_output) {
+  if (input_for_decode.empty() || desired_output.empty()) {
+    std::cerr << "error: got empty string for making TextFormat data, input: \""
+         << input_for_decode << "\", desired: \"" << desired_output << "\"."
+         << std::endl;
+    std::cerr.flush();
+    abort();
+  }
+  if ((input_for_decode.find('\0') != std::string::npos) ||
+      (desired_output.find('\0') != std::string::npos)) {
+    std::cerr << "error: got a null char in a string for making TextFormat data,"
+         << " input: \"" << CEscape(input_for_decode) << "\", desired: \""
+         << CEscape(desired_output) << "\"." << std::endl;
+    std::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 {
+
+class Parser {
+ public:
+  Parser(LineConsumer* line_consumer)
+      : line_consumer_(line_consumer), line_(0) {}
+
+  // Feeds in some input, parse what it can, returning success/failure. Calling
+  // again after an error is undefined.
+  bool ParseChunk(StringPiece chunk, std::string* out_error);
+
+  // Should be called to finish parsing (after all input has been provided via
+  // successful calls to ParseChunk(), calling after a ParseChunk() failure is
+  // undefined). Returns success/failure.
+  bool Finish(std::string* out_error);
+
+  int last_line() const { return line_; }
+
+ private:
+  LineConsumer* line_consumer_;
+  int line_;
+  std::string leftover_;
+};
+
+bool Parser::ParseChunk(StringPiece chunk, std::string* out_error) {
+  StringPiece full_chunk;
+  if (!leftover_.empty()) {
+    leftover_ += std::string(chunk);
+    full_chunk = StringPiece(leftover_);
+  } else {
+    full_chunk = chunk;
+  }
+
+  StringPiece line;
+  while (ReadLine(&full_chunk, &line)) {
+    ++line_;
+    RemoveComment(&line);
+    TrimWhitespace(&line);
+    if (!line.empty() && !line_consumer_->ConsumeLine(line, out_error)) {
+      if (out_error->empty()) {
+        *out_error = "ConsumeLine failed without setting an error.";
+      }
+      leftover_.clear();
+      return false;
+    }
+  }
+
+  if (full_chunk.empty()) {
+    leftover_.clear();
+  } else {
+    leftover_ = std::string(full_chunk);
+  }
+  return true;
+}
+
+bool Parser::Finish(std::string* out_error) {
+  // If there is still something to go, flush it with a newline.
+  if (!leftover_.empty() && !ParseChunk("\n", out_error)) {
+    return false;
+  }
+  // This really should never fail if ParseChunk succeeded, but check to be sure.
+  if (!leftover_.empty()) {
+    *out_error = "ParseSimple Internal error: finished with pending data.";
+    return false;
+  }
+  return true;
+}
+
+std::string FullErrorString(const std::string& name, int line_num, const std::string& msg) {
+  return std::string("error: ") + name + " Line " + StrCat(line_num) + ", " + msg;
+}
+
+}  // namespace
+
+LineConsumer::LineConsumer() {}
+
+LineConsumer::~LineConsumer() {}
+
+bool ParseSimpleFile(const std::string& path, LineConsumer* line_consumer,
+                     std::string* out_error) {
+  int fd;
+  do {
+    fd = posix::open(path.c_str(), O_RDONLY);
+  } while (fd < 0 && errno == EINTR);
+  if (fd < 0) {
+    *out_error = std::string("error: Unable to open \"") + path + "\", " +
+                 strerror(errno);
+    return false;
+  }
+  io::FileInputStream file_stream(fd);
+  file_stream.SetCloseOnDelete(true);
+
+  return ParseSimpleStream(file_stream, path, line_consumer, out_error);
+}
+
+bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream,
+                       const std::string& stream_name,
+                       LineConsumer* line_consumer,
+                       std::string* out_error) {
+  std::string local_error;
+  Parser parser(line_consumer);
+  const void* buf;
+  int buf_len;
+  while (input_stream.Next(&buf, &buf_len)) {
+    if (buf_len == 0) {
+      continue;
+    }
+
+    if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len),
+                           &local_error)) {
+      *out_error = FullErrorString(stream_name, parser.last_line(), local_error);
+      return false;
+    }
+  }
+  if (!parser.Finish(&local_error)) {
+    *out_error = FullErrorString(stream_name, parser.last_line(), local_error);
+    return false;
+  }
+  return true;
+}
+
+ImportWriter::ImportWriter(
+    const std::string& generate_for_named_framework,
+    const std::string& named_framework_to_proto_path_mappings_path,
+    const std::string& runtime_import_prefix, bool include_wkt_imports)
+    : generate_for_named_framework_(generate_for_named_framework),
+      named_framework_to_proto_path_mappings_path_(
+          named_framework_to_proto_path_mappings_path),
+      runtime_import_prefix_(runtime_import_prefix),
+      include_wkt_imports_(include_wkt_imports),
+      need_to_parse_mapping_file_(true) {}
+
+ImportWriter::~ImportWriter() {}
+
+void ImportWriter::AddFile(const FileDescriptor* file,
+                           const std::string& header_extension) {
+  if (IsProtobufLibraryBundledProtoFile(file)) {
+    // The imports of the WKTs are only needed within the library itself,
+    // in other cases, they get skipped because the generated code already
+    // import GPBProtocolBuffers.h and hence proves them.
+    if (include_wkt_imports_) {
+      const std::string header_name =
+          "GPB" + FilePathBasename(file) + header_extension;
+      protobuf_imports_.push_back(header_name);
+    }
+    return;
+  }
+
+  // Lazy parse any mappings.
+  if (need_to_parse_mapping_file_) {
+    ParseFrameworkMappings();
+  }
+
+  std::map<std::string, std::string>::iterator proto_lookup =
+      proto_file_to_framework_name_.find(file->name());
+  if (proto_lookup != proto_file_to_framework_name_.end()) {
+    other_framework_imports_.push_back(
+        proto_lookup->second + "/" +
+        FilePathBasename(file) + header_extension);
+    return;
+  }
+
+  if (!generate_for_named_framework_.empty()) {
+    other_framework_imports_.push_back(
+        generate_for_named_framework_ + "/" +
+        FilePathBasename(file) + header_extension);
+    return;
+  }
+
+  other_imports_.push_back(FilePath(file) + header_extension);
+}
+
+void ImportWriter::Print(io::Printer* printer) const {
+  bool add_blank_line = false;
+
+  if (!protobuf_imports_.empty()) {
+    PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_);
+    add_blank_line = true;
+  }
+
+  if (!other_framework_imports_.empty()) {
+    if (add_blank_line) {
+      printer->Print("\n");
+    }
+
+    for (std::vector<std::string>::const_iterator iter =
+             other_framework_imports_.begin();
+         iter != other_framework_imports_.end(); ++iter) {
+      printer->Print(
+          "#import <$header$>\n",
+          "header", *iter);
+    }
+
+    add_blank_line = true;
+  }
+
+  if (!other_imports_.empty()) {
+    if (add_blank_line) {
+      printer->Print("\n");
+    }
+
+    for (std::vector<std::string>::const_iterator iter = other_imports_.begin();
+         iter != other_imports_.end(); ++iter) {
+      printer->Print(
+          "#import \"$header$\"\n",
+          "header", *iter);
+    }
+  }
+}
+
+void ImportWriter::PrintRuntimeImports(
+    io::Printer* printer, const std::vector<std::string>& header_to_import,
+    const std::string& runtime_import_prefix, bool default_cpp_symbol) {
+  // Given an override, use that.
+  if (!runtime_import_prefix.empty()) {
+    for (const auto& header : header_to_import) {
+      printer->Print(
+          " #import \"$import_prefix$/$header$\"\n",
+          "import_prefix", runtime_import_prefix,
+          "header", header);
+    }
+    return;
+  }
+
+  const std::string framework_name(ProtobufLibraryFrameworkName);
+  const std::string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
+
+  if (default_cpp_symbol) {
+    printer->Print(
+        "// This CPP symbol can be defined to use imports that match up to the framework\n"
+        "// imports needed when using CocoaPods.\n"
+        "#if !defined($cpp_symbol$)\n"
+        " #define $cpp_symbol$ 0\n"
+        "#endif\n"
+        "\n",
+        "cpp_symbol", cpp_symbol);
+  }
+
+  printer->Print(
+      "#if $cpp_symbol$\n",
+      "cpp_symbol", cpp_symbol);
+  for (const auto& header : header_to_import) {
+    printer->Print(
+        " #import <$framework_name$/$header$>\n",
+        "framework_name", framework_name,
+        "header", header);
+  }
+  printer->Print(
+      "#else\n");
+  for (const auto& header : header_to_import) {
+    printer->Print(
+        " #import \"$header$\"\n",
+        "header", header);
+  }
+  printer->Print(
+      "#endif\n");
+}
+
+void ImportWriter::ParseFrameworkMappings() {
+  need_to_parse_mapping_file_ = false;
+  if (named_framework_to_proto_path_mappings_path_.empty()) {
+    return;  // Nothing to do.
+  }
+
+  ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
+  std::string parse_error;
+  if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
+                       &collector, &parse_error)) {
+    std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
+         << " : " << parse_error << std::endl;
+    std::cerr.flush();
+  }
+}
+
+bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
+    const StringPiece& line, std::string* out_error) {
+  int offset = line.find(':');
+  if (offset == StringPiece::npos) {
+    *out_error =
+        std::string("Framework/proto file mapping line without colon sign: '") +
+        std::string(line) + "'.";
+    return false;
+  }
+  StringPiece framework_name = line.substr(0, offset);
+  StringPiece proto_file_list = line.substr(offset + 1);
+  TrimWhitespace(&framework_name);
+
+  int start = 0;
+  while (start < proto_file_list.length()) {
+    offset = proto_file_list.find(',', start);
+    if (offset == StringPiece::npos) {
+      offset = proto_file_list.length();
+    }
+
+    StringPiece proto_file = proto_file_list.substr(start, offset - start);
+    TrimWhitespace(&proto_file);
+    if (!proto_file.empty()) {
+      std::map<std::string, std::string>::iterator existing_entry =
+          map_->find(std::string(proto_file));
+      if (existing_entry != map_->end()) {
+        std::cerr << "warning: duplicate proto file reference, replacing "
+                     "framework entry for '"
+                  << std::string(proto_file) << "' with '" << std::string(framework_name)
+                  << "' (was '" << existing_entry->second << "')." << std::endl;
+        std::cerr.flush();
+      }
+
+      if (proto_file.find(' ') != StringPiece::npos) {
+        std::cerr << "note: framework mapping file had a proto file with a "
+                     "space in, hopefully that isn't a missing comma: '"
+                  << std::string(proto_file) << "'" << std::endl;
+        std::cerr.flush();
+      }
+
+      (*map_)[std::string(proto_file)] = std::string(framework_name);
+    }
+
+    start = offset + 1;
+  }
+
+  return true;
+}
+
+}  // 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..d21fed2
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -0,0 +1,353 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Helper functions for generating ObjectiveC code.
+
+#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>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+// Get/Set the path to a file to load for objc class prefix lookups.
+std::string PROTOC_EXPORT GetPackageToPrefixMappingsPath();
+void PROTOC_EXPORT SetPackageToPrefixMappingsPath(
+    const std::string& file_path);
+// Get/Set if the proto package should be used to make the default prefix for
+// symbols. This will then impact most of the type naming apis below. It is done
+// as a global to not break any other generator reusing the methods since they
+// are exported.
+bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix();
+void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off);
+// Get/Set the path to a file to load as exceptions when
+// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there
+// should be no exceptions.
+std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList();
+void PROTOC_EXPORT SetProtoPackagePrefixExceptionList(
+    const std::string& file_path);
+
+// Generator Prefix Validation Options (see objectivec_generator.cc for a
+// description of each):
+struct Options {
+  Options();
+  std::string expected_prefixes_path;
+  std::vector<std::string> expected_prefixes_suppressions;
+  bool prefixes_must_be_registered;
+  bool require_prefixes;
+};
+
+// Escape C++ trigraphs by escaping question marks to "\?".
+std::string PROTOC_EXPORT EscapeTrigraphs(const std::string& to_escape);
+
+// Remove white space from either end of a StringPiece.
+void PROTOC_EXPORT TrimWhitespace(StringPiece* input);
+
+// Returns true if the name requires a ns_returns_not_retained attribute applied
+// to it.
+bool PROTOC_EXPORT IsRetainedName(const std::string& name);
+
+// Returns true if the name starts with "init" and will need to have special
+// handling under ARC.
+bool PROTOC_EXPORT IsInitName(const std::string& name);
+
+// Gets the objc_class_prefix or the prefix made from the proto package.
+std::string PROTOC_EXPORT FileClassPrefix(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.
+std::string PROTOC_EXPORT FilePath(const FileDescriptor* file);
+
+// Just like FilePath(), but without the directory part.
+std::string PROTOC_EXPORT FilePathBasename(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
+std::string PROTOC_EXPORT FileClassName(const FileDescriptor* file);
+
+// These return the fully-qualified class name corresponding to the given
+// descriptor.
+std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor);
+std::string PROTOC_EXPORT ClassName(const Descriptor* descriptor,
+                                    std::string* out_suffix_added);
+std::string PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor);
+
+// Returns the fully-qualified name of the enum value corresponding to the
+// the descriptor.
+std::string PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor);
+
+// Returns the name of the enum value corresponding to the descriptor.
+std::string PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor);
+
+// Reverse what an enum does.
+std::string PROTOC_EXPORT UnCamelCaseEnumShortName(const std::string& name);
+
+// Returns the name to use for the extension (used as the method off the file's
+// Root class).
+std::string PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor);
+
+// Returns the transformed field name.
+std::string PROTOC_EXPORT FieldName(const FieldDescriptor* field);
+std::string PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field);
+
+// Returns the transformed oneof name.
+std::string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor);
+std::string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor);
+std::string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor);
+
+// Returns a symbol that can be used in C code to refer to an Objective C
+// class without initializing the class.
+std::string PROTOC_EXPORT ObjCClass(const std::string& class_name);
+
+// Declares an Objective C class without initializing the class so that it can
+// be refrerred to by ObjCClass.
+std::string PROTOC_EXPORT ObjCClassDeclaration(const std::string& class_name);
+
+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.
+std::string PROTOC_EXPORT UnCamelCaseFieldName(const std::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
+};
+
+enum FlagType {
+  FLAGTYPE_DESCRIPTOR_INITIALIZATION,
+  FLAGTYPE_EXTENSION,
+  FLAGTYPE_FIELD
+};
+
+template <class TDescriptor>
+std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor,
+                                           const FileDescriptor* file = NULL,
+                                           bool preSpace = true,
+                                           bool postNewline = false) {
+  bool isDeprecated = descriptor->options().deprecated();
+  // The file is only passed when checking Messages & Enums, so those types
+  // get tagged. At the moment, it doesn't seem to make sense to tag every
+  // field or enum value with when the file is deprecated.
+  bool isFileLevelDeprecation = false;
+  if (!isDeprecated && file) {
+    isFileLevelDeprecation = file->options().deprecated();
+    isDeprecated = isFileLevelDeprecation;
+  }
+  if (isDeprecated) {
+    std::string message;
+    const FileDescriptor* sourceFile = descriptor->file();
+    if (isFileLevelDeprecation) {
+      message = sourceFile->name() + " is deprecated.";
+    } else {
+      message = descriptor->full_name() + " is deprecated (see " +
+                sourceFile->name() + ").";
+    }
+
+    std::string result = std::string("GPB_DEPRECATED_MSG(\"") + message + "\")";
+    if (preSpace) {
+      result.insert(0, " ");
+    }
+    if (postNewline) {
+      result.append("\n");
+    }
+    return result;
+  } else {
+    return "";
+  }
+}
+
+std::string PROTOC_EXPORT GetCapitalizedType(const FieldDescriptor* field);
+
+ObjectiveCType PROTOC_EXPORT
+GetObjectiveCType(FieldDescriptor::Type field_type);
+
+inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
+  return GetObjectiveCType(field->type());
+}
+
+bool PROTOC_EXPORT IsPrimitiveType(const FieldDescriptor* field);
+bool PROTOC_EXPORT IsReferenceType(const FieldDescriptor* field);
+
+std::string PROTOC_EXPORT
+GPBGenericValueFieldName(const FieldDescriptor* field);
+std::string PROTOC_EXPORT DefaultValue(const FieldDescriptor* field);
+bool PROTOC_EXPORT HasNonZeroDefaultValue(const FieldDescriptor* field);
+
+std::string PROTOC_EXPORT
+BuildFlagsString(const FlagType type, const std::vector<std::string>& strings);
+
+// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
+// file.
+std::string PROTOC_EXPORT BuildCommentsString(const SourceLocation& location,
+                                              bool prefer_single_line);
+
+// The name the commonly used by the library when built as a framework.
+// This lines up to the name used in the CocoaPod.
+extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName;
+// Returns the CPP symbol name to use as the gate for framework style imports
+// for the given framework name to use.
+std::string PROTOC_EXPORT
+ProtobufFrameworkImportSymbol(const std::string& framework_name);
+
+// Checks if the file is one of the proto's bundled with the library.
+bool PROTOC_EXPORT
+IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
+
+// Checks the prefix for the given files and outputs any warnings as needed. If
+// there are flat out errors, then out_error is filled in with the first error
+// and the result is false.
+bool PROTOC_EXPORT ValidateObjCClassPrefixes(
+    const std::vector<const FileDescriptor*>& files,
+    const Options& validation_options, std::string* out_error);
+// Same was the other ValidateObjCClassPrefixes() calls, but the options all
+// come from the environment variables.
+bool PROTOC_EXPORT ValidateObjCClassPrefixes(
+    const std::vector<const FileDescriptor*>& files, std::string* out_error);
+
+// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
+// the input into the expected output.
+class PROTOC_EXPORT TextFormatDecodeData {
+ public:
+  TextFormatDecodeData();
+  ~TextFormatDecodeData();
+
+  TextFormatDecodeData(const TextFormatDecodeData&) = delete;
+  TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete;
+
+  void AddString(int32_t key, const std::string& input_for_decode,
+                 const std::string& desired_output);
+  size_t num_entries() const { return entries_.size(); }
+  std::string Data() const;
+
+  static std::string DecodeDataForString(const std::string& input_for_decode,
+                                         const std::string& desired_output);
+
+ private:
+  typedef std::pair<int32_t, std::string> DataEntry;
+  std::vector<DataEntry> entries_;
+};
+
+// Helper for parsing simple files.
+class PROTOC_EXPORT LineConsumer {
+ public:
+  LineConsumer();
+  virtual ~LineConsumer();
+  virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) = 0;
+};
+
+bool PROTOC_EXPORT ParseSimpleFile(const std::string& path,
+                                   LineConsumer* line_consumer,
+                                   std::string* out_error);
+
+bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream,
+                                     const std::string& stream_name,
+                                     LineConsumer* line_consumer,
+                                     std::string* out_error);
+
+// Helper class for parsing framework import mappings and generating
+// import statements.
+class PROTOC_EXPORT ImportWriter {
+ public:
+  ImportWriter(const std::string& generate_for_named_framework,
+               const std::string& named_framework_to_proto_path_mappings_path,
+               const std::string& runtime_import_prefix,
+               bool include_wkt_imports);
+  ~ImportWriter();
+
+  void AddFile(const FileDescriptor* file, const std::string& header_extension);
+  void Print(io::Printer* printer) const;
+
+  static void PrintRuntimeImports(io::Printer* printer,
+                                  const std::vector<std::string>& header_to_import,
+                                  const std::string& runtime_import_prefix,
+                                  bool default_cpp_symbol = false);
+
+ private:
+  class ProtoFrameworkCollector : public LineConsumer {
+   public:
+    ProtoFrameworkCollector(std::map<std::string, std::string>* inout_proto_file_to_framework_name)
+        : map_(inout_proto_file_to_framework_name) {}
+
+    virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override;
+
+   private:
+    std::map<std::string, std::string>* map_;
+  };
+
+  void ParseFrameworkMappings();
+
+  const std::string generate_for_named_framework_;
+  const std::string named_framework_to_proto_path_mappings_path_;
+  const std::string runtime_import_prefix_;
+  const bool include_wkt_imports_;
+  std::map<std::string, std::string> proto_file_to_framework_name_;
+  bool need_to_parse_mapping_file_;
+
+  std::vector<std::string> protobuf_imports_;
+  std::vector<std::string> other_framework_imports_;
+  std::vector<std::string> other_imports_;
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..7ae6a92
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
@@ -0,0 +1,384 @@
+// 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/io/zero_copy_stream_impl_lite.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+namespace {
+
+TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_RawStrings) {
+  std::string input_for_decode("abcdefghIJ");
+  std::string desired_output_for_decode;
+  std::string expected;
+  std::string result;
+
+  // Different data, can't transform.
+
+  desired_output_for_decode = "zbcdefghIJ";
+  expected = std::string("\0zbcdefghIJ\0", 12);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  desired_output_for_decode = "abcdezghIJ";
+  expected = std::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 = std::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 = std::string("\0abcdefghIJz\0", 13);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+}
+
+TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_ByteCodes) {
+  std::string input_for_decode("abcdefghIJ");
+  std::string desired_output_for_decode;
+  std::string expected;
+  std::string result;
+
+  desired_output_for_decode = "abcdefghIJ";
+  expected = std::string("\x0A\x0", 2);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  desired_output_for_decode = "_AbcdefghIJ";
+  expected = std::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 = std::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 = std::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.
+
+  std::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_t 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,
+  };
+  std::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_t 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,
+  };
+  std::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.
+
+  std::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
+
+class TestLineCollector : public LineConsumer {
+ public:
+  TestLineCollector(std::vector<std::string>* inout_lines,
+                    const std::string* reject_line = nullptr,
+                    bool skip_msg = false)
+    : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {}
+
+  bool ConsumeLine(const StringPiece& line, std::string* out_error) override {
+    if (reject_ && *reject_ == line) {
+      if (!skip_msg_) {
+        *out_error = std::string("Rejected '") + *reject_ + "'";
+      }
+      return false;
+    }
+    if (lines_) {
+      lines_->emplace_back(line);
+    }
+    return true;
+  }
+
+ private:
+  std::vector<std::string>* lines_;
+  const std::string* reject_;
+  bool skip_msg_;
+};
+
+const int kBlockSizes[] = {-1, 1, 2, 5, 64};
+const int kBlockSizeCount = GOOGLE_ARRAYSIZE(kBlockSizes);
+
+TEST(ObjCHelper, ParseSimple_BasicsSuccess) {
+  const std::vector<std::pair<std::string, std::vector<std::string>>> tests = {
+    {"", {}},
+    {"a", {"a"}},
+    {"a c", {"a c"}},
+    {" a c ", {"a c"}},
+    {"\ta c ", {"a c"}},
+    {"abc\n", {"abc"}},
+    {"abc\nd f", {"abc", "d f"}},
+    {"\n abc \n def \n\n", {"abc", "def"}},
+  };
+
+  for (const auto& test : tests) {
+    for (int i = 0; i < kBlockSizeCount; i++) {
+      io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]);
+      std::string err_str;
+      std::vector<std::string> lines;
+      TestLineCollector collector(&lines);
+      EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str));
+      EXPECT_EQ(lines, test.second);
+      EXPECT_TRUE(err_str.empty());
+    }
+  }
+}
+
+TEST(ObjCHelper, ParseSimple_DropsComments) {
+  const std::vector<std::pair<std::string, std::vector<std::string>>> tests = {
+    {"# nothing", {}},
+    {"#", {}},
+    {"##", {}},
+    {"\n# nothing\n", {}},
+    {"a # same line", {"a"}},
+    {"a # same line\n", {"a"}},
+    {"a\n# line\nc", {"a", "c"}},
+    {"# n o t # h i n g #", {}},
+    {"## n o # t h i n g #", {}},
+    {"a# n o t # h i n g #", {"a"}},
+    {"a\n## n o # t h i n g #", {"a"}},
+  };
+
+  for (const auto& test : tests) {
+    for (int i = 0; i < kBlockSizeCount; i++) {
+      io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]);
+      std::string err_str;
+      std::vector<std::string> lines;
+      TestLineCollector collector(&lines);
+      EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str));
+      EXPECT_EQ(lines, test.second);
+      EXPECT_TRUE(err_str.empty());
+    }
+  }
+}
+
+TEST(ObjCHelper, ParseSimple_RejectLines) {
+  const std::vector<std::tuple<std::string, std::string, int>> tests = {
+    std::make_tuple("a\nb\nc", "a", 1),
+    std::make_tuple("a\nb\nc", "b", 2),
+    std::make_tuple("a\nb\nc", "c", 3),
+    std::make_tuple("a\nb\nc\n", "c", 3),
+  };
+
+  for (const auto& test : tests) {
+    for (int i = 0; i < kBlockSizeCount; i++) {
+      io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(),
+                                 kBlockSizes[i]);
+      std::string err_str;
+      TestLineCollector collector(nullptr, &std::get<1>(test));
+      EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str));
+      std::string expected_err =
+        StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '", std::get<1>(test), "'");
+      EXPECT_EQ(err_str, expected_err);
+    }
+  }
+}
+
+TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) {
+  const std::vector<std::tuple<std::string, std::string, int>> tests = {
+    std::make_tuple("a\nb\nc", "a", 1),
+    std::make_tuple("a\nb\nc", "b", 2),
+    std::make_tuple("a\nb\nc", "c", 3),
+    std::make_tuple("a\nb\nc\n", "c", 3),
+  };
+
+  for (const auto& test : tests) {
+    for (int i = 0; i < kBlockSizeCount; i++) {
+      io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(),
+                                 kBlockSizes[i]);
+      std::string err_str;
+      TestLineCollector collector(nullptr, &std::get<1>(test), true /* skip msg */);
+      EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str));
+      std::string expected_err =
+        StrCat("error: dummy Line ", std::get<2>(test),
+               ", ConsumeLine failed without setting an error.");
+      EXPECT_EQ(err_str, expected_err);
+    }
+  }
+}
+
+// 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..99d7581
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -0,0 +1,196 @@
+// 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/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.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()->map_key();
+  const FieldDescriptor* value_descriptor =
+      descriptor->message_type()->map_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<std::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") !=
+      std::string::npos) {
+    field_flags.push_back("GPBFieldTextFormatNameCustom");
+  }
+  // Pull over some info from the value's flags.
+  const std::string& value_field_flags =
+      value_field_generator_->variable("fieldflags");
+  if (value_field_flags.find("GPBFieldHasDefaultValue") != std::string::npos) {
+    field_flags.push_back("GPBFieldHasDefaultValue");
+  }
+  if (value_field_flags.find("GPBFieldHasEnumDescriptor") !=
+      std::string::npos) {
+    field_flags.push_back("GPBFieldHasEnumDescriptor");
+  }
+
+  variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
+
+  ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
+  const bool value_is_object_type =
+      ((value_objc_type == OBJECTIVECTYPE_STRING) ||
+       (value_objc_type == OBJECTIVECTYPE_DATA) ||
+       (value_objc_type == OBJECTIVECTYPE_MESSAGE));
+  if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
+      value_is_object_type) {
+    variables_["array_storage_type"] = "NSMutableDictionary";
+    variables_["array_property_type"] =
+        "NSMutableDictionary<NSString*, " +
+        value_field_generator_->variable("storage_type") + "*>";
+  } else {
+    std::string class_name("GPB");
+    class_name += MapEntryTypeName(key_descriptor, true);
+    class_name += MapEntryTypeName(value_descriptor, false);
+    class_name += "Dictionary";
+    variables_["array_storage_type"] = class_name;
+    if (value_is_object_type) {
+      variables_["array_property_type"] =
+          class_name + "<" +
+          value_field_generator_->variable("storage_type") + "*>";
+    }
+  }
+
+  variables_["dataTypeSpecific_name"] =
+      value_field_generator_->variable("dataTypeSpecific_name");
+  variables_["dataTypeSpecific_value"] =
+      value_field_generator_->variable("dataTypeSpecific_value");
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  // Use the array_comment support in RepeatedFieldGenerator to output what the
+  // values in the map are.
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->map_value();
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) {
+    variables_["array_comment"] =
+        "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
+  }
+}
+
+void MapFieldGenerator::DetermineForwardDeclarations(
+    std::set<std::string>* fwd_decls,
+    bool include_external_types) const {
+  RepeatedFieldGenerator::DetermineForwardDeclarations(
+      fwd_decls, include_external_types);
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->map_value();
+  // Within a file there is no requirement on the order of the messages, so
+  // local references need a forward declaration. External files (not WKTs),
+  // need one when requested.
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE &&
+      ((include_external_types &&
+        !IsProtobufLibraryBundledProtoFile(value_descriptor->file())) ||
+       descriptor_->file() == value_descriptor->file())) {
+    const std::string& value_storage_type =
+        value_field_generator_->variable("storage_type");
+    fwd_decls->insert("@class " + value_storage_type);
+  }
+}
+
+void MapFieldGenerator::DetermineObjectiveCClassDefinitions(
+    std::set<std::string>* fwd_decls) const {
+  // Class name is already in "storage_type".
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->map_value();
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
+    fwd_decls->insert(ObjCClassDeclaration(
+        value_field_generator_->variable("storage_type")));
+  }
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
new file mode 100644
index 0000000..d9aa387
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
@@ -0,0 +1,71 @@
+// 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) override;
+
+  MapFieldGenerator(const MapFieldGenerator&) = delete;
+  MapFieldGenerator& operator=(const MapFieldGenerator&) = delete;
+
+ protected:
+  explicit MapFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~MapFieldGenerator();
+
+  virtual void DetermineObjectiveCClassDefinitions(
+      std::set<std::string>* fwd_decls) const override;
+  virtual void DetermineForwardDeclarations(
+      std::set<std::string>* fwd_decls,
+      bool include_external_types) const override;
+
+ private:
+  std::unique_ptr<FieldGenerator> value_field_generator_;
+};
+
+}  // 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..4ebb75c
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -0,0 +1,633 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+struct FieldOrderingByNumber {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    return a->number() < b->number();
+  }
+};
+
+int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
+  // The first item in the object structure is our uint32[] for has bits.
+  // We then want to order things to make the instances as small as
+  // possible. So we follow the has bits with:
+  //   1. Anything always 4 bytes - float, *32, enums
+  //   2. Anything that is always a pointer (they will be 8 bytes on 64 bit
+  //      builds and 4 bytes on 32bit builds.
+  //   3. Anything always 8 bytes - double, *64
+  //
+  // NOTE: Bools aren't listed, they were stored in the has bits.
+  //
+  // Why? Using 64bit builds as an example, this means worse case, we have
+  // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes
+  // are wasted before the 4 byte values. Then if we have an odd number of
+  // those 4 byte values, the 8 byte values will be pushed down by 32bits to
+  // keep them aligned. But the structure will end 8 byte aligned, so no
+  // waste on the end. If you did the reverse order, you could waste 4 bytes
+  // before the first 8 byte value (after the has array), then a single
+  // bool on the end would need 7 bytes of padding to make the overall
+  // structure 8 byte aligned; so 11 bytes, wasted total.
+
+  // Anything repeated is a GPB*Array/NSArray, so pointer.
+  if (descriptor->is_repeated()) {
+    return 3;
+  }
+
+  switch (descriptor->type()) {
+    // All always 8 bytes.
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_FIXED64:
+      return 4;
+
+    // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes
+    // depending on the build architecture.
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      return 3;
+
+    // All always 4 bytes (enums are int32s).
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_ENUM:
+      return 2;
+
+    // 0 bytes. Stored in the has bits.
+    case FieldDescriptor::TYPE_BOOL:
+      return 99;  // End of the list (doesn't really matter).
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return 0;
+}
+
+struct FieldOrderingByStorageSize {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    // Order by grouping.
+    const int order_group_a = OrderGroupForFieldDescriptor(a);
+    const int order_group_b = OrderGroupForFieldDescriptor(b);
+    if (order_group_a != order_group_b) {
+      return order_group_a < order_group_b;
+    }
+    // Within the group, order by field number (provides stable ordering).
+    return a->number() < b->number();
+  }
+};
+
+struct ExtensionRangeOrdering {
+  bool operator()(const Descriptor::ExtensionRange* a,
+                  const Descriptor::ExtensionRange* b) const {
+    return a->start < b->start;
+  }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+  const FieldDescriptor** fields =
+      new const FieldDescriptor* [descriptor->field_count()];
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields[i] = descriptor->field(i);
+  }
+  std::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);
+  }
+  std::sort(fields, fields + descriptor->field_count(),
+       FieldOrderingByStorageSize());
+  return fields;
+}
+}  // namespace
+
+MessageGenerator::MessageGenerator(const std::string& root_classname,
+                                   const Descriptor* descriptor)
+    : root_classname_(root_classname),
+      descriptor_(descriptor),
+      field_generators_(descriptor),
+      class_name_(ClassName(descriptor_)),
+      deprecated_attribute_(GetOptionalDeprecatedAttribute(
+          descriptor, descriptor->file(), false, true)) {
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    extension_generators_.emplace_back(
+        new ExtensionGenerator(class_name_, descriptor_->extension(i)));
+  }
+
+  for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
+    OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
+    oneof_generators_.emplace_back(generator);
+  }
+
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i));
+    enum_generators_.emplace_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_.emplace_back(generator);
+  }
+}
+
+MessageGenerator::~MessageGenerator() {}
+
+void MessageGenerator::GenerateStaticVariablesInitialization(
+    io::Printer* printer) {
+  for (const auto& generator : extension_generators_) {
+    generator->GenerateStaticVariablesInitialization(printer);
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->GenerateStaticVariablesInitialization(printer);
+  }
+}
+
+void MessageGenerator::DetermineForwardDeclarations(
+    std::set<std::string>* fwd_decls,
+    bool include_external_types) {
+  if (!IsMapEntryMessage(descriptor_)) {
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+      field_generators_.get(fieldDescriptor)
+          .DetermineForwardDeclarations(fwd_decls, include_external_types);
+    }
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->DetermineForwardDeclarations(fwd_decls, include_external_types);
+  }
+}
+
+void MessageGenerator::DetermineObjectiveCClassDefinitions(
+    std::set<std::string>* fwd_decls) {
+  if (!IsMapEntryMessage(descriptor_)) {
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+      field_generators_.get(fieldDescriptor)
+          .DetermineObjectiveCClassDefinitions(fwd_decls);
+    }
+  }
+
+  for (const auto& generator : extension_generators_) {
+    generator->DetermineObjectiveCClassDefinitions(fwd_decls);
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->DetermineObjectiveCClassDefinitions(fwd_decls);
+  }
+
+  const Descriptor* containing_descriptor = descriptor_->containing_type();
+  if (containing_descriptor != NULL) {
+    std::string containing_class = ClassName(containing_descriptor);
+    fwd_decls->insert(ObjCClassDeclaration(containing_class));
+  }
+}
+
+bool MessageGenerator::IncludesOneOfDefinition() const {
+  if (!oneof_generators_.empty()) {
+    return true;
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    if (generator->IncludesOneOfDefinition()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
+  for (const auto& generator : enum_generators_) {
+    generator->GenerateHeader(printer);
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->GenerateEnumHeader(printer);
+  }
+}
+
+void MessageGenerator::GenerateExtensionRegistrationSource(
+    io::Printer* printer) {
+  for (const auto& generator : extension_generators_) {
+    generator->GenerateRegistrationSource(printer);
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->GenerateExtensionRegistrationSource(printer);
+  }
+}
+
+void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
+  // This a a map entry message, just recurse and do nothing directly.
+  if (IsMapEntryMessage(descriptor_)) {
+    for (const auto& generator : nested_message_generators_) {
+      generator->GenerateMessageHeader(printer);
+    }
+    return;
+  }
+
+  printer->Print(
+      "#pragma mark - $classname$\n"
+      "\n",
+      "classname", class_name_);
+
+  if (descriptor_->field_count()) {
+    std::unique_ptr<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 (const auto& generator : oneof_generators_) {
+    generator->GenerateCaseEnum(printer);
+  }
+
+  std::string message_comments;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    message_comments = BuildCommentsString(location, false);
+  } else {
+    message_comments = "";
+  }
+
+  printer->Print(
+      "$comments$$deprecated_attribute$GPB_FINAL @interface $classname$ : GPBMessage\n\n",
+      "classname", class_name_,
+      "deprecated_attribute", deprecated_attribute_,
+      "comments", message_comments);
+
+  std::vector<char> seen_oneofs(oneof_generators_.size(), 0);
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const OneofDescriptor* oneof = field->real_containing_oneof();
+    if (oneof) {
+      const int oneof_index = 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 (const auto& generator : oneof_generators_) {
+      generator->GenerateClearFunctionDeclaration(printer);
+    }
+    printer->Print("\n");
+  }
+
+  if (descriptor_->extension_count() > 0) {
+    printer->Print("@interface $classname$ (DynamicMethods)\n\n",
+                   "classname", class_name_);
+    for (const auto& generator : extension_generators_) {
+      generator->GenerateMembersHeader(printer);
+    }
+    printer->Print("@end\n\n");
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->GenerateMessageHeader(printer);
+  }
+}
+
+void MessageGenerator::GenerateSource(io::Printer* printer) {
+  if (!IsMapEntryMessage(descriptor_)) {
+    printer->Print(
+        "#pragma mark - $classname$\n"
+        "\n",
+        "classname", class_name_);
+
+    if (!deprecated_attribute_.empty()) {
+      // No warnings when compiling the impl of this deprecated class.
+      printer->Print(
+          "#pragma clang diagnostic push\n"
+          "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n"
+          "\n");
+    }
+
+    printer->Print("@implementation $classname$\n\n",
+                   "classname", class_name_);
+
+    for (const auto& generator : oneof_generators_) {
+      generator->GeneratePropertyImplementation(printer);
+    }
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(descriptor_->field(i))
+          .GeneratePropertyImplementation(printer);
+    }
+
+    std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
+        SortFieldsByNumber(descriptor_));
+    std::unique_ptr<const FieldDescriptor*[]> size_order_fields(
+        SortFieldsByStorageSize(descriptor_));
+
+    std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
+    sorted_extensions.reserve(descriptor_->extension_range_count());
+    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());
+
+    // Assign has bits:
+    // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing
+    //    who needs has bits and assigning them.
+    // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
+    //    index that groups all the elements in the oneof.
+    size_t num_has_bits = field_generators_.CalculateHasBits();
+    size_t sizeof_has_storage = (num_has_bits + 31) / 32;
+    if (sizeof_has_storage == 0) {
+      // In the case where no field needs has bits, don't let the _has_storage_
+      // end up as zero length (zero length arrays are sort of a grey area
+      // since it has to be at the start of the struct). This also ensures a
+      // field with only oneofs keeps the required negative indices they need.
+      sizeof_has_storage = 1;
+    }
+    // Tell all the fields the oneof base.
+    for (const auto& generator : oneof_generators_) {
+      generator->SetOneofIndexBase(sizeof_has_storage);
+    }
+    field_generators_.SetOneofIndexBase(sizeof_has_storage);
+    // sizeof_has_storage needs enough bits for the single fields that aren't in
+    // any oneof, and then one int32 for each oneof (to store the field number).
+    sizeof_has_storage += oneof_generators_.size();
+
+    printer->Print(
+        "\n"
+        "typedef struct $classname$__storage_ {\n"
+        "  uint32_t _has_storage_[$sizeof_has_storage$];\n",
+        "classname", class_name_,
+        "sizeof_has_storage", StrCat(sizeof_has_storage));
+    printer->Indent();
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(size_order_fields[i])
+          .GenerateFieldStorageDeclaration(printer);
+    }
+    printer->Outdent();
+
+    printer->Print("} $classname$__storage_;\n\n", "classname", class_name_);
+
+
+    printer->Print(
+        "// This method is threadsafe because it is initially called\n"
+        "// in +initialize for each subclass.\n"
+        "+ (GPBDescriptor *)descriptor {\n"
+        "  static GPBDescriptor *descriptor = nil;\n"
+        "  if (!descriptor) {\n");
+
+    TextFormatDecodeData text_format_decode_data;
+    bool has_fields = descriptor_->field_count() > 0;
+    bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault();
+    std::string field_description_type;
+    if (need_defaults) {
+      field_description_type = "GPBMessageFieldDescriptionWithDefault";
+    } else {
+      field_description_type = "GPBMessageFieldDescription";
+    }
+    if (has_fields) {
+      printer->Indent();
+      printer->Indent();
+      printer->Print(
+          "static $field_description_type$ fields[] = {\n",
+          "field_description_type", field_description_type);
+      printer->Indent();
+      for (int i = 0; i < descriptor_->field_count(); ++i) {
+        const FieldGenerator& field_generator =
+            field_generators_.get(sorted_fields[i]);
+        field_generator.GenerateFieldDescription(printer, need_defaults);
+        if (field_generator.needs_textformat_name_support()) {
+          text_format_decode_data.AddString(sorted_fields[i]->number(),
+                                            field_generator.generated_objc_name(),
+                                            field_generator.raw_field_name());
+        }
+      }
+      printer->Outdent();
+      printer->Print(
+          "};\n");
+      printer->Outdent();
+      printer->Outdent();
+    }
+
+    std::map<std::string, std::string> vars;
+    vars["classname"] = class_name_;
+    vars["rootclassname"] = root_classname_;
+    vars["fields"] = has_fields ? "fields" : "NULL";
+    if (has_fields) {
+      vars["fields_count"] =
+          "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))";
+    } else {
+      vars["fields_count"] = "0";
+    }
+
+    std::vector<std::string> init_flags;
+    init_flags.push_back("GPBDescriptorInitializationFlag_UsesClassRefs");
+    init_flags.push_back("GPBDescriptorInitializationFlag_Proto3OptionalKnown");
+    if (need_defaults) {
+      init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault");
+    }
+    if (descriptor_->options().message_set_wire_format()) {
+      init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
+    }
+    vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION,
+                                          init_flags);
+
+    printer->Print(
+        vars,
+        "    GPBDescriptor *localDescriptor =\n"
+        "        [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
+        "                                     rootClass:[$rootclassname$ class]\n"
+        "                                          file:$rootclassname$_FileDescriptor()\n"
+        "                                        fields:$fields$\n"
+        "                                    fieldCount:$fields_count$\n"
+        "                                   storageSize:sizeof($classname$__storage_)\n"
+        "                                         flags:$init_flags$];\n");
+    if (!oneof_generators_.empty()) {
+      printer->Print(
+          "    static const char *oneofs[] = {\n");
+      for (const auto& generator : oneof_generators_) {
+        printer->Print("      \"$name$\",\n", "name",
+                       generator->DescriptorName());
+      }
+      printer->Print(
+          "    };\n"
+          "    [localDescriptor setupOneofs:oneofs\n"
+          "                           count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n"
+          "                   firstHasIndex:$first_has_index$];\n",
+          "first_has_index", oneof_generators_[0]->HasIndexAsString());
+    }
+    if (text_format_decode_data.num_entries() != 0) {
+      const std::string text_format_data_str(text_format_decode_data.Data());
+      printer->Print(
+          "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
+          "    static const char *extraTextFormatInfo =");
+      static const int kBytesPerLine = 40;  // allow for escaping
+      for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) {
+        printer->Print(
+            "\n        \"$data$\"",
+            "data", EscapeTrigraphs(
+                CEscape(text_format_data_str.substr(i, kBytesPerLine))));
+      }
+      printer->Print(
+          ";\n"
+          "    [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n"
+          "#endif  // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n");
+    }
+    if (!sorted_extensions.empty()) {
+      printer->Print(
+          "    static const GPBExtensionRange ranges[] = {\n");
+      for (int i = 0; i < sorted_extensions.size(); i++) {
+        printer->Print("      { .start = $start$, .end = $end$ },\n",
+                       "start", StrCat(sorted_extensions[i]->start),
+                       "end", StrCat(sorted_extensions[i]->end));
+      }
+      printer->Print(
+          "    };\n"
+          "    [localDescriptor setupExtensionRanges:ranges\n"
+          "                                    count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
+    }
+    if (descriptor_->containing_type() != NULL) {
+      std::string containing_class = ClassName(descriptor_->containing_type());
+      std::string parent_class_ref = ObjCClass(containing_class);
+      printer->Print(
+          "    [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n",
+          "parent_class_ref", parent_class_ref);
+    }
+    std::string suffix_added;
+    ClassName(descriptor_, &suffix_added);
+    if (!suffix_added.empty()) {
+      printer->Print(
+          "    [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
+          "suffix", suffix_added);
+    }
+    printer->Print(
+        "    #if defined(DEBUG) && DEBUG\n"
+        "      NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
+        "    #endif  // DEBUG\n"
+        "    descriptor = localDescriptor;\n"
+        "  }\n"
+        "  return descriptor;\n"
+        "}\n\n"
+        "@end\n\n");
+
+    if (!deprecated_attribute_.empty()) {
+      printer->Print(
+          "#pragma clang diagnostic pop\n"
+          "\n");
+    }
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateCFunctionImplementations(printer);
+    }
+
+    for (const auto& generator : oneof_generators_) {
+      generator->GenerateClearFunctionImplementation(printer);
+    }
+  }
+
+  for (const auto& generator : enum_generators_) {
+    generator->GenerateSource(printer);
+  }
+
+  for (const auto& generator : nested_message_generators_) {
+    generator->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..9d14430
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h
@@ -0,0 +1,99 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_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_oneof.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class ExtensionGenerator;
+class EnumGenerator;
+
+class MessageGenerator {
+ public:
+  MessageGenerator(const std::string& root_classname,
+                   const Descriptor* descriptor);
+  ~MessageGenerator();
+
+  MessageGenerator(const MessageGenerator&) = delete;
+  MessageGenerator& operator=(const MessageGenerator&) = delete;
+
+  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 DetermineObjectiveCClassDefinitions(std::set<std::string>* fwd_decls);
+  void DetermineForwardDeclarations(std::set<std::string>* fwd_decls,
+                                    bool include_external_types);
+
+  // Checks if the message or a nested message includes a oneof definition.
+  bool IncludesOneOfDefinition() const;
+
+ 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 std::string root_classname_;
+  const Descriptor* descriptor_;
+  FieldGeneratorMap field_generators_;
+  const std::string class_name_;
+  const std::string deprecated_attribute_;
+  std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_;
+  std::vector<std::unique_ptr<EnumGenerator>> enum_generators_;
+  std::vector<std::unique_ptr<MessageGenerator>> nested_message_generators_;
+  std::vector<std::unique_ptr<OneofGenerator>> oneof_generators_;
+};
+
+}  // 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..2ff0b44
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
@@ -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.
+
+#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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         std::map<std::string, std::string>* variables) {
+  const std::string& message_type = ClassName(descriptor->message_type());
+  const std::string& containing_class =
+      ClassName(descriptor->containing_type());
+  (*variables)["type"] = message_type;
+  (*variables)["containing_class"] = containing_class;
+  (*variables)["storage_type"] = message_type;
+  (*variables)["group_or_message"] =
+      (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message";
+  (*variables)["dataTypeSpecific_value"] = ObjCClass(message_type);
+}
+
+}  // namespace
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor)
+    : ObjCObjFieldGenerator(descriptor) {
+  SetMessageVariables(descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::DetermineForwardDeclarations(
+    std::set<std::string>* fwd_decls,
+    bool include_external_types) const {
+  ObjCObjFieldGenerator::DetermineForwardDeclarations(
+      fwd_decls, include_external_types);
+  // Within a file there is no requirement on the order of the messages, so
+  // local references need a forward declaration. External files (not WKTs),
+  // need one when requested.
+  if ((include_external_types &&
+       !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) ||
+      descriptor_->file() == descriptor_->message_type()->file()) {
+    // Class name is already in "storage_type".
+    fwd_decls->insert("@class " + variable("storage_type"));
+  }
+}
+
+void MessageFieldGenerator::DetermineObjectiveCClassDefinitions(
+    std::set<std::string>* fwd_decls) const {
+  fwd_decls->insert(ObjCClassDeclaration(variable("storage_type")));
+}
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+    const FieldDescriptor* descriptor)
+    : RepeatedFieldGenerator(descriptor) {
+  SetMessageVariables(descriptor, &variables_);
+  variables_["array_storage_type"] = "NSMutableArray";
+  variables_["array_property_type"] =
+      "NSMutableArray<" + variables_["storage_type"] + "*>";
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::DetermineForwardDeclarations(
+    std::set<std::string>* fwd_decls,
+    bool include_external_types) const {
+  RepeatedFieldGenerator::DetermineForwardDeclarations(
+      fwd_decls, include_external_types);
+  // Within a file there is no requirement on the order of the messages, so
+  // local references need a forward declaration. External files (not WKTs),
+  // need one when requested.
+  if ((include_external_types &&
+       !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) ||
+      descriptor_->file() == descriptor_->message_type()->file()) {
+    // Class name is already in "storage_type".
+    fwd_decls->insert("@class " + variable("storage_type"));
+  }
+}
+
+void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions(
+    std::set<std::string>* fwd_decls) const {
+  fwd_decls->insert(ObjCClassDeclaration(variable("storage_type")));
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
new file mode 100644
index 0000000..49a84fb
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_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_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);
+
+  MessageFieldGenerator(const MessageFieldGenerator&) = delete;
+  MessageFieldGenerator& operator=(const MessageFieldGenerator&) = delete;
+
+  virtual ~MessageFieldGenerator();
+
+ public:
+  virtual void DetermineForwardDeclarations(
+      std::set<std::string>* fwd_decls,
+      bool include_external_types) const override;
+  virtual void DetermineObjectiveCClassDefinitions(
+      std::set<std::string>* fwd_decls) const override;
+};
+
+class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~RepeatedMessageFieldGenerator();
+
+  RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete;
+  RepeatedMessageFieldGenerator operator=(const RepeatedMessageFieldGenerator&) = delete;
+
+ public:
+  virtual void DetermineForwardDeclarations(
+      std::set<std::string>* fwd_decls,
+      bool include_external_types) const override;
+  virtual void DetermineObjectiveCClassDefinitions(
+      std::set<std::string>* fwd_decls) const override;
+};
+
+}  // 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_nsobject_methods.h b/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h
new file mode 100644
index 0000000..1633046
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h
@@ -0,0 +1,197 @@
+// NSObject methods
+// Autogenerated by method_dump.sh. Do not edit by hand.
+// Date: Thu Nov  1 14:12:16 PDT 2018
+// macOS: MacOSX10.14.sdk
+// iOS: iPhoneSimulator12.1.sdk
+
+const char* const kNSObjectMethodsList[] = {
+	"CAMLType",
+	"CA_copyRenderValue",
+	"CA_prepareRenderValue",
+	"NS_copyCGImage",
+	"NS_tiledLayerVisibleRect",
+	"___tryRetain_OA",
+	"__autorelease_OA",
+	"__dealloc_zombie",
+	"__release_OA",
+	"__retain_OA",
+	"_accessibilityFinalize",
+	"_accessibilityIsTableViewDescendant",
+	"_accessibilityUIElementSpecifier",
+	"_accessibilityUseConvenienceAPI",
+	"_allowsDirectEncoding",
+	"_asScriptTerminologyNameArray",
+	"_asScriptTerminologyNameString",
+	"_bindingAdaptor",
+	"_cfTypeID",
+	"_copyDescription",
+	"_destroyObserverList",
+	"_didEndKeyValueObserving",
+	"_implicitObservationInfo",
+	"_internalAccessibilityAttributedHint",
+	"_internalAccessibilityAttributedLabel",
+	"_internalAccessibilityAttributedValue",
+	"_isAXConnector",
+	"_isAccessibilityContainerSectionCandidate",
+	"_isAccessibilityContentNavigatorSectionCandidate",
+	"_isAccessibilityContentSectionCandidate",
+	"_isAccessibilityTopLevelNavigatorSectionCandidate",
+	"_isDeallocating",
+	"_isKVOA",
+	"_isToManyChangeInformation",
+	"_ivarDescription",
+	"_localClassNameForClass",
+	"_methodDescription",
+	"_observerStorage",
+	"_overrideUseFastBlockObservers",
+	"_propertyDescription",
+	"_releaseBindingAdaptor",
+	"_scriptingCount",
+	"_scriptingCountNonrecursively",
+	"_scriptingDebugDescription",
+	"_scriptingExists",
+	"_scriptingShouldCheckObjectIndexes",
+	"_shortMethodDescription",
+	"_shouldSearchChildrenForSection",
+	"_traitStorageList",
+	"_tryRetain",
+	"_ui_descriptionBuilder",
+	"_uikit_variesByTraitCollections",
+	"_web_description",
+	"_webkit_invokeOnMainThread",
+	"_willBeginKeyValueObserving",
+	"accessibilityActivate",
+	"accessibilityActivationPoint",
+	"accessibilityAllowsOverriddenAttributesWhenIgnored",
+	"accessibilityAssistiveTechnologyFocusedIdentifiers",
+	"accessibilityAttributedHint",
+	"accessibilityAttributedLabel",
+	"accessibilityAttributedValue",
+	"accessibilityContainer",
+	"accessibilityContainerType",
+	"accessibilityCustomActions",
+	"accessibilityCustomRotors",
+	"accessibilityDecrement",
+	"accessibilityDragSourceDescriptors",
+	"accessibilityDropPointDescriptors",
+	"accessibilityElementCount",
+	"accessibilityElementDidBecomeFocused",
+	"accessibilityElementDidLoseFocus",
+	"accessibilityElementIsFocused",
+	"accessibilityElements",
+	"accessibilityElementsHidden",
+	"accessibilityFrame",
+	"accessibilityHeaderElements",
+	"accessibilityHint",
+	"accessibilityIdentification",
+	"accessibilityIdentifier",
+	"accessibilityIncrement",
+	"accessibilityLabel",
+	"accessibilityLanguage",
+	"accessibilityLocalizedStringKey",
+	"accessibilityNavigationStyle",
+	"accessibilityOverriddenAttributes",
+	"accessibilityParameterizedAttributeNames",
+	"accessibilityPath",
+	"accessibilityPerformEscape",
+	"accessibilityPerformMagicTap",
+	"accessibilityPresenterProcessIdentifier",
+	"accessibilityShouldUseUniqueId",
+	"accessibilitySupportsNotifications",
+	"accessibilitySupportsOverriddenAttributes",
+	"accessibilityTemporaryChildren",
+	"accessibilityTraits",
+	"accessibilityValue",
+	"accessibilityViewIsModal",
+	"accessibilityVisibleArea",
+	"allPropertyKeys",
+	"allowsWeakReference",
+	"attributeKeys",
+	"autoContentAccessingProxy",
+	"autorelease",
+	"awakeFromNib",
+	"boolValueSafe",
+	"bs_encoded",
+	"bs_isPlistableType",
+	"bs_secureEncoded",
+	"cl_json_serializeKey",
+	"class",
+	"classCode",
+	"classDescription",
+	"classForArchiver",
+	"classForCoder",
+	"classForKeyedArchiver",
+	"classForPortCoder",
+	"className",
+	"clearProperties",
+	"copy",
+	"dealloc",
+	"debugDescription",
+	"defaultAccessibilityTraits",
+	"description",
+	"doubleValueSafe",
+	"entityName",
+	"exposedBindings",
+	"finalize",
+	"finishObserving",
+	"flushKeyBindings",
+	"hash",
+	"init",
+	"int64ValueSafe",
+	"isAccessibilityElement",
+	"isAccessibilityElementByDefault",
+	"isElementAccessibilityExposedToInterfaceBuilder",
+	"isFault",
+	"isNSArray__",
+	"isNSCFConstantString__",
+	"isNSData__",
+	"isNSDate__",
+	"isNSDictionary__",
+	"isNSNumber__",
+	"isNSObject__",
+	"isNSOrderedSet__",
+	"isNSSet__",
+	"isNSString__",
+	"isNSTimeZone__",
+	"isNSValue__",
+	"isProxy",
+	"mutableCopy",
+	"nilValueForKey",
+	"objectSpecifier",
+	"observationInfo",
+	"pep_onDetachedThread",
+	"pep_onMainThread",
+	"pep_onMainThreadIfNecessary",
+	"prepareForInterfaceBuilder",
+	"release",
+	"releaseOnMainThread",
+	"retain",
+	"retainCount",
+	"retainWeakReference",
+	"scriptingProperties",
+	"self",
+	"shouldGroupAccessibilityChildren",
+	"storedAccessibilityActivationPoint",
+	"storedAccessibilityContainerType",
+	"storedAccessibilityElementsHidden",
+	"storedAccessibilityFrame",
+	"storedAccessibilityNavigationStyle",
+	"storedAccessibilityTraits",
+	"storedAccessibilityViewIsModal",
+	"storedIsAccessibilityElement",
+	"storedShouldGroupAccessibilityChildren",
+	"stringValueSafe",
+	"superclass",
+	"toManyRelationshipKeys",
+	"toOneRelationshipKeys",
+	"traitStorageList",
+	"un_safeBoolValue",
+	"userInterfaceItemIdentifier",
+	"utf8ValueSafe",
+	"valuesForKeysWithDictionary",
+	"zone",
+// Protocol: CAAnimatableValue
+// Protocol: CARenderValue
+// Protocol: NSObject
+// Protocol: ROCKRemoteInvocationInterface
+};
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..1bef293
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.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 <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"] = StrCat(descriptor_->index());
+  const Descriptor* msg_descriptor = descriptor_->containing_type();
+  variables_["owning_message_class"] = ClassName(msg_descriptor);
+
+  std::string comments;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    comments = BuildCommentsString(location, true);
+  } 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"] = StrCat(-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");
+  std::string enum_name = variables_["enum_name"];
+  for (int j = 0; j < descriptor_->field_count(); j++) {
+    const FieldDescriptor* field = descriptor_->field(j);
+    std::string field_name = FieldNameCapitalized(field);
+    printer->Print(
+        "$enum_name$_$field_name$ = $field_number$,\n",
+        "enum_name", enum_name,
+        "field_name", field_name,
+        "field_number", StrCat(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_,
+      "/**\n"
+      " * Clears whatever value was set for the oneof '$name$'.\n"
+      " **/\n"
+      "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n");
+}
+
+void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "@dynamic $name$OneOfCase;\n");
+}
+
+void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n"
+      "  GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n"
+      "  GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:$raw_index$];\n"
+      "  GPBClearOneof(message, oneof);\n"
+      "}\n");
+}
+
+std::string OneofGenerator::DescriptorName(void) const {
+  return variables_.find("name")->second;
+}
+
+std::string OneofGenerator::HasIndexAsString(void) const {
+  return variables_.find("index")->second;
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
new file mode 100644
index 0000000..034f07f
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class OneofGenerator {
+ public:
+  explicit OneofGenerator(const OneofDescriptor* descriptor);
+  ~OneofGenerator();
+
+  OneofGenerator(const OneofGenerator&) = delete;
+  OneofGenerator& operator=(const OneofGenerator&) = delete;
+
+  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);
+
+  std::string DescriptorName(void) const;
+  std::string HasIndexAsString(void) const;
+
+ private:
+  const OneofDescriptor* descriptor_;
+  std::map<std::string, std::string> variables_;
+};
+
+}  // 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..1fefde5
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* PrimitiveTypeName(const FieldDescriptor* descriptor) {
+  ObjectiveCType type = GetObjectiveCType(descriptor);
+  switch (type) {
+    case OBJECTIVECTYPE_INT32:
+      return "int32_t";
+    case OBJECTIVECTYPE_UINT32:
+      return "uint32_t";
+    case OBJECTIVECTYPE_INT64:
+      return "int64_t";
+    case OBJECTIVECTYPE_UINT64:
+      return "uint64_t";
+    case OBJECTIVECTYPE_FLOAT:
+      return "float";
+    case OBJECTIVECTYPE_DOUBLE:
+      return "double";
+    case OBJECTIVECTYPE_BOOLEAN:
+      return "BOOL";
+    case OBJECTIVECTYPE_STRING:
+      return "NSString";
+    case OBJECTIVECTYPE_DATA:
+      return "NSData";
+    case OBJECTIVECTYPE_ENUM:
+      return "int32_t";
+    case OBJECTIVECTYPE_MESSAGE:
+      return NULL;  // Messages go through objectivec_message_field.cc|h.
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) {
+  ObjectiveCType type = GetObjectiveCType(descriptor);
+  switch (type) {
+    case OBJECTIVECTYPE_INT32:
+      return "Int32";
+    case OBJECTIVECTYPE_UINT32:
+      return "UInt32";
+    case OBJECTIVECTYPE_INT64:
+      return "Int64";
+    case OBJECTIVECTYPE_UINT64:
+      return "UInt64";
+    case OBJECTIVECTYPE_FLOAT:
+      return "Float";
+    case OBJECTIVECTYPE_DOUBLE:
+      return "Double";
+    case OBJECTIVECTYPE_BOOLEAN:
+      return "Bool";
+    case OBJECTIVECTYPE_STRING:
+      return "";  // Want NSArray
+    case OBJECTIVECTYPE_DATA:
+      return "";  // Want NSArray
+    case OBJECTIVECTYPE_ENUM:
+      return "Enum";
+    case OBJECTIVECTYPE_MESSAGE:
+      // Want NSArray (but goes through objectivec_message_field.cc|h).
+      return "";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           std::map<std::string, std::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() {}
+
+void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration(
+    io::Printer* printer) const {
+  if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) {
+    // Nothing, BOOLs are stored in the has bits.
+  } else {
+    SingleFieldGenerator::GenerateFieldStorageDeclaration(printer);
+  }
+}
+
+int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const {
+  if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) {
+    // Reserve a bit for the storage of the boolean.
+    return 1;
+  }
+  return 0;
+}
+
+void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int has_base) {
+  if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) {
+    // Set into the offset the has bit to use for the actual value.
+    variables_["storage_offset_value"] = StrCat(has_base);
+    variables_["storage_offset_comment"] =
+        "  // Stored in _has_storage_ to save space.";
+  }
+}
+
+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_);
+
+  std::string base_name = PrimitiveArrayTypeName(descriptor);
+  if (base_name.length()) {
+    variables_["array_storage_type"] = "GPB" + base_name + "Array";
+  } else {
+    variables_["array_storage_type"] = "NSMutableArray";
+    variables_["array_property_type"] =
+        "NSMutableArray<" + variables_["storage_type"] + "*>";
+  }
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
new file mode 100644
index 0000000..06a1528
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
+
+#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();
+
+  PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete;
+  PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete;
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override;
+
+  virtual int ExtraRuntimeHasBitsNeeded(void) const override;
+  virtual void SetExtraRuntimeHasBitsBase(int index_base) override;
+};
+
+class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+  explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~PrimitiveObjFieldGenerator();
+
+  PrimitiveObjFieldGenerator(const PrimitiveObjFieldGenerator&) = delete;
+  PrimitiveObjFieldGenerator& operator=(const PrimitiveObjFieldGenerator&) =
+      delete;
+};
+
+class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+
+ protected:
+  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  virtual ~RepeatedPrimitiveFieldGenerator();
+
+  RepeatedPrimitiveFieldGenerator(const RepeatedPrimitiveFieldGenerator&) =
+      delete;
+  RepeatedPrimitiveFieldGenerator& operator=(
+      const RepeatedPrimitiveFieldGenerator&) = delete;
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/package_info.h b/src/google/protobuf/compiler/package_info.h
new file mode 100644
index 0000000..105ef60
--- /dev/null
+++ b/src/google/protobuf/compiler/package_info.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file exists solely to document the google::protobuf::compiler namespace.
+// It is not compiled into anything, but it may be read by an automated
+// documentation generator.
+
+namespace google {
+namespace protobuf {
+
+// Implementation of the Protocol Buffer compiler.
+//
+// This package contains code for parsing .proto files and generating code
+// based on them.  There are two reasons you might be interested in this
+// package:
+// - You want to parse .proto files at runtime.  In this case, you should
+//   look at importer.h.  Since this functionality is widely useful, it is
+//   included in the libprotobuf base library; you do not have to link against
+//   libprotoc.
+// - You want to write a custom protocol compiler which generates different
+//   kinds of code, e.g. code in a different language which is not supported
+//   by the official compiler.  For this purpose, command_line_interface.h
+//   provides you with a complete compiler front-end, so all you need to do
+//   is write a custom implementation of CodeGenerator and a trivial main()
+//   function.  You can even make your compiler support the official languages
+//   in addition to your own.  Since this functionality is only useful to those
+//   writing custom compilers, it is in a separate library called "libprotoc"
+//   which you will have to link against.
+namespace compiler {}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
new file mode 100644
index 0000000..5bd37d1
--- /dev/null
+++ b/src/google/protobuf/compiler/parser.cc
@@ -0,0 +1,2446 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Recursive descent FTW.
+
+#include <google/protobuf/compiler/parser.h>
+
+#include <float.h>
+
+#include <cstdint>
+#include <limits>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+using internal::WireFormat;
+
+namespace {
+
+typedef std::unordered_map<std::string, FieldDescriptorProto::Type> TypeNameMap;
+
+const TypeNameMap& GetTypeNameTable() {
+  static auto* table = new auto([]() {
+    TypeNameMap result;
+
+    result["double"] = FieldDescriptorProto::TYPE_DOUBLE;
+    result["float"] = FieldDescriptorProto::TYPE_FLOAT;
+    result["uint64"] = FieldDescriptorProto::TYPE_UINT64;
+    result["fixed64"] = FieldDescriptorProto::TYPE_FIXED64;
+    result["fixed32"] = FieldDescriptorProto::TYPE_FIXED32;
+    result["bool"] = FieldDescriptorProto::TYPE_BOOL;
+    result["string"] = FieldDescriptorProto::TYPE_STRING;
+    result["group"] = FieldDescriptorProto::TYPE_GROUP;
+
+    result["bytes"] = FieldDescriptorProto::TYPE_BYTES;
+    result["uint32"] = FieldDescriptorProto::TYPE_UINT32;
+    result["sfixed32"] = FieldDescriptorProto::TYPE_SFIXED32;
+    result["sfixed64"] = FieldDescriptorProto::TYPE_SFIXED64;
+    result["int32"] = FieldDescriptorProto::TYPE_INT32;
+    result["int64"] = FieldDescriptorProto::TYPE_INT64;
+    result["sint32"] = FieldDescriptorProto::TYPE_SINT32;
+    result["sint64"] = FieldDescriptorProto::TYPE_SINT64;
+
+    return result;
+  }());
+  return *table;
+}
+
+// Camel-case the field name and append "Entry" for generated map entry name.
+// e.g. map<KeyType, ValueType> foo_map => FooMapEntry
+std::string MapEntryName(const std::string& field_name) {
+  std::string result;
+  static const char kSuffix[] = "Entry";
+  result.reserve(field_name.size() + sizeof(kSuffix));
+  bool cap_next = true;
+  for (const char field_name_char : field_name) {
+    if (field_name_char == '_') {
+      cap_next = true;
+    } else if (cap_next) {
+      // Note: Do not use ctype.h due to locales.
+      if ('a' <= field_name_char && field_name_char <= 'z') {
+        result.push_back(field_name_char - 'a' + 'A');
+      } else {
+        result.push_back(field_name_char);
+      }
+      cap_next = false;
+    } else {
+      result.push_back(field_name_char);
+    }
+  }
+  result.append(kSuffix);
+  return result;
+}
+
+bool IsUppercase(char c) { return c >= 'A' && c <= 'Z'; }
+
+bool IsLowercase(char c) { return c >= 'a' && c <= 'z'; }
+
+bool IsNumber(char c) { return c >= '0' && c <= '9'; }
+
+bool IsUpperCamelCase(const std::string& name) {
+  if (name.empty()) {
+    return true;
+  }
+  // Name must start with an upper case character.
+  if (!IsUppercase(name[0])) {
+    return false;
+  }
+  // Must not contains underscore.
+  for (const char c : name) {
+    if (c == '_') {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IsUpperUnderscore(const std::string& name) {
+  for (const char c : name) {
+    if (!IsUppercase(c) && c != '_' && !IsNumber(c)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IsLowerUnderscore(const std::string& name) {
+  for (const char c : name) {
+    if (!IsLowercase(c) && c != '_' && !IsNumber(c)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IsNumberFollowUnderscore(const std::string& name) {
+  for (int i = 1; i < name.length(); i++) {
+    const char c = name[i];
+    if (IsNumber(c) && name[i - 1] == '_') {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // anonymous namespace
+
+// Makes code slightly more readable.  The meaning of "DO(foo)" is
+// "Execute foo and fail if it fails.", where failure is indicated by
+// returning false.
+#define DO(STATEMENT) \
+  if (STATEMENT) {    \
+  } else              \
+    return false
+
+// ===================================================================
+
+Parser::Parser()
+    : input_(nullptr),
+      error_collector_(nullptr),
+      source_location_table_(nullptr),
+      had_errors_(false),
+      require_syntax_identifier_(false),
+      stop_after_syntax_identifier_(false) {
+}
+
+Parser::~Parser() {}
+
+// ===================================================================
+
+inline bool Parser::LookingAt(const char* text) {
+  return input_->current().text == text;
+}
+
+inline bool Parser::LookingAtType(io::Tokenizer::TokenType token_type) {
+  return input_->current().type == token_type;
+}
+
+inline bool Parser::AtEnd() { return LookingAtType(io::Tokenizer::TYPE_END); }
+
+bool Parser::TryConsume(const char* text) {
+  if (LookingAt(text)) {
+    input_->Next();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool Parser::Consume(const char* text, const char* error) {
+  if (TryConsume(text)) {
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::Consume(const char* text) {
+  std::string error = "Expected \"" + std::string(text) + "\".";
+  return Consume(text, error.c_str());
+}
+
+bool Parser::ConsumeIdentifier(std::string* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+    *output = input_->current().text;
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeInteger(int* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+    uint64_t value = 0;
+    if (!io::Tokenizer::ParseInteger(input_->current().text,
+                                     std::numeric_limits<int32_t>::max(),
+                                     &value)) {
+      AddError("Integer out of range.");
+      // We still return true because we did, in fact, parse an integer.
+    }
+    *output = value;
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeSignedInteger(int* output, const char* error) {
+  bool is_negative = false;
+  uint64_t max_value = std::numeric_limits<int32_t>::max();
+  if (TryConsume("-")) {
+    is_negative = true;
+    max_value += 1;
+  }
+  uint64_t value = 0;
+  DO(ConsumeInteger64(max_value, &value, error));
+  if (is_negative) value *= -1;
+  *output = value;
+  return true;
+}
+
+bool Parser::ConsumeInteger64(uint64_t max_value, uint64_t* output,
+                              const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+    if (!io::Tokenizer::ParseInteger(input_->current().text, max_value,
+                                     output)) {
+      AddError("Integer out of range.");
+      // We still return true because we did, in fact, parse an integer.
+      *output = 0;
+    }
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeNumber(double* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
+    *output = io::Tokenizer::ParseFloat(input_->current().text);
+    input_->Next();
+    return true;
+  } else if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+    // Also accept integers.
+    uint64_t value = 0;
+    if (!io::Tokenizer::ParseInteger(input_->current().text,
+                                     std::numeric_limits<uint64_t>::max(),
+                                     &value)) {
+      AddError("Integer out of range.");
+      // We still return true because we did, in fact, parse a number.
+    }
+    *output = value;
+    input_->Next();
+    return true;
+  } else if (LookingAt("inf")) {
+    *output = std::numeric_limits<double>::infinity();
+    input_->Next();
+    return true;
+  } else if (LookingAt("nan")) {
+    *output = std::numeric_limits<double>::quiet_NaN();
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeString(std::string* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    io::Tokenizer::ParseString(input_->current().text, output);
+    input_->Next();
+    // Allow C++ like concatenation of adjacent string tokens.
+    while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      io::Tokenizer::ParseStringAppend(input_->current().text, output);
+      input_->Next();
+    }
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::TryConsumeEndOfDeclaration(const char* text,
+                                        const LocationRecorder* location) {
+  if (LookingAt(text)) {
+    std::string leading, trailing;
+    std::vector<std::string> detached;
+    input_->NextWithComments(&trailing, &detached, &leading);
+
+    // Save the leading comments for next time, and recall the leading comments
+    // from last time.
+    leading.swap(upcoming_doc_comments_);
+
+    if (location != nullptr) {
+      upcoming_detached_comments_.swap(detached);
+      location->AttachComments(&leading, &trailing, &detached);
+    } else if (strcmp(text, "}") == 0) {
+      // If the current location is null and we are finishing the current scope,
+      // drop pending upcoming detached comments.
+      upcoming_detached_comments_.swap(detached);
+    } else {
+      // Otherwise, append the new detached comments to the existing upcoming
+      // detached comments.
+      upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
+                                         detached.begin(), detached.end());
+    }
+
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool Parser::ConsumeEndOfDeclaration(const char* text,
+                                     const LocationRecorder* location) {
+  if (TryConsumeEndOfDeclaration(text, location)) {
+    return true;
+  } else {
+    AddError("Expected \"" + std::string(text) + "\".");
+    return false;
+  }
+}
+
+// -------------------------------------------------------------------
+
+void Parser::AddError(int line, int column, const std::string& error) {
+  if (error_collector_ != nullptr) {
+    error_collector_->AddError(line, column, error);
+  }
+  had_errors_ = true;
+}
+
+void Parser::AddError(const std::string& error) {
+  AddError(input_->current().line, input_->current().column, error);
+}
+
+void Parser::AddWarning(const std::string& warning) {
+  if (error_collector_ != nullptr) {
+    error_collector_->AddWarning(input_->current().line,
+                                 input_->current().column, warning);
+  }
+}
+
+// -------------------------------------------------------------------
+
+Parser::LocationRecorder::LocationRecorder(Parser* parser)
+    : parser_(parser),
+      source_code_info_(parser->source_code_info_),
+      location_(parser_->source_code_info_->add_location()) {
+  location_->add_span(parser_->input_->current().line);
+  location_->add_span(parser_->input_->current().column);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) {
+  Init(parent, parent.source_code_info_);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1,
+                                           SourceCodeInfo* source_code_info) {
+  Init(parent, source_code_info);
+  AddPath(path1);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1) {
+  Init(parent, parent.source_code_info_);
+  AddPath(path1);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1, int path2) {
+  Init(parent, parent.source_code_info_);
+  AddPath(path1);
+  AddPath(path2);
+}
+
+void Parser::LocationRecorder::Init(const LocationRecorder& parent,
+                                    SourceCodeInfo* source_code_info) {
+  parser_ = parent.parser_;
+  source_code_info_ = source_code_info;
+
+  location_ = source_code_info_->add_location();
+  location_->mutable_path()->CopyFrom(parent.location_->path());
+
+  location_->add_span(parser_->input_->current().line);
+  location_->add_span(parser_->input_->current().column);
+}
+
+Parser::LocationRecorder::~LocationRecorder() {
+  if (location_->span_size() <= 2) {
+    EndAt(parser_->input_->previous());
+  }
+}
+
+void Parser::LocationRecorder::AddPath(int path_component) {
+  location_->add_path(path_component);
+}
+
+void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) {
+  location_->set_span(0, token.line);
+  location_->set_span(1, token.column);
+}
+
+void Parser::LocationRecorder::StartAt(const LocationRecorder& other) {
+  location_->set_span(0, other.location_->span(0));
+  location_->set_span(1, other.location_->span(1));
+}
+
+void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) {
+  if (token.line != location_->span(0)) {
+    location_->add_span(token.line);
+  }
+  location_->add_span(token.end_column);
+}
+
+void Parser::LocationRecorder::RecordLegacyLocation(
+    const Message* descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location) {
+  if (parser_->source_location_table_ != nullptr) {
+    parser_->source_location_table_->Add(
+        descriptor, location, location_->span(0), location_->span(1));
+  }
+}
+
+void Parser::LocationRecorder::RecordLegacyImportLocation(
+    const Message* descriptor, const std::string& name) {
+  if (parser_->source_location_table_ != nullptr) {
+    parser_->source_location_table_->AddImport(
+        descriptor, name, location_->span(0), location_->span(1));
+  }
+}
+
+int Parser::LocationRecorder::CurrentPathSize() const {
+  return location_->path_size();
+}
+
+void Parser::LocationRecorder::AttachComments(
+    std::string* leading, std::string* trailing,
+    std::vector<std::string>* detached_comments) const {
+  GOOGLE_CHECK(!location_->has_leading_comments());
+  GOOGLE_CHECK(!location_->has_trailing_comments());
+
+  if (!leading->empty()) {
+    location_->mutable_leading_comments()->swap(*leading);
+  }
+  if (!trailing->empty()) {
+    location_->mutable_trailing_comments()->swap(*trailing);
+  }
+  for (int i = 0; i < detached_comments->size(); ++i) {
+    location_->add_leading_detached_comments()->swap((*detached_comments)[i]);
+  }
+  detached_comments->clear();
+}
+
+// -------------------------------------------------------------------
+
+void Parser::SkipStatement() {
+  while (true) {
+    if (AtEnd()) {
+      return;
+    } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
+      if (TryConsumeEndOfDeclaration(";", nullptr)) {
+        return;
+      } else if (TryConsume("{")) {
+        SkipRestOfBlock();
+        return;
+      } else if (LookingAt("}")) {
+        return;
+      }
+    }
+    input_->Next();
+  }
+}
+
+void Parser::SkipRestOfBlock() {
+  while (true) {
+    if (AtEnd()) {
+      return;
+    } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
+      if (TryConsumeEndOfDeclaration("}", nullptr)) {
+        return;
+      } else if (TryConsume("{")) {
+        SkipRestOfBlock();
+      }
+    }
+    input_->Next();
+  }
+}
+
+// ===================================================================
+
+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) {
+    std::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;
+  }
+
+  std::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) {
+    std::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;
+  }
+
+  // Enforce that enum constants must be UPPER_CASE except in case of
+  // enum_alias.
+  if (!allow_alias) {
+    for (const auto& enum_value : proto->value()) {
+      if (!IsUpperUnderscore(enum_value.name())) {
+        AddWarning(
+            "Enum constant should be in UPPER_CASE. Found: " +
+            enum_value.name() +
+            ". See https://developers.google.com/protocol-buffers/docs/style");
+      }
+    }
+  }
+
+  return true;
+}
+
+bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
+  input_ = input;
+  had_errors_ = false;
+  syntax_identifier_.clear();
+
+  // Note that |file| could be NULL at this point if
+  // stop_after_syntax_identifier_ is true.  So, we conservatively allocate
+  // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto
+  // later on.
+  SourceCodeInfo source_code_info;
+  source_code_info_ = &source_code_info;
+
+  if (LookingAtType(io::Tokenizer::TYPE_START)) {
+    // Advance to first token.
+    input_->NextWithComments(nullptr, &upcoming_detached_comments_,
+                             &upcoming_doc_comments_);
+  }
+
+  {
+    LocationRecorder root_location(this);
+    root_location.RecordLegacyLocation(file,
+                                       DescriptorPool::ErrorCollector::OTHER);
+
+    if (require_syntax_identifier_ || LookingAt("syntax")) {
+      if (!ParseSyntaxIdentifier(root_location)) {
+        // Don't attempt to parse the file if we didn't recognize the syntax
+        // identifier.
+        return false;
+      }
+      // Store the syntax into the file.
+      if (file != nullptr) file->set_syntax(syntax_identifier_);
+    } else if (!stop_after_syntax_identifier_) {
+      GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: " << file->name()
+                   << ". Please use 'syntax = \"proto2\";' "
+                   << "or 'syntax = \"proto3\";' to specify a syntax "
+                   << "version. (Defaulted to proto2 syntax.)";
+      syntax_identifier_ = "proto2";
+    }
+
+    if (stop_after_syntax_identifier_) return !had_errors_;
+
+    // Repeatedly parse statements until we reach the end of the file.
+    while (!AtEnd()) {
+      if (!ParseTopLevelStatement(file, root_location)) {
+        // This statement failed to parse.  Skip it, but keep looping to parse
+        // other statements.
+        SkipStatement();
+
+        if (LookingAt("}")) {
+          AddError("Unmatched \"}\".");
+          input_->NextWithComments(nullptr, &upcoming_detached_comments_,
+                                   &upcoming_doc_comments_);
+        }
+      }
+    }
+  }
+
+  input_ = nullptr;
+  source_code_info_ = nullptr;
+  assert(file != nullptr);
+  source_code_info.Swap(file->mutable_source_code_info());
+  return !had_errors_;
+}
+
+bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
+  LocationRecorder syntax_location(parent,
+                                   FileDescriptorProto::kSyntaxFieldNumber);
+  DO(Consume(
+      "syntax",
+      "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
+  DO(Consume("="));
+  io::Tokenizer::Token syntax_token = input_->current();
+  std::string syntax;
+  DO(ConsumeString(&syntax, "Expected syntax identifier."));
+  DO(ConsumeEndOfDeclaration(";", &syntax_location));
+
+  syntax_identifier_ = syntax;
+
+  if (syntax != "proto2" && syntax != "proto3" &&
+      !stop_after_syntax_identifier_) {
+    AddError(syntax_token.line, syntax_token.column,
+             "Unrecognized syntax identifier \"" + syntax +
+                 "\".  This parser "
+                 "only recognizes \"proto2\" and \"proto3\".");
+    return false;
+  }
+
+  return true;
+}
+
+bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
+                                    const LocationRecorder& root_location) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("message")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kMessageTypeFieldNumber,
+                              file->message_type_size());
+    return ParseMessageDefinition(file->add_message_type(), location, file);
+  } else if (LookingAt("enum")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kEnumTypeFieldNumber,
+                              file->enum_type_size());
+    return ParseEnumDefinition(file->add_enum_type(), location, file);
+  } else if (LookingAt("service")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kServiceFieldNumber,
+                              file->service_size());
+    return ParseServiceDefinition(file->add_service(), location, file);
+  } else if (LookingAt("extend")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kExtensionFieldNumber);
+    return ParseExtend(
+        file->mutable_extension(), file->mutable_message_type(), root_location,
+        FileDescriptorProto::kMessageTypeFieldNumber, location, file);
+  } else if (LookingAt("import")) {
+    return ParseImport(file->mutable_dependency(),
+                       file->mutable_public_dependency(),
+                       file->mutable_weak_dependency(), root_location, file);
+  } else if (LookingAt("package")) {
+    return ParsePackage(file, root_location, file);
+  } else if (LookingAt("option")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(file->mutable_options(), location, file,
+                       OPTION_STATEMENT);
+  } else {
+    AddError("Expected top-level statement (e.g. \"message\").");
+    return false;
+  }
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+bool Parser::ParseMessageDefinition(
+    DescriptorProto* message, const LocationRecorder& message_location,
+    const FileDescriptorProto* containing_file) {
+  DO(Consume("message"));
+  {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(message,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
+    if (!IsUpperCamelCase(message->name())) {
+      AddWarning(
+          "Message name should be in UpperCamelCase. Found: " +
+          message->name() +
+          ". See https://developers.google.com/protocol-buffers/docs/style");
+    }
+  }
+  DO(ParseMessageBlock(message, message_location, containing_file));
+
+  if (syntax_identifier_ == "proto3") {
+    // Add synthetic one-field oneofs for optional fields, except messages which
+    // already have presence in proto3.
+    //
+    // We have to make sure the oneof names don't conflict with any other
+    // field or oneof.
+    std::unordered_set<std::string> names;
+    for (const auto& field : message->field()) {
+      names.insert(field.name());
+    }
+    for (const auto& oneof : message->oneof_decl()) {
+      names.insert(oneof.name());
+    }
+
+    for (auto& field : *message->mutable_field()) {
+      if (field.proto3_optional()) {
+        std::string oneof_name = field.name();
+
+        // Prepend 'XXXXX_' until we are no longer conflicting.
+        // Avoid prepending a double-underscore because such names are
+        // reserved in C++.
+        if (oneof_name.empty() || oneof_name[0] != '_') {
+          oneof_name = '_' + oneof_name;
+        }
+        while (names.count(oneof_name) > 0) {
+          oneof_name = 'X' + oneof_name;
+        }
+
+        names.insert(oneof_name);
+        field.set_oneof_index(message->oneof_decl_size());
+        OneofDescriptorProto* oneof = message->add_oneof_decl();
+        oneof->set_name(oneof_name);
+      }
+    }
+  }
+
+  return true;
+}
+
+namespace {
+
+const int kMaxRangeSentinel = -1;
+
+bool IsMessageSetWireFormatMessage(const DescriptorProto& message) {
+  const MessageOptions& options = message.options();
+  for (int i = 0; i < options.uninterpreted_option_size(); ++i) {
+    const UninterpretedOption& uninterpreted = options.uninterpreted_option(i);
+    if (uninterpreted.name_size() == 1 &&
+        uninterpreted.name(0).name_part() == "message_set_wire_format" &&
+        uninterpreted.identifier_value() == "true") {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Modifies any extension ranges that specified 'max' as the end of the
+// extension range, and sets them to the type-specific maximum. The actual max
+// tag number can only be determined after all options have been parsed.
+void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) {
+  const bool is_message_set = IsMessageSetWireFormatMessage(*message);
+  const int max_extension_number = is_message_set
+                                       ? std::numeric_limits<int32_t>::max()
+                                       : FieldDescriptor::kMaxNumber + 1;
+  for (int i = 0; i < message->extension_range_size(); ++i) {
+    if (message->extension_range(i).end() == kMaxRangeSentinel) {
+      message->mutable_extension_range(i)->set_end(max_extension_number);
+    }
+  }
+}
+
+// Modifies any reserved ranges that specified 'max' as the end of the
+// reserved range, and sets them to the type-specific maximum. The actual max
+// tag number can only be determined after all options have been parsed.
+void AdjustReservedRangesWithMaxEndNumber(DescriptorProto* message) {
+  const bool is_message_set = IsMessageSetWireFormatMessage(*message);
+  const int max_field_number = is_message_set
+                                   ? std::numeric_limits<int32_t>::max()
+                                   : FieldDescriptor::kMaxNumber + 1;
+  for (int i = 0; i < message->reserved_range_size(); ++i) {
+    if (message->reserved_range(i).end() == kMaxRangeSentinel) {
+      message->mutable_reserved_range(i)->set_end(max_field_number);
+    }
+  }
+}
+
+}  // namespace
+
+bool Parser::ParseMessageBlock(DescriptorProto* message,
+                               const LocationRecorder& message_location,
+                               const FileDescriptorProto* containing_file) {
+  DO(ConsumeEndOfDeclaration("{", &message_location));
+
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in message definition (missing '}').");
+      return false;
+    }
+
+    if (!ParseMessageStatement(message, message_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  }
+
+  if (message->extension_range_size() > 0) {
+    AdjustExtensionRangesWithMaxEndNumber(message);
+  }
+  if (message->reserved_range_size() > 0) {
+    AdjustReservedRangesWithMaxEndNumber(message);
+  }
+  return true;
+}
+
+bool Parser::ParseMessageStatement(DescriptorProto* message,
+                                   const LocationRecorder& message_location,
+                                   const FileDescriptorProto* containing_file) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("message")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kNestedTypeFieldNumber,
+                              message->nested_type_size());
+    return ParseMessageDefinition(message->add_nested_type(), location,
+                                  containing_file);
+  } else if (LookingAt("enum")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kEnumTypeFieldNumber,
+                              message->enum_type_size());
+    return ParseEnumDefinition(message->add_enum_type(), location,
+                               containing_file);
+  } else if (LookingAt("extensions")) {
+    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);
+    return ParseExtend(message->mutable_extension(),
+                       message->mutable_nested_type(), message_location,
+                       DescriptorProto::kNestedTypeFieldNumber, location,
+                       containing_file);
+  } else if (LookingAt("option")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kOptionsFieldNumber);
+    return ParseOption(message->mutable_options(), location, containing_file,
+                       OPTION_STATEMENT);
+  } else if (LookingAt("oneof")) {
+    int oneof_index = message->oneof_decl_size();
+    LocationRecorder oneof_location(
+        message_location, DescriptorProto::kOneofDeclFieldNumber, oneof_index);
+
+    return ParseOneof(message->add_oneof_decl(), message, oneof_index,
+                      oneof_location, message_location, containing_file);
+  } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kFieldFieldNumber,
+                              message->field_size());
+    return ParseMessageField(
+        message->add_field(), message->mutable_nested_type(), message_location,
+        DescriptorProto::kNestedTypeFieldNumber, location, containing_file);
+  }
+}
+
+bool Parser::ParseMessageField(FieldDescriptorProto* field,
+                               RepeatedPtrField<DescriptorProto>* messages,
+                               const LocationRecorder& parent_location,
+                               int location_field_number_for_nested_type,
+                               const LocationRecorder& field_location,
+                               const FileDescriptorProto* containing_file) {
+  {
+    FieldDescriptorProto::Label label;
+    if (ParseLabel(&label, field_location)) {
+      field->set_label(label);
+      if (label == FieldDescriptorProto::LABEL_OPTIONAL &&
+          syntax_identifier_ == "proto3") {
+        field->set_proto3_optional(true);
+      }
+    }
+  }
+
+  return ParseMessageFieldNoLabel(field, messages, parent_location,
+                                  location_field_number_for_nested_type,
+                                  field_location, containing_file);
+}
+
+bool Parser::ParseMessageFieldNoLabel(
+    FieldDescriptorProto* field, RepeatedPtrField<DescriptorProto>* messages,
+    const LocationRecorder& parent_location,
+    int location_field_number_for_nested_type,
+    const LocationRecorder& field_location,
+    const FileDescriptorProto* containing_file) {
+  MapField map_field;
+  // Parse type.
+  {
+    LocationRecorder location(field_location);  // add path later
+    location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE);
+
+    bool type_parsed = false;
+    FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
+    std::string type_name;
+
+    // Special case map field. We only treat the field as a map field if the
+    // field type name starts with the word "map" with a following "<".
+    if (TryConsume("map")) {
+      if (LookingAt("<")) {
+        map_field.is_map_field = true;
+        DO(ParseMapType(&map_field, field, location));
+      } else {
+        // False positive
+        type_parsed = true;
+        type_name = "map";
+      }
+    }
+    if (!map_field.is_map_field) {
+      // Handle the case where no explicit label is given for a non-map field.
+      if (!field->has_label() && DefaultToOptionalFields()) {
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+      }
+      if (!field->has_label()) {
+        AddError("Expected \"required\", \"optional\", or \"repeated\".");
+        // We can actually reasonably recover here by just assuming the user
+        // forgot the label altogether.
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+      }
+
+      // Handle the case where the actual type is a message or enum named
+      // "map", which we already consumed in the code above.
+      if (!type_parsed) {
+        DO(ParseType(&type, &type_name));
+      }
+      if (type_name.empty()) {
+        location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
+        field->set_type(type);
+      } else {
+        location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
+        field->set_type_name(type_name);
+      }
+    }
+  }
+
+  // Parse name and '='.
+  io::Tokenizer::Token name_token = input_->current();
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
+
+    if (!IsLowerUnderscore(field->name())) {
+      AddWarning(
+          "Field name should be lowercase. Found: " + field->name() +
+          ". See: https://developers.google.com/protocol-buffers/docs/style");
+    }
+    if (IsNumberFollowUnderscore(field->name())) {
+      AddWarning(
+          "Number should not come right after an underscore. Found: " +
+          field->name() +
+          ". See: https://developers.google.com/protocol-buffers/docs/style");
+    }
+  }
+  DO(Consume("=", "Missing field number."));
+
+  // Parse field number.
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kNumberFieldNumber);
+    location.RecordLegacyLocation(field,
+                                  DescriptorPool::ErrorCollector::NUMBER);
+    int number;
+    DO(ConsumeInteger(&number, "Expected field number."));
+    field->set_number(number);
+  }
+
+  // Parse options.
+  DO(ParseFieldOptions(field, field_location, containing_file));
+
+  // Deal with groups.
+  if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) {
+    // Awkward:  Since a group declares both a message type and a field, we
+    //   have to create overlapping locations.
+    LocationRecorder group_location(parent_location);
+    group_location.StartAt(field_location);
+    group_location.AddPath(location_field_number_for_nested_type);
+    group_location.AddPath(messages->size());
+
+    DescriptorProto* group = messages->Add();
+    group->set_name(field->name());
+
+    // Record name location to match the field name's location.
+    {
+      LocationRecorder location(group_location,
+                                DescriptorProto::kNameFieldNumber);
+      location.StartAt(name_token);
+      location.EndAt(name_token);
+      location.RecordLegacyLocation(group,
+                                    DescriptorPool::ErrorCollector::NAME);
+    }
+
+    // The field's type_name also comes from the name.  Confusing!
+    {
+      LocationRecorder location(field_location,
+                                FieldDescriptorProto::kTypeNameFieldNumber);
+      location.StartAt(name_token);
+      location.EndAt(name_token);
+    }
+
+    // As a hack for backwards-compatibility, we force the group name to start
+    // with a capital letter and lower-case the field name.  New code should
+    // not use groups; it should use nested messages.
+    if (group->name()[0] < 'A' || 'Z' < group->name()[0]) {
+      AddError(name_token.line, name_token.column,
+               "Group names must start with a capital letter.");
+    }
+    LowerString(field->mutable_name());
+
+    field->set_type_name(group->name());
+    if (LookingAt("{")) {
+      DO(ParseMessageBlock(group, group_location, containing_file));
+    } else {
+      AddError("Missing group body.");
+      return false;
+    }
+  } else {
+    DO(ConsumeEndOfDeclaration(";", &field_location));
+  }
+
+  // Create a map entry type if this is a map field.
+  if (map_field.is_map_field) {
+    GenerateMapEntry(map_field, field, messages);
+  }
+
+  return true;
+}
+
+bool Parser::ParseMapType(MapField* map_field, FieldDescriptorProto* field,
+                          LocationRecorder& type_name_location) {
+  if (field->has_oneof_index()) {
+    AddError("Map fields are not allowed in oneofs.");
+    return false;
+  }
+  if (field->has_label()) {
+    AddError(
+        "Field labels (required/optional/repeated) are not allowed on "
+        "map fields.");
+    return false;
+  }
+  if (field->has_extendee()) {
+    AddError("Map fields are not allowed to be extensions.");
+    return false;
+  }
+  field->set_label(FieldDescriptorProto::LABEL_REPEATED);
+  DO(Consume("<"));
+  DO(ParseType(&map_field->key_type, &map_field->key_type_name));
+  DO(Consume(","));
+  DO(ParseType(&map_field->value_type, &map_field->value_type_name));
+  DO(Consume(">"));
+  // Defer setting of the type name of the map field until the
+  // field name is parsed. Add the source location though.
+  type_name_location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
+  return true;
+}
+
+void Parser::GenerateMapEntry(const MapField& map_field,
+                              FieldDescriptorProto* field,
+                              RepeatedPtrField<DescriptorProto>* messages) {
+  DescriptorProto* entry = messages->Add();
+  std::string entry_name = MapEntryName(field->name());
+  field->set_type_name(entry_name);
+  entry->set_name(entry_name);
+  entry->mutable_options()->set_map_entry(true);
+  FieldDescriptorProto* key_field = entry->add_field();
+  key_field->set_name("key");
+  key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  key_field->set_number(1);
+  if (map_field.key_type_name.empty()) {
+    key_field->set_type(map_field.key_type);
+  } else {
+    key_field->set_type_name(map_field.key_type_name);
+  }
+  FieldDescriptorProto* value_field = entry->add_field();
+  value_field->set_name("value");
+  value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  value_field->set_number(2);
+  if (map_field.value_type_name.empty()) {
+    value_field->set_type(map_field.value_type);
+  } else {
+    value_field->set_type_name(map_field.value_type_name);
+  }
+  // Propagate the "enforce_utf8" option to key and value fields if they
+  // are strings. This helps simplify the implementation of code generators
+  // and also reflection-based parsing code.
+  //
+  // The following definition:
+  //   message Foo {
+  //     map<string, string> value = 1 [enforce_utf8 = false];
+  //   }
+  // will be interpreted as:
+  //   message Foo {
+  //     message ValueEntry {
+  //       option map_entry = true;
+  //       string key = 1 [enforce_utf8 = false];
+  //       string value = 2 [enforce_utf8 = false];
+  //     }
+  //     repeated ValueEntry value = 1 [enforce_utf8 = false];
+  //  }
+  //
+  // TODO(xiaofeng): Remove this when the "enforce_utf8" option is removed
+  // from protocol compiler.
+  for (int i = 0; i < field->options().uninterpreted_option_size(); ++i) {
+    const UninterpretedOption& option =
+        field->options().uninterpreted_option(i);
+    if (option.name_size() == 1 &&
+        option.name(0).name_part() == "enforce_utf8" &&
+        !option.name(0).is_extension()) {
+      if (key_field->type() == FieldDescriptorProto::TYPE_STRING) {
+        key_field->mutable_options()->add_uninterpreted_option()->CopyFrom(
+            option);
+      }
+      if (value_field->type() == FieldDescriptorProto::TYPE_STRING) {
+        value_field->mutable_options()->add_uninterpreted_option()->CopyFrom(
+            option);
+      }
+    }
+  }
+}
+
+bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
+                               const LocationRecorder& field_location,
+                               const FileDescriptorProto* containing_file) {
+  if (!LookingAt("[")) return true;
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kOptionsFieldNumber);
+
+  DO(Consume("["));
+
+  // Parse field options.
+  do {
+    if (LookingAt("default")) {
+      // 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));
+    }
+  } while (TryConsume(","));
+
+  DO(Consume("]"));
+  return true;
+}
+
+bool Parser::ParseDefaultAssignment(
+    FieldDescriptorProto* field, const LocationRecorder& field_location,
+    const FileDescriptorProto* containing_file) {
+  if (field->has_default_value()) {
+    AddError("Already set option \"default\".");
+    field->clear_default_value();
+  }
+
+  DO(Consume("default"));
+  DO(Consume("="));
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kDefaultValueFieldNumber);
+  location.RecordLegacyLocation(field,
+                                DescriptorPool::ErrorCollector::DEFAULT_VALUE);
+  std::string* default_value = field->mutable_default_value();
+
+  if (!field->has_type()) {
+    // The field has a type name, but we don't know if it is a message or an
+    // enum yet. (If it were a primitive type, |field| would have a type set
+    // already.) In this case, simply take the current string as the default
+    // value; we will catch the error later if it is not a valid enum value.
+    // (N.B. that we do not check whether the current token is an identifier:
+    // doing so throws strange errors when the user mistypes a primitive
+    // typename and we assume it's an enum. E.g.: "optional int foo = 1 [default
+    // = 42]". In such a case the fundamental error is really that "int" is not
+    // a type, not that "42" is not an identifier. See b/12533582.)
+    *default_value = input_->current().text;
+    input_->Next();
+    return true;
+  }
+
+  switch (field->type()) {
+    case FieldDescriptorProto::TYPE_INT32:
+    case FieldDescriptorProto::TYPE_INT64:
+    case FieldDescriptorProto::TYPE_SINT32:
+    case FieldDescriptorProto::TYPE_SINT64:
+    case FieldDescriptorProto::TYPE_SFIXED32:
+    case FieldDescriptorProto::TYPE_SFIXED64: {
+      uint64_t max_value = std::numeric_limits<int64_t>::max();
+      if (field->type() == FieldDescriptorProto::TYPE_INT32 ||
+          field->type() == FieldDescriptorProto::TYPE_SINT32 ||
+          field->type() == FieldDescriptorProto::TYPE_SFIXED32) {
+        max_value = std::numeric_limits<int32_t>::max();
+      }
+
+      // These types can be negative.
+      if (TryConsume("-")) {
+        default_value->append("-");
+        // Two's complement always has one more negative value than positive.
+        ++max_value;
+      }
+      // Parse the integer to verify that it is not out-of-range.
+      uint64_t value;
+      DO(ConsumeInteger64(max_value, &value,
+                          "Expected integer for field default value."));
+      // And stringify it again.
+      default_value->append(StrCat(value));
+      break;
+    }
+
+    case FieldDescriptorProto::TYPE_UINT32:
+    case FieldDescriptorProto::TYPE_UINT64:
+    case FieldDescriptorProto::TYPE_FIXED32:
+    case FieldDescriptorProto::TYPE_FIXED64: {
+      uint64_t max_value = std::numeric_limits<uint64_t>::max();
+      if (field->type() == FieldDescriptorProto::TYPE_UINT32 ||
+          field->type() == FieldDescriptorProto::TYPE_FIXED32) {
+        max_value = std::numeric_limits<uint32_t>::max();
+      }
+
+      // Numeric, not negative.
+      if (TryConsume("-")) {
+        AddError("Unsigned field can't have negative default value.");
+      }
+      // Parse the integer to verify that it is not out-of-range.
+      uint64_t value;
+      DO(ConsumeInteger64(max_value, &value,
+                          "Expected integer for field default value."));
+      // And stringify it again.
+      default_value->append(StrCat(value));
+      break;
+    }
+
+    case FieldDescriptorProto::TYPE_FLOAT:
+    case FieldDescriptorProto::TYPE_DOUBLE:
+      // These types can be negative.
+      if (TryConsume("-")) {
+        default_value->append("-");
+      }
+      // Parse the integer because we have to convert hex integers to decimal
+      // floats.
+      double value;
+      DO(ConsumeNumber(&value, "Expected number."));
+      // And stringify it again.
+      default_value->append(SimpleDtoa(value));
+      break;
+
+    case FieldDescriptorProto::TYPE_BOOL:
+      if (TryConsume("true")) {
+        default_value->assign("true");
+      } else if (TryConsume("false")) {
+        default_value->assign("false");
+      } else {
+        AddError("Expected \"true\" or \"false\".");
+        return false;
+      }
+      break;
+
+    case FieldDescriptorProto::TYPE_STRING:
+      // Note: When file option java_string_check_utf8 is true, if a
+      // non-string representation (eg byte[]) is later supported, it must
+      // be checked for UTF-8-ness.
+      DO(ConsumeString(default_value,
+                       "Expected string for field default "
+                       "value."));
+      break;
+
+    case FieldDescriptorProto::TYPE_BYTES:
+      DO(ConsumeString(default_value, "Expected string."));
+      *default_value = CEscape(*default_value);
+      break;
+
+    case FieldDescriptorProto::TYPE_ENUM:
+      DO(ConsumeIdentifier(default_value,
+                           "Expected enum identifier for field "
+                           "default value."));
+      break;
+
+    case FieldDescriptorProto::TYPE_MESSAGE:
+    case FieldDescriptorProto::TYPE_GROUP:
+      AddError("Messages can't have default values.");
+      return false;
+  }
+
+  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();
+  }
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kJsonNameFieldNumber);
+  location.RecordLegacyLocation(field,
+                                DescriptorPool::ErrorCollector::OPTION_NAME);
+
+  DO(Consume("json_name"));
+  DO(Consume("="));
+
+  LocationRecorder value_location(location);
+  value_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) {
+  UninterpretedOption::NamePart* name = uninterpreted_option->add_name();
+  std::string identifier;  // We parse identifiers into this string.
+  if (LookingAt("(")) {    // This is an extension.
+    DO(Consume("("));
+
+    {
+      LocationRecorder location(
+          part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
+      // An extension name consists of dot-separated identifiers, and may begin
+      // with a dot.
+      if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+        DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+        name->mutable_name_part()->append(identifier);
+      }
+      while (LookingAt(".")) {
+        DO(Consume("."));
+        name->mutable_name_part()->append(".");
+        DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+        name->mutable_name_part()->append(identifier);
+      }
+    }
+
+    DO(Consume(")"));
+    name->set_is_extension(true);
+  } else {  // This is a regular field.
+    LocationRecorder location(
+        part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    name->mutable_name_part()->append(identifier);
+    name->set_is_extension(false);
+  }
+  return true;
+}
+
+bool Parser::ParseUninterpretedBlock(std::string* value) {
+  // Note that enclosing braces are not added to *value.
+  // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting
+  // an expression, not a block of statements.
+  DO(Consume("{"));
+  int brace_depth = 1;
+  while (!AtEnd()) {
+    if (LookingAt("{")) {
+      brace_depth++;
+    } else if (LookingAt("}")) {
+      brace_depth--;
+      if (brace_depth == 0) {
+        input_->Next();
+        return true;
+      }
+    }
+    // TODO(sanjay): Interpret line/column numbers to preserve formatting
+    if (!value->empty()) value->push_back(' ');
+    value->append(input_->current().text);
+    input_->Next();
+  }
+  AddError("Unexpected end of stream while parsing aggregate value.");
+  return false;
+}
+
+// We don't interpret the option here. Instead we store it in an
+// UninterpretedOption, to be interpreted later.
+bool Parser::ParseOption(Message* options,
+                         const LocationRecorder& options_location,
+                         const FileDescriptorProto* containing_file,
+                         OptionStyle style) {
+  // Create an entry in the uninterpreted_option field.
+  const FieldDescriptor* uninterpreted_option_field =
+      options->GetDescriptor()->FindFieldByName("uninterpreted_option");
+  GOOGLE_CHECK(uninterpreted_option_field != nullptr)
+      << "No field named \"uninterpreted_option\" in the Options proto.";
+
+  const Reflection* reflection = options->GetReflection();
+
+  LocationRecorder location(
+      options_location, uninterpreted_option_field->number(),
+      reflection->FieldSize(*options, uninterpreted_option_field));
+
+  if (style == OPTION_STATEMENT) {
+    DO(Consume("option"));
+  }
+
+  UninterpretedOption* uninterpreted_option =
+      down_cast<UninterpretedOption*>(options->GetReflection()->AddMessage(
+          options, uninterpreted_option_field));
+
+  // Parse dot-separated name.
+  {
+    LocationRecorder name_location(location,
+                                   UninterpretedOption::kNameFieldNumber);
+    name_location.RecordLegacyLocation(
+        uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME);
+
+    {
+      LocationRecorder part_location(name_location,
+                                     uninterpreted_option->name_size());
+      DO(ParseOptionNamePart(uninterpreted_option, part_location,
+                             containing_file));
+    }
+
+    while (LookingAt(".")) {
+      DO(Consume("."));
+      LocationRecorder part_location(name_location,
+                                     uninterpreted_option->name_size());
+      DO(ParseOptionNamePart(uninterpreted_option, part_location,
+                             containing_file));
+    }
+  }
+
+  DO(Consume("="));
+
+  {
+    LocationRecorder value_location(location);
+    value_location.RecordLegacyLocation(
+        uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
+
+    // All values are a single token, except for negative numbers, which consist
+    // of a single '-' symbol, followed by a positive number.
+    bool is_negative = TryConsume("-");
+
+    switch (input_->current().type) {
+      case io::Tokenizer::TYPE_START:
+        GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
+        return false;
+
+      case io::Tokenizer::TYPE_END:
+        AddError("Unexpected end of stream while parsing option value.");
+        return false;
+
+      case io::Tokenizer::TYPE_WHITESPACE:
+      case io::Tokenizer::TYPE_NEWLINE:
+        GOOGLE_CHECK(!input_->report_whitespace() && !input_->report_newlines())
+            << "Whitespace tokens were not requested.";
+        GOOGLE_LOG(FATAL) << "Tokenizer reported whitespace.";
+        return false;
+
+      case io::Tokenizer::TYPE_IDENTIFIER: {
+        value_location.AddPath(
+            UninterpretedOption::kIdentifierValueFieldNumber);
+        if (is_negative) {
+          AddError("Invalid '-' symbol before identifier.");
+          return false;
+        }
+        std::string value;
+        DO(ConsumeIdentifier(&value, "Expected identifier."));
+        uninterpreted_option->set_identifier_value(value);
+        break;
+      }
+
+      case io::Tokenizer::TYPE_INTEGER: {
+        uint64_t value;
+        uint64_t max_value =
+            is_negative
+                ? static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1
+                : std::numeric_limits<uint64_t>::max();
+        DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+        if (is_negative) {
+          value_location.AddPath(
+              UninterpretedOption::kNegativeIntValueFieldNumber);
+          uninterpreted_option->set_negative_int_value(
+              static_cast<int64_t>(0 - value));
+        } else {
+          value_location.AddPath(
+              UninterpretedOption::kPositiveIntValueFieldNumber);
+          uninterpreted_option->set_positive_int_value(value);
+        }
+        break;
+      }
+
+      case io::Tokenizer::TYPE_FLOAT: {
+        value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
+        double value;
+        DO(ConsumeNumber(&value, "Expected number."));
+        uninterpreted_option->set_double_value(is_negative ? -value : value);
+        break;
+      }
+
+      case io::Tokenizer::TYPE_STRING: {
+        value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
+        if (is_negative) {
+          AddError("Invalid '-' symbol before string.");
+          return false;
+        }
+        std::string value;
+        DO(ConsumeString(&value, "Expected string."));
+        uninterpreted_option->set_string_value(value);
+        break;
+      }
+
+      case io::Tokenizer::TYPE_SYMBOL:
+        if (LookingAt("{")) {
+          value_location.AddPath(
+              UninterpretedOption::kAggregateValueFieldNumber);
+          DO(ParseUninterpretedBlock(
+              uninterpreted_option->mutable_aggregate_value()));
+        } else {
+          AddError("Expected option value.");
+          return false;
+        }
+        break;
+    }
+  }
+
+  if (style == OPTION_STATEMENT) {
+    DO(ConsumeEndOfDeclaration(";", &location));
+  }
+
+  return true;
+}
+
+bool Parser::ParseExtensions(DescriptorProto* message,
+                             const LocationRecorder& extensions_location,
+                             const FileDescriptorProto* containing_file) {
+  // Parse the declaration.
+  DO(Consume("extensions"));
+
+  int old_range_size = message->extension_range_size();
+
+  do {
+    // Note that kExtensionRangeFieldNumber was already pushed by the parent.
+    LocationRecorder location(extensions_location,
+                              message->extension_range_size());
+
+    DescriptorProto::ExtensionRange* range = message->add_extension_range();
+    location.RecordLegacyLocation(range,
+                                  DescriptorPool::ErrorCollector::NUMBER);
+
+    int start, end;
+    io::Tokenizer::Token start_token;
+
+    {
+      LocationRecorder start_location(
+          location, DescriptorProto::ExtensionRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeInteger(&start, "Expected field number range."));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, DescriptorProto::ExtensionRange::kEndFieldNumber);
+      if (TryConsume("max")) {
+        // Set to the sentinel value - 1 since we increment the value below.
+        // The actual value of the end of the range should be set with
+        // AdjustExtensionRangesWithMaxEndNumber.
+        end = kMaxRangeSentinel - 1;
+      } else {
+        DO(ConsumeInteger(&end, "Expected integer."));
+      }
+    } else {
+      LocationRecorder end_location(
+          location, DescriptorProto::ExtensionRange::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);
+  } while (TryConsume(","));
+
+  if (LookingAt("[")) {
+    int range_number_index = extensions_location.CurrentPathSize();
+    SourceCodeInfo info;
+
+    // Parse extension range options in the first range.
+    ExtensionRangeOptions* options =
+        message->mutable_extension_range(old_range_size)->mutable_options();
+
+    {
+      LocationRecorder index_location(
+          extensions_location, 0 /* we fill this in w/ actual index below */,
+          &info);
+      LocationRecorder location(
+          index_location, DescriptorProto::ExtensionRange::kOptionsFieldNumber);
+      DO(Consume("["));
+
+      do {
+        DO(ParseOption(options, location, containing_file, OPTION_ASSIGNMENT));
+      } while (TryConsume(","));
+
+      DO(Consume("]"));
+    }
+
+    // Then copy the extension range options to all of the other ranges we've
+    // parsed.
+    for (int i = old_range_size + 1; i < message->extension_range_size(); i++) {
+      message->mutable_extension_range(i)->mutable_options()->CopyFrom(
+          *options);
+    }
+    // and copy source locations to the other ranges, too
+    for (int i = old_range_size; i < message->extension_range_size(); i++) {
+      for (int j = 0; j < info.location_size(); j++) {
+        if (info.location(j).path_size() == range_number_index + 1) {
+          // this location's path is up to the extension range index, but
+          // doesn't include options; so it's redundant with location above
+          continue;
+        }
+        SourceCodeInfo_Location* dest = source_code_info_->add_location();
+        *dest = info.location(j);
+        dest->set_path(range_number_index, i);
+      }
+    }
+  }
+
+  DO(ConsumeEndOfDeclaration(";", &extensions_location));
+  return true;
+}
+
+// This is similar to extension range parsing, except that it accepts field
+// name literals.
+bool Parser::ParseReserved(DescriptorProto* message,
+                           const LocationRecorder& message_location) {
+  io::Tokenizer::Token start_token = input_->current();
+  // Parse the declaration.
+  DO(Consume("reserved"));
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedNameFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNames(message, location);
+  } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedRangeFieldNumber);
+    location.StartAt(start_token);
+    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);
+      if (TryConsume("max")) {
+        // Set to the sentinel value - 1 since we increment the value below.
+        // The actual value of the end of the range should be set with
+        // AdjustExtensionRangesWithMaxEndNumber.
+        end = kMaxRangeSentinel - 1;
+      } else {
+        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::ParseReserved(EnumDescriptorProto* message,
+                           const LocationRecorder& message_location) {
+  io::Tokenizer::Token start_token = input_->current();
+  // Parse the declaration.
+  DO(Consume("reserved"));
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    LocationRecorder location(message_location,
+                              EnumDescriptorProto::kReservedNameFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNames(message, location);
+  } else {
+    LocationRecorder location(message_location,
+                              EnumDescriptorProto::kReservedRangeFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNumbers(message, location);
+  }
+}
+
+bool Parser::ParseReservedNames(EnumDescriptorProto* message,
+                                const LocationRecorder& parent_location) {
+  do {
+    LocationRecorder location(parent_location, message->reserved_name_size());
+    DO(ConsumeString(message->add_reserved_name(), "Expected enum value."));
+  } while (TryConsume(","));
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseReservedNumbers(EnumDescriptorProto* message,
+                                  const LocationRecorder& parent_location) {
+  bool first = true;
+  do {
+    LocationRecorder location(parent_location, message->reserved_range_size());
+
+    EnumDescriptorProto::EnumReservedRange* range =
+        message->add_reserved_range();
+    int start, end;
+    io::Tokenizer::Token start_token;
+    {
+      LocationRecorder start_location(
+          location, EnumDescriptorProto::EnumReservedRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeSignedInteger(&start,
+                              (first ? "Expected enum value or number range."
+                                     : "Expected enum number range.")));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber);
+      if (TryConsume("max")) {
+        // This is in the enum descriptor path, which doesn't have the message
+        // set duality to fix up, so it doesn't integrate with the sentinel.
+        end = INT_MAX;
+      } else {
+        DO(ConsumeSignedInteger(&end, "Expected integer."));
+      }
+    } else {
+      LocationRecorder end_location(
+          location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
+      end = start;
+    }
+
+    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,
+                         int location_field_number_for_nested_type,
+                         const LocationRecorder& extend_location,
+                         const FileDescriptorProto* containing_file) {
+  DO(Consume("extend"));
+
+  // Parse the extendee type.
+  io::Tokenizer::Token extendee_start = input_->current();
+  std::string extendee;
+  DO(ParseUserDefinedType(&extendee));
+  io::Tokenizer::Token extendee_end = input_->previous();
+
+  // Parse the block.
+  DO(ConsumeEndOfDeclaration("{", &extend_location));
+
+  bool is_first = true;
+
+  do {
+    if (AtEnd()) {
+      AddError("Reached end of input in extend definition (missing '}').");
+      return false;
+    }
+
+    // Note that kExtensionFieldNumber was already pushed by the parent.
+    LocationRecorder location(extend_location, extensions->size());
+
+    FieldDescriptorProto* field = extensions->Add();
+
+    {
+      LocationRecorder extendee_location(
+          location, FieldDescriptorProto::kExtendeeFieldNumber);
+      extendee_location.StartAt(extendee_start);
+      extendee_location.EndAt(extendee_end);
+
+      if (is_first) {
+        extendee_location.RecordLegacyLocation(
+            field, DescriptorPool::ErrorCollector::EXTENDEE);
+        is_first = false;
+      }
+    }
+
+    field->set_extendee(extendee);
+
+    if (!ParseMessageField(field, messages, parent_location,
+                           location_field_number_for_nested_type, location,
+                           containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  } while (!TryConsumeEndOfDeclaration("}", nullptr));
+
+  return true;
+}
+
+bool Parser::ParseOneof(OneofDescriptorProto* oneof_decl,
+                        DescriptorProto* containing_type, int oneof_index,
+                        const LocationRecorder& oneof_location,
+                        const LocationRecorder& containing_type_location,
+                        const FileDescriptorProto* containing_file) {
+  DO(Consume("oneof"));
+
+  {
+    LocationRecorder name_location(oneof_location,
+                                   OneofDescriptorProto::kNameFieldNumber);
+    DO(ConsumeIdentifier(oneof_decl->mutable_name(), "Expected oneof name."));
+  }
+
+  DO(ConsumeEndOfDeclaration("{", &oneof_location));
+
+  do {
+    if (AtEnd()) {
+      AddError("Reached end of input in oneof definition (missing '}').");
+      return false;
+    }
+
+    if (LookingAt("option")) {
+      LocationRecorder option_location(
+          oneof_location, OneofDescriptorProto::kOptionsFieldNumber);
+      if (!ParseOption(oneof_decl->mutable_options(), option_location,
+                       containing_file, OPTION_STATEMENT)) {
+        return false;
+      }
+      continue;
+    }
+
+    // Print a nice error if the user accidentally tries to place a label
+    // on an individual member of a oneof.
+    if (LookingAt("required") || LookingAt("optional") ||
+        LookingAt("repeated")) {
+      AddError(
+          "Fields in oneofs must not have labels (required / optional "
+          "/ repeated).");
+      // We can continue parsing here because we understand what the user
+      // meant.  The error report will still make parsing fail overall.
+      input_->Next();
+    }
+
+    LocationRecorder field_location(containing_type_location,
+                                    DescriptorProto::kFieldFieldNumber,
+                                    containing_type->field_size());
+
+    FieldDescriptorProto* field = containing_type->add_field();
+    field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+    field->set_oneof_index(oneof_index);
+
+    if (!ParseMessageFieldNoLabel(field, containing_type->mutable_nested_type(),
+                                  containing_type_location,
+                                  DescriptorProto::kNestedTypeFieldNumber,
+                                  field_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  } while (!TryConsumeEndOfDeclaration("}", nullptr));
+
+  return true;
+}
+
+// -------------------------------------------------------------------
+// Enums
+
+bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
+                                 const LocationRecorder& enum_location,
+                                 const FileDescriptorProto* containing_file) {
+  DO(Consume("enum"));
+
+  {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(enum_type,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
+  }
+
+  DO(ParseEnumBlock(enum_type, enum_location, containing_file));
+
+  DO(ValidateEnum(enum_type));
+
+  return true;
+}
+
+bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
+                            const LocationRecorder& enum_location,
+                            const FileDescriptorProto* containing_file) {
+  DO(ConsumeEndOfDeclaration("{", &enum_location));
+
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in enum definition (missing '}').");
+      return false;
+    }
+
+    if (!ParseEnumStatement(enum_type, enum_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  }
+
+  return true;
+}
+
+bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
+                                const LocationRecorder& enum_location,
+                                const FileDescriptorProto* containing_file) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("option")) {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(enum_type->mutable_options(), location, containing_file,
+                       OPTION_STATEMENT);
+  } else if (LookingAt("reserved")) {
+    return ParseReserved(enum_type, enum_location);
+  } else {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kValueFieldNumber,
+                              enum_type->value_size());
+    return ParseEnumConstant(enum_type->add_value(), location, containing_file);
+  }
+}
+
+bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
+                               const LocationRecorder& enum_value_location,
+                               const FileDescriptorProto* containing_file) {
+  // Parse name.
+  {
+    LocationRecorder location(enum_value_location,
+                              EnumValueDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(enum_value,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(enum_value->mutable_name(),
+                         "Expected enum constant name."));
+  }
+
+  DO(Consume("=", "Missing numeric value for enum constant."));
+
+  // Parse value.
+  {
+    LocationRecorder location(enum_value_location,
+                              EnumValueDescriptorProto::kNumberFieldNumber);
+    location.RecordLegacyLocation(enum_value,
+                                  DescriptorPool::ErrorCollector::NUMBER);
+
+    int number;
+    DO(ConsumeSignedInteger(&number, "Expected integer."));
+    enum_value->set_number(number);
+  }
+
+  DO(ParseEnumConstantOptions(enum_value, enum_value_location,
+                              containing_file));
+
+  DO(ConsumeEndOfDeclaration(";", &enum_value_location));
+
+  return true;
+}
+
+bool Parser::ParseEnumConstantOptions(
+    EnumValueDescriptorProto* value,
+    const LocationRecorder& enum_value_location,
+    const FileDescriptorProto* containing_file) {
+  if (!LookingAt("[")) return true;
+
+  LocationRecorder location(enum_value_location,
+                            EnumValueDescriptorProto::kOptionsFieldNumber);
+
+  DO(Consume("["));
+
+  do {
+    DO(ParseOption(value->mutable_options(), location, containing_file,
+                   OPTION_ASSIGNMENT));
+  } while (TryConsume(","));
+
+  DO(Consume("]"));
+  return true;
+}
+
+// -------------------------------------------------------------------
+// Services
+
+bool Parser::ParseServiceDefinition(
+    ServiceDescriptorProto* service, const LocationRecorder& service_location,
+    const FileDescriptorProto* containing_file) {
+  DO(Consume("service"));
+
+  {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(service,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
+  }
+
+  DO(ParseServiceBlock(service, service_location, containing_file));
+  return true;
+}
+
+bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
+                               const LocationRecorder& service_location,
+                               const FileDescriptorProto* containing_file) {
+  DO(ConsumeEndOfDeclaration("{", &service_location));
+
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in service definition (missing '}').");
+      return false;
+    }
+
+    if (!ParseServiceStatement(service, service_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  }
+
+  return true;
+}
+
+bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
+                                   const LocationRecorder& service_location,
+                                   const FileDescriptorProto* containing_file) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("option")) {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(service->mutable_options(), location, containing_file,
+                       OPTION_STATEMENT);
+  } else {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kMethodFieldNumber,
+                              service->method_size());
+    return ParseServiceMethod(service->add_method(), location, containing_file);
+  }
+}
+
+bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
+                                const LocationRecorder& method_location,
+                                const FileDescriptorProto* containing_file) {
+  DO(Consume("rpc"));
+
+  {
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(method, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
+  }
+
+  // Parse input type.
+  DO(Consume("("));
+  {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
+      location.RecordLegacyLocation(method,
+                                    DescriptorPool::ErrorCollector::OTHER);
+      method->set_client_streaming(true);
+      DO(Consume("stream"));
+    }
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kInputTypeFieldNumber);
+    location.RecordLegacyLocation(method,
+                                  DescriptorPool::ErrorCollector::INPUT_TYPE);
+    DO(ParseUserDefinedType(method->mutable_input_type()));
+  }
+  DO(Consume(")"));
+
+  // Parse output type.
+  DO(Consume("returns"));
+  DO(Consume("("));
+  {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
+      location.RecordLegacyLocation(method,
+                                    DescriptorPool::ErrorCollector::OTHER);
+      DO(Consume("stream"));
+      method->set_server_streaming(true);
+    }
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kOutputTypeFieldNumber);
+    location.RecordLegacyLocation(method,
+                                  DescriptorPool::ErrorCollector::OUTPUT_TYPE);
+    DO(ParseUserDefinedType(method->mutable_output_type()));
+  }
+  DO(Consume(")"));
+
+  if (LookingAt("{")) {
+    // Options!
+    DO(ParseMethodOptions(method_location, containing_file,
+                          MethodDescriptorProto::kOptionsFieldNumber,
+                          method->mutable_options()));
+  } else {
+    DO(ConsumeEndOfDeclaration(";", &method_location));
+  }
+
+  return true;
+}
+
+bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
+                                const FileDescriptorProto* containing_file,
+                                const int optionsFieldNumber,
+                                Message* mutable_options) {
+  // Options!
+  ConsumeEndOfDeclaration("{", &parent_location);
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in method options (missing '}').");
+      return false;
+    }
+
+    if (TryConsumeEndOfDeclaration(";", nullptr)) {
+      // empty statement; ignore
+    } else {
+      LocationRecorder location(parent_location, optionsFieldNumber);
+      if (!ParseOption(mutable_options, location, containing_file,
+                       OPTION_STATEMENT)) {
+        // This statement failed to parse.  Skip it, but keep looping to
+        // parse other statements.
+        SkipStatement();
+      }
+    }
+  }
+
+  return true;
+}
+
+// -------------------------------------------------------------------
+
+bool Parser::ParseLabel(FieldDescriptorProto::Label* label,
+                        const LocationRecorder& field_location) {
+  if (!LookingAt("optional") && !LookingAt("repeated") &&
+      !LookingAt("required")) {
+    return false;
+  }
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kLabelFieldNumber);
+  if (TryConsume("optional")) {
+    *label = FieldDescriptorProto::LABEL_OPTIONAL;
+  } else if (TryConsume("repeated")) {
+    *label = FieldDescriptorProto::LABEL_REPEATED;
+  } else {
+    Consume("required");
+    *label = FieldDescriptorProto::LABEL_REQUIRED;
+  }
+  return true;
+}
+
+bool Parser::ParseType(FieldDescriptorProto::Type* type,
+                       std::string* type_name) {
+  const auto& type_names_table = GetTypeNameTable();
+  auto iter = type_names_table.find(input_->current().text);
+  if (iter != type_names_table.end()) {
+    *type = iter->second;
+    input_->Next();
+  } else {
+    DO(ParseUserDefinedType(type_name));
+  }
+  return true;
+}
+
+bool Parser::ParseUserDefinedType(std::string* type_name) {
+  type_name->clear();
+
+  const auto& type_names_table = GetTypeNameTable();
+  auto iter = type_names_table.find(input_->current().text);
+  if (iter != type_names_table.end()) {
+    // Note:  The only place enum types are allowed is for field types, but
+    //   if we are parsing a field type then we would not get here because
+    //   primitives are allowed there as well.  So this error message doesn't
+    //   need to account for enums.
+    AddError("Expected message type.");
+
+    // Pretend to accept this type so that we can go on parsing.
+    *type_name = input_->current().text;
+    input_->Next();
+    return true;
+  }
+
+  // A leading "." means the name is fully-qualified.
+  if (TryConsume(".")) type_name->append(".");
+
+  // Consume the first part of the name.
+  std::string identifier;
+  DO(ConsumeIdentifier(&identifier, "Expected type name."));
+  type_name->append(identifier);
+
+  // Consume more parts.
+  while (TryConsume(".")) {
+    type_name->append(".");
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    type_name->append(identifier);
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+bool Parser::ParsePackage(FileDescriptorProto* file,
+                          const LocationRecorder& root_location,
+                          const FileDescriptorProto* containing_file) {
+  if (file->has_package()) {
+    AddError("Multiple package definitions.");
+    // Don't append the new package to the old one.  Just replace it.  Not
+    // that it really matters since this is an error anyway.
+    file->clear_package();
+  }
+
+  LocationRecorder location(root_location,
+                            FileDescriptorProto::kPackageFieldNumber);
+  location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
+
+  DO(Consume("package"));
+
+  while (true) {
+    std::string identifier;
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    file->mutable_package()->append(identifier);
+    if (!TryConsume(".")) break;
+    file->mutable_package()->append(".");
+  }
+
+  DO(ConsumeEndOfDeclaration(";", &location));
+
+  return true;
+}
+
+bool Parser::ParseImport(RepeatedPtrField<std::string>* dependency,
+                         RepeatedField<int32_t>* public_dependency,
+                         RepeatedField<int32_t>* weak_dependency,
+                         const LocationRecorder& root_location,
+                         const FileDescriptorProto* containing_file) {
+  LocationRecorder location(root_location,
+                            FileDescriptorProto::kDependencyFieldNumber,
+                            dependency->size());
+
+  DO(Consume("import"));
+
+  if (LookingAt("public")) {
+    LocationRecorder public_location(
+        root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
+        public_dependency->size());
+    DO(Consume("public"));
+    *public_dependency->Add() = dependency->size();
+  } else if (LookingAt("weak")) {
+    LocationRecorder weak_location(
+        root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
+        weak_dependency->size());
+    weak_location.RecordLegacyImportLocation(containing_file, "weak");
+    DO(Consume("weak"));
+    *weak_dependency->Add() = dependency->size();
+  }
+
+  std::string import_file;
+  DO(ConsumeString(&import_file,
+                   "Expected a string naming the file to import."));
+  *dependency->Add() = import_file;
+  location.RecordLegacyImportLocation(containing_file, import_file);
+
+  DO(ConsumeEndOfDeclaration(";", &location));
+
+  return true;
+}
+
+// ===================================================================
+
+SourceLocationTable::SourceLocationTable() {}
+SourceLocationTable::~SourceLocationTable() {}
+
+bool SourceLocationTable::Find(
+    const Message* descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location, int* line,
+    int* column) const {
+  const std::pair<int, int>* result =
+      FindOrNull(location_map_, std::make_pair(descriptor, location));
+  if (result == nullptr) {
+    *line = -1;
+    *column = 0;
+    return false;
+  } else {
+    *line = result->first;
+    *column = result->second;
+    return true;
+  }
+}
+
+bool SourceLocationTable::FindImport(const Message* descriptor,
+                                     const std::string& name, int* line,
+                                     int* column) const {
+  const std::pair<int, int>* result =
+      FindOrNull(import_location_map_, std::make_pair(descriptor, name));
+  if (result == nullptr) {
+    *line = -1;
+    *column = 0;
+    return false;
+  } else {
+    *line = result->first;
+    *column = result->second;
+    return true;
+  }
+}
+
+void SourceLocationTable::Add(
+    const Message* descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location, int line,
+    int column) {
+  location_map_[std::make_pair(descriptor, location)] =
+      std::make_pair(line, column);
+}
+
+void SourceLocationTable::AddImport(const Message* descriptor,
+                                    const std::string& name, int line,
+                                    int column) {
+  import_location_map_[std::make_pair(descriptor, name)] =
+      std::make_pair(line, column);
+}
+
+void SourceLocationTable::Clear() { location_map_.clear(); }
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
new file mode 100644
index 0000000..d4eb763
--- /dev/null
+++ b/src/google/protobuf/compiler/parser.h
@@ -0,0 +1,602 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Implements parsing of .proto files to FileDescriptorProtos.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__
+#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/repeated_field.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace compiler {
+
+// Defined in this file.
+class Parser;
+class SourceLocationTable;
+
+// Implements parsing of protocol definitions (such as .proto files).
+//
+// Note that most users will be more interested in the Importer class.
+// Parser is a lower-level class which simply converts a single .proto file
+// to a FileDescriptorProto.  It does not resolve import directives or perform
+// many other kinds of validation needed to construct a complete
+// FileDescriptor.
+class PROTOBUF_EXPORT Parser {
+ public:
+  Parser();
+  ~Parser();
+
+  // Parse the entire input and construct a FileDescriptorProto representing
+  // it.  Returns true if no errors occurred, false otherwise.
+  bool Parse(io::Tokenizer* input, FileDescriptorProto* file);
+
+  // Optional features:
+
+  // DEPRECATED:  New code should use the SourceCodeInfo embedded in the
+  //   FileDescriptorProto.
+  //
+  // Requests that locations of certain definitions be recorded to the given
+  // SourceLocationTable while parsing.  This can be used to look up exact line
+  // and column numbers for errors reported by DescriptorPool during validation.
+  // Set to NULL (the default) to discard source location information.
+  void RecordSourceLocationsTo(SourceLocationTable* location_table) {
+    source_location_table_ = location_table;
+  }
+
+  // Requests that errors be recorded to the given ErrorCollector while
+  // parsing.  Set to NULL (the default) to discard error messages.
+  void RecordErrorsTo(io::ErrorCollector* error_collector) {
+    error_collector_ = error_collector;
+  }
+
+  // Returns the identifier used in the "syntax = " declaration, if one was
+  // seen during the last call to Parse(), or the empty string otherwise.
+  const std::string& GetSyntaxIdentifier() { return syntax_identifier_; }
+
+  // If set true, input files will be required to begin with a syntax
+  // identifier.  Otherwise, files may omit this.  If a syntax identifier
+  // is provided, it must be 'syntax = "proto2";' and must appear at the
+  // top of this file regardless of whether or not it was required.
+  void SetRequireSyntaxIdentifier(bool value) {
+    require_syntax_identifier_ = value;
+  }
+
+  // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop
+  // parsing as soon as it has seen the syntax identifier, or lack thereof.
+  // This is useful for quickly identifying the syntax of the file without
+  // parsing the whole thing.  If this is enabled, no error will be recorded
+  // if the syntax identifier is something other than "proto2" (since
+  // presumably the caller intends to deal with that), but other kinds of
+  // errors (e.g. parse errors) will still be reported.  When this is enabled,
+  // you may pass a NULL FileDescriptorProto to Parse().
+  void SetStopAfterSyntaxIdentifier(bool value) {
+    stop_after_syntax_identifier_ = value;
+  }
+
+ private:
+  class LocationRecorder;
+  struct MapField;
+
+  // =================================================================
+  // Error recovery helpers
+
+  // Consume the rest of the current statement.  This consumes tokens
+  // until it sees one of:
+  //   ';'  Consumes the token and returns.
+  //   '{'  Consumes the brace then calls SkipRestOfBlock().
+  //   '}'  Returns without consuming.
+  //   EOF  Returns (can't consume).
+  // The Parser often calls SkipStatement() after encountering a syntax
+  // error.  This allows it to go on parsing the following lines, allowing
+  // it to report more than just one error in the file.
+  void SkipStatement();
+
+  // Consume the rest of the current block, including nested blocks,
+  // ending after the closing '}' is encountered and consumed, or at EOF.
+  void SkipRestOfBlock();
+
+  // -----------------------------------------------------------------
+  // Single-token consuming helpers
+  //
+  // These make parsing code more readable.
+
+  // True if the current token is TYPE_END.
+  inline bool AtEnd();
+
+  // True if the next token matches the given text.
+  inline bool LookingAt(const char* text);
+  // True if the next token is of the given type.
+  inline bool LookingAtType(io::Tokenizer::TokenType token_type);
+
+  // If the next token exactly matches the text given, consume it and return
+  // true.  Otherwise, return false without logging an error.
+  bool TryConsume(const char* text);
+
+  // These attempt to read some kind of token from the input.  If successful,
+  // they return true.  Otherwise they return false and add the given error
+  // to the error list.
+
+  // Consume a token with the exact text given.
+  bool Consume(const char* text, const char* error);
+  // Same as above, but automatically generates the error "Expected \"text\".",
+  // where "text" is the expected token text.
+  bool Consume(const char* text);
+  // Consume a token of type IDENTIFIER and store its text in "output".
+  bool ConsumeIdentifier(std::string* output, const char* error);
+  // Consume an integer and store its value in "output".
+  bool ConsumeInteger(int* output, const char* error);
+  // Consume a signed integer and store its value in "output".
+  bool ConsumeSignedInteger(int* output, const char* error);
+  // Consume a 64-bit integer and store its value in "output".  If the value
+  // is greater than max_value, an error will be reported.
+  bool ConsumeInteger64(uint64_t max_value, uint64_t* output,
+                        const char* error);
+  // Consume a number and store its value in "output".  This will accept
+  // tokens of either INTEGER or FLOAT type.
+  bool ConsumeNumber(double* output, const char* error);
+  // Consume a string literal and store its (unescaped) value in "output".
+  bool ConsumeString(std::string* output, const char* error);
+
+  // Consume a token representing the end of the statement.  Comments between
+  // this token and the next will be harvested for documentation.  The given
+  // LocationRecorder should refer to the declaration that was just parsed;
+  // it will be populated with these comments.
+  //
+  // TODO(kenton):  The LocationRecorder is const because historically locations
+  //   have been passed around by const reference, for no particularly good
+  //   reason.  We should probably go through and change them all to mutable
+  //   pointer to make this more intuitive.
+  bool TryConsumeEndOfDeclaration(const char* text,
+                                  const LocationRecorder* location);
+  bool TryConsumeEndOfDeclarationFinishScope(const char* text,
+                                             const LocationRecorder* location);
+
+  bool ConsumeEndOfDeclaration(const char* text,
+                               const LocationRecorder* location);
+
+  // -----------------------------------------------------------------
+  // Error logging helpers
+
+  // Invokes error_collector_->AddError(), if error_collector_ is not NULL.
+  void AddError(int line, int column, const std::string& error);
+
+  // Invokes error_collector_->AddError() with the line and column number
+  // of the current token.
+  void AddError(const std::string& error);
+
+  // Invokes error_collector_->AddWarning() with the line and column number
+  // of the current token.
+  void AddWarning(const std::string& warning);
+
+  // Records a location in the SourceCodeInfo.location table (see
+  // descriptor.proto).  We use RAII to ensure that the start and end locations
+  // are recorded -- the constructor records the start location and the
+  // destructor records the end location.  Since the parser is
+  // recursive-descent, this works out beautifully.
+  class PROTOBUF_EXPORT LocationRecorder {
+   public:
+    // Construct the file's "root" location.
+    LocationRecorder(Parser* parser);
+
+    // Construct a location that represents a declaration nested within the
+    // given parent.  E.g. a field's location is nested within the location
+    // for a message type.  The parent's path will be copied, so you should
+    // call AddPath() only to add the path components leading from the parent
+    // to the child (as opposed to leading from the root to the child).
+    LocationRecorder(const LocationRecorder& parent);
+
+    // Convenience constructors that call AddPath() one or two times.
+    LocationRecorder(const LocationRecorder& parent, int path1);
+    LocationRecorder(const LocationRecorder& parent, int path1, int path2);
+
+    // Creates a recorder that generates locations into given source code info.
+    LocationRecorder(const LocationRecorder& parent, int path1,
+                     SourceCodeInfo* source_code_info);
+
+    ~LocationRecorder();
+
+    // Add a path component.  See SourceCodeInfo.Location.path in
+    // descriptor.proto.
+    void AddPath(int path_component);
+
+    // By default the location is considered to start at the current token at
+    // the time the LocationRecorder is created.  StartAt() sets the start
+    // location to the given token instead.
+    void StartAt(const io::Tokenizer::Token& token);
+
+    // Start at the same location as some other LocationRecorder.
+    void StartAt(const LocationRecorder& other);
+
+    // By default the location is considered to end at the previous token at
+    // the time the LocationRecorder is destroyed.  EndAt() sets the end
+    // location to the given token instead.
+    void EndAt(const io::Tokenizer::Token& token);
+
+    // Records the start point of this location to the SourceLocationTable that
+    // was passed to RecordSourceLocationsTo(), if any.  SourceLocationTable
+    // is an older way of keeping track of source locations which is still
+    // used in some places.
+    void RecordLegacyLocation(
+        const Message* descriptor,
+        DescriptorPool::ErrorCollector::ErrorLocation location);
+    void RecordLegacyImportLocation(const Message* descriptor,
+                                    const std::string& name);
+
+    // Returns the number of path components in the recorder's current location.
+    int CurrentPathSize() const;
+
+    // Attaches leading and trailing comments to the location.  The two strings
+    // will be swapped into place, so after this is called *leading and
+    // *trailing will be empty.
+    //
+    // TODO(kenton):  See comment on TryConsumeEndOfDeclaration(), above, for
+    //   why this is const.
+    void AttachComments(std::string* leading, std::string* trailing,
+                        std::vector<std::string>* detached_comments) const;
+
+   private:
+    Parser* parser_;
+    SourceCodeInfo* source_code_info_;
+    SourceCodeInfo::Location* location_;
+
+    void Init(const LocationRecorder& parent, SourceCodeInfo* source_code_info);
+  };
+
+  // =================================================================
+  // Parsers for various language constructs
+
+  // Parses the "syntax = \"proto2\";" line at the top of the file.  Returns
+  // false if it failed to parse or if the syntax identifier was not
+  // recognized.
+  bool ParseSyntaxIdentifier(const LocationRecorder& parent);
+
+  // These methods parse various individual bits of code.  They return
+  // false if they completely fail to parse the construct.  In this case,
+  // it is probably necessary to skip the rest of the statement to recover.
+  // However, if these methods return true, it does NOT mean that there
+  // were no errors; only that there were no *syntax* errors.  For instance,
+  // if a service method is defined using proper syntax but uses a primitive
+  // type as its input or output, ParseMethodField() still returns true
+  // and only reports the error by calling AddError().  In practice, this
+  // makes logic much simpler for the caller.
+
+  // Parse a top-level message, enum, service, etc.
+  bool ParseTopLevelStatement(FileDescriptorProto* file,
+                              const LocationRecorder& root_location);
+
+  // Parse various language high-level language construrcts.
+  bool ParseMessageDefinition(DescriptorProto* message,
+                              const LocationRecorder& message_location,
+                              const FileDescriptorProto* containing_file);
+  bool ParseEnumDefinition(EnumDescriptorProto* enum_type,
+                           const LocationRecorder& enum_location,
+                           const FileDescriptorProto* containing_file);
+  bool ParseServiceDefinition(ServiceDescriptorProto* service,
+                              const LocationRecorder& service_location,
+                              const FileDescriptorProto* containing_file);
+  bool ParsePackage(FileDescriptorProto* file,
+                    const LocationRecorder& root_location,
+                    const FileDescriptorProto* containing_file);
+  bool ParseImport(RepeatedPtrField<std::string>* dependency,
+                   RepeatedField<int32_t>* public_dependency,
+                   RepeatedField<int32_t>* weak_dependency,
+                   const LocationRecorder& root_location,
+                   const FileDescriptorProto* containing_file);
+
+  // These methods parse the contents of a message, enum, or service type and
+  // add them to the given object.  They consume the entire block including
+  // the beginning and ending brace.
+  bool ParseMessageBlock(DescriptorProto* message,
+                         const LocationRecorder& message_location,
+                         const FileDescriptorProto* containing_file);
+  bool ParseEnumBlock(EnumDescriptorProto* enum_type,
+                      const LocationRecorder& enum_location,
+                      const FileDescriptorProto* containing_file);
+  bool ParseServiceBlock(ServiceDescriptorProto* service,
+                         const LocationRecorder& service_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Parse one statement within a message, enum, or service block, including
+  // final semicolon.
+  bool ParseMessageStatement(DescriptorProto* message,
+                             const LocationRecorder& message_location,
+                             const FileDescriptorProto* containing_file);
+  bool ParseEnumStatement(EnumDescriptorProto* message,
+                          const LocationRecorder& enum_location,
+                          const FileDescriptorProto* containing_file);
+  bool ParseServiceStatement(ServiceDescriptorProto* message,
+                             const LocationRecorder& service_location,
+                             const FileDescriptorProto* containing_file);
+
+  // Parse a field of a message.  If the field is a group, its type will be
+  // added to "messages".
+  //
+  // parent_location and location_field_number_for_nested_type are needed when
+  // parsing groups -- we need to generate a nested message type within the
+  // parent and record its location accordingly.  Since the parent could be
+  // either a FileDescriptorProto or a DescriptorProto, we must pass in the
+  // correct field number to use.
+  bool ParseMessageField(FieldDescriptorProto* field,
+                         RepeatedPtrField<DescriptorProto>* messages,
+                         const LocationRecorder& parent_location,
+                         int location_field_number_for_nested_type,
+                         const LocationRecorder& field_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Like ParseMessageField() but expects the label has already been filled in
+  // by the caller.
+  bool ParseMessageFieldNoLabel(FieldDescriptorProto* field,
+                                RepeatedPtrField<DescriptorProto>* messages,
+                                const LocationRecorder& parent_location,
+                                int location_field_number_for_nested_type,
+                                const LocationRecorder& field_location,
+                                const FileDescriptorProto* containing_file);
+
+  bool ParseMapType(MapField* map_field, FieldDescriptorProto* field,
+                    LocationRecorder& type_name_location);
+
+  // Parse an "extensions" declaration.
+  bool ParseExtensions(DescriptorProto* message,
+                       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);
+  bool ParseReserved(EnumDescriptorProto* message,
+                     const LocationRecorder& message_location);
+  bool ParseReservedNames(EnumDescriptorProto* message,
+                          const LocationRecorder& parent_location);
+  bool ParseReservedNumbers(EnumDescriptorProto* message,
+                            const LocationRecorder& parent_location);
+
+  // Parse an "extend" declaration.  (See also comments for
+  // ParseMessageField().)
+  bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
+                   RepeatedPtrField<DescriptorProto>* messages,
+                   const LocationRecorder& parent_location,
+                   int location_field_number_for_nested_type,
+                   const LocationRecorder& extend_location,
+                   const FileDescriptorProto* containing_file);
+
+  // Parse a "oneof" declaration.  The caller is responsible for setting
+  // oneof_decl->label() since it will have had to parse the label before it
+  // knew it was parsing a oneof.
+  bool ParseOneof(OneofDescriptorProto* oneof_decl,
+                  DescriptorProto* containing_type, int oneof_index,
+                  const LocationRecorder& oneof_location,
+                  const LocationRecorder& containing_type_location,
+                  const FileDescriptorProto* containing_file);
+
+  // Parse a single enum value within an enum block.
+  bool ParseEnumConstant(EnumValueDescriptorProto* enum_value,
+                         const LocationRecorder& enum_value_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Parse enum constant options, i.e. the list in square brackets at the end
+  // of the enum constant value definition.
+  bool ParseEnumConstantOptions(EnumValueDescriptorProto* value,
+                                const LocationRecorder& enum_value_location,
+                                const FileDescriptorProto* containing_file);
+
+  // Parse a single method within a service definition.
+  bool ParseServiceMethod(MethodDescriptorProto* method,
+                          const LocationRecorder& method_location,
+                          const FileDescriptorProto* containing_file);
+
+  // Parse options of a single method or stream.
+  bool ParseMethodOptions(const LocationRecorder& parent_location,
+                          const FileDescriptorProto* containing_file,
+                          const int optionsFieldNumber,
+                          Message* mutable_options);
+
+  // Parse "required", "optional", or "repeated" and fill in "label"
+  // with the value. Returns true if such a label is consumed.
+  bool ParseLabel(FieldDescriptorProto::Label* label,
+                  const LocationRecorder& field_location);
+
+  // Parse a type name and fill in "type" (if it is a primitive) or
+  // "type_name" (if it is not) with the type parsed.
+  bool ParseType(FieldDescriptorProto::Type* type, std::string* type_name);
+  // Parse a user-defined type and fill in "type_name" with the name.
+  // If a primitive type is named, it is treated as an error.
+  bool ParseUserDefinedType(std::string* type_name);
+
+  // Parses field options, i.e. the stuff in square brackets at the end
+  // of a field definition.  Also parses default value.
+  bool ParseFieldOptions(FieldDescriptorProto* field,
+                         const LocationRecorder& field_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Parse the "default" option.  This needs special handling because its
+  // type is the field's type.
+  bool ParseDefaultAssignment(FieldDescriptorProto* field,
+                              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;"
+  };
+
+  // Parse a single option name/value pair, e.g. "ctype = CORD".  The name
+  // identifies a field of the given Message, and the value of that field
+  // is set to the parsed value.
+  bool ParseOption(Message* options, const LocationRecorder& options_location,
+                   const FileDescriptorProto* containing_file,
+                   OptionStyle style);
+
+  // Parses a single part of a multipart option name. A multipart name consists
+  // of names separated by dots. Each name is either an identifier or a series
+  // of identifiers separated by dots and enclosed in parentheses. E.g.,
+  // "foo.(bar.baz).moo".
+  bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
+                           const LocationRecorder& part_location,
+                           const FileDescriptorProto* containing_file);
+
+  // Parses a string surrounded by balanced braces.  Strips off the outer
+  // braces and stores the enclosed string in *value.
+  // E.g.,
+  //     { foo }                     *value gets 'foo'
+  //     { foo { bar: box } }        *value gets 'foo { bar: box }'
+  //     {}                          *value gets ''
+  //
+  // REQUIRES: LookingAt("{")
+  // When finished successfully, we are looking at the first token past
+  // the ending brace.
+  bool ParseUninterpretedBlock(std::string* value);
+
+  struct MapField {
+    // Whether the field is a map field.
+    bool is_map_field;
+    // The types of the key and value if they are primitive types.
+    FieldDescriptorProto::Type key_type;
+    FieldDescriptorProto::Type value_type;
+    // Or the type names string if the types are customized types.
+    std::string key_type_name;
+    std::string value_type_name;
+
+    MapField() : is_map_field(false) {}
+  };
+  // Desugar the map syntax to generate a nested map entry message.
+  void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field,
+                        RepeatedPtrField<DescriptorProto>* messages);
+
+  // Whether fields without label default to optional fields.
+  bool DefaultToOptionalFields() const {
+    return syntax_identifier_ == "proto3";
+  }
+
+  bool ValidateEnum(const EnumDescriptorProto* proto);
+
+  // =================================================================
+
+  io::Tokenizer* input_;
+  io::ErrorCollector* error_collector_;
+  SourceCodeInfo* source_code_info_;
+  SourceLocationTable* source_location_table_;  // legacy
+  bool had_errors_;
+  bool require_syntax_identifier_;
+  bool stop_after_syntax_identifier_;
+  std::string syntax_identifier_;
+
+  // Leading doc comments for the next declaration.  These are not complete
+  // yet; use ConsumeEndOfDeclaration() to get the complete comments.
+  std::string upcoming_doc_comments_;
+
+  // Detached comments are not connected to any syntax entities. Elements in
+  // this vector are paragraphs of comments separated by empty lines. The
+  // detached comments will be put into the leading_detached_comments field for
+  // the next element (See SourceCodeInfo.Location in descriptor.proto), when
+  // ConsumeEndOfDeclaration() is called.
+  std::vector<std::string> upcoming_detached_comments_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
+};
+
+// A table mapping (descriptor, ErrorLocation) pairs -- as reported by
+// DescriptorPool when validating descriptors -- to line and column numbers
+// within the original source code.
+//
+// This is semi-obsolete:  FileDescriptorProto.source_code_info now contains
+// far more complete information about source locations.  However, as of this
+// writing you still need to use SourceLocationTable when integrating with
+// DescriptorPool.
+class PROTOBUF_EXPORT SourceLocationTable {
+ public:
+  SourceLocationTable();
+  ~SourceLocationTable();
+
+  // Finds the precise location of the given error and fills in *line and
+  // *column with the line and column numbers.  If not found, sets *line to
+  // -1 and *column to 0 (since line = -1 is used to mean "error has no exact
+  // location" in the ErrorCollector interface).  Returns true if found, false
+  // otherwise.
+  bool Find(const Message* descriptor,
+            DescriptorPool::ErrorCollector::ErrorLocation location, int* line,
+            int* column) const;
+  bool FindImport(const Message* descriptor, const std::string& name, int* line,
+                  int* column) const;
+
+  // Adds a location to the table.
+  void Add(const Message* descriptor,
+           DescriptorPool::ErrorCollector::ErrorLocation location, int line,
+           int column);
+  void AddImport(const Message* descriptor, const std::string& name, int line,
+                 int column);
+
+  // Clears the contents of the table.
+  void Clear();
+
+ private:
+  typedef std::map<
+      std::pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>,
+      std::pair<int, int> >
+      LocationMap;
+  LocationMap location_map_;
+  std::map<std::pair<const Message*, std::string>, std::pair<int, int> >
+      import_location_map_;
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PARSER_H__
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
new file mode 100644
index 0000000..2d681d9
--- /dev/null
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -0,0 +1,3685 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/parser.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+namespace {
+
+class MockErrorCollector : public io::ErrorCollector {
+ public:
+  MockErrorCollector() = default;
+  ~MockErrorCollector() override = default;
+
+  std::string warning_;
+  std::string text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddWarning(int line, int column, const std::string& message) override {
+    strings::SubstituteAndAppend(&warning_, "$0:$1: $2\n", line, column, message);
+  }
+
+  void AddError(int line, int column, const std::string& message) override {
+    strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line, column, message);
+  }
+};
+
+class MockValidationErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  MockValidationErrorCollector(const SourceLocationTable& source_locations,
+                               io::ErrorCollector* wrapped_collector)
+      : source_locations_(source_locations),
+        wrapped_collector_(wrapped_collector) {}
+  ~MockValidationErrorCollector() override {}
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const std::string& filename, const std::string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const std::string& message) override {
+    int line, column;
+    if (location == DescriptorPool::ErrorCollector::IMPORT) {
+      source_locations_.FindImport(descriptor, element_name, &line, &column);
+    } else {
+      source_locations_.Find(descriptor, location, &line, &column);
+    }
+    wrapped_collector_->AddError(line, column, message);
+  }
+
+ private:
+  const SourceLocationTable& source_locations_;
+  io::ErrorCollector* wrapped_collector_;
+};
+
+class ParserTest : public testing::Test {
+ protected:
+  ParserTest() : require_syntax_identifier_(false) {}
+
+  // Set up the parser to parse the given text.
+  void SetupParser(const char* text) {
+    raw_input_.reset(new io::ArrayInputStream(text, strlen(text)));
+    input_.reset(new io::Tokenizer(raw_input_.get(), &error_collector_));
+    parser_.reset(new Parser());
+    parser_->RecordErrorsTo(&error_collector_);
+    parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_);
+  }
+
+  // Parse the input and expect that the resulting FileDescriptorProto matches
+  // the given output.  The output is a FileDescriptorProto in protocol buffer
+  // text format.
+  void ExpectParsesTo(const char* input, const char* output) {
+    SetupParser(input);
+    FileDescriptorProto actual, expected;
+
+    parser_->Parse(input_.get(), &actual);
+    EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+    ASSERT_EQ("", error_collector_.text_);
+
+    // We don't cover SourceCodeInfo in these tests.
+    actual.clear_source_code_info();
+
+    // Parse the ASCII representation in order to canonicalize it.  We could
+    // just compare directly to actual.DebugString(), but that would require
+    // that the caller precisely match the formatting that DebugString()
+    // produces.
+    ASSERT_TRUE(TextFormat::ParseFromString(output, &expected));
+
+    // Compare by comparing debug strings.
+    // TODO(kenton):  Use differencer, once it is available.
+    EXPECT_EQ(expected.DebugString(), actual.DebugString());
+  }
+
+  // Parse the text and expect that the given errors are reported.
+  void ExpectHasErrors(const char* text, const char* expected_errors) {
+    ExpectHasEarlyExitErrors(text, expected_errors);
+    EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+  }
+
+  // Same as above but does not expect that the parser parses the complete
+  // input.
+  void ExpectHasEarlyExitErrors(const char* text, const char* expected_errors) {
+    SetupParser(text);
+    FileDescriptorProto file;
+    parser_->Parse(input_.get(), &file);
+    EXPECT_EQ(expected_errors, error_collector_.text_);
+  }
+
+  // Parse the text as a file and validate it (with a DescriptorPool), and
+  // expect that the validation step reports the given errors.
+  void ExpectHasValidationErrors(const char* text,
+                                 const char* expected_errors) {
+    SetupParser(text);
+    SourceLocationTable source_locations;
+    parser_->RecordSourceLocationsTo(&source_locations);
+
+    FileDescriptorProto file;
+    file.set_name("foo.proto");
+    parser_->Parse(input_.get(), &file);
+    EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+    ASSERT_EQ("", error_collector_.text_);
+
+    MockValidationErrorCollector validation_error_collector(source_locations,
+                                                            &error_collector_);
+    EXPECT_TRUE(pool_.BuildFileCollectingErrors(
+                    file, &validation_error_collector) == nullptr);
+    EXPECT_EQ(expected_errors, error_collector_.text_);
+  }
+
+  MockErrorCollector error_collector_;
+  DescriptorPool pool_;
+
+  std::unique_ptr<io::ZeroCopyInputStream> raw_input_;
+  std::unique_ptr<io::Tokenizer> input_;
+  std::unique_ptr<Parser> parser_;
+  bool require_syntax_identifier_;
+};
+
+// ===================================================================
+
+TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
+  SetupParser(
+      "// blah\n"
+      "syntax = \"foobar\";\n"
+      "this line will not be parsed\n");
+  parser_->SetStopAfterSyntaxIdentifier(true);
+  EXPECT_TRUE(parser_->Parse(input_.get(), nullptr));
+  EXPECT_EQ("", error_collector_.text_);
+  EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
+  SetupParser(
+      "// blah\n"
+      "this line will not be parsed\n");
+  parser_->SetStopAfterSyntaxIdentifier(true);
+  EXPECT_TRUE(parser_->Parse(input_.get(), nullptr));
+  EXPECT_EQ("", error_collector_.text_);
+  EXPECT_EQ("", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
+  SetupParser(
+      "// blah\n"
+      "syntax = error;\n");
+  parser_->SetStopAfterSyntaxIdentifier(true);
+  EXPECT_FALSE(parser_->Parse(input_.get(), nullptr));
+  EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
+}
+
+TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
+  SetupParser("message A {}");
+  FileDescriptorProto file;
+  CaptureTestStderr();
+  EXPECT_TRUE(parser_->Parse(input_.get(), &file));
+  EXPECT_TRUE(GetCapturedTestStderr().find("No syntax specified") !=
+              std::string::npos);
+}
+
+TEST_F(ParserTest, WarnIfFieldNameIsNotUpperCamel) {
+  SetupParser(
+      "syntax = \"proto2\";"
+      "message abc {}");
+  FileDescriptorProto file;
+  EXPECT_TRUE(parser_->Parse(input_.get(), &file));
+  EXPECT_TRUE(error_collector_.warning_.find(
+                  "Message name should be in UpperCamelCase. Found: abc.") !=
+              std::string::npos);
+}
+
+TEST_F(ParserTest, WarnIfFieldNameIsNotLowerUnderscore) {
+  SetupParser(
+      "syntax = \"proto2\";"
+      "message A {"
+      "  optional string SongName = 1;"
+      "}");
+  FileDescriptorProto file;
+  EXPECT_TRUE(parser_->Parse(input_.get(), &file));
+  EXPECT_TRUE(error_collector_.warning_.find(
+                  "Field name should be lowercase. Found: SongName") !=
+              std::string::npos);
+}
+
+TEST_F(ParserTest, WarnIfFieldNameContainsNumberImmediatelyFollowUnderscore) {
+  SetupParser(
+      "syntax = \"proto2\";"
+      "message A {"
+      "  optional string song_name_1 = 1;"
+      "}");
+  FileDescriptorProto file;
+  EXPECT_TRUE(parser_->Parse(input_.get(), &file));
+  EXPECT_TRUE(error_collector_.warning_.find(
+                  "Number should not come right after an underscore. Found: "
+                  "song_name_1.") != std::string::npos);
+}
+
+// ===================================================================
+
+typedef ParserTest ParseMessageTest;
+
+TEST_F(ParseMessageTest, IgnoreBOM) {
+  char input[] =
+      "   message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n";
+  // Set UTF-8 BOM.
+  input[0] = (char)0xEF;
+  input[1] = (char)0xBB;
+  input[2] = (char)0xBF;
+  ExpectParsesTo(
+      input,
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, BOMError) {
+  char input[] =
+      "   message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n";
+  input[0] = (char)0xEF;
+  ExpectHasErrors(input,
+                  "0:1: Proto file starts with 0xEF but not UTF-8 BOM. "
+                  "Only UTF-8 is accepted for proto file.\n"
+                  "0:0: Expected top-level statement (e.g. \"message\").\n");
+}
+
+TEST_F(ParseMessageTest, SimpleMessage) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
+  require_syntax_identifier_ = false;
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+      "}");
+  EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
+  ExpectParsesTo(
+      "syntax = \"proto2\";\n"
+      "message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n",
+
+      "syntax: 'proto2' "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+      "}");
+  EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
+  require_syntax_identifier_ = true;
+  ExpectParsesTo(
+      "syntax = \"proto2\";\n"
+      "message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n",
+
+      "syntax: 'proto2' "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+      "}");
+  EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParseMessageTest, SimpleFields) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  required int32 foo = 15;\n"
+      "  optional int32 bar = 34;\n"
+      "  repeated int32 baz = 3;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
+      "  field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
+      "  field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  required int32    foo = 1;\n"
+      "  required int64    foo = 1;\n"
+      "  required uint32   foo = 1;\n"
+      "  required uint64   foo = 1;\n"
+      "  required sint32   foo = 1;\n"
+      "  required sint64   foo = 1;\n"
+      "  required fixed32  foo = 1;\n"
+      "  required fixed64  foo = 1;\n"
+      "  required sfixed32 foo = 1;\n"
+      "  required sfixed64 foo = 1;\n"
+      "  required float    foo = 1;\n"
+      "  required double   foo = 1;\n"
+      "  required string   foo = 1;\n"
+      "  required bytes    foo = 1;\n"
+      "  required bool     foo = 1;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32    number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64    number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32   number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64   number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32   number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64   number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32  number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64  number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT    number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE   number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING   number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES    number:1 "
+      "}"
+      "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL     number:1 "
+      "}"
+      "}");
+}
+
+TEST_F(ParseMessageTest, FieldDefaults) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  required int32  foo = 1 [default=  1  ];\n"
+      "  required int32  foo = 1 [default= -2  ];\n"
+      "  required int64  foo = 1 [default=  3  ];\n"
+      "  required int64  foo = 1 [default= -4  ];\n"
+      "  required uint32 foo = 1 [default=  5  ];\n"
+      "  required uint64 foo = 1 [default=  6  ];\n"
+      "  required float  foo = 1 [default=  7.5];\n"
+      "  required float  foo = 1 [default= -8.5];\n"
+      "  required float  foo = 1 [default=  9  ];\n"
+      "  required double foo = 1 [default= 10.5];\n"
+      "  required double foo = 1 [default=-11.5];\n"
+      "  required double foo = 1 [default= 12  ];\n"
+      "  required double foo = 1 [default= inf ];\n"
+      "  required double foo = 1 [default=-inf ];\n"
+      "  required double foo = 1 [default= nan ];\n"
+      "  required string foo = 1 [default='13\\001'];\n"
+      "  required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
+      "  required bytes  foo = 1 [default='14\\002'];\n"
+      "  required bytes  foo = 1 [default='a' \"b\" \n 'c'];\n"
+      "  required bool   foo = 1 [default=true ];\n"
+      "  required Foo    foo = 1 [default=FOO  ];\n"
+
+      "  required int32  foo = 1 [default= 0x7FFFFFFF];\n"
+      "  required int32  foo = 1 [default=-0x80000000];\n"
+      "  required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
+      "  required int64  foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
+      "  required int64  foo = 1 [default=-0x8000000000000000];\n"
+      "  required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
+      "  required double foo = 1 [default= 0xabcd];\n"
+      "}\n",
+
+#define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { type:TYPE_INT32   default_value:\"1\"         " ETC
+      " }"
+      "  field { type:TYPE_INT32   default_value:\"-2\"        " ETC
+      " }"
+      "  field { type:TYPE_INT64   default_value:\"3\"         " ETC
+      " }"
+      "  field { type:TYPE_INT64   default_value:\"-4\"        " ETC
+      " }"
+      "  field { type:TYPE_UINT32  default_value:\"5\"         " ETC
+      " }"
+      "  field { type:TYPE_UINT64  default_value:\"6\"         " ETC
+      " }"
+      "  field { type:TYPE_FLOAT   default_value:\"7.5\"       " ETC
+      " }"
+      "  field { type:TYPE_FLOAT   default_value:\"-8.5\"      " ETC
+      " }"
+      "  field { type:TYPE_FLOAT   default_value:\"9\"         " ETC
+      " }"
+      "  field { type:TYPE_DOUBLE  default_value:\"10.5\"      " ETC
+      " }"
+      "  field { type:TYPE_DOUBLE  default_value:\"-11.5\"     " ETC
+      " }"
+      "  field { type:TYPE_DOUBLE  default_value:\"12\"        " ETC
+      " }"
+      "  field { type:TYPE_DOUBLE  default_value:\"inf\"       " ETC
+      " }"
+      "  field { type:TYPE_DOUBLE  default_value:\"-inf\"      " ETC
+      " }"
+      "  field { type:TYPE_DOUBLE  default_value:\"nan\"       " ETC
+      " }"
+      "  field { type:TYPE_STRING  default_value:\"13\\001\"   " ETC
+      " }"
+      "  field { type:TYPE_STRING  default_value:\"abc\"       " ETC
+      " }"
+      "  field { type:TYPE_BYTES   default_value:\"14\\\\002\" " ETC
+      " }"
+      "  field { type:TYPE_BYTES   default_value:\"abc\"       " ETC
+      " }"
+      "  field { type:TYPE_BOOL    default_value:\"true\"      " ETC
+      " }"
+      "  field { type_name:\"Foo\" default_value:\"FOO\"       " ETC
+      " }"
+
+      "  field {"
+      "    type:TYPE_INT32   default_value:\"2147483647\"           " ETC
+      "  }"
+      "  field {"
+      "    type:TYPE_INT32   default_value:\"-2147483648\"          " ETC
+      "  }"
+      "  field {"
+      "    type:TYPE_UINT32  default_value:\"4294967295\"           " ETC
+      "  }"
+      "  field {"
+      "    type:TYPE_INT64   default_value:\"9223372036854775807\"  " ETC
+      "  }"
+      "  field {"
+      "    type:TYPE_INT64   default_value:\"-9223372036854775808\" " ETC
+      "  }"
+      "  field {"
+      "    type:TYPE_UINT64  default_value:\"18446744073709551615\" " ETC
+      "  }"
+      "  field {"
+      "    type:TYPE_DOUBLE  default_value:\"43981\"                " ETC
+      "  }"
+      "}");
+#undef ETC
+}
+
+TEST_F(ParseMessageTest, FieldJsonName) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  optional string foo = 1 [json_name = \"@type\"];\n"
+      "}\n",
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field {\n"
+      "    name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
+      "    json_name: \"@type\"\n"
+      "  }\n"
+      "}\n");
+}
+
+TEST_F(ParseMessageTest, FieldOptions) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  optional string foo = 1\n"
+      "      [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
+      "       (quux)=\"x\040y\", (baz.qux)=hey];\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: "
+      "1"
+      "          options { uninterpreted_option: { name { name_part: \"ctype\" "
+      "                                                   is_extension: false "
+      "} "
+      "                                            identifier_value: \"CORD\"  "
+      "}"
+      "                    uninterpreted_option: { name { name_part: \"foo\" "
+      "                                                   is_extension: true } "
+      "                                            positive_int_value: 7  }"
+      "                    uninterpreted_option: { name { name_part: \"foo\" "
+      "                                                   is_extension: false "
+      "} "
+      "                                            name { name_part: "
+      "\".bar.baz\""
+      "                                                   is_extension: true } "
+      "                                            name { name_part: \"qux\" "
+      "                                                   is_extension: false "
+      "} "
+      "                                            name { name_part: \"quux\" "
+      "                                                   is_extension: false "
+      "} "
+      "                                            name { name_part: \"corge\" "
+      "                                                   is_extension: true } "
+      "                                            negative_int_value: -33 }"
+      "                    uninterpreted_option: { name { name_part: \"quux\" "
+      "                                                   is_extension: true } "
+      "                                            string_value: \"x y\" }"
+      "                    uninterpreted_option: { name { name_part: "
+      "\"baz.qux\" "
+      "                                                   is_extension: true } "
+      "                                            identifier_value: \"hey\" }"
+      "          }"
+      "  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, Oneof) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  oneof foo {\n"
+      "    int32 a = 1;\n"
+      "    string b = 2;\n"
+      "    TestMessage c = 3;\n"
+      "    group D = 4 { optional int32 i = 5; }\n"
+      "  }\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
+      "          oneof_index:0 }"
+      "  field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
+      "          oneof_index:0 }"
+      "  field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" "
+      "          number:3 oneof_index:0 }"
+      "  field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP "
+      "          type_name:\"D\" number:4 oneof_index:0 }"
+      "  oneof_decl {"
+      "    name: \"foo\""
+      "  }"
+      "  nested_type {"
+      "    name: \"D\""
+      "    field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }"
+      "  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, MultipleOneofs) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  oneof foo {\n"
+      "    int32 a = 1;\n"
+      "    string b = 2;\n"
+      "  }\n"
+      "  oneof bar {\n"
+      "    int32 c = 3;\n"
+      "    string d = 4;\n"
+      "  }\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
+      "          oneof_index:0 }"
+      "  field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
+      "          oneof_index:0 }"
+      "  field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 "
+      "          oneof_index:1 }"
+      "  field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 "
+      "          oneof_index:1 }"
+      "  oneof_decl {"
+      "    name: \"foo\""
+      "  }"
+      "  oneof_decl {"
+      "    name: \"bar\""
+      "  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, Maps) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  map<int32, string> primitive_type_map = 1;\n"
+      "  map<KeyType, ValueType> composite_type_map = 2;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  nested_type {"
+      "    name: \"PrimitiveTypeMapEntry\""
+      "    field { "
+      "       name: \"key\" number: 1 label:LABEL_OPTIONAL"
+      "       type:TYPE_INT32"
+      "    }"
+      "    field { "
+      "       name: \"value\" number: 2 label:LABEL_OPTIONAL"
+      "       type:TYPE_STRING"
+      "    }"
+      "    options { map_entry: true }"
+      "  }"
+      "  nested_type {"
+      "    name: \"CompositeTypeMapEntry\""
+      "    field { "
+      "       name: \"key\" number: 1 label:LABEL_OPTIONAL"
+      "       type_name: \"KeyType\""
+      "    }"
+      "    field { "
+      "       name: \"value\" number: 2 label:LABEL_OPTIONAL"
+      "       type_name: \"ValueType\""
+      "    }"
+      "    options { map_entry: true }"
+      "  }"
+      "  field {"
+      "    name: \"primitive_type_map\""
+      "    label: LABEL_REPEATED"
+      "    type_name: \"PrimitiveTypeMapEntry\""
+      "    number: 1"
+      "  }"
+      "  field {"
+      "    name: \"composite_type_map\""
+      "    label: LABEL_REPEATED"
+      "    type_name: \"CompositeTypeMapEntry\""
+      "    number: 2"
+      "  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, Group) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  optional group TestGroup = 1 {};\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  nested_type { name: \"TestGroup\" }"
+      "  field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
+      "          type:TYPE_GROUP type_name: \"TestGroup\" }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, NestedMessage) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  message Nested {}\n"
+      "  optional Nested test_nested = 1;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  nested_type { name: \"Nested\" }"
+      "  field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
+      "          type_name: \"Nested\" }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, NestedEnum) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  enum NestedEnum {}\n"
+      "  optional NestedEnum test_enum = 1;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  enum_type { name: \"NestedEnum\" }"
+      "  field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
+      "          type_name: \"NestedEnum\" }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, ReservedRange) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "  reserved 2, 15, 9 to 11, 3, 20 to max;\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         }"
+      "  reserved_range { start:20  end:536870912 }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, ReservedRangeOnMessageSet) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  option message_set_wire_format = true;\n"
+      "  reserved 20 to max;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  options {"
+      "    uninterpreted_option {"
+      "      name {"
+      "        name_part: \"message_set_wire_format\""
+      "        is_extension: false"
+      "      }"
+      "      identifier_value: \"true\""
+      "    }"
+      "  }"
+      "  reserved_range { start:20  end:2147483647 }"
+      "}");
+}
+
+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"
+      "  extensions 10 to 19;\n"
+      "  extensions 30 to max;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  extension_range { start:10 end:20        }"
+      "  extension_range { start:30 end:536870912 }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, ExtensionRangeWithOptions) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  extensions 10 to 19 [(i) = 5];\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  extension_range {"
+      "    start:10"
+      "    end:20"
+      "    options {"
+      "      uninterpreted_option {"
+      "        name {"
+      "          name_part: \"i\""
+      "          is_extension: true"
+      "        }"
+      "        positive_int_value: 5"
+      "      }"
+      "    }"
+      "  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, CompoundExtensionRange) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  extensions 2, 15, 9 to 11, 100 to max, 3;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  extension_range { start:2   end:3         }"
+      "  extension_range { start:15  end:16        }"
+      "  extension_range { start:9   end:12        }"
+      "  extension_range { start:100 end:536870912 }"
+      "  extension_range { start:3   end:4         }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, CompoundExtensionRangeWithOptions) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  extensions 2, 15, 9 to 11, 100 to max, 3 [(i) = 5];\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  extension_range {"
+      "    start:2"
+      "    end:3"
+      "    options {"
+      "      uninterpreted_option {"
+      "        name {"
+      "          name_part: \"i\""
+      "          is_extension: true"
+      "        }"
+      "        positive_int_value: 5"
+      "      }"
+      "    }"
+      "  }"
+      "  extension_range {"
+      "    start:15"
+      "    end:16"
+      "    options {"
+      "      uninterpreted_option {"
+      "        name {"
+      "          name_part: \"i\""
+      "          is_extension: true"
+      "        }"
+      "        positive_int_value: 5"
+      "      }"
+      "    }"
+      "  }"
+      "  extension_range {"
+      "    start:9"
+      "    end:12"
+      "    options {"
+      "      uninterpreted_option {"
+      "        name {"
+      "          name_part: \"i\""
+      "          is_extension: true"
+      "        }"
+      "        positive_int_value: 5"
+      "      }"
+      "    }"
+      "  }"
+      "  extension_range {"
+      "    start:100"
+      "    end:536870912"
+      "    options {"
+      "      uninterpreted_option {"
+      "        name {"
+      "          name_part: \"i\""
+      "          is_extension: true"
+      "        }"
+      "        positive_int_value: 5"
+      "      }"
+      "    }"
+      "  }"
+      "  extension_range {"
+      "    start:3"
+      "    end:4"
+      "    options {"
+      "      uninterpreted_option {"
+      "        name {"
+      "          name_part: \"i\""
+      "          is_extension: true"
+      "        }"
+      "        positive_int_value: 5"
+      "      }"
+      "    }"
+      "  }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
+  // Messages using the message_set_wire_format option can accept larger
+  // extension numbers, as the numbers are not encoded as int32 field values
+  // rather than tags.
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  extensions 4 to max;\n"
+      "  option message_set_wire_format = true;\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "    extension_range { start:4 end: 0x7fffffff }"
+      "  options {\n"
+      "    uninterpreted_option { \n"
+      "      name {\n"
+      "        name_part: \"message_set_wire_format\"\n"
+      "        is_extension: false\n"
+      "      }\n"
+      "      identifier_value: \"true\"\n"
+      "    }\n"
+      "  }\n"
+      "}");
+}
+
+TEST_F(ParseMessageTest, Extensions) {
+  ExpectParsesTo(
+      "extend Extendee1 { optional int32 foo = 12; }\n"
+      "extend Extendee2 { repeated TestMessage bar = 22; }\n",
+
+      "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
+      "            extendee: \"Extendee1\" } "
+      "extension { name:\"bar\" label:LABEL_REPEATED number:22"
+      "            type_name:\"TestMessage\" extendee: \"Extendee2\" }");
+}
+
+TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
+  ExpectParsesTo(
+      "message TestMessage {\n"
+      "  extend Extendee1 { optional int32 foo = 12; }\n"
+      "  extend Extendee2 { repeated TestMessage bar = 22; }\n"
+      "}\n",
+
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "number:12"
+      "              extendee: \"Extendee1\" }"
+      "  extension { name:\"bar\" label:LABEL_REPEATED number:22"
+      "              type_name:\"TestMessage\" extendee: \"Extendee2\" }"
+      "}");
+}
+
+TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
+  ExpectParsesTo(
+      "extend Extendee1 {\n"
+      "  optional int32 foo = 12;\n"
+      "  repeated TestMessage bar = 22;\n"
+      "}\n",
+
+      "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
+      "            extendee: \"Extendee1\" } "
+      "extension { name:\"bar\" label:LABEL_REPEATED number:22"
+      "            type_name:\"TestMessage\" extendee: \"Extendee1\" }");
+}
+
+TEST_F(ParseMessageTest, OptionalLabelProto3) {
+  ExpectParsesTo(
+      "syntax = \"proto3\";\n"
+      "message TestMessage {\n"
+      "  int32 foo = 1;\n"
+      "}\n",
+
+      "syntax: \"proto3\" "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } "
+      "}");
+}
+
+TEST_F(ParseMessageTest, ExplicitOptionalLabelProto3) {
+  ExpectParsesTo(
+      "syntax = 'proto3';\n"
+      "message TestMessage {\n"
+      "  optional int32 foo = 1;\n"
+      "}\n",
+
+      "syntax: \"proto3\" "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
+      "          proto3_optional: true oneof_index: 0 } "
+      "  oneof_decl { name:\"_foo\" } "
+      "}");
+
+  // Handle collisions in the synthetic oneof name.
+  ExpectParsesTo(
+      "syntax = 'proto3';\n"
+      "message TestMessage {\n"
+      "  optional int32 foo = 1;\n"
+      "  oneof _foo {\n"
+      "    int32 __foo = 2;\n"
+      "  }\n"
+      "}\n",
+
+      "syntax: \"proto3\" "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
+      "          proto3_optional: true oneof_index: 1 } "
+      "  field { name:\"__foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 "
+      "          oneof_index: 0 } "
+      "  oneof_decl { name:\"_foo\" } "
+      "  oneof_decl { name:\"X_foo\" } "
+      "}");
+}
+
+// ===================================================================
+
+typedef ParserTest ParseEnumTest;
+
+TEST_F(ParseEnumTest, SimpleEnum) {
+  ExpectParsesTo(
+      "enum TestEnum {\n"
+      "  FOO = 0;\n"
+      "}\n",
+
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name:\"FOO\" number:0 }"
+      "}");
+}
+
+TEST_F(ParseEnumTest, Values) {
+  ExpectParsesTo(
+      "enum TestEnum {\n"
+      "  FOO = 13;\n"
+      "  BAR = -10;\n"
+      "  BAZ = 500;\n"
+      "  HEX_MAX = 0x7FFFFFFF;\n"
+      "  HEX_MIN = -0x80000000;\n"
+      "  INT_MAX = 2147483647;\n"
+      "  INT_MIN = -2147483648;\n"
+      "}\n",
+
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name:\"FOO\" number:13 }"
+      "  value { name:\"BAR\" number:-10 }"
+      "  value { name:\"BAZ\" number:500 }"
+      "  value { name:\"HEX_MAX\" number:2147483647 }"
+      "  value { name:\"HEX_MIN\" number:-2147483648 }"
+      "  value { name:\"INT_MAX\" number:2147483647 }"
+      "  value { name:\"INT_MIN\" number:-2147483648 }"
+      "}");
+}
+
+TEST_F(ParseEnumTest, ValueOptions) {
+  ExpectParsesTo(
+      "enum TestEnum {\n"
+      "  FOO = 13;\n"
+      "  BAR = -10 [ (something.text) = 'abc' ];\n"
+      "  BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
+      "}\n",
+
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name: \"FOO\" number: 13 }"
+      "  value { name: \"BAR\" number: -10 "
+      "    options { "
+      "      uninterpreted_option { "
+      "        name { name_part: \"something.text\" is_extension: true } "
+      "        string_value: \"abc\" "
+      "      } "
+      "    } "
+      "  } "
+      "  value { name: \"BAZ\" number: 500 "
+      "    options { "
+      "      uninterpreted_option { "
+      "        name { name_part: \"something.text\" is_extension: true } "
+      "        string_value: \"def\" "
+      "      } "
+      "      uninterpreted_option { "
+      "        name { name_part: \"other\" is_extension: false } "
+      "        positive_int_value: 1 "
+      "      } "
+      "    } "
+      "  } "
+      "}");
+}
+
+TEST_F(ParseEnumTest, ReservedRange) {
+  ExpectParsesTo(
+      "enum TestEnum {\n"
+      "  FOO = 0;\n"
+      "  reserved -2147483648, -6 to -4, -1 to 1, 2, 15, 9 to 11, 3, 20 to "
+      "max;\n"
+      "}\n",
+
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name:\"FOO\" number:0 }"
+      "  reserved_range { start:-2147483648  end:-2147483648 }"
+      "  reserved_range { start:-6           end:-4          }"
+      "  reserved_range { start:-1           end:1           }"
+      "  reserved_range { start:2            end:2           }"
+      "  reserved_range { start:15           end:15          }"
+      "  reserved_range { start:9            end:11          }"
+      "  reserved_range { start:3            end:3           }"
+      "  reserved_range { start:20           end:2147483647  }"
+      "}");
+}
+
+TEST_F(ParseEnumTest, ReservedNames) {
+  ExpectParsesTo(
+      "enum TestEnum {\n"
+      "  FOO = 0;\n"
+      "  reserved \"foo\", \"bar\";\n"
+      "}\n",
+
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name:\"FOO\" number:0 }"
+      "  reserved_name: \"foo\""
+      "  reserved_name: \"bar\""
+      "}");
+}
+
+// ===================================================================
+
+typedef ParserTest ParseServiceTest;
+
+TEST_F(ParseServiceTest, SimpleService) {
+  ExpectParsesTo(
+      "service TestService {\n"
+      "  rpc Foo(In) returns (Out);\n"
+      "}\n",
+
+      "service {"
+      "  name: \"TestService\""
+      "  method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
+      "}");
+}
+
+TEST_F(ParseServiceTest, MethodsAndStreams) {
+  ExpectParsesTo(
+      "service TestService {\n"
+      "  rpc Foo(In1) returns (Out1);\n"
+      "  rpc Bar(In2) returns (Out2);\n"
+      "  rpc Baz(In3) returns (Out3);\n"
+      "}\n",
+
+      "service {"
+      "  name: \"TestService\""
+      "  method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
+      "  method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
+      "  method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
+      "}");
+}
+
+
+// ===================================================================
+// imports and packages
+
+typedef ParserTest ParseMiscTest;
+
+TEST_F(ParseMiscTest, ParseImport) {
+  ExpectParsesTo("import \"foo/bar/baz.proto\";\n",
+                 "dependency: \"foo/bar/baz.proto\"");
+}
+
+TEST_F(ParseMiscTest, ParseMultipleImports) {
+  ExpectParsesTo(
+      "import \"foo.proto\";\n"
+      "import \"bar.proto\";\n"
+      "import \"baz.proto\";\n",
+      "dependency: \"foo.proto\""
+      "dependency: \"bar.proto\""
+      "dependency: \"baz.proto\"");
+}
+
+TEST_F(ParseMiscTest, ParsePublicImports) {
+  ExpectParsesTo(
+      "import \"foo.proto\";\n"
+      "import public \"bar.proto\";\n"
+      "import \"baz.proto\";\n"
+      "import public \"qux.proto\";\n",
+      "dependency: \"foo.proto\""
+      "dependency: \"bar.proto\""
+      "dependency: \"baz.proto\""
+      "dependency: \"qux.proto\""
+      "public_dependency: 1 "
+      "public_dependency: 3 ");
+}
+
+TEST_F(ParseMiscTest, ParsePackage) {
+  ExpectParsesTo("package foo.bar.baz;\n", "package: \"foo.bar.baz\"");
+}
+
+TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
+  ExpectParsesTo(
+      "package foo   .   bar.  \n"
+      "  baz;\n",
+      "package: \"foo.bar.baz\"");
+}
+
+// ===================================================================
+// options
+
+TEST_F(ParseMiscTest, ParseFileOptions) {
+  ExpectParsesTo(
+      "option java_package = \"com.google.foo\";\n"
+      "option optimize_for = CODE_SIZE;",
+
+      "options {"
+      "uninterpreted_option { name { name_part: \"java_package\" "
+      "                              is_extension: false }"
+      "                       string_value: \"com.google.foo\"} "
+      "uninterpreted_option { name { name_part: \"optimize_for\" "
+      "                              is_extension: false }"
+      "                       identifier_value: \"CODE_SIZE\" } "
+      "}");
+}
+
+// ===================================================================
+// Error tests
+//
+// There are a very large number of possible errors that the parser could
+// report, so it's infeasible to test every single one of them.  Instead,
+// we test each unique call to AddError() in parser.h.  This does not mean
+// we are testing every possible error that Parser can generate because
+// each variant of the Consume() helper only counts as one unique call to
+// AddError().
+
+typedef ParserTest ParseErrorTest;
+
+TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
+  require_syntax_identifier_ = true;
+  ExpectHasEarlyExitErrors("message TestMessage {}",
+                           "0:0: File must begin with a syntax statement, e.g. "
+                           "'syntax = \"proto2\";'.\n");
+  EXPECT_EQ("", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
+  ExpectHasEarlyExitErrors(
+      "syntax = \"no_such_syntax\";",
+      "0:9: Unrecognized syntax identifier \"no_such_syntax\".  This parser "
+      "only recognizes \"proto2\" and \"proto3\".\n");
+  EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParseErrorTest, SimpleSyntaxError) {
+  ExpectHasErrors("message TestMessage @#$ { blah }",
+                  "0:20: Expected \"{\".\n");
+  EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParseErrorTest, ExpectedTopLevel) {
+  ExpectHasErrors("blah;",
+                  "0:0: Expected top-level statement (e.g. \"message\").\n");
+}
+
+TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
+  // This used to cause an infinite loop.  Doh.
+  ExpectHasErrors("}",
+                  "0:0: Expected top-level statement (e.g. \"message\").\n"
+                  "0:0: Unmatched \"}\".\n");
+}
+
+// -------------------------------------------------------------------
+// Message errors
+
+TEST_F(ParseErrorTest, MessageMissingName) {
+  ExpectHasErrors("message {}", "0:8: Expected message name.\n");
+}
+
+TEST_F(ParseErrorTest, MessageMissingBody) {
+  ExpectHasErrors("message TestMessage;", "0:19: Expected \"{\".\n");
+}
+
+TEST_F(ParseErrorTest, EofInMessage) {
+  ExpectHasErrors(
+      "message TestMessage {",
+      "0:21: Reached end of input in message definition (missing '}').\n");
+}
+
+TEST_F(ParseErrorTest, MissingFieldNumber) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional int32 foo;\n"
+      "}\n",
+      "1:20: Missing field number.\n");
+}
+
+TEST_F(ParseErrorTest, ExpectedFieldNumber) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional int32 foo = ;\n"
+      "}\n",
+      "1:23: Expected field number.\n");
+}
+
+TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional int32 foo = 0x100000000;\n"
+      "}\n",
+      "1:23: Integer out of range.\n");
+}
+
+TEST_F(ParseErrorTest, MissingLabel) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  int32 foo = 1;\n"
+      "}\n",
+      "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
+}
+
+TEST_F(ParseErrorTest, ExpectedOptionName) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional uint32 foo = 1 [];\n"
+      "}\n",
+      "1:27: Expected identifier.\n");
+}
+
+TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional uint32 foo = 1 [.foo=1];\n"
+      "}\n",
+      "1:27: Expected identifier.\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional uint32 foo = 1 [default=true];\n"
+      "}\n",
+      "1:35: Expected integer for field default value.\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional bool foo = 1 [default=blah];\n"
+      "}\n",
+      "1:33: Expected \"true\" or \"false\".\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueNotString) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional string foo = 1 [default=1];\n"
+      "}\n",
+      "1:35: Expected string for field default value.\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional uint32 foo = 1 [default=-1];\n"
+      "}\n",
+      "1:36: Unsigned field can't have negative default value.\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueTooLarge) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional int32  foo = 1 [default= 0x80000000];\n"
+      "  optional int32  foo = 1 [default=-0x80000001];\n"
+      "  optional uint32 foo = 1 [default= 0x100000000];\n"
+      "  optional int64  foo = 1 [default= 0x80000000000000000];\n"
+      "  optional int64  foo = 1 [default=-0x80000000000000001];\n"
+      "  optional uint64 foo = 1 [default= 0x100000000000000000];\n"
+      "}\n",
+      "1:36: Integer out of range.\n"
+      "2:36: Integer out of range.\n"
+      "3:36: Integer out of range.\n"
+      "4:36: Integer out of range.\n"
+      "5:36: Integer out of range.\n"
+      "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"
+      "  HEX_TOO_BIG   =  0x80000000;\n"
+      "  HEX_TOO_SMALL = -0x80000001;\n"
+      "  INT_TOO_BIG   =  2147483648;\n"
+      "  INT_TOO_SMALL = -2147483649;\n"
+      "}\n",
+      "1:19: Integer out of range.\n"
+      "2:19: Integer out of range.\n"
+      "3:19: Integer out of range.\n"
+      "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"
+      "  optional uint32 foo = 1 [default=];\n"
+      "}\n",
+      "1:35: Expected integer for field default value.\n");
+}
+
+TEST_F(ParseErrorTest, DefaultValueForGroup) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional group Foo = 1 [default=blah] {}\n"
+      "}\n",
+      "1:34: Messages can't have default values.\n");
+}
+
+TEST_F(ParseErrorTest, DuplicateDefaultValue) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional uint32 foo = 1 [default=1,default=2];\n"
+      "}\n",
+      "1:37: Already set option \"default\".\n");
+}
+
+TEST_F(ParseErrorTest, MissingOneofName) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  oneof {\n"
+      "    int32 bar = 1;\n"
+      "  }\n"
+      "}\n",
+      "1:8: Expected oneof name.\n");
+}
+
+TEST_F(ParseErrorTest, LabelInOneof) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  oneof foo {\n"
+      "    optional int32 bar = 1;\n"
+      "  }\n"
+      "}\n",
+      "2:4: Fields in oneofs must not have labels (required / optional "
+      "/ repeated).\n");
+}
+
+TEST_F(ParseErrorTest, MapInOneof) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  oneof foo {\n"
+      "    map<int32, int32> foo_map = 1;\n"
+      "    map message_field = 2;\n"  // a normal message field is OK
+      "  }\n"
+      "}\n",
+      "2:7: Map fields are not allowed in oneofs.\n");
+}
+
+TEST_F(ParseErrorTest, LabelForMap) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional map<int32, int32> int_map = 1;\n"
+      "  required map<int32, int32> int_map2 = 2;\n"
+      "  repeated map<int32, int32> int_map3 = 3;\n"
+      "  optional map map_message = 4;\n"  // a normal message field is OK
+      "}\n",
+      "1:14: Field labels (required/optional/repeated) are not allowed on map "
+      "fields.\n"
+      "2:14: Field labels (required/optional/repeated) are not allowed on map "
+      "fields.\n"
+      "3:14: Field labels (required/optional/repeated) are not allowed on map "
+      "fields.\n");
+}
+
+TEST_F(ParseErrorTest, MalformedMaps) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  map map_message = 1;\n"  // a normal message field lacking label
+      "  map<string> str_map = 2;\n"
+      "  map<string,> str_map2 = 3;\n"
+      "  map<,string> str_map3 = 4;\n"
+      "  map<> empty_map = 5;\n"
+      "  map<string,string str_map6 = 6;\n"
+      "}"
+      "extend SomeMessage {\n"
+      "  map<int32, int32> int_map = 1;\n"
+      "}",
+      "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
+      "2:12: Expected \",\".\n"
+      "3:13: Expected type name.\n"
+      "4:6: Expected type name.\n"
+      "5:6: Expected type name.\n"
+      "6:20: Expected \">\".\n"
+      "8:5: Map fields are not allowed to be extensions.\n");
+}
+
+TEST_F(ParseErrorTest, GroupNotCapitalized) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional group foo = 1 {}\n"
+      "}\n",
+      "1:17: Group names must start with a capital letter.\n");
+}
+
+TEST_F(ParseErrorTest, GroupMissingBody) {
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional group Foo = 1;\n"
+      "}\n",
+      "1:24: Missing group body.\n");
+}
+
+TEST_F(ParseErrorTest, ExtendingPrimitive) {
+  ExpectHasErrors("extend int32 { optional string foo = 4; }\n",
+                  "0:7: Expected message type.\n");
+}
+
+TEST_F(ParseErrorTest, ErrorInExtension) {
+  ExpectHasErrors(
+      "message Foo { extensions 100 to 199; }\n"
+      "extend Foo { optional string foo; }\n",
+      "1:32: Missing field number.\n");
+}
+
+TEST_F(ParseErrorTest, MultipleParseErrors) {
+  // When a statement has a parse error, the parser should be able to continue
+  // parsing at the next statement.
+  ExpectHasErrors(
+      "message TestMessage {\n"
+      "  optional int32 foo;\n"
+      "  !invalid statement ending in a block { blah blah { blah } blah }\n"
+      "  optional int32 bar = 3 {}\n"
+      "}\n",
+      "1:20: Missing field number.\n"
+      "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
+      "2:2: Expected type name.\n"
+      "3:25: Expected \";\".\n");
+}
+
+TEST_F(ParseErrorTest, EofInAggregateValue) {
+  ExpectHasErrors(
+      "option (fileopt) = { i:100\n",
+      "1:0: Unexpected end of stream while parsing aggregate value.\n");
+}
+
+// -------------------------------------------------------------------
+// Enum errors
+
+TEST_F(ParseErrorTest, EofInEnum) {
+  ExpectHasErrors(
+      "enum TestEnum {",
+      "0:15: Reached end of input in enum definition (missing '}').\n");
+}
+
+TEST_F(ParseErrorTest, EnumValueMissingNumber) {
+  ExpectHasErrors(
+      "enum TestEnum {\n"
+      "  FOO;\n"
+      "}\n",
+      "1:5: Missing numeric value for enum constant.\n");
+}
+
+TEST_F(ParseErrorTest, EnumReservedStandaloneMaxNotAllowed) {
+  ExpectHasErrors(
+      "enum TestEnum {\n"
+      "  FOO = 1;\n"
+      "  reserved max;\n"
+      "}\n",
+      "2:11: Expected enum value or number range.\n");
+}
+
+TEST_F(ParseErrorTest, EnumReservedMixNameAndNumber) {
+  ExpectHasErrors(
+      "enum TestEnum {\n"
+      "  FOO = 1;\n"
+      "  reserved 10, \"foo\";\n"
+      "}\n",
+      "2:15: Expected enum number range.\n");
+}
+
+TEST_F(ParseErrorTest, EnumReservedPositiveNumberOutOfRange) {
+  ExpectHasErrors(
+      "enum TestEnum {\n"
+      "FOO = 1;\n"
+      "  reserved 2147483648;\n"
+      "}\n",
+      "2:11: Integer out of range.\n");
+}
+
+TEST_F(ParseErrorTest, EnumReservedNegativeNumberOutOfRange) {
+  ExpectHasErrors(
+      "enum TestEnum {\n"
+      "FOO = 1;\n"
+      "  reserved -2147483649;\n"
+      "}\n",
+      "2:12: Integer out of range.\n");
+}
+
+TEST_F(ParseErrorTest, EnumReservedMissingQuotes) {
+  ExpectHasErrors(
+      "enum TestEnum {\n"
+      "  FOO = 1;\n"
+      "  reserved foo;\n"
+      "}\n",
+      "2:11: Expected enum value or number range.\n");
+}
+
+// -------------------------------------------------------------------
+// Reserved field number errors
+
+TEST_F(ParseErrorTest, ReservedStandaloneMaxNotAllowed) {
+  ExpectHasErrors(
+      "message Foo {\n"
+      "  reserved max;\n"
+      "}\n",
+      "1:11: Expected field name or number range.\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");
+}
+
+TEST_F(ParseErrorTest, ReservedNegativeNumber) {
+  ExpectHasErrors(
+      "message Foo {\n"
+      "  reserved -10;\n"
+      "}\n",
+      "1:11: Expected field name or number range.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedNumberOutOfRange) {
+  ExpectHasErrors(
+      "message Foo {\n"
+      "  reserved 2147483648;\n"
+      "}\n",
+      "1:11: Integer out of range.\n");
+}
+
+// -------------------------------------------------------------------
+// Service errors
+
+TEST_F(ParseErrorTest, EofInService) {
+  ExpectHasErrors(
+      "service TestService {",
+      "0:21: Reached end of input in service definition (missing '}').\n");
+}
+
+TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
+  ExpectHasErrors(
+      "service TestService {\n"
+      "  rpc Foo(int32) returns (string);\n"
+      "}\n",
+      "1:10: Expected message type.\n"
+      "1:26: Expected message type.\n");
+}
+
+
+TEST_F(ParseErrorTest, EofInMethodOptions) {
+  ExpectHasErrors(
+      "service TestService {\n"
+      "  rpc Foo(Bar) returns(Bar) {",
+      "1:29: Reached end of input in method options (missing '}').\n"
+      "1:29: Reached end of input in service definition (missing '}').\n");
+}
+
+
+TEST_F(ParseErrorTest, PrimitiveMethodInput) {
+  ExpectHasErrors(
+      "service TestService {\n"
+      "  rpc Foo(int32) returns(Bar);\n"
+      "}\n",
+      "1:10: Expected message type.\n");
+}
+
+
+TEST_F(ParseErrorTest, MethodOptionTypeError) {
+  // This used to cause an infinite loop.
+  ExpectHasErrors(
+      "message Baz {}\n"
+      "service Foo {\n"
+      "  rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
+      "}\n",
+      "2:45: Expected \"=\".\n");
+}
+
+
+// -------------------------------------------------------------------
+// Import and package errors
+
+TEST_F(ParseErrorTest, ImportNotQuoted) {
+  ExpectHasErrors("import foo;\n",
+                  "0:7: Expected a string naming the file to import.\n");
+}
+
+TEST_F(ParseErrorTest, MultiplePackagesInFile) {
+  ExpectHasErrors(
+      "package foo;\n"
+      "package bar;\n",
+      "1:0: Multiple package definitions.\n");
+}
+
+// ===================================================================
+// Test that errors detected by DescriptorPool correctly report line and
+// column numbers.  We have one test for every call to RecordLocation() in
+// parser.cc.
+
+typedef ParserTest ParserValidationErrorTest;
+
+TEST_F(ParserValidationErrorTest, PackageNameError) {
+  // Create another file which defines symbol "foo".
+  FileDescriptorProto other_file;
+  other_file.set_name("bar.proto");
+  other_file.add_message_type()->set_name("foo");
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
+
+  // Now try to define it as a package.
+  ExpectHasValidationErrors(
+      "package foo.bar;",
+      "0:0: \"foo\" is already defined (as something other than a package) "
+      "in file \"bar.proto\".\n");
+}
+
+TEST_F(ParserValidationErrorTest, ImportUnloadedError) {
+  ExpectHasValidationErrors(
+      "package test;\n"
+      "\n"
+      "import \"unloaded.proto\";",
+      "2:0: Import \"unloaded.proto\" has not been loaded.\n");
+}
+
+TEST_F(ParserValidationErrorTest, ImportTwice) {
+  FileDescriptorProto other_file;
+  other_file.set_name("bar.proto");
+  other_file.add_message_type()->set_name("foo");
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
+
+  ExpectHasValidationErrors(
+      "package test;\n"
+      "\n"
+      "import \"bar.proto\";\n"
+      "  import \"bar.proto\";",
+      "3:2: Import \"bar.proto\" was listed twice.\n");
+}
+
+TEST_F(ParserValidationErrorTest, DuplicateFileError) {
+  FileDescriptorProto other_file;
+  other_file.set_name("foo.proto");
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
+
+  ExpectHasValidationErrors(
+      "package test;", "0:0: A file with this name is already in the pool.\n");
+}
+
+TEST_F(ParserValidationErrorTest, MessageNameError) {
+  ExpectHasValidationErrors(
+      "message Foo {}\n"
+      "message Foo {}\n",
+      "1:8: \"Foo\" is already defined.\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldNameError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  optional int32 bar = 1;\n"
+      "  optional int32 bar = 2;\n"
+      "}\n",
+      "2:17: \"bar\" is already defined in \"Foo\".\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldTypeError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  optional Baz bar = 1;\n"
+      "}\n",
+      "1:11: \"Baz\" is not defined.\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldNumberError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  optional int32 bar = 0;\n"
+      "}\n",
+      "1:23: Field numbers must be positive integers.\n"
+      "1:23: Suggested field numbers for Foo: 1\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
+  ExpectHasValidationErrors("extend Baz { optional int32 bar = 1; }\n",
+                            "0:7: \"Baz\" is not defined.\n");
+}
+
+TEST_F(ParserValidationErrorTest, ExtensionJsonNameError) {
+  ExpectHasValidationErrors(
+      "message TestMessage {\n"
+      "  extensions 1 to 100;\n"
+      "}\n"
+      "extend TestMessage {\n"
+      "  optional int32 foo = 12 [json_name = \"bar\"];\n"
+      "}",
+      "4:27: option json_name is not allowed on extension fields.\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
+  ExpectHasValidationErrors(
+      "enum Baz { QUX = 1; }\n"
+      "message Foo {\n"
+      "  optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
+      "}\n",
+      "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
+}
+
+TEST_F(ParserValidationErrorTest, FileOptionNameError) {
+  ExpectHasValidationErrors(
+      "option foo = 5;",
+      "0:7: Option \"foo\" unknown. Ensure that your proto definition file "
+      "imports the proto which defines the option.\n");
+}
+
+TEST_F(ParserValidationErrorTest, FileOptionValueError) {
+  ExpectHasValidationErrors(
+      "option java_outer_classname = 5;",
+      "0:30: Value must be quoted string for string option "
+      "\"google.protobuf.FileOptions.java_outer_classname\".\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  optional bool bar = 1 [foo=1];\n"
+      "}\n",
+      "1:25: Option \"foo\" unknown. Ensure that your proto definition file "
+      "imports the proto which defines the option.\n");
+}
+
+TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  optional int32 bar = 1 [ctype=1];\n"
+      "}\n",
+      "1:32: Value must be identifier for enum-valued option "
+      "\"google.protobuf.FieldOptions.ctype\".\n");
+}
+
+TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  extensions 0;\n"
+      "}\n",
+      "1:13: Extension numbers must be positive integers.\n"
+      "1:13: Suggested field numbers for Foo: 1\n");
+}
+
+TEST_F(ParserValidationErrorTest, Proto3ExtensionError) {
+  ExpectHasValidationErrors(
+      "syntax = 'proto3';\n"
+      "message Foo { \n"
+      "  extensions 100 to 199;\n"
+      "}\n"
+      "extend Foo { string foo = 101; }\n",
+      "4:7: Extensions in proto3 are only allowed for defining options.\n"
+      "2:13: Extension ranges are not allowed in proto3.\n");
+}
+
+TEST_F(ParserValidationErrorTest, Proto3MessageSet) {
+  ExpectHasValidationErrors(
+      "syntax = 'proto3';\n"
+      "message Foo { \n"
+      "  option message_set_wire_format = true;\n"
+      "}\n",
+      "1:8: MessageSet is not supported in proto3.\n");
+}
+
+TEST_F(ParserValidationErrorTest, Proto3Required) {
+  ExpectHasValidationErrors(
+      "syntax = 'proto3';\n"
+      "message Foo { \n"
+      "  required int32 field = 1;"
+      "}\n",
+      "2:11: Required fields are not allowed in proto3.\n");
+}
+
+TEST_F(ParserValidationErrorTest, Proto3Default) {
+  ExpectHasValidationErrors(
+      "syntax = 'proto3';\n"
+      "message Foo { \n"
+      "  int32 field = 1 [default = 12];"
+      "}\n",
+      "2:29: Explicit default values are not allowed in proto3.\n");
+}
+
+TEST_F(ParserValidationErrorTest, Proto3JsonConflictError) {
+  ExpectHasValidationErrors(
+      "syntax = 'proto3';\n"
+      "message TestMessage {\n"
+      "  uint32 foo = 1;\n"
+      "  uint32 Foo = 2;\n"
+      "}\n",
+      "3:9: The JSON camel-case name of field \"Foo\" conflicts with field "
+      "\"foo\". This is not allowed in proto3.\n");
+}
+
+TEST_F(ParserValidationErrorTest, EnumNameError) {
+  ExpectHasValidationErrors(
+      "enum Foo {A = 1;}\n"
+      "enum Foo {B = 1;}\n",
+      "1:5: \"Foo\" is already defined.\n");
+}
+
+TEST_F(ParserValidationErrorTest, Proto3EnumError) {
+  ExpectHasValidationErrors(
+      "syntax = 'proto3';\n"
+      "enum Foo {A = 1;}\n",
+      "1:14: The first enum value must be zero in proto3.\n");
+}
+
+TEST_F(ParserValidationErrorTest, EnumValueNameError) {
+  ExpectHasValidationErrors(
+      "enum Foo {\n"
+      "  BAR = 1;\n"
+      "  BAR = 1;\n"
+      "}\n",
+      "2:2: \"BAR\" is already defined.\n");
+}
+
+TEST_F(ParserValidationErrorTest, EnumValueAliasError) {
+  ExpectHasValidationErrors(
+      "enum Foo {\n"
+      "  BAR = 1;\n"
+      "  BAZ = 1;\n"
+      "}\n",
+      "2:8: \"BAZ\" uses the same enum value as \"BAR\". If this is "
+      "intended, set 'option allow_alias = true;' to the enum "
+      "definition.\n");
+}
+
+TEST_F(ParserValidationErrorTest, ExplicitlyMapEntryError) {
+  ExpectHasValidationErrors(
+      "message Foo {\n"
+      "  message ValueEntry {\n"
+      "    option map_entry = true;\n"
+      "    optional int32 key = 1;\n"
+      "    optional int32 value = 2;\n"
+      "    extensions 99 to 999;\n"
+      "  }\n"
+      "  repeated ValueEntry value = 1;\n"
+      "}",
+      "7:11: map_entry should not be set explicitly. Use "
+      "map<KeyType, ValueType> instead.\n");
+}
+
+TEST_F(ParserValidationErrorTest, ServiceNameError) {
+  ExpectHasValidationErrors(
+      "service Foo {}\n"
+      "service Foo {}\n",
+      "1:8: \"Foo\" is already defined.\n");
+}
+
+TEST_F(ParserValidationErrorTest, MethodNameError) {
+  ExpectHasValidationErrors(
+      "message Baz {}\n"
+      "service Foo {\n"
+      "  rpc Bar(Baz) returns(Baz);\n"
+      "  rpc Bar(Baz) returns(Baz);\n"
+      "}\n",
+      "3:6: \"Bar\" is already defined in \"Foo\".\n");
+}
+
+
+TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
+  ExpectHasValidationErrors(
+      "message Baz {}\n"
+      "service Foo {\n"
+      "  rpc Bar(Qux) returns(Baz);\n"
+      "}\n",
+      "2:10: \"Qux\" is not defined.\n");
+}
+
+
+TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
+  ExpectHasValidationErrors(
+      "message Baz {}\n"
+      "service Foo {\n"
+      "  rpc Bar(Baz) returns(Qux);\n"
+      "}\n",
+      "2:23: \"Qux\" is not defined.\n");
+}
+
+
+TEST_F(ParserValidationErrorTest, ResolvedUndefinedError) {
+  // Create another file which defines symbol ".base.bar".
+  FileDescriptorProto other_file;
+  other_file.set_name("base.proto");
+  other_file.set_package("base");
+  other_file.add_message_type()->set_name("bar");
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
+
+  // Define "foo.base" and try "base.bar".
+  // "base.bar" is resolved to "foo.base.bar" which is not defined.
+  ExpectHasValidationErrors(
+      "package foo.base;\n"
+      "import \"base.proto\";\n"
+      "message qux {\n"
+      "  optional base.bar baz = 1;\n"
+      "  optional .base.bar quz = 2;\n"
+      "}\n",
+      "3:11: \"base.bar\" is resolved to \"foo.base.bar\","
+      " which is not defined. The innermost scope is searched first "
+      "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")"
+      " to start from the outermost scope.\n");
+}
+
+TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) {
+  // Build descriptor message in test pool
+  FileDescriptorProto descriptor_proto;
+  DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto);
+  ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != nullptr);
+
+  // base2.proto:
+  //   package baz
+  //   import net/proto2/proto/descriptor.proto
+  //   message Bar { optional int32 foo = 1; }
+  //   extend FileOptions { optional Bar bar = 7672757; }
+  FileDescriptorProto other_file;
+  other_file.set_name("base2.proto");
+  other_file.set_package("baz");
+  other_file.add_dependency();
+  other_file.set_dependency(0, descriptor_proto.name());
+
+  DescriptorProto* message(other_file.add_message_type());
+  message->set_name("Bar");
+  FieldDescriptorProto* field(message->add_field());
+  field->set_name("foo");
+  field->set_number(1);
+  field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  field->set_type(FieldDescriptorProto::TYPE_INT32);
+
+  FieldDescriptorProto* extension(other_file.add_extension());
+  extension->set_name("bar");
+  extension->set_number(7672757);
+  extension->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  extension->set_type(FieldDescriptorProto::TYPE_MESSAGE);
+  extension->set_type_name("Bar");
+  extension->set_extendee("google.protobuf.FileOptions");
+
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
+
+  // qux.proto:
+  //   package qux.baz
+  //   option (baz.bar).foo = 1;
+  //
+  // Although "baz.bar" is already defined, the lookup code will try
+  // "qux.baz.bar", since it's the match from the innermost scope,
+  // which will cause a symbol not defined error.
+  ExpectHasValidationErrors(
+      "package qux.baz;\n"
+      "import \"base2.proto\";\n"
+      "option (baz.bar).foo = 1;\n",
+      "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\","
+      " which is not defined. The innermost scope is searched first "
+      "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")"
+      " to start from the outermost scope.\n");
+}
+
+// ===================================================================
+// Test that the output from FileDescriptor::DebugString() (and all other
+// descriptor types) is parseable, and results in the same Descriptor
+// definitions again afoter parsing (note, however, that the order of messages
+// cannot be guaranteed to be the same)
+
+typedef ParserTest ParseDescriptorDebugTest;
+
+class CompareDescriptorNames {
+ public:
+  bool operator()(const DescriptorProto* left,
+                  const DescriptorProto* right) const {
+    return left->name() < right->name();
+  }
+};
+
+// Sorts nested DescriptorProtos of a DescriptoProto, by name.
+void SortMessages(DescriptorProto* descriptor_proto) {
+  int size = descriptor_proto->nested_type_size();
+  // recursively sort; we can't guarantee the order of nested messages either
+  for (int i = 0; i < size; ++i) {
+    SortMessages(descriptor_proto->mutable_nested_type(i));
+  }
+  DescriptorProto** data =
+      descriptor_proto->mutable_nested_type()->mutable_data();
+  std::sort(data, data + size, CompareDescriptorNames());
+}
+
+// Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
+void SortMessages(FileDescriptorProto* file_descriptor_proto) {
+  int size = file_descriptor_proto->message_type_size();
+  // recursively sort; we can't guarantee the order of nested messages either
+  for (int i = 0; i < size; ++i) {
+    SortMessages(file_descriptor_proto->mutable_message_type(i));
+  }
+  DescriptorProto** data =
+      file_descriptor_proto->mutable_message_type()->mutable_data();
+  std::sort(data, data + size, CompareDescriptorNames());
+}
+
+// Strips the message and enum field type names for comparison purpose only.
+void StripFieldTypeName(DescriptorProto* proto) {
+  for (int i = 0; i < proto->field_size(); ++i) {
+    std::string type_name = proto->field(i).type_name();
+    std::string::size_type pos = type_name.find_last_of('.');
+    if (pos != std::string::npos) {
+      proto->mutable_field(i)->mutable_type_name()->assign(
+          type_name.begin() + pos + 1, type_name.end());
+    }
+  }
+  for (int i = 0; i < proto->nested_type_size(); ++i) {
+    StripFieldTypeName(proto->mutable_nested_type(i));
+  }
+}
+
+void StripFieldTypeName(FileDescriptorProto* file_proto) {
+  for (int i = 0; i < file_proto->message_type_size(); ++i) {
+    StripFieldTypeName(file_proto->mutable_message_type(i));
+  }
+}
+
+TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) {
+  const FileDescriptor* original_file =
+      protobuf_unittest::TestAllTypes::descriptor()->file();
+  FileDescriptorProto expected;
+  original_file->CopyTo(&expected);
+
+  // Get the DebugString of the unittest.proto FileDecriptor, which includes
+  // all other descriptor types
+  std::string debug_string = original_file->DebugString();
+
+  // Parse the debug string
+  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;
+
+  // We now have a FileDescriptorProto, but to compare with the expected we
+  // need to link to a FileDecriptor, then output back to a proto. We'll
+  // also need to give it the same name as the original.
+  parsed.set_name(
+      TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto"));
+  // We need the imported dependency before we can build our parsed proto
+  const FileDescriptor* public_import =
+      protobuf_unittest_import::PublicImportMessage::descriptor()->file();
+  FileDescriptorProto public_import_proto;
+  public_import->CopyTo(&public_import_proto);
+  ASSERT_TRUE(pool_.BuildFile(public_import_proto) != nullptr);
+  const FileDescriptor* import =
+      protobuf_unittest_import::ImportMessage::descriptor()->file();
+  FileDescriptorProto import_proto;
+  import->CopyTo(&import_proto);
+  ASSERT_TRUE(pool_.BuildFile(import_proto) != nullptr);
+  const FileDescriptor* actual = pool_.BuildFile(parsed);
+  parsed.Clear();
+  ASSERT_TRUE(actual != nullptr) << "Failed to validate:\n" << debug_string;
+  actual->CopyTo(&parsed);
+  ASSERT_TRUE(actual != nullptr);
+
+  // The messages might be in different orders, making them hard to compare.
+  // So, sort the messages in the descriptor protos (including nested messages,
+  // recursively).
+  SortMessages(&expected);
+  SortMessages(&parsed);
+
+  // I really wanted to use StringDiff here for the debug output on fail,
+  // but the strings are too long for it, and if I increase its max size,
+  // we get a memory allocation failure :(
+  EXPECT_EQ(expected.DebugString(), parsed.DebugString());
+}
+
+TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
+  const FileDescriptor* original_file =
+      protobuf_unittest::AggregateMessage::descriptor()->file();
+  FileDescriptorProto expected;
+  original_file->CopyTo(&expected);
+
+  std::string debug_string = original_file->DebugString();
+
+  // Parse the debug string
+  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_);
+
+  // We now have a FileDescriptorProto, but to compare with the expected we
+  // need to link to a FileDecriptor, then output back to a proto. We'll
+  // also need to give it the same name as the original.
+  parsed.set_name(original_file->name());
+
+  // unittest_custom_options.proto depends on descriptor.proto.
+  const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
+  FileDescriptorProto import_proto;
+  import->CopyTo(&import_proto);
+  ASSERT_TRUE(pool_.BuildFile(import_proto) != nullptr);
+
+  FileDescriptorProto any_import;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_import);
+  ASSERT_TRUE(pool_.BuildFile(any_import) != nullptr);
+
+  const FileDescriptor* actual = pool_.BuildFile(parsed);
+  ASSERT_TRUE(actual != nullptr);
+  parsed.Clear();
+  actual->CopyTo(&parsed);
+
+  // The messages might be in different orders, making them hard to compare.
+  // So, sort the messages in the descriptor protos (including nested messages,
+  // recursively).
+  SortMessages(&expected);
+  SortMessages(&parsed);
+
+  EXPECT_EQ(expected.DebugString(), parsed.DebugString());
+}
+
+// Ensure that DebugStringWithOptions(), with |include_comments| set to true,
+// includes comments from the original parser input in all of the appropriate
+// places.
+TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
+  SetupParser(
+      "// Detached comment before syntax.\n"
+      "\n"
+      "// Syntax comment.\n"
+      "syntax = \"proto2\";\n"
+      "\n"
+      "// Detached comment before package.\n"
+      "\n"
+      "// Package comment.\n"
+      "package comment_test;\n"
+      "\n"
+      "// Detached comment before TestMessage1.\n"
+      "\n"
+      "// Message comment.\n"
+      "//\n"
+      "// More detail in message comment.\n"
+      "message TestMessage1 {\n"
+      "\n"
+      "  // Detached comment before foo.\n"
+      "\n"
+      "  // Field comment.\n"
+      "  optional int32 foo = 1;\n"
+      "\n"
+      "  // Detached comment before NestedMessage.\n"
+      "\n"
+      "  // Nested-message comment.\n"
+      "  message NestedMessage {\n"
+      "    optional int32 bar = 1;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "// Detached comment before MyEnumType.\n"
+      "\n"
+      "// Enum comment.\n"
+      "enum MyEnumType {\n"
+      "\n"
+      "  // Detached comment before ASDF.\n"
+      "\n"
+      "  // Enum-value comment.\n"
+      "  ASDF = 1;\n"
+      "}\n"
+      "\n"
+      "// Detached comment before MyService.\n"
+      "\n"
+      "// Service comment.\n"
+      "service MyService {\n"
+      "\n"
+      "  // Detached comment before MyRPCCall.\n"
+      "\n"
+      "  // RPC comment.\n"
+      "  rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
+      "}\n");
+
+  FileDescriptorProto parsed_desc;
+  parsed_desc.set_name("foo.proto");
+  SourceLocationTable source_locations;
+  parser_->RecordSourceLocationsTo(&source_locations);
+  parser_->Parse(input_.get(), &parsed_desc);
+  EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+  ASSERT_EQ("", error_collector_.text_);
+
+  // We need to import the FileDescriptorProto to get a FileDescriptor.
+  MockValidationErrorCollector collector(source_locations, &error_collector_);
+  const FileDescriptor* descriptor =
+      pool_.BuildFileCollectingErrors(parsed_desc, &collector);
+  ASSERT_TRUE(descriptor != nullptr);
+
+  // Ensure that each of the comments appears somewhere in the DebugString().
+  // We don't test the exact comment placement or formatting, because we do not
+  // want to be too fragile here.
+  const char* expected_comments[] = {
+      "Detached comment before syntax.",
+      "Syntax comment.",
+      "Detached comment before package.",
+      "Package comment.",
+      "Detached comment before TestMessage1.",
+      "Message comment.",
+      "More detail in message comment.",
+      "Detached comment before foo.",
+      "Field comment",
+      "Detached comment before NestedMessage.",
+      "Nested-message comment",
+      "Detached comment before MyEnumType.",
+      "Enum comment",
+      "Detached comment before ASDF.",
+      "Enum-value comment",
+      "Detached comment before MyService.",
+      "Service comment",
+      "Detached comment before MyRPCCall.",
+      "RPC comment",
+  };
+
+  DebugStringOptions debug_string_options;
+  debug_string_options.include_comments = true;
+
+  {
+    const std::string debug_string =
+        descriptor->DebugStringWithOptions(debug_string_options);
+
+    for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
+      std::string::size_type found_pos =
+          debug_string.find(expected_comments[i]);
+      EXPECT_TRUE(found_pos != std::string::npos)
+          << "\"" << expected_comments[i] << "\" not found.";
+    }
+
+    // Result of DebugStringWithOptions should be parseable.
+    SetupParser(debug_string.c_str());
+    FileDescriptorProto parsed;
+    parser_->Parse(input_.get(), &parsed);
+    EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+    ASSERT_EQ("", error_collector_.text_) << "Failed to parse:\n"
+                                          << debug_string;
+  }
+
+}
+
+TEST_F(ParseDescriptorDebugTest, TestMaps) {
+  SetupParser(
+      "syntax = \"proto3\"; "
+      "message Foo { "
+      "  message Bar { } "
+      "  map<int32, Bar> enum_message_map = 1; "
+      "  map<string, float> primitive_map = 2; "
+      "} ");
+  FileDescriptorProto original;
+  EXPECT_TRUE(parser_->Parse(input_.get(), &original));
+  original.set_name("foo.proto");
+  const FileDescriptor* file = pool_.BuildFile(original);
+  ASSERT_TRUE(file != nullptr);
+
+  // Make sure the debug string uses map syntax and does not have the auto
+  // generated entry.
+  std::string debug_string = file->DebugString();
+  EXPECT_TRUE(debug_string.find("map<") != std::string::npos);
+  EXPECT_TRUE(debug_string.find("option map_entry") == std::string::npos);
+  EXPECT_TRUE(debug_string.find("MapEntry") == std::string::npos);
+
+  // Make sure the descriptor debug string is parsable.
+  FileDescriptorProto parsed;
+  SetupParser(debug_string.c_str());
+  parsed.set_name("foo.proto");
+  ASSERT_TRUE(parser_->Parse(input_.get(), &parsed));
+
+  original.clear_source_code_info();
+  parsed.clear_source_code_info();
+  StripFieldTypeName(&original);
+  StripFieldTypeName(&parsed);
+  EXPECT_EQ(original.DebugString(), parsed.DebugString());
+}
+
+// ===================================================================
+// SourceCodeInfo tests.
+
+// Follows a path -- as defined by SourceCodeInfo.Location.path -- from a
+// message to a particular sub-field.
+// * If the target is itself a message, sets *output_message to point at it,
+//   *output_field to NULL, and *output_index to -1.
+// * Otherwise, if the target is an element of a repeated field, sets
+//   *output_message to the containing message, *output_field to the descriptor
+//   of the field, and *output_index to the index of the element.
+// * Otherwise, the target is a field (possibly a repeated field, but not any
+//   one element).  Sets *output_message to the containing message,
+//   *output_field to the descriptor of the field, and *output_index to -1.
+// Returns true if the path was valid, false otherwise.  A gTest failure is
+// recorded before returning false.
+bool FollowPath(const Message& root,
+                RepeatedField<int>::const_iterator path_begin,
+                RepeatedField<int>::const_iterator path_end,
+                const Message** output_message,
+                const FieldDescriptor** output_field, int* output_index) {
+  if (path_begin == path_end) {
+    // Path refers to this whole message.
+    *output_message = &root;
+    *output_field = nullptr;
+    *output_index = -1;
+    return true;
+  }
+
+  const Descriptor* descriptor = root.GetDescriptor();
+  const Reflection* reflection = root.GetReflection();
+
+  const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
+
+  if (field == nullptr) {
+    ADD_FAILURE() << descriptor->name()
+                  << " has no field number: " << *path_begin;
+    return false;
+  }
+
+  ++path_begin;
+
+  if (field->is_repeated()) {
+    if (path_begin == path_end) {
+      // Path refers to the whole repeated field.
+      *output_message = &root;
+      *output_field = field;
+      *output_index = -1;
+      return true;
+    }
+
+    int index = *path_begin++;
+    int size = reflection->FieldSize(root, field);
+
+    if (index >= size) {
+      ADD_FAILURE() << descriptor->name() << "." << field->name()
+                    << " has size " << size
+                    << ", but path contained index: " << index;
+      return false;
+    }
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // Descend into child message.
+      const Message& child = reflection->GetRepeatedMessage(root, field, index);
+      return FollowPath(child, path_begin, path_end, output_message,
+                        output_field, output_index);
+    } else if (path_begin == path_end) {
+      // Path refers to this element.
+      *output_message = &root;
+      *output_field = field;
+      *output_index = index;
+      return true;
+    } else {
+      ADD_FAILURE() << descriptor->name() << "." << field->name()
+                    << " is not a message; cannot descend into it.";
+      return false;
+    }
+  } else {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      const Message& child = reflection->GetMessage(root, field);
+      return FollowPath(child, path_begin, path_end, output_message,
+                        output_field, output_index);
+    } else if (path_begin == path_end) {
+      // Path refers to this field.
+      *output_message = &root;
+      *output_field = field;
+      *output_index = -1;
+      return true;
+    } else {
+      ADD_FAILURE() << descriptor->name() << "." << field->name()
+                    << " is not a message; cannot descend into it.";
+      return false;
+    }
+  }
+}
+
+// Check if two spans are equal.
+bool CompareSpans(const RepeatedField<int>& span1,
+                  const RepeatedField<int>& span2) {
+  if (span1.size() != span2.size()) return false;
+  for (int i = 0; i < span1.size(); i++) {
+    if (span1.Get(i) != span2.Get(i)) return false;
+  }
+  return true;
+}
+
+// Test fixture for source info tests, which check that source locations are
+// recorded correctly in FileDescriptorProto.source_code_info.location.
+class SourceInfoTest : public ParserTest {
+ protected:
+  // The parsed file (initialized by Parse()).
+  FileDescriptorProto file_;
+
+  // Parse the given text as a .proto file and populate the spans_ map with
+  // all the source location spans in its SourceCodeInfo table.
+  bool Parse(const char* text) {
+    ExtractMarkers(text);
+    SetupParser(text_without_markers_.c_str());
+    if (!parser_->Parse(input_.get(), &file_)) {
+      return false;
+    }
+
+    const SourceCodeInfo& source_info = file_.source_code_info();
+    for (int i = 0; i < source_info.location_size(); i++) {
+      const SourceCodeInfo::Location& location = source_info.location(i);
+      const Message* descriptor_proto = nullptr;
+      const FieldDescriptor* field = nullptr;
+      int index = 0;
+      if (!FollowPath(file_, location.path().begin(), location.path().end(),
+                      &descriptor_proto, &field, &index)) {
+        return false;
+      }
+
+      spans_.insert(
+          std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
+    }
+
+    return true;
+  }
+
+  void TearDown() override {
+    EXPECT_TRUE(spans_.empty()) << "Forgot to call HasSpan() for:\n"
+                                << spans_.begin()->second->DebugString();
+  }
+
+  // -----------------------------------------------------------------
+  // HasSpan() checks that the span of source code delimited by the given
+  // tags (comments) correspond via the SourceCodeInfo table to the given
+  // part of the FileDescriptorProto.  (If unclear, look at the actual tests;
+  // it should quickly become obvious.)
+
+  bool HasSpan(char start_marker, char end_marker,
+               const Message& descriptor_proto) {
+    return HasSpanWithComment(start_marker, end_marker, descriptor_proto,
+                              nullptr, -1, nullptr, nullptr, nullptr);
+  }
+
+  bool HasSpanWithComment(char start_marker, char end_marker,
+                          const Message& descriptor_proto,
+                          const char* expected_leading_comments,
+                          const char* expected_trailing_comments,
+                          const char* expected_leading_detached_comments) {
+    return HasSpanWithComment(start_marker, end_marker, descriptor_proto,
+                              nullptr, -1, expected_leading_comments,
+                              expected_trailing_comments,
+                              expected_leading_detached_comments);
+  }
+
+  bool HasSpan(char start_marker, char end_marker,
+               const Message& descriptor_proto, const std::string& field_name) {
+    return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1);
+  }
+
+  bool HasSpan(char start_marker, char end_marker,
+               const Message& descriptor_proto, const std::string& field_name,
+               int index) {
+    return HasSpan(start_marker, end_marker, descriptor_proto, field_name,
+                   index, nullptr, nullptr, nullptr);
+  }
+
+  bool HasSpan(char start_marker, char end_marker,
+               const Message& descriptor_proto, const std::string& field_name,
+               int index, const char* expected_leading_comments,
+               const char* expected_trailing_comments,
+               const char* expected_leading_detached_comments) {
+    const FieldDescriptor* field =
+        descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
+    if (field == nullptr) {
+      ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
+                    << " has no such field: " << field_name;
+      return false;
+    }
+
+    return HasSpanWithComment(start_marker, end_marker, descriptor_proto, field,
+                              index, expected_leading_comments,
+                              expected_trailing_comments,
+                              expected_leading_detached_comments);
+  }
+
+  bool HasSpan(const Message& descriptor_proto) {
+    return HasSpanWithComment('\0', '\0', descriptor_proto, nullptr, -1,
+                              nullptr, nullptr, nullptr);
+  }
+
+  bool HasSpan(const Message& descriptor_proto, const std::string& field_name) {
+    return HasSpan('\0', '\0', descriptor_proto, field_name, -1);
+  }
+
+  bool HasSpanWithComment(char start_marker, char end_marker,
+                          const Message& descriptor_proto,
+                          const FieldDescriptor* field, int index,
+                          const char* expected_leading_comments,
+                          const char* expected_trailing_comments,
+                          const char* expected_leading_detached_comments) {
+    std::pair<SpanMap::iterator, SpanMap::iterator> range =
+        spans_.equal_range(SpanKey(descriptor_proto, field, index));
+
+    if (start_marker == '\0') {
+      if (range.first == range.second) {
+        return false;
+      } else {
+        spans_.erase(range.first);
+        return true;
+      }
+    } else {
+      std::pair<int, int> start_pos = FindOrDie(markers_, start_marker);
+      std::pair<int, int> end_pos = FindOrDie(markers_, end_marker);
+
+      RepeatedField<int> expected_span;
+      expected_span.Add(start_pos.first);
+      expected_span.Add(start_pos.second);
+      if (end_pos.first != start_pos.first) {
+        expected_span.Add(end_pos.first);
+      }
+      expected_span.Add(end_pos.second);
+
+      for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
+        if (CompareSpans(expected_span, iter->second->span())) {
+          if (expected_leading_comments == nullptr) {
+            EXPECT_FALSE(iter->second->has_leading_comments());
+          } else {
+            EXPECT_TRUE(iter->second->has_leading_comments());
+            EXPECT_EQ(expected_leading_comments,
+                      iter->second->leading_comments());
+          }
+          if (expected_trailing_comments == nullptr) {
+            EXPECT_FALSE(iter->second->has_trailing_comments());
+          } else {
+            EXPECT_TRUE(iter->second->has_trailing_comments());
+            EXPECT_EQ(expected_trailing_comments,
+                      iter->second->trailing_comments());
+          }
+          if (expected_leading_detached_comments == nullptr) {
+            EXPECT_EQ(0, iter->second->leading_detached_comments_size());
+          } else {
+            EXPECT_EQ(
+                expected_leading_detached_comments,
+                Join(iter->second->leading_detached_comments(), "\n"));
+          }
+
+          spans_.erase(iter);
+          return true;
+        }
+      }
+
+      return false;
+    }
+  }
+
+ private:
+  struct SpanKey {
+    const Message* descriptor_proto;
+    const FieldDescriptor* field;
+    int index;
+
+    inline SpanKey() {}
+    inline SpanKey(const Message& descriptor_proto_param,
+                   const FieldDescriptor* field_param, int index_param)
+        : descriptor_proto(&descriptor_proto_param),
+          field(field_param),
+          index(index_param) {}
+
+    inline bool operator<(const SpanKey& other) const {
+      if (descriptor_proto < other.descriptor_proto) return true;
+      if (descriptor_proto > other.descriptor_proto) return false;
+      if (field < other.field) return true;
+      if (field > other.field) return false;
+      return index < other.index;
+    }
+  };
+
+  typedef std::multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
+  SpanMap spans_;
+  std::map<char, std::pair<int, int> > markers_;
+  std::string text_without_markers_;
+
+  void ExtractMarkers(const char* text) {
+    markers_.clear();
+    text_without_markers_.clear();
+    int line = 0;
+    int column = 0;
+    while (*text != '\0') {
+      if (*text == '$') {
+        ++text;
+        GOOGLE_CHECK_NE('\0', *text);
+        if (*text == '$') {
+          text_without_markers_ += '$';
+          ++column;
+        } else {
+          markers_[*text] = std::make_pair(line, column);
+          ++text;
+          GOOGLE_CHECK_EQ('$', *text);
+        }
+      } else if (*text == '\n') {
+        ++line;
+        column = 0;
+        text_without_markers_ += *text;
+      } else {
+        text_without_markers_ += *text;
+        ++column;
+      }
+      ++text;
+    }
+  }
+};
+
+TEST_F(SourceInfoTest, BasicFileDecls) {
+  EXPECT_TRUE(
+      Parse("$a$syntax = \"proto2\";$i$\n"
+            "$b$package foo.bar;$c$\n"
+            "$d$import \"baz.proto\";$e$\n"
+            "$f$import\"qux.proto\";$h$\n"
+            "$j$import $k$public$l$ \"bar.proto\";$m$\n"
+            "$n$import $o$weak$p$ \"bar.proto\";$q$\n"
+            "\n"
+            "// comment ignored\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'q', file_));
+  EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
+  EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
+  EXPECT_TRUE(HasSpan('f', 'h', file_, "dependency", 1));
+  EXPECT_TRUE(HasSpan('j', 'm', file_, "dependency", 2));
+  EXPECT_TRUE(HasSpan('k', 'l', file_, "public_dependency", 0));
+  EXPECT_TRUE(HasSpan('n', 'q', file_, "dependency", 3));
+  EXPECT_TRUE(HasSpan('o', 'p', file_, "weak_dependency", 0));
+  EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
+}
+
+TEST_F(SourceInfoTest, Messages) {
+  EXPECT_TRUE(
+      Parse("$a$message $b$Foo$c$ {}$d$\n"
+            "$e$message $f$Bar$g$ {}$h$\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0)));
+  EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1)));
+  EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, Fields) {
+  EXPECT_TRUE(
+      Parse("message Foo {\n"
+            "  $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
+            "  $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
+            "}\n"));
+
+  const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
+  const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
+
+  EXPECT_TRUE(HasSpan('a', 'i', field1));
+  EXPECT_TRUE(HasSpan('a', 'b', field1, "label"));
+  EXPECT_TRUE(HasSpan('c', 'd', field1, "type"));
+  EXPECT_TRUE(HasSpan('e', 'f', field1, "name"));
+  EXPECT_TRUE(HasSpan('g', 'h', field1, "number"));
+
+  EXPECT_TRUE(HasSpan('j', 'r', field2));
+  EXPECT_TRUE(HasSpan('j', 'k', field2, "label"));
+  EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name"));
+  EXPECT_TRUE(HasSpan('n', 'o', field2, "name"));
+  EXPECT_TRUE(HasSpan('p', 'q', field2, "number"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Proto3Fields) {
+  EXPECT_TRUE(
+      Parse("syntax = \"proto3\";\n"
+            "message Foo {\n"
+            "  $a$int32$b$ $c$bar$d$ = $e$1$f$;$g$\n"
+            "  $h$repeated$i$ $j$X.Y$k$ $l$baz$m$ = $n$2$o$;$p$\n"
+            "}\n"));
+
+  const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
+  const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
+
+  EXPECT_TRUE(HasSpan('a', 'g', field1));
+  EXPECT_TRUE(HasSpan('a', 'b', field1, "type"));
+  EXPECT_TRUE(HasSpan('c', 'd', field1, "name"));
+  EXPECT_TRUE(HasSpan('e', 'f', field1, "number"));
+
+  EXPECT_TRUE(HasSpan('h', 'p', field2));
+  EXPECT_TRUE(HasSpan('h', 'i', field2, "label"));
+  EXPECT_TRUE(HasSpan('j', 'k', field2, "type_name"));
+  EXPECT_TRUE(HasSpan('l', 'm', field2, "name"));
+  EXPECT_TRUE(HasSpan('n', 'o', field2, "number"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_, "syntax"));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Extensions) {
+  EXPECT_TRUE(
+      Parse("$a$extend $b$Foo$c$ {\n"
+            "  $d$optional$e$ int32 bar = 1;$f$\n"
+            "  $g$repeated$h$ X.Y baz = 2;$i$\n"
+            "}$j$\n"
+            "$k$extend $l$Bar$m$ {\n"
+            "  $n$optional int32 qux = 1;$o$\n"
+            "}$p$\n"));
+
+  const FieldDescriptorProto& field1 = file_.extension(0);
+  const FieldDescriptorProto& field2 = file_.extension(1);
+  const FieldDescriptorProto& field3 = file_.extension(2);
+
+  EXPECT_TRUE(HasSpan('a', 'j', file_, "extension"));
+  EXPECT_TRUE(HasSpan('k', 'p', file_, "extension"));
+
+  EXPECT_TRUE(HasSpan('d', 'f', field1));
+  EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
+  EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
+
+  EXPECT_TRUE(HasSpan('g', 'i', field2));
+  EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
+  EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
+
+  EXPECT_TRUE(HasSpan('n', 'o', field3));
+  EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(field1, "type"));
+  EXPECT_TRUE(HasSpan(field1, "name"));
+  EXPECT_TRUE(HasSpan(field1, "number"));
+  EXPECT_TRUE(HasSpan(field2, "type_name"));
+  EXPECT_TRUE(HasSpan(field2, "name"));
+  EXPECT_TRUE(HasSpan(field2, "number"));
+  EXPECT_TRUE(HasSpan(field3, "label"));
+  EXPECT_TRUE(HasSpan(field3, "type"));
+  EXPECT_TRUE(HasSpan(field3, "name"));
+  EXPECT_TRUE(HasSpan(field3, "number"));
+}
+
+TEST_F(SourceInfoTest, NestedExtensions) {
+  EXPECT_TRUE(
+      Parse("message Message {\n"
+            "  $a$extend $b$Foo$c$ {\n"
+            "    $d$optional$e$ int32 bar = 1;$f$\n"
+            "    $g$repeated$h$ X.Y baz = 2;$i$\n"
+            "  }$j$\n"
+            "  $k$extend $l$Bar$m$ {\n"
+            "    $n$optional int32 qux = 1;$o$\n"
+            "  }$p$\n"
+            "}\n"));
+
+  const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
+  const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
+  const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
+
+  EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension"));
+  EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension"));
+
+  EXPECT_TRUE(HasSpan('d', 'f', field1));
+  EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
+  EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
+
+  EXPECT_TRUE(HasSpan('g', 'i', field2));
+  EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
+  EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
+
+  EXPECT_TRUE(HasSpan('n', 'o', field3));
+  EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(field1, "type"));
+  EXPECT_TRUE(HasSpan(field1, "name"));
+  EXPECT_TRUE(HasSpan(field1, "number"));
+  EXPECT_TRUE(HasSpan(field2, "type_name"));
+  EXPECT_TRUE(HasSpan(field2, "name"));
+  EXPECT_TRUE(HasSpan(field2, "number"));
+  EXPECT_TRUE(HasSpan(field3, "label"));
+  EXPECT_TRUE(HasSpan(field3, "type"));
+  EXPECT_TRUE(HasSpan(field3, "name"));
+  EXPECT_TRUE(HasSpan(field3, "number"));
+}
+
+TEST_F(SourceInfoTest, ExtensionRanges) {
+  EXPECT_TRUE(
+      Parse("message Message {\n"
+            "  $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
+            "  $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
+            "}\n"));
+
+  const DescriptorProto::ExtensionRange& range1 =
+      file_.message_type(0).extension_range(0);
+  const DescriptorProto::ExtensionRange& range2 =
+      file_.message_type(0).extension_range(1);
+  const DescriptorProto::ExtensionRange& range3 =
+      file_.message_type(0).extension_range(2);
+
+  EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range"));
+  EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range"));
+
+  EXPECT_TRUE(HasSpan('b', 'e', range1));
+  EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
+  EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
+
+  EXPECT_TRUE(HasSpan('f', 'g', range2));
+  EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
+  EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
+
+  EXPECT_TRUE(HasSpan('j', 'm', range3));
+  EXPECT_TRUE(HasSpan('j', 'k', range3, "start"));
+  EXPECT_TRUE(HasSpan('l', 'm', range3, "end"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, ReservedRanges) {
+  EXPECT_TRUE(
+      Parse("message Message {\n"
+            "  $a$reserved $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
+            "}\n"));
+
+  const DescriptorProto::ReservedRange& range1 =
+      file_.message_type(0).reserved_range(0);
+  const DescriptorProto::ReservedRange& range2 =
+      file_.message_type(0).reserved_range(1);
+
+  EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "reserved_range"));
+
+  EXPECT_TRUE(HasSpan('b', 'e', range1));
+  EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
+  EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
+
+  EXPECT_TRUE(HasSpan('f', 'g', range2));
+  EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
+  EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Oneofs) {
+  EXPECT_TRUE(
+      Parse("message Foo {\n"
+            "  $a$oneof $c$foo$d$ {\n"
+            "    $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n"
+            "  }$r$\n"
+            "}\n"));
+
+  const OneofDescriptorProto& oneof_decl = file_.message_type(0).oneof_decl(0);
+  const FieldDescriptorProto& field = file_.message_type(0).field(0);
+
+  EXPECT_TRUE(HasSpan('a', 'r', oneof_decl));
+  EXPECT_TRUE(HasSpan('c', 'd', oneof_decl, "name"));
+
+  EXPECT_TRUE(HasSpan('e', 'k', field));
+  EXPECT_TRUE(HasSpan('e', 'f', field, "type"));
+  EXPECT_TRUE(HasSpan('g', 'h', field, "name"));
+  EXPECT_TRUE(HasSpan('i', 'j', field, "number"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, NestedMessages) {
+  EXPECT_TRUE(
+      Parse("message Foo {\n"
+            "  $a$message $b$Bar$c$ {\n"
+            "    $d$message $e$Baz$f$ {}$g$\n"
+            "  }$h$\n"
+            "  $i$message $j$Qux$k$ {}$l$\n"
+            "}\n"));
+
+  const DescriptorProto& bar = file_.message_type(0).nested_type(0);
+  const DescriptorProto& baz = bar.nested_type(0);
+  const DescriptorProto& qux = file_.message_type(0).nested_type(1);
+
+  EXPECT_TRUE(HasSpan('a', 'h', bar));
+  EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+  EXPECT_TRUE(HasSpan('d', 'g', baz));
+  EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
+  EXPECT_TRUE(HasSpan('i', 'l', qux));
+  EXPECT_TRUE(HasSpan('j', 'k', qux, "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Groups) {
+  EXPECT_TRUE(
+      Parse("message Foo {\n"
+            "  message Bar {}\n"
+            "  $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
+            "    $i$message Qux {}$j$\n"
+            "  }$k$\n"
+            "}\n"));
+
+  const DescriptorProto& bar = file_.message_type(0).nested_type(0);
+  const DescriptorProto& baz = file_.message_type(0).nested_type(1);
+  const DescriptorProto& qux = baz.nested_type(0);
+  const FieldDescriptorProto& field = file_.message_type(0).field(0);
+
+  EXPECT_TRUE(HasSpan('a', 'k', field));
+  EXPECT_TRUE(HasSpan('a', 'b', field, "label"));
+  EXPECT_TRUE(HasSpan('c', 'd', field, "type"));
+  EXPECT_TRUE(HasSpan('e', 'f', field, "name"));
+  EXPECT_TRUE(HasSpan('e', 'f', field, "type_name"));
+  EXPECT_TRUE(HasSpan('g', 'h', field, "number"));
+
+  EXPECT_TRUE(HasSpan('a', 'k', baz));
+  EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
+  EXPECT_TRUE(HasSpan('i', 'j', qux));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(bar));
+  EXPECT_TRUE(HasSpan(bar, "name"));
+  EXPECT_TRUE(HasSpan(qux, "name"));
+}
+
+TEST_F(SourceInfoTest, Enums) {
+  EXPECT_TRUE(
+      Parse("$a$enum $b$Foo$c$ {}$d$\n"
+            "$e$enum $f$Bar$g$ {}$h$\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name"));
+  EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1)));
+  EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, EnumValues) {
+  EXPECT_TRUE(
+      Parse("enum Foo {\n"
+            "  $a$BAR$b$ = $c$1$d$;$e$\n"
+            "  $f$BAZ$g$ = $h$2$i$;$j$\n"
+            "}"));
+
+  const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
+  const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
+
+  EXPECT_TRUE(HasSpan('a', 'e', bar));
+  EXPECT_TRUE(HasSpan('a', 'b', bar, "name"));
+  EXPECT_TRUE(HasSpan('c', 'd', bar, "number"));
+  EXPECT_TRUE(HasSpan('f', 'j', baz));
+  EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
+  EXPECT_TRUE(HasSpan('h', 'i', baz, "number"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, EnumReservedRange) {
+  EXPECT_TRUE(
+      Parse("enum TestEnum {\n"
+            "  $a$reserved $b$1$c$ to $d$10$e$;$f$\n"
+            "}"));
+
+  const EnumDescriptorProto::EnumReservedRange& bar =
+      file_.enum_type(0).reserved_range(0);
+
+  EXPECT_TRUE(HasSpan('a', 'f', file_.enum_type(0), "reserved_range"));
+  EXPECT_TRUE(HasSpan('b', 'e', bar));
+  EXPECT_TRUE(HasSpan('b', 'c', bar, "start"));
+  EXPECT_TRUE(HasSpan('d', 'e', bar, "end"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, EnumReservedName) {
+  EXPECT_TRUE(
+      Parse("enum TestEnum {\n"
+            "  $a$reserved $b$'foo'$c$;$d$\n"
+            "}"));
+
+  const EnumDescriptorProto& bar = file_.enum_type(0);
+
+  EXPECT_TRUE(HasSpan('a', 'd', bar, "reserved_name"));
+  EXPECT_TRUE(HasSpan('b', 'c', bar, "reserved_name", 0));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, NestedEnums) {
+  EXPECT_TRUE(
+      Parse("message Foo {\n"
+            "  $a$enum $b$Bar$c$ {}$d$\n"
+            "  $e$enum $f$Baz$g$ {}$h$\n"
+            "}\n"));
+
+  const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
+  const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
+
+  EXPECT_TRUE(HasSpan('a', 'd', bar));
+  EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+  EXPECT_TRUE(HasSpan('e', 'h', baz));
+  EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Services) {
+  EXPECT_TRUE(
+      Parse("$a$service $b$Foo$c$ {}$d$\n"
+            "$e$service $f$Bar$g$ {}$h$\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'd', file_.service(0)));
+  EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name"));
+  EXPECT_TRUE(HasSpan('e', 'h', file_.service(1)));
+  EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, MethodsAndStreams) {
+  EXPECT_TRUE(
+      Parse("service Foo {\n"
+            "  $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
+            "  $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
+            "}"));
+
+  const MethodDescriptorProto& bar = file_.service(0).method(0);
+  const MethodDescriptorProto& baz = file_.service(0).method(1);
+
+  EXPECT_TRUE(HasSpan('a', 'h', bar));
+  EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
+  EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type"));
+  EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type"));
+
+  EXPECT_TRUE(HasSpan('i', 'p', baz));
+  EXPECT_TRUE(HasSpan('j', 'k', baz, "name"));
+  EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type"));
+  EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.service(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0), "name"));
+}
+
+
+TEST_F(SourceInfoTest, Options) {
+  EXPECT_TRUE(
+      Parse("$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
+            "$h$123$i$;$j$\n"
+            "$k$option qux = $l$-123$m$;$n$\n"
+            "$o$option corge = $p$abc$q$;$r$\n"
+            "$s$option grault = $t$'blah'$u$;$v$\n"
+            "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
+            "$0$option waldo = $1$123.0$2$;$3$\n"));
+
+  const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
+  const UninterpretedOption& option2 = file_.options().uninterpreted_option(1);
+  const UninterpretedOption& option3 = file_.options().uninterpreted_option(2);
+  const UninterpretedOption& option4 = file_.options().uninterpreted_option(3);
+  const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
+  const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
+
+  EXPECT_TRUE(HasSpan('a', 'j', file_.options()));
+  EXPECT_TRUE(HasSpan('a', 'j', option1));
+  EXPECT_TRUE(HasSpan('b', 'g', option1, "name"));
+  EXPECT_TRUE(HasSpan('b', 'c', option1.name(0)));
+  EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan('d', 'g', option1.name(1)));
+  EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part"));
+  EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value"));
+
+  EXPECT_TRUE(HasSpan('k', 'n', file_.options()));
+  EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value"));
+
+  EXPECT_TRUE(HasSpan('o', 'r', file_.options()));
+  EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value"));
+
+  EXPECT_TRUE(HasSpan('s', 'v', file_.options()));
+  EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value"));
+
+  EXPECT_TRUE(HasSpan('w', 'z', file_.options()));
+  EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value"));
+
+  EXPECT_TRUE(HasSpan('0', '3', file_.options()));
+  EXPECT_TRUE(HasSpan('1', '2', option6, "double_value"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(option2));
+  EXPECT_TRUE(HasSpan(option3));
+  EXPECT_TRUE(HasSpan(option4));
+  EXPECT_TRUE(HasSpan(option5));
+  EXPECT_TRUE(HasSpan(option6));
+  EXPECT_TRUE(HasSpan(option2, "name"));
+  EXPECT_TRUE(HasSpan(option3, "name"));
+  EXPECT_TRUE(HasSpan(option4, "name"));
+  EXPECT_TRUE(HasSpan(option5, "name"));
+  EXPECT_TRUE(HasSpan(option6, "name"));
+  EXPECT_TRUE(HasSpan(option2.name(0)));
+  EXPECT_TRUE(HasSpan(option3.name(0)));
+  EXPECT_TRUE(HasSpan(option4.name(0)));
+  EXPECT_TRUE(HasSpan(option5.name(0)));
+  EXPECT_TRUE(HasSpan(option6.name(0)));
+  EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option3.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option4.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option5.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option6.name(0), "name_part"));
+}
+
+TEST_F(SourceInfoTest, ScopedOptions) {
+  EXPECT_TRUE(
+      Parse("message Foo {\n"
+            "  $a$option mopt = 1;$b$\n"
+            "}\n"
+            "enum Bar {\n"
+            "  $c$option eopt = 1;$d$\n"
+            "}\n"
+            "service Baz {\n"
+            "  $e$option sopt = 1;$f$\n"
+            "  rpc M(X) returns(Y) {\n"
+            "    $g$option mopt = 1;$h$\n"
+            "  }\n"
+            "  rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
+            "    $k$option mopt = 1;$l$\n"
+            "  }\n"
+            "}\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
+  EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options()));
+  EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options()));
+  EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options()));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options().uninterpreted_option(0)));
+  EXPECT_TRUE(
+      HasSpan(file_.message_type(0).options().uninterpreted_option(0), "name"));
+  EXPECT_TRUE(
+      HasSpan(file_.message_type(0).options().uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(
+      HasSpan(file_.message_type(0).options().uninterpreted_option(0).name(0),
+              "name_part"));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options().uninterpreted_option(0),
+                      "positive_int_value"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options().uninterpreted_option(0)));
+  EXPECT_TRUE(
+      HasSpan(file_.enum_type(0).options().uninterpreted_option(0), "name"));
+  EXPECT_TRUE(
+      HasSpan(file_.enum_type(0).options().uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(
+      HasSpan(file_.enum_type(0).options().uninterpreted_option(0).name(0),
+              "name_part"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options().uninterpreted_option(0),
+                      "positive_int_value"));
+  EXPECT_TRUE(HasSpan(file_.service(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).options().uninterpreted_option(0)));
+  EXPECT_TRUE(
+      HasSpan(file_.service(0).options().uninterpreted_option(0), "name"));
+  EXPECT_TRUE(
+      HasSpan(file_.service(0).options().uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).options().uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.service(0).options().uninterpreted_option(0),
+                      "positive_int_value"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type"));
+  EXPECT_TRUE(
+      HasSpan(file_.service(0).method(0).options().uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).method(0).options().uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).method(0).options().uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).method(0).options().uninterpreted_option(0).name(0),
+      "name_part"));
+  EXPECT_TRUE(
+      HasSpan(file_.service(0).method(0).options().uninterpreted_option(0),
+              "positive_int_value"));
+
+  EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
+  EXPECT_TRUE(
+      HasSpan(file_.service(0).method(1).options().uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).method(1).options().uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).method(1).options().uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(
+      file_.service(0).method(1).options().uninterpreted_option(0).name(0),
+      "name_part"));
+  EXPECT_TRUE(
+      HasSpan(file_.service(0).method(1).options().uninterpreted_option(0),
+              "positive_int_value"));
+  EXPECT_TRUE(
+      HasSpan('1', '2', file_.service(0).method(1), "client_streaming"));
+  EXPECT_TRUE(
+      HasSpan('3', '4', file_.service(0).method(1), "server_streaming"));
+}
+
+TEST_F(SourceInfoTest, FieldOptions) {
+  // The actual "name = value" pairs are parsed by the same code as for
+  // top-level options so we won't re-test that -- just make sure that the
+  // syntax used for field options is understood.
+  EXPECT_TRUE(
+      Parse("message Foo {"
+            "  optional int32 bar = 1 "
+            "$a$[default=$b$123$c$,$d$opt1=123$e$,"
+            "$f$opt2='hi'$g$]$h$;"
+            "}\n"));
+
+  const FieldDescriptorProto& field = file_.message_type(0).field(0);
+  const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
+  const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
+
+  EXPECT_TRUE(HasSpan('a', 'h', field.options()));
+  EXPECT_TRUE(HasSpan('b', 'c', field, "default_value"));
+  EXPECT_TRUE(HasSpan('d', 'e', option1));
+  EXPECT_TRUE(HasSpan('f', 'g', option2));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(field));
+  EXPECT_TRUE(HasSpan(field, "label"));
+  EXPECT_TRUE(HasSpan(field, "type"));
+  EXPECT_TRUE(HasSpan(field, "name"));
+  EXPECT_TRUE(HasSpan(field, "number"));
+  EXPECT_TRUE(HasSpan(option1, "name"));
+  EXPECT_TRUE(HasSpan(option2, "name"));
+  EXPECT_TRUE(HasSpan(option1.name(0)));
+  EXPECT_TRUE(HasSpan(option2.name(0)));
+  EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
+  EXPECT_TRUE(HasSpan(option2, "string_value"));
+}
+
+TEST_F(SourceInfoTest, EnumValueOptions) {
+  // The actual "name = value" pairs are parsed by the same code as for
+  // top-level options so we won't re-test that -- just make sure that the
+  // syntax used for enum options is understood.
+  EXPECT_TRUE(
+      Parse("enum Foo {"
+            "  BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
+            "}\n"));
+
+  const EnumValueDescriptorProto& value = file_.enum_type(0).value(0);
+  const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
+  const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
+
+  EXPECT_TRUE(HasSpan('a', 'f', value.options()));
+  EXPECT_TRUE(HasSpan('b', 'c', option1));
+  EXPECT_TRUE(HasSpan('d', 'e', option2));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+  EXPECT_TRUE(HasSpan(value));
+  EXPECT_TRUE(HasSpan(value, "name"));
+  EXPECT_TRUE(HasSpan(value, "number"));
+  EXPECT_TRUE(HasSpan(option1, "name"));
+  EXPECT_TRUE(HasSpan(option2, "name"));
+  EXPECT_TRUE(HasSpan(option1.name(0)));
+  EXPECT_TRUE(HasSpan(option2.name(0)));
+  EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
+  EXPECT_TRUE(HasSpan(option2, "string_value"));
+}
+
+TEST_F(SourceInfoTest, DocComments) {
+  EXPECT_TRUE(
+      Parse("// Foo leading\n"
+            "// line 2\n"
+            "$a$message Foo {\n"
+            "  // Foo trailing\n"
+            "  // line 2\n"
+            "\n"
+            "  // detached\n"
+            "\n"
+            "  // bar leading\n"
+            "  $b$optional int32 bar = 1;$c$\n"
+            "  // bar trailing\n"
+            "}$d$\n"
+            "// ignored\n"));
+
+  const DescriptorProto& foo = file_.message_type(0);
+  const FieldDescriptorProto& bar = foo.field(0);
+
+  EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n",
+                                 " Foo trailing\n line 2\n", nullptr));
+  EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
+                                 " bar trailing\n", " detached\n"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(foo, "name"));
+  EXPECT_TRUE(HasSpan(bar, "label"));
+  EXPECT_TRUE(HasSpan(bar, "type"));
+  EXPECT_TRUE(HasSpan(bar, "name"));
+  EXPECT_TRUE(HasSpan(bar, "number"));
+}
+
+TEST_F(SourceInfoTest, DocComments2) {
+  EXPECT_TRUE(
+      Parse("// detached before message.\n"
+            "\n"
+            "// Foo leading\n"
+            "// line 2\n"
+            "$a$message Foo {\n"
+            "  /* Foo trailing\n"
+            "   * line 2 */\n"
+            "  // detached\n"
+            "  /* bar leading\n"
+            "   */"
+            "  $b$optional int32 bar = 1;$c$  // bar trailing\n"
+            "  // ignored detached\n"
+            "}$d$\n"
+            "// ignored\n"
+            "\n"
+            "// detached before option\n"
+            "\n"
+            "// option leading\n"
+            "$e$option baz = 123;$f$\n"
+            "// option trailing\n"));
+
+  const DescriptorProto& foo = file_.message_type(0);
+  const FieldDescriptorProto& bar = foo.field(0);
+  const UninterpretedOption& baz = file_.options().uninterpreted_option(0);
+
+  EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n",
+                                 " Foo trailing\n line 2 ",
+                                 " detached before message.\n"));
+  EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
+                                 " bar trailing\n", " detached\n"));
+  EXPECT_TRUE(HasSpanWithComment('e', 'f', baz, " option leading\n",
+                                 " option trailing\n",
+                                 " detached before option\n"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(foo, "name"));
+  EXPECT_TRUE(HasSpan(bar, "label"));
+  EXPECT_TRUE(HasSpan(bar, "type"));
+  EXPECT_TRUE(HasSpan(bar, "name"));
+  EXPECT_TRUE(HasSpan(bar, "number"));
+  EXPECT_TRUE(HasSpan(file_.options()));
+  EXPECT_TRUE(HasSpan(baz, "name"));
+  EXPECT_TRUE(HasSpan(baz.name(0)));
+  EXPECT_TRUE(HasSpan(baz.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(baz, "positive_int_value"));
+}
+
+TEST_F(SourceInfoTest, DocComments3) {
+  EXPECT_TRUE(
+      Parse("$a$message Foo {\n"
+            "  // bar leading\n"
+            "  $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
+            "  // bar trailing\n"
+            "}$d$\n"
+            "// ignored\n"));
+
+  const DescriptorProto& foo = file_.message_type(0);
+  const FieldDescriptorProto& bar = foo.field(0);
+
+  EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
+                                 " bar trailing\n", nullptr));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(foo));
+  EXPECT_TRUE(HasSpan(foo, "name"));
+  EXPECT_TRUE(HasSpan(bar, "label"));
+  EXPECT_TRUE(HasSpan(bar, "type"));
+  EXPECT_TRUE(HasSpan(bar, "name"));
+  EXPECT_TRUE(HasSpan(bar, "number"));
+  EXPECT_TRUE(HasSpan(bar.options()));
+  EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(
+      HasSpan(bar.options().uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(
+      HasSpan(bar.options().uninterpreted_option(0), "aggregate_value"));
+}
+
+TEST_F(SourceInfoTest, DocCommentsTopLevel) {
+  EXPECT_TRUE(
+      Parse("// detached before syntax paragraph 1\n"
+            "\n"
+            "// detached before syntax paragraph 2\n"
+            "\n"
+            "// syntax leading\n"
+            "$a$syntax = \"proto2\";$b$\n"
+            "// syntax trailing\n"
+            "\n"
+            "// syntax-package detached comments\n"
+            "\n"
+            ";\n"
+            "\n"
+            "// detached after empty before package\n"
+            "\n"
+            "// package leading\n"
+            "$c$package foo;$d$\n"
+            "// package trailing\n"
+            "\n"
+            "// ignored detach\n"
+            "\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1, " syntax leading\n",
+                      " syntax trailing\n",
+                      " detached before syntax paragraph 1\n"
+                      "\n"
+                      " detached before syntax paragraph 2\n"));
+  EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1, " package leading\n",
+                      " package trailing\n",
+                      " syntax-package detached comments\n"
+                      "\n"
+                      " detached after empty before package\n"));
+
+  // ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, DocCommentsOneof) {
+  EXPECT_TRUE(
+      Parse("// Foo leading\n"
+            "$a$message Foo {\n"
+            "  /* Foo trailing\n"
+            "   */\n"
+            "  // detached before oneof\n"
+            "  /* bar leading\n"
+            "   * line 2 */\n"
+            "  $b$oneof bar {\n"
+            "  /* bar trailing\n"
+            "   * line 2 */\n"
+            "  // detached before bar_int\n"
+            "  /* bar_int leading\n"
+            "   */\n"
+            "  $c$int32 bar_int = 1;$d$  // bar_int trailing\n"
+            "  // detach comment ignored\n"
+            "  }$e$\n"
+            "}$f$\n"));
+
+  const DescriptorProto& foo = file_.message_type(0);
+  const OneofDescriptorProto& bar = foo.oneof_decl(0);
+  const FieldDescriptorProto& bar_int = foo.field(0);
+
+  EXPECT_TRUE(HasSpanWithComment('a', 'f', foo, " Foo leading\n",
+                                 " Foo trailing\n", nullptr));
+  EXPECT_TRUE(HasSpanWithComment('b', 'e', bar, " bar leading\n line 2 ",
+                                 " bar trailing\n line 2 ",
+                                 " detached before oneof\n"));
+  EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int, " bar_int leading\n",
+                                 " bar_int trailing\n",
+                                 " detached before bar_int\n"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(foo, "name"));
+  EXPECT_TRUE(HasSpan(bar, "name"));
+  EXPECT_TRUE(HasSpan(bar_int, "type"));
+  EXPECT_TRUE(HasSpan(bar_int, "name"));
+  EXPECT_TRUE(HasSpan(bar_int, "number"));
+}
+
+// ===================================================================
+
+}  // anonymous namespace
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc
new file mode 100644
index 0000000..f3aa92f
--- /dev/null
+++ b/src/google/protobuf/compiler/php/php_generator.cc
@@ -0,0 +1,2426 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/php/php_generator.h>
+
+#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 <sstream>
+
+const std::string kDescriptorFile = "google/protobuf/descriptor.proto";
+const std::string kEmptyFile = "google/protobuf/empty.proto";
+const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php";
+const std::string kDescriptorMetadataFile =
+    "GPBMetadata/Google/Protobuf/Internal/Descriptor.php";
+const std::string kDescriptorDirName = "Google/Protobuf/Internal";
+const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
+const char* const kReservedNames[] = {
+    "abstract",     "and",        "array",        "as",         "break",
+    "callable",     "case",       "catch",        "class",      "clone",
+    "const",        "continue",   "declare",      "default",    "die",
+    "do",           "echo",       "else",         "elseif",     "empty",
+    "enddeclare",   "endfor",     "endforeach",   "endif",      "endswitch",
+    "endwhile",     "eval",       "exit",         "extends",    "final",
+    "finally",      "fn",         "for",          "foreach",    "function",
+    "global",       "goto",       "if",           "implements", "include",
+    "include_once", "instanceof", "insteadof",    "interface",  "isset",
+    "list",         "match",      "namespace",    "new",        "or",
+    "parent",       "print",      "private",      "protected",  "public",
+    "readonly",     "require",    "require_once", "return",     "self",
+    "static",       "switch",     "throw",        "trait",      "try",
+    "unset",        "use",        "var",          "while",      "xor",
+    "yield",        "int",        "float",        "bool",       "string",
+    "true",         "false",      "null",         "void",       "iterable"};
+const char* const kValidConstantNames[] = {
+    "int",   "float", "bool", "string",   "true",
+    "false", "null",  "void", "iterable", "parent",
+    "self", "readonly"
+};
+const int kReservedNamesSize = 80;
+const int kValidConstantNamesSize = 12;
+const int kFieldSetter = 1;
+const int kFieldGetter = 2;
+const int kFieldProperty = 3;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace php {
+
+struct Options {
+  bool is_descriptor = false;
+  bool aggregate_metadata = false;
+  bool gen_c_wkt = false;
+  std::set<std::string> aggregate_metadata_prefixes;
+};
+
+namespace {
+
+// Forward decls.
+std::string PhpName(const std::string& full_name, const Options& options);
+std::string IntToString(int32_t value);
+std::string FilenameToClassname(const std::string& filename);
+std::string GeneratedMetadataFileName(const FileDescriptor* file,
+                                      const Options& options);
+std::string UnderscoresToCamelCase(const std::string& name,
+                                   bool cap_first_letter);
+void Indent(io::Printer* printer);
+void Outdent(io::Printer* printer);
+void GenerateAddFilesToPool(const FileDescriptor* file, const Options& options,
+                            io::Printer* printer);
+void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message,
+                               const Options& options);
+void GenerateMessageConstructorDocComment(io::Printer* printer,
+                                          const Descriptor* message,
+                                          const Options& options);
+void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
+                             const Options& options, int function_type);
+void GenerateWrapperFieldGetterDocComment(io::Printer* printer,
+                                          const FieldDescriptor* field);
+void GenerateWrapperFieldSetterDocComment(io::Printer* printer,
+                                          const FieldDescriptor* field);
+void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
+                            const Options& options);
+void GenerateEnumValueDocComment(io::Printer* printer,
+                                 const EnumValueDescriptor* value);
+void GenerateServiceDocComment(io::Printer* printer,
+                               const ServiceDescriptor* service);
+void GenerateServiceMethodDocComment(io::Printer* printer,
+                              const MethodDescriptor* method);
+
+std::string ReservedNamePrefix(const std::string& classname,
+                                const FileDescriptor* file) {
+  bool is_reserved = false;
+
+  std::string lower = classname;
+  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+
+  for (int i = 0; i < kReservedNamesSize; i++) {
+    if (lower == kReservedNames[i]) {
+      is_reserved = true;
+      break;
+    }
+  }
+
+  if (is_reserved) {
+    if (file->package() == "google.protobuf") {
+      return "GPB";
+    } else {
+      return "PB";
+    }
+  }
+
+  return "";
+}
+
+template <typename DescriptorType>
+std::string DescriptorFullName(const DescriptorType* desc, bool is_internal) {
+  if (is_internal) {
+    return StringReplace(desc->full_name(),
+                         "google.protobuf",
+                         "google.protobuf.internal", false);
+  } else {
+    return desc->full_name();
+  }
+}
+
+template <typename DescriptorType>
+std::string ClassNamePrefix(const std::string& classname,
+                            const DescriptorType* desc) {
+  const std::string& prefix = (desc->file()->options()).php_class_prefix();
+  if (!prefix.empty()) {
+    return prefix;
+  }
+
+  return ReservedNamePrefix(classname, desc->file());
+}
+
+template <typename DescriptorType>
+std::string GeneratedClassNameImpl(const DescriptorType* desc) {
+  std::string classname = ClassNamePrefix(desc->name(), desc) + desc->name();
+  const Descriptor* containing = desc->containing_type();
+  while (containing != NULL) {
+    classname = ClassNamePrefix(containing->name(), desc) + containing->name()
+       + '\\' + classname;
+    containing = containing->containing_type();
+  }
+  return classname;
+}
+
+std::string GeneratedClassNameImpl(const ServiceDescriptor* desc) {
+  std::string classname = desc->name();
+  return ClassNamePrefix(classname, desc) + classname;
+}
+
+template <typename DescriptorType>
+std::string LegacyGeneratedClassName(const DescriptorType* desc) {
+  std::string classname = desc->name();
+  const Descriptor* containing = desc->containing_type();
+  while (containing != NULL) {
+    classname = containing->name() + '_' + classname;
+    containing = containing->containing_type();
+  }
+  return ClassNamePrefix(classname, desc) + classname;
+}
+
+std::string ClassNamePrefix(const std::string& classname) {
+  std::string lower = classname;
+  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+
+  for (int i = 0; i < kReservedNamesSize; i++) {
+    if (lower == kReservedNames[i]) {
+      return "PB";
+    }
+  }
+
+  return "";
+}
+
+std::string ConstantNamePrefix(const std::string& classname) {
+  bool is_reserved = false;
+
+  std::string lower = classname;
+  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+
+  for (int i = 0; i < kReservedNamesSize; i++) {
+    if (lower == kReservedNames[i]) {
+      is_reserved = true;
+      break;
+    }
+  }
+
+  for (int i = 0; i < kValidConstantNamesSize; i++) {
+    if (lower == kValidConstantNames[i]) {
+      is_reserved = false;
+      break;
+    }
+  }
+
+  if (is_reserved) {
+    return "PB";
+  }
+
+  return "";
+}
+
+template <typename DescriptorType>
+std::string RootPhpNamespace(const DescriptorType* desc,
+                             const Options& options) {
+  if (desc->file()->options().has_php_namespace()) {
+    const std::string& php_namespace = desc->file()->options().php_namespace();
+    if (!php_namespace.empty()) {
+      return php_namespace;
+    }
+    return "";
+  }
+
+  if (!desc->file()->package().empty()) {
+    return PhpName(desc->file()->package(), options);
+  }
+  return "";
+}
+
+template <typename DescriptorType>
+std::string FullClassName(const DescriptorType* desc, const Options& options) {
+  std::string classname = GeneratedClassNameImpl(desc);
+  std::string php_namespace = RootPhpNamespace(desc, options);
+  if (!php_namespace.empty()) {
+    return php_namespace + "\\" + classname;
+  }
+  return classname;
+}
+
+template <typename DescriptorType>
+std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
+  Options options;
+  options.is_descriptor = is_descriptor;
+  return FullClassName(desc, options);
+}
+
+template <typename DescriptorType>
+std::string LegacyFullClassName(const DescriptorType* desc,
+                                const Options& options) {
+  std::string classname = LegacyGeneratedClassName(desc);
+  std::string php_namespace = RootPhpNamespace(desc, options);
+  if (!php_namespace.empty()) {
+    return php_namespace + "\\" + classname;
+  }
+  return classname;
+}
+
+std::string PhpName(const std::string& full_name, const Options& options) {
+  if (options.is_descriptor) {
+    return kDescriptorPackageName;
+  }
+
+  std::string segment;
+  std::string result;
+  bool cap_next_letter = true;
+  for (int i = 0; i < full_name.size(); i++) {
+    if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) {
+      segment += full_name[i] + ('A' - 'a');
+      cap_next_letter = false;
+    } else if (full_name[i] == '.') {
+      result += ClassNamePrefix(segment) + segment + '\\';
+      segment = "";
+      cap_next_letter = true;
+    } else {
+      segment += full_name[i];
+      cap_next_letter = false;
+    }
+  }
+  result += ClassNamePrefix(segment) + segment;
+  return result;
+}
+
+std::string DefaultForField(const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_ENUM: return "0";
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT: return "0.0";
+    case FieldDescriptor::TYPE_BOOL: return "false";
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES: return "''";
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP: return "null";
+    default: assert(false); return "";
+  }
+}
+
+std::string GeneratedMetadataFileName(const FileDescriptor* file,
+                                      const Options& options) {
+  const std::string& proto_file = file->name();
+  int start_index = 0;
+  int first_index = proto_file.find_first_of("/", start_index);
+  std::string result = "";
+  std::string segment = "";
+
+  if (proto_file == kEmptyFile) {
+    return kEmptyMetadataFile;
+  }
+  if (options.is_descriptor) {
+    return kDescriptorMetadataFile;
+  }
+
+  // Append directory name.
+  std::string file_no_suffix;
+  int lastindex = proto_file.find_last_of(".");
+  if (proto_file == kEmptyFile) {
+    return kEmptyMetadataFile;
+  } else {
+    file_no_suffix = proto_file.substr(0, lastindex);
+  }
+
+  if (file->options().has_php_metadata_namespace()) {
+    const std::string& php_metadata_namespace =
+        file->options().php_metadata_namespace();
+    if (!php_metadata_namespace.empty() && php_metadata_namespace != "\\") {
+      result += php_metadata_namespace;
+      std::replace(result.begin(), result.end(), '\\', '/');
+      if (result.at(result.size() - 1) != '/') {
+        result += "/";
+      }
+    }
+  } else {
+    result += "GPBMetadata/";
+    while (first_index != std::string::npos) {
+      segment = UnderscoresToCamelCase(
+          file_no_suffix.substr(start_index, first_index - start_index), true);
+      result += ReservedNamePrefix(segment, file) + segment + "/";
+      start_index = first_index + 1;
+      first_index = file_no_suffix.find_first_of("/", start_index);
+    }
+  }
+
+  // Append file name.
+  int file_name_start = file_no_suffix.find_last_of("/");
+  if (file_name_start == std::string::npos) {
+    file_name_start = 0;
+  } else {
+    file_name_start += 1;
+  }
+  segment = UnderscoresToCamelCase(
+      file_no_suffix.substr(file_name_start, first_index - file_name_start), true);
+
+  return result + ReservedNamePrefix(segment, file) + segment + ".php";
+}
+
+std::string GeneratedMetadataFileName(const FileDescriptor* file,
+                                      bool is_descriptor) {
+  Options options;
+  options.is_descriptor = is_descriptor;
+  return GeneratedMetadataFileName(file, options);
+}
+
+template <typename DescriptorType>
+std::string GeneratedClassFileName(const DescriptorType* desc,
+                                   const Options& options) {
+  std::string result = FullClassName(desc, options);
+  for (int i = 0; i < result.size(); i++) {
+    if (result[i] == '\\') {
+      result[i] = '/';
+    }
+  }
+  return result + ".php";
+}
+
+template <typename DescriptorType>
+std::string LegacyGeneratedClassFileName(const DescriptorType* desc,
+                                         const Options& options) {
+  std::string result = LegacyFullClassName(desc, options);
+
+  for (int i = 0; i < result.size(); i++) {
+    if (result[i] == '\\') {
+      result[i] = '/';
+    }
+  }
+  return result + ".php";
+}
+
+template <typename DescriptorType>
+std::string LegacyReadOnlyGeneratedClassFileName(std::string php_namespace,
+                                                 const DescriptorType* desc) {
+  if (!php_namespace.empty()) {
+    for (int i = 0; i < php_namespace.size(); i++) {
+      if (php_namespace[i] == '\\') {
+        php_namespace[i] = '/';
+      }
+    }
+    return php_namespace + "/" + desc->name() + ".php";
+  }
+
+  return desc->name() + ".php";
+}
+
+std::string GeneratedServiceFileName(const ServiceDescriptor* service,
+                                     const Options& options) {
+  std::string result = FullClassName(service, options) + "Interface";
+  for (int i = 0; i < result.size(); i++) {
+    if (result[i] == '\\') {
+      result[i] = '/';
+    }
+  }
+  return result + ".php";
+}
+
+std::string IntToString(int32_t value) {
+  std::ostringstream os;
+  os << value;
+  return os.str();
+}
+
+std::string LabelForField(const FieldDescriptor* field) {
+  switch (field->label()) {
+    case FieldDescriptor::LABEL_OPTIONAL: return "optional";
+    case FieldDescriptor::LABEL_REQUIRED: return "required";
+    case FieldDescriptor::LABEL_REPEATED: return "repeated";
+    default: assert(false); return "";
+  }
+}
+
+std::string PhpSetterTypeName(const FieldDescriptor* field,
+                              const Options& options) {
+  if (field->is_map()) {
+    return "array|\\Google\\Protobuf\\Internal\\MapField";
+  }
+  std::string type;
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_ENUM:
+      type = "int";
+      break;
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+      type = "int|string";
+      break;
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT:
+      type = "float";
+      break;
+    case FieldDescriptor::TYPE_BOOL:
+      type = "bool";
+      break;
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      type = "string";
+      break;
+    case FieldDescriptor::TYPE_MESSAGE:
+      type = "\\" + FullClassName(field->message_type(), options);
+      break;
+    case FieldDescriptor::TYPE_GROUP:
+      return "null";
+    default: assert(false); return "";
+  }
+  if (field->is_repeated()) {
+    // accommodate for edge case with multiple types.
+    size_t start_pos = type.find("|");
+    if (start_pos != std::string::npos) {
+      type.replace(start_pos, 1, ">|array<");
+    }
+    type = "array<" + type + ">|\\Google\\Protobuf\\Internal\\RepeatedField";
+  }
+  return type;
+}
+
+std::string PhpSetterTypeName(const FieldDescriptor* field,
+                              bool is_descriptor) {
+  Options options;
+  options.is_descriptor = is_descriptor;
+  return PhpSetterTypeName(field, options);
+}
+
+std::string PhpGetterTypeName(const FieldDescriptor* field,
+                              const Options& options) {
+  if (field->is_map()) {
+    return "\\Google\\Protobuf\\Internal\\MapField";
+  }
+  if (field->is_repeated()) {
+    return "\\Google\\Protobuf\\Internal\\RepeatedField";
+  }
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_ENUM: return "int";
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64: return "int|string";
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT: return "float";
+    case FieldDescriptor::TYPE_BOOL: return "bool";
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES: return "string";
+    case FieldDescriptor::TYPE_MESSAGE:
+      return "\\" + FullClassName(field->message_type(), options);
+    case FieldDescriptor::TYPE_GROUP: return "null";
+    default: assert(false); return "";
+  }
+}
+
+std::string PhpGetterTypeName(const FieldDescriptor* field,
+                              bool is_descriptor) {
+  Options options;
+  options.is_descriptor = is_descriptor;
+  return PhpGetterTypeName(field, options);
+}
+
+std::string EnumOrMessageSuffix(const FieldDescriptor* field,
+                                const Options& options) {
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    return ", '" +
+           DescriptorFullName(field->message_type(), options.is_descriptor) +
+           "'";
+  }
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+    return ", '" +
+           DescriptorFullName(field->enum_type(), options.is_descriptor) + "'";
+  }
+  return "";
+}
+
+std::string EnumOrMessageSuffix(const FieldDescriptor* field,
+                                bool is_descriptor) {
+  Options options;
+  options.is_descriptor = is_descriptor;
+  return EnumOrMessageSuffix(field, options);
+}
+
+// Converts a name to camel-case. If cap_first_letter is true, capitalize the
+// first letter.
+std::string UnderscoresToCamelCase(const std::string& name,
+                                   bool cap_first_letter) {
+  std::string result;
+  for (int i = 0; i < name.size(); i++) {
+    if ('a' <= name[i] && name[i] <= 'z') {
+      if (cap_first_letter) {
+        result += name[i] + ('A' - 'a');
+      } else {
+        result += name[i];
+      }
+      cap_first_letter = false;
+    } else if ('A' <= name[i] && name[i] <= 'Z') {
+      if (i == 0 && !cap_first_letter) {
+        // Force first letter to lower-case unless explicitly told to
+        // capitalize it.
+        result += name[i] + ('a' - 'A');
+      } else {
+        // Capital letters after the first are left as-is.
+        result += name[i];
+      }
+      cap_first_letter = false;
+    } else if ('0' <= name[i] && name[i] <= '9') {
+      result += name[i];
+      cap_first_letter = true;
+    } else {
+      cap_first_letter = true;
+    }
+  }
+  // Add a trailing "_" if the name should be altered.
+  if (name[name.size() - 1] == '#') {
+    result += '_';
+  }
+  return result;
+}
+
+void Indent(io::Printer* printer) {
+  printer->Indent();
+  printer->Indent();
+}
+void Outdent(io::Printer* printer) {
+  printer->Outdent();
+  printer->Outdent();
+}
+
+void GenerateField(const FieldDescriptor* field, io::Printer* printer,
+                   const Options& options) {
+  if (field->is_repeated()) {
+    GenerateFieldDocComment(printer, field, options, kFieldProperty);
+    printer->Print(
+        "private $^name^;\n",
+        "name", field->name());
+  } else if (field->real_containing_oneof()) {
+    // Oneof fields are handled by GenerateOneofField.
+    return;
+  } else {
+    std::string initial_value =
+        field->has_presence() ? "null" : DefaultForField(field);
+    GenerateFieldDocComment(printer, field, options, kFieldProperty);
+    printer->Print(
+        "protected $^name^ = ^initial_value^;\n",
+        "name", field->name(),
+        "initial_value", initial_value);
+  }
+}
+
+void GenerateOneofField(const OneofDescriptor* oneof, io::Printer* printer) {
+  // Oneof property needs to be protected in order to be accessed by parent
+  // class in implementation.
+  printer->Print(
+      "protected $^name^;\n",
+      "name", oneof->name());
+}
+
+void GenerateFieldAccessor(const FieldDescriptor* field, const Options& options,
+                           io::Printer* printer) {
+  const OneofDescriptor* oneof = field->real_containing_oneof();
+
+  // Generate getter.
+  GenerateFieldDocComment(printer, field, options, kFieldGetter);
+
+  // deprecation
+  std::string deprecation_trigger = (field->options().deprecated()) ? "@trigger_error('" +
+      field->name() + " is deprecated.', E_USER_DEPRECATED);\n        " : "";
+
+  // Emit getter.
+  if (oneof != NULL) {
+    printer->Print(
+        "public function get^camel_name^()\n"
+        "{\n"
+        "    ^deprecation_trigger^return $this->readOneof(^number^);\n"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "number", IntToString(field->number()),
+        "deprecation_trigger", deprecation_trigger);
+  } else if (field->has_presence() && !field->message_type()) {
+    printer->Print(
+        "public function get^camel_name^()\n"
+        "{\n"
+        "    ^deprecation_trigger^return isset($this->^name^) ? $this->^name^ : ^default_value^;\n"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "name", field->name(),
+        "default_value", DefaultForField(field),
+        "deprecation_trigger", deprecation_trigger);
+  } else {
+    printer->Print(
+        "public function get^camel_name^()\n"
+        "{\n"
+        "    ^deprecation_trigger^return $this->^name^;\n"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "name", field->name(),
+        "deprecation_trigger", deprecation_trigger);
+  }
+
+  // Emit hazzers/clear.
+  if (oneof) {
+    printer->Print(
+        "public function has^camel_name^()\n"
+        "{\n"
+        "    ^deprecation_trigger^return $this->hasOneof(^number^);\n"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "number", IntToString(field->number()),
+        "deprecation_trigger", deprecation_trigger);
+  } else if (field->has_presence()) {
+    printer->Print(
+        "public function has^camel_name^()\n"
+        "{\n"
+        "    ^deprecation_trigger^return isset($this->^name^);\n"
+        "}\n\n"
+        "public function clear^camel_name^()\n"
+        "{\n"
+        "    ^deprecation_trigger^unset($this->^name^);\n"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "name", field->name(),
+        "default_value", DefaultForField(field),
+        "deprecation_trigger", deprecation_trigger);
+  }
+
+  // For wrapper types, generate an additional getXXXUnwrapped getter
+  if (!field->is_map() &&
+      !field->is_repeated() &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      IsWrapperType(field)) {
+    GenerateWrapperFieldGetterDocComment(printer, field);
+    printer->Print(
+        "public function get^camel_name^Unwrapped()\n"
+        "{\n"
+        "    ^deprecation_trigger^return $this->readWrapperValue(\"^field_name^\");\n"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "field_name", field->name(),
+        "deprecation_trigger", deprecation_trigger);
+  }
+
+  // Generate setter.
+  GenerateFieldDocComment(printer, field, options, kFieldSetter);
+  printer->Print(
+      "public function set^camel_name^($var)\n"
+      "{\n",
+      "camel_name", UnderscoresToCamelCase(field->name(), true));
+
+  Indent(printer);
+
+  if (field->options().deprecated()) {
+      printer->Print(
+          "^deprecation_trigger^",
+          "deprecation_trigger", deprecation_trigger
+      );
+  }
+
+  // Type check.
+  if (field->is_map()) {
+    const Descriptor* map_entry = field->message_type();
+    const FieldDescriptor* key = map_entry->map_key();
+    const FieldDescriptor* value = map_entry->map_value();
+    printer->Print(
+        "$arr = GPBUtil::checkMapField($var, "
+        "\\Google\\Protobuf\\Internal\\GPBType::^key_type^, "
+        "\\Google\\Protobuf\\Internal\\GPBType::^value_type^",
+        "key_type", ToUpper(key->type_name()),
+        "value_type", ToUpper(value->type_name()));
+    if (value->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+          ", \\^class_name^);\n",
+          "class_name",
+          FullClassName(value->message_type(), options) + "::class");
+    } else if (value->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      printer->Print(
+          ", \\^class_name^);\n",
+          "class_name",
+          FullClassName(value->enum_type(), options) + "::class");
+    } else {
+      printer->Print(");\n");
+    }
+  } else if (field->is_repeated()) {
+    printer->Print(
+        "$arr = GPBUtil::checkRepeatedField($var, "
+        "\\Google\\Protobuf\\Internal\\GPBType::^type^",
+        "type", ToUpper(field->type_name()));
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+          ", \\^class_name^);\n",
+          "class_name",
+          FullClassName(field->message_type(), options) + "::class");
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      printer->Print(
+          ", \\^class_name^);\n",
+          "class_name",
+          FullClassName(field->enum_type(), options) + "::class");
+    } else {
+      printer->Print(");\n");
+    }
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        "GPBUtil::checkMessage($var, \\^class_name^::class);\n",
+        "class_name", FullClassName(field->message_type(), options));
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+    printer->Print(
+        "GPBUtil::checkEnum($var, \\^class_name^::class);\n",
+        "class_name", FullClassName(field->enum_type(), options));
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+    printer->Print(
+        "GPBUtil::checkString($var, ^utf8^);\n",
+        "utf8",
+        field->type() == FieldDescriptor::TYPE_STRING ? "True": "False");
+  } else {
+    printer->Print(
+        "GPBUtil::check^type^($var);\n",
+        "type", UnderscoresToCamelCase(field->cpp_type_name(), true));
+  }
+
+  if (oneof != NULL) {
+    printer->Print(
+        "$this->writeOneof(^number^, $var);\n",
+        "number", IntToString(field->number()));
+  } else if (field->is_repeated()) {
+    printer->Print(
+        "$this->^name^ = $arr;\n",
+        "name", field->name());
+  } else {
+    printer->Print(
+        "$this->^name^ = $var;\n",
+        "name", field->name());
+  }
+
+  printer->Print("\nreturn $this;\n");
+
+  Outdent(printer);
+
+  printer->Print(
+      "}\n\n");
+
+  // For wrapper types, generate an additional setXXXValue getter
+  if (!field->is_map() &&
+      !field->is_repeated() &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      IsWrapperType(field)) {
+    GenerateWrapperFieldSetterDocComment(printer, field);
+    printer->Print(
+        "public function set^camel_name^Unwrapped($var)\n"
+        "{\n"
+        "    $this->writeWrapperValue(\"^field_name^\", $var);\n"
+        "    return $this;"
+        "}\n\n",
+        "camel_name", UnderscoresToCamelCase(field->name(), true),
+        "field_name", field->name());
+  }
+}
+
+void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) {
+  printer->Print(
+      "$pool->addEnum('^name^', "
+      "\\Google\\Protobuf\\Internal\\^class_name^::class)\n",
+      "name", DescriptorFullName(en, true),
+      "class_name", en->name());
+  Indent(printer);
+
+  for (int i = 0; i < en->value_count(); i++) {
+    const EnumValueDescriptor* value = en->value(i);
+    printer->Print(
+        "->value(\"^name^\", ^number^)\n",
+        "name", ConstantNamePrefix(value->name()) + value->name(),
+        "number", IntToString(value->number()));
+  }
+  printer->Print("->finalizeToPool();\n\n");
+  Outdent(printer);
+}
+
+void GenerateServiceMethod(const MethodDescriptor* method,
+                           io::Printer* printer) {
+  printer->Print(
+        "public function ^camel_name^(\\^request_name^ $request);\n\n",
+        "camel_name", UnderscoresToCamelCase(method->name(), false),
+        "request_name", FullClassName(
+          method->input_type(), false)
+  );
+}
+
+void GenerateMessageToPool(const std::string& name_prefix,
+                           const Descriptor* message, io::Printer* printer) {
+  // Don't generate MapEntry messages -- we use the PHP extension's native
+  // support for map fields instead.
+  if (message->options().map_entry()) {
+    return;
+  }
+  std::string class_name =
+      (name_prefix.empty() ? "" : name_prefix + "\\") +
+      ReservedNamePrefix(message->name(), message->file()) + message->name();
+
+  printer->Print(
+      "$pool->addMessage('^message^', "
+      "\\Google\\Protobuf\\Internal\\^class_name^::class)\n",
+      "message", DescriptorFullName(message, true),
+      "class_name", class_name);
+
+  Indent(printer);
+
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    if (field->is_map()) {
+      const FieldDescriptor* key =
+          field->message_type()->map_key();
+      const FieldDescriptor* val =
+          field->message_type()->map_value();
+      printer->Print(
+          "->map('^field^', \\Google\\Protobuf\\Internal\\GPBType::^key^, "
+          "\\Google\\Protobuf\\Internal\\GPBType::^value^, ^number^^other^)\n",
+          "field", field->name(),
+          "key", ToUpper(key->type_name()),
+          "value", ToUpper(val->type_name()),
+          "number", StrCat(field->number()),
+          "other", EnumOrMessageSuffix(val, true));
+    } else if (!field->real_containing_oneof()) {
+      printer->Print(
+          "->^label^('^field^', "
+          "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n",
+          "field", field->name(),
+          "label", LabelForField(field),
+          "type", ToUpper(field->type_name()),
+          "number", StrCat(field->number()),
+          "other", EnumOrMessageSuffix(field, true));
+    }
+  }
+
+  // oneofs.
+  for (int i = 0; i < message->real_oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    printer->Print("->oneof(^name^)\n",
+                   "name", oneof->name());
+    Indent(printer);
+    for (int index = 0; index < oneof->field_count(); index++) {
+      const FieldDescriptor* field = oneof->field(index);
+      printer->Print(
+          "->value('^field^', "
+          "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n",
+          "field", field->name(),
+          "type", ToUpper(field->type_name()),
+          "number", StrCat(field->number()),
+          "other", EnumOrMessageSuffix(field, true));
+    }
+    printer->Print("->finish()\n");
+    Outdent(printer);
+  }
+
+  printer->Print(
+      "->finalizeToPool();\n");
+
+  Outdent(printer);
+
+  printer->Print(
+      "\n");
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateMessageToPool(class_name, message->nested_type(i), printer);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnumToPool(message->enum_type(i), printer);
+  }
+}
+
+void GenerateAddFileToPool(const FileDescriptor* file, const Options& options,
+                           io::Printer* printer) {
+  printer->Print(
+      "public static $is_initialized = false;\n\n"
+      "public static function initOnce() {\n");
+  Indent(printer);
+
+  if (options.aggregate_metadata) {
+    GenerateAddFilesToPool(file, options, printer);
+  } else {
+    printer->Print(
+        "$pool = \\Google\\Protobuf\\Internal\\"
+        "DescriptorPool::getGeneratedPool();\n\n"
+        "if (static::$is_initialized == true) {\n"
+        "  return;\n"
+        "}\n");
+
+    if (options.is_descriptor) {
+      for (int i = 0; i < file->message_type_count(); i++) {
+        GenerateMessageToPool("", file->message_type(i), printer);
+      }
+      for (int i = 0; i < file->enum_type_count(); i++) {
+        GenerateEnumToPool(file->enum_type(i), printer);
+      }
+
+      printer->Print(
+          "$pool->finish();\n");
+    } else {
+      for (int i = 0; i < file->dependency_count(); i++) {
+        const std::string& name = file->dependency(i)->name();
+        // Currently, descriptor.proto is not ready for external usage. Skip to
+        // import it for now, so that its dependencies can still work as long as
+        // they don't use protos defined in descriptor.proto.
+        if (name == kDescriptorFile) {
+          continue;
+        }
+        std::string dependency_filename =
+            GeneratedMetadataFileName(file->dependency(i), options);
+        printer->Print(
+            "\\^name^::initOnce();\n",
+            "name", FilenameToClassname(dependency_filename));
+      }
+
+      // Add messages and enums to descriptor pool.
+      FileDescriptorSet files;
+      FileDescriptorProto* file_proto = files.add_file();
+      file->CopyTo(file_proto);
+
+      // Filter out descriptor.proto as it cannot be depended on for now.
+      RepeatedPtrField<std::string>* dependency =
+          file_proto->mutable_dependency();
+      for (RepeatedPtrField<std::string>::iterator it = dependency->begin();
+           it != dependency->end(); ++it) {
+        if (*it != kDescriptorFile) {
+          dependency->erase(it);
+          break;
+        }
+      }
+
+      // Filter out all extensions, since we do not support extension yet.
+      file_proto->clear_extension();
+      RepeatedPtrField<DescriptorProto>* message_type =
+          file_proto->mutable_message_type();
+      for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin();
+           it != message_type->end(); ++it) {
+        it->clear_extension();
+      }
+
+      std::string files_data;
+      files.SerializeToString(&files_data);
+
+      printer->Print("$pool->internalAddGeneratedFile(\n");
+      Indent(printer);
+      printer->Print("'");
+
+      for (auto ch : files_data) {
+        switch (ch) {
+          case '\\':
+            printer->Print(R"(\\)");
+            break;
+          case '\'':
+            printer->Print(R"(\')");
+            break;
+          default:
+            printer->Print("^char^", "char", std::string(1, ch));
+            break;
+        }
+      }
+
+      printer->Print("'\n");
+      Outdent(printer);
+      printer->Print(
+          ", true);\n\n");
+    }
+    printer->Print(
+        "static::$is_initialized = true;\n");
+  }
+
+  Outdent(printer);
+  printer->Print("}\n");
+}
+
+static void AnalyzeDependencyForFile(
+    const FileDescriptor* file,
+    std::set<const FileDescriptor*>* nodes_without_dependency,
+    std::map<const FileDescriptor*, std::set<const FileDescriptor*>>* deps,
+    std::map<const FileDescriptor*, int>* dependency_count) {
+  int count = file->dependency_count();
+  for (int i = 0; i < file->dependency_count(); i++) {
+      const FileDescriptor* dependency = file->dependency(i);
+      if (dependency->name() == kDescriptorFile) {
+        count--;
+        break;
+      }
+  }
+
+  if (count == 0) {
+    nodes_without_dependency->insert(file);
+  } else {
+    (*dependency_count)[file] = count;
+    for (int i = 0; i < file->dependency_count(); i++) {
+      const FileDescriptor* dependency = file->dependency(i);
+      if (dependency->name() == kDescriptorFile) {
+        continue;
+      }
+      if (deps->find(dependency) == deps->end()) {
+        (*deps)[dependency] = std::set<const FileDescriptor*>();
+      }
+      (*deps)[dependency].insert(file);
+      AnalyzeDependencyForFile(
+          dependency, nodes_without_dependency, deps, dependency_count);
+    }
+  }
+}
+
+static bool NeedsUnwrapping(const FileDescriptor* file,
+                            const Options& options) {
+  bool has_aggregate_metadata_prefix = false;
+  if (options.aggregate_metadata_prefixes.empty()) {
+    has_aggregate_metadata_prefix = true;
+  } else {
+    for (const auto& prefix : options.aggregate_metadata_prefixes) {
+      if (HasPrefixString(file->package(), prefix)) {
+        has_aggregate_metadata_prefix = true;
+        break;
+      }
+    }
+  }
+
+  return has_aggregate_metadata_prefix;
+}
+
+void GenerateAddFilesToPool(const FileDescriptor* file, const Options& options,
+                            io::Printer* printer) {
+  printer->Print(
+      "$pool = \\Google\\Protobuf\\Internal\\"
+      "DescriptorPool::getGeneratedPool();\n"
+      "if (static::$is_initialized == true) {\n"
+      "  return;\n"
+      "}\n");
+
+  // Sort files according to dependency
+  std::map<const FileDescriptor*, std::set<const FileDescriptor*>> deps;
+  std::map<const FileDescriptor*, int> dependency_count;
+  std::set<const FileDescriptor*> nodes_without_dependency;
+  FileDescriptorSet sorted_file_set;
+
+  AnalyzeDependencyForFile(
+      file, &nodes_without_dependency, &deps, &dependency_count);
+
+  while (!nodes_without_dependency.empty()) {
+    auto file_node = *nodes_without_dependency.begin();
+    nodes_without_dependency.erase(file_node);
+    for (auto dependent : deps[file_node]) {
+      if (dependency_count[dependent] == 1) {
+        dependency_count.erase(dependent);
+        nodes_without_dependency.insert(dependent);
+      } else {
+        dependency_count[dependent] -= 1;
+      }
+    }
+
+    bool needs_aggregate = NeedsUnwrapping(file_node, options);
+
+    if (needs_aggregate) {
+      auto file_proto = sorted_file_set.add_file();
+      file_node->CopyTo(file_proto);
+
+      // Filter out descriptor.proto as it cannot be depended on for now.
+      RepeatedPtrField<std::string>* dependency =
+          file_proto->mutable_dependency();
+      for (RepeatedPtrField<std::string>::iterator it = dependency->begin();
+           it != dependency->end(); ++it) {
+        if (*it != kDescriptorFile) {
+          dependency->erase(it);
+          break;
+        }
+      }
+
+      // Filter out all extensions, since we do not support extension yet.
+      file_proto->clear_extension();
+      RepeatedPtrField<DescriptorProto>* message_type =
+          file_proto->mutable_message_type();
+      for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin();
+           it != message_type->end(); ++it) {
+        it->clear_extension();
+      }
+    } else {
+      std::string dependency_filename = GeneratedMetadataFileName(file_node, false);
+      printer->Print(
+          "\\^name^::initOnce();\n",
+          "name", FilenameToClassname(dependency_filename));
+    }
+  }
+
+  std::string files_data;
+  sorted_file_set.SerializeToString(&files_data);
+
+  printer->Print("$pool->internalAddGeneratedFile(\n");
+  Indent(printer);
+  printer->Print("'");
+
+  for (auto ch : files_data) {
+    switch (ch) {
+      case '\\':
+        printer->Print(R"(\\)");
+        break;
+      case '\'':
+        printer->Print(R"(\')");
+        break;
+      default:
+        printer->Print("^char^", "char", std::string(1, ch));
+        break;
+    }
+  }
+
+  printer->Print("'\n");
+  Outdent(printer);
+  printer->Print(
+      ", true);\n");
+
+  printer->Print(
+      "static::$is_initialized = true;\n");
+}
+
+void GenerateUseDeclaration(const Options& options, io::Printer* printer) {
+  if (!options.is_descriptor) {
+    printer->Print(
+        "use Google\\Protobuf\\Internal\\GPBType;\n"
+        "use Google\\Protobuf\\Internal\\RepeatedField;\n"
+        "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
+  } else {
+    printer->Print(
+        "use Google\\Protobuf\\Internal\\GPBType;\n"
+        "use Google\\Protobuf\\Internal\\GPBWire;\n"
+        "use Google\\Protobuf\\Internal\\RepeatedField;\n"
+        "use Google\\Protobuf\\Internal\\InputStream;\n"
+        "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
+  }
+}
+
+void GenerateHead(const FileDescriptor* file, io::Printer* printer) {
+  printer->Print(
+    "<?php\n"
+    "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "# source: ^filename^\n"
+    "\n",
+    "filename", file->name());
+}
+
+std::string FilenameToClassname(const std::string& filename) {
+  int lastindex = filename.find_last_of(".");
+  std::string result = filename.substr(0, lastindex);
+  for (int i = 0; i < result.size(); i++) {
+    if (result[i] == '/') {
+      result[i] = '\\';
+    }
+  }
+  return result;
+}
+
+void GenerateMetadataFile(const FileDescriptor* file, const Options& options,
+                          GeneratorContext* generator_context) {
+  std::string filename = GeneratedMetadataFileName(file, options);
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  std::string fullname = FilenameToClassname(filename);
+  int lastindex = fullname.find_last_of("\\");
+
+  if (lastindex != std::string::npos) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", fullname.substr(0, lastindex));
+
+    printer.Print(
+        "class ^name^\n"
+        "{\n",
+        "name", fullname.substr(lastindex + 1));
+  } else {
+    printer.Print(
+        "class ^name^\n"
+        "{\n",
+        "name", fullname);
+  }
+  Indent(&printer);
+
+  GenerateAddFileToPool(file, options, &printer);
+
+  Outdent(&printer);
+  printer.Print("}\n\n");
+}
+
+template <typename DescriptorType>
+void LegacyGenerateClassFile(const FileDescriptor* file,
+                             const DescriptorType* desc, const Options& options,
+                             GeneratorContext* generator_context) {
+  std::string filename = LegacyGeneratedClassFileName(desc, options);
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  std::string php_namespace = RootPhpNamespace(desc, options);
+  if (!php_namespace.empty()) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", php_namespace);
+  }
+  std::string newname = FullClassName(desc, options);
+  printer.Print("if (false) {\n");
+  Indent(&printer);
+  printer.Print("/**\n");
+  printer.Print(" * This class is deprecated. Use ^new^ instead.\n",
+      "new", newname);
+  printer.Print(" * @deprecated\n");
+  printer.Print(" */\n");
+  printer.Print("class ^old^ {}\n",
+      "old", LegacyGeneratedClassName(desc));
+  Outdent(&printer);
+  printer.Print("}\n");
+  printer.Print("class_exists(^new^::class);\n",
+      "new", GeneratedClassNameImpl(desc));
+  printer.Print("@trigger_error('^old^ is deprecated and will be removed in "
+      "the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
+      "old", LegacyFullClassName(desc, options),
+      "fullname", newname);
+}
+
+template <typename DescriptorType>
+void LegacyReadOnlyGenerateClassFile(const FileDescriptor* file,
+                             const DescriptorType* desc, const Options& options,
+                             GeneratorContext* generator_context) {
+  std::string fullname = FullClassName(desc, options);
+  std::string php_namespace;
+  std::string classname;
+  int lastindex = fullname.find_last_of("\\");
+
+  if (lastindex != std::string::npos) {
+    php_namespace = fullname.substr(0, lastindex);
+    classname = fullname.substr(lastindex + 1);
+  } else {
+    php_namespace = "";
+    classname = fullname;
+  }
+
+  std::string filename = LegacyReadOnlyGeneratedClassFileName(php_namespace, desc);
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  if (!php_namespace.empty()) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", php_namespace);
+  }
+
+  printer.Print("class_exists(^new^::class); // autoload the new class, which "
+      "will also create an alias to the deprecated class\n",
+      "new", classname);
+  printer.Print("@trigger_error(__NAMESPACE__ . '\\^old^ is deprecated and will be removed in "
+      "the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
+      "old", desc->name(),
+      "fullname", classname);
+}
+
+void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
+                      const Options& options,
+                      GeneratorContext* generator_context) {
+  std::string filename = GeneratedClassFileName(en, options);
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  std::string fullname = FilenameToClassname(filename);
+  int lastindex = fullname.find_last_of("\\");
+
+  if (lastindex != std::string::npos) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", fullname.substr(0, lastindex));
+
+    // We only need this 'use' statement if the enum has a namespace.
+    // Otherwise, we get a warning that the use statement has no effect.
+    printer.Print("use UnexpectedValueException;\n\n");
+  }
+
+  GenerateEnumDocComment(&printer, en, options);
+
+  if (lastindex != std::string::npos) {
+    fullname = fullname.substr(lastindex + 1);
+  }
+
+  printer.Print(
+      "class ^name^\n"
+      "{\n",
+      "name", fullname);
+  Indent(&printer);
+
+  bool hasReserved = false;
+  for (int i = 0; i < en->value_count(); i++) {
+    const EnumValueDescriptor* value = en->value(i);
+    GenerateEnumValueDocComment(&printer, value);
+
+    std::string prefix = ConstantNamePrefix(value->name());
+    if (!prefix.empty()) {
+      hasReserved = true;
+    }
+
+    printer.Print("const ^name^ = ^number^;\n",
+                  "name", prefix + value->name(),
+                  "number", IntToString(value->number()));
+  }
+
+  printer.Print("\nprivate static $valueToName = [\n");
+  Indent(&printer);
+  for (int i = 0; i < en->value_count(); i++) {
+    const EnumValueDescriptor* value = en->value(i);
+    printer.Print("self::^constant^ => '^name^',\n",
+                  "constant", ConstantNamePrefix(value->name()) + value->name(),
+                  "name", value->name());
+  }
+  Outdent(&printer);
+  printer.Print("];\n");
+
+  printer.Print(
+      "\npublic static function name($value)\n"
+      "{\n");
+  Indent(&printer);
+  printer.Print("if (!isset(self::$valueToName[$value])) {\n");
+  Indent(&printer);
+  printer.Print("throw new UnexpectedValueException(sprintf(\n");
+  Indent(&printer);
+  Indent(&printer);
+  printer.Print("'Enum %s has no name defined for value %s', __CLASS__, $value));\n");
+  Outdent(&printer);
+  Outdent(&printer);
+  Outdent(&printer);
+  printer.Print("}\n"
+                "return self::$valueToName[$value];\n");
+  Outdent(&printer);
+  printer.Print("}\n\n");
+
+  printer.Print(
+      "\npublic static function value($name)\n"
+      "{\n");
+  Indent(&printer);
+  printer.Print("$const = __CLASS__ . '::' . strtoupper($name);\n"
+                "if (!defined($const)) {\n");
+  Indent(&printer);
+  if (hasReserved) {
+    printer.Print("$pbconst =  __CLASS__. '::PB' . strtoupper($name);\n"
+                "if (!defined($pbconst)) {\n");
+    Indent(&printer);
+  }
+  printer.Print("throw new UnexpectedValueException(sprintf(\n");
+  Indent(&printer);
+  Indent(&printer);
+  printer.Print("'Enum %s has no value defined for name %s', __CLASS__, $name));\n");
+  Outdent(&printer);
+  Outdent(&printer);
+  if (hasReserved) {
+    Outdent(&printer);
+    printer.Print("}\n"
+                  "return constant($pbconst);\n");
+  }
+  Outdent(&printer);
+  printer.Print("}\n"
+                "return constant($const);\n");
+  Outdent(&printer);
+  printer.Print("}\n");
+
+  Outdent(&printer);
+  printer.Print("}\n\n");
+
+  // write legacy file for backwards compatibility with nested messages and enums
+  if (en->containing_type() != NULL) {
+    printer.Print(
+        "// Adding a class alias for backwards compatibility with the previous class name.\n");
+    printer.Print(
+        "class_alias(^new^::class, \\^old^::class);\n\n",
+        "new", fullname,
+        "old", LegacyFullClassName(en, options));
+    LegacyGenerateClassFile(file, en, options, generator_context);
+  }
+
+  // Write legacy file for backwards compatibility with "readonly" keywword
+  std::string lower = en->name();
+  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+  if (lower == "readonly") {
+    printer.Print(
+        "// Adding a class alias for backwards compatibility with the \"readonly\" keyword.\n");
+    printer.Print(
+        "class_alias(^new^::class, __NAMESPACE__ . '\\^old^');\n\n",
+        "new", fullname,
+        "old", en->name());
+    LegacyReadOnlyGenerateClassFile(file, en, options, generator_context);
+  }
+}
+
+void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
+                         const Options& options,
+                         GeneratorContext* generator_context) {
+  // Don't generate MapEntry messages -- we use the PHP extension's native
+  // support for map fields instead.
+  if (message->options().map_entry()) {
+    return;
+  }
+
+  std::string filename = GeneratedClassFileName(message, options);
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  std::string fullname = FilenameToClassname(filename);
+  int lastindex = fullname.find_last_of("\\");
+
+  if (lastindex != std::string::npos) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", fullname.substr(0, lastindex));
+  }
+
+  GenerateUseDeclaration(options, &printer);
+
+  GenerateMessageDocComment(&printer, message, options);
+  if (lastindex != std::string::npos) {
+    fullname = fullname.substr(lastindex + 1);
+  }
+
+  std::string base;
+
+  switch (message->well_known_type()) {
+    case Descriptor::WELLKNOWNTYPE_ANY:
+      base = "\\Google\\Protobuf\\Internal\\AnyBase";
+      break;
+    case Descriptor::WELLKNOWNTYPE_TIMESTAMP:
+      base = "\\Google\\Protobuf\\Internal\\TimestampBase";
+      break;
+    default:
+      base = "\\Google\\Protobuf\\Internal\\Message";
+      break;
+  }
+
+  printer.Print(
+      "class ^name^ extends ^base^\n"
+      "{\n",
+      "base", base,
+      "name", fullname);
+  Indent(&printer);
+
+  // Field and oneof definitions.
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    GenerateField(field, &printer, options);
+  }
+  for (int i = 0; i < message->real_oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    GenerateOneofField(oneof, &printer);
+  }
+  printer.Print("\n");
+
+  GenerateMessageConstructorDocComment(&printer, message, options);
+  printer.Print(
+      "public function __construct($data = NULL) {\n");
+  Indent(&printer);
+
+  std::string metadata_filename = GeneratedMetadataFileName(file, options);
+  std::string metadata_fullname = FilenameToClassname(metadata_filename);
+  printer.Print(
+      "\\^fullname^::initOnce();\n",
+      "fullname", metadata_fullname);
+
+  printer.Print(
+      "parent::__construct($data);\n");
+
+  Outdent(&printer);
+  printer.Print("}\n\n");
+
+  // Field and oneof accessors.
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    GenerateFieldAccessor(field, options, &printer);
+  }
+  for (int i = 0; i < message->real_oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    printer.Print(
+      "/**\n"
+      " * @return string\n"
+      " */\n"
+      "public function get^camel_name^()\n"
+      "{\n"
+      "    return $this->whichOneof(\"^name^\");\n"
+      "}\n\n",
+      "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name",
+      oneof->name());
+  }
+
+  Outdent(&printer);
+  printer.Print("}\n\n");
+
+  // write legacy file for backwards compatibility with nested messages and enums
+  if (message->containing_type() != NULL) {
+    printer.Print(
+        "// Adding a class alias for backwards compatibility with the previous class name.\n");
+    printer.Print(
+        "class_alias(^new^::class, \\^old^::class);\n\n",
+        "new", fullname,
+        "old", LegacyFullClassName(message, options));
+    LegacyGenerateClassFile(file, message, options, generator_context);
+  }
+
+  // Write legacy file for backwards compatibility with "readonly" keywword
+  std::string lower = message->name();
+  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+  if (lower == "readonly") {
+    printer.Print(
+        "// Adding a class alias for backwards compatibility with the \"readonly\" keyword.\n");
+    printer.Print(
+        "class_alias(^new^::class, __NAMESPACE__ . '\\^old^');\n\n",
+        "new", fullname,
+        "old", message->name());
+    LegacyReadOnlyGenerateClassFile(file, message, options, generator_context);
+  }
+
+  // Nested messages and enums.
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateMessageFile(file, message->nested_type(i), options,
+                        generator_context);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnumFile(file, message->enum_type(i), options, generator_context);
+  }
+}
+
+void GenerateServiceFile(
+    const FileDescriptor* file, const ServiceDescriptor* service,
+    const Options& options, GeneratorContext* generator_context) {
+  std::string filename = GeneratedServiceFileName(service, options);
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  std::string fullname = FilenameToClassname(filename);
+  int lastindex = fullname.find_last_of("\\");
+
+  if (!file->options().php_namespace().empty() ||
+      (!file->options().has_php_namespace() && !file->package().empty()) ||
+      lastindex != std::string::npos) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", fullname.substr(0, lastindex));
+  }
+
+  GenerateServiceDocComment(&printer, service);
+
+  if (lastindex != std::string::npos) {
+    printer.Print(
+        "interface ^name^\n"
+        "{\n",
+        "name", fullname.substr(lastindex + 1));
+  } else {
+    printer.Print(
+        "interface ^name^\n"
+        "{\n",
+        "name", fullname);
+  }
+
+  Indent(&printer);
+
+  for (int i = 0; i < service->method_count(); i++) {
+    const MethodDescriptor* method = service->method(i);
+    GenerateServiceMethodDocComment(&printer, method);
+    GenerateServiceMethod(method, &printer);
+  }
+
+  Outdent(&printer);
+  printer.Print("}\n\n");
+}
+
+void GenerateFile(const FileDescriptor* file, const Options& options,
+                  GeneratorContext* generator_context) {
+  GenerateMetadataFile(file, options, generator_context);
+
+  for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateMessageFile(file, file->message_type(i), options,
+                        generator_context);
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnumFile(file, file->enum_type(i), options, generator_context);
+  }
+  if (file->options().php_generic_services()) {
+    for (int i = 0; i < file->service_count(); i++) {
+      GenerateServiceFile(file, file->service(i), options, generator_context);
+    }
+  }
+}
+
+static std::string EscapePhpdoc(const std::string& input) {
+  std::string result;
+  result.reserve(input.size() * 2);
+
+  char prev = '*';
+
+  for (std::string::size_type i = 0; i < input.size(); i++) {
+    char c = input[i];
+    switch (c) {
+      case '*':
+        // Avoid "/*".
+        if (prev == '/') {
+          result.append("&#42;");
+        } else {
+          result.push_back(c);
+        }
+        break;
+      case '/':
+        // Avoid "*/".
+        if (prev == '*') {
+          result.append("&#47;");
+        } else {
+          result.push_back(c);
+        }
+        break;
+      case '@':
+        // '@' starts phpdoc tags including the @deprecated tag, which will
+        // cause a compile-time error if inserted before a declaration that
+        // does not have a corresponding @Deprecated annotation.
+        result.append("&#64;");
+        break;
+      default:
+        result.push_back(c);
+        break;
+    }
+
+    prev = c;
+  }
+
+  return result;
+}
+
+static void GenerateDocCommentBodyForLocation(
+    io::Printer* printer, const SourceLocation& location, bool trailingNewline,
+    int indentCount) {
+  std::string comments = location.leading_comments.empty()
+                             ? location.trailing_comments
+                             : location.leading_comments;
+  if (!comments.empty()) {
+    // TODO(teboring):  Ideally we should parse the comment text as Markdown and
+    //   write it back as HTML, but this requires a Markdown parser.  For now
+    //   we just use the proto comments unchanged.
+
+    // If the comment itself contains block comment start or end markers,
+    // HTML-escape them so that they don't accidentally close the doc comment.
+    comments = EscapePhpdoc(comments);
+
+    std::vector<std::string> lines = Split(comments, "\n", true);
+    while (!lines.empty() && lines.back().empty()) {
+      lines.pop_back();
+    }
+
+    for (int i = 0; i < lines.size(); i++) {
+      // Most lines should start with a space.  Watch out for lines that start
+      // with a /, since putting that right after the leading asterisk will
+      // close the comment.
+      if (indentCount == 0 && !lines[i].empty() && lines[i][0] == '/') {
+        printer->Print(" * ^line^\n", "line", lines[i]);
+      } else {
+        std::string indent = std::string(indentCount, ' ');
+        printer->Print(" *^ind^^line^\n", "ind", indent, "line", lines[i]);
+      }
+    }
+    if (trailingNewline) {
+      printer->Print(" *\n");
+    }
+  }
+}
+
+template <typename DescriptorType>
+static void GenerateDocCommentBody(
+    io::Printer* printer, const DescriptorType* descriptor) {
+  SourceLocation location;
+  if (descriptor->GetSourceLocation(&location)) {
+    GenerateDocCommentBodyForLocation(printer, location, true, 0);
+  }
+}
+
+static std::string FirstLineOf(const std::string& value) {
+  std::string result = value;
+
+  std::string::size_type pos = result.find_first_of('\n');
+  if (pos != std::string::npos) {
+    result.erase(pos);
+  }
+
+  return result;
+}
+
+void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message,
+                               const Options& options) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, message);
+  printer->Print(
+    " * Generated from protobuf message <code>^messagename^</code>\n"
+    " */\n",
+    "fullname", EscapePhpdoc(FullClassName(message, options)),
+    "messagename", EscapePhpdoc(message->full_name()));
+}
+
+void GenerateMessageConstructorDocComment(io::Printer* printer,
+                                          const Descriptor* message,
+                                          const Options& options) {
+  // In theory we should have slightly different comments for setters, getters,
+  // etc., but in practice everyone already knows the difference between these
+  // so it's redundant information.
+
+  // We start the comment with the main body based on the comments from the
+  // .proto file (if present). We then end with the field declaration, e.g.:
+  //   optional string foo = 5;
+  // If the field is a group, the debug string might end with {.
+  printer->Print("/**\n");
+  printer->Print(" * Constructor.\n");
+  printer->Print(" *\n");
+  printer->Print(" * @param array $data {\n");
+  printer->Print(" *     Optional. Data for populating the Message object.\n");
+  printer->Print(" *\n");
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    printer->Print(" *     @type ^php_type^ $^var^\n",
+      "php_type", PhpSetterTypeName(field, options),
+      "var", field->name());
+    SourceLocation location;
+    if (field->GetSourceLocation(&location)) {
+      GenerateDocCommentBodyForLocation(printer, location, false, 10);
+    }
+  }
+  printer->Print(" * }\n");
+  printer->Print(" */\n");
+}
+
+void GenerateServiceDocComment(io::Printer* printer,
+                               const ServiceDescriptor* service) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, service);
+  printer->Print(
+    " * Protobuf type <code>^fullname^</code>\n"
+    " */\n",
+    "fullname", EscapePhpdoc(service->full_name()));
+}
+
+void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
+                             const Options& options, int function_type) {
+  // In theory we should have slightly different comments for setters, getters,
+  // etc., but in practice everyone already knows the difference between these
+  // so it's redundant information.
+
+  // We start the comment with the main body based on the comments from the
+  // .proto file (if present). We then end with the field declaration, e.g.:
+  //   optional string foo = 5;
+  // If the field is a group, the debug string might end with {.
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, field);
+  printer->Print(
+    " * Generated from protobuf field <code>^def^</code>\n",
+    "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
+  if (function_type == kFieldSetter) {
+    printer->Print(" * @param ^php_type^ $var\n",
+      "php_type", PhpSetterTypeName(field, options));
+    printer->Print(" * @return $this\n");
+  } else if (function_type == kFieldGetter) {
+    bool can_return_null = field->has_presence() &&
+                           field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
+    printer->Print(" * @return ^php_type^^maybe_null^\n",
+      "php_type", PhpGetterTypeName(field, options),
+      "maybe_null", can_return_null ? "|null" : "");
+  }
+  if (field->options().deprecated()) {
+    printer->Print(" * @deprecated\n");
+  }
+  printer->Print(" */\n");
+}
+
+void GenerateWrapperFieldGetterDocComment(io::Printer* printer, const FieldDescriptor* field) {
+  // Generate a doc comment for the special getXXXValue methods that are
+  // generated for wrapper types.
+  const FieldDescriptor* primitiveField = field->message_type()->FindFieldByName("value");
+  printer->Print("/**\n");
+  printer->Print(
+      " * Returns the unboxed value from <code>get^camel_name^()</code>\n\n",
+      "camel_name", UnderscoresToCamelCase(field->name(), true));
+  GenerateDocCommentBody(printer, field);
+  printer->Print(
+    " * Generated from protobuf field <code>^def^</code>\n",
+    "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
+  printer->Print(" * @return ^php_type^|null\n",
+        "php_type", PhpGetterTypeName(primitiveField, false));
+  printer->Print(" */\n");
+}
+
+void GenerateWrapperFieldSetterDocComment(io::Printer* printer, const FieldDescriptor* field) {
+  // Generate a doc comment for the special setXXXValue methods that are
+  // generated for wrapper types.
+  const FieldDescriptor* primitiveField = field->message_type()->FindFieldByName("value");
+  printer->Print("/**\n");
+  printer->Print(
+      " * Sets the field by wrapping a primitive type in a ^message_name^ object.\n\n",
+      "message_name", FullClassName(field->message_type(), false));
+  GenerateDocCommentBody(printer, field);
+  printer->Print(
+    " * Generated from protobuf field <code>^def^</code>\n",
+    "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
+  printer->Print(" * @param ^php_type^|null $var\n",
+        "php_type", PhpSetterTypeName(primitiveField, false));
+  printer->Print(" * @return $this\n");
+  printer->Print(" */\n");
+}
+
+void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
+                            const Options& options) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, enum_);
+  printer->Print(
+    " * Protobuf type <code>^fullname^</code>\n"
+    " */\n",
+    "fullname", EscapePhpdoc(enum_->full_name()));
+}
+
+void GenerateEnumValueDocComment(io::Printer* printer,
+                                 const EnumValueDescriptor* value) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, value);
+  printer->Print(
+    " * Generated from protobuf enum <code>^def^</code>\n"
+    " */\n",
+    "def", EscapePhpdoc(FirstLineOf(value->DebugString())));
+}
+
+void GenerateServiceMethodDocComment(io::Printer* printer,
+                                     const MethodDescriptor* method) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, method);
+  printer->Print(
+    " * Method <code>^method_name^</code>\n"
+    " *\n",
+    "method_name", EscapePhpdoc(UnderscoresToCamelCase(method->name(), false)));
+  printer->Print(
+    " * @param \\^input_type^ $request\n",
+    "input_type", EscapePhpdoc(FullClassName(method->input_type(), false)));
+  printer->Print(
+    " * @return \\^return_type^\n"
+    " */\n",
+    "return_type", EscapePhpdoc(FullClassName(method->output_type(), false)));
+}
+
+std::string FilenameCName(const FileDescriptor* file) {
+  std::string c_name = file->name();
+  c_name = StringReplace(c_name, ".", "_", true);
+  c_name = StringReplace(c_name, "/", "_", true);
+  return c_name;
+}
+
+void GenerateCEnum(const EnumDescriptor* desc, io::Printer* printer) {
+  std::string c_name = desc->full_name();
+  c_name = StringReplace(c_name, ".", "_", true);
+  std::string php_name = FullClassName(desc, Options());
+  php_name = StringReplace(php_name, "\\", "\\\\", true);
+  printer->Print(
+      "/* $c_name$ */\n"
+      "\n"
+      "zend_class_entry* $c_name$_ce;\n"
+      "\n"
+      "PHP_METHOD($c_name$, name) {\n"
+      "  $file_c_name$_AddDescriptor();\n"
+      "  const upb_DefPool *symtab = DescriptorPool_GetSymbolTable();\n"
+      "  const upb_EnumDef *e = upb_DefPool_FindEnumByName(symtab, \"$name$\");\n"
+      "  zend_long value;\n"
+      "  if (zend_parse_parameters(ZEND_NUM_ARGS(), \"l\", &value) ==\n"
+      "      FAILURE) {\n"
+      "    return;\n"
+      "  }\n"
+      "  const upb_EnumValueDef* ev =\n"
+      "      upb_EnumDef_FindValueByNumber(e, value);\n"
+      "  if (!ev) {\n"
+      "    zend_throw_exception_ex(NULL, 0,\n"
+      "                            \"$php_name$ has no name \"\n"
+      "                            \"defined for value \" ZEND_LONG_FMT \".\",\n"
+      "                            value);\n"
+      "    return;\n"
+      "  }\n"
+      "  RETURN_STRING(upb_EnumValueDef_Name(ev));\n"
+      "}\n"
+      "\n"
+      "PHP_METHOD($c_name$, value) {\n"
+      "  $file_c_name$_AddDescriptor();\n"
+      "  const upb_DefPool *symtab = DescriptorPool_GetSymbolTable();\n"
+      "  const upb_EnumDef *e = upb_DefPool_FindEnumByName(symtab, \"$name$\");\n"
+      "  char *name = NULL;\n"
+      "  size_t name_len;\n"
+      "  if (zend_parse_parameters(ZEND_NUM_ARGS(), \"s\", &name,\n"
+      "                            &name_len) == FAILURE) {\n"
+      "    return;\n"
+      "  }\n"
+      "  const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNameWithSize(\n"
+      "      e, name, name_len);\n"
+      "  if (!ev) {\n"
+      "    zend_throw_exception_ex(NULL, 0,\n"
+      "                            \"$php_name$ has no value \"\n"
+      "                            \"defined for name %s.\",\n"
+      "                            name);\n"
+      "    return;\n"
+      "  }\n"
+      "  RETURN_LONG(upb_EnumValueDef_Number(ev));\n"
+      "}\n"
+      "\n"
+      "static zend_function_entry $c_name$_phpmethods[] = {\n"
+      "  PHP_ME($c_name$, name, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n"
+      "  PHP_ME($c_name$, value, arginfo_lookup, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n"
+      "  ZEND_FE_END\n"
+      "};\n"
+      "\n"
+      "static void $c_name$_ModuleInit() {\n"
+      "  zend_class_entry tmp_ce;\n"
+      "\n"
+      "  INIT_CLASS_ENTRY(tmp_ce, \"$php_name$\",\n"
+      "                   $c_name$_phpmethods);\n"
+      "\n"
+      "  $c_name$_ce = zend_register_internal_class(&tmp_ce);\n",
+      "name", desc->full_name(),
+      "file_c_name", FilenameCName(desc->file()),
+      "c_name", c_name,
+      "php_name", php_name);
+
+  for (int i = 0; i < desc->value_count(); i++) {
+    const EnumValueDescriptor* value = desc->value(i);
+    printer->Print(
+        "  zend_declare_class_constant_long($c_name$_ce, \"$name$\",\n"
+        "                                   strlen(\"$name$\"), $num$);\n",
+        "c_name", c_name,
+        "name", value->name(),
+        "num", std::to_string(value->number()));
+  }
+
+  printer->Print(
+      "}\n"
+      "\n");
+}
+
+void GenerateCMessage(const Descriptor* message, io::Printer* printer) {
+  std::string c_name = message->full_name();
+  c_name = StringReplace(c_name, ".", "_", true);
+  std::string php_name = FullClassName(message, Options());
+  php_name = StringReplace(php_name, "\\", "\\\\", true);
+  printer->Print(
+      "/* $c_name$ */\n"
+      "\n"
+      "zend_class_entry* $c_name$_ce;\n"
+      "\n"
+      "static PHP_METHOD($c_name$, __construct) {\n"
+      "  $file_c_name$_AddDescriptor();\n"
+      "  zim_Message___construct(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n"
+      "}\n"
+      "\n",
+      "file_c_name", FilenameCName(message->file()),
+      "c_name", c_name);
+
+  for (int i = 0; i < message->field_count(); i++) {
+    auto field = message->field(i);
+    printer->Print(
+      "static PHP_METHOD($c_name$, get$camel_name$) {\n"
+      "  Message* intern = (Message*)Z_OBJ_P(getThis());\n"
+      "  const upb_FieldDef *f = upb_MessageDef_FindFieldByName(\n"
+      "      intern->desc->msgdef, \"$name$\");\n"
+      "  zval ret;\n"
+      "  Message_get(intern, f, &ret);\n"
+      "  RETURN_COPY_VALUE(&ret);\n"
+      "}\n"
+      "\n"
+      "static PHP_METHOD($c_name$, set$camel_name$) {\n"
+      "  Message* intern = (Message*)Z_OBJ_P(getThis());\n"
+      "  const upb_FieldDef *f = upb_MessageDef_FindFieldByName(\n"
+      "      intern->desc->msgdef, \"$name$\");\n"
+      "  zval *val;\n"
+      "  if (zend_parse_parameters(ZEND_NUM_ARGS(), \"z\", &val)\n"
+      "      == FAILURE) {\n"
+      "    return;\n"
+      "  }\n"
+      "  Message_set(intern, f, val);\n"
+      "  RETURN_COPY(getThis());\n"
+      "}\n"
+      "\n",
+      "c_name", c_name,
+      "name", field->name(),
+      "camel_name", UnderscoresToCamelCase(field->name(), true));
+  }
+
+  for (int i = 0; i < message->real_oneof_decl_count(); i++) {
+    auto oneof = message->oneof_decl(i);
+    printer->Print(
+      "static PHP_METHOD($c_name$, get$camel_name$) {\n"
+      "  Message* intern = (Message*)Z_OBJ_P(getThis());\n"
+      "  const upb_OneofDef *oneof = upb_MessageDef_FindOneofByName(\n"
+      "      intern->desc->msgdef, \"$name$\");\n"
+      "  const upb_FieldDef *field = \n"
+      "      upb_Message_WhichOneof(intern->msg, oneof);\n"
+      "  RETURN_STRING(field ? upb_FieldDef_Name(field) : \"\");\n"
+      "}\n",
+      "c_name", c_name,
+      "name", oneof->name(),
+      "camel_name", UnderscoresToCamelCase(oneof->name(), true));
+  }
+
+  switch (message->well_known_type()) {
+    case Descriptor::WELLKNOWNTYPE_ANY:
+      printer->Print(
+          "ZEND_BEGIN_ARG_INFO_EX(arginfo_is, 0, 0, 1)\n"
+          "  ZEND_ARG_INFO(0, proto)\n"
+          "ZEND_END_ARG_INFO()\n"
+          "\n"
+      );
+      break;
+    case Descriptor::WELLKNOWNTYPE_TIMESTAMP:
+      printer->Print(
+          "ZEND_BEGIN_ARG_INFO_EX(arginfo_timestamp_fromdatetime, 0, 0, 1)\n"
+          "  ZEND_ARG_INFO(0, datetime)\n"
+          "ZEND_END_ARG_INFO()\n"
+          "\n"
+      );
+      break;
+    default:
+      break;
+  }
+
+  printer->Print(
+      "static zend_function_entry $c_name$_phpmethods[] = {\n"
+      "  PHP_ME($c_name$, __construct, arginfo_construct, ZEND_ACC_PUBLIC)\n",
+      "c_name", c_name);
+
+  for (int i = 0; i < message->field_count(); i++) {
+    auto field = message->field(i);
+    printer->Print(
+      "  PHP_ME($c_name$, get$camel_name$, arginfo_void, ZEND_ACC_PUBLIC)\n"
+      "  PHP_ME($c_name$, set$camel_name$, arginfo_setter, ZEND_ACC_PUBLIC)\n",
+      "c_name", c_name,
+      "camel_name", UnderscoresToCamelCase(field->name(), true));
+  }
+
+  for (int i = 0; i < message->real_oneof_decl_count(); i++) {
+    auto oneof = message->oneof_decl(i);
+    printer->Print(
+      "  PHP_ME($c_name$, get$camel_name$, arginfo_void, ZEND_ACC_PUBLIC)\n",
+      "c_name", c_name,
+      "camel_name", UnderscoresToCamelCase(oneof->name(), true));
+  }
+
+  // Extra hand-written functions added to the well-known types.
+  switch (message->well_known_type()) {
+    case Descriptor::WELLKNOWNTYPE_ANY:
+      printer->Print(
+        "  PHP_ME($c_name$, is, arginfo_is, ZEND_ACC_PUBLIC)\n"
+        "  PHP_ME($c_name$, pack, arginfo_setter, ZEND_ACC_PUBLIC)\n"
+        "  PHP_ME($c_name$, unpack, arginfo_void, ZEND_ACC_PUBLIC)\n",
+        "c_name", c_name);
+      break;
+    case Descriptor::WELLKNOWNTYPE_TIMESTAMP:
+      printer->Print(
+        "  PHP_ME($c_name$, fromDateTime, arginfo_timestamp_fromdatetime, ZEND_ACC_PUBLIC)\n"
+        "  PHP_ME($c_name$, toDateTime, arginfo_void, ZEND_ACC_PUBLIC)\n",
+        "c_name", c_name);
+      break;
+    default:
+      break;
+  }
+
+  printer->Print(
+      "  ZEND_FE_END\n"
+      "};\n"
+      "\n"
+      "static void $c_name$_ModuleInit() {\n"
+      "  zend_class_entry tmp_ce;\n"
+      "\n"
+      "  INIT_CLASS_ENTRY(tmp_ce, \"$php_name$\",\n"
+      "                   $c_name$_phpmethods);\n"
+      "\n"
+      "  $c_name$_ce = zend_register_internal_class(&tmp_ce);\n"
+      "  $c_name$_ce->ce_flags |= ZEND_ACC_FINAL;\n"
+      "  $c_name$_ce->create_object = Message_create;\n"
+      "  zend_do_inheritance($c_name$_ce, message_ce);\n"
+      "}\n"
+      "\n",
+      "c_name", c_name,
+      "php_name", php_name);
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateCMessage(message->nested_type(i), printer);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateCEnum(message->enum_type(i), printer);
+  }
+}
+
+void GenerateEnumCInit(const EnumDescriptor* desc, io::Printer* printer) {
+  std::string c_name = desc->full_name();
+  c_name = StringReplace(c_name, ".", "_", true);
+
+  printer->Print(
+      "  $c_name$_ModuleInit();\n",
+      "c_name", c_name);
+}
+
+void GenerateCInit(const Descriptor* message, io::Printer* printer) {
+  std::string c_name = message->full_name();
+  c_name = StringReplace(c_name, ".", "_", true);
+
+  printer->Print(
+      "  $c_name$_ModuleInit();\n",
+      "c_name", c_name);
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateCInit(message->nested_type(i), printer);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnumCInit(message->enum_type(i), printer);
+  }
+}
+
+void GenerateCWellKnownTypes(const std::vector<const FileDescriptor*>& files,
+                             GeneratorContext* context) {
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      context->Open("../ext/google/protobuf/wkt.inc"));
+  io::Printer printer(output.get(), '$');
+
+  printer.Print(
+      "// This file is generated from the .proto files for the well-known\n"
+      "// types. Do not edit!\n\n");
+
+  printer.Print(
+      "ZEND_BEGIN_ARG_INFO_EX(arginfo_lookup, 0, 0, 1)\n"
+      "  ZEND_ARG_INFO(0, key)\n"
+      "ZEND_END_ARG_INFO()\n"
+      "\n"
+  );
+
+  for (auto file : files) {
+    printer.Print(
+        "static void $c_name$_AddDescriptor();\n",
+        "c_name", FilenameCName(file));
+  }
+
+  for (auto file : files) {
+    std::string c_name = FilenameCName(file);
+    std::string metadata_filename = GeneratedMetadataFileName(file, Options());
+    std::string metadata_classname = FilenameToClassname(metadata_filename);
+    std::string metadata_c_name =
+        StringReplace(metadata_classname, "\\", "_", true);
+    metadata_classname = StringReplace(metadata_classname, "\\", "\\\\", true);
+    FileDescriptorProto file_proto;
+    file->CopyTo(&file_proto);
+    std::string serialized;
+    file_proto.SerializeToString(&serialized);
+    printer.Print(
+        "/* $filename$ */\n"
+        "\n"
+        "zend_class_entry* $metadata_c_name$_ce;\n"
+        "\n"
+        "const char $c_name$_descriptor [$size$] = {\n",
+        "filename", file->name(),
+        "c_name", c_name,
+        "metadata_c_name", metadata_c_name,
+        "size", std::to_string(serialized.size()));
+
+    for (size_t i = 0; i < serialized.size();) {
+      for (size_t j = 0; j < 25 && i < serialized.size(); ++i, ++j) {
+        printer.Print("'$ch$', ", "ch", CEscape(serialized.substr(i, 1)));
+      }
+      printer.Print("\n");
+    }
+
+    printer.Print(
+        "};\n"
+        "\n"
+        "static void $c_name$_AddDescriptor() {\n"
+        "  if (DescriptorPool_HasFile(\"$filename$\")) return;\n",
+        "filename", file->name(),
+        "c_name", c_name,
+        "metadata_c_name", metadata_c_name);
+
+    for (int i = 0; i < file->dependency_count(); i++) {
+      std::string dep_c_name = FilenameCName(file->dependency(i));
+      printer.Print(
+          "  $dep_c_name$_AddDescriptor();\n",
+          "dep_c_name", dep_c_name);
+    }
+
+    printer.Print(
+        "  DescriptorPool_AddDescriptor(\"$filename$\", $c_name$_descriptor,\n"
+        "                               sizeof($c_name$_descriptor));\n"
+        "}\n"
+        "\n"
+        "static PHP_METHOD($metadata_c_name$, initOnce) {\n"
+        "  $c_name$_AddDescriptor();\n"
+        "}\n"
+        "\n"
+        "static zend_function_entry $metadata_c_name$_methods[] = {\n"
+        "  PHP_ME($metadata_c_name$, initOnce, arginfo_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)\n"
+        "  ZEND_FE_END\n"
+        "};\n"
+        "\n"
+        "static void $metadata_c_name$_ModuleInit() {\n"
+        "  zend_class_entry tmp_ce;\n"
+        "\n"
+        "  INIT_CLASS_ENTRY(tmp_ce, \"$metadata_classname$\",\n"
+        "                   $metadata_c_name$_methods);\n"
+        "\n"
+        "  $metadata_c_name$_ce = zend_register_internal_class(&tmp_ce);\n"
+        "}\n"
+        "\n",
+        "filename", file->name(),
+        "c_name", c_name,
+        "metadata_c_name", metadata_c_name,
+        "metadata_classname", metadata_classname);
+    for (int i = 0; i < file->message_type_count(); i++) {
+      GenerateCMessage(file->message_type(i), &printer);
+    }
+    for (int i = 0; i < file->enum_type_count(); i++) {
+      GenerateCEnum(file->enum_type(i), &printer);
+    }
+  }
+
+  printer.Print(
+      "static void WellKnownTypes_ModuleInit() {\n");
+
+  for (auto file : files) {
+    std::string metadata_filename = GeneratedMetadataFileName(file, Options());
+    std::string metadata_classname = FilenameToClassname(metadata_filename);
+    std::string metadata_c_name =
+        StringReplace(metadata_classname, "\\", "_", true);
+    printer.Print(
+        "  $metadata_c_name$_ModuleInit();\n",
+        "metadata_c_name", metadata_c_name);
+    for (int i = 0; i < file->message_type_count(); i++) {
+      GenerateCInit(file->message_type(i), &printer);
+    }
+    for (int i = 0; i < file->enum_type_count(); i++) {
+      GenerateEnumCInit(file->enum_type(i), &printer);
+    }
+  }
+
+  printer.Print(
+      "}\n");
+}
+
+}  // namespace
+
+std::string GeneratedClassName(const Descriptor* desc) {
+  return GeneratedClassNameImpl(desc);
+}
+
+std::string GeneratedClassName(const EnumDescriptor* desc) {
+  return GeneratedClassNameImpl(desc);
+}
+
+std::string GeneratedClassName(const ServiceDescriptor* desc) {
+  return GeneratedClassNameImpl(desc);
+}
+
+bool Generator::Generate(const FileDescriptor* file,
+                         const std::string& parameter,
+                         GeneratorContext* generator_context,
+                         std::string* error) const {
+  return Generate(file, Options(), generator_context, error);
+}
+
+bool Generator::Generate(const FileDescriptor* file, const Options& options,
+                         GeneratorContext* generator_context,
+                         std::string* error) const {
+  if (options.is_descriptor && file->name() != kDescriptorFile) {
+    *error =
+        "Can only generate PHP code for google/protobuf/descriptor.proto.\n";
+    return false;
+  }
+
+  if (!options.is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+    *error =
+        "Can only generate PHP code for proto3 .proto files.\n"
+        "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
+    return false;
+  }
+
+  GenerateFile(file, options, generator_context);
+
+  return true;
+}
+
+bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
+                            const std::string& parameter,
+                            GeneratorContext* generator_context,
+                            std::string* error) const {
+  Options options;
+
+  for (const auto& option : Split(parameter, ",", true)) {
+    const std::vector<std::string> option_pair = Split(option, "=", true);
+    if (HasPrefixString(option_pair[0], "aggregate_metadata")) {
+      options.aggregate_metadata = true;
+      for (const auto& prefix : Split(option_pair[1], "#", false)) {
+        options.aggregate_metadata_prefixes.emplace(prefix);
+        GOOGLE_LOG(INFO) << prefix;
+      }
+    } else if (option_pair[0] == "internal") {
+      options.is_descriptor = true;
+    } else if (option_pair[0] == "internal_generate_c_wkt") {
+      GenerateCWellKnownTypes(files, generator_context);
+    } else {
+      GOOGLE_LOG(FATAL) << "Unknown codegen option: " << option_pair[0];
+    }
+  }
+
+  for (auto file : files) {
+    if (!Generate(file, options, generator_context, error)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace php
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/php/php_generator.h b/src/google/protobuf/compiler/php/php_generator.h
new file mode 100644
index 0000000..17cb59c
--- /dev/null
+++ b/src/google/protobuf/compiler/php/php_generator.h
@@ -0,0 +1,92 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace php {
+
+struct Options;
+
+class PROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+  virtual bool Generate(
+      const FileDescriptor* file,
+      const std::string& parameter,
+      GeneratorContext* generator_context,
+      std::string* error) const override;
+
+  bool GenerateAll(const std::vector<const FileDescriptor*>& files,
+                   const std::string& parameter,
+                   GeneratorContext* generator_context,
+                   std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override {
+    return FEATURE_PROTO3_OPTIONAL;
+  }
+
+ private:
+  bool Generate(
+      const FileDescriptor* file,
+      const Options& options,
+      GeneratorContext* generator_context,
+      std::string* error) const;
+};
+
+// To skip reserved keywords in php, some generated classname are prefixed.
+// Other code generators may need following API to figure out the actual
+// classname.
+PROTOC_EXPORT std::string GeneratedClassName(const Descriptor* desc);
+PROTOC_EXPORT std::string GeneratedClassName(const EnumDescriptor* desc);
+PROTOC_EXPORT std::string GeneratedClassName(const ServiceDescriptor* desc);
+
+inline bool IsWrapperType(const FieldDescriptor* descriptor) {
+  return descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
+}
+
+}  // namespace php
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
new file mode 100644
index 0000000..0a32384
--- /dev/null
+++ b/src/google/protobuf/compiler/plugin.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/compiler/plugin.h>
+
+#include <iostream>
+#include <set>
+
+#ifdef _WIN32
+#include <fcntl.h>
+#else
+#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>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#if defined(_WIN32)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::setmode;
+#endif
+
+class GeneratorResponseContext : public GeneratorContext {
+ public:
+  GeneratorResponseContext(
+      const Version& compiler_version, CodeGeneratorResponse* response,
+      const std::vector<const FileDescriptor*>& parsed_files)
+      : compiler_version_(compiler_version),
+        response_(response),
+        parsed_files_(parsed_files) {}
+  ~GeneratorResponseContext() override {}
+
+  // implements GeneratorContext --------------------------------------
+
+  io::ZeroCopyOutputStream* Open(const std::string& filename) override {
+    CodeGeneratorResponse::File* file = response_->add_file();
+    file->set_name(filename);
+    return new io::StringOutputStream(file->mutable_content());
+  }
+
+  io::ZeroCopyOutputStream* OpenForInsert(
+      const std::string& filename,
+      const std::string& insertion_point) override {
+    CodeGeneratorResponse::File* file = response_->add_file();
+    file->set_name(filename);
+    file->set_insertion_point(insertion_point);
+    return new io::StringOutputStream(file->mutable_content());
+  }
+
+  io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo(
+      const std::string& filename, const std::string& insertion_point,
+      const google::protobuf::GeneratedCodeInfo& info) override {
+    CodeGeneratorResponse::File* file = response_->add_file();
+    file->set_name(filename);
+    file->set_insertion_point(insertion_point);
+    *file->mutable_generated_code_info() = info;
+    return new io::StringOutputStream(file->mutable_content());
+  }
+
+  void ListParsedFiles(std::vector<const FileDescriptor*>* output) override {
+    *output = parsed_files_;
+  }
+
+  void GetCompilerVersion(Version* version) const override {
+    *version = compiler_version_;
+  }
+
+ private:
+  Version compiler_version_;
+  CodeGeneratorResponse* response_;
+  const std::vector<const FileDescriptor*>& parsed_files_;
+};
+
+bool GenerateCode(const CodeGeneratorRequest& request,
+                  const CodeGenerator& generator,
+                  CodeGeneratorResponse* response, std::string* error_msg) {
+  DescriptorPool pool;
+  for (int i = 0; i < request.proto_file_size(); i++) {
+    const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
+    if (file == nullptr) {
+      // BuildFile() already wrote an error message.
+      return false;
+    }
+  }
+
+  std::vector<const FileDescriptor*> parsed_files;
+  for (int i = 0; i < request.file_to_generate_size(); i++) {
+    parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
+    if (parsed_files.back() == nullptr) {
+      *error_msg =
+          "protoc asked plugin to generate a file but "
+          "did not provide a descriptor for the file: " +
+          request.file_to_generate(i);
+      return false;
+    }
+  }
+
+  GeneratorResponseContext context(request.compiler_version(), response,
+                                   parsed_files);
+
+
+  std::string error;
+  bool succeeded = generator.GenerateAll(parsed_files, request.parameter(),
+                                         &context, &error);
+
+  response->set_supported_features(generator.GetSupportedFeatures());
+
+  if (!succeeded && error.empty()) {
+    error =
+        "Code generator returned false but provided no error "
+        "description.";
+  }
+  if (!error.empty()) {
+    response->set_error(error);
+  }
+
+  return true;
+}
+
+int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
+
+  if (argc > 1) {
+    std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
+    return 1;
+  }
+
+#ifdef _WIN32
+  setmode(STDIN_FILENO, _O_BINARY);
+  setmode(STDOUT_FILENO, _O_BINARY);
+#endif
+
+  CodeGeneratorRequest request;
+  if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
+    std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
+              << std::endl;
+    return 1;
+  }
+
+
+  std::string error_msg;
+  CodeGeneratorResponse response;
+
+  if (GenerateCode(request, *generator, &response, &error_msg)) {
+    if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
+      std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
+      return 1;
+    }
+  } else {
+    if (!error_msg.empty()) {
+      std::cerr << argv[0] << ": " << error_msg << std::endl;
+    }
+    return 1;
+  }
+
+  return 0;
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
new file mode 100644
index 0000000..611713e
--- /dev/null
+++ b/src/google/protobuf/compiler/plugin.h
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// Front-end for protoc code generator plugins written in C++.
+//
+// To implement a protoc plugin in C++, simply write an implementation of
+// CodeGenerator, then create a main() function like:
+//   int main(int argc, char* argv[]) {
+//     MyCodeGenerator generator;
+//     return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+//   }
+// You must link your plugin against libprotobuf and libprotoc.
+//
+// The core part of PluginMain is to invoke the given CodeGenerator on a
+// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is
+// abstracted out and made into function GenerateCode so that it can be reused,
+// for example, to implement a variant of PluginMain that does some
+// preprocessing on the input CodeGeneratorRequest before feeding the request
+// to the given code generator.
+//
+// To get protoc to use the plugin, do one of the following:
+// * Place the plugin binary somewhere in the PATH and give it the name
+//   "protoc-gen-NAME" (replacing "NAME" with the name of your plugin).  If you
+//   then invoke protoc with the parameter --NAME_out=OUT_DIR (again, replace
+//   "NAME" with your plugin's name), protoc will invoke your plugin to generate
+//   the output, which will be placed in OUT_DIR.
+// * Place the plugin binary anywhere, with any name, and pass the --plugin
+//   parameter to protoc to direct it to your plugin like so:
+//     protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR
+//   On Windows, make sure to include the .exe suffix:
+//     protoc --plugin=protoc-gen-NAME=path/to/mybinary.exe --NAME_out=OUT_DIR
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
+#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
+
+#include <string>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+class CodeGenerator;  // code_generator.h
+class CodeGeneratorRequest;
+class CodeGeneratorResponse;
+
+// Implements main() for a protoc plugin exposing the given code generator.
+PROTOC_EXPORT int PluginMain(int argc, char* argv[],
+                             const CodeGenerator* generator);
+
+
+// Generates code using the given code generator. Returns true if the code
+// generation is successful. If the code generation fails, error_msg may be
+// populated to describe the failure cause.
+bool GenerateCode(const CodeGeneratorRequest& request,
+                  const CodeGenerator& generator,
+                  CodeGeneratorResponse* response, std::string* error_msg);
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
new file mode 100644
index 0000000..8f8d83f
--- /dev/null
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -0,0 +1,1612 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/compiler/plugin.proto
+
+#include <google/protobuf/compiler/plugin.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+namespace compiler {
+PROTOBUF_CONSTEXPR Version::Version(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.suffix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.major_)*/0
+  , /*decltype(_impl_.minor_)*/0
+  , /*decltype(_impl_.patch_)*/0} {}
+struct VersionDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR VersionDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~VersionDefaultTypeInternal() {}
+  union {
+    Version _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 VersionDefaultTypeInternal _Version_default_instance_;
+PROTOBUF_CONSTEXPR CodeGeneratorRequest::CodeGeneratorRequest(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.file_to_generate_)*/{}
+  , /*decltype(_impl_.proto_file_)*/{}
+  , /*decltype(_impl_.parameter_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.compiler_version_)*/nullptr} {}
+struct CodeGeneratorRequestDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR CodeGeneratorRequestDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~CodeGeneratorRequestDefaultTypeInternal() {}
+  union {
+    CodeGeneratorRequest _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 CodeGeneratorRequestDefaultTypeInternal _CodeGeneratorRequest_default_instance_;
+PROTOBUF_CONSTEXPR CodeGeneratorResponse_File::CodeGeneratorResponse_File(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.insertion_point_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.content_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.generated_code_info_)*/nullptr} {}
+struct CodeGeneratorResponse_FileDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR CodeGeneratorResponse_FileDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~CodeGeneratorResponse_FileDefaultTypeInternal() {}
+  union {
+    CodeGeneratorResponse_File _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 CodeGeneratorResponse_FileDefaultTypeInternal _CodeGeneratorResponse_File_default_instance_;
+PROTOBUF_CONSTEXPR CodeGeneratorResponse::CodeGeneratorResponse(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.file_)*/{}
+  , /*decltype(_impl_.error_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.supported_features_)*/uint64_t{0u}} {}
+struct CodeGeneratorResponseDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR CodeGeneratorResponseDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~CodeGeneratorResponseDefaultTypeInternal() {}
+  union {
+    CodeGeneratorResponse _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 CodeGeneratorResponseDefaultTypeInternal _CodeGeneratorResponse_default_instance_;
+}  // namespace compiler
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.major_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.minor_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.patch_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _impl_.suffix_),
+  1,
+  2,
+  3,
+  0,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.file_to_generate_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.parameter_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.proto_file_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, _impl_.compiler_version_),
+  ~0u,
+  0,
+  ~0u,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.insertion_point_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.content_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, _impl_.generated_code_info_),
+  0,
+  1,
+  2,
+  3,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_.error_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_.supported_features_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, _impl_.file_),
+  0,
+  1,
+  ~0u,
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, 10, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::Version)},
+  { 14, 24, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest)},
+  { 28, 38, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File)},
+  { 42, 51, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::compiler::_Version_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorRequest_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_File_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n%google/protobuf/compiler/plugin.proto\022"
+  "\030google.protobuf.compiler\032 google/protob"
+  "uf/descriptor.proto\"F\n\007Version\022\r\n\005major\030"
+  "\001 \001(\005\022\r\n\005minor\030\002 \001(\005\022\r\n\005patch\030\003 \001(\005\022\016\n\006s"
+  "uffix\030\004 \001(\t\"\272\001\n\024CodeGeneratorRequest\022\030\n\020"
+  "file_to_generate\030\001 \003(\t\022\021\n\tparameter\030\002 \001("
+  "\t\0228\n\nproto_file\030\017 \003(\0132$.google.protobuf."
+  "FileDescriptorProto\022;\n\020compiler_version\030"
+  "\003 \001(\0132!.google.protobuf.compiler.Version"
+  "\"\301\002\n\025CodeGeneratorResponse\022\r\n\005error\030\001 \001("
+  "\t\022\032\n\022supported_features\030\002 \001(\004\022B\n\004file\030\017 "
+  "\003(\01324.google.protobuf.compiler.CodeGener"
+  "atorResponse.File\032\177\n\004File\022\014\n\004name\030\001 \001(\t\022"
+  "\027\n\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001("
+  "\t\022\?\n\023generated_code_info\030\020 \001(\0132\".google."
+  "protobuf.GeneratedCodeInfo\"8\n\007Feature\022\020\n"
+  "\014FEATURE_NONE\020\000\022\033\n\027FEATURE_PROTO3_OPTION"
+  "AL\020\001BW\n\034com.google.protobuf.compilerB\014Pl"
+  "uginProtosZ)google.golang.org/protobuf/t"
+  "ypes/pluginpb"
+  ;
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps[1] = {
+  &::descriptor_table_google_2fprotobuf_2fdescriptor_2eproto,
+};
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
+    false, false, 773, descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+    "google/protobuf/compiler/plugin.proto",
+    &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps, 1, 4,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fcompiler_2fplugin_2eproto(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+namespace compiler {
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0];
+}
+bool CodeGeneratorResponse_Feature_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_NONE;
+constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_PROTO3_OPTIONAL;
+constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MIN;
+constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MAX;
+constexpr int CodeGeneratorResponse::Feature_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+
+// ===================================================================
+
+class Version::_Internal {
+ public:
+  using HasBits = decltype(std::declval<Version>()._impl_._has_bits_);
+  static void set_has_major(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_minor(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_patch(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_suffix(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+Version::Version(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.Version)
+}
+Version::Version(const Version& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Version* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.suffix_){}
+    , decltype(_impl_.major_){}
+    , decltype(_impl_.minor_){}
+    , decltype(_impl_.patch_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.suffix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.suffix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_suffix()) {
+    _this->_impl_.suffix_.Set(from._internal_suffix(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.major_, &from._impl_.major_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.patch_) -
+    reinterpret_cast<char*>(&_impl_.major_)) + sizeof(_impl_.patch_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.Version)
+}
+
+inline void Version::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.suffix_){}
+    , decltype(_impl_.major_){0}
+    , decltype(_impl_.minor_){0}
+    , decltype(_impl_.patch_){0}
+  };
+  _impl_.suffix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.suffix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Version::~Version() {
+  // @@protoc_insertion_point(destructor:google.protobuf.compiler.Version)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Version::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.suffix_.Destroy();
+}
+
+void Version::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Version::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.Version)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    _impl_.suffix_.ClearNonDefaultToEmpty();
+  }
+  if (cached_has_bits & 0x0000000eu) {
+    ::memset(&_impl_.major_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.patch_) -
+        reinterpret_cast<char*>(&_impl_.major_)) + sizeof(_impl_.patch_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Version::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 major = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_major(&has_bits);
+          _impl_.major_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 minor = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_minor(&has_bits);
+          _impl_.minor_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 patch = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_patch(&has_bits);
+          _impl_.patch_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string suffix = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_suffix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.Version.suffix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Version::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.Version)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 major = 1;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_major(), target);
+  }
+
+  // optional int32 minor = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_minor(), target);
+  }
+
+  // optional int32 patch = 3;
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_patch(), target);
+  }
+
+  // optional string suffix = 4;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_suffix().data(), static_cast<int>(this->_internal_suffix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.Version.suffix");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_suffix(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.Version)
+  return target;
+}
+
+size_t Version::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.Version)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    // optional string suffix = 4;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_suffix());
+    }
+
+    // optional int32 major = 1;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_major());
+    }
+
+    // optional int32 minor = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_minor());
+    }
+
+    // optional int32 patch = 3;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_patch());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Version::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Version::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Version::GetClassData() const { return &_class_data_; }
+
+
+void Version::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Version*>(&to_msg);
+  auto& from = static_cast<const Version&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.Version)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_suffix(from._internal_suffix());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.major_ = from._impl_.major_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.minor_ = from._impl_.minor_;
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.patch_ = from._impl_.patch_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Version::CopyFrom(const Version& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.Version)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Version::IsInitialized() const {
+  return true;
+}
+
+void Version::InternalSwap(Version* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.suffix_, lhs_arena,
+      &other->_impl_.suffix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Version, _impl_.patch_)
+      + sizeof(Version::_impl_.patch_)
+      - PROTOBUF_FIELD_OFFSET(Version, _impl_.major_)>(
+          reinterpret_cast<char*>(&_impl_.major_),
+          reinterpret_cast<char*>(&other->_impl_.major_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Version::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]);
+}
+
+// ===================================================================
+
+class CodeGeneratorRequest::_Internal {
+ public:
+  using HasBits = decltype(std::declval<CodeGeneratorRequest>()._impl_._has_bits_);
+  static void set_has_parameter(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::compiler::Version& compiler_version(const CodeGeneratorRequest* msg);
+  static void set_has_compiler_version(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::compiler::Version&
+CodeGeneratorRequest::_Internal::compiler_version(const CodeGeneratorRequest* msg) {
+  return *msg->_impl_.compiler_version_;
+}
+void CodeGeneratorRequest::clear_proto_file() {
+  _impl_.proto_file_.Clear();
+}
+CodeGeneratorRequest::CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorRequest)
+}
+CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  CodeGeneratorRequest* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.file_to_generate_){from._impl_.file_to_generate_}
+    , decltype(_impl_.proto_file_){from._impl_.proto_file_}
+    , decltype(_impl_.parameter_){}
+    , decltype(_impl_.compiler_version_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.parameter_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.parameter_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_parameter()) {
+    _this->_impl_.parameter_.Set(from._internal_parameter(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_compiler_version()) {
+    _this->_impl_.compiler_version_ = new ::PROTOBUF_NAMESPACE_ID::compiler::Version(*from._impl_.compiler_version_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorRequest)
+}
+
+inline void CodeGeneratorRequest::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.file_to_generate_){arena}
+    , decltype(_impl_.proto_file_){arena}
+    , decltype(_impl_.parameter_){}
+    , decltype(_impl_.compiler_version_){nullptr}
+  };
+  _impl_.parameter_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.parameter_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+CodeGeneratorRequest::~CodeGeneratorRequest() {
+  // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorRequest)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void CodeGeneratorRequest::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.file_to_generate_.~RepeatedPtrField();
+  _impl_.proto_file_.~RepeatedPtrField();
+  _impl_.parameter_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.compiler_version_;
+}
+
+void CodeGeneratorRequest::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void CodeGeneratorRequest::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.file_to_generate_.Clear();
+  _impl_.proto_file_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.parameter_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.compiler_version_ != nullptr);
+      _impl_.compiler_version_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated string file_to_generate = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_file_to_generate();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string parameter = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_parameter();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.compiler.Version compiler_version = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_compiler_version(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+      case 15:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_proto_file(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* CodeGeneratorRequest::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated string file_to_generate = 1;
+  for (int i = 0, n = this->_internal_file_to_generate_size(); i < n; i++) {
+    const auto& s = this->_internal_file_to_generate(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
+    target = stream->WriteString(1, s, target);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string parameter = 2;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_parameter().data(), static_cast<int>(this->_internal_parameter().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorRequest.parameter");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_parameter(), target);
+  }
+
+  // optional .google.protobuf.compiler.Version compiler_version = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::compiler_version(this),
+        _Internal::compiler_version(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_proto_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_proto_file(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(15, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorRequest)
+  return target;
+}
+
+size_t CodeGeneratorRequest::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated string file_to_generate = 1;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.file_to_generate_.size());
+  for (int i = 0, n = _impl_.file_to_generate_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.file_to_generate_.Get(i));
+  }
+
+  // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+  total_size += 1UL * this->_internal_proto_file_size();
+  for (const auto& msg : this->_impl_.proto_file_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string parameter = 2;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_parameter());
+    }
+
+    // optional .google.protobuf.compiler.Version compiler_version = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.compiler_version_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorRequest::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    CodeGeneratorRequest::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorRequest::GetClassData() const { return &_class_data_; }
+
+
+void CodeGeneratorRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<CodeGeneratorRequest*>(&to_msg);
+  auto& from = static_cast<const CodeGeneratorRequest&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.file_to_generate_.MergeFrom(from._impl_.file_to_generate_);
+  _this->_impl_.proto_file_.MergeFrom(from._impl_.proto_file_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_parameter(from._internal_parameter());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_compiler_version()->::PROTOBUF_NAMESPACE_ID::compiler::Version::MergeFrom(
+          from._internal_compiler_version());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool CodeGeneratorRequest::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.proto_file_))
+    return false;
+  return true;
+}
+
+void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.file_to_generate_.InternalSwap(&other->_impl_.file_to_generate_);
+  _impl_.proto_file_.InternalSwap(&other->_impl_.proto_file_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.parameter_, lhs_arena,
+      &other->_impl_.parameter_, rhs_arena
+  );
+  swap(_impl_.compiler_version_, other->_impl_.compiler_version_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorRequest::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]);
+}
+
+// ===================================================================
+
+class CodeGeneratorResponse_File::_Internal {
+ public:
+  using HasBits = decltype(std::declval<CodeGeneratorResponse_File>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_insertion_point(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_content(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& generated_code_info(const CodeGeneratorResponse_File* msg);
+  static void set_has_generated_code_info(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo&
+CodeGeneratorResponse_File::_Internal::generated_code_info(const CodeGeneratorResponse_File* msg) {
+  return *msg->_impl_.generated_code_info_;
+}
+void CodeGeneratorResponse_File::clear_generated_code_info() {
+  if (_impl_.generated_code_info_ != nullptr) _impl_.generated_code_info_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+CodeGeneratorResponse_File::CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
+}
+CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  CodeGeneratorResponse_File* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.insertion_point_){}
+    , decltype(_impl_.content_){}
+    , decltype(_impl_.generated_code_info_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.insertion_point_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.insertion_point_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_insertion_point()) {
+    _this->_impl_.insertion_point_.Set(from._internal_insertion_point(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.content_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.content_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_content()) {
+    _this->_impl_.content_.Set(from._internal_content(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_generated_code_info()) {
+    _this->_impl_.generated_code_info_ = new ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo(*from._impl_.generated_code_info_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
+}
+
+inline void CodeGeneratorResponse_File::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.insertion_point_){}
+    , decltype(_impl_.content_){}
+    , decltype(_impl_.generated_code_info_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.insertion_point_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.insertion_point_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.content_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.content_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+CodeGeneratorResponse_File::~CodeGeneratorResponse_File() {
+  // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse.File)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void CodeGeneratorResponse_File::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.insertion_point_.Destroy();
+  _impl_.content_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.generated_code_info_;
+}
+
+void CodeGeneratorResponse_File::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void CodeGeneratorResponse_File::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.insertion_point_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.content_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      GOOGLE_DCHECK(_impl_.generated_code_info_ != nullptr);
+      _impl_.generated_code_info_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string insertion_point = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_insertion_point();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string content = 15;
+      case 15:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) {
+          auto str = _internal_mutable_content();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
+      case 16:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 130)) {
+          ptr = ctx->ParseMessage(_internal_mutable_generated_code_info(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* CodeGeneratorResponse_File::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorResponse.File.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string insertion_point = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_insertion_point().data(), static_cast<int>(this->_internal_insertion_point().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_insertion_point(), target);
+  }
+
+  // optional string content = 15;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_content().data(), static_cast<int>(this->_internal_content().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorResponse.File.content");
+    target = stream->WriteStringMaybeAliased(
+        15, this->_internal_content(), target);
+  }
+
+  // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
+  if (cached_has_bits & 0x00000008u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(16, _Internal::generated_code_info(this),
+        _Internal::generated_code_info(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse.File)
+  return target;
+}
+
+size_t CodeGeneratorResponse_File::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string insertion_point = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_insertion_point());
+    }
+
+    // optional string content = 15;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_content());
+    }
+
+    // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.generated_code_info_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorResponse_File::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    CodeGeneratorResponse_File::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse_File::GetClassData() const { return &_class_data_; }
+
+
+void CodeGeneratorResponse_File::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<CodeGeneratorResponse_File*>(&to_msg);
+  auto& from = static_cast<const CodeGeneratorResponse_File&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_insertion_point(from._internal_insertion_point());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_content(from._internal_content());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_mutable_generated_code_info()->::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo::MergeFrom(
+          from._internal_generated_code_info());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool CodeGeneratorResponse_File::IsInitialized() const {
+  return true;
+}
+
+void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.insertion_point_, lhs_arena,
+      &other->_impl_.insertion_point_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.content_, lhs_arena,
+      &other->_impl_.content_, rhs_arena
+  );
+  swap(_impl_.generated_code_info_, other->_impl_.generated_code_info_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse_File::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]);
+}
+
+// ===================================================================
+
+class CodeGeneratorResponse::_Internal {
+ public:
+  using HasBits = decltype(std::declval<CodeGeneratorResponse>()._impl_._has_bits_);
+  static void set_has_error(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_supported_features(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+CodeGeneratorResponse::CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse)
+}
+CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  CodeGeneratorResponse* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.file_){from._impl_.file_}
+    , decltype(_impl_.error_){}
+    , decltype(_impl_.supported_features_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.error_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.error_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_error()) {
+    _this->_impl_.error_.Set(from._internal_error(), 
+      _this->GetArenaForAllocation());
+  }
+  _this->_impl_.supported_features_ = from._impl_.supported_features_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse)
+}
+
+inline void CodeGeneratorResponse::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.file_){arena}
+    , decltype(_impl_.error_){}
+    , decltype(_impl_.supported_features_){uint64_t{0u}}
+  };
+  _impl_.error_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.error_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+CodeGeneratorResponse::~CodeGeneratorResponse() {
+  // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void CodeGeneratorResponse::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.file_.~RepeatedPtrField();
+  _impl_.error_.Destroy();
+}
+
+void CodeGeneratorResponse::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void CodeGeneratorResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.file_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    _impl_.error_.ClearNonDefaultToEmpty();
+  }
+  _impl_.supported_features_ = uint64_t{0u};
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string error = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_error();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.error");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional uint64 supported_features = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_supported_features(&has_bits);
+          _impl_.supported_features_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+      case 15:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_file(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* CodeGeneratorResponse::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string error = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_error().data(), static_cast<int>(this->_internal_error().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorResponse.error");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_error(), target);
+  }
+
+  // optional uint64 supported_features = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(2, this->_internal_supported_features(), target);
+  }
+
+  // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_file(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(15, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse)
+  return target;
+}
+
+size_t CodeGeneratorResponse::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+  total_size += 1UL * this->_internal_file_size();
+  for (const auto& msg : this->_impl_.file_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string error = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_error());
+    }
+
+    // optional uint64 supported_features = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_supported_features());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorResponse::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    CodeGeneratorResponse::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse::GetClassData() const { return &_class_data_; }
+
+
+void CodeGeneratorResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<CodeGeneratorResponse*>(&to_msg);
+  auto& from = static_cast<const CodeGeneratorResponse&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.file_.MergeFrom(from._impl_.file_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_error(from._internal_error());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.supported_features_ = from._impl_.supported_features_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool CodeGeneratorResponse::IsInitialized() const {
+  return true;
+}
+
+void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.file_.InternalSwap(&other->_impl_.file_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.error_, lhs_arena,
+      &other->_impl_.error_, rhs_arena
+  );
+  swap(_impl_.supported_features_, other->_impl_.supported_features_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace compiler
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::Version*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
new file mode 100644
index 0000000..65c2cb0
--- /dev/null
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -0,0 +1,1901 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/compiler/plugin.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/descriptor.pb.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fcompiler_2fplugin_2eproto PROTOC_EXPORT
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOC_EXPORT TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOC_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+namespace compiler {
+class CodeGeneratorRequest;
+struct CodeGeneratorRequestDefaultTypeInternal;
+PROTOC_EXPORT extern CodeGeneratorRequestDefaultTypeInternal _CodeGeneratorRequest_default_instance_;
+class CodeGeneratorResponse;
+struct CodeGeneratorResponseDefaultTypeInternal;
+PROTOC_EXPORT extern CodeGeneratorResponseDefaultTypeInternal _CodeGeneratorResponse_default_instance_;
+class CodeGeneratorResponse_File;
+struct CodeGeneratorResponse_FileDefaultTypeInternal;
+PROTOC_EXPORT extern CodeGeneratorResponse_FileDefaultTypeInternal _CodeGeneratorResponse_File_default_instance_;
+class Version;
+struct VersionDefaultTypeInternal;
+PROTOC_EXPORT extern VersionDefaultTypeInternal _Version_default_instance_;
+}  // namespace compiler
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest>(Arena*);
+template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse>(Arena*);
+template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File>(Arena*);
+template<> PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::compiler::Version* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::Version>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+namespace compiler {
+
+enum CodeGeneratorResponse_Feature : int {
+  CodeGeneratorResponse_Feature_FEATURE_NONE = 0,
+  CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL = 1
+};
+PROTOC_EXPORT bool CodeGeneratorResponse_Feature_IsValid(int value);
+constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MIN = CodeGeneratorResponse_Feature_FEATURE_NONE;
+constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MAX = CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL;
+constexpr int CodeGeneratorResponse_Feature_Feature_ARRAYSIZE = CodeGeneratorResponse_Feature_Feature_MAX + 1;
+
+PROTOC_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor();
+template<typename T>
+inline const std::string& CodeGeneratorResponse_Feature_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, CodeGeneratorResponse_Feature>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function CodeGeneratorResponse_Feature_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    CodeGeneratorResponse_Feature_descriptor(), enum_t_value);
+}
+inline bool CodeGeneratorResponse_Feature_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, CodeGeneratorResponse_Feature* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<CodeGeneratorResponse_Feature>(
+    CodeGeneratorResponse_Feature_descriptor(), name, value);
+}
+// ===================================================================
+
+class PROTOC_EXPORT Version final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.Version) */ {
+ public:
+  inline Version() : Version(nullptr) {}
+  ~Version() override;
+  explicit PROTOBUF_CONSTEXPR Version(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Version(const Version& from);
+  Version(Version&& from) noexcept
+    : Version() {
+    *this = ::std::move(from);
+  }
+
+  inline Version& operator=(const Version& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Version& operator=(Version&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Version& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Version* internal_default_instance() {
+    return reinterpret_cast<const Version*>(
+               &_Version_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Version& a, Version& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Version* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Version* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Version* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Version>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Version& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Version& from) {
+    Version::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Version* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.Version";
+  }
+  protected:
+  explicit Version(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kSuffixFieldNumber = 4,
+    kMajorFieldNumber = 1,
+    kMinorFieldNumber = 2,
+    kPatchFieldNumber = 3,
+  };
+  // optional string suffix = 4;
+  bool has_suffix() const;
+  private:
+  bool _internal_has_suffix() const;
+  public:
+  void clear_suffix();
+  const std::string& suffix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_suffix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_suffix();
+  PROTOBUF_NODISCARD std::string* release_suffix();
+  void set_allocated_suffix(std::string* suffix);
+  private:
+  const std::string& _internal_suffix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_suffix(const std::string& value);
+  std::string* _internal_mutable_suffix();
+  public:
+
+  // optional int32 major = 1;
+  bool has_major() const;
+  private:
+  bool _internal_has_major() const;
+  public:
+  void clear_major();
+  int32_t major() const;
+  void set_major(int32_t value);
+  private:
+  int32_t _internal_major() const;
+  void _internal_set_major(int32_t value);
+  public:
+
+  // optional int32 minor = 2;
+  bool has_minor() const;
+  private:
+  bool _internal_has_minor() const;
+  public:
+  void clear_minor();
+  int32_t minor() const;
+  void set_minor(int32_t value);
+  private:
+  int32_t _internal_minor() const;
+  void _internal_set_minor(int32_t value);
+  public:
+
+  // optional int32 patch = 3;
+  bool has_patch() const;
+  private:
+  bool _internal_has_patch() const;
+  public:
+  void clear_patch();
+  int32_t patch() const;
+  void set_patch(int32_t value);
+  private:
+  int32_t _internal_patch() const;
+  void _internal_set_patch(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.compiler.Version)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr suffix_;
+    int32_t major_;
+    int32_t minor_;
+    int32_t patch_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOC_EXPORT CodeGeneratorRequest final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorRequest) */ {
+ public:
+  inline CodeGeneratorRequest() : CodeGeneratorRequest(nullptr) {}
+  ~CodeGeneratorRequest() override;
+  explicit PROTOBUF_CONSTEXPR CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  CodeGeneratorRequest(const CodeGeneratorRequest& from);
+  CodeGeneratorRequest(CodeGeneratorRequest&& from) noexcept
+    : CodeGeneratorRequest() {
+    *this = ::std::move(from);
+  }
+
+  inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline CodeGeneratorRequest& operator=(CodeGeneratorRequest&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const CodeGeneratorRequest& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const CodeGeneratorRequest* internal_default_instance() {
+    return reinterpret_cast<const CodeGeneratorRequest*>(
+               &_CodeGeneratorRequest_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(CodeGeneratorRequest& a, CodeGeneratorRequest& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(CodeGeneratorRequest* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(CodeGeneratorRequest* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  CodeGeneratorRequest* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<CodeGeneratorRequest>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const CodeGeneratorRequest& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const CodeGeneratorRequest& from) {
+    CodeGeneratorRequest::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(CodeGeneratorRequest* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.CodeGeneratorRequest";
+  }
+  protected:
+  explicit CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFileToGenerateFieldNumber = 1,
+    kProtoFileFieldNumber = 15,
+    kParameterFieldNumber = 2,
+    kCompilerVersionFieldNumber = 3,
+  };
+  // repeated string file_to_generate = 1;
+  int file_to_generate_size() const;
+  private:
+  int _internal_file_to_generate_size() const;
+  public:
+  void clear_file_to_generate();
+  const std::string& file_to_generate(int index) const;
+  std::string* mutable_file_to_generate(int index);
+  void set_file_to_generate(int index, const std::string& value);
+  void set_file_to_generate(int index, std::string&& value);
+  void set_file_to_generate(int index, const char* value);
+  void set_file_to_generate(int index, const char* value, size_t size);
+  std::string* add_file_to_generate();
+  void add_file_to_generate(const std::string& value);
+  void add_file_to_generate(std::string&& value);
+  void add_file_to_generate(const char* value);
+  void add_file_to_generate(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& file_to_generate() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_file_to_generate();
+  private:
+  const std::string& _internal_file_to_generate(int index) const;
+  std::string* _internal_add_file_to_generate();
+  public:
+
+  // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+  int proto_file_size() const;
+  private:
+  int _internal_proto_file_size() const;
+  public:
+  void clear_proto_file();
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* mutable_proto_file(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
+      mutable_proto_file();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& _internal_proto_file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _internal_add_proto_file();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& proto_file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* add_proto_file();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >&
+      proto_file() const;
+
+  // optional string parameter = 2;
+  bool has_parameter() const;
+  private:
+  bool _internal_has_parameter() const;
+  public:
+  void clear_parameter();
+  const std::string& parameter() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_parameter(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_parameter();
+  PROTOBUF_NODISCARD std::string* release_parameter();
+  void set_allocated_parameter(std::string* parameter);
+  private:
+  const std::string& _internal_parameter() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_parameter(const std::string& value);
+  std::string* _internal_mutable_parameter();
+  public:
+
+  // optional .google.protobuf.compiler.Version compiler_version = 3;
+  bool has_compiler_version() const;
+  private:
+  bool _internal_has_compiler_version() const;
+  public:
+  void clear_compiler_version();
+  const ::PROTOBUF_NAMESPACE_ID::compiler::Version& compiler_version() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::compiler::Version* release_compiler_version();
+  ::PROTOBUF_NAMESPACE_ID::compiler::Version* mutable_compiler_version();
+  void set_allocated_compiler_version(::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::compiler::Version& _internal_compiler_version() const;
+  ::PROTOBUF_NAMESPACE_ID::compiler::Version* _internal_mutable_compiler_version();
+  public:
+  void unsafe_arena_set_allocated_compiler_version(
+      ::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version);
+  ::PROTOBUF_NAMESPACE_ID::compiler::Version* unsafe_arena_release_compiler_version();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> file_to_generate_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto > proto_file_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr parameter_;
+    ::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOC_EXPORT CodeGeneratorResponse_File final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse.File) */ {
+ public:
+  inline CodeGeneratorResponse_File() : CodeGeneratorResponse_File(nullptr) {}
+  ~CodeGeneratorResponse_File() override;
+  explicit PROTOBUF_CONSTEXPR CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from);
+  CodeGeneratorResponse_File(CodeGeneratorResponse_File&& from) noexcept
+    : CodeGeneratorResponse_File() {
+    *this = ::std::move(from);
+  }
+
+  inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline CodeGeneratorResponse_File& operator=(CodeGeneratorResponse_File&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const CodeGeneratorResponse_File& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const CodeGeneratorResponse_File* internal_default_instance() {
+    return reinterpret_cast<const CodeGeneratorResponse_File*>(
+               &_CodeGeneratorResponse_File_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(CodeGeneratorResponse_File& a, CodeGeneratorResponse_File& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(CodeGeneratorResponse_File* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(CodeGeneratorResponse_File* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  CodeGeneratorResponse_File* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<CodeGeneratorResponse_File>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const CodeGeneratorResponse_File& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const CodeGeneratorResponse_File& from) {
+    CodeGeneratorResponse_File::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(CodeGeneratorResponse_File* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.CodeGeneratorResponse.File";
+  }
+  protected:
+  explicit CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kInsertionPointFieldNumber = 2,
+    kContentFieldNumber = 15,
+    kGeneratedCodeInfoFieldNumber = 16,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string insertion_point = 2;
+  bool has_insertion_point() const;
+  private:
+  bool _internal_has_insertion_point() const;
+  public:
+  void clear_insertion_point();
+  const std::string& insertion_point() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_insertion_point(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_insertion_point();
+  PROTOBUF_NODISCARD std::string* release_insertion_point();
+  void set_allocated_insertion_point(std::string* insertion_point);
+  private:
+  const std::string& _internal_insertion_point() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_insertion_point(const std::string& value);
+  std::string* _internal_mutable_insertion_point();
+  public:
+
+  // optional string content = 15;
+  bool has_content() const;
+  private:
+  bool _internal_has_content() const;
+  public:
+  void clear_content();
+  const std::string& content() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_content(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_content();
+  PROTOBUF_NODISCARD std::string* release_content();
+  void set_allocated_content(std::string* content);
+  private:
+  const std::string& _internal_content() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_content(const std::string& value);
+  std::string* _internal_mutable_content();
+  public:
+
+  // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
+  bool has_generated_code_info() const;
+  private:
+  bool _internal_has_generated_code_info() const;
+  public:
+  void clear_generated_code_info();
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& generated_code_info() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* release_generated_code_info();
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* mutable_generated_code_info();
+  void set_allocated_generated_code_info(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& _internal_generated_code_info() const;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* _internal_mutable_generated_code_info();
+  public:
+  void unsafe_arena_set_allocated_generated_code_info(
+      ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info);
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* unsafe_arena_release_generated_code_info();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr insertion_point_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr content_;
+    ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOC_EXPORT CodeGeneratorResponse final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse) */ {
+ public:
+  inline CodeGeneratorResponse() : CodeGeneratorResponse(nullptr) {}
+  ~CodeGeneratorResponse() override;
+  explicit PROTOBUF_CONSTEXPR CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  CodeGeneratorResponse(const CodeGeneratorResponse& from);
+  CodeGeneratorResponse(CodeGeneratorResponse&& from) noexcept
+    : CodeGeneratorResponse() {
+    *this = ::std::move(from);
+  }
+
+  inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline CodeGeneratorResponse& operator=(CodeGeneratorResponse&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const CodeGeneratorResponse& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const CodeGeneratorResponse* internal_default_instance() {
+    return reinterpret_cast<const CodeGeneratorResponse*>(
+               &_CodeGeneratorResponse_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(CodeGeneratorResponse& a, CodeGeneratorResponse& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(CodeGeneratorResponse* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(CodeGeneratorResponse* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  CodeGeneratorResponse* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<CodeGeneratorResponse>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const CodeGeneratorResponse& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const CodeGeneratorResponse& from) {
+    CodeGeneratorResponse::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(CodeGeneratorResponse* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.CodeGeneratorResponse";
+  }
+  protected:
+  explicit CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef CodeGeneratorResponse_File File;
+
+  typedef CodeGeneratorResponse_Feature Feature;
+  static constexpr Feature FEATURE_NONE =
+    CodeGeneratorResponse_Feature_FEATURE_NONE;
+  static constexpr Feature FEATURE_PROTO3_OPTIONAL =
+    CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL;
+  static inline bool Feature_IsValid(int value) {
+    return CodeGeneratorResponse_Feature_IsValid(value);
+  }
+  static constexpr Feature Feature_MIN =
+    CodeGeneratorResponse_Feature_Feature_MIN;
+  static constexpr Feature Feature_MAX =
+    CodeGeneratorResponse_Feature_Feature_MAX;
+  static constexpr int Feature_ARRAYSIZE =
+    CodeGeneratorResponse_Feature_Feature_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Feature_descriptor() {
+    return CodeGeneratorResponse_Feature_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Feature_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Feature>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Feature_Name.");
+    return CodeGeneratorResponse_Feature_Name(enum_t_value);
+  }
+  static inline bool Feature_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Feature* value) {
+    return CodeGeneratorResponse_Feature_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFileFieldNumber = 15,
+    kErrorFieldNumber = 1,
+    kSupportedFeaturesFieldNumber = 2,
+  };
+  // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+  int file_size() const;
+  private:
+  int _internal_file_size() const;
+  public:
+  void clear_file();
+  ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* mutable_file(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >*
+      mutable_file();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& _internal_file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* _internal_add_file();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* add_file();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >&
+      file() const;
+
+  // optional string error = 1;
+  bool has_error() const;
+  private:
+  bool _internal_has_error() const;
+  public:
+  void clear_error();
+  const std::string& error() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_error(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_error();
+  PROTOBUF_NODISCARD std::string* release_error();
+  void set_allocated_error(std::string* error);
+  private:
+  const std::string& _internal_error() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_error(const std::string& value);
+  std::string* _internal_mutable_error();
+  public:
+
+  // optional uint64 supported_features = 2;
+  bool has_supported_features() const;
+  private:
+  bool _internal_has_supported_features() const;
+  public:
+  void clear_supported_features();
+  uint64_t supported_features() const;
+  void set_supported_features(uint64_t value);
+  private:
+  uint64_t _internal_supported_features() const;
+  void _internal_set_supported_features(uint64_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File > file_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr error_;
+    uint64_t supported_features_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Version
+
+// optional int32 major = 1;
+inline bool Version::_internal_has_major() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool Version::has_major() const {
+  return _internal_has_major();
+}
+inline void Version::clear_major() {
+  _impl_.major_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t Version::_internal_major() const {
+  return _impl_.major_;
+}
+inline int32_t Version::major() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.major)
+  return _internal_major();
+}
+inline void Version::_internal_set_major(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.major_ = value;
+}
+inline void Version::set_major(int32_t value) {
+  _internal_set_major(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.major)
+}
+
+// optional int32 minor = 2;
+inline bool Version::_internal_has_minor() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool Version::has_minor() const {
+  return _internal_has_minor();
+}
+inline void Version::clear_minor() {
+  _impl_.minor_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t Version::_internal_minor() const {
+  return _impl_.minor_;
+}
+inline int32_t Version::minor() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.minor)
+  return _internal_minor();
+}
+inline void Version::_internal_set_minor(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.minor_ = value;
+}
+inline void Version::set_minor(int32_t value) {
+  _internal_set_minor(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.minor)
+}
+
+// optional int32 patch = 3;
+inline bool Version::_internal_has_patch() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool Version::has_patch() const {
+  return _internal_has_patch();
+}
+inline void Version::clear_patch() {
+  _impl_.patch_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline int32_t Version::_internal_patch() const {
+  return _impl_.patch_;
+}
+inline int32_t Version::patch() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.patch)
+  return _internal_patch();
+}
+inline void Version::_internal_set_patch(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.patch_ = value;
+}
+inline void Version::set_patch(int32_t value) {
+  _internal_set_patch(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.patch)
+}
+
+// optional string suffix = 4;
+inline bool Version::_internal_has_suffix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool Version::has_suffix() const {
+  return _internal_has_suffix();
+}
+inline void Version::clear_suffix() {
+  _impl_.suffix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& Version::suffix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.suffix)
+  return _internal_suffix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Version::set_suffix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.suffix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.suffix)
+}
+inline std::string* Version::mutable_suffix() {
+  std::string* _s = _internal_mutable_suffix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.Version.suffix)
+  return _s;
+}
+inline const std::string& Version::_internal_suffix() const {
+  return _impl_.suffix_.Get();
+}
+inline void Version::_internal_set_suffix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.suffix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Version::_internal_mutable_suffix() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.suffix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Version::release_suffix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.Version.suffix)
+  if (!_internal_has_suffix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.suffix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.suffix_.IsDefault()) {
+    _impl_.suffix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void Version::set_allocated_suffix(std::string* suffix) {
+  if (suffix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.suffix_.SetAllocated(suffix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.suffix_.IsDefault()) {
+    _impl_.suffix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.Version.suffix)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorRequest
+
+// repeated string file_to_generate = 1;
+inline int CodeGeneratorRequest::_internal_file_to_generate_size() const {
+  return _impl_.file_to_generate_.size();
+}
+inline int CodeGeneratorRequest::file_to_generate_size() const {
+  return _internal_file_to_generate_size();
+}
+inline void CodeGeneratorRequest::clear_file_to_generate() {
+  _impl_.file_to_generate_.Clear();
+}
+inline std::string* CodeGeneratorRequest::add_file_to_generate() {
+  std::string* _s = _internal_add_file_to_generate();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return _s;
+}
+inline const std::string& CodeGeneratorRequest::_internal_file_to_generate(int index) const {
+  return _impl_.file_to_generate_.Get(index);
+}
+inline const std::string& CodeGeneratorRequest::file_to_generate(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return _internal_file_to_generate(index);
+}
+inline std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return _impl_.file_to_generate_.Mutable(index);
+}
+inline void CodeGeneratorRequest::set_file_to_generate(int index, const std::string& value) {
+  _impl_.file_to_generate_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline void CodeGeneratorRequest::set_file_to_generate(int index, std::string&& value) {
+  _impl_.file_to_generate_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.file_to_generate_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
+  _impl_.file_to_generate_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline std::string* CodeGeneratorRequest::_internal_add_file_to_generate() {
+  return _impl_.file_to_generate_.Add();
+}
+inline void CodeGeneratorRequest::add_file_to_generate(const std::string& value) {
+  _impl_.file_to_generate_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline void CodeGeneratorRequest::add_file_to_generate(std::string&& value) {
+  _impl_.file_to_generate_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline void CodeGeneratorRequest::add_file_to_generate(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.file_to_generate_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
+  _impl_.file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+CodeGeneratorRequest::file_to_generate() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return _impl_.file_to_generate_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+CodeGeneratorRequest::mutable_file_to_generate() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return &_impl_.file_to_generate_;
+}
+
+// optional string parameter = 2;
+inline bool CodeGeneratorRequest::_internal_has_parameter() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool CodeGeneratorRequest::has_parameter() const {
+  return _internal_has_parameter();
+}
+inline void CodeGeneratorRequest::clear_parameter() {
+  _impl_.parameter_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& CodeGeneratorRequest::parameter() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return _internal_parameter();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void CodeGeneratorRequest::set_parameter(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.parameter_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+inline std::string* CodeGeneratorRequest::mutable_parameter() {
+  std::string* _s = _internal_mutable_parameter();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return _s;
+}
+inline const std::string& CodeGeneratorRequest::_internal_parameter() const {
+  return _impl_.parameter_.Get();
+}
+inline void CodeGeneratorRequest::_internal_set_parameter(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.parameter_.Set(value, GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorRequest::_internal_mutable_parameter() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.parameter_.Mutable(GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorRequest::release_parameter() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  if (!_internal_has_parameter()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.parameter_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.parameter_.IsDefault()) {
+    _impl_.parameter_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void CodeGeneratorRequest::set_allocated_parameter(std::string* parameter) {
+  if (parameter != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.parameter_.SetAllocated(parameter, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.parameter_.IsDefault()) {
+    _impl_.parameter_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+
+// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+inline int CodeGeneratorRequest::_internal_proto_file_size() const {
+  return _impl_.proto_file_.size();
+}
+inline int CodeGeneratorRequest::proto_file_size() const {
+  return _internal_proto_file_size();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return _impl_.proto_file_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
+CodeGeneratorRequest::mutable_proto_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return &_impl_.proto_file_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& CodeGeneratorRequest::_internal_proto_file(int index) const {
+  return _impl_.proto_file_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return _internal_proto_file(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* CodeGeneratorRequest::_internal_add_proto_file() {
+  return _impl_.proto_file_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _add = _internal_add_proto_file();
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >&
+CodeGeneratorRequest::proto_file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return _impl_.proto_file_;
+}
+
+// optional .google.protobuf.compiler.Version compiler_version = 3;
+inline bool CodeGeneratorRequest::_internal_has_compiler_version() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.compiler_version_ != nullptr);
+  return value;
+}
+inline bool CodeGeneratorRequest::has_compiler_version() const {
+  return _internal_has_compiler_version();
+}
+inline void CodeGeneratorRequest::clear_compiler_version() {
+  if (_impl_.compiler_version_ != nullptr) _impl_.compiler_version_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::compiler::Version& CodeGeneratorRequest::_internal_compiler_version() const {
+  const ::PROTOBUF_NAMESPACE_ID::compiler::Version* p = _impl_.compiler_version_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::compiler::Version&>(
+      ::PROTOBUF_NAMESPACE_ID::compiler::_Version_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::compiler::Version& CodeGeneratorRequest::compiler_version() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
+  return _internal_compiler_version();
+}
+inline void CodeGeneratorRequest::unsafe_arena_set_allocated_compiler_version(
+    ::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.compiler_version_);
+  }
+  _impl_.compiler_version_ = compiler_version;
+  if (compiler_version) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::release_compiler_version() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::compiler::Version* temp = _impl_.compiler_version_;
+  _impl_.compiler_version_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::unsafe_arena_release_compiler_version() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::compiler::Version* temp = _impl_.compiler_version_;
+  _impl_.compiler_version_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::_internal_mutable_compiler_version() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.compiler_version_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::compiler::Version>(GetArenaForAllocation());
+    _impl_.compiler_version_ = p;
+  }
+  return _impl_.compiler_version_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::Version* CodeGeneratorRequest::mutable_compiler_version() {
+  ::PROTOBUF_NAMESPACE_ID::compiler::Version* _msg = _internal_mutable_compiler_version();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
+  return _msg;
+}
+inline void CodeGeneratorRequest::set_allocated_compiler_version(::PROTOBUF_NAMESPACE_ID::compiler::Version* compiler_version) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.compiler_version_;
+  }
+  if (compiler_version) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(compiler_version);
+    if (message_arena != submessage_arena) {
+      compiler_version = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, compiler_version, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.compiler_version_ = compiler_version;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorResponse_File
+
+// optional string name = 1;
+inline bool CodeGeneratorResponse_File::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool CodeGeneratorResponse_File::has_name() const {
+  return _internal_has_name();
+}
+inline void CodeGeneratorResponse_File::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& CodeGeneratorResponse_File::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void CodeGeneratorResponse_File::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+inline std::string* CodeGeneratorResponse_File::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return _s;
+}
+inline const std::string& CodeGeneratorResponse_File::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void CodeGeneratorResponse_File::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse_File::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse_File::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void CodeGeneratorResponse_File::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+
+// optional string insertion_point = 2;
+inline bool CodeGeneratorResponse_File::_internal_has_insertion_point() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool CodeGeneratorResponse_File::has_insertion_point() const {
+  return _internal_has_insertion_point();
+}
+inline void CodeGeneratorResponse_File::clear_insertion_point() {
+  _impl_.insertion_point_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& CodeGeneratorResponse_File::insertion_point() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return _internal_insertion_point();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void CodeGeneratorResponse_File::set_insertion_point(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.insertion_point_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+inline std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+  std::string* _s = _internal_mutable_insertion_point();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return _s;
+}
+inline const std::string& CodeGeneratorResponse_File::_internal_insertion_point() const {
+  return _impl_.insertion_point_.Get();
+}
+inline void CodeGeneratorResponse_File::_internal_set_insertion_point(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.insertion_point_.Set(value, GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse_File::_internal_mutable_insertion_point() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.insertion_point_.Mutable(GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse_File::release_insertion_point() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  if (!_internal_has_insertion_point()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.insertion_point_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.insertion_point_.IsDefault()) {
+    _impl_.insertion_point_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void CodeGeneratorResponse_File::set_allocated_insertion_point(std::string* insertion_point) {
+  if (insertion_point != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.insertion_point_.SetAllocated(insertion_point, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.insertion_point_.IsDefault()) {
+    _impl_.insertion_point_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+
+// optional string content = 15;
+inline bool CodeGeneratorResponse_File::_internal_has_content() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool CodeGeneratorResponse_File::has_content() const {
+  return _internal_has_content();
+}
+inline void CodeGeneratorResponse_File::clear_content() {
+  _impl_.content_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& CodeGeneratorResponse_File::content() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return _internal_content();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void CodeGeneratorResponse_File::set_content(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.content_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+inline std::string* CodeGeneratorResponse_File::mutable_content() {
+  std::string* _s = _internal_mutable_content();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return _s;
+}
+inline const std::string& CodeGeneratorResponse_File::_internal_content() const {
+  return _impl_.content_.Get();
+}
+inline void CodeGeneratorResponse_File::_internal_set_content(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.content_.Set(value, GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse_File::_internal_mutable_content() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.content_.Mutable(GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse_File::release_content() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  if (!_internal_has_content()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.content_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.content_.IsDefault()) {
+    _impl_.content_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void CodeGeneratorResponse_File::set_allocated_content(std::string* content) {
+  if (content != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.content_.SetAllocated(content, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.content_.IsDefault()) {
+    _impl_.content_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+
+// optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
+inline bool CodeGeneratorResponse_File::_internal_has_generated_code_info() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.generated_code_info_ != nullptr);
+  return value;
+}
+inline bool CodeGeneratorResponse_File::has_generated_code_info() const {
+  return _internal_has_generated_code_info();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& CodeGeneratorResponse_File::_internal_generated_code_info() const {
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* p = _impl_.generated_code_info_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo&>(
+      ::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo& CodeGeneratorResponse_File::generated_code_info() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info)
+  return _internal_generated_code_info();
+}
+inline void CodeGeneratorResponse_File::unsafe_arena_set_allocated_generated_code_info(
+    ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.generated_code_info_);
+  }
+  _impl_.generated_code_info_ = generated_code_info;
+  if (generated_code_info) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info)
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::release_generated_code_info() {
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* temp = _impl_.generated_code_info_;
+  _impl_.generated_code_info_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::unsafe_arena_release_generated_code_info() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info)
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* temp = _impl_.generated_code_info_;
+  _impl_.generated_code_info_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::_internal_mutable_generated_code_info() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  if (_impl_.generated_code_info_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo>(GetArenaForAllocation());
+    _impl_.generated_code_info_ = p;
+  }
+  return _impl_.generated_code_info_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* CodeGeneratorResponse_File::mutable_generated_code_info() {
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* _msg = _internal_mutable_generated_code_info();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info)
+  return _msg;
+}
+inline void CodeGeneratorResponse_File::set_allocated_generated_code_info(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* generated_code_info) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.generated_code_info_);
+  }
+  if (generated_code_info) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(generated_code_info));
+    if (message_arena != submessage_arena) {
+      generated_code_info = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, generated_code_info, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.generated_code_info_ = generated_code_info;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorResponse
+
+// optional string error = 1;
+inline bool CodeGeneratorResponse::_internal_has_error() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool CodeGeneratorResponse::has_error() const {
+  return _internal_has_error();
+}
+inline void CodeGeneratorResponse::clear_error() {
+  _impl_.error_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& CodeGeneratorResponse::error() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return _internal_error();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void CodeGeneratorResponse::set_error(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.error_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+inline std::string* CodeGeneratorResponse::mutable_error() {
+  std::string* _s = _internal_mutable_error();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return _s;
+}
+inline const std::string& CodeGeneratorResponse::_internal_error() const {
+  return _impl_.error_.Get();
+}
+inline void CodeGeneratorResponse::_internal_set_error(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.error_.Set(value, GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse::_internal_mutable_error() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.error_.Mutable(GetArenaForAllocation());
+}
+inline std::string* CodeGeneratorResponse::release_error() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error)
+  if (!_internal_has_error()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.error_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.error_.IsDefault()) {
+    _impl_.error_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void CodeGeneratorResponse::set_allocated_error(std::string* error) {
+  if (error != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.error_.SetAllocated(error, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.error_.IsDefault()) {
+    _impl_.error_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+
+// optional uint64 supported_features = 2;
+inline bool CodeGeneratorResponse::_internal_has_supported_features() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool CodeGeneratorResponse::has_supported_features() const {
+  return _internal_has_supported_features();
+}
+inline void CodeGeneratorResponse::clear_supported_features() {
+  _impl_.supported_features_ = uint64_t{0u};
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline uint64_t CodeGeneratorResponse::_internal_supported_features() const {
+  return _impl_.supported_features_;
+}
+inline uint64_t CodeGeneratorResponse::supported_features() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.supported_features)
+  return _internal_supported_features();
+}
+inline void CodeGeneratorResponse::_internal_set_supported_features(uint64_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.supported_features_ = value;
+}
+inline void CodeGeneratorResponse::set_supported_features(uint64_t value) {
+  _internal_set_supported_features(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.supported_features)
+}
+
+// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+inline int CodeGeneratorResponse::_internal_file_size() const {
+  return _impl_.file_.size();
+}
+inline int CodeGeneratorResponse::file_size() const {
+  return _internal_file_size();
+}
+inline void CodeGeneratorResponse::clear_file() {
+  _impl_.file_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return _impl_.file_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >*
+CodeGeneratorResponse::mutable_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return &_impl_.file_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::_internal_file(int index) const {
+  return _impl_.file_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return _internal_file(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::_internal_add_file() {
+  return _impl_.file_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+  ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* _add = _internal_add_file();
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >&
+CodeGeneratorResponse::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return _impl_.file_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace compiler
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature>() {
+  return ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fcompiler_2fplugin_2eproto
diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto
new file mode 100644
index 0000000..9242aac
--- /dev/null
+++ b/src/google/protobuf/compiler/plugin.proto
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// WARNING:  The plugin interface is currently EXPERIMENTAL and is subject to
+//   change.
+//
+// protoc (aka the Protocol Compiler) can be extended via plugins.  A plugin is
+// just a program that reads a CodeGeneratorRequest from stdin and writes a
+// CodeGeneratorResponse to stdout.
+//
+// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead
+// of dealing with the raw protocol defined here.
+//
+// A plugin executable needs only to be placed somewhere in the path.  The
+// plugin should be named "protoc-gen-$NAME", and will then be used when the
+// flag "--${NAME}_out" is passed to protoc.
+
+syntax = "proto2";
+
+package google.protobuf.compiler;
+option java_package = "com.google.protobuf.compiler";
+option java_outer_classname = "PluginProtos";
+
+option go_package = "google.golang.org/protobuf/types/pluginpb";
+
+import "google/protobuf/descriptor.proto";
+
+// The version number of protocol compiler.
+message Version {
+  optional int32 major = 1;
+  optional int32 minor = 2;
+  optional int32 patch = 3;
+  // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
+  // be empty for mainline stable releases.
+  optional string suffix = 4;
+}
+
+// An encoded CodeGeneratorRequest is written to the plugin's stdin.
+message CodeGeneratorRequest {
+  // The .proto files that were explicitly listed on the command-line.  The
+  // code generator should generate code only for these files.  Each file's
+  // descriptor will be included in proto_file, below.
+  repeated string file_to_generate = 1;
+
+  // The generator parameter passed on the command-line.
+  optional string parameter = 2;
+
+  // FileDescriptorProtos for all files in files_to_generate and everything
+  // they import.  The files will appear in topological order, so each file
+  // appears before any file that imports it.
+  //
+  // protoc guarantees that all proto_files will be written after
+  // the fields above, even though this is not technically guaranteed by the
+  // protobuf wire format.  This theoretically could allow a plugin to stream
+  // in the FileDescriptorProtos and handle them one by one rather than read
+  // the entire set into memory at once.  However, as of this writing, this
+  // is not similarly optimized on protoc's end -- it will store all fields in
+  // memory at once before sending them to the plugin.
+  //
+  // Type names of fields and extensions in the FileDescriptorProto are always
+  // fully qualified.
+  repeated FileDescriptorProto proto_file = 15;
+
+  // The version number of protocol compiler.
+  optional Version compiler_version = 3;
+
+}
+
+// The plugin writes an encoded CodeGeneratorResponse to stdout.
+message CodeGeneratorResponse {
+  // Error message.  If non-empty, code generation failed.  The plugin process
+  // should exit with status code zero even if it reports an error in this way.
+  //
+  // This should be used to indicate errors in .proto files which prevent the
+  // code generator from generating correct code.  Errors which indicate a
+  // problem in protoc itself -- such as the input CodeGeneratorRequest being
+  // unparseable -- should be reported by writing a message to stderr and
+  // exiting with a non-zero status code.
+  optional string error = 1;
+
+  // A bitmask of supported features that the code generator supports.
+  // This is a bitwise "or" of values from the Feature enum.
+  optional uint64 supported_features = 2;
+
+  // Sync with code_generator.h.
+  enum Feature {
+    FEATURE_NONE = 0;
+    FEATURE_PROTO3_OPTIONAL = 1;
+  }
+
+  // Represents a single generated file.
+  message File {
+    // The file name, relative to the output directory.  The name must not
+    // contain "." or ".." components and must be relative, not be absolute (so,
+    // the file cannot lie outside the output directory).  "/" must be used as
+    // the path separator, not "\".
+    //
+    // If the name is omitted, the content will be appended to the previous
+    // file.  This allows the generator to break large files into small chunks,
+    // and allows the generated text to be streamed back to protoc so that large
+    // files need not reside completely in memory at one time.  Note that as of
+    // this writing protoc does not optimize for this -- it will read the entire
+    // CodeGeneratorResponse before writing files to disk.
+    optional string name = 1;
+
+    // If non-empty, indicates that the named file should already exist, and the
+    // content here is to be inserted into that file at a defined insertion
+    // point.  This feature allows a code generator to extend the output
+    // produced by another code generator.  The original generator may provide
+    // insertion points by placing special annotations in the file that look
+    // like:
+    //   @@protoc_insertion_point(NAME)
+    // The annotation can have arbitrary text before and after it on the line,
+    // which allows it to be placed in a comment.  NAME should be replaced with
+    // an identifier naming the point -- this is what other generators will use
+    // as the insertion_point.  Code inserted at this point will be placed
+    // immediately above the line containing the insertion point (thus multiple
+    // insertions to the same point will come out in the order they were added).
+    // The double-@ is intended to make it unlikely that the generated code
+    // could contain things that look like insertion points by accident.
+    //
+    // For example, the C++ code generator places the following line in the
+    // .pb.h files that it generates:
+    //   // @@protoc_insertion_point(namespace_scope)
+    // This line appears within the scope of the file's package namespace, but
+    // outside of any particular class.  Another plugin can then specify the
+    // insertion_point "namespace_scope" to generate additional classes or
+    // other declarations that should be placed in this scope.
+    //
+    // Note that if the line containing the insertion point begins with
+    // whitespace, the same whitespace will be added to every line of the
+    // inserted text.  This is useful for languages like Python, where
+    // indentation matters.  In these languages, the insertion point comment
+    // should be indented the same amount as any inserted code will need to be
+    // in order to work correctly in that context.
+    //
+    // The code generator that generates the initial file and the one which
+    // inserts into it must both run as part of a single invocation of protoc.
+    // Code generators are executed in the order in which they appear on the
+    // command line.
+    //
+    // If |insertion_point| is present, |name| must also be present.
+    optional string insertion_point = 2;
+
+    // The file contents.
+    optional string content = 15;
+
+    // Information describing the file content being inserted. If an insertion
+    // point is used, this information will be appropriately offset and inserted
+    // into the code generation metadata for the generated files.
+    optional GeneratedCodeInfo generated_code_info = 16;
+  }
+  repeated File file = 15;
+}
diff --git a/src/google/protobuf/compiler/python/generator.cc b/src/google/protobuf/compiler/python/generator.cc
new file mode 100644
index 0000000..d8d6d74
--- /dev/null
+++ b/src/google/protobuf/compiler/python/generator.cc
@@ -0,0 +1,1393 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: robinson@google.com (Will Robinson)
+//
+// This module outputs pure-Python protocol message classes that will
+// largely be constructed at runtime via the metaclass in reflection.py.
+// In other words, our job is basically to output a Python equivalent
+// of the C++ *Descriptor objects, and fix up all circular references
+// within these objects.
+//
+// Note that the runtime performance of protocol message classes created in
+// this way is expected to be lousy.  The plan is to create an alternate
+// generator that outputs a Python/C extension module that lets
+// performance-minded Python code leverage the fast C++ implementation
+// directly.
+
+#include <google/protobuf/compiler/python/generator.h>
+
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/python/helpers.h>
+#include <google/protobuf/compiler/python/pyi_generator.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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+namespace {
+// Returns the alias we assign to the module of the given .proto filename
+// when importing. See testPackageInitializationImport in
+// net/proto2/python/internal/reflection_test.py
+// to see why we need the alias.
+std::string ModuleAlias(const std::string& filename) {
+  std::string module_name = ModuleName(filename);
+  // We can't have dots in the module name, so we replace each with _dot_.
+  // But that could lead to a collision between a.b and a_dot_b, so we also
+  // duplicate each underscore.
+  GlobalReplaceSubstring("_", "__", &module_name);
+  GlobalReplaceSubstring(".", "_dot_", &module_name);
+  return module_name;
+}
+
+// Name of the class attribute where we store the Python
+// descriptor.Descriptor instance for the generated class.
+// Must stay consistent with the _DESCRIPTOR_KEY constant
+// in proto2/public/reflection.py.
+const char kDescriptorKey[] = "DESCRIPTOR";
+
+
+// file output by this generator.
+void PrintTopBoilerplate(io::Printer* printer, const FileDescriptor* file,
+                         bool descriptor_proto) {
+  // TODO(robinson): Allow parameterization of Python version?
+  printer->Print(
+      "# -*- coding: utf-8 -*-\n"
+      "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "# source: $filename$\n"
+      "\"\"\"Generated protocol buffer code.\"\"\"\n",
+      "filename", file->name());
+  printer->Print(
+      "from google.protobuf.internal import builder as _builder\n"
+      "from google.protobuf import descriptor as _descriptor\n"
+      "from google.protobuf import descriptor_pool as "
+      "_descriptor_pool\n"
+      "from google.protobuf import symbol_database as "
+      "_symbol_database\n");
+
+  printer->Print("# @@protoc_insertion_point(imports)\n\n");
+  printer->Print("_sym_db = _symbol_database.Default()\n");
+  printer->Print("\n\n");
+}
+
+// Returns a Python literal giving the default value for a field.
+// If the field specifies no explicit default value, we'll return
+// the default default value for the field type (zero for numbers,
+// empty string for strings, empty list for repeated fields, and
+// None for non-repeated, composite fields).
+//
+// TODO(robinson): Unify with code from
+// //compiler/cpp/internal/primitive_field.cc
+// //compiler/cpp/internal/enum_field.cc
+// //compiler/cpp/internal/string_field.cc
+std::string StringifyDefaultValue(const FieldDescriptor& field) {
+  if (field.is_repeated()) {
+    return "[]";
+  }
+
+  switch (field.cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return StrCat(field.default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return StrCat(field.default_value_uint32());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return StrCat(field.default_value_int64());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return StrCat(field.default_value_uint64());
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value = field.default_value_double();
+      if (value == std::numeric_limits<double>::infinity()) {
+        // Python pre-2.6 on Windows does not parse "inf" correctly.  However,
+        // a numeric literal that is too big for a double will become infinity.
+        return "1e10000";
+      } else if (value == -std::numeric_limits<double>::infinity()) {
+        // See above.
+        return "-1e10000";
+      } else if (value != value) {
+        // infinity * 0 = nan
+        return "(1e10000 * 0)";
+      } else {
+        return "float(" + SimpleDtoa(value) + ")";
+      }
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value = field.default_value_float();
+      if (value == std::numeric_limits<float>::infinity()) {
+        // Python pre-2.6 on Windows does not parse "inf" correctly.  However,
+        // a numeric literal that is too big for a double will become infinity.
+        return "1e10000";
+      } else if (value == -std::numeric_limits<float>::infinity()) {
+        // See above.
+        return "-1e10000";
+      } else if (value != value) {
+        // infinity - infinity = nan
+        return "(1e10000 * 0)";
+      } else {
+        return "float(" + SimpleFtoa(value) + ")";
+      }
+    }
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field.default_value_bool() ? "True" : "False";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return StrCat(field.default_value_enum()->number());
+    case FieldDescriptor::CPPTYPE_STRING:
+      return "b\"" + CEscape(field.default_value_string()) +
+             (field.type() != FieldDescriptor::TYPE_STRING
+                  ? "\""
+                  : "\".decode('utf-8')");
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "None";
+  }
+  // (We could add a default case above but then we wouldn't get the nice
+  // compiler warning when a new type is added.)
+  GOOGLE_LOG(FATAL) << "Not reached.";
+  return "";
+}
+
+std::string StringifySyntax(FileDescriptor::Syntax syntax) {
+  switch (syntax) {
+    case FileDescriptor::SYNTAX_PROTO2:
+      return "proto2";
+    case FileDescriptor::SYNTAX_PROTO3:
+      return "proto3";
+    case FileDescriptor::SYNTAX_UNKNOWN:
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports proto2 "
+                    "and proto3 syntax.";
+      return "";
+  }
+}
+
+}  // namespace
+
+Generator::Generator() : file_(nullptr) {}
+
+Generator::~Generator() {}
+
+uint64_t Generator::GetSupportedFeatures() const {
+  return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
+}
+
+bool Generator::Generate(const FileDescriptor* file,
+                         const std::string& parameter,
+                         GeneratorContext* context, std::string* error) const {
+  // -----------------------------------------------------------------
+  // parse generator options
+  bool cpp_generated_lib_linked = false;
+
+  std::vector<std::pair<std::string, std::string> > options;
+  ParseGeneratorParameter(parameter, &options);
+
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "cpp_generated_lib_linked") {
+      cpp_generated_lib_linked = true;
+    } else if (options[i].first == "pyi_out") {
+      python::PyiGenerator pyi_generator;
+      if (!pyi_generator.Generate(file, "", context, error)) {
+        return false;
+      }
+    } else {
+      *error = "Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  // Completely serialize all Generate() calls on this instance.  The
+  // thread-safety constraints of the CodeGenerator interface aren't clear so
+  // just be as conservative as possible.  It's easier to relax this later if
+  // we need to, but I doubt it will be an issue.
+  // TODO(kenton):  The proper thing to do would be to allocate any state on
+  //   the stack and use that, so that the Generator class itself does not need
+  //   to have any mutable members.  Then it is implicitly thread-safe.
+  MutexLock lock(&mutex_);
+  file_ = file;
+
+  std::string filename = GetFileName(file, ".py");
+  pure_python_workable_ = !cpp_generated_lib_linked;
+  if (HasPrefixString(file->name(), "google/protobuf/")) {
+    pure_python_workable_ = true;
+  }
+
+  FileDescriptorProto fdp;
+  file_->CopyTo(&fdp);
+  fdp.SerializeToString(&file_descriptor_serialized_);
+
+
+  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  GOOGLE_CHECK(output.get());
+  io::Printer printer(output.get(), '$');
+  printer_ = &printer;
+
+  PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto());
+  if (pure_python_workable_) {
+    PrintImports();
+  }
+  PrintFileDescriptor();
+  if (pure_python_workable_) {
+    if (GeneratingDescriptorProto()) {
+      printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n");
+      printer_->Indent();
+      // Create enums before message descriptors
+      PrintAllNestedEnumsInFile();
+      PrintMessageDescriptors();
+      FixForeignFieldsInDescriptors();
+      printer_->Outdent();
+      printer_->Print("else:\n");
+      printer_->Indent();
+    }
+    // Find the message descriptors first and then use the message
+    // descriptor to find enums.
+    printer_->Print(
+        "_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n");
+    if (GeneratingDescriptorProto()) {
+      printer_->Outdent();
+    }
+  }
+  std::string module_name = ModuleName(file->name());
+  printer_->Print(
+      "_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, '$module_name$', "
+      "globals())\n",
+      "module_name", module_name);
+  if (pure_python_workable_) {
+    printer.Print("if _descriptor._USE_C_DESCRIPTORS == False:\n");
+    printer_->Indent();
+
+    // We have to fix up the extensions after the message classes themselves,
+    // since they need to call static RegisterExtension() methods on these
+    // classes.
+    FixForeignFieldsInExtensions();
+    // Descriptor options may have custom extensions. These custom options
+    // can only be successfully parsed after we register corresponding
+    // extensions. Therefore we parse all options again here to recognize
+    // custom options that may be unknown when we define the descriptors.
+    // This does not apply to services because they are not used by extensions.
+    FixAllDescriptorOptions();
+
+    // Set serialized_start and serialized_end.
+    SetSerializedPbInterval();
+
+    printer_->Outdent();
+  }
+  if (HasGenericServices(file)) {
+    printer_->Print(
+        "_builder.BuildServices(DESCRIPTOR, '$module_name$', globals())\n",
+        "module_name", module_name);
+  }
+
+  printer.Print("# @@protoc_insertion_point(module_scope)\n");
+
+  return !printer.failed();
+}
+
+// Prints Python imports for all modules imported by |file|.
+void Generator::PrintImports() const {
+  for (int i = 0; i < file_->dependency_count(); ++i) {
+    const std::string& filename = file_->dependency(i)->name();
+
+    std::string module_name = ModuleName(filename);
+    std::string module_alias = ModuleAlias(filename);
+    if (ContainsPythonKeyword(module_name)) {
+      // If the module path contains a Python keyword, we have to quote the
+      // module name and import it using importlib. Otherwise the usual kind of
+      // import statement would result in a syntax error from the presence of
+      // the keyword.
+      printer_->Print("import importlib\n");
+      printer_->Print("$alias$ = importlib.import_module('$name$')\n", "alias",
+                      module_alias, "name", module_name);
+    } else {
+      int last_dot_pos = module_name.rfind('.');
+      std::string import_statement;
+      if (last_dot_pos == std::string::npos) {
+        // NOTE(petya): this is not tested as it would require a protocol buffer
+        // outside of any package, and I don't think that is easily achievable.
+        import_statement = "import " + module_name;
+      } else {
+        import_statement = "from " + module_name.substr(0, last_dot_pos) +
+                           " import " + module_name.substr(last_dot_pos + 1);
+      }
+      printer_->Print("$statement$ as $alias$\n", "statement", import_statement,
+                      "alias", module_alias);
+    }
+
+    CopyPublicDependenciesAliases(module_alias, file_->dependency(i));
+  }
+  printer_->Print("\n");
+
+  // Print public imports.
+  for (int i = 0; i < file_->public_dependency_count(); ++i) {
+    std::string module_name = ModuleName(file_->public_dependency(i)->name());
+    printer_->Print("from $module$ import *\n", "module", module_name);
+  }
+  printer_->Print("\n");
+}
+
+// Prints the single file descriptor for this file.
+void Generator::PrintFileDescriptor() const {
+  std::map<std::string, std::string> m;
+  m["descriptor_name"] = kDescriptorKey;
+  m["name"] = file_->name();
+  m["package"] = file_->package();
+  m["syntax"] = StringifySyntax(file_->syntax());
+  m["options"] = OptionsValue(file_->options().SerializeAsString());
+  m["serialized_descriptor"] = strings::CHexEscape(file_descriptor_serialized_);
+  if (GeneratingDescriptorProto()) {
+    printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n");
+    printer_->Indent();
+    // Pure python's AddSerializedFile() depend on the generated
+    // descriptor_pb2.py thus we can not use AddSerializedFile() when
+    // generated descriptor.proto for pure python.
+    const char file_descriptor_template[] =
+        "$descriptor_name$ = _descriptor.FileDescriptor(\n"
+        "  name='$name$',\n"
+        "  package='$package$',\n"
+        "  syntax='$syntax$',\n"
+        "  serialized_options=$options$,\n"
+        "  create_key=_descriptor._internal_create_key,\n";
+    printer_->Print(m, file_descriptor_template);
+    printer_->Indent();
+    if (pure_python_workable_) {
+      printer_->Print("serialized_pb=b'$value$'\n", "value",
+                      strings::CHexEscape(file_descriptor_serialized_));
+      if (file_->dependency_count() != 0) {
+        printer_->Print(",\ndependencies=[");
+        for (int i = 0; i < file_->dependency_count(); ++i) {
+          std::string module_alias = ModuleAlias(file_->dependency(i)->name());
+          printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
+                          module_alias);
+        }
+        printer_->Print("]");
+      }
+      if (file_->public_dependency_count() > 0) {
+        printer_->Print(",\npublic_dependencies=[");
+        for (int i = 0; i < file_->public_dependency_count(); ++i) {
+          std::string module_alias =
+              ModuleAlias(file_->public_dependency(i)->name());
+          printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
+                          module_alias);
+        }
+        printer_->Print("]");
+      }
+    } else {
+      printer_->Print("serialized_pb=''\n");
+    }
+
+    // TODO(falk): Also print options and fix the message_type, enum_type,
+    //             service and extension later in the generation.
+
+    printer_->Outdent();
+    printer_->Print(")\n");
+
+    printer_->Outdent();
+    printer_->Print("else:\n");
+    printer_->Indent();
+  }
+  printer_->Print(m,
+                  "$descriptor_name$ = "
+                  "_descriptor_pool.Default().AddSerializedFile(b'$serialized_"
+                  "descriptor$')\n");
+  if (GeneratingDescriptorProto()) {
+    printer_->Outdent();
+  }
+  printer_->Print("\n");
+}
+
+// Prints all enums contained in all message types in |file|.
+void Generator::PrintAllNestedEnumsInFile() const {
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    PrintNestedEnums(*file_->message_type(i));
+  }
+}
+
+// Prints a Python statement assigning the appropriate module-level
+// enum name to a Python EnumDescriptor object equivalent to
+// enum_descriptor.
+void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
+  std::map<std::string, std::string> m;
+  std::string module_level_descriptor_name =
+      ModuleLevelDescriptorName(enum_descriptor);
+  m["descriptor_name"] = module_level_descriptor_name;
+  m["name"] = enum_descriptor.name();
+  m["full_name"] = enum_descriptor.full_name();
+  m["file"] = kDescriptorKey;
+  const char enum_descriptor_template[] =
+      "$descriptor_name$ = _descriptor.EnumDescriptor(\n"
+      "  name='$name$',\n"
+      "  full_name='$full_name$',\n"
+      "  filename=None,\n"
+      "  file=$file$,\n"
+      "  create_key=_descriptor._internal_create_key,\n"
+      "  values=[\n";
+  std::string options_string;
+  enum_descriptor.options().SerializeToString(&options_string);
+  printer_->Print(m, enum_descriptor_template);
+  printer_->Indent();
+  printer_->Indent();
+
+  if (pure_python_workable_) {
+    for (int i = 0; i < enum_descriptor.value_count(); ++i) {
+      PrintEnumValueDescriptor(*enum_descriptor.value(i));
+      printer_->Print(",\n");
+    }
+  }
+
+  printer_->Outdent();
+  printer_->Print("],\n");
+  printer_->Print("containing_type=None,\n");
+  printer_->Print("serialized_options=$options_value$,\n", "options_value",
+                  OptionsValue(options_string));
+  EnumDescriptorProto edp;
+  printer_->Outdent();
+  printer_->Print(")\n");
+  if (pure_python_workable_) {
+    printer_->Print("_sym_db.RegisterEnumDescriptor($name$)\n", "name",
+                    module_level_descriptor_name);
+  }
+  printer_->Print("\n");
+}
+
+// Recursively prints enums in nested types within descriptor, then
+// prints enums contained at the top level in descriptor.
+void Generator::PrintNestedEnums(const Descriptor& descriptor) const {
+  for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+    PrintNestedEnums(*descriptor.nested_type(i));
+  }
+
+  for (int i = 0; i < descriptor.enum_type_count(); ++i) {
+    PrintEnum(*descriptor.enum_type(i));
+  }
+}
+
+// Prints Python equivalents of all Descriptors in |file|.
+void Generator::PrintMessageDescriptors() const {
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    PrintDescriptor(*file_->message_type(i));
+    printer_->Print("\n");
+  }
+}
+
+void Generator::PrintServiceDescriptors() const {
+  for (int i = 0; i < file_->service_count(); ++i) {
+    PrintServiceDescriptor(*file_->service(i));
+  }
+}
+
+void Generator::PrintServices() const {
+  for (int i = 0; i < file_->service_count(); ++i) {
+    PrintServiceClass(*file_->service(i));
+    PrintServiceStub(*file_->service(i));
+    printer_->Print("\n");
+  }
+}
+
+void Generator::PrintServiceDescriptor(
+    const ServiceDescriptor& descriptor) const {
+  std::map<std::string, std::string> m;
+  m["service_name"] = ModuleLevelServiceDescriptorName(descriptor);
+  m["name"] = descriptor.name();
+  m["file"] = kDescriptorKey;
+  printer_->Print(m, "$service_name$ = $file$.services_by_name['$name$']\n");
+}
+
+void Generator::PrintDescriptorKeyAndModuleName(
+    const ServiceDescriptor& descriptor) const {
+  std::string name = ModuleLevelServiceDescriptorName(descriptor);
+  if (!pure_python_workable_) {
+    name = "_descriptor.ServiceDescriptor(full_name='" +
+           descriptor.full_name() + "')";
+  }
+  printer_->Print("$descriptor_key$ = $descriptor_name$,\n", "descriptor_key",
+                  kDescriptorKey, "descriptor_name", name);
+  std::string module_name = ModuleName(file_->name());
+  printer_->Print("__module__ = '$module_name$'\n", "module_name", module_name);
+}
+
+void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
+  // Print the service.
+  printer_->Print(
+      "$class_name$ = service_reflection.GeneratedServiceType("
+      "'$class_name$', (_service.Service,), dict(\n",
+      "class_name", descriptor.name());
+  printer_->Indent();
+  Generator::PrintDescriptorKeyAndModuleName(descriptor);
+  printer_->Print("))\n\n");
+  printer_->Outdent();
+}
+
+void Generator::PrintServiceStub(const ServiceDescriptor& descriptor) const {
+  // Print the service stub.
+  printer_->Print(
+      "$class_name$_Stub = "
+      "service_reflection.GeneratedServiceStubType("
+      "'$class_name$_Stub', ($class_name$,), dict(\n",
+      "class_name", descriptor.name());
+  printer_->Indent();
+  Generator::PrintDescriptorKeyAndModuleName(descriptor);
+  printer_->Print("))\n\n");
+  printer_->Outdent();
+}
+
+// Prints statement assigning ModuleLevelDescriptorName(message_descriptor)
+// to a Python Descriptor object for message_descriptor.
+//
+// Mutually recursive with PrintNestedDescriptors().
+void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
+  std::map<std::string, std::string> m;
+  m["name"] = message_descriptor.name();
+  m["full_name"] = message_descriptor.full_name();
+  m["file"] = kDescriptorKey;
+
+  PrintNestedDescriptors(message_descriptor);
+
+  printer_->Print("\n");
+  printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n",
+                  "descriptor_name",
+                  ModuleLevelDescriptorName(message_descriptor));
+  printer_->Indent();
+  const char required_function_arguments[] =
+      "name='$name$',\n"
+      "full_name='$full_name$',\n"
+      "filename=None,\n"
+      "file=$file$,\n"
+      "containing_type=None,\n"
+      "create_key=_descriptor._internal_create_key,\n";
+  printer_->Print(m, required_function_arguments);
+  PrintFieldsInDescriptor(message_descriptor);
+  PrintExtensionsInDescriptor(message_descriptor);
+
+  // Nested types
+  printer_->Print("nested_types=[");
+  for (int i = 0; i < message_descriptor.nested_type_count(); ++i) {
+    const std::string nested_name =
+        ModuleLevelDescriptorName(*message_descriptor.nested_type(i));
+    printer_->Print("$name$, ", "name", nested_name);
+  }
+  printer_->Print("],\n");
+
+  // Enum types
+  printer_->Print("enum_types=[\n");
+  printer_->Indent();
+  for (int i = 0; i < message_descriptor.enum_type_count(); ++i) {
+    const std::string descriptor_name =
+        ModuleLevelDescriptorName(*message_descriptor.enum_type(i));
+    printer_->Print(descriptor_name.c_str());
+    printer_->Print(",\n");
+  }
+  printer_->Outdent();
+  printer_->Print("],\n");
+  std::string options_string;
+  message_descriptor.options().SerializeToString(&options_string);
+  printer_->Print(
+      "serialized_options=$options_value$,\n"
+      "is_extendable=$extendable$,\n"
+      "syntax='$syntax$'",
+      "options_value", OptionsValue(options_string), "extendable",
+      message_descriptor.extension_range_count() > 0 ? "True" : "False",
+      "syntax", StringifySyntax(message_descriptor.file()->syntax()));
+  printer_->Print(",\n");
+
+  // Extension ranges
+  printer_->Print("extension_ranges=[");
+  for (int i = 0; i < message_descriptor.extension_range_count(); ++i) {
+    const Descriptor::ExtensionRange* range =
+        message_descriptor.extension_range(i);
+    printer_->Print("($start$, $end$), ", "start", StrCat(range->start),
+                    "end", StrCat(range->end));
+  }
+  printer_->Print("],\n");
+  printer_->Print("oneofs=[\n");
+  printer_->Indent();
+  for (int i = 0; i < message_descriptor.oneof_decl_count(); ++i) {
+    const OneofDescriptor* desc = message_descriptor.oneof_decl(i);
+    m.clear();
+    m["name"] = desc->name();
+    m["full_name"] = desc->full_name();
+    m["index"] = StrCat(desc->index());
+    options_string = OptionsValue(desc->options().SerializeAsString());
+    if (options_string == "None") {
+      m["serialized_options"] = "";
+    } else {
+      m["serialized_options"] = ", serialized_options=" + options_string;
+    }
+    printer_->Print(m,
+                    "_descriptor.OneofDescriptor(\n"
+                    "  name='$name$', full_name='$full_name$',\n"
+                    "  index=$index$, containing_type=None,\n"
+                    "  create_key=_descriptor._internal_create_key,\n"
+                    "fields=[]$serialized_options$),\n");
+  }
+  printer_->Outdent();
+  printer_->Print("],\n");
+
+  printer_->Outdent();
+  printer_->Print(")\n");
+}
+
+// Prints Python Descriptor objects for all nested types contained in
+// message_descriptor.
+//
+// Mutually recursive with PrintDescriptor().
+void Generator::PrintNestedDescriptors(
+    const Descriptor& containing_descriptor) const {
+  for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
+    PrintDescriptor(*containing_descriptor.nested_type(i));
+  }
+}
+
+// Prints all messages in |file|.
+void Generator::PrintMessages() const {
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    std::vector<std::string> to_register;
+    PrintMessage(*file_->message_type(i), "", &to_register, false);
+    for (int j = 0; j < to_register.size(); ++j) {
+      printer_->Print("_sym_db.RegisterMessage($name$)\n", "name",
+                      ResolveKeyword(to_register[j]));
+    }
+    printer_->Print("\n");
+  }
+}
+
+// Prints a Python class for the given message descriptor.  We defer to the
+// metaclass to do almost all of the work of actually creating a useful class.
+// The purpose of this function and its many helper functions above is merely
+// to output a Python version of the descriptors, which the metaclass in
+// reflection.py will use to construct the meat of the class itself.
+//
+// Mutually recursive with PrintNestedMessages().
+// Collect nested message names to_register for the symbol_database.
+void Generator::PrintMessage(const Descriptor& message_descriptor,
+                             const std::string& prefix,
+                             std::vector<std::string>* to_register,
+                             bool is_nested) const {
+  std::string qualified_name;
+  if (is_nested) {
+    if (IsPythonKeyword(message_descriptor.name())) {
+      qualified_name =
+          "getattr(" + prefix + ", '" + message_descriptor.name() + "')";
+    } else {
+      qualified_name = prefix + "." + message_descriptor.name();
+    }
+    printer_->Print(
+        "'$name$' : _reflection.GeneratedProtocolMessageType('$name$', "
+        "(_message.Message,), {\n",
+        "name", message_descriptor.name());
+  } else {
+    qualified_name = ResolveKeyword(message_descriptor.name());
+    printer_->Print(
+        "$qualified_name$ = _reflection.GeneratedProtocolMessageType('$name$', "
+        "(_message.Message,), {\n",
+        "qualified_name", qualified_name, "name", message_descriptor.name());
+  }
+  printer_->Indent();
+
+  to_register->push_back(qualified_name);
+
+  PrintNestedMessages(message_descriptor, qualified_name, to_register);
+  std::map<std::string, std::string> m;
+  m["descriptor_key"] = kDescriptorKey;
+  if (pure_python_workable_) {
+    m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
+  } else {
+    m["descriptor_name"] = "_descriptor.Descriptor(full_name='" +
+                           message_descriptor.full_name() + "')";
+  }
+  printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n");
+  std::string module_name = ModuleName(file_->name());
+  printer_->Print("'__module__' : '$module_name$'\n", "module_name",
+                  module_name);
+  printer_->Print("# @@protoc_insertion_point(class_scope:$full_name$)\n",
+                  "full_name", message_descriptor.full_name());
+  printer_->Print("})\n");
+  printer_->Outdent();
+}
+
+// Prints all nested messages within |containing_descriptor|.
+// Mutually recursive with PrintMessage().
+void Generator::PrintNestedMessages(
+    const Descriptor& containing_descriptor, const std::string& prefix,
+    std::vector<std::string>* to_register) const {
+  for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
+    printer_->Print("\n");
+    PrintMessage(*containing_descriptor.nested_type(i), prefix, to_register,
+                 true);
+    printer_->Print(",\n");
+  }
+}
+
+// Recursively fixes foreign fields in all nested types in |descriptor|, then
+// sets the message_type and enum_type of all message and enum fields to point
+// to their respective descriptors.
+// Args:
+//   descriptor: descriptor to print fields for.
+//   containing_descriptor: if descriptor is a nested type, this is its
+//       containing type, or NULL if this is a root/top-level type.
+void Generator::FixForeignFieldsInDescriptor(
+    const Descriptor& descriptor,
+    const Descriptor* containing_descriptor) const {
+  for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+    FixForeignFieldsInDescriptor(*descriptor.nested_type(i), &descriptor);
+  }
+
+  for (int i = 0; i < descriptor.field_count(); ++i) {
+    const FieldDescriptor& field_descriptor = *descriptor.field(i);
+    FixForeignFieldsInField(&descriptor, field_descriptor, "fields_by_name");
+  }
+
+  FixContainingTypeInDescriptor(descriptor, containing_descriptor);
+  for (int i = 0; i < descriptor.enum_type_count(); ++i) {
+    const EnumDescriptor& enum_descriptor = *descriptor.enum_type(i);
+    FixContainingTypeInDescriptor(enum_descriptor, &descriptor);
+  }
+  for (int i = 0; i < descriptor.oneof_decl_count(); ++i) {
+    std::map<std::string, std::string> m;
+    const OneofDescriptor* oneof = descriptor.oneof_decl(i);
+    m["descriptor_name"] = ModuleLevelDescriptorName(descriptor);
+    m["oneof_name"] = oneof->name();
+    for (int j = 0; j < oneof->field_count(); ++j) {
+      m["field_name"] = oneof->field(j)->name();
+      printer_->Print(
+          m,
+          "$descriptor_name$.oneofs_by_name['$oneof_name$'].fields.append(\n"
+          "  $descriptor_name$.fields_by_name['$field_name$'])\n");
+      printer_->Print(
+          m,
+          "$descriptor_name$.fields_by_name['$field_name$'].containing_oneof = "
+          "$descriptor_name$.oneofs_by_name['$oneof_name$']\n");
+    }
+  }
+}
+
+void Generator::AddMessageToFileDescriptor(const Descriptor& descriptor) const {
+  std::map<std::string, std::string> m;
+  m["descriptor_name"] = kDescriptorKey;
+  m["message_name"] = descriptor.name();
+  m["message_descriptor_name"] = ModuleLevelDescriptorName(descriptor);
+  const char file_descriptor_template[] =
+      "$descriptor_name$.message_types_by_name['$message_name$'] = "
+      "$message_descriptor_name$\n";
+  printer_->Print(m, file_descriptor_template);
+}
+
+void Generator::AddServiceToFileDescriptor(
+    const ServiceDescriptor& descriptor) const {
+  std::map<std::string, std::string> m;
+  m["descriptor_name"] = kDescriptorKey;
+  m["service_name"] = descriptor.name();
+  m["service_descriptor_name"] = ModuleLevelServiceDescriptorName(descriptor);
+  const char file_descriptor_template[] =
+      "$descriptor_name$.services_by_name['$service_name$'] = "
+      "$service_descriptor_name$\n";
+  printer_->Print(m, file_descriptor_template);
+}
+
+void Generator::AddEnumToFileDescriptor(
+    const EnumDescriptor& descriptor) const {
+  std::map<std::string, std::string> m;
+  m["descriptor_name"] = kDescriptorKey;
+  m["enum_name"] = descriptor.name();
+  m["enum_descriptor_name"] = ModuleLevelDescriptorName(descriptor);
+  const char file_descriptor_template[] =
+      "$descriptor_name$.enum_types_by_name['$enum_name$'] = "
+      "$enum_descriptor_name$\n";
+  printer_->Print(m, file_descriptor_template);
+}
+
+void Generator::AddExtensionToFileDescriptor(
+    const FieldDescriptor& descriptor) const {
+  std::map<std::string, std::string> m;
+  m["descriptor_name"] = kDescriptorKey;
+  m["field_name"] = descriptor.name();
+  m["resolved_name"] = ResolveKeyword(descriptor.name());
+  const char file_descriptor_template[] =
+      "$descriptor_name$.extensions_by_name['$field_name$'] = "
+      "$resolved_name$\n";
+  printer_->Print(m, file_descriptor_template);
+}
+
+// Sets any necessary message_type and enum_type attributes
+// for the Python version of |field|.
+//
+// containing_type may be NULL, in which case this is a module-level field.
+//
+// python_dict_name is the name of the Python dict where we should
+// look the field up in the containing type.  (e.g., fields_by_name
+// or extensions_by_name).  We ignore python_dict_name if containing_type
+// is NULL.
+void Generator::FixForeignFieldsInField(
+    const Descriptor* containing_type, const FieldDescriptor& field,
+    const std::string& python_dict_name) const {
+  const std::string field_referencing_expression =
+      FieldReferencingExpression(containing_type, field, python_dict_name);
+  std::map<std::string, std::string> m;
+  m["field_ref"] = field_referencing_expression;
+  const Descriptor* foreign_message_type = field.message_type();
+  if (foreign_message_type) {
+    m["foreign_type"] = ModuleLevelDescriptorName(*foreign_message_type);
+    printer_->Print(m, "$field_ref$.message_type = $foreign_type$\n");
+  }
+  const EnumDescriptor* enum_type = field.enum_type();
+  if (enum_type) {
+    m["enum_type"] = ModuleLevelDescriptorName(*enum_type);
+    printer_->Print(m, "$field_ref$.enum_type = $enum_type$\n");
+  }
+}
+
+// Returns the module-level expression for the given FieldDescriptor.
+// Only works for fields in the .proto file this Generator is generating for.
+//
+// containing_type may be NULL, in which case this is a module-level field.
+//
+// python_dict_name is the name of the Python dict where we should
+// look the field up in the containing type.  (e.g., fields_by_name
+// or extensions_by_name).  We ignore python_dict_name if containing_type
+// is NULL.
+std::string Generator::FieldReferencingExpression(
+    const Descriptor* containing_type, const FieldDescriptor& field,
+    const std::string& python_dict_name) const {
+  // We should only ever be looking up fields in the current file.
+  // The only things we refer to from other files are message descriptors.
+  GOOGLE_CHECK_EQ(field.file(), file_)
+      << field.file()->name() << " vs. " << file_->name();
+  if (!containing_type) {
+    return ResolveKeyword(field.name());
+  }
+  return strings::Substitute("$0.$1['$2']",
+                          ModuleLevelDescriptorName(*containing_type),
+                          python_dict_name, field.name());
+}
+
+// Prints containing_type for nested descriptors or enum descriptors.
+template <typename DescriptorT>
+void Generator::FixContainingTypeInDescriptor(
+    const DescriptorT& descriptor,
+    const Descriptor* containing_descriptor) const {
+  if (containing_descriptor != nullptr) {
+    const std::string nested_name = ModuleLevelDescriptorName(descriptor);
+    const std::string parent_name =
+        ModuleLevelDescriptorName(*containing_descriptor);
+    printer_->Print("$nested_name$.containing_type = $parent_name$\n",
+                    "nested_name", nested_name, "parent_name", parent_name);
+  }
+}
+
+// Prints statements setting the message_type and enum_type fields in the
+// Python descriptor objects we've already output in the file.  We must
+// do this in a separate step due to circular references (otherwise, we'd
+// just set everything in the initial assignment statements).
+void Generator::FixForeignFieldsInDescriptors() const {
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    FixForeignFieldsInDescriptor(*file_->message_type(i), nullptr);
+  }
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    AddMessageToFileDescriptor(*file_->message_type(i));
+  }
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    AddEnumToFileDescriptor(*file_->enum_type(i));
+  }
+  for (int i = 0; i < file_->extension_count(); ++i) {
+    AddExtensionToFileDescriptor(*file_->extension(i));
+  }
+
+  // TODO(jieluo): Move this register to PrintFileDescriptor() when
+  // FieldDescriptor.file is added in generated file.
+  printer_->Print("_sym_db.RegisterFileDescriptor($name$)\n", "name",
+                  kDescriptorKey);
+  printer_->Print("\n");
+}
+
+// We need to not only set any necessary message_type fields, but
+// also need to call RegisterExtension() on each message we're
+// extending.
+void Generator::FixForeignFieldsInExtensions() const {
+  // Top-level extensions.
+  for (int i = 0; i < file_->extension_count(); ++i) {
+    FixForeignFieldsInExtension(*file_->extension(i));
+  }
+  // Nested extensions.
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    FixForeignFieldsInNestedExtensions(*file_->message_type(i));
+  }
+  printer_->Print("\n");
+}
+
+void Generator::FixForeignFieldsInExtension(
+    const FieldDescriptor& extension_field) const {
+  GOOGLE_CHECK(extension_field.is_extension());
+
+  std::map<std::string, std::string> m;
+  // Confusingly, for FieldDescriptors that happen to be extensions,
+  // containing_type() means "extended type."
+  // On the other hand, extension_scope() will give us what we normally
+  // mean by containing_type().
+  m["extended_message_class"] =
+      ModuleLevelMessageName(*extension_field.containing_type());
+  m["field"] = FieldReferencingExpression(
+      extension_field.extension_scope(), extension_field, "extensions_by_name");
+  printer_->Print(m, "$extended_message_class$.RegisterExtension($field$)\n");
+}
+
+void Generator::FixForeignFieldsInNestedExtensions(
+    const Descriptor& descriptor) const {
+  // Recursively fix up extensions in all nested types.
+  for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+    FixForeignFieldsInNestedExtensions(*descriptor.nested_type(i));
+  }
+  // Fix up extensions directly contained within this type.
+  for (int i = 0; i < descriptor.extension_count(); ++i) {
+    FixForeignFieldsInExtension(*descriptor.extension(i));
+  }
+}
+
+// Returns a Python expression that instantiates a Python EnumValueDescriptor
+// object for the given C++ descriptor.
+void Generator::PrintEnumValueDescriptor(
+    const EnumValueDescriptor& descriptor) const {
+  // TODO(robinson): Fix up EnumValueDescriptor "type" fields.
+  // More circular references.  ::sigh::
+  std::string options_string;
+  descriptor.options().SerializeToString(&options_string);
+  std::map<std::string, std::string> m;
+  m["name"] = descriptor.name();
+  m["index"] = StrCat(descriptor.index());
+  m["number"] = StrCat(descriptor.number());
+  m["options"] = OptionsValue(options_string);
+  printer_->Print(m,
+                  "_descriptor.EnumValueDescriptor(\n"
+                  "  name='$name$', index=$index$, number=$number$,\n"
+                  "  serialized_options=$options$,\n"
+                  "  type=None,\n"
+                  "  create_key=_descriptor._internal_create_key)");
+}
+
+// Returns a CEscaped string of serialized_options.
+std::string Generator::OptionsValue(
+    const std::string& serialized_options) const {
+  if (serialized_options.length() == 0 || GeneratingDescriptorProto()) {
+    return "None";
+  } else {
+    return "b'" + CEscape(serialized_options) + "'";
+  }
+}
+
+// Prints an expression for a Python FieldDescriptor for |field|.
+void Generator::PrintFieldDescriptor(const FieldDescriptor& field,
+                                     bool is_extension) const {
+  std::string options_string;
+  field.options().SerializeToString(&options_string);
+  std::map<std::string, std::string> m;
+  m["name"] = field.name();
+  m["full_name"] = field.full_name();
+  m["index"] = StrCat(field.index());
+  m["number"] = StrCat(field.number());
+  m["type"] = StrCat(field.type());
+  m["cpp_type"] = StrCat(field.cpp_type());
+  m["label"] = StrCat(field.label());
+  m["has_default_value"] = field.has_default_value() ? "True" : "False";
+  m["default_value"] = StringifyDefaultValue(field);
+  m["is_extension"] = is_extension ? "True" : "False";
+  m["serialized_options"] = OptionsValue(options_string);
+  m["json_name"] =
+      field.has_json_name() ? ", json_name='" + field.json_name() + "'" : "";
+  // We always set message_type and enum_type to None at this point, and then
+  // these fields in correctly after all referenced descriptors have been
+  // defined and/or imported (see FixForeignFieldsInDescriptors()).
+  const char field_descriptor_decl[] =
+      "_descriptor.FieldDescriptor(\n"
+      "  name='$name$', full_name='$full_name$', index=$index$,\n"
+      "  number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n"
+      "  has_default_value=$has_default_value$, "
+      "default_value=$default_value$,\n"
+      "  message_type=None, enum_type=None, containing_type=None,\n"
+      "  is_extension=$is_extension$, extension_scope=None,\n"
+      "  serialized_options=$serialized_options$$json_name$, file=DESCRIPTOR,"
+      "  create_key=_descriptor._internal_create_key)";
+  printer_->Print(m, field_descriptor_decl);
+}
+
+// Helper for Print{Fields,Extensions}InDescriptor().
+void Generator::PrintFieldDescriptorsInDescriptor(
+    const Descriptor& message_descriptor, bool is_extension,
+    const std::string& list_variable_name, int (Descriptor::*CountFn)() const,
+    const FieldDescriptor* (Descriptor::*GetterFn)(int)const) const {
+  printer_->Print("$list$=[\n", "list", list_variable_name);
+  printer_->Indent();
+  for (int i = 0; i < (message_descriptor.*CountFn)(); ++i) {
+    PrintFieldDescriptor(*(message_descriptor.*GetterFn)(i), is_extension);
+    printer_->Print(",\n");
+  }
+  printer_->Outdent();
+  printer_->Print("],\n");
+}
+
+// Prints a statement assigning "fields" to a list of Python FieldDescriptors,
+// one for each field present in message_descriptor.
+void Generator::PrintFieldsInDescriptor(
+    const Descriptor& message_descriptor) const {
+  const bool is_extension = false;
+  PrintFieldDescriptorsInDescriptor(message_descriptor, is_extension, "fields",
+                                    &Descriptor::field_count,
+                                    &Descriptor::field);
+}
+
+// Prints a statement assigning "extensions" to a list of Python
+// FieldDescriptors, one for each extension present in message_descriptor.
+void Generator::PrintExtensionsInDescriptor(
+    const Descriptor& message_descriptor) const {
+  const bool is_extension = true;
+  PrintFieldDescriptorsInDescriptor(message_descriptor, is_extension,
+                                    "extensions", &Descriptor::extension_count,
+                                    &Descriptor::extension);
+}
+
+bool Generator::GeneratingDescriptorProto() const {
+  return file_->name() == "net/proto2/proto/descriptor.proto" ||
+         file_->name() == "google/protobuf/descriptor.proto";
+}
+
+// Returns the unique Python module-level identifier given to a descriptor.
+// This name is module-qualified iff the given descriptor describes an
+// entity that doesn't come from the current file.
+template <typename DescriptorT>
+std::string Generator::ModuleLevelDescriptorName(
+    const DescriptorT& descriptor) const {
+  // FIXME(robinson):
+  // We currently don't worry about collisions with underscores in the type
+  // names, so these would collide in nasty ways if found in the same file:
+  //   OuterProto.ProtoA.ProtoB
+  //   OuterProto_ProtoA.ProtoB  # Underscore instead of period.
+  // As would these:
+  //   OuterProto.ProtoA_.ProtoB
+  //   OuterProto.ProtoA._ProtoB  # Leading vs. trailing underscore.
+  // (Contrived, but certainly possible).
+  //
+  // The C++ implementation doesn't guard against this either.  Leaving
+  // it for now...
+  std::string name = NamePrefixedWithNestedTypes(descriptor, "_");
+  ToUpper(&name);
+  // Module-private for now.  Easy to make public later; almost impossible
+  // to make private later.
+  name = "_" + name;
+  // We now have the name relative to its own module.  Also qualify with
+  // the module name iff this descriptor is from a different .proto file.
+  if (descriptor.file() != file_) {
+    name = ModuleAlias(descriptor.file()->name()) + "." + name;
+  }
+  return name;
+}
+
+// Returns the name of the message class itself, not the descriptor.
+// Like ModuleLevelDescriptorName(), module-qualifies the name iff
+// the given descriptor describes an entity that doesn't come from
+// the current file.
+std::string Generator::ModuleLevelMessageName(
+    const Descriptor& descriptor) const {
+  std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
+  if (descriptor.file() != file_) {
+    name = ModuleAlias(descriptor.file()->name()) + "." + name;
+  }
+  return name;
+}
+
+// Returns the unique Python module-level identifier given to a service
+// descriptor.
+std::string Generator::ModuleLevelServiceDescriptorName(
+    const ServiceDescriptor& descriptor) const {
+  std::string name = descriptor.name();
+  ToUpper(&name);
+  name = "_" + name;
+  if (descriptor.file() != file_) {
+    name = ModuleAlias(descriptor.file()->name()) + "." + name;
+  }
+  return name;
+}
+
+// Prints standard constructor arguments serialized_start and serialized_end.
+// Args:
+//   descriptor: The cpp descriptor to have a serialized reference.
+//   proto: A proto
+// Example printer output:
+// serialized_start=41,
+// serialized_end=43,
+//
+template <typename DescriptorT, typename DescriptorProtoT>
+void Generator::PrintSerializedPbInterval(const DescriptorT& descriptor,
+                                          DescriptorProtoT& proto,
+                                          const std::string& name) const {
+  descriptor.CopyTo(&proto);
+  std::string sp;
+  proto.SerializeToString(&sp);
+  int offset = file_descriptor_serialized_.find(sp);
+  GOOGLE_CHECK_GE(offset, 0);
+
+  printer_->Print(
+      "$name$._serialized_start=$serialized_start$\n"
+      "$name$._serialized_end=$serialized_end$\n",
+      "name", name, "serialized_start", StrCat(offset), "serialized_end",
+      StrCat(offset + sp.size()));
+}
+
+namespace {
+void PrintDescriptorOptionsFixingCode(const std::string& descriptor,
+                                      const std::string& options,
+                                      io::Printer* printer) {
+  // Reset the _options to None thus DescriptorBase.GetOptions() can
+  // parse _options again after extensions are registered.
+  printer->Print(
+      "$descriptor$._options = None\n"
+      "$descriptor$._serialized_options = $serialized_value$\n",
+      "descriptor", descriptor, "serialized_value", options);
+}
+}  // namespace
+
+void Generator::SetSerializedPbInterval() const {
+  // Top level enums.
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    EnumDescriptorProto proto;
+    const EnumDescriptor& descriptor = *file_->enum_type(i);
+    PrintSerializedPbInterval(descriptor, proto,
+                              ModuleLevelDescriptorName(descriptor));
+  }
+
+  // Messages.
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    SetMessagePbInterval(*file_->message_type(i));
+  }
+
+  // Services.
+  for (int i = 0; i < file_->service_count(); ++i) {
+    ServiceDescriptorProto proto;
+    const ServiceDescriptor& service = *file_->service(i);
+    PrintSerializedPbInterval(service, proto,
+                              ModuleLevelServiceDescriptorName(service));
+  }
+}
+
+void Generator::SetMessagePbInterval(const Descriptor& descriptor) const {
+  DescriptorProto message_proto;
+  PrintSerializedPbInterval(descriptor, message_proto,
+                            ModuleLevelDescriptorName(descriptor));
+
+  // Nested messages.
+  for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+    SetMessagePbInterval(*descriptor.nested_type(i));
+  }
+
+  for (int i = 0; i < descriptor.enum_type_count(); ++i) {
+    EnumDescriptorProto proto;
+    const EnumDescriptor& enum_des = *descriptor.enum_type(i);
+    PrintSerializedPbInterval(enum_des, proto,
+                              ModuleLevelDescriptorName(enum_des));
+  }
+}
+
+// Prints expressions that set the options field of all descriptors.
+void Generator::FixAllDescriptorOptions() const {
+  // Prints an expression that sets the file descriptor's options.
+  std::string file_options = OptionsValue(file_->options().SerializeAsString());
+  if (file_options != "None") {
+    PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_);
+  } else {
+    printer_->Print("DESCRIPTOR._options = None\n");
+  }
+  // Prints expressions that set the options for all top level enums.
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
+    FixOptionsForEnum(enum_descriptor);
+  }
+  // Prints expressions that set the options for all top level extensions.
+  for (int i = 0; i < file_->extension_count(); ++i) {
+    const FieldDescriptor& field = *file_->extension(i);
+    FixOptionsForField(field);
+  }
+  // Prints expressions that set the options for all messages, nested enums,
+  // nested extensions and message fields.
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    FixOptionsForMessage(*file_->message_type(i));
+  }
+
+  for (int i = 0; i < file_->service_count(); ++i) {
+    FixOptionsForService(*file_->service(i));
+  }
+}
+
+void Generator::FixOptionsForOneof(const OneofDescriptor& oneof) const {
+  std::string oneof_options = OptionsValue(oneof.options().SerializeAsString());
+  if (oneof_options != "None") {
+    std::string oneof_name = strings::Substitute(
+        "$0.$1['$2']", ModuleLevelDescriptorName(*oneof.containing_type()),
+        "oneofs_by_name", oneof.name());
+    PrintDescriptorOptionsFixingCode(oneof_name, oneof_options, printer_);
+  }
+}
+
+// Prints expressions that set the options for an enum descriptor and its
+// value descriptors.
+void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
+  std::string descriptor_name = ModuleLevelDescriptorName(enum_descriptor);
+  std::string enum_options =
+      OptionsValue(enum_descriptor.options().SerializeAsString());
+  if (enum_options != "None") {
+    PrintDescriptorOptionsFixingCode(descriptor_name, enum_options, printer_);
+  }
+  for (int i = 0; i < enum_descriptor.value_count(); ++i) {
+    const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(i);
+    std::string value_options =
+        OptionsValue(value_descriptor.options().SerializeAsString());
+    if (value_options != "None") {
+      PrintDescriptorOptionsFixingCode(
+          StringPrintf("%s.values_by_name[\"%s\"]", descriptor_name.c_str(),
+                          value_descriptor.name().c_str()),
+          value_options, printer_);
+    }
+  }
+}
+
+// Prints expressions that set the options for an service descriptor and its
+// value descriptors.
+void Generator::FixOptionsForService(
+    const ServiceDescriptor& service_descriptor) const {
+  std::string descriptor_name =
+      ModuleLevelServiceDescriptorName(service_descriptor);
+  std::string service_options =
+      OptionsValue(service_descriptor.options().SerializeAsString());
+  if (service_options != "None") {
+    PrintDescriptorOptionsFixingCode(descriptor_name, service_options,
+                                     printer_);
+  }
+
+  for (int i = 0; i < service_descriptor.method_count(); ++i) {
+    const MethodDescriptor* method = service_descriptor.method(i);
+    std::string method_options =
+        OptionsValue(method->options().SerializeAsString());
+    if (method_options != "None") {
+      std::string method_name =
+          descriptor_name + ".methods_by_name['" + method->name() + "']";
+      PrintDescriptorOptionsFixingCode(method_name, method_options, printer_);
+    }
+  }
+}
+
+// Prints expressions that set the options for field descriptors (including
+// extensions).
+void Generator::FixOptionsForField(const FieldDescriptor& field) const {
+  std::string field_options = OptionsValue(field.options().SerializeAsString());
+  if (field_options != "None") {
+    std::string field_name;
+    if (field.is_extension()) {
+      if (field.extension_scope() == nullptr) {
+        // Top level extensions.
+        field_name = field.name();
+      } else {
+        field_name = FieldReferencingExpression(field.extension_scope(), field,
+                                                "extensions_by_name");
+      }
+    } else {
+      field_name = FieldReferencingExpression(field.containing_type(), field,
+                                              "fields_by_name");
+    }
+    PrintDescriptorOptionsFixingCode(field_name, field_options, printer_);
+  }
+}
+
+// Prints expressions that set the options for a message and all its inner
+// types (nested messages, nested enums, extensions, fields).
+void Generator::FixOptionsForMessage(const Descriptor& descriptor) const {
+  // Nested messages.
+  for (int i = 0; i < descriptor.nested_type_count(); ++i) {
+    FixOptionsForMessage(*descriptor.nested_type(i));
+  }
+  // Oneofs.
+  for (int i = 0; i < descriptor.oneof_decl_count(); ++i) {
+    FixOptionsForOneof(*descriptor.oneof_decl(i));
+  }
+  // Enums.
+  for (int i = 0; i < descriptor.enum_type_count(); ++i) {
+    FixOptionsForEnum(*descriptor.enum_type(i));
+  }
+  // Fields.
+  for (int i = 0; i < descriptor.field_count(); ++i) {
+    const FieldDescriptor& field = *descriptor.field(i);
+    FixOptionsForField(field);
+  }
+  // Extensions.
+  for (int i = 0; i < descriptor.extension_count(); ++i) {
+    const FieldDescriptor& field = *descriptor.extension(i);
+    FixOptionsForField(field);
+  }
+  // Message option for this message.
+  std::string message_options =
+      OptionsValue(descriptor.options().SerializeAsString());
+  if (message_options != "None") {
+    std::string descriptor_name = ModuleLevelDescriptorName(descriptor);
+    PrintDescriptorOptionsFixingCode(descriptor_name, message_options,
+                                     printer_);
+  }
+}
+
+// If a dependency forwards other files through public dependencies, let's
+// copy over the corresponding module aliases.
+void Generator::CopyPublicDependenciesAliases(
+    const std::string& copy_from, const FileDescriptor* file) const {
+  for (int i = 0; i < file->public_dependency_count(); ++i) {
+    std::string module_name = ModuleName(file->public_dependency(i)->name());
+    std::string module_alias = ModuleAlias(file->public_dependency(i)->name());
+    // There's no module alias in the dependent file if it was generated by
+    // an old protoc (less than 3.0.0-alpha-1). Use module name in this
+    // situation.
+    printer_->Print(
+        "try:\n"
+        "  $alias$ = $copy_from$.$alias$\n"
+        "except AttributeError:\n"
+        "  $alias$ = $copy_from$.$module$\n",
+        "alias", module_alias, "module", module_name, "copy_from", copy_from);
+    CopyPublicDependenciesAliases(copy_from, file->public_dependency(i));
+  }
+}
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/python/generator.h b/src/google/protobuf/compiler/python/generator.h
new file mode 100644
index 0000000..f1fecbc
--- /dev/null
+++ b/src/google/protobuf/compiler/python/generator.h
@@ -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.
+
+// Author: robinson@google.com (Will Robinson)
+//
+// Generates Python code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/compiler/code_generator.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class ServiceDescriptor;
+
+namespace io {
+class Printer;
+}
+
+namespace compiler {
+namespace python {
+
+// CodeGenerator implementation for generated Python protocol buffer classes.
+// If you create your own protocol compiler binary and you want it to support
+// Python output, you can do so by registering an instance of this
+// CodeGenerator with the CommandLineInterface in your main() function.
+class PROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+  Generator();
+  ~Generator() override;
+
+  // CodeGenerator methods.
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* generator_context,
+                std::string* error) const override;
+
+  uint64_t GetSupportedFeatures() const override;
+
+ private:
+  void PrintImports() const;
+  void PrintFileDescriptor() const;
+  void PrintAllNestedEnumsInFile() const;
+  void PrintNestedEnums(const Descriptor& descriptor) const;
+  void PrintEnum(const EnumDescriptor& enum_descriptor) const;
+
+  void PrintFieldDescriptor(const FieldDescriptor& field,
+                            bool is_extension) const;
+  void PrintFieldDescriptorsInDescriptor(
+      const Descriptor& message_descriptor, bool is_extension,
+      const std::string& list_variable_name, int (Descriptor::*CountFn)() const,
+      const FieldDescriptor* (Descriptor::*GetterFn)(int)const) const;
+  void PrintFieldsInDescriptor(const Descriptor& message_descriptor) const;
+  void PrintExtensionsInDescriptor(const Descriptor& message_descriptor) const;
+  void PrintMessageDescriptors() const;
+  void PrintDescriptor(const Descriptor& message_descriptor) const;
+  void PrintNestedDescriptors(const Descriptor& containing_descriptor) const;
+
+  void PrintMessages() const;
+  void PrintMessage(const Descriptor& message_descriptor,
+                    const std::string& prefix,
+                    std::vector<std::string>* to_register,
+                    bool is_nested) const;
+  void PrintNestedMessages(const Descriptor& containing_descriptor,
+                           const std::string& prefix,
+                           std::vector<std::string>* to_register) const;
+
+  void FixForeignFieldsInDescriptors() const;
+  void FixForeignFieldsInDescriptor(
+      const Descriptor& descriptor,
+      const Descriptor* containing_descriptor) const;
+  void FixForeignFieldsInField(const Descriptor* containing_type,
+                               const FieldDescriptor& field,
+                               const std::string& python_dict_name) const;
+  void AddMessageToFileDescriptor(const Descriptor& descriptor) const;
+  void AddEnumToFileDescriptor(const EnumDescriptor& descriptor) const;
+  void AddExtensionToFileDescriptor(const FieldDescriptor& descriptor) const;
+  void AddServiceToFileDescriptor(const ServiceDescriptor& descriptor) const;
+  std::string FieldReferencingExpression(
+      const Descriptor* containing_type, const FieldDescriptor& field,
+      const std::string& python_dict_name) const;
+  template <typename DescriptorT>
+  void FixContainingTypeInDescriptor(
+      const DescriptorT& descriptor,
+      const Descriptor* containing_descriptor) const;
+
+  void FixForeignFieldsInExtensions() const;
+  void FixForeignFieldsInExtension(
+      const FieldDescriptor& extension_field) const;
+  void FixForeignFieldsInNestedExtensions(const Descriptor& descriptor) const;
+
+  void PrintServices() const;
+  void PrintServiceDescriptors() const;
+  void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const;
+  void PrintServiceClass(const ServiceDescriptor& descriptor) const;
+  void PrintServiceStub(const ServiceDescriptor& descriptor) const;
+  void PrintDescriptorKeyAndModuleName(
+      const ServiceDescriptor& descriptor) const;
+
+  void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const;
+  std::string OptionsValue(const std::string& serialized_options) const;
+  bool GeneratingDescriptorProto() const;
+
+  template <typename DescriptorT>
+  std::string ModuleLevelDescriptorName(const DescriptorT& descriptor) const;
+  std::string ModuleLevelMessageName(const Descriptor& descriptor) const;
+  std::string ModuleLevelServiceDescriptorName(
+      const ServiceDescriptor& descriptor) const;
+
+  template <typename DescriptorT, typename DescriptorProtoT>
+  void PrintSerializedPbInterval(const DescriptorT& descriptor,
+                                 DescriptorProtoT& proto,
+                                 const std::string& name) const;
+
+  void FixAllDescriptorOptions() const;
+  void FixOptionsForField(const FieldDescriptor& field) const;
+  void FixOptionsForOneof(const OneofDescriptor& oneof) const;
+  void FixOptionsForEnum(const EnumDescriptor& descriptor) const;
+  void FixOptionsForService(const ServiceDescriptor& descriptor) const;
+  void FixOptionsForMessage(const Descriptor& descriptor) const;
+
+  void SetSerializedPbInterval() const;
+  void SetMessagePbInterval(const Descriptor& descriptor) const;
+
+  void CopyPublicDependenciesAliases(const std::string& copy_from,
+                                     const FileDescriptor* file) const;
+
+  // Very coarse-grained lock to ensure that Generate() is reentrant.
+  // Guards file_, printer_ and file_descriptor_serialized_.
+  mutable Mutex mutex_;
+  mutable const FileDescriptor* file_;  // Set in Generate().  Under mutex_.
+  mutable std::string file_descriptor_serialized_;
+  mutable io::Printer* printer_;  // Set in Generate().  Under mutex_.
+  mutable bool pure_python_workable_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator);
+};
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/python/helpers.cc b/src/google/protobuf/compiler/python/helpers.cc
new file mode 100644
index 0000000..e4d3c13
--- /dev/null
+++ b/src/google/protobuf/compiler/python/helpers.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/compiler/python/helpers.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+// Returns the Python module name expected for a given .proto filename.
+std::string ModuleName(const std::string& filename) {
+  std::string basename = StripProto(filename);
+  ReplaceCharacters(&basename, "-", '_');
+  ReplaceCharacters(&basename, "/", '.');
+  return basename + "_pb2";
+}
+
+std::string StrippedModuleName(const std::string& filename) {
+  std::string module_name = ModuleName(filename);
+  return module_name;
+}
+
+// Keywords reserved by the Python language.
+const char* const kKeywords[] = {
+    "False",  "None",     "True",  "and",    "as",       "assert",
+    "async",  "await",    "break", "class",  "continue", "def",
+    "del",    "elif",     "else",  "except", "finally",  "for",
+    "from",   "global",   "if",    "import", "in",       "is",
+    "lambda", "nonlocal", "not",   "or",     "pass",     "raise",
+    "return", "try",      "while", "with",   "yield",
+};
+const char* const* kKeywordsEnd =
+    kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0]));
+
+bool ContainsPythonKeyword(const std::string& module_name) {
+  std::vector<std::string> tokens = Split(module_name, ".");
+  for (int i = 0; i < static_cast<int>(tokens.size()); ++i) {
+    if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsPythonKeyword(const std::string& name) {
+  return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd);
+}
+
+std::string ResolveKeyword(const std::string& name) {
+  if (IsPythonKeyword(name)) {
+    return "globals()['" + name + "']";
+  }
+  return name;
+}
+
+std::string GetFileName(const FileDescriptor* file_des,
+                        const std::string& suffix) {
+  std::string module_name = ModuleName(file_des->name());
+  std::string filename = module_name;
+  ReplaceCharacters(&filename, ".", '/');
+  filename += suffix;
+  return filename;
+}
+
+bool HasGenericServices(const FileDescriptor* file) {
+  return file->service_count() > 0 && file->options().py_generic_services();
+}
+
+template <typename DescriptorT>
+std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
+                                        const std::string& separator) {
+  std::string name = descriptor.name();
+  const Descriptor* parent = descriptor.containing_type();
+  if (parent != nullptr) {
+    std::string prefix = NamePrefixedWithNestedTypes(*parent, separator);
+    if (separator == "." && IsPythonKeyword(name)) {
+      return "getattr(" + prefix + ", '" + name + "')";
+    } else {
+      return prefix + separator + name;
+    }
+  }
+  if (separator == ".") {
+    name = ResolveKeyword(name);
+  }
+  return name;
+}
+
+template std::string NamePrefixedWithNestedTypes<Descriptor>(
+    const Descriptor& descriptor, const std::string& separator);
+template std::string NamePrefixedWithNestedTypes<EnumDescriptor>(
+    const EnumDescriptor& descriptor, const std::string& separator);
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/python/helpers.h b/src/google/protobuf/compiler/python/helpers.h
new file mode 100644
index 0000000..a68ceb1
--- /dev/null
+++ b/src/google/protobuf/compiler/python/helpers.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
+
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+
+std::string ModuleName(const std::string& filename);
+std::string StrippedModuleName(const std::string& filename);
+bool ContainsPythonKeyword(const std::string& module_name);
+bool IsPythonKeyword(const std::string& name);
+std::string ResolveKeyword(const std::string& name);
+std::string GetFileName(const FileDescriptor* file_des,
+                        const std::string& suffix);
+bool HasGenericServices(const FileDescriptor* file);
+
+template <typename DescriptorT>
+std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
+                                        const std::string& separator);
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
diff --git a/src/google/protobuf/compiler/python/plugin_unittest.cc b/src/google/protobuf/compiler/python/plugin_unittest.cc
new file mode 100644
index 0000000..7f9589b
--- /dev/null
+++ b/src/google/protobuf/compiler/python/plugin_unittest.cc
@@ -0,0 +1,126 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <memory>
+#include <string>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/python/generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+namespace {
+
+class TestGenerator : public CodeGenerator {
+ public:
+  TestGenerator() {}
+  ~TestGenerator() override {}
+
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
+    TryInsert("test_pb2.py", "imports", context);
+    TryInsert("test_pb2.py", "module_scope", context);
+    TryInsert("test_pb2.py", "class_scope:foo.Bar", context);
+    TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", context);
+    return true;
+  }
+
+  void TryInsert(const std::string& filename,
+                 const std::string& insertion_point,
+                 GeneratorContext* context) const {
+    std::unique_ptr<io::ZeroCopyOutputStream> output(
+        context->OpenForInsert(filename, insertion_point));
+    io::Printer printer(output.get(), '$');
+    printer.Print("// inserted $name$\n", "name", insertion_point);
+  }
+};
+
+// opposed to importlib) in the usual case where the .proto file paths do not
+// not contain any Python keywords.
+TEST(PythonPluginTest, ImportTest) {
+  // Create files test1.proto and test2.proto with the former importing the
+  // latter.
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test1.proto",
+                             "syntax = \"proto3\";\n"
+                             "package foo;\n"
+                             "import \"test2.proto\";"
+                             "message Message1 {\n"
+                             "  Message2 message_2 = 1;\n"
+                             "}\n",
+                             true));
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test2.proto",
+                             "syntax = \"proto3\";\n"
+                             "package foo;\n"
+                             "message Message2 {}\n",
+                             true));
+
+  compiler::CommandLineInterface cli;
+  cli.SetInputsAreProtoPathRelative(true);
+  python::Generator python_generator;
+  cli.RegisterGenerator("--python_out", &python_generator, "");
+  std::string proto_path = "-I" + TestTempDir();
+  std::string python_out = "--python_out=" + TestTempDir();
+  const char* argv[] = {"protoc", proto_path.c_str(), "-I.", python_out.c_str(),
+                        "test1.proto"};
+  ASSERT_EQ(0, cli.Run(5, argv));
+
+  // Loop over the lines of the generated code and verify that we find an
+  // ordinary Python import but do not find the string "importlib".
+  std::string output;
+  GOOGLE_CHECK_OK(File::GetContents(TestTempDir() + "/test1_pb2.py", &output,
+                             true));
+  std::vector<std::string> lines = Split(output, "\n");
+  std::string expected_import = "import test2_pb2";
+  bool found_expected_import = false;
+  for (int i = 0; i < lines.size(); ++i) {
+    if (lines[i].find(expected_import) != std::string::npos) {
+      found_expected_import = true;
+    }
+    EXPECT_EQ(std::string::npos, lines[i].find("importlib"));
+  }
+  EXPECT_TRUE(found_expected_import);
+}
+
+}  // namespace
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/python/pyi_generator.cc b/src/google/protobuf/compiler/python/pyi_generator.cc
new file mode 100644
index 0000000..1ccc9a2
--- /dev/null
+++ b/src/google/protobuf/compiler/python/pyi_generator.cc
@@ -0,0 +1,636 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/python/pyi_generator.h>
+
+#include <string>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/python/helpers.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>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+template <typename DescriptorT>
+struct SortByName {
+  bool operator()(const DescriptorT* l, const DescriptorT* r) const {
+    return l->name() < r->name();
+  }
+};
+
+PyiGenerator::PyiGenerator() : file_(nullptr) {}
+
+PyiGenerator::~PyiGenerator() {}
+
+void PyiGenerator::PrintItemMap(
+    const std::map<std::string, std::string>& item_map) const {
+  for (const auto& entry : item_map) {
+    printer_->Print("$key$: $value$\n", "key", entry.first, "value",
+                    entry.second);
+  }
+}
+
+template <typename DescriptorT>
+std::string PyiGenerator::ModuleLevelName(
+    const DescriptorT& descriptor,
+    const std::map<std::string, std::string>& import_map) const {
+  std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
+  if (descriptor.file() != file_) {
+    std::string module_alias;
+    std::string filename = descriptor.file()->name();
+    if (import_map.find(filename) == import_map.end()) {
+      std::string module_name = ModuleName(descriptor.file()->name());
+      std::vector<std::string> tokens = Split(module_name, ".");
+      module_alias = "_" + tokens.back();
+    } else {
+      module_alias = import_map.at(filename);
+    }
+    name = module_alias + "." + name;
+  }
+  return name;
+}
+
+struct ImportModules {
+  bool has_repeated = false;    // _containers
+  bool has_iterable = false;    // typing.Iterable
+  bool has_messages = false;    // _message
+  bool has_enums = false;       // _enum_type_wrapper
+  bool has_extendable = false;  // _python_message
+  bool has_mapping = false;     // typing.Mapping
+  bool has_optional = false;    // typing.Optional
+  bool has_union = false;       // typing.Union
+  bool has_well_known_type = false;
+};
+
+// Checks whether a descriptor name matches a well-known type.
+bool IsWellKnownType(const std::string& name) {
+  // LINT.IfChange(wktbases)
+  return (name == "google.protobuf.Any" ||
+          name == "google.protobuf.Duration" ||
+          name == "google.protobuf.FieldMask" ||
+          name == "google.protobuf.ListValue" ||
+          name == "google.protobuf.Struct" ||
+          name == "google.protobuf.Timestamp");
+  // LINT.ThenChange(//depot/google3/net/proto2/python/internal/well_known_types.py:wktbases)
+}
+
+// Checks what modules should be imported for this message
+// descriptor.
+void CheckImportModules(const Descriptor* descriptor,
+                        ImportModules* import_modules) {
+  if (descriptor->extension_range_count() > 0) {
+    import_modules->has_extendable = true;
+  }
+  if (descriptor->enum_type_count() > 0) {
+    import_modules->has_enums = true;
+  }
+  if (IsWellKnownType(descriptor->full_name())) {
+    import_modules->has_well_known_type = true;
+  }
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (IsPythonKeyword(field->name())) {
+      continue;
+    }
+    import_modules->has_optional = true;
+    if (field->is_repeated()) {
+      import_modules->has_repeated = true;
+    }
+    if (field->is_map()) {
+      import_modules->has_mapping = true;
+      const FieldDescriptor* value_des = field->message_type()->field(1);
+      if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+          value_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        import_modules->has_union = true;
+      }
+    } else {
+      if (field->is_repeated()) {
+        import_modules->has_iterable = true;
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        import_modules->has_union = true;
+        import_modules->has_mapping = true;
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        import_modules->has_union = true;
+      }
+    }
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    CheckImportModules(descriptor->nested_type(i), import_modules);
+  }
+}
+
+void PyiGenerator::PrintImportForDescriptor(
+    const FileDescriptor& desc,
+    std::map<std::string, std::string>* import_map,
+    std::set<std::string>* seen_aliases) const {
+  const std::string& filename = desc.name();
+  std::string module_name = StrippedModuleName(filename);
+  size_t last_dot_pos = module_name.rfind('.');
+  std::string import_statement;
+  if (last_dot_pos == std::string::npos) {
+    import_statement = "import " + module_name;
+  } else {
+    import_statement = "from " + module_name.substr(0, last_dot_pos) +
+                       " import " + module_name.substr(last_dot_pos + 1);
+    module_name = module_name.substr(last_dot_pos + 1);
+  }
+  std::string alias = "_" + module_name;
+  // Generate a unique alias by adding _1 suffixes until we get an unused alias.
+  while (seen_aliases->find(alias) != seen_aliases->end()) {
+    alias = alias + "_1";
+  }
+  printer_->Print("$statement$ as $alias$\n", "statement",
+                  import_statement, "alias", alias);
+  (*import_map)[filename] = alias;
+  seen_aliases->insert(alias);
+}
+
+void PyiGenerator::PrintImports(
+    std::map<std::string, std::string>* item_map,
+    std::map<std::string, std::string>* import_map) const {
+  // Prints imported dependent _pb2 files.
+  std::set<std::string> seen_aliases;
+  for (int i = 0; i < file_->dependency_count(); ++i) {
+    const FileDescriptor* dep = file_->dependency(i);
+    PrintImportForDescriptor(*dep, import_map, &seen_aliases);
+    for (int j = 0; j < dep->public_dependency_count(); ++j) {
+      PrintImportForDescriptor(
+          *dep->public_dependency(j), import_map, &seen_aliases);
+    }
+  }
+
+  // Checks what modules should be imported.
+  ImportModules import_modules;
+  if (file_->message_type_count() > 0) {
+    import_modules.has_messages = true;
+  }
+  if (file_->enum_type_count() > 0) {
+    import_modules.has_enums = true;
+  }
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    CheckImportModules(file_->message_type(i), &import_modules);
+  }
+
+  // Prints modules (e.g. _containers, _messages, typing) that are
+  // required in the proto file.
+  if (import_modules.has_repeated) {
+    printer_->Print(
+        "from google.protobuf.internal import containers as "
+        "_containers\n");
+  }
+  if (import_modules.has_enums) {
+    printer_->Print(
+        "from google.protobuf.internal import enum_type_wrapper"
+        " as _enum_type_wrapper\n");
+  }
+  if (import_modules.has_extendable) {
+    printer_->Print(
+        "from google.protobuf.internal import python_message"
+        " as _python_message\n");
+  }
+  if (import_modules.has_well_known_type) {
+    printer_->Print(
+        "from google.protobuf.internal import well_known_types"
+        " as _well_known_types\n");
+  }
+  printer_->Print(
+      "from google.protobuf import"
+      " descriptor as _descriptor\n");
+  if (import_modules.has_messages) {
+    printer_->Print(
+        "from google.protobuf import message as _message\n");
+  }
+  if (HasGenericServices(file_)) {
+    printer_->Print(
+        "from google.protobuf import service as"
+        " _service\n");
+  }
+  printer_->Print("from typing import ");
+  printer_->Print("ClassVar as _ClassVar");
+  if (import_modules.has_iterable) {
+    printer_->Print(", Iterable as _Iterable");
+  }
+  if (import_modules.has_mapping) {
+    printer_->Print(", Mapping as _Mapping");
+  }
+  if (import_modules.has_optional) {
+    printer_->Print(", Optional as _Optional");
+  }
+  if (import_modules.has_union) {
+    printer_->Print(", Union as _Union");
+  }
+  printer_->Print("\n\n");
+
+  // Public imports
+  for (int i = 0; i < file_->public_dependency_count(); ++i) {
+    const FileDescriptor* public_dep = file_->public_dependency(i);
+    std::string module_name = StrippedModuleName(public_dep->name());
+    // Top level messages in public imports
+    for (int i = 0; i < public_dep->message_type_count(); ++i) {
+      printer_->Print("from $module$ import $message_class$\n", "module",
+                      module_name, "message_class",
+                      public_dep->message_type(i)->name());
+    }
+    // Top level enums for public imports
+    for (int i = 0; i < public_dep->enum_type_count(); ++i) {
+      printer_->Print("from $module$ import $enum_class$\n", "module",
+                      module_name, "enum_class",
+                      public_dep->enum_type(i)->name());
+    }
+    // Enum values for public imports
+    for (int i = 0; i < public_dep->enum_type_count(); ++i) {
+      const EnumDescriptor* enum_descriptor = public_dep->enum_type(i);
+      for (int j = 0; j < enum_descriptor->value_count(); ++j) {
+        (*item_map)[enum_descriptor->value(j)->name()] =
+            ModuleLevelName(*enum_descriptor, *import_map);
+      }
+    }
+    // Top level extensions for public imports
+    AddExtensions(*public_dep, item_map);
+  }
+}
+
+void PyiGenerator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
+  std::string enum_name = enum_descriptor.name();
+  printer_->Print(
+      "class $enum_name$(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):\n"
+      "    __slots__ = []\n",
+      "enum_name", enum_name);
+}
+
+// Adds enum value to item map which will be ordered and printed later.
+void PyiGenerator::AddEnumValue(
+    const EnumDescriptor& enum_descriptor,
+    std::map<std::string, std::string>* item_map,
+    const std::map<std::string, std::string>& import_map) const {
+  // enum values
+  std::string module_enum_name = ModuleLevelName(enum_descriptor, import_map);
+  for (int j = 0; j < enum_descriptor.value_count(); ++j) {
+    const EnumValueDescriptor* value_descriptor = enum_descriptor.value(j);
+    (*item_map)[value_descriptor->name()] = module_enum_name;
+  }
+}
+
+// Prints top level enums
+void PyiGenerator::PrintTopLevelEnums() const {
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    printer_->Print("\n");
+    PrintEnum(*file_->enum_type(i));
+  }
+}
+
+// Add top level extensions to item_map which will be ordered and
+// printed later.
+template <typename DescriptorT>
+void PyiGenerator::AddExtensions(
+    const DescriptorT& descriptor,
+    std::map<std::string, std::string>* item_map) const {
+  for (int i = 0; i < descriptor.extension_count(); ++i) {
+    const FieldDescriptor* extension_field = descriptor.extension(i);
+    std::string constant_name = extension_field->name() + "_FIELD_NUMBER";
+    ToUpper(&constant_name);
+    (*item_map)[constant_name] = "_ClassVar[int]";
+    (*item_map)[extension_field->name()] = "_descriptor.FieldDescriptor";
+  }
+}
+
+// Returns the string format of a field's cpp_type
+std::string PyiGenerator::GetFieldType(
+    const FieldDescriptor& field_des, const Descriptor& containing_des,
+    const std::map<std::string, std::string>& import_map) const {
+  switch (field_des.cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return "int";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return ModuleLevelName(*field_des.enum_type(), import_map);
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field_des.type() == FieldDescriptor::TYPE_STRING) {
+        return "str";
+      } else {
+        return "bytes";
+      }
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      // If the field is inside a nested message and the nested message has the
+      // same name as a top-level message, then we need to prefix the field type
+      // with the module name for disambiguation.
+      std::string name = ModuleLevelName(*field_des.message_type(), import_map);
+      if ((containing_des.containing_type() != nullptr &&
+           name == containing_des.name())) {
+        std::string module = ModuleName(field_des.file()->name());
+        name = module + "." + name;
+      }
+      return name;
+    }
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported field type.";
+  }
+  return "";
+}
+
+void PyiGenerator::PrintMessage(
+    const Descriptor& message_descriptor, bool is_nested,
+    const std::map<std::string, std::string>& import_map) const {
+  if (!is_nested) {
+    printer_->Print("\n");
+  }
+  std::string class_name = message_descriptor.name();
+  std::string extra_base;
+  // A well-known type needs to inherit from its corresponding base class in
+  // net/proto2/python/internal/well_known_types.
+  if (IsWellKnownType(message_descriptor.full_name())) {
+    extra_base = ", _well_known_types." + message_descriptor.name();
+  } else {
+    extra_base = "";
+  }
+  printer_->Print("class $class_name$(_message.Message$extra_base$):\n",
+                  "class_name", class_name, "extra_base", extra_base);
+  printer_->Indent();
+  printer_->Indent();
+
+  std::vector<const FieldDescriptor*> fields;
+  fields.reserve(message_descriptor.field_count());
+  for (int i = 0; i < message_descriptor.field_count(); ++i) {
+    fields.push_back(message_descriptor.field(i));
+  }
+  std::sort(fields.begin(), fields.end(), SortByName<FieldDescriptor>());
+
+  // Prints slots
+  printer_->Print("__slots__ = [", "class_name", class_name);
+  bool first_item = true;
+  for (const auto& field_des : fields) {
+    if (IsPythonKeyword(field_des->name())) {
+      continue;
+    }
+    if (first_item) {
+      first_item = false;
+    } else {
+      printer_->Print(", ");
+    }
+    printer_->Print("\"$field_name$\"", "field_name", field_des->name());
+  }
+  printer_->Print("]\n");
+
+  std::map<std::string, std::string> item_map;
+  // Prints Extensions for extendable messages
+  if (message_descriptor.extension_range_count() > 0) {
+    item_map["Extensions"] = "_python_message._ExtensionDict";
+  }
+
+  // Prints nested enums
+  std::vector<const EnumDescriptor*> nested_enums;
+  nested_enums.reserve(message_descriptor.enum_type_count());
+  for (int i = 0; i < message_descriptor.enum_type_count(); ++i) {
+    nested_enums.push_back(message_descriptor.enum_type(i));
+  }
+  std::sort(nested_enums.begin(), nested_enums.end(),
+            SortByName<EnumDescriptor>());
+
+  for (const auto& entry : nested_enums) {
+    PrintEnum(*entry);
+    // Adds enum value to item_map which will be ordered and printed later
+    AddEnumValue(*entry, &item_map, import_map);
+  }
+
+  // Prints nested messages
+  std::vector<const Descriptor*> nested_messages;
+  nested_messages.reserve(message_descriptor.nested_type_count());
+  for (int i = 0; i < message_descriptor.nested_type_count(); ++i) {
+    nested_messages.push_back(message_descriptor.nested_type(i));
+  }
+  std::sort(nested_messages.begin(), nested_messages.end(),
+            SortByName<Descriptor>());
+
+  for (const auto& entry : nested_messages) {
+    PrintMessage(*entry, true, import_map);
+  }
+
+  // Adds extensions to item_map which will be ordered and printed later
+  AddExtensions(message_descriptor, &item_map);
+
+  // Adds field number and field descriptor to item_map
+  for (int i = 0; i < message_descriptor.field_count(); ++i) {
+    const FieldDescriptor& field_des = *message_descriptor.field(i);
+    item_map[ToUpper(field_des.name()) + "_FIELD_NUMBER"] =
+        "_ClassVar[int]";
+    if (IsPythonKeyword(field_des.name())) {
+      continue;
+    }
+    std::string field_type = "";
+    if (field_des.is_map()) {
+      const FieldDescriptor* key_des = field_des.message_type()->field(0);
+      const FieldDescriptor* value_des = field_des.message_type()->field(1);
+      field_type = (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+                        ? "_containers.MessageMap["
+                        : "_containers.ScalarMap[");
+      field_type += GetFieldType(*key_des, message_descriptor, import_map);
+      field_type += ", ";
+      field_type += GetFieldType(*value_des, message_descriptor, import_map);
+    } else {
+      if (field_des.is_repeated()) {
+        field_type = (field_des.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+                          ? "_containers.RepeatedCompositeFieldContainer["
+                          : "_containers.RepeatedScalarFieldContainer[");
+      }
+      field_type += GetFieldType(field_des, message_descriptor, import_map);
+    }
+
+    if (field_des.is_repeated()) {
+      field_type += "]";
+    }
+    item_map[field_des.name()] = field_type;
+  }
+
+  // Prints all items in item_map
+  PrintItemMap(item_map);
+
+  // Prints __init__
+  printer_->Print("def __init__(self");
+  bool has_key_words = false;
+  bool is_first = true;
+  for (int i = 0; i < message_descriptor.field_count(); ++i) {
+    const FieldDescriptor* field_des = message_descriptor.field(i);
+    if (IsPythonKeyword(field_des->name())) {
+      has_key_words = true;
+      continue;
+    }
+    std::string field_name = field_des->name();
+    if (is_first && field_name == "self") {
+      // See b/144146793 for an example of real code that generates a (self,
+      // self) method signature. Since repeating a parameter name is illegal in
+      // Python, we rename the duplicate self.
+      field_name = "self_";
+    }
+    is_first = false;
+    printer_->Print(", $field_name$: ", "field_name", field_name);
+    if (field_des->is_repeated() ||
+        field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) {
+      printer_->Print("_Optional[");
+    }
+    if (field_des->is_map()) {
+      const Descriptor* map_entry = field_des->message_type();
+      printer_->Print(
+          "_Mapping[$key_type$, $value_type$]", "key_type",
+          GetFieldType(*map_entry->field(0), message_descriptor, import_map),
+          "value_type",
+          GetFieldType(*map_entry->field(1), message_descriptor, import_map));
+    } else {
+      if (field_des->is_repeated()) {
+        printer_->Print("_Iterable[");
+      }
+      if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        printer_->Print(
+            "_Union[$type_name$, _Mapping]", "type_name",
+            GetFieldType(*field_des, message_descriptor, import_map));
+      } else {
+        if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+          printer_->Print("_Union[$type_name$, str]", "type_name",
+                          ModuleLevelName(*field_des->enum_type(), import_map));
+        } else {
+          printer_->Print(
+              "$type_name$", "type_name",
+              GetFieldType(*field_des, message_descriptor, import_map));
+        }
+      }
+      if (field_des->is_repeated()) {
+        printer_->Print("]");
+      }
+    }
+    if (field_des->is_repeated() ||
+        field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) {
+      printer_->Print("]");
+    }
+    printer_->Print(" = ...");
+  }
+  if (has_key_words) {
+    printer_->Print(", **kwargs");
+  }
+  printer_->Print(") -> None: ...\n");
+
+  printer_->Outdent();
+  printer_->Outdent();
+}
+
+void PyiGenerator::PrintMessages(
+    const std::map<std::string, std::string>& import_map) const {
+  // Deterministically order the descriptors.
+  std::vector<const Descriptor*> messages;
+  messages.reserve(file_->message_type_count());
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    messages.push_back(file_->message_type(i));
+  }
+  std::sort(messages.begin(), messages.end(), SortByName<Descriptor>());
+
+  for (const auto& entry : messages) {
+    PrintMessage(*entry, false, import_map);
+  }
+}
+
+void PyiGenerator::PrintServices() const {
+  std::vector<const ServiceDescriptor*> services;
+  services.reserve(file_->service_count());
+  for (int i = 0; i < file_->service_count(); ++i) {
+    services.push_back(file_->service(i));
+  }
+  std::sort(services.begin(), services.end(), SortByName<ServiceDescriptor>());
+
+  // Prints $Service$ and $Service$_Stub classes
+  for (const auto& entry : services) {
+    printer_->Print("\n");
+    printer_->Print(
+        "class $service_name$(_service.service): ...\n\n"
+        "class $service_name$_Stub($service_name$): ...\n",
+        "service_name", entry->name());
+  }
+}
+
+bool PyiGenerator::Generate(const FileDescriptor* file,
+                            const std::string& parameter,
+                            GeneratorContext* context,
+                            std::string* error) const {
+  MutexLock lock(&mutex_);
+  // Calculate file name.
+  file_ = file;
+  std::string filename =
+      parameter.empty() ? GetFileName(file, ".pyi") : parameter;
+
+  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  GOOGLE_CHECK(output.get());
+  io::Printer printer(output.get(), '$');
+  printer_ = &printer;
+
+  // item map will store "DESCRIPTOR", top level extensions, top level enum
+  // values. The items will be sorted and printed later.
+  std::map<std::string, std::string> item_map;
+
+  // Adds "DESCRIPTOR" into item_map.
+  item_map["DESCRIPTOR"] = "_descriptor.FileDescriptor";
+
+  // import_map will be a mapping from filename to module alias, e.g.
+  // "google3/foo/bar.py" -> "_bar"
+  std::map<std::string, std::string> import_map;
+
+  PrintImports(&item_map, &import_map);
+  // Adds top level enum values to item_map.
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    AddEnumValue(*file_->enum_type(i), &item_map, import_map);
+  }
+  // Adds top level extensions to item_map.
+  AddExtensions(*file_, &item_map);
+  // Prints item map
+  PrintItemMap(item_map);
+
+  PrintMessages(import_map);
+  PrintTopLevelEnums();
+  if (HasGenericServices(file)) {
+    PrintServices();
+  }
+  return true;
+}
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/python/pyi_generator.h b/src/google/protobuf/compiler/python/pyi_generator.h
new file mode 100644
index 0000000..9611ed4
--- /dev/null
+++ b/src/google/protobuf/compiler/python/pyi_generator.h
@@ -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.
+
+// Author: jieluo@google.com (Jie Luo)
+//
+// Generates Python stub (.pyi) for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__
+
+#include <map>
+#include <set>
+#include <string>
+
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/compiler/code_generator.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class MethodDescriptor;
+class ServiceDescriptor;
+
+namespace io {
+class Printer;
+}
+
+namespace compiler {
+namespace python {
+
+class PROTOC_EXPORT PyiGenerator : public google::protobuf::compiler::CodeGenerator {
+ public:
+  PyiGenerator();
+  ~PyiGenerator() override;
+
+  // CodeGenerator methods.
+  uint64_t GetSupportedFeatures() const override {
+    // Code generators must explicitly support proto3 optional.
+    return CodeGenerator::FEATURE_PROTO3_OPTIONAL;
+  }
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* generator_context,
+                std::string* error) const override;
+
+ private:
+  void PrintImportForDescriptor(const FileDescriptor& desc,
+                                std::map<std::string, std::string>* import_map,
+                                std::set<std::string>* seen_aliases) const;
+  void PrintImports(std::map<std::string, std::string>* item_map,
+                    std::map<std::string, std::string>* import_map) const;
+  void PrintEnum(const EnumDescriptor& enum_descriptor) const;
+  void AddEnumValue(const EnumDescriptor& enum_descriptor,
+                    std::map<std::string, std::string>* item_map,
+                    const std::map<std::string, std::string>& import_map) const;
+  void PrintTopLevelEnums() const;
+  template <typename DescriptorT>
+  void AddExtensions(const DescriptorT& descriptor,
+                     std::map<std::string, std::string>* item_map) const;
+  void PrintMessages(
+      const std::map<std::string, std::string>& import_map) const;
+  void PrintMessage(const Descriptor& message_descriptor, bool is_nested,
+                    const std::map<std::string, std::string>& import_map) const;
+  void PrintServices() const;
+  void PrintItemMap(const std::map<std::string, std::string>& item_map) const;
+  std::string GetFieldType(
+      const FieldDescriptor& field_des, const Descriptor& containing_des,
+      const std::map<std::string, std::string>& import_map) const;
+  template <typename DescriptorT>
+  std::string ModuleLevelName(
+      const DescriptorT& descriptor,
+      const std::map<std::string, std::string>& import_map) const;
+
+  // Very coarse-grained lock to ensure that Generate() is reentrant.
+  // Guards file_ and printer_.
+  mutable Mutex mutex_;
+  mutable const FileDescriptor* file_;  // Set in Generate().  Under mutex_.
+  mutable io::Printer* printer_;        // Set in Generate().  Under mutex_.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PyiGenerator);
+};
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
new file mode 100644
index 0000000..21d48cd
--- /dev/null
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -0,0 +1,6 @@
+#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_PYTHON_GENERATOR_H_
+#define GOOGLE_PROTOBUF_COMPILER_PYTHON_PYTHON_GENERATOR_H_
+
+#include <google/protobuf/compiler/python/generator.h>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PYTHON_PYTHON_GENERATOR_H_
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..70ec9f1
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code.proto
@@ -0,0 +1,70 @@
+syntax = "proto3";
+
+package A.B.C;
+
+import "ruby_generated_code_proto2_import.proto";
+
+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;
+  TestImportedMessage optional_proto2_submessage = 12;
+
+  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_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
new file mode 100644
index 0000000..256ac7c
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
@@ -0,0 +1,79 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_code.proto
+
+require 'google/protobuf'
+
+require 'ruby_generated_code_proto2_import_pb'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_code.proto", :syntax => :proto3) 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"
+      optional :optional_proto2_submessage, :message, 12, "A.B.C.TestImportedMessage"
+      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
+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_generated_code_proto2.proto b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto
new file mode 100644
index 0000000..ea7f783
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto
@@ -0,0 +1,71 @@
+syntax = "proto2";
+
+package A.B.C;
+
+import "ruby_generated_code_proto2_import.proto";
+
+message TestMessage {
+  optional int32 optional_int32 = 1 [default = 1];
+  optional int64 optional_int64 = 2 [default = 2];
+  optional uint32 optional_uint32 = 3 [default = 3];
+  optional uint64 optional_uint64 = 4 [default = 4];
+  optional bool optional_bool = 5 [default = true];
+  optional double optional_double = 6 [default = 6.0];
+  optional float optional_float = 7 [default = 7.0];
+  optional string optional_string = 8 [default = "default str"];
+  optional bytes optional_bytes = 9 [default = "\0\1\2\100fubar"];
+  optional TestEnum optional_enum = 10 [default = A];
+  optional TestMessage optional_msg = 11;
+  optional TestImportedMessage optional_proto2_submessage = 12;
+
+  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;
+
+  required int32 required_int32 = 41;
+  required int64 required_int64 = 42;
+  required uint32 required_uint32 = 43;
+  required uint64 required_uint64 = 44;
+  required bool required_bool = 45;
+  required double required_double = 46;
+  required float required_float = 47;
+  required string required_string = 48;
+  required bytes required_bytes = 49;
+  required TestEnum required_enum = 50;
+  required TestMessage required_msg = 51;
+
+  oneof my_oneof {
+    int32 oneof_int32 = 61;
+    int64 oneof_int64 = 62;
+    uint32 oneof_uint32 = 63;
+    uint64 oneof_uint64 = 64;
+    bool oneof_bool = 65;
+    double oneof_double = 66;
+    float oneof_float = 67;
+    string oneof_string = 68;
+    bytes oneof_bytes = 69;
+    TestEnum oneof_enum = 70;
+    TestMessage oneof_msg = 71;
+  }
+
+  message NestedMessage {
+    optional int32 foo = 1;
+  }
+
+  optional 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_proto2_import.proto b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto
new file mode 100644
index 0000000..9ec0738
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto
@@ -0,0 +1,5 @@
+syntax = "proto2";
+
+package A.B.C;
+
+message TestImportedMessage {}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
new file mode 100644
index 0000000..44d3196
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
@@ -0,0 +1,80 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_code_proto2.proto
+
+require 'google/protobuf'
+
+require 'ruby_generated_code_proto2_import_pb'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_code_proto2.proto", :syntax => :proto2) do
+    add_message "A.B.C.TestMessage" do
+      optional :optional_int32, :int32, 1, default: 1
+      optional :optional_int64, :int64, 2, default: 2
+      optional :optional_uint32, :uint32, 3, default: 3
+      optional :optional_uint64, :uint64, 4, default: 4
+      optional :optional_bool, :bool, 5, default: true
+      optional :optional_double, :double, 6, default: 6
+      optional :optional_float, :float, 7, default: 7
+      optional :optional_string, :string, 8, default: "default str"
+      optional :optional_bytes, :bytes, 9, default: "\x00\x01\x02\x40\x66\x75\x62\x61\x72".force_encoding("ASCII-8BIT")
+      optional :optional_enum, :enum, 10, "A.B.C.TestEnum", default: 1
+      optional :optional_msg, :message, 11, "A.B.C.TestMessage"
+      optional :optional_proto2_submessage, :message, 12, "A.B.C.TestImportedMessage"
+      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"
+      required :required_int32, :int32, 41
+      required :required_int64, :int64, 42
+      required :required_uint32, :uint32, 43
+      required :required_uint64, :uint64, 44
+      required :required_bool, :bool, 45
+      required :required_double, :double, 46
+      required :required_float, :float, 47
+      required :required_string, :string, 48
+      required :required_bytes, :bytes, 49
+      required :required_enum, :enum, 50, "A.B.C.TestEnum"
+      required :required_msg, :message, 51, "A.B.C.TestMessage"
+      optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
+      oneof :my_oneof do
+        optional :oneof_int32, :int32, 61
+        optional :oneof_int64, :int64, 62
+        optional :oneof_uint32, :uint32, 63
+        optional :oneof_uint64, :uint64, 64
+        optional :oneof_bool, :bool, 65
+        optional :oneof_double, :double, 66
+        optional :oneof_float, :float, 67
+        optional :oneof_string, :string, 68
+        optional :oneof_bytes, :bytes, 69
+        optional :oneof_enum, :enum, 70, "A.B.C.TestEnum"
+        optional :oneof_msg, :message, 71, "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
+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_generated_pkg_explicit.proto b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto
new file mode 100644
index 0000000..8d7c948
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package one.two.a_three;
+
+option ruby_package = "A::B::C";
+
+message Four {
+  string a_string = 1;
+}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto
new file mode 100644
index 0000000..7a0d260
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package one.two.a_three.and;
+
+option ruby_package = "AA.BB.CC";
+
+message Four {
+  string another_string = 1;
+}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb
new file mode 100644
index 0000000..cdbbe89
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy_pb.rb
@@ -0,0 +1,20 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_pkg_explicit_legacy.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_pkg_explicit_legacy.proto", :syntax => :proto3) do
+    add_message "one.two.a_three.and.Four" do
+      optional :another_string, :string, 1
+    end
+  end
+end
+
+module AA
+  module BB
+    module CC
+      Four = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.and.Four").msgclass
+    end
+  end
+end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb
new file mode 100644
index 0000000..e6d4701
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_pb.rb
@@ -0,0 +1,20 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_pkg_explicit.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_pkg_explicit.proto", :syntax => :proto3) do
+    add_message "one.two.a_three.Four" do
+      optional :a_string, :string, 1
+    end
+  end
+end
+
+module A
+  module B
+    module C
+      Four = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.Four").msgclass
+    end
+  end
+end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto
new file mode 100644
index 0000000..544db64
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package one.two.a_three;
+
+message Four {
+  string a_string = 1;
+}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb
new file mode 100644
index 0000000..1ac0ef7
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_pkg_implicit_pb.rb
@@ -0,0 +1,20 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_pkg_implicit.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_file("ruby_generated_pkg_implicit.proto", :syntax => :proto3) do
+    add_message "one.two.a_three.Four" do
+      optional :a_string, :string, 1
+    end
+  end
+end
+
+module One
+  module Two
+    module AThree
+      Four = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("one.two.a_three.Four").msgclass
+    end
+  end
+end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
new file mode 100644
index 0000000..d4a53d5
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -0,0 +1,575 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <iomanip>
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+
+// Forward decls.
+template <class numeric_type>
+std::string NumberToString(numeric_type value);
+std::string GetRequireName(const std::string& proto_file);
+std::string LabelForField(FieldDescriptor* field);
+std::string TypeName(FieldDescriptor* field);
+bool GenerateMessage(const Descriptor* message, io::Printer* printer,
+                     std::string* error);
+void GenerateEnum(const EnumDescriptor* en, io::Printer* printer);
+void GenerateMessageAssignment(const std::string& prefix,
+                               const Descriptor* message, io::Printer* printer);
+void GenerateEnumAssignment(const std::string& prefix, const EnumDescriptor* en,
+                            io::Printer* printer);
+std::string DefaultValueForField(const FieldDescriptor* field);
+
+template<class numeric_type>
+std::string NumberToString(numeric_type value) {
+  std::ostringstream os;
+  os << value;
+  return os.str();
+}
+
+std::string GetRequireName(const std::string& proto_file) {
+  int lastindex = proto_file.find_last_of(".");
+  return proto_file.substr(0, lastindex) + "_pb";
+}
+
+std::string GetOutputFilename(const std::string& proto_file) {
+  return GetRequireName(proto_file) + ".rb";
+}
+
+std::string LabelForField(const FieldDescriptor* field) {
+  if (field->has_optional_keyword() &&
+      field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    return "proto3_optional";
+  }
+  switch (field->label()) {
+    case FieldDescriptor::LABEL_OPTIONAL: return "optional";
+    case FieldDescriptor::LABEL_REQUIRED: return "required";
+    case FieldDescriptor::LABEL_REPEATED: return "repeated";
+    default: assert(false); return "";
+  }
+}
+
+std::string TypeName(const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32: return "int32";
+    case FieldDescriptor::TYPE_INT64: return "int64";
+    case FieldDescriptor::TYPE_UINT32: return "uint32";
+    case FieldDescriptor::TYPE_UINT64: return "uint64";
+    case FieldDescriptor::TYPE_SINT32: return "sint32";
+    case FieldDescriptor::TYPE_SINT64: return "sint64";
+    case FieldDescriptor::TYPE_FIXED32: return "fixed32";
+    case FieldDescriptor::TYPE_FIXED64: return "fixed64";
+    case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
+    case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
+    case FieldDescriptor::TYPE_DOUBLE: return "double";
+    case FieldDescriptor::TYPE_FLOAT: return "float";
+    case FieldDescriptor::TYPE_BOOL: return "bool";
+    case FieldDescriptor::TYPE_ENUM: return "enum";
+    case FieldDescriptor::TYPE_STRING: return "string";
+    case FieldDescriptor::TYPE_BYTES: return "bytes";
+    case FieldDescriptor::TYPE_MESSAGE: return "message";
+    case FieldDescriptor::TYPE_GROUP: return "group";
+    default: assert(false); return "";
+  }
+}
+
+std::string StringifySyntax(FileDescriptor::Syntax syntax) {
+  switch (syntax) {
+    case FileDescriptor::SYNTAX_PROTO2:
+      return "proto2";
+    case FileDescriptor::SYNTAX_PROTO3:
+      return "proto3";
+    case FileDescriptor::SYNTAX_UNKNOWN:
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports "
+                           "proto2 and proto3 syntax.";
+      return "";
+  }
+}
+
+std::string DefaultValueForField(const FieldDescriptor* field) {
+  switch(field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return NumberToString(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return NumberToString(field->default_value_int64());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return NumberToString(field->default_value_uint32());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return NumberToString(field->default_value_uint64());
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return NumberToString(field->default_value_float());
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return NumberToString(field->default_value_double());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return NumberToString(field->default_value_enum()->number());
+    case FieldDescriptor::CPPTYPE_STRING: {
+      std::ostringstream os;
+      std::string default_str = field->default_value_string();
+
+      if (field->type() == FieldDescriptor::TYPE_STRING) {
+        os << "\"" << default_str << "\"";
+      } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
+        os << "\"";
+
+        os.fill('0');
+        for (int i = 0; i < default_str.length(); ++i) {
+          // Write the hex form of each byte.
+          os << "\\x" << std::hex << std::setw(2)
+             << ((uint16_t)((unsigned char)default_str.at(i)));
+        }
+        os << "\".force_encoding(\"ASCII-8BIT\")";
+      }
+
+      return os.str();
+    }
+    default: assert(false); return "";
+  }
+}
+
+void GenerateField(const FieldDescriptor* field, io::Printer* printer) {
+  if (field->is_map()) {
+    const FieldDescriptor* key_field =
+        field->message_type()->FindFieldByNumber(1);
+    const FieldDescriptor* value_field =
+        field->message_type()->FindFieldByNumber(2);
+
+    printer->Print(
+      "map :$name$, :$key_type$, :$value_type$, $number$",
+      "name", field->name(),
+      "key_type", TypeName(key_field),
+      "value_type", TypeName(value_field),
+      "number", NumberToString(field->number()));
+
+    if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+        ", \"$subtype$\"\n",
+        "subtype", value_field->message_type()->full_name());
+    } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      printer->Print(
+        ", \"$subtype$\"\n",
+        "subtype", value_field->enum_type()->full_name());
+    } else {
+      printer->Print("\n");
+    }
+  } else {
+
+    printer->Print(
+      "$label$ :$name$, ",
+      "label", LabelForField(field),
+      "name", field->name());
+    printer->Print(
+      ":$type$, $number$",
+      "type", TypeName(field),
+      "number", NumberToString(field->number()));
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+        ", \"$subtype$\"",
+       "subtype", field->message_type()->full_name());
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      printer->Print(
+        ", \"$subtype$\"",
+        "subtype", field->enum_type()->full_name());
+    }
+
+    if (field->has_default_value()) {
+      printer->Print(", default: $default$", "default",
+                     DefaultValueForField(field));
+    }
+
+    if (field->has_json_name()) {
+      printer->Print(", json_name: \"$json_name$\"", "json_name",
+                    field->json_name());
+    }
+
+    printer->Print("\n");
+  }
+}
+
+void GenerateOneof(const OneofDescriptor* oneof, io::Printer* printer) {
+  printer->Print(
+      "oneof :$name$ do\n",
+      "name", oneof->name());
+  printer->Indent();
+
+  for (int i = 0; i < oneof->field_count(); i++) {
+    const FieldDescriptor* field = oneof->field(i);
+    GenerateField(field, printer);
+  }
+
+  printer->Outdent();
+  printer->Print("end\n");
+}
+
+bool GenerateMessage(const Descriptor* message, io::Printer* printer,
+                     std::string* error) {
+  if (message->extension_range_count() > 0 || message->extension_count() > 0) {
+    GOOGLE_LOG(WARNING) << "Extensions are not yet supported for proto2 .proto files.";
+  }
+
+  // Don't generate MapEntry messages -- we use the Ruby extension's native
+  // support for map fields instead.
+  if (message->options().map_entry()) {
+    return true;
+  }
+
+  printer->Print(
+    "add_message \"$name$\" do\n",
+    "name", message->full_name());
+  printer->Indent();
+
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    if (!field->real_containing_oneof()) {
+      GenerateField(field, printer);
+    }
+  }
+
+  for (int i = 0; i < message->real_oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    GenerateOneof(oneof, printer);
+  }
+
+  printer->Outdent();
+  printer->Print("end\n");
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    if (!GenerateMessage(message->nested_type(i), printer, error)) {
+      return false;
+    }
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnum(message->enum_type(i), printer);
+  }
+
+  return true;
+}
+
+void GenerateEnum(const EnumDescriptor* en, io::Printer* printer) {
+  printer->Print(
+    "add_enum \"$name$\" do\n",
+    "name", en->full_name());
+  printer->Indent();
+
+  for (int i = 0; i < en->value_count(); i++) {
+    const EnumValueDescriptor* value = en->value(i);
+    printer->Print(
+      "value :$name$, $number$\n",
+      "name", value->name(),
+      "number", NumberToString(value->number()));
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "end\n");
+}
+
+// Locale-agnostic utility functions.
+bool IsLower(char ch) { return ch >= 'a' && ch <= 'z'; }
+
+bool IsUpper(char ch) { return ch >= 'A' && ch <= 'Z'; }
+
+bool IsAlpha(char ch) { return IsLower(ch) || IsUpper(ch); }
+
+char UpperChar(char ch) { return IsLower(ch) ? (ch - 'a' + 'A') : ch; }
+
+
+// Package names in protobuf are snake_case by convention, but Ruby module
+// names must be PascalCased.
+//
+//   foo_bar_baz -> FooBarBaz
+std::string PackageToModule(const std::string& name) {
+  bool next_upper = true;
+  std::string result;
+  result.reserve(name.size());
+
+  for (int i = 0; i < name.size(); i++) {
+    if (name[i] == '_') {
+      next_upper = true;
+    } else {
+      if (next_upper) {
+        result.push_back(UpperChar(name[i]));
+      } else {
+        result.push_back(name[i]);
+      }
+      next_upper = false;
+    }
+  }
+
+  return result;
+}
+
+// Class and enum names in protobuf should be PascalCased by convention, but
+// since there is nothing enforcing this we need to ensure that they are valid
+// Ruby constants.  That mainly means making sure that the first character is
+// an upper-case letter.
+std::string RubifyConstant(const std::string& name) {
+  std::string ret = name;
+  if (!ret.empty()) {
+    if (IsLower(ret[0])) {
+      // If it starts with a lowercase letter, capitalize it.
+      ret[0] = UpperChar(ret[0]);
+    } else if (!IsAlpha(ret[0])) {
+      // Otherwise (e.g. if it begins with an underscore), we need to come up
+      // with some prefix that starts with a capital letter. We could be smarter
+      // here, e.g. try to strip leading underscores, but this may cause other
+      // problems if the user really intended the name. So let's just prepend a
+      // well-known suffix.
+      ret = "PB_" + ret;
+    }
+  }
+
+  return ret;
+}
+
+void GenerateMessageAssignment(const std::string& prefix,
+                               const Descriptor* message,
+                               io::Printer* printer) {
+  // Don't generate MapEntry messages -- we use the Ruby extension's native
+  // support for map fields instead.
+  if (message->options().map_entry()) {
+    return;
+  }
+
+  printer->Print(
+    "$prefix$$name$ = ",
+    "prefix", prefix,
+    "name", RubifyConstant(message->name()));
+  printer->Print(
+    "::Google::Protobuf::DescriptorPool.generated_pool."
+    "lookup(\"$full_name$\").msgclass\n",
+    "full_name", message->full_name());
+
+  std::string nested_prefix = prefix + RubifyConstant(message->name()) + "::";
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateMessageAssignment(nested_prefix, message->nested_type(i), printer);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnumAssignment(nested_prefix, message->enum_type(i), printer);
+  }
+}
+
+void GenerateEnumAssignment(const std::string& prefix, const EnumDescriptor* en,
+                            io::Printer* printer) {
+  printer->Print(
+    "$prefix$$name$ = ",
+    "prefix", prefix,
+    "name", RubifyConstant(en->name()));
+  printer->Print(
+    "::Google::Protobuf::DescriptorPool.generated_pool."
+    "lookup(\"$full_name$\").enummodule\n",
+    "full_name", en->full_name());
+}
+
+int GeneratePackageModules(const FileDescriptor* file, io::Printer* printer) {
+  int levels = 0;
+  bool need_change_to_module = true;
+  std::string package_name;
+
+  // Determine the name to use in either format:
+  //   proto package:         one.two.three
+  //   option ruby_package:   One::Two::Three
+  if (file->options().has_ruby_package()) {
+    package_name = file->options().ruby_package();
+
+    // If :: is in the package use the Ruby formatted name as-is
+    //    -> A::B::C
+    // otherwise, use the dot separator
+    //    -> A.B.C
+    if (package_name.find("::") != std::string::npos) {
+      need_change_to_module = false;
+    } else if (package_name.find(".") != std::string::npos) {
+      GOOGLE_LOG(WARNING) << "ruby_package option should be in the form of:"
+                          << " 'A::B::C' and not 'A.B.C'";
+    }
+  } else {
+    package_name = file->package();
+  }
+
+  // Use the appropriate delimiter
+  std::string delimiter = need_change_to_module ? "." : "::";
+  int delimiter_size = need_change_to_module ? 1 : 2;
+
+  // Extract each module name and indent
+  while (!package_name.empty()) {
+    size_t dot_index = package_name.find(delimiter);
+    std::string component;
+    if (dot_index == std::string::npos) {
+      component = package_name;
+      package_name = "";
+    } else {
+      component = package_name.substr(0, dot_index);
+      package_name = package_name.substr(dot_index + delimiter_size);
+    }
+    if (need_change_to_module) {
+      component = PackageToModule(component);
+    }
+    printer->Print(
+      "module $name$\n",
+      "name", component);
+    printer->Indent();
+    levels++;
+  }
+  return levels;
+}
+
+void EndPackageModules(int levels, io::Printer* printer) {
+  while (levels > 0) {
+    levels--;
+    printer->Outdent();
+    printer->Print(
+      "end\n");
+  }
+}
+
+bool GenerateDslDescriptor(const FileDescriptor* file, io::Printer* printer,
+                           std::string* error) {
+  printer->Print("Google::Protobuf::DescriptorPool.generated_pool.build do\n");
+  printer->Indent();
+  printer->Print("add_file(\"$filename$\", :syntax => :$syntax$) do\n",
+                 "filename", file->name(), "syntax",
+                 StringifySyntax(file->syntax()));
+  printer->Indent();
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (!GenerateMessage(file->message_type(i), printer, error)) {
+      return false;
+    }
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnum(file->enum_type(i), printer);
+  }
+  printer->Outdent();
+  printer->Print("end\n");
+  printer->Outdent();
+  printer->Print(
+    "end\n\n");
+  return true;
+}
+
+bool GenerateBinaryDescriptor(const FileDescriptor* file, io::Printer* printer,
+                              std::string* error) {
+  printer->Print(
+      R"(descriptor_data = File.binread(__FILE__).split("\n__END__\n", 2)[1])");
+  printer->Print(
+      "\nGoogle::Protobuf::DescriptorPool.generated_pool.add_serialized_file("
+      "descriptor_data)\n\n");
+  return true;
+}
+
+bool GenerateFile(const FileDescriptor* file, io::Printer* printer,
+                  std::string* error) {
+  printer->Print(
+    "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "# source: $filename$\n"
+    "\n",
+    "filename", file->name());
+
+  printer->Print("require 'google/protobuf'\n\n");
+
+  if (file->dependency_count() != 0) {
+    for (int i = 0; i < file->dependency_count(); i++) {
+      printer->Print("require '$name$'\n", "name", GetRequireName(file->dependency(i)->name()));
+    }
+    printer->Print("\n");
+  }
+
+  // TODO: Remove this when ruby supports extensions for proto2 syntax.
+  if (file->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
+      file->extension_count() > 0) {
+    GOOGLE_LOG(WARNING) << "Extensions are not yet supported for proto2 .proto files.";
+  }
+
+  bool use_raw_descriptor = file->name() == "google/protobuf/descriptor.proto";
+
+  if (use_raw_descriptor) {
+    GenerateBinaryDescriptor(file, printer, error);
+  } else {
+    GenerateDslDescriptor(file, printer, error);
+  }
+
+  int levels = GeneratePackageModules(file, printer);
+  for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateMessageAssignment("", file->message_type(i), printer);
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnumAssignment("", file->enum_type(i), printer);
+  }
+  EndPackageModules(levels, printer);
+
+  if (use_raw_descriptor) {
+    printer->Print("\n__END__\n");
+    FileDescriptorProto file_proto;
+    file->CopyTo(&file_proto);
+    std::string file_data;
+    file_proto.SerializeToString(&file_data);
+    printer->Print("$raw_descriptor$", "raw_descriptor", file_data);
+  }
+  return true;
+}
+
+bool Generator::Generate(
+    const FileDescriptor* file,
+    const std::string& parameter,
+    GeneratorContext* generator_context,
+    std::string* error) const {
+
+  if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
+      file->syntax() != FileDescriptor::SYNTAX_PROTO2) {
+    *error = "Invalid or unsupported proto syntax";
+    return false;
+  }
+
+  std::unique_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(GetOutputFilename(file->name())));
+  io::Printer printer(output.get(), '$');
+
+  return GenerateFile(file, &printer, error);
+}
+
+}  // namespace ruby
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.h b/src/google/protobuf/compiler/ruby/ruby_generator.h
new file mode 100644
index 0000000..647bb83
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.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.
+
+// Generates Ruby code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+
+// CodeGenerator implementation for generated Ruby protocol buffer classes.
+// If you create your own protocol compiler binary and you want it to support
+// Ruby output, you can do so by registering an instance of this
+// CodeGenerator with the CommandLineInterface in your main() function.
+class PROTOC_EXPORT Generator : public CodeGenerator {
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* generator_context,
+                std::string* error) const override;
+  uint64_t GetSupportedFeatures() const override {
+    return FEATURE_PROTO3_OPTIONAL;
+  }
+};
+
+}  // namespace ruby
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
new file mode 100644
index 0000000..c3ce1d3
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -0,0 +1,145 @@
+// 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 <list>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+namespace {
+
+std::string FindRubyTestDir() {
+  return TestSourceDir() + "/google/protobuf/compiler/ruby";
+}
+
+// This test is a simple golden-file test over the output of the Ruby code
+// generator. When we make changes to the Ruby extension and alter the Ruby code
+// generator to use those changes, we should (i) manually test the output of the
+// code generator with the extension, and (ii) update the golden output above.
+// Some day, we may integrate build systems between protoc and the language
+// extensions to the point where we can do this test in a more automated way.
+
+void RubyTest(std::string proto_file, std::string import_proto_file = "") {
+  std::string ruby_tests = FindRubyTestDir();
+
+  google::protobuf::compiler::CommandLineInterface cli;
+  cli.SetInputsAreProtoPathRelative(true);
+
+  ruby::Generator ruby_generator;
+  cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+
+  // Copy generated_code.proto to the temporary test directory.
+  std::string test_input;
+  GOOGLE_CHECK_OK(File::GetContents(
+      ruby_tests + proto_file + ".proto",
+      &test_input,
+      true));
+  GOOGLE_CHECK_OK(File::SetContents(
+      TestTempDir() + proto_file + ".proto",
+      test_input,
+      true));
+
+  // Copy generated_code_import.proto to the temporary test directory.
+  std::string test_import;
+  if (!import_proto_file.empty()) {
+    GOOGLE_CHECK_OK(File::GetContents(
+        ruby_tests + import_proto_file + ".proto",
+        &test_import,
+        true));
+    GOOGLE_CHECK_OK(File::SetContents(
+        TestTempDir() + import_proto_file + ".proto",
+        test_import,
+        true));
+  }
+
+  // Invoke the proto compiler (we will be inside TestTempDir() at this point).
+  std::string ruby_out = "--ruby_out=" + TestTempDir();
+  std::string proto_path = "--proto_path=" + TestTempDir();
+
+  std::string proto_target = TestTempDir() + proto_file + ".proto";
+  const char* argv[] = {
+    "protoc",
+    ruby_out.c_str(),
+    proto_path.c_str(),
+    proto_target.c_str(),
+  };
+
+  EXPECT_EQ(0, cli.Run(4, argv));
+
+  // Load the generated output and compare to the expected result.
+  std::string output;
+  GOOGLE_CHECK_OK(File::GetContentsAsText(
+      TestTempDir() + proto_file + "_pb.rb",
+      &output,
+      true));
+  std::string expected_output;
+  GOOGLE_CHECK_OK(File::GetContentsAsText(
+      ruby_tests + proto_file + "_pb.rb",
+      &expected_output,
+      true));
+  EXPECT_EQ(expected_output, output);
+}
+
+TEST(RubyGeneratorTest, Proto3GeneratorTest) {
+  RubyTest("/ruby_generated_code", "/ruby_generated_code_proto2_import");
+}
+
+TEST(RubyGeneratorTest, Proto2GeneratorTest) {
+    RubyTest("/ruby_generated_code_proto2", "/ruby_generated_code_proto2_import");
+}
+
+TEST(RubyGeneratorTest, Proto3ImplicitPackageTest) {
+    RubyTest("/ruby_generated_pkg_implicit");
+}
+
+TEST(RubyGeneratorTest, Proto3ExplictPackageTest) {
+    RubyTest("/ruby_generated_pkg_explicit");
+}
+
+TEST(RubyGeneratorTest, Proto3ExplictLegacyPackageTest) {
+    RubyTest("/ruby_generated_pkg_explicit_legacy");
+}
+
+}  // namespace
+}  // namespace ruby
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/scc.h b/src/google/protobuf/compiler/scc.h
new file mode 100644
index 0000000..7b95689
--- /dev/null
+++ b/src/google/protobuf/compiler/scc.h
@@ -0,0 +1,165 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_SCC_H__
+#define GOOGLE_PROTOBUF_COMPILER_SCC_H__
+
+#include <map>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+// Description of each strongly connected component. Note that the order
+// of both the descriptors in this SCC and the order of children is
+// deterministic.
+struct SCC {
+  std::vector<const Descriptor*> descriptors;
+  std::vector<const SCC*> children;
+
+  const Descriptor* GetRepresentative() const { return descriptors[0]; }
+
+  // All messages must necessarily be in the same file.
+  const FileDescriptor* GetFile() const { return descriptors[0]->file(); }
+};
+
+// This class is used for analyzing the SCC for each message, to ensure linear
+// instead of quadratic performance, if we do this per message we would get
+// O(V*(V+E)).
+template <class DepsGenerator>
+class PROTOC_EXPORT SCCAnalyzer {
+ public:
+  explicit SCCAnalyzer() : index_(0) {}
+
+  const SCC* GetSCC(const Descriptor* descriptor) {
+    if (cache_.count(descriptor)) return cache_[descriptor].scc;
+    return DFS(descriptor).scc;
+  }
+
+ private:
+  struct NodeData {
+    const SCC* scc;  // if null it means its still on the stack
+    int index;
+    int lowlink;
+  };
+
+  std::map<const Descriptor*, NodeData> cache_;
+  std::vector<const Descriptor*> stack_;
+  int index_;
+  std::vector<std::unique_ptr<SCC>> garbage_bin_;
+
+  SCC* CreateSCC() {
+    garbage_bin_.emplace_back(new SCC());
+    return garbage_bin_.back().get();
+  }
+
+  // Tarjan's Strongly Connected Components algo
+  NodeData DFS(const Descriptor* descriptor) {
+    // Must not have visited already.
+    GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
+
+    // Mark visited by inserting in map.
+    NodeData& result = cache_[descriptor];
+    // Initialize data structures.
+    result.index = result.lowlink = index_++;
+    stack_.push_back(descriptor);
+
+    // Recurse the fields / nodes in graph
+    for (auto dep : DepsGenerator()(descriptor)) {
+      GOOGLE_CHECK(dep);
+      if (cache_.count(dep) == 0) {
+        // unexplored node
+        NodeData child_data = DFS(dep);
+        result.lowlink = std::min(result.lowlink, child_data.lowlink);
+      } else {
+        NodeData child_data = cache_[dep];
+        if (child_data.scc == nullptr) {
+          // Still in the stack_ so we found a back edge
+          result.lowlink = std::min(result.lowlink, child_data.index);
+        }
+      }
+    }
+    if (result.index == result.lowlink) {
+      // This is the root of a strongly connected component
+      SCC* scc = CreateSCC();
+      while (true) {
+        const Descriptor* scc_desc = stack_.back();
+        scc->descriptors.push_back(scc_desc);
+        // Remove from stack
+        stack_.pop_back();
+        cache_[scc_desc].scc = scc;
+
+        if (scc_desc == descriptor) break;
+      }
+
+      // The order of descriptors is random and depends how this SCC was
+      // discovered. In-order to ensure maximum stability we sort it by name.
+      std::sort(scc->descriptors.begin(), scc->descriptors.end(),
+                [](const Descriptor* a, const Descriptor* b) {
+                  return a->full_name() < b->full_name();
+                });
+      AddChildren(scc);
+    }
+    return result;
+  }
+
+  // Add the SCC's that are children of this SCC to its children.
+  void AddChildren(SCC* scc) {
+    std::set<const SCC*> seen;
+    for (auto descriptor : scc->descriptors) {
+      for (auto child_msg : DepsGenerator()(descriptor)) {
+        GOOGLE_CHECK(child_msg);
+        const SCC* child = GetSCC(child_msg);
+        if (child == scc) continue;
+        if (seen.insert(child).second) {
+          scc->children.push_back(child);
+        }
+      }
+    }
+  }
+
+  // This is necessary for compiler bug in msvc2015.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SCCAnalyzer);
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_SCC_H__
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
new file mode 100644
index 0000000..6f547db
--- /dev/null
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -0,0 +1,498 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/compiler/subprocess.h>
+
+#include <algorithm>
+#include <cstring>
+#include <iostream>
+
+#ifndef _WIN32
+#include <errno.h>
+#include <signal.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#endif
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/io/io_win32.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+namespace {
+char* portable_strdup(const char* s) {
+  char* ns = (char*)malloc(strlen(s) + 1);
+  if (ns != nullptr) {
+    strcpy(ns, s);
+  }
+  return ns;
+}
+}  // namespace
+
+#ifdef _WIN32
+
+static void CloseHandleOrDie(HANDLE handle) {
+  if (!CloseHandle(handle)) {
+    GOOGLE_LOG(FATAL) << "CloseHandle: "
+                      << Subprocess::Win32ErrorMessage(GetLastError());
+  }
+}
+
+Subprocess::Subprocess()
+    : process_start_error_(ERROR_SUCCESS),
+      child_handle_(nullptr),
+      child_stdin_(nullptr),
+      child_stdout_(nullptr) {}
+
+Subprocess::~Subprocess() {
+  if (child_stdin_ != nullptr) {
+    CloseHandleOrDie(child_stdin_);
+  }
+  if (child_stdout_ != nullptr) {
+    CloseHandleOrDie(child_stdout_);
+  }
+}
+
+void Subprocess::Start(const std::string& program, SearchMode search_mode) {
+  // Create the pipes.
+  HANDLE stdin_pipe_read;
+  HANDLE stdin_pipe_write;
+  HANDLE stdout_pipe_read;
+  HANDLE stdout_pipe_write;
+
+  if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, nullptr, 0)) {
+    GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
+  }
+  if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, nullptr, 0)) {
+    GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
+  }
+
+  // Make child side of the pipes inheritable.
+  if (!SetHandleInformation(stdin_pipe_read, HANDLE_FLAG_INHERIT,
+                            HANDLE_FLAG_INHERIT)) {
+    GOOGLE_LOG(FATAL) << "SetHandleInformation: "
+                      << Win32ErrorMessage(GetLastError());
+  }
+  if (!SetHandleInformation(stdout_pipe_write, HANDLE_FLAG_INHERIT,
+                            HANDLE_FLAG_INHERIT)) {
+    GOOGLE_LOG(FATAL) << "SetHandleInformation: "
+                      << Win32ErrorMessage(GetLastError());
+  }
+
+  // Setup STARTUPINFO to redirect handles.
+  STARTUPINFOW startup_info;
+  ZeroMemory(&startup_info, sizeof(startup_info));
+  startup_info.cb = sizeof(startup_info);
+  startup_info.dwFlags = STARTF_USESTDHANDLES;
+  startup_info.hStdInput = stdin_pipe_read;
+  startup_info.hStdOutput = stdout_pipe_write;
+  startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+  if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
+    GOOGLE_LOG(FATAL) << "GetStdHandle: " << Win32ErrorMessage(GetLastError());
+  }
+
+  // get wide string version of program as the path may contain non-ascii characters
+  std::wstring wprogram;
+  if (!io::win32::strings::utf8_to_wcs(program.c_str(), &wprogram)) {
+    GOOGLE_LOG(FATAL) << "utf8_to_wcs: " << Win32ErrorMessage(GetLastError());
+  }
+
+  // Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'.
+  std::string command_line = "cmd.exe /c \"" + program + "\"";
+
+  // get wide string version of command line as the path may contain non-ascii characters
+  std::wstring wcommand_line;
+  if (!io::win32::strings::utf8_to_wcs(command_line.c_str(), &wcommand_line)) {
+    GOOGLE_LOG(FATAL) << "utf8_to_wcs: " << Win32ErrorMessage(GetLastError());
+  }
+
+  // Using a malloc'ed string because CreateProcess() can mutate its second
+  // parameter.
+  wchar_t *wcommand_line_copy = _wcsdup(wcommand_line.c_str());
+
+  // Create the process.
+  PROCESS_INFORMATION process_info;
+
+  if (CreateProcessW((search_mode == SEARCH_PATH) ? nullptr : wprogram.c_str(),
+                     (search_mode == SEARCH_PATH) ? wcommand_line_copy : NULL,
+                     nullptr,  // process security attributes
+                     nullptr,  // thread security attributes
+                     TRUE,     // inherit handles?
+                     0,        // obscure creation flags
+                     nullptr,  // environment (inherit from parent)
+                     nullptr,  // current directory (inherit from parent)
+                     &startup_info, &process_info)) {
+    child_handle_ = process_info.hProcess;
+    CloseHandleOrDie(process_info.hThread);
+    child_stdin_ = stdin_pipe_write;
+    child_stdout_ = stdout_pipe_read;
+  } else {
+    process_start_error_ = GetLastError();
+    CloseHandleOrDie(stdin_pipe_write);
+    CloseHandleOrDie(stdout_pipe_read);
+  }
+
+  CloseHandleOrDie(stdin_pipe_read);
+  CloseHandleOrDie(stdout_pipe_write);
+  free(wcommand_line_copy);
+}
+
+bool Subprocess::Communicate(const Message& input, Message* output,
+                             std::string* error) {
+  if (process_start_error_ != ERROR_SUCCESS) {
+    *error = Win32ErrorMessage(process_start_error_);
+    return false;
+  }
+
+  GOOGLE_CHECK(child_handle_ != nullptr) << "Must call Start() first.";
+
+  std::string input_data;
+  if (!input.SerializeToString(&input_data)) {
+    *error = "Failed to serialize request.";
+    return false;
+  }
+  std::string output_data;
+
+  int input_pos = 0;
+
+  while (child_stdout_ != nullptr) {
+    HANDLE handles[2];
+    int handle_count = 0;
+
+    if (child_stdin_ != nullptr) {
+      handles[handle_count++] = child_stdin_;
+    }
+    if (child_stdout_ != nullptr) {
+      handles[handle_count++] = child_stdout_;
+    }
+
+    DWORD wait_result =
+        WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
+
+    HANDLE signaled_handle = nullptr;
+    if (wait_result >= WAIT_OBJECT_0 &&
+        wait_result < WAIT_OBJECT_0 + handle_count) {
+      signaled_handle = handles[wait_result - WAIT_OBJECT_0];
+    } else if (wait_result == WAIT_FAILED) {
+      GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: "
+                        << Win32ErrorMessage(GetLastError());
+    } else {
+      GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
+                        << wait_result;
+    }
+
+    if (signaled_handle == child_stdin_) {
+      DWORD n;
+      if (!WriteFile(child_stdin_, input_data.data() + input_pos,
+                     input_data.size() - input_pos, &n, nullptr)) {
+        // Child closed pipe.  Presumably it will report an error later.
+        // Pretend we're done for now.
+        input_pos = input_data.size();
+      } else {
+        input_pos += n;
+      }
+
+      if (input_pos == input_data.size()) {
+        // We're done writing.  Close.
+        CloseHandleOrDie(child_stdin_);
+        child_stdin_ = nullptr;
+      }
+    } else if (signaled_handle == child_stdout_) {
+      char buffer[4096];
+      DWORD n;
+
+      if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, nullptr)) {
+        // We're done reading.  Close.
+        CloseHandleOrDie(child_stdout_);
+        child_stdout_ = nullptr;
+      } else {
+        output_data.append(buffer, n);
+      }
+    }
+  }
+
+  if (child_stdin_ != nullptr) {
+    // Child did not finish reading input before it closed the output.
+    // Presumably it exited with an error.
+    CloseHandleOrDie(child_stdin_);
+    child_stdin_ = nullptr;
+  }
+
+  DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
+
+  if (wait_result == WAIT_FAILED) {
+    GOOGLE_LOG(FATAL) << "WaitForSingleObject: "
+                      << Win32ErrorMessage(GetLastError());
+  } else if (wait_result != WAIT_OBJECT_0) {
+    GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
+                      << wait_result;
+  }
+
+  DWORD exit_code;
+  if (!GetExitCodeProcess(child_handle_, &exit_code)) {
+    GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
+                      << Win32ErrorMessage(GetLastError());
+  }
+
+  CloseHandleOrDie(child_handle_);
+  child_handle_ = nullptr;
+
+  if (exit_code != 0) {
+    *error = strings::Substitute("Plugin failed with status code $0.", exit_code);
+    return false;
+  }
+
+  if (!output->ParseFromString(output_data)) {
+    *error = "Plugin output is unparseable: " + CEscape(output_data);
+    return false;
+  }
+
+  return true;
+}
+
+std::string Subprocess::Win32ErrorMessage(DWORD error_code) {
+  char* message;
+
+  // WTF?
+  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+                     FORMAT_MESSAGE_IGNORE_INSERTS,
+                 nullptr, error_code,
+                 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+                 (LPSTR)&message,  // NOT A BUG!
+                 0, nullptr);
+
+  std::string result = message;
+  LocalFree(message);
+  return result;
+}
+
+// ===================================================================
+
+#else  // _WIN32
+
+Subprocess::Subprocess()
+    : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
+
+Subprocess::~Subprocess() {
+  if (child_stdin_ != -1) {
+    close(child_stdin_);
+  }
+  if (child_stdout_ != -1) {
+    close(child_stdout_);
+  }
+}
+
+void Subprocess::Start(const std::string& program, SearchMode search_mode) {
+  // Note that we assume that there are no other threads, thus we don't have to
+  // do crazy stuff like using socket pairs or avoiding libc locks.
+
+  // [0] is read end, [1] is write end.
+  int stdin_pipe[2];
+  int stdout_pipe[2];
+
+  GOOGLE_CHECK(pipe(stdin_pipe) != -1);
+  GOOGLE_CHECK(pipe(stdout_pipe) != -1);
+
+  char* argv[2] = {portable_strdup(program.c_str()), nullptr};
+
+  child_pid_ = fork();
+  if (child_pid_ == -1) {
+    GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
+  } else if (child_pid_ == 0) {
+    // We are the child.
+    dup2(stdin_pipe[0], STDIN_FILENO);
+    dup2(stdout_pipe[1], STDOUT_FILENO);
+
+    close(stdin_pipe[0]);
+    close(stdin_pipe[1]);
+    close(stdout_pipe[0]);
+    close(stdout_pipe[1]);
+
+    switch (search_mode) {
+      case SEARCH_PATH:
+        execvp(argv[0], argv);
+        break;
+      case EXACT_NAME:
+        execv(argv[0], argv);
+        break;
+    }
+
+    // Write directly to STDERR_FILENO to avoid stdio code paths that may do
+    // stuff that is unsafe here.
+    int ignored;
+    ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
+    const char* message =
+        ": program not found or is not executable\n"
+        "Please specify a program using absolute path or make sure "
+        "the program is available in your PATH system variable\n";
+    ignored = write(STDERR_FILENO, message, strlen(message));
+    (void)ignored;
+
+    // Must use _exit() rather than exit() to avoid flushing output buffers
+    // that will also be flushed by the parent.
+    _exit(1);
+  } else {
+    free(argv[0]);
+
+    close(stdin_pipe[0]);
+    close(stdout_pipe[1]);
+
+    child_stdin_ = stdin_pipe[1];
+    child_stdout_ = stdout_pipe[0];
+  }
+}
+
+bool Subprocess::Communicate(const Message& input, Message* output,
+                             std::string* error) {
+  GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";
+
+  // The "sighandler_t" typedef is GNU-specific, so define our own.
+  typedef void SignalHandler(int);
+
+  // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
+  SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
+
+  std::string input_data;
+  if (!input.SerializeToString(&input_data)) {
+    *error = "Failed to serialize request.";
+    return false;
+  }
+  std::string output_data;
+
+  int input_pos = 0;
+  int max_fd = std::max(child_stdin_, child_stdout_);
+
+  while (child_stdout_ != -1) {
+    fd_set read_fds;
+    fd_set write_fds;
+    FD_ZERO(&read_fds);
+    FD_ZERO(&write_fds);
+    if (child_stdout_ != -1) {
+      FD_SET(child_stdout_, &read_fds);
+    }
+    if (child_stdin_ != -1) {
+      FD_SET(child_stdin_, &write_fds);
+    }
+
+    if (select(max_fd + 1, &read_fds, &write_fds, nullptr, nullptr) < 0) {
+      if (errno == EINTR) {
+        // Interrupted by signal.  Try again.
+        continue;
+      } else {
+        GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
+      }
+    }
+
+    if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
+      int n = write(child_stdin_, input_data.data() + input_pos,
+                    input_data.size() - input_pos);
+      if (n < 0) {
+        // Child closed pipe.  Presumably it will report an error later.
+        // Pretend we're done for now.
+        input_pos = input_data.size();
+      } else {
+        input_pos += n;
+      }
+
+      if (input_pos == input_data.size()) {
+        // We're done writing.  Close.
+        close(child_stdin_);
+        child_stdin_ = -1;
+      }
+    }
+
+    if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
+      char buffer[4096];
+      int n = read(child_stdout_, buffer, sizeof(buffer));
+
+      if (n > 0) {
+        output_data.append(buffer, n);
+      } else {
+        // We're done reading.  Close.
+        close(child_stdout_);
+        child_stdout_ = -1;
+      }
+    }
+  }
+
+  if (child_stdin_ != -1) {
+    // Child did not finish reading input before it closed the output.
+    // Presumably it exited with an error.
+    close(child_stdin_);
+    child_stdin_ = -1;
+  }
+
+  int status;
+  while (waitpid(child_pid_, &status, 0) == -1) {
+    if (errno != EINTR) {
+      GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
+    }
+  }
+
+  // Restore SIGPIPE handling.
+  signal(SIGPIPE, old_pipe_handler);
+
+  if (WIFEXITED(status)) {
+    if (WEXITSTATUS(status) != 0) {
+      int error_code = WEXITSTATUS(status);
+      *error =
+          strings::Substitute("Plugin failed with status code $0.", error_code);
+      return false;
+    }
+  } else if (WIFSIGNALED(status)) {
+    int signal = WTERMSIG(status);
+    *error = strings::Substitute("Plugin killed by signal $0.", signal);
+    return false;
+  } else {
+    *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
+    return false;
+  }
+
+  if (!output->ParseFromString(output_data)) {
+    *error = "Plugin output is unparseable: " + CEscape(output_data);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // !_WIN32
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/subprocess.h b/src/google/protobuf/compiler/subprocess.h
new file mode 100644
index 0000000..5cb784d
--- /dev/null
+++ b/src/google/protobuf/compiler/subprocess.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
+#define GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN  // right...
+#endif
+#include <windows.h>
+#else  // _WIN32
+#include <sys/types.h>
+#include <unistd.h>
+#endif  // !_WIN32
+#include <google/protobuf/stubs/common.h>
+
+#include <string>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace compiler {
+
+// Utility class for launching sub-processes.
+class PROTOC_EXPORT Subprocess {
+ public:
+  Subprocess();
+  ~Subprocess();
+
+  enum SearchMode {
+    SEARCH_PATH,  // Use PATH environment variable.
+    EXACT_NAME    // Program is an exact file name; don't use the PATH.
+  };
+
+  // Start the subprocess.  Currently we don't provide a way to specify
+  // arguments as protoc plugins don't have any.
+  void Start(const std::string& program, SearchMode search_mode);
+
+  // Serialize the input message and pipe it to the subprocess's stdin, then
+  // close the pipe.  Meanwhile, read from the subprocess's stdout and parse
+  // the data into *output.  All this is done carefully to avoid deadlocks.
+  // Returns true if successful.  On any sort of error, returns false and sets
+  // *error to a description of the problem.
+  bool Communicate(const Message& input, Message* output, std::string* error);
+
+#ifdef _WIN32
+  // Given an error code, returns a human-readable error message.  This is
+  // defined here so that CommandLineInterface can share it.
+  static std::string Win32ErrorMessage(DWORD error_code);
+#endif
+
+ private:
+#ifdef _WIN32
+  DWORD process_start_error_;
+  HANDLE child_handle_;
+
+  // The file handles for our end of the child's pipes.  We close each and
+  // set it to NULL when no longer needed.
+  HANDLE child_stdin_;
+  HANDLE child_stdout_;
+
+#else  // _WIN32
+  pid_t child_pid_;
+
+  // The file descriptors for our end of the child's pipes.  We close each and
+  // set it to -1 when no longer needed.
+  int child_stdin_;
+  int child_stdout_;
+
+#endif  // !_WIN32
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
diff --git a/src/google/protobuf/compiler/test_plugin.cc b/src/google/protobuf/compiler/test_plugin.cc
new file mode 100644
index 0000000..2556078
--- /dev/null
+++ b/src/google/protobuf/compiler/test_plugin.cc
@@ -0,0 +1,63 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is a dummy code generator plugin used by
+// command_line_interface_unittest.
+
+#include <stdlib.h>
+
+#include <string>
+
+#include <google/protobuf/compiler/mock_code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+int ProtobufMain(int argc, char* argv[]) {
+  MockCodeGenerator generator("test_plugin");
+  return PluginMain(argc, argv, &generator);
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+int main(int argc, char* argv[]) {
+#ifdef _MSC_VER
+  // Don't print a silly message or stick a modal dialog box in my face,
+  // please.
+  _set_abort_behavior(0, ~0);
+#endif  // !_MSC_VER
+  return google::protobuf::compiler::ProtobufMain(argc, argv);
+}
diff --git a/src/google/protobuf/compiler/zip_output_unittest.sh b/src/google/protobuf/compiler/zip_output_unittest.sh
new file mode 100755
index 0000000..f859791
--- /dev/null
+++ b/src/google/protobuf/compiler/zip_output_unittest.sh
@@ -0,0 +1,100 @@
+#!/bin/sh
+#
+# Protocol Buffers - Google's data interchange format
+# Copyright 2009 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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)
+#
+# Test protoc's zip output mode.
+
+fail() {
+  echo "$@" >&2
+  exit 1
+}
+
+TEST_TMPDIR=.
+PROTOC=./protoc
+JAR=jar
+UNZIP=unzip
+
+echo '
+  syntax = "proto2";
+  option java_multiple_files = true;
+  option java_package = "test.jar";
+  option java_outer_classname = "Outer";
+  message Foo {}
+  message Bar {}
+' > $TEST_TMPDIR/testzip.proto
+
+$PROTOC \
+    --cpp_out=$TEST_TMPDIR/testzip.zip --python_out=$TEST_TMPDIR/testzip.zip \
+    --java_out=$TEST_TMPDIR/testzip.jar -I$TEST_TMPDIR testzip.proto \
+    || fail 'protoc failed.'
+
+echo "Testing output to zip..."
+if $UNZIP -h > /dev/null; then
+  $UNZIP -t $TEST_TMPDIR/testzip.zip > $TEST_TMPDIR/testzip.list \
+    || fail 'unzip failed.'
+
+  grep 'testing: testzip\.pb\.cc *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'testzip.pb.cc not found in output zip.'
+  grep 'testing: testzip\.pb\.h *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'testzip.pb.h not found in output zip.'
+  grep 'testing: testzip_pb2\.py *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'testzip_pb2.py not found in output zip.'
+  grep -i 'manifest' $TEST_TMPDIR/testzip.list > /dev/null \
+    && fail 'Zip file contained manifest.'
+else
+  echo "Warning:  'unzip' command not available.  Skipping test."
+fi
+
+echo "Testing output to jar..."
+if $JAR c $TEST_TMPDIR/testzip.proto > /dev/null; then
+  $JAR tf $TEST_TMPDIR/testzip.jar > $TEST_TMPDIR/testzip.list \
+    || fail 'jar failed.'
+
+  # Check that -interface.jar timestamps are normalized:
+  if [[ "$(TZ=UTC $JAR tvf $TEST_TMPDIR/testzip.jar)" != *'Tue Jan 01 00:00:00 UTC 1980'* ]]; then
+    fail 'Zip did not contain normalized timestamps'
+  fi
+
+  grep '^test/jar/Foo\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'Foo.java not found in output jar.'
+  grep '^test/jar/Bar\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'Bar.java not found in output jar.'
+  grep '^test/jar/Outer\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'Outer.java not found in output jar.'
+  grep '^META-INF/MANIFEST\.MF$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'Manifest not found in output jar.'
+else
+  echo "Warning:  'jar' command not available.  Skipping test."
+fi
+
+echo PASS
diff --git a/src/google/protobuf/compiler/zip_writer.cc b/src/google/protobuf/compiler/zip_writer.cc
new file mode 100644
index 0000000..72e1d71
--- /dev/null
+++ b/src/google/protobuf/compiler/zip_writer.cc
@@ -0,0 +1,195 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: ambrose@google.com (Ambrose Feinstein),
+//         kenton@google.com (Kenton Varda)
+//
+// Based on http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+#include <google/protobuf/compiler/zip_writer.h>
+
+#include <cstdint>
+
+#include <google/protobuf/io/coded_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+// January 1, 1980 as a DOS date.
+// see https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
+static const uint16_t kDosEpoch = 1 << 5 | 1;
+
+static const uint32_t kCRC32Table[256] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+
+static uint32_t ComputeCRC32(const std::string& buf) {
+  uint32_t x = ~0U;
+  for (int i = 0; i < buf.size(); ++i) {
+    unsigned char c = buf[i];
+    x = kCRC32Table[(x ^ c) & 0xff] ^ (x >> 8);
+  }
+  return ~x;
+}
+
+static void WriteShort(io::CodedOutputStream* out, uint16_t val) {
+  uint8_t p[2];
+  p[0] = static_cast<uint8_t>(val);
+  p[1] = static_cast<uint8_t>(val >> 8);
+  out->WriteRaw(p, 2);
+}
+
+ZipWriter::ZipWriter(io::ZeroCopyOutputStream* raw_output)
+    : raw_output_(raw_output) {}
+ZipWriter::~ZipWriter() {}
+
+bool ZipWriter::Write(const std::string& filename,
+                      const std::string& contents) {
+  FileInfo info;
+
+  info.name = filename;
+  uint16_t filename_size = filename.size();
+  info.offset = raw_output_->ByteCount();
+  info.size = contents.size();
+  info.crc32 = ComputeCRC32(contents);
+
+  files_.push_back(info);
+
+  // write file header
+  io::CodedOutputStream output(raw_output_);
+  output.WriteLittleEndian32(0x04034b50);  // magic
+  WriteShort(&output, 10);                 // version needed to extract
+  WriteShort(&output, 0);                  // flags
+  WriteShort(&output, 0);                  // compression method: stored
+  WriteShort(&output, 0);                  // last modified time
+  WriteShort(&output, kDosEpoch);          // last modified date
+  output.WriteLittleEndian32(info.crc32);  // crc-32
+  output.WriteLittleEndian32(info.size);   // compressed size
+  output.WriteLittleEndian32(info.size);   // uncompressed size
+  WriteShort(&output, filename_size);      // file name length
+  WriteShort(&output, 0);                  // extra field length
+  output.WriteString(filename);            // file name
+  output.WriteString(contents);            // file data
+
+  return !output.HadError();
+}
+
+bool ZipWriter::WriteDirectory() {
+  uint16_t num_entries = files_.size();
+  uint32_t dir_ofs = raw_output_->ByteCount();
+
+  // write central directory
+  io::CodedOutputStream output(raw_output_);
+  for (int i = 0; i < num_entries; ++i) {
+    const std::string& filename = files_[i].name;
+    uint16_t filename_size = filename.size();
+    uint32_t crc32 = files_[i].crc32;
+    uint32_t size = files_[i].size;
+    uint32_t offset = files_[i].offset;
+
+    output.WriteLittleEndian32(0x02014b50);  // magic
+    WriteShort(&output, 10);                 // version made by
+    WriteShort(&output, 10);                 // version needed to extract
+    WriteShort(&output, 0);                  // flags
+    WriteShort(&output, 0);                  // compression method: stored
+    WriteShort(&output, 0);                  // last modified time
+    WriteShort(&output, kDosEpoch);          // last modified date
+    output.WriteLittleEndian32(crc32);       // crc-32
+    output.WriteLittleEndian32(size);        // compressed size
+    output.WriteLittleEndian32(size);        // uncompressed size
+    WriteShort(&output, filename_size);      // file name length
+    WriteShort(&output, 0);                  // extra field length
+    WriteShort(&output, 0);                  // file comment length
+    WriteShort(&output, 0);                  // starting disk number
+    WriteShort(&output, 0);                  // internal file attributes
+    output.WriteLittleEndian32(0);           // external file attributes
+    output.WriteLittleEndian32(offset);      // local header offset
+    output.WriteString(filename);            // file name
+  }
+  uint32_t dir_len = output.ByteCount();
+
+  // write end of central directory marker
+  output.WriteLittleEndian32(0x06054b50);  // magic
+  WriteShort(&output, 0);                  // disk number
+  WriteShort(&output, 0);               // disk with start of central directory
+  WriteShort(&output, num_entries);     // central directory entries (this disk)
+  WriteShort(&output, num_entries);     // central directory entries (total)
+  output.WriteLittleEndian32(dir_len);  // central directory byte size
+  output.WriteLittleEndian32(dir_ofs);  // central directory offset
+  WriteShort(&output, 0);               // comment length
+
+  return output.HadError();
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/zip_writer.h b/src/google/protobuf/compiler/zip_writer.h
new file mode 100644
index 0000000..5d7f69a
--- /dev/null
+++ b/src/google/protobuf/compiler/zip_writer.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.
+
+// Author: kenton@google.com (Kenton Varda)
+#ifndef GOOGLE_PROTOBUF_COMPILER_ZIP_WRITER_H__
+#define GOOGLE_PROTOBUF_COMPILER_ZIP_WRITER_H__
+
+#include <cstdint>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+class ZipWriter {
+ public:
+  ZipWriter(io::ZeroCopyOutputStream* raw_output);
+  ~ZipWriter();
+
+  bool Write(const std::string& filename, const std::string& contents);
+  bool WriteDirectory();
+
+ private:
+  struct FileInfo {
+    std::string name;
+    uint32_t offset;
+    uint32_t size;
+    uint32_t crc32;
+  };
+
+  io::ZeroCopyOutputStream* raw_output_;
+  std::vector<FileInfo> files_;
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_ZIP_WRITER_H__
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
new file mode 100644
index 0000000..5f3427d
--- /dev/null
+++ b/src/google/protobuf/descriptor.cc
@@ -0,0 +1,8340 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/descriptor.h>
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <limits>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+#undef PACKAGE  // autoheader #defines this.  :(
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+const int kPackageLimit = 100;
+
+// Note:  I distrust ctype.h due to locales.
+char ToUpper(char ch) {
+  return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
+}
+
+char ToLower(char ch) {
+  return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
+}
+
+std::string ToCamelCase(const std::string& input, bool lower_first) {
+  bool capitalize_next = !lower_first;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpper(character));
+      capitalize_next = false;
+    } else {
+      result.push_back(character);
+    }
+  }
+
+  // Lower-case the first letter.
+  if (lower_first && !result.empty()) {
+    result[0] = ToLower(result[0]);
+  }
+
+  return result;
+}
+
+std::string ToJsonName(const std::string& input) {
+  bool capitalize_next = false;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpper(character));
+      capitalize_next = false;
+    } else {
+      result.push_back(character);
+    }
+  }
+
+  return result;
+}
+
+// Backport of fold expressions for the comma operator to C++11.
+// Usage:  Fold({expr...});
+// Guaranteed to evaluate left-to-right
+struct ExpressionEater {
+  template <typename T>
+  ExpressionEater(T&&) {}  // NOLINT
+};
+void Fold(std::initializer_list<ExpressionEater>) {}
+
+template <int R>
+constexpr size_t RoundUpTo(size_t n) {
+  static_assert((R & (R - 1)) == 0, "Must be power of two");
+  return (n + (R - 1)) & ~(R - 1);
+}
+
+constexpr size_t Max(size_t a, size_t b) { return a > b ? a : b; }
+template <typename T, typename... Ts>
+constexpr size_t Max(T a, Ts... b) {
+  return Max(a, Max(b...));
+}
+
+template <typename T>
+constexpr size_t EffectiveAlignof() {
+  // `char` is special in that it gets aligned to 8. It is where we drop the
+  // trivial structs.
+  return std::is_same<T, char>::value ? 8 : alignof(T);
+}
+
+template <int align, typename U, typename... T>
+using AppendIfAlign =
+    typename std::conditional<EffectiveAlignof<U>() == align, void (*)(T..., U),
+                              void (*)(T...)>::type;
+
+// Metafunction to sort types in descending order of alignment.
+// Useful for the flat allocator to ensure proper alignment of all elements
+// without having to add padding.
+// Instead of implementing a proper sort metafunction we just do a
+// filter+merge, which is much simpler to write as a metafunction.
+// We have a fixed set of alignments we can filter on.
+// For simplicity we use a function pointer as a type list.
+template <typename In, typename T16, typename T8, typename T4, typename T2,
+          typename T1>
+struct TypeListSortImpl;
+
+template <typename... T16, typename... T8, typename... T4, typename... T2,
+          typename... T1>
+struct TypeListSortImpl<void (*)(), void (*)(T16...), void (*)(T8...),
+                        void (*)(T4...), void (*)(T2...), void (*)(T1...)> {
+  using type = void (*)(T16..., T8..., T4..., T2..., T1...);
+};
+
+template <typename First, typename... Rest, typename... T16, typename... T8,
+          typename... T4, typename... T2, typename... T1>
+struct TypeListSortImpl<void (*)(First, Rest...), void (*)(T16...),
+                        void (*)(T8...), void (*)(T4...), void (*)(T2...),
+                        void (*)(T1...)> {
+  using type = typename TypeListSortImpl<
+      void (*)(Rest...), AppendIfAlign<16, First, T16...>,
+      AppendIfAlign<8, First, T8...>, AppendIfAlign<4, First, T4...>,
+      AppendIfAlign<2, First, T2...>, AppendIfAlign<1, First, T1...>>::type;
+};
+
+template <typename... T>
+using SortByAlignment =
+    typename TypeListSortImpl<void (*)(T...), void (*)(), void (*)(),
+                              void (*)(), void (*)(), void (*)()>::type;
+
+template <template <typename...> class C, typename... T>
+auto ApplyTypeList(void (*)(T...)) -> C<T...>;
+
+template <typename T>
+constexpr int FindTypeIndex() {
+  return -1;
+}
+
+template <typename T, typename T1, typename... Ts>
+constexpr int FindTypeIndex() {
+  return std::is_same<T, T1>::value ? 0 : FindTypeIndex<T, Ts...>() + 1;
+}
+
+// A type to value map, where the possible keys as specified in `Keys...`.
+// The values for key `K` is `ValueT<K>`
+template <template <typename> class ValueT, typename... Keys>
+class TypeMap {
+ public:
+  template <typename K>
+  ValueT<K>& Get() {
+    return static_cast<Base<K>&>(payload_).value;
+  }
+
+  template <typename K>
+  const ValueT<K>& Get() const {
+    return static_cast<const Base<K>&>(payload_).value;
+  }
+
+ private:
+  template <typename K>
+  struct Base {
+    ValueT<K> value{};
+  };
+  struct Payload : Base<Keys>... {};
+  Payload payload_;
+};
+
+template <typename T>
+using IntT = int;
+template <typename T>
+using PointerT = T*;
+
+// Manages an allocation of sequential arrays of type `T...`.
+// It is more space efficient than storing N (ptr, size) pairs, by storing only
+// the pointer to the head and the boundaries between the arrays.
+template <typename... T>
+class FlatAllocation {
+ public:
+  static constexpr size_t kMaxAlign = Max(alignof(T)...);
+
+  FlatAllocation(const TypeMap<IntT, T...>& ends) : ends_(ends) {
+    // The arrays start just after FlatAllocation, so adjust the ends.
+    Fold({(ends_.template Get<T>() +=
+           RoundUpTo<kMaxAlign>(sizeof(FlatAllocation)))...});
+    Fold({Init<T>()...});
+  }
+
+  void Destroy() {
+    Fold({Destroy<T>()...});
+    internal::SizedDelete(this, total_bytes());
+  }
+
+  template <int I>
+  using type = typename std::tuple_element<I, std::tuple<T...>>::type;
+
+  // Gets a tuple of the head pointers for the arrays
+  TypeMap<PointerT, T...> Pointers() const {
+    TypeMap<PointerT, T...> out;
+    Fold({(out.template Get<T>() = Begin<T>())...});
+    return out;
+  }
+
+
+ private:
+  // Total number of bytes used by all arrays.
+  int total_bytes() const {
+    // Get the last end.
+    return ends_.template Get<typename std::tuple_element<
+        sizeof...(T) - 1, std::tuple<T...>>::type>();
+  }
+
+
+  template <typename U>
+  int BeginOffset() const {
+    constexpr int type_index = FindTypeIndex<U, T...>();
+    // Avoid a negative value here to keep it compiling when type_index == 0
+    constexpr int prev_type_index = type_index == 0 ? 0 : type_index - 1;
+    using PrevType =
+        typename std::tuple_element<prev_type_index, std::tuple<T...>>::type;
+    // Ensure the types are properly aligned.
+    static_assert(EffectiveAlignof<PrevType>() >= EffectiveAlignof<U>(), "");
+    return type_index == 0 ? RoundUpTo<kMaxAlign>(sizeof(FlatAllocation))
+                           : ends_.template Get<PrevType>();
+  }
+
+  template <typename U>
+  int EndOffset() const {
+    return ends_.template Get<U>();
+  }
+
+  // Avoid the reinterpret_cast if the array is empty.
+  // Clang's Control Flow Integrity does not like the cast pointing to memory
+  // that is not yet initialized to be of that type.
+  // (from -fsanitize=cfi-unrelated-cast)
+  template <typename U>
+  U* Begin() const {
+    int begin = BeginOffset<U>(), end = EndOffset<U>();
+    if (begin == end) return nullptr;
+    return reinterpret_cast<U*>(data() + begin);
+  }
+
+  template <typename U>
+  U* End() const {
+    int begin = BeginOffset<U>(), end = EndOffset<U>();
+    if (begin == end) return nullptr;
+    return reinterpret_cast<U*>(data() + end);
+  }
+
+  template <typename U>
+  bool Init() {
+    // Skip for the `char` block. No need to zero initialize it.
+    if (std::is_same<U, char>::value) return true;
+    for (char *p = data() + BeginOffset<U>(), *end = data() + EndOffset<U>();
+         p != end; p += sizeof(U)) {
+      ::new (p) U{};
+    }
+    return true;
+  }
+
+  template <typename U>
+  bool Destroy() {
+    if (std::is_trivially_destructible<U>::value) return true;
+    for (U* it = Begin<U>(), *end = End<U>(); it != end; ++it) {
+      it->~U();
+    }
+    return true;
+  }
+
+  char* data() const {
+    return const_cast<char*>(reinterpret_cast<const char*>(this));
+  }
+
+  TypeMap<IntT, T...> ends_;
+};
+
+template <typename... T>
+TypeMap<IntT, T...> CalculateEnds(const TypeMap<IntT, T...>& sizes) {
+  int total = 0;
+  TypeMap<IntT, T...> out;
+  Fold({(out.template Get<T>() = total +=
+         sizeof(T) * sizes.template Get<T>())...});
+  return out;
+}
+
+// The implementation for FlatAllocator below.
+// This separate class template makes it easier to have methods that fold on
+// `T...`.
+template <typename... T>
+class FlatAllocatorImpl {
+ public:
+  using Allocation = FlatAllocation<T...>;
+
+  template <typename U>
+  void PlanArray(int array_size) {
+    // We can't call PlanArray after FinalizePlanning has been called.
+    GOOGLE_CHECK(!has_allocated());
+    if (std::is_trivially_destructible<U>::value) {
+      // Trivial types are aligned to 8 bytes.
+      static_assert(alignof(U) <= 8, "");
+      total_.template Get<char>() += RoundUpTo<8>(array_size * sizeof(U));
+    } else {
+      // Since we can't use `if constexpr`, just make the expression compile
+      // when this path is not taken.
+      using TypeToUse =
+          typename std::conditional<std::is_trivially_destructible<U>::value,
+                                    char, U>::type;
+      total_.template Get<TypeToUse>() += array_size;
+    }
+  }
+
+  template <typename U>
+  U* AllocateArray(int array_size) {
+    constexpr bool trivial = std::is_trivially_destructible<U>::value;
+    using TypeToUse = typename std::conditional<trivial, char, U>::type;
+
+    // We can only allocate after FinalizePlanning has been called.
+    GOOGLE_CHECK(has_allocated());
+
+    TypeToUse*& data = pointers_.template Get<TypeToUse>();
+    int& used = used_.template Get<TypeToUse>();
+    U* res = reinterpret_cast<U*>(data + used);
+    used += trivial ? RoundUpTo<8>(array_size * sizeof(U)) : array_size;
+    GOOGLE_CHECK_LE(used, total_.template Get<TypeToUse>());
+    return res;
+  }
+
+  template <typename... In>
+  const std::string* AllocateStrings(In&&... in) {
+    std::string* strings = AllocateArray<std::string>(sizeof...(in));
+    std::string* res = strings;
+    Fold({(*strings++ = std::string(std::forward<In>(in)))...});
+    return res;
+  }
+
+  // Allocate all 5 names of the field:
+  // name, full name, lowercase, camelcase and json.
+  // It will dedup the strings when possible.
+  // The resulting array contains `name` at index 0, `full_name` at index 1
+  // and the other 3 indices are specified in the result.
+  void PlanFieldNames(const std::string& name,
+                      const std::string* opt_json_name) {
+    GOOGLE_CHECK(!has_allocated());
+
+    // Fast path for snake_case names, which follow the style guide.
+    if (opt_json_name == nullptr) {
+      switch (GetFieldNameCase(name)) {
+        case FieldNameCase::kAllLower:
+          // Case 1: they are all the same.
+          return PlanArray<std::string>(2);
+        case FieldNameCase::kSnakeCase:
+          // Case 2: name==lower, camel==json
+          return PlanArray<std::string>(3);
+        default:
+          break;
+      }
+    }
+
+    std::string lowercase_name = name;
+    LowerString(&lowercase_name);
+
+    std::string camelcase_name = ToCamelCase(name, /* lower_first = */ true);
+    std::string json_name =
+        opt_json_name != nullptr ? *opt_json_name : ToJsonName(name);
+
+    StringPiece all_names[] = {name, lowercase_name, camelcase_name,
+                                     json_name};
+    std::sort(all_names, all_names + 4);
+    int unique =
+        static_cast<int>(std::unique(all_names, all_names + 4) - all_names);
+
+    PlanArray<std::string>(unique + 1);
+  }
+
+  struct FieldNamesResult {
+    const std::string* array;
+    int lowercase_index;
+    int camelcase_index;
+    int json_index;
+  };
+  FieldNamesResult AllocateFieldNames(const std::string& name,
+                                      const std::string& scope,
+                                      const std::string* opt_json_name) {
+    GOOGLE_CHECK(has_allocated());
+
+    std::string full_name =
+        scope.empty() ? name : StrCat(scope, ".", name);
+
+    // Fast path for snake_case names, which follow the style guide.
+    if (opt_json_name == nullptr) {
+      switch (GetFieldNameCase(name)) {
+        case FieldNameCase::kAllLower:
+          // Case 1: they are all the same.
+          return {AllocateStrings(name, std::move(full_name)), 0, 0, 0};
+        case FieldNameCase::kSnakeCase:
+          // Case 2: name==lower, camel==json
+          return {AllocateStrings(name, std::move(full_name),
+                                  ToCamelCase(name, /* lower_first = */ true)),
+                  0, 2, 2};
+        default:
+          break;
+      }
+    }
+
+    std::vector<std::string> names;
+    names.push_back(name);
+    names.push_back(std::move(full_name));
+
+    const auto push_name = [&](std::string new_name) {
+      for (size_t i = 0; i < names.size(); ++i) {
+        // Do not compare the full_name. It is unlikely to match, except in
+        // custom json_name. We are not taking this into account in
+        // PlanFieldNames so better to not try it.
+        if (i == 1) continue;
+        if (names[i] == new_name) return i;
+      }
+      names.push_back(std::move(new_name));
+      return names.size() - 1;
+    };
+
+    FieldNamesResult result{nullptr, 0, 0, 0};
+
+    std::string lowercase_name = name;
+    LowerString(&lowercase_name);
+    result.lowercase_index = push_name(std::move(lowercase_name));
+    result.camelcase_index =
+        push_name(ToCamelCase(name, /* lower_first = */ true));
+    result.json_index =
+        push_name(opt_json_name != nullptr ? *opt_json_name : ToJsonName(name));
+
+    std::string* all_names = AllocateArray<std::string>(names.size());
+    result.array = all_names;
+    std::move(names.begin(), names.end(), all_names);
+
+    return result;
+  }
+
+  template <typename Alloc>
+  void FinalizePlanning(Alloc& alloc) {
+    GOOGLE_CHECK(!has_allocated());
+
+    pointers_ = alloc->CreateFlatAlloc(total_)->Pointers();
+
+    GOOGLE_CHECK(has_allocated());
+  }
+
+  void ExpectConsumed() const {
+    // We verify that we consumed all the memory requested if there was no
+    // error in processing.
+    Fold({ExpectConsumed<T>()...});
+  }
+
+ private:
+  bool has_allocated() const {
+    return pointers_.template Get<char>() != nullptr;
+  }
+
+  static bool IsLower(char c) { return 'a' <= c && c <= 'z'; }
+  static bool IsDigit(char c) { return '0' <= c && c <= '9'; }
+  static bool IsLowerOrDigit(char c) { return IsLower(c) || IsDigit(c); }
+
+  enum class FieldNameCase { kAllLower, kSnakeCase, kOther };
+  FieldNameCase GetFieldNameCase(const std::string& name) {
+    if (!IsLower(name[0])) return FieldNameCase::kOther;
+    FieldNameCase best = FieldNameCase::kAllLower;
+    for (char c : name) {
+      if (IsLowerOrDigit(c)) {
+        // nothing to do
+      } else if (c == '_') {
+        best = FieldNameCase::kSnakeCase;
+      } else {
+        return FieldNameCase::kOther;
+      }
+    }
+    return best;
+  }
+
+  template <typename U>
+  bool ExpectConsumed() const {
+    GOOGLE_CHECK_EQ(total_.template Get<U>(), used_.template Get<U>());
+    return true;
+  }
+
+  TypeMap<PointerT, T...> pointers_;
+  TypeMap<IntT, T...> total_;
+  TypeMap<IntT, T...> used_;
+};
+
+}  // namespace
+
+class Symbol {
+ public:
+  enum Type {
+    NULL_SYMBOL,
+    MESSAGE,
+    FIELD,
+    ONEOF,
+    ENUM,
+    ENUM_VALUE,
+    ENUM_VALUE_OTHER_PARENT,
+    SERVICE,
+    METHOD,
+    FULL_PACKAGE,
+    SUB_PACKAGE,
+    QUERY_KEY
+  };
+
+  Symbol() {
+    static constexpr internal::SymbolBase null_symbol{};
+    static_assert(null_symbol.symbol_type_ == NULL_SYMBOL, "");
+    // Initialize with a sentinel to make sure `ptr_` is never null.
+    ptr_ = &null_symbol;
+  }
+
+  // Every object we store derives from internal::SymbolBase, where we store the
+  // symbol type enum.
+  // Storing in the object can be done without using more space in most cases,
+  // while storing it in the Symbol type would require 8 bytes.
+#define DEFINE_MEMBERS(TYPE, TYPE_CONSTANT, FIELD)                             \
+  explicit Symbol(TYPE* value) : ptr_(value) {                                 \
+    value->symbol_type_ = TYPE_CONSTANT;                                       \
+  }                                                                            \
+  const TYPE* FIELD() const {                                                  \
+    return type() == TYPE_CONSTANT ? static_cast<const TYPE*>(ptr_) : nullptr; \
+  }
+
+  DEFINE_MEMBERS(Descriptor, MESSAGE, descriptor)
+  DEFINE_MEMBERS(FieldDescriptor, FIELD, field_descriptor)
+  DEFINE_MEMBERS(OneofDescriptor, ONEOF, oneof_descriptor)
+  DEFINE_MEMBERS(EnumDescriptor, ENUM, enum_descriptor)
+  DEFINE_MEMBERS(ServiceDescriptor, SERVICE, service_descriptor)
+  DEFINE_MEMBERS(MethodDescriptor, METHOD, method_descriptor)
+  DEFINE_MEMBERS(FileDescriptor, FULL_PACKAGE, file_descriptor)
+
+  // We use a special node for subpackage FileDescriptor.
+  // It is potentially added to the table with multiple different names, so we
+  // need a separate place to put the name.
+  struct Subpackage : internal::SymbolBase {
+    int name_size;
+    const FileDescriptor* file;
+  };
+  DEFINE_MEMBERS(Subpackage, SUB_PACKAGE, sub_package_file_descriptor)
+
+  // Enum values have two different parents.
+  // We use two different identitied for the same object to determine the two
+  // different insertions in the map.
+  static Symbol EnumValue(EnumValueDescriptor* value, int n) {
+    Symbol s;
+    internal::SymbolBase* ptr;
+    if (n == 0) {
+      ptr = static_cast<internal::SymbolBaseN<0>*>(value);
+      ptr->symbol_type_ = ENUM_VALUE;
+    } else {
+      ptr = static_cast<internal::SymbolBaseN<1>*>(value);
+      ptr->symbol_type_ = ENUM_VALUE_OTHER_PARENT;
+    }
+    s.ptr_ = ptr;
+    return s;
+  }
+
+  const EnumValueDescriptor* enum_value_descriptor() const {
+    return type() == ENUM_VALUE
+               ? static_cast<const EnumValueDescriptor*>(
+                     static_cast<const internal::SymbolBaseN<0>*>(ptr_))
+           : type() == ENUM_VALUE_OTHER_PARENT
+               ? static_cast<const EnumValueDescriptor*>(
+                     static_cast<const internal::SymbolBaseN<1>*>(ptr_))
+               : nullptr;
+  }
+
+  // Not a real symbol.
+  // Only used for heterogeneous lookups and never actually inserted in the
+  // tables.
+  // TODO(b/215557658): If we templetize QueryKey on the expected object type we
+  // can skip the switches for the eq function altogether.
+  struct QueryKey : internal::SymbolBase {
+    StringPiece name;
+    const void* parent;
+    int field_number;
+
+    // Adaptor functions to look like a Symbol to the comparators.
+    StringPiece full_name() const { return name; }
+    std::pair<const void*, int> parent_number_key() const {
+      return {parent, field_number};
+    }
+    std::pair<const void*, StringPiece> parent_name_key() const {
+      return {parent, name};
+    }
+  };
+  // This constructor is implicit to allow for non-transparent lookups when
+  // necessary.
+  // For transparent lookup cases we query directly with the object without the
+  // type erasure layer.
+  Symbol(QueryKey& value) : ptr_(&value) {  // NOLINT
+    value.symbol_type_ = QUERY_KEY;
+  }
+  const QueryKey* query_key() const {
+    return type() == QUERY_KEY ? static_cast<const QueryKey*>(ptr_) : nullptr;
+  }
+#undef DEFINE_MEMBERS
+
+  Type type() const { return static_cast<Type>(ptr_->symbol_type_); }
+  bool IsNull() const { return type() == NULL_SYMBOL; }
+  bool IsType() const { return type() == MESSAGE || type() == ENUM; }
+  bool IsAggregate() const {
+    return IsType() || IsPackage() || type() == SERVICE;
+  }
+  bool IsPackage() const {
+    return type() == FULL_PACKAGE || type() == SUB_PACKAGE;
+  }
+
+  const FileDescriptor* GetFile() const {
+    switch (type()) {
+      case MESSAGE:
+        return descriptor()->file();
+      case FIELD:
+        return field_descriptor()->file();
+      case ONEOF:
+        return oneof_descriptor()->containing_type()->file();
+      case ENUM:
+        return enum_descriptor()->file();
+      case ENUM_VALUE:
+        return enum_value_descriptor()->type()->file();
+      case SERVICE:
+        return service_descriptor()->file();
+      case METHOD:
+        return method_descriptor()->service()->file();
+      case FULL_PACKAGE:
+        return file_descriptor();
+      case SUB_PACKAGE:
+        return sub_package_file_descriptor()->file;
+      default:
+        return nullptr;
+    }
+  }
+
+  StringPiece full_name() const {
+    switch (type()) {
+      case MESSAGE:
+        return descriptor()->full_name();
+      case FIELD:
+        return field_descriptor()->full_name();
+      case ONEOF:
+        return oneof_descriptor()->full_name();
+      case ENUM:
+        return enum_descriptor()->full_name();
+      case ENUM_VALUE:
+        return enum_value_descriptor()->full_name();
+      case SERVICE:
+        return service_descriptor()->full_name();
+      case METHOD:
+        return method_descriptor()->full_name();
+      case FULL_PACKAGE:
+        return file_descriptor()->package();
+      case SUB_PACKAGE:
+        return StringPiece(sub_package_file_descriptor()->file->package())
+            .substr(0, sub_package_file_descriptor()->name_size);
+      case QUERY_KEY:
+        return query_key()->full_name();
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return "";
+  }
+
+  std::pair<const void*, StringPiece> parent_name_key() const {
+    const auto or_file = [&](const void* p) { return p ? p : GetFile(); };
+    switch (type()) {
+      case MESSAGE:
+        return {or_file(descriptor()->containing_type()), descriptor()->name()};
+      case FIELD: {
+        auto* field = field_descriptor();
+        return {or_file(field->is_extension() ? field->extension_scope()
+                                              : field->containing_type()),
+                field->name()};
+      }
+      case ONEOF:
+        return {oneof_descriptor()->containing_type(),
+                oneof_descriptor()->name()};
+      case ENUM:
+        return {or_file(enum_descriptor()->containing_type()),
+                enum_descriptor()->name()};
+      case ENUM_VALUE:
+        return {or_file(enum_value_descriptor()->type()->containing_type()),
+                enum_value_descriptor()->name()};
+      case ENUM_VALUE_OTHER_PARENT:
+        return {enum_value_descriptor()->type(),
+                enum_value_descriptor()->name()};
+      case SERVICE:
+        return {GetFile(), service_descriptor()->name()};
+      case METHOD:
+        return {method_descriptor()->service(), method_descriptor()->name()};
+      case QUERY_KEY:
+        return query_key()->parent_name_key();
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return {};
+  }
+
+  std::pair<const void*, int> parent_number_key() const {
+    switch (type()) {
+      case FIELD:
+        return {field_descriptor()->containing_type(),
+                field_descriptor()->number()};
+      case ENUM_VALUE:
+        return {enum_value_descriptor()->type(),
+                enum_value_descriptor()->number()};
+      case QUERY_KEY:
+        return query_key()->parent_number_key();
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return {};
+  }
+
+ private:
+  const internal::SymbolBase* ptr_;
+};
+
+const FieldDescriptor::CppType
+    FieldDescriptor::kTypeToCppTypeMap[MAX_TYPE + 1] = {
+        static_cast<CppType>(0),  // 0 is reserved for errors
+
+        CPPTYPE_DOUBLE,   // TYPE_DOUBLE
+        CPPTYPE_FLOAT,    // TYPE_FLOAT
+        CPPTYPE_INT64,    // TYPE_INT64
+        CPPTYPE_UINT64,   // TYPE_UINT64
+        CPPTYPE_INT32,    // TYPE_INT32
+        CPPTYPE_UINT64,   // TYPE_FIXED64
+        CPPTYPE_UINT32,   // TYPE_FIXED32
+        CPPTYPE_BOOL,     // TYPE_BOOL
+        CPPTYPE_STRING,   // TYPE_STRING
+        CPPTYPE_MESSAGE,  // TYPE_GROUP
+        CPPTYPE_MESSAGE,  // TYPE_MESSAGE
+        CPPTYPE_STRING,   // TYPE_BYTES
+        CPPTYPE_UINT32,   // TYPE_UINT32
+        CPPTYPE_ENUM,     // TYPE_ENUM
+        CPPTYPE_INT32,    // TYPE_SFIXED32
+        CPPTYPE_INT64,    // TYPE_SFIXED64
+        CPPTYPE_INT32,    // TYPE_SINT32
+        CPPTYPE_INT64,    // TYPE_SINT64
+};
+
+const char* const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = {
+    "ERROR",  // 0 is reserved for errors
+
+    "double",    // TYPE_DOUBLE
+    "float",     // TYPE_FLOAT
+    "int64",     // TYPE_INT64
+    "uint64",    // TYPE_UINT64
+    "int32",     // TYPE_INT32
+    "fixed64",   // TYPE_FIXED64
+    "fixed32",   // TYPE_FIXED32
+    "bool",      // TYPE_BOOL
+    "string",    // TYPE_STRING
+    "group",     // TYPE_GROUP
+    "message",   // TYPE_MESSAGE
+    "bytes",     // TYPE_BYTES
+    "uint32",    // TYPE_UINT32
+    "enum",      // TYPE_ENUM
+    "sfixed32",  // TYPE_SFIXED32
+    "sfixed64",  // TYPE_SFIXED64
+    "sint32",    // TYPE_SINT32
+    "sint64",    // TYPE_SINT64
+};
+
+const char* const FieldDescriptor::kCppTypeToName[MAX_CPPTYPE + 1] = {
+    "ERROR",  // 0 is reserved for errors
+
+    "int32",    // CPPTYPE_INT32
+    "int64",    // CPPTYPE_INT64
+    "uint32",   // CPPTYPE_UINT32
+    "uint64",   // CPPTYPE_UINT64
+    "double",   // CPPTYPE_DOUBLE
+    "float",    // CPPTYPE_FLOAT
+    "bool",     // CPPTYPE_BOOL
+    "enum",     // CPPTYPE_ENUM
+    "string",   // CPPTYPE_STRING
+    "message",  // CPPTYPE_MESSAGE
+};
+
+const char* const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = {
+    "ERROR",  // 0 is reserved for errors
+
+    "optional",  // LABEL_OPTIONAL
+    "required",  // LABEL_REQUIRED
+    "repeated",  // LABEL_REPEATED
+};
+
+const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) {
+  switch (syntax) {
+    case SYNTAX_PROTO2:
+      return "proto2";
+    case SYNTAX_PROTO3:
+      return "proto3";
+    case SYNTAX_UNKNOWN:
+      return "unknown";
+  }
+  GOOGLE_LOG(FATAL) << "can't reach here.";
+  return nullptr;
+}
+
+static const char* const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
+
+#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
+const int FieldDescriptor::kMaxNumber;
+const int FieldDescriptor::kFirstReservedNumber;
+const int FieldDescriptor::kLastReservedNumber;
+#endif
+
+namespace {
+
+std::string EnumValueToPascalCase(const std::string& input) {
+  bool next_upper = true;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      next_upper = true;
+    } else {
+      if (next_upper) {
+        result.push_back(ToUpper(character));
+      } else {
+        result.push_back(ToLower(character));
+      }
+      next_upper = false;
+    }
+  }
+
+  return result;
+}
+
+// Class to remove an enum prefix from enum values.
+class PrefixRemover {
+ public:
+  PrefixRemover(StringPiece prefix) {
+    // Strip underscores and lower-case the prefix.
+    for (char character : prefix) {
+      if (character != '_') {
+        prefix_ += ascii_tolower(character);
+      }
+    }
+  }
+
+  // Tries to remove the enum prefix from this enum value.
+  // If this is not possible, returns the input verbatim.
+  std::string MaybeRemove(StringPiece str) {
+    // We can't just lowercase and strip str and look for a prefix.
+    // We need to properly recognize the difference between:
+    //
+    //   enum Foo {
+    //     FOO_BAR_BAZ = 0;
+    //     FOO_BARBAZ = 1;
+    //   }
+    //
+    // This is acceptable (though perhaps not advisable) because even when
+    // we PascalCase, these two will still be distinct (BarBaz vs. Barbaz).
+    size_t i, j;
+
+    // Skip past prefix_ in str if we can.
+    for (i = 0, j = 0; i < str.size() && j < prefix_.size(); i++) {
+      if (str[i] == '_') {
+        continue;
+      }
+
+      if (ascii_tolower(str[i]) != prefix_[j++]) {
+        return std::string(str);
+      }
+    }
+
+    // If we didn't make it through the prefix, we've failed to strip the
+    // prefix.
+    if (j < prefix_.size()) {
+      return std::string(str);
+    }
+
+    // Skip underscores between prefix and further characters.
+    while (i < str.size() && str[i] == '_') {
+      i++;
+    }
+
+    // Enum label can't be the empty string.
+    if (i == str.size()) {
+      return std::string(str);
+    }
+
+    // We successfully stripped the prefix.
+    str.remove_prefix(i);
+    return std::string(str);
+  }
+
+ private:
+  std::string prefix_;
+};
+
+// A DescriptorPool contains a bunch of hash-maps to implement the
+// various Find*By*() methods.  Since hashtable lookups are O(1), it's
+// most efficient to construct a fixed set of large hash-maps used by
+// all objects in the pool rather than construct one or more small
+// hash-maps for each object.
+//
+// The keys to these hash-maps are (parent, name) or (parent, number) pairs.
+
+typedef std::pair<const void*, StringPiece> PointerStringPair;
+
+typedef std::pair<const Descriptor*, int> DescriptorIntPair;
+
+#define HASH_MAP std::unordered_map
+#define HASH_SET std::unordered_set
+#define HASH_FXN hash
+
+template <typename PairType>
+struct PointerIntegerPairHash {
+  size_t operator()(const PairType& p) const {
+    static const size_t prime1 = 16777499;
+    static const size_t prime2 = 16777619;
+    return reinterpret_cast<size_t>(p.first) * prime1 ^
+           static_cast<size_t>(p.second) * prime2;
+  }
+
+#ifdef _MSC_VER
+  // Used only by MSVC and platforms where hash_map is not available.
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+#endif
+  inline bool operator()(const PairType& a, const PairType& b) const {
+    return a < b;
+  }
+};
+
+struct PointerStringPairHash {
+  size_t operator()(const PointerStringPair& p) const {
+    static const size_t prime = 16777619;
+    hash<StringPiece> string_hash;
+    return reinterpret_cast<size_t>(p.first) * prime ^
+           static_cast<size_t>(string_hash(p.second));
+  }
+
+#ifdef _MSC_VER
+  // Used only by MSVC and platforms where hash_map is not available.
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+#endif
+  inline bool operator()(const PointerStringPair& a,
+                         const PointerStringPair& b) const {
+    return a < b;
+  }
+};
+
+
+struct SymbolByFullNameHash {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
+    return HASH_FXN<StringPiece>{}(s.full_name());
+  }
+};
+struct SymbolByFullNameEq {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a.full_name() == b.full_name();
+  }
+};
+using SymbolsByNameSet =
+    HASH_SET<Symbol, SymbolByFullNameHash, SymbolByFullNameEq>;
+
+struct SymbolByParentHash {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
+    return PointerStringPairHash{}(s.parent_name_key());
+  }
+};
+struct SymbolByParentEq {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a.parent_name_key() == b.parent_name_key();
+  }
+};
+using SymbolsByParentSet =
+    HASH_SET<Symbol, SymbolByParentHash, SymbolByParentEq>;
+
+typedef HASH_MAP<StringPiece, const FileDescriptor*,
+                 HASH_FXN<StringPiece>>
+    FilesByNameMap;
+
+typedef HASH_MAP<PointerStringPair, const FieldDescriptor*,
+                 PointerStringPairHash>
+    FieldsByNameMap;
+
+struct FieldsByNumberHash {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
+    return PointerIntegerPairHash<std::pair<const void*, int>>{}(
+        s.parent_number_key());
+  }
+};
+struct FieldsByNumberEq {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a.parent_number_key() == b.parent_number_key();
+  }
+};
+using FieldsByNumberSet =
+    HASH_SET<Symbol, FieldsByNumberHash, FieldsByNumberEq>;
+using EnumValuesByNumberSet = FieldsByNumberSet;
+
+// This is a map rather than a hash-map, since we use it to iterate
+// through all the extensions that extend a given Descriptor, and an
+// ordered data structure that implements lower_bound is convenient
+// for that.
+typedef std::map<DescriptorIntPair, const FieldDescriptor*>
+    ExtensionsGroupedByDescriptorMap;
+typedef HASH_MAP<std::string, const SourceCodeInfo_Location*>
+    LocationsByPathMap;
+
+std::set<std::string>* NewAllowedProto3Extendee() {
+  auto allowed_proto3_extendees = new std::set<std::string>;
+  const char* kOptionNames[] = {
+      "FileOptions",   "MessageOptions",   "FieldOptions",
+      "EnumOptions",   "EnumValueOptions", "ServiceOptions",
+      "MethodOptions", "OneofOptions",     "ExtensionRangeOptions"};
+  for (const char* option_name : kOptionNames) {
+    // descriptor.proto has a different package name in opensource. We allow
+    // both so the opensource protocol compiler can also compile internal
+    // proto3 files with custom options. See: b/27567912
+    allowed_proto3_extendees->insert(std::string("google.protobuf.") +
+                                     option_name);
+    // Split the word to trick the opensource processing scripts so they
+    // will keep the original package name.
+    allowed_proto3_extendees->insert(std::string("proto") + "2." + option_name);
+  }
+  return allowed_proto3_extendees;
+}
+
+// Checks whether the extendee type is allowed in proto3.
+// Only extensions to descriptor options are allowed. We use name comparison
+// instead of comparing the descriptor directly because the extensions may be
+// defined in a different pool.
+bool AllowedExtendeeInProto3(const std::string& name) {
+  static auto allowed_proto3_extendees =
+      internal::OnShutdownDelete(NewAllowedProto3Extendee());
+  return allowed_proto3_extendees->find(name) !=
+         allowed_proto3_extendees->end();
+}
+}  // anonymous namespace
+
+// Contains tables specific to a particular file.  These tables are not
+// modified once the file has been constructed, so they need not be
+// protected by a mutex.  This makes operations that depend only on the
+// contents of a single file -- e.g. Descriptor::FindFieldByName() --
+// lock-free.
+//
+// For historical reasons, the definitions of the methods of
+// FileDescriptorTables and DescriptorPool::Tables are interleaved below.
+// These used to be a single class.
+class FileDescriptorTables {
+ public:
+  FileDescriptorTables();
+  ~FileDescriptorTables();
+
+  // Empty table, used with placeholder files.
+  inline static const FileDescriptorTables& GetEmptyInstance();
+
+  // -----------------------------------------------------------------
+  // Finding items.
+
+  // Returns a null Symbol (symbol.IsNull() is true) if not found.
+  inline Symbol FindNestedSymbol(const void* parent,
+                                 StringPiece name) const;
+
+  // These return nullptr if not found.
+  inline const FieldDescriptor* FindFieldByNumber(const Descriptor* parent,
+                                                  int number) const;
+  inline const FieldDescriptor* FindFieldByLowercaseName(
+      const void* parent, StringPiece lowercase_name) const;
+  inline const FieldDescriptor* FindFieldByCamelcaseName(
+      const void* parent, StringPiece camelcase_name) const;
+  inline const EnumValueDescriptor* FindEnumValueByNumber(
+      const EnumDescriptor* parent, int number) const;
+  // This creates a new EnumValueDescriptor if not found, in a thread-safe way.
+  inline const EnumValueDescriptor* FindEnumValueByNumberCreatingIfUnknown(
+      const EnumDescriptor* parent, int number) const;
+
+  // -----------------------------------------------------------------
+  // Adding items.
+
+  // These add items to the corresponding tables.  They return false if
+  // the key already exists in the table.
+  bool AddAliasUnderParent(const void* parent, const std::string& name,
+                           Symbol symbol);
+  bool AddFieldByNumber(FieldDescriptor* field);
+  bool AddEnumValueByNumber(EnumValueDescriptor* value);
+
+  // Populates p->first->locations_by_path_ from p->second.
+  // Unusual signature dictated by internal::call_once.
+  static void BuildLocationsByPath(
+      std::pair<const FileDescriptorTables*, const SourceCodeInfo*>* p);
+
+  // Returns the location denoted by the specified path through info,
+  // or nullptr if not found.
+  // The value of info must be that of the corresponding FileDescriptor.
+  // (Conceptually a pure function, but stateful as an optimisation.)
+  const SourceCodeInfo_Location* GetSourceLocation(
+      const std::vector<int>& path, const SourceCodeInfo* info) const;
+
+  // Must be called after BuildFileImpl(), even if the build failed and
+  // we are going to roll back to the last checkpoint.
+  void FinalizeTables();
+
+ private:
+  const void* FindParentForFieldsByMap(const FieldDescriptor* field) const;
+  static void FieldsByLowercaseNamesLazyInitStatic(
+      const FileDescriptorTables* tables);
+  void FieldsByLowercaseNamesLazyInitInternal() const;
+  static void FieldsByCamelcaseNamesLazyInitStatic(
+      const FileDescriptorTables* tables);
+  void FieldsByCamelcaseNamesLazyInitInternal() const;
+
+  SymbolsByParentSet symbols_by_parent_;
+  mutable internal::once_flag fields_by_lowercase_name_once_;
+  mutable internal::once_flag fields_by_camelcase_name_once_;
+  // Make these fields atomic to avoid race conditions with
+  // GetEstimatedOwnedMemoryBytesSize. Once the pointer is set the map won't
+  // change anymore.
+  mutable std::atomic<const FieldsByNameMap*> fields_by_lowercase_name_{};
+  mutable std::atomic<const FieldsByNameMap*> fields_by_camelcase_name_{};
+  FieldsByNumberSet fields_by_number_;  // Not including extensions.
+  EnumValuesByNumberSet enum_values_by_number_;
+  mutable EnumValuesByNumberSet unknown_enum_values_by_number_
+      PROTOBUF_GUARDED_BY(unknown_enum_values_mu_);
+
+  // Populated on first request to save space, hence constness games.
+  mutable internal::once_flag locations_by_path_once_;
+  mutable LocationsByPathMap locations_by_path_;
+
+  // Mutex to protect the unknown-enum-value map due to dynamic
+  // EnumValueDescriptor creation on unknown values.
+  mutable internal::WrappedMutex unknown_enum_values_mu_;
+};
+
+namespace internal {
+
+// Small sequential allocator to be used within a single file.
+// Most of the memory for a single FileDescriptor and everything under it is
+// allocated in a single block of memory, with the FlatAllocator giving it out
+// in parts later.
+// The code first plans the total number of bytes needed by calling PlanArray
+// with all the allocations that will happen afterwards, then calls
+// FinalizePlanning passing the underlying allocator (the DescriptorPool::Tables
+// instance), and then proceeds to get the memory via
+// `AllocateArray`/`AllocateString` calls. The calls to PlanArray and
+// The calls have to match between planning and allocating, though not
+// necessarily in the same order.
+class FlatAllocator
+    : public decltype(ApplyTypeList<FlatAllocatorImpl>(
+          SortByAlignment<char, std::string, SourceCodeInfo,
+                          FileDescriptorTables,
+                          // Option types
+                          MessageOptions, FieldOptions, EnumOptions,
+                          EnumValueOptions, ExtensionRangeOptions, OneofOptions,
+                          ServiceOptions, MethodOptions, FileOptions>())) {};
+
+}  // namespace internal
+
+// ===================================================================
+// DescriptorPool::Tables
+
+class DescriptorPool::Tables {
+ public:
+  Tables();
+  ~Tables();
+
+  // Record the current state of the tables to the stack of checkpoints.
+  // Each call to AddCheckpoint() must be paired with exactly one call to either
+  // ClearLastCheckpoint() or RollbackToLastCheckpoint().
+  //
+  // This is used when building files, since some kinds of validation errors
+  // cannot be detected until the file's descriptors have already been added to
+  // the tables.
+  //
+  // This supports recursive checkpoints, since building a file may trigger
+  // recursive building of other files. Note that recursive checkpoints are not
+  // normally necessary; explicit dependencies are built prior to checkpointing.
+  // So although we recursively build transitive imports, there is at most one
+  // checkpoint in the stack during dependency building.
+  //
+  // Recursive checkpoints only arise during cross-linking of the descriptors.
+  // Symbol references must be resolved, via DescriptorBuilder::FindSymbol and
+  // friends. If the pending file references an unknown symbol
+  // (e.g., it is not defined in the pending file's explicit dependencies), and
+  // the pool is using a fallback database, and that database contains a file
+  // defining that symbol, and that file has not yet been built by the pool,
+  // the pool builds the file during cross-linking, leading to another
+  // checkpoint.
+  void AddCheckpoint();
+
+  // Mark the last checkpoint as having cleared successfully, removing it from
+  // the stack. If the stack is empty, all pending symbols will be committed.
+  //
+  // Note that this does not guarantee that the symbols added since the last
+  // checkpoint won't be rolled back: if a checkpoint gets rolled back,
+  // everything past that point gets rolled back, including symbols added after
+  // checkpoints that were pushed onto the stack after it and marked as cleared.
+  void ClearLastCheckpoint();
+
+  // Roll back the Tables to the state of the checkpoint at the top of the
+  // stack, removing everything that was added after that point.
+  void RollbackToLastCheckpoint();
+
+  // The stack of files which are currently being built.  Used to detect
+  // cyclic dependencies when loading files from a DescriptorDatabase.  Not
+  // used when fallback_database_ == nullptr.
+  std::vector<std::string> pending_files_;
+
+  // A set of files which we have tried to load from the fallback database
+  // and encountered errors.  We will not attempt to load them again during
+  // execution of the current public API call, but for compatibility with
+  // legacy clients, this is cleared at the beginning of each public API call.
+  // Not used when fallback_database_ == nullptr.
+  HASH_SET<std::string> known_bad_files_;
+
+  // A set of symbols which we have tried to load from the fallback database
+  // and encountered errors. We will not attempt to load them again during
+  // execution of the current public API call, but for compatibility with
+  // legacy clients, this is cleared at the beginning of each public API call.
+  HASH_SET<std::string> known_bad_symbols_;
+
+  // The set of descriptors for which we've already loaded the full
+  // set of extensions numbers from fallback_database_.
+  HASH_SET<const Descriptor*> extensions_loaded_from_db_;
+
+  // Maps type name to Descriptor::WellKnownType.  This is logically global
+  // and const, but we make it a member here to simplify its construction and
+  // destruction.  This only has 20-ish entries and is one per DescriptorPool,
+  // so the overhead is small.
+  HASH_MAP<std::string, Descriptor::WellKnownType> well_known_types_;
+
+  // -----------------------------------------------------------------
+  // Finding items.
+
+  // Find symbols.  This returns a null Symbol (symbol.IsNull() is true)
+  // if not found.
+  inline Symbol FindSymbol(StringPiece key) const;
+
+  // This implements the body of DescriptorPool::Find*ByName().  It should
+  // really be a private method of DescriptorPool, but that would require
+  // declaring Symbol in descriptor.h, which would drag all kinds of other
+  // stuff into the header.  Yay C++.
+  Symbol FindByNameHelper(const DescriptorPool* pool, StringPiece name);
+
+  // These return nullptr if not found.
+  inline const FileDescriptor* FindFile(StringPiece key) const;
+  inline const FieldDescriptor* FindExtension(const Descriptor* extendee,
+                                              int number) const;
+  inline void FindAllExtensions(const Descriptor* extendee,
+                                std::vector<const FieldDescriptor*>* out) const;
+
+  // -----------------------------------------------------------------
+  // Adding items.
+
+  // These add items to the corresponding tables.  They return false if
+  // the key already exists in the table.  For AddSymbol(), the string passed
+  // in must be one that was constructed using AllocateString(), as it will
+  // be used as a key in the symbols_by_name_ map without copying.
+  bool AddSymbol(const std::string& full_name, Symbol symbol);
+  bool AddFile(const FileDescriptor* file);
+  bool AddExtension(const FieldDescriptor* field);
+
+  // -----------------------------------------------------------------
+  // Allocating memory.
+
+  // Allocate an object which will be reclaimed when the pool is
+  // destroyed.  Note that the object's destructor will never be called,
+  // so its fields must be plain old data (primitive data types and
+  // pointers).  All of the descriptor types are such objects.
+  template <typename Type>
+  Type* Allocate();
+
+  // Allocate some bytes which will be reclaimed when the pool is
+  // destroyed. Memory is aligned to 8 bytes.
+  void* AllocateBytes(int size);
+
+  // Create a FlatAllocation for the corresponding sizes.
+  // All objects within it will be default constructed.
+  // The whole allocation, including the non-trivial objects within, will be
+  // destroyed with the pool.
+  template <typename... T>
+  internal::FlatAllocator::Allocation* CreateFlatAlloc(
+      const TypeMap<IntT, T...>& sizes);
+
+
+ private:
+  // All memory allocated in the pool.  Must be first as other objects can
+  // point into these.
+  struct MiscDeleter {
+    void operator()(int* p) const { internal::SizedDelete(p, *p + 8); }
+  };
+  // Miscellaneous allocations are length prefixed. The paylaod is 8 bytes after
+  // the `int` that contains the size. This keeps the payload aligned.
+  std::vector<std::unique_ptr<int, MiscDeleter>> misc_allocs_;
+  struct FlatAllocDeleter {
+    void operator()(internal::FlatAllocator::Allocation* p) const {
+      p->Destroy();
+    }
+  };
+  std::vector<
+      std::unique_ptr<internal::FlatAllocator::Allocation, FlatAllocDeleter>>
+      flat_allocs_;
+
+  SymbolsByNameSet symbols_by_name_;
+  FilesByNameMap files_by_name_;
+  ExtensionsGroupedByDescriptorMap extensions_;
+
+  struct CheckPoint {
+    explicit CheckPoint(const Tables* tables)
+        : flat_allocations_before_checkpoint(
+              static_cast<int>(tables->flat_allocs_.size())),
+          misc_allocations_before_checkpoint(
+              static_cast<int>(tables->misc_allocs_.size())),
+          pending_symbols_before_checkpoint(
+              tables->symbols_after_checkpoint_.size()),
+          pending_files_before_checkpoint(
+              tables->files_after_checkpoint_.size()),
+          pending_extensions_before_checkpoint(
+              tables->extensions_after_checkpoint_.size()) {}
+    int flat_allocations_before_checkpoint;
+    int misc_allocations_before_checkpoint;
+    int pending_symbols_before_checkpoint;
+    int pending_files_before_checkpoint;
+    int pending_extensions_before_checkpoint;
+  };
+  std::vector<CheckPoint> checkpoints_;
+  std::vector<Symbol> symbols_after_checkpoint_;
+  std::vector<const FileDescriptor*> files_after_checkpoint_;
+  std::vector<DescriptorIntPair> extensions_after_checkpoint_;
+};
+
+DescriptorPool::Tables::Tables() {
+  well_known_types_.insert({
+      {"google.protobuf.DoubleValue", Descriptor::WELLKNOWNTYPE_DOUBLEVALUE},
+      {"google.protobuf.FloatValue", Descriptor::WELLKNOWNTYPE_FLOATVALUE},
+      {"google.protobuf.Int64Value", Descriptor::WELLKNOWNTYPE_INT64VALUE},
+      {"google.protobuf.UInt64Value", Descriptor::WELLKNOWNTYPE_UINT64VALUE},
+      {"google.protobuf.Int32Value", Descriptor::WELLKNOWNTYPE_INT32VALUE},
+      {"google.protobuf.UInt32Value", Descriptor::WELLKNOWNTYPE_UINT32VALUE},
+      {"google.protobuf.StringValue", Descriptor::WELLKNOWNTYPE_STRINGVALUE},
+      {"google.protobuf.BytesValue", Descriptor::WELLKNOWNTYPE_BYTESVALUE},
+      {"google.protobuf.BoolValue", Descriptor::WELLKNOWNTYPE_BOOLVALUE},
+      {"google.protobuf.Any", Descriptor::WELLKNOWNTYPE_ANY},
+      {"google.protobuf.FieldMask", Descriptor::WELLKNOWNTYPE_FIELDMASK},
+      {"google.protobuf.Duration", Descriptor::WELLKNOWNTYPE_DURATION},
+      {"google.protobuf.Timestamp", Descriptor::WELLKNOWNTYPE_TIMESTAMP},
+      {"google.protobuf.Value", Descriptor::WELLKNOWNTYPE_VALUE},
+      {"google.protobuf.ListValue", Descriptor::WELLKNOWNTYPE_LISTVALUE},
+      {"google.protobuf.Struct", Descriptor::WELLKNOWNTYPE_STRUCT},
+  });
+}
+
+DescriptorPool::Tables::~Tables() { GOOGLE_DCHECK(checkpoints_.empty()); }
+
+FileDescriptorTables::FileDescriptorTables() {}
+
+FileDescriptorTables::~FileDescriptorTables() {
+  delete fields_by_lowercase_name_.load(std::memory_order_acquire);
+  delete fields_by_camelcase_name_.load(std::memory_order_acquire);
+}
+
+inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() {
+  static auto file_descriptor_tables =
+      internal::OnShutdownDelete(new FileDescriptorTables());
+  return *file_descriptor_tables;
+}
+
+void DescriptorPool::Tables::AddCheckpoint() {
+  checkpoints_.push_back(CheckPoint(this));
+}
+
+void DescriptorPool::Tables::ClearLastCheckpoint() {
+  GOOGLE_DCHECK(!checkpoints_.empty());
+  checkpoints_.pop_back();
+  if (checkpoints_.empty()) {
+    // All checkpoints have been cleared: we can now commit all of the pending
+    // data.
+    symbols_after_checkpoint_.clear();
+    files_after_checkpoint_.clear();
+    extensions_after_checkpoint_.clear();
+  }
+}
+
+void DescriptorPool::Tables::RollbackToLastCheckpoint() {
+  GOOGLE_DCHECK(!checkpoints_.empty());
+  const CheckPoint& checkpoint = checkpoints_.back();
+
+  for (size_t i = checkpoint.pending_symbols_before_checkpoint;
+       i < symbols_after_checkpoint_.size(); i++) {
+    symbols_by_name_.erase(symbols_after_checkpoint_[i]);
+  }
+  for (size_t i = checkpoint.pending_files_before_checkpoint;
+       i < files_after_checkpoint_.size(); i++) {
+    files_by_name_.erase(files_after_checkpoint_[i]->name());
+  }
+  for (size_t i = checkpoint.pending_extensions_before_checkpoint;
+       i < extensions_after_checkpoint_.size(); i++) {
+    extensions_.erase(extensions_after_checkpoint_[i]);
+  }
+
+  symbols_after_checkpoint_.resize(
+      checkpoint.pending_symbols_before_checkpoint);
+  files_after_checkpoint_.resize(checkpoint.pending_files_before_checkpoint);
+  extensions_after_checkpoint_.resize(
+      checkpoint.pending_extensions_before_checkpoint);
+
+  flat_allocs_.resize(checkpoint.flat_allocations_before_checkpoint);
+  misc_allocs_.resize(checkpoint.misc_allocations_before_checkpoint);
+  checkpoints_.pop_back();
+}
+
+// -------------------------------------------------------------------
+
+inline Symbol DescriptorPool::Tables::FindSymbol(StringPiece key) const {
+  Symbol::QueryKey name;
+  name.name = key;
+  auto it = symbols_by_name_.find(name);
+  return it == symbols_by_name_.end() ? Symbol() : *it;
+}
+
+inline Symbol FileDescriptorTables::FindNestedSymbol(
+    const void* parent, StringPiece name) const {
+  Symbol::QueryKey query;
+  query.name = name;
+  query.parent = parent;
+  auto it = symbols_by_parent_.find(query);
+  return it == symbols_by_parent_.end() ? Symbol() : *it;
+}
+
+Symbol DescriptorPool::Tables::FindByNameHelper(const DescriptorPool* pool,
+                                                StringPiece name) {
+  if (pool->mutex_ != nullptr) {
+    // Fast path: the Symbol is already cached.  This is just a hash lookup.
+    ReaderMutexLock lock(pool->mutex_);
+    if (known_bad_symbols_.empty() && known_bad_files_.empty()) {
+      Symbol result = FindSymbol(name);
+      if (!result.IsNull()) return result;
+    }
+  }
+  MutexLockMaybe lock(pool->mutex_);
+  if (pool->fallback_database_ != nullptr) {
+    known_bad_symbols_.clear();
+    known_bad_files_.clear();
+  }
+  Symbol result = FindSymbol(name);
+
+  if (result.IsNull() && pool->underlay_ != nullptr) {
+    // Symbol not found; check the underlay.
+    result = pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name);
+  }
+
+  if (result.IsNull()) {
+    // Symbol still not found, so check fallback database.
+    if (pool->TryFindSymbolInFallbackDatabase(name)) {
+      result = FindSymbol(name);
+    }
+  }
+
+  return result;
+}
+
+inline const FileDescriptor* DescriptorPool::Tables::FindFile(
+    StringPiece key) const {
+  return FindPtrOrNull(files_by_name_, key);
+}
+
+inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
+    const Descriptor* parent, int number) const {
+  // If `number` is within the sequential range, just index into the parent
+  // without doing a table lookup.
+  if (parent != nullptr &&  //
+      1 <= number && number <= parent->sequential_field_limit_) {
+    return parent->field(number - 1);
+  }
+
+  Symbol::QueryKey query;
+  query.parent = parent;
+  query.field_number = number;
+
+  auto it = fields_by_number_.find(query);
+  return it == fields_by_number_.end() ? nullptr : it->field_descriptor();
+}
+
+const void* FileDescriptorTables::FindParentForFieldsByMap(
+    const FieldDescriptor* field) const {
+  if (field->is_extension()) {
+    if (field->extension_scope() == nullptr) {
+      return field->file();
+    } else {
+      return field->extension_scope();
+    }
+  } else {
+    return field->containing_type();
+  }
+}
+
+void FileDescriptorTables::FieldsByLowercaseNamesLazyInitStatic(
+    const FileDescriptorTables* tables) {
+  tables->FieldsByLowercaseNamesLazyInitInternal();
+}
+
+void FileDescriptorTables::FieldsByLowercaseNamesLazyInitInternal() const {
+  auto* map = new FieldsByNameMap;
+  for (Symbol symbol : symbols_by_parent_) {
+    const FieldDescriptor* field = symbol.field_descriptor();
+    if (!field) continue;
+    (*map)[{FindParentForFieldsByMap(field), field->lowercase_name().c_str()}] =
+        field;
+  }
+  fields_by_lowercase_name_.store(map, std::memory_order_release);
+}
+
+inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
+    const void* parent, StringPiece lowercase_name) const {
+  internal::call_once(
+      fields_by_lowercase_name_once_,
+      &FileDescriptorTables::FieldsByLowercaseNamesLazyInitStatic, this);
+  return FindPtrOrNull(
+      *fields_by_lowercase_name_.load(std::memory_order_acquire),
+      PointerStringPair(parent, lowercase_name));
+}
+
+void FileDescriptorTables::FieldsByCamelcaseNamesLazyInitStatic(
+    const FileDescriptorTables* tables) {
+  tables->FieldsByCamelcaseNamesLazyInitInternal();
+}
+
+void FileDescriptorTables::FieldsByCamelcaseNamesLazyInitInternal() const {
+  auto* map = new FieldsByNameMap;
+  for (Symbol symbol : symbols_by_parent_) {
+    const FieldDescriptor* field = symbol.field_descriptor();
+    if (!field) continue;
+    (*map)[{FindParentForFieldsByMap(field), field->camelcase_name().c_str()}] =
+        field;
+  }
+  fields_by_camelcase_name_.store(map, std::memory_order_release);
+}
+
+inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName(
+    const void* parent, StringPiece camelcase_name) const {
+  internal::call_once(
+      fields_by_camelcase_name_once_,
+      FileDescriptorTables::FieldsByCamelcaseNamesLazyInitStatic, this);
+  return FindPtrOrNull(
+      *fields_by_camelcase_name_.load(std::memory_order_acquire),
+      PointerStringPair(parent, camelcase_name));
+}
+
+inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
+    const EnumDescriptor* parent, int number) const {
+  // If `number` is within the sequential range, just index into the parent
+  // without doing a table lookup.
+  const int base = parent->value(0)->number();
+  if (base <= number &&
+      number <= static_cast<int64_t>(base) + parent->sequential_value_limit_) {
+    return parent->value(number - base);
+  }
+
+  Symbol::QueryKey query;
+  query.parent = parent;
+  query.field_number = number;
+
+  auto it = enum_values_by_number_.find(query);
+  return it == enum_values_by_number_.end() ? nullptr
+                                            : it->enum_value_descriptor();
+}
+
+inline const EnumValueDescriptor*
+FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
+    const EnumDescriptor* parent, int number) const {
+  // First try, with map of compiled-in values.
+  {
+    const auto* value = FindEnumValueByNumber(parent, number);
+    if (value != nullptr) {
+      return value;
+    }
+  }
+
+  Symbol::QueryKey query;
+  query.parent = parent;
+  query.field_number = number;
+
+  // Second try, with reader lock held on unknown enum values: common case.
+  {
+    ReaderMutexLock l(&unknown_enum_values_mu_);
+    auto it = unknown_enum_values_by_number_.find(query);
+    if (it != unknown_enum_values_by_number_.end() &&
+        it->enum_value_descriptor() != nullptr) {
+      return it->enum_value_descriptor();
+    }
+  }
+  // If not found, try again with writer lock held, and create new descriptor if
+  // necessary.
+  {
+    WriterMutexLock l(&unknown_enum_values_mu_);
+    auto it = unknown_enum_values_by_number_.find(query);
+    if (it != unknown_enum_values_by_number_.end() &&
+        it->enum_value_descriptor() != nullptr) {
+      return it->enum_value_descriptor();
+    }
+
+    // Create an EnumValueDescriptor dynamically. We don't insert it into the
+    // EnumDescriptor (it's not a part of the enum as originally defined), but
+    // we do insert it into the table so that we can return the same pointer
+    // later.
+    std::string enum_value_name = StringPrintf(
+        "UNKNOWN_ENUM_VALUE_%s_%d", parent->name().c_str(), number);
+    auto* pool = DescriptorPool::generated_pool();
+    auto* tables = const_cast<DescriptorPool::Tables*>(pool->tables_.get());
+    internal::FlatAllocator alloc;
+    alloc.PlanArray<EnumValueDescriptor>(1);
+    alloc.PlanArray<std::string>(2);
+
+    {
+      // Must lock the pool because we will do allocations in the shared arena.
+      MutexLockMaybe l2(pool->mutex_);
+      alloc.FinalizePlanning(tables);
+    }
+    EnumValueDescriptor* result = alloc.AllocateArray<EnumValueDescriptor>(1);
+    result->all_names_ = alloc.AllocateStrings(
+        enum_value_name,
+        StrCat(parent->full_name(), ".", enum_value_name));
+    result->number_ = number;
+    result->type_ = parent;
+    result->options_ = &EnumValueOptions::default_instance();
+    unknown_enum_values_by_number_.insert(Symbol::EnumValue(result, 0));
+    return result;
+  }
+}
+
+inline const FieldDescriptor* DescriptorPool::Tables::FindExtension(
+    const Descriptor* extendee, int number) const {
+  return FindPtrOrNull(extensions_, std::make_pair(extendee, number));
+}
+
+inline void DescriptorPool::Tables::FindAllExtensions(
+    const Descriptor* extendee,
+    std::vector<const FieldDescriptor*>* out) const {
+  ExtensionsGroupedByDescriptorMap::const_iterator it =
+      extensions_.lower_bound(std::make_pair(extendee, 0));
+  for (; it != extensions_.end() && it->first.first == extendee; ++it) {
+    out->push_back(it->second);
+  }
+}
+
+// -------------------------------------------------------------------
+
+bool DescriptorPool::Tables::AddSymbol(const std::string& full_name,
+                                       Symbol symbol) {
+  GOOGLE_DCHECK_EQ(full_name, symbol.full_name());
+  if (symbols_by_name_.insert(symbol).second) {
+    symbols_after_checkpoint_.push_back(symbol);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool FileDescriptorTables::AddAliasUnderParent(const void* parent,
+                                               const std::string& name,
+                                               Symbol symbol) {
+  GOOGLE_DCHECK_EQ(name, symbol.parent_name_key().second);
+  GOOGLE_DCHECK_EQ(parent, symbol.parent_name_key().first);
+  return symbols_by_parent_.insert(symbol).second;
+}
+
+bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
+  if (InsertIfNotPresent(&files_by_name_, file->name(), file)) {
+    files_after_checkpoint_.push_back(file);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void FileDescriptorTables::FinalizeTables() {}
+
+bool FileDescriptorTables::AddFieldByNumber(FieldDescriptor* field) {
+  // Skip fields that are at the start of the sequence.
+  if (field->containing_type() != nullptr && field->number() >= 1 &&
+      field->number() <= field->containing_type()->sequential_field_limit_) {
+    if (field->is_extension()) {
+      // Conflicts with the field that already exists in the sequential range.
+      return false;
+    }
+    // Only return true if the field at that index matches. Otherwise it
+    // conflicts with the existing field in the sequential range.
+    return field->containing_type()->field(field->number() - 1) == field;
+  }
+
+  return fields_by_number_.insert(Symbol(field)).second;
+}
+
+bool FileDescriptorTables::AddEnumValueByNumber(EnumValueDescriptor* value) {
+  // Skip values that are at the start of the sequence.
+  const int base = value->type()->value(0)->number();
+  if (base <= value->number() &&
+      value->number() <=
+          static_cast<int64_t>(base) + value->type()->sequential_value_limit_)
+    return true;
+  return enum_values_by_number_.insert(Symbol::EnumValue(value, 0)).second;
+}
+
+bool DescriptorPool::Tables::AddExtension(const FieldDescriptor* field) {
+  DescriptorIntPair key(field->containing_type(), field->number());
+  if (InsertIfNotPresent(&extensions_, key, field)) {
+    extensions_after_checkpoint_.push_back(key);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+// -------------------------------------------------------------------
+
+template <typename Type>
+Type* DescriptorPool::Tables::Allocate() {
+  static_assert(std::is_trivially_destructible<Type>::value, "");
+  static_assert(alignof(Type) <= 8, "");
+  return ::new (AllocateBytes(sizeof(Type))) Type{};
+}
+
+void* DescriptorPool::Tables::AllocateBytes(int size) {
+  if (size == 0) return nullptr;
+  void* p = ::operator new(size + RoundUpTo<8>(sizeof(int)));
+  int* sizep = static_cast<int*>(p);
+  misc_allocs_.emplace_back(sizep);
+  *sizep = size;
+  return static_cast<char*>(p) + RoundUpTo<8>(sizeof(int));
+}
+
+template <typename... T>
+internal::FlatAllocator::Allocation* DescriptorPool::Tables::CreateFlatAlloc(
+    const TypeMap<IntT, T...>& sizes) {
+  auto ends = CalculateEnds(sizes);
+  using FlatAlloc = internal::FlatAllocator::Allocation;
+
+  int last_end = ends.template Get<
+      typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type>();
+  size_t total_size =
+      last_end + RoundUpTo<FlatAlloc::kMaxAlign>(sizeof(FlatAlloc));
+  char* data = static_cast<char*>(::operator new(total_size));
+  auto* res = ::new (data) FlatAlloc(ends);
+  flat_allocs_.emplace_back(res);
+
+  return res;
+}
+
+void FileDescriptorTables::BuildLocationsByPath(
+    std::pair<const FileDescriptorTables*, const SourceCodeInfo*>* p) {
+  for (int i = 0, len = p->second->location_size(); i < len; ++i) {
+    const SourceCodeInfo_Location* loc = &p->second->location().Get(i);
+    p->first->locations_by_path_[Join(loc->path(), ",")] = loc;
+  }
+}
+
+const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
+    const std::vector<int>& path, const SourceCodeInfo* info) const {
+  std::pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
+      std::make_pair(this, info));
+  internal::call_once(locations_by_path_once_,
+                      FileDescriptorTables::BuildLocationsByPath, &p);
+  return FindPtrOrNull(locations_by_path_, Join(path, ","));
+}
+
+// ===================================================================
+// DescriptorPool
+
+DescriptorPool::ErrorCollector::~ErrorCollector() {}
+
+DescriptorPool::DescriptorPool()
+    : mutex_(nullptr),
+      fallback_database_(nullptr),
+      default_error_collector_(nullptr),
+      underlay_(nullptr),
+      tables_(new Tables),
+      enforce_dependencies_(true),
+      lazily_build_dependencies_(false),
+      allow_unknown_(false),
+      enforce_weak_(false),
+      disallow_enforce_utf8_(false) {}
+
+DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database,
+                               ErrorCollector* error_collector)
+    : mutex_(new internal::WrappedMutex),
+      fallback_database_(fallback_database),
+      default_error_collector_(error_collector),
+      underlay_(nullptr),
+      tables_(new Tables),
+      enforce_dependencies_(true),
+      lazily_build_dependencies_(false),
+      allow_unknown_(false),
+      enforce_weak_(false),
+      disallow_enforce_utf8_(false) {}
+
+DescriptorPool::DescriptorPool(const DescriptorPool* underlay)
+    : mutex_(nullptr),
+      fallback_database_(nullptr),
+      default_error_collector_(nullptr),
+      underlay_(underlay),
+      tables_(new Tables),
+      enforce_dependencies_(true),
+      lazily_build_dependencies_(false),
+      allow_unknown_(false),
+      enforce_weak_(false),
+      disallow_enforce_utf8_(false) {}
+
+DescriptorPool::~DescriptorPool() {
+  if (mutex_ != nullptr) delete mutex_;
+}
+
+// DescriptorPool::BuildFile() defined later.
+// DescriptorPool::BuildFileCollectingErrors() defined later.
+
+void DescriptorPool::InternalDontEnforceDependencies() {
+  enforce_dependencies_ = false;
+}
+
+void DescriptorPool::AddUnusedImportTrackFile(ConstStringParam file_name,
+                                              bool is_error) {
+  unused_import_track_files_[std::string(file_name)] = is_error;
+}
+
+void DescriptorPool::ClearUnusedImportTrackFiles() {
+  unused_import_track_files_.clear();
+}
+
+bool DescriptorPool::InternalIsFileLoaded(ConstStringParam filename) const {
+  MutexLockMaybe lock(mutex_);
+  return tables_->FindFile(filename) != nullptr;
+}
+
+// generated_pool ====================================================
+
+namespace {
+
+
+EncodedDescriptorDatabase* GeneratedDatabase() {
+  static auto generated_database =
+      internal::OnShutdownDelete(new EncodedDescriptorDatabase());
+  return generated_database;
+}
+
+DescriptorPool* NewGeneratedPool() {
+  auto generated_pool = new DescriptorPool(GeneratedDatabase());
+  generated_pool->InternalSetLazilyBuildDependencies();
+  return generated_pool;
+}
+
+}  // anonymous namespace
+
+DescriptorDatabase* DescriptorPool::internal_generated_database() {
+  return GeneratedDatabase();
+}
+
+DescriptorPool* DescriptorPool::internal_generated_pool() {
+  static DescriptorPool* generated_pool =
+      internal::OnShutdownDelete(NewGeneratedPool());
+  return generated_pool;
+}
+
+const DescriptorPool* DescriptorPool::generated_pool() {
+  const DescriptorPool* pool = internal_generated_pool();
+  // Ensure that descriptor.proto has been registered in the generated pool.
+  DescriptorProto::descriptor();
+  return pool;
+}
+
+
+void DescriptorPool::InternalAddGeneratedFile(
+    const void* encoded_file_descriptor, int size) {
+  // So, this function is called in the process of initializing the
+  // descriptors for generated proto classes.  Each generated .pb.cc file
+  // has an internal procedure called AddDescriptors() which is called at
+  // process startup, and that function calls this one in order to register
+  // the raw bytes of the FileDescriptorProto representing the file.
+  //
+  // We do not actually construct the descriptor objects right away.  We just
+  // hang on to the bytes until they are actually needed.  We actually construct
+  // the descriptor the first time one of the following things happens:
+  // * Someone calls a method like descriptor(), GetDescriptor(), or
+  //   GetReflection() on the generated types, which requires returning the
+  //   descriptor or an object based on it.
+  // * Someone looks up the descriptor in DescriptorPool::generated_pool().
+  //
+  // Once one of these happens, the DescriptorPool actually parses the
+  // FileDescriptorProto and generates a FileDescriptor (and all its children)
+  // based on it.
+  //
+  // Note that FileDescriptorProto is itself a generated protocol message.
+  // Therefore, when we parse one, we have to be very careful to avoid using
+  // any descriptor-based operations, since this might cause infinite recursion
+  // or deadlock.
+  GOOGLE_CHECK(GeneratedDatabase()->Add(encoded_file_descriptor, size));
+}
+
+
+// Find*By* methods ==================================================
+
+// TODO(kenton):  There's a lot of repeated code here, but I'm not sure if
+//   there's any good way to factor it out.  Think about this some time when
+//   there's nothing more important to do (read: never).
+
+const FileDescriptor* DescriptorPool::FindFileByName(
+    ConstStringParam name) const {
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+  const FileDescriptor* result = tables_->FindFile(name);
+  if (result != nullptr) return result;
+  if (underlay_ != nullptr) {
+    result = underlay_->FindFileByName(name);
+    if (result != nullptr) return result;
+  }
+  if (TryFindFileInFallbackDatabase(name)) {
+    result = tables_->FindFile(name);
+    if (result != nullptr) return result;
+  }
+  return nullptr;
+}
+
+const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
+    ConstStringParam symbol_name) const {
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+  Symbol result = tables_->FindSymbol(symbol_name);
+  if (!result.IsNull()) return result.GetFile();
+  if (underlay_ != nullptr) {
+    const FileDescriptor* file_result =
+        underlay_->FindFileContainingSymbol(symbol_name);
+    if (file_result != nullptr) return file_result;
+  }
+  if (TryFindSymbolInFallbackDatabase(symbol_name)) {
+    result = tables_->FindSymbol(symbol_name);
+    if (!result.IsNull()) return result.GetFile();
+  }
+  return nullptr;
+}
+
+const Descriptor* DescriptorPool::FindMessageTypeByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).descriptor();
+}
+
+const FieldDescriptor* DescriptorPool::FindFieldByName(
+    ConstStringParam name) const {
+  if (const FieldDescriptor* field =
+          tables_->FindByNameHelper(this, name).field_descriptor()) {
+    if (!field->is_extension()) {
+      return field;
+    }
+  }
+  return nullptr;
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByName(
+    ConstStringParam name) const {
+  if (const FieldDescriptor* field =
+          tables_->FindByNameHelper(this, name).field_descriptor()) {
+    if (field->is_extension()) {
+      return field;
+    }
+  }
+  return nullptr;
+}
+
+const OneofDescriptor* DescriptorPool::FindOneofByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).oneof_descriptor();
+}
+
+const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).enum_descriptor();
+}
+
+const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).enum_value_descriptor();
+}
+
+const ServiceDescriptor* DescriptorPool::FindServiceByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).service_descriptor();
+}
+
+const MethodDescriptor* DescriptorPool::FindMethodByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).method_descriptor();
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
+    const Descriptor* extendee, int number) const {
+  if (extendee->extension_range_count() == 0) return nullptr;
+  // A faster path to reduce lock contention in finding extensions, assuming
+  // most extensions will be cache hit.
+  if (mutex_ != nullptr) {
+    ReaderMutexLock lock(mutex_);
+    const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+    if (result != nullptr) {
+      return result;
+    }
+  }
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+  const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+  if (result != nullptr) {
+    return result;
+  }
+  if (underlay_ != nullptr) {
+    result = underlay_->FindExtensionByNumber(extendee, number);
+    if (result != nullptr) return result;
+  }
+  if (TryFindExtensionInFallbackDatabase(extendee, number)) {
+    result = tables_->FindExtension(extendee, number);
+    if (result != nullptr) {
+      return result;
+    }
+  }
+  return nullptr;
+}
+
+const FieldDescriptor* DescriptorPool::InternalFindExtensionByNumberNoLock(
+    const Descriptor* extendee, int number) const {
+  if (extendee->extension_range_count() == 0) return nullptr;
+
+  const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+  if (result != nullptr) {
+    return result;
+  }
+
+  if (underlay_ != nullptr) {
+    result = underlay_->InternalFindExtensionByNumberNoLock(extendee, number);
+    if (result != nullptr) return result;
+  }
+
+  return nullptr;
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByPrintableName(
+    const Descriptor* extendee, ConstStringParam printable_name) const {
+  if (extendee->extension_range_count() == 0) return nullptr;
+  const FieldDescriptor* result = FindExtensionByName(printable_name);
+  if (result != nullptr && result->containing_type() == extendee) {
+    return result;
+  }
+  if (extendee->options().message_set_wire_format()) {
+    // MessageSet extensions may be identified by type name.
+    const Descriptor* type = FindMessageTypeByName(printable_name);
+    if (type != nullptr) {
+      // Look for a matching extension in the foreign type's scope.
+      const int type_extension_count = type->extension_count();
+      for (int i = 0; i < type_extension_count; i++) {
+        const FieldDescriptor* extension = type->extension(i);
+        if (extension->containing_type() == extendee &&
+            extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+            extension->is_optional() && extension->message_type() == type) {
+          // Found it.
+          return extension;
+        }
+      }
+    }
+  }
+  return nullptr;
+}
+
+void DescriptorPool::FindAllExtensions(
+    const Descriptor* extendee,
+    std::vector<const FieldDescriptor*>* out) const {
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+
+  // Initialize tables_->extensions_ from the fallback database first
+  // (but do this only once per descriptor).
+  if (fallback_database_ != nullptr &&
+      tables_->extensions_loaded_from_db_.count(extendee) == 0) {
+    std::vector<int> numbers;
+    if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(),
+                                                    &numbers)) {
+      for (int number : numbers) {
+        if (tables_->FindExtension(extendee, number) == nullptr) {
+          TryFindExtensionInFallbackDatabase(extendee, number);
+        }
+      }
+      tables_->extensions_loaded_from_db_.insert(extendee);
+    }
+  }
+
+  tables_->FindAllExtensions(extendee, out);
+  if (underlay_ != nullptr) {
+    underlay_->FindAllExtensions(extendee, out);
+  }
+}
+
+
+// -------------------------------------------------------------------
+
+const FieldDescriptor* Descriptor::FindFieldByNumber(int key) const {
+  const FieldDescriptor* result = file()->tables_->FindFieldByNumber(this, key);
+  if (result == nullptr || result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindFieldByLowercaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByLowercaseName(this, key);
+  if (result == nullptr || result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindFieldByCamelcaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByCamelcaseName(this, key);
+  if (result == nullptr || result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindFieldByName(ConstStringParam key) const {
+  const FieldDescriptor* field =
+      file()->tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && !field->is_extension() ? field : nullptr;
+}
+
+const OneofDescriptor* Descriptor::FindOneofByName(ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).oneof_descriptor();
+}
+
+const FieldDescriptor* Descriptor::FindExtensionByName(
+    ConstStringParam key) const {
+  const FieldDescriptor* field =
+      file()->tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && field->is_extension() ? field : nullptr;
+}
+
+const FieldDescriptor* Descriptor::FindExtensionByLowercaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByLowercaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindExtensionByCamelcaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByCamelcaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const Descriptor* Descriptor::FindNestedTypeByName(ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).descriptor();
+}
+
+const EnumDescriptor* Descriptor::FindEnumTypeByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).enum_descriptor();
+}
+
+const EnumValueDescriptor* Descriptor::FindEnumValueByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).enum_value_descriptor();
+}
+
+const FieldDescriptor* Descriptor::map_key() const {
+  if (!options().map_entry()) return nullptr;
+  GOOGLE_DCHECK_EQ(field_count(), 2);
+  return field(0);
+}
+
+const FieldDescriptor* Descriptor::map_value() const {
+  if (!options().map_entry()) return nullptr;
+  GOOGLE_DCHECK_EQ(field_count(), 2);
+  return field(1);
+}
+
+const EnumValueDescriptor* EnumDescriptor::FindValueByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).enum_value_descriptor();
+}
+
+const EnumValueDescriptor* EnumDescriptor::FindValueByNumber(int key) const {
+  return file()->tables_->FindEnumValueByNumber(this, key);
+}
+
+const EnumValueDescriptor* EnumDescriptor::FindValueByNumberCreatingIfUnknown(
+    int key) const {
+  return file()->tables_->FindEnumValueByNumberCreatingIfUnknown(this, key);
+}
+
+const MethodDescriptor* ServiceDescriptor::FindMethodByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).method_descriptor();
+}
+
+const Descriptor* FileDescriptor::FindMessageTypeByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).descriptor();
+}
+
+const EnumDescriptor* FileDescriptor::FindEnumTypeByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).enum_descriptor();
+}
+
+const EnumValueDescriptor* FileDescriptor::FindEnumValueByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).enum_value_descriptor();
+}
+
+const ServiceDescriptor* FileDescriptor::FindServiceByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).service_descriptor();
+}
+
+const FieldDescriptor* FileDescriptor::FindExtensionByName(
+    ConstStringParam key) const {
+  const FieldDescriptor* field =
+      tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && field->is_extension() ? field : nullptr;
+}
+
+const FieldDescriptor* FileDescriptor::FindExtensionByLowercaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result = tables_->FindFieldByLowercaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* FileDescriptor::FindExtensionByCamelcaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result = tables_->FindFieldByCamelcaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+void Descriptor::ExtensionRange::CopyTo(
+    DescriptorProto_ExtensionRange* proto) const {
+  proto->set_start(this->start);
+  proto->set_end(this->end);
+  if (options_ != &ExtensionRangeOptions::default_instance()) {
+    *proto->mutable_options() = *options_;
+  }
+}
+
+const Descriptor::ExtensionRange*
+Descriptor::FindExtensionRangeContainingNumber(int number) const {
+  // Linear search should be fine because we don't expect a message to have
+  // more than a couple extension ranges.
+  for (int i = 0; i < extension_range_count(); i++) {
+    if (number >= extension_range(i)->start &&
+        number < extension_range(i)->end) {
+      return extension_range(i);
+    }
+  }
+  return nullptr;
+}
+
+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 nullptr;
+}
+
+const EnumDescriptor::ReservedRange*
+EnumDescriptor::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 nullptr;
+}
+
+// -------------------------------------------------------------------
+
+bool DescriptorPool::TryFindFileInFallbackDatabase(
+    StringPiece name) const {
+  if (fallback_database_ == nullptr) return false;
+
+  auto name_string = std::string(name);
+  if (tables_->known_bad_files_.count(name_string) > 0) return false;
+
+  FileDescriptorProto file_proto;
+  if (!fallback_database_->FindFileByName(name_string, &file_proto) ||
+      BuildFileFromDatabase(file_proto) == nullptr) {
+    tables_->known_bad_files_.insert(std::move(name_string));
+    return false;
+  }
+  return true;
+}
+
+bool DescriptorPool::IsSubSymbolOfBuiltType(StringPiece name) const {
+  auto prefix = std::string(name);
+  for (;;) {
+    std::string::size_type dot_pos = prefix.find_last_of('.');
+    if (dot_pos == std::string::npos) {
+      break;
+    }
+    prefix = prefix.substr(0, dot_pos);
+    Symbol symbol = tables_->FindSymbol(prefix);
+    // If the symbol type is anything other than PACKAGE, then its complete
+    // definition is already known.
+    if (!symbol.IsNull() && !symbol.IsPackage()) {
+      return true;
+    }
+  }
+  if (underlay_ != nullptr) {
+    // Check to see if any prefix of this symbol exists in the underlay.
+    return underlay_->IsSubSymbolOfBuiltType(name);
+  }
+  return false;
+}
+
+bool DescriptorPool::TryFindSymbolInFallbackDatabase(
+    StringPiece name) const {
+  if (fallback_database_ == nullptr) return false;
+
+  auto name_string = std::string(name);
+  if (tables_->known_bad_symbols_.count(name_string) > 0) return false;
+
+  FileDescriptorProto file_proto;
+  if (  // We skip looking in the fallback database if the name is a sub-symbol
+        // of any descriptor that already exists in the descriptor pool (except
+        // for package descriptors).  This is valid because all symbols except
+        // for packages are defined in a single file, so if the symbol exists
+        // then we should already have its definition.
+        //
+        // The other reason to do this is to support "overriding" type
+        // definitions by merging two databases that define the same type. (Yes,
+        // people do this.)  The main difficulty with making this work is that
+        // FindFileContainingSymbol() is allowed to return both false positives
+        // (e.g., SimpleDescriptorDatabase, UpgradedDescriptorDatabase) and
+        // false negatives (e.g. ProtoFileParser, SourceTreeDescriptorDatabase).
+        // When two such databases are merged, looking up a non-existent
+        // sub-symbol of a type that already exists in the descriptor pool can
+        // result in an attempt to load multiple definitions of the same type.
+        // The check below avoids this.
+      IsSubSymbolOfBuiltType(name)
+
+      // Look up file containing this symbol in fallback database.
+      || !fallback_database_->FindFileContainingSymbol(name_string, &file_proto)
+
+      // Check if we've already built this file. If so, it apparently doesn't
+      // contain the symbol we're looking for.  Some DescriptorDatabases
+      // return false positives.
+      || tables_->FindFile(file_proto.name()) != nullptr
+
+      // Build the file.
+      || BuildFileFromDatabase(file_proto) == nullptr) {
+    tables_->known_bad_symbols_.insert(std::move(name_string));
+    return false;
+  }
+
+  return true;
+}
+
+bool DescriptorPool::TryFindExtensionInFallbackDatabase(
+    const Descriptor* containing_type, int field_number) const {
+  if (fallback_database_ == nullptr) return false;
+
+  FileDescriptorProto file_proto;
+  if (!fallback_database_->FindFileContainingExtension(
+          containing_type->full_name(), field_number, &file_proto)) {
+    return false;
+  }
+
+  if (tables_->FindFile(file_proto.name()) != nullptr) {
+    // We've already loaded this file, and it apparently doesn't contain the
+    // extension we're looking for.  Some DescriptorDatabases return false
+    // positives.
+    return false;
+  }
+
+  if (BuildFileFromDatabase(file_proto) == nullptr) {
+    return false;
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+bool FieldDescriptor::is_map_message_type() const {
+  return type_descriptor_.message_type->options().map_entry();
+}
+
+std::string FieldDescriptor::DefaultValueAsString(
+    bool quote_string_type) const {
+  GOOGLE_CHECK(has_default_value()) << "No default value";
+  switch (cpp_type()) {
+    case CPPTYPE_INT32:
+      return StrCat(default_value_int32_t());
+    case CPPTYPE_INT64:
+      return StrCat(default_value_int64_t());
+    case CPPTYPE_UINT32:
+      return StrCat(default_value_uint32_t());
+    case CPPTYPE_UINT64:
+      return StrCat(default_value_uint64_t());
+    case CPPTYPE_FLOAT:
+      return SimpleFtoa(default_value_float());
+    case CPPTYPE_DOUBLE:
+      return SimpleDtoa(default_value_double());
+    case CPPTYPE_BOOL:
+      return default_value_bool() ? "true" : "false";
+    case CPPTYPE_STRING:
+      if (quote_string_type) {
+        return "\"" + CEscape(default_value_string()) + "\"";
+      } else {
+        if (type() == TYPE_BYTES) {
+          return CEscape(default_value_string());
+        } else {
+          return default_value_string();
+        }
+      }
+    case CPPTYPE_ENUM:
+      return default_value_enum()->name();
+    case CPPTYPE_MESSAGE:
+      GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
+      break;
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here: failed to get default value as string";
+  return "";
+}
+
+// CopyTo methods ====================================================
+
+void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
+  proto->set_name(name());
+  if (!package().empty()) proto->set_package(package());
+  // TODO(liujisi): Also populate when syntax="proto2".
+  if (syntax() == SYNTAX_PROTO3) proto->set_syntax(SyntaxName(syntax()));
+
+  for (int i = 0; i < dependency_count(); i++) {
+    proto->add_dependency(dependency(i)->name());
+  }
+
+  for (int i = 0; i < public_dependency_count(); i++) {
+    proto->add_public_dependency(public_dependencies_[i]);
+  }
+
+  for (int i = 0; i < weak_dependency_count(); i++) {
+    proto->add_weak_dependency(weak_dependencies_[i]);
+  }
+
+  for (int i = 0; i < message_type_count(); i++) {
+    message_type(i)->CopyTo(proto->add_message_type());
+  }
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->CopyTo(proto->add_enum_type());
+  }
+  for (int i = 0; i < service_count(); i++) {
+    service(i)->CopyTo(proto->add_service());
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyTo(proto->add_extension());
+  }
+
+  if (&options() != &FileOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+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()) {
+    proto->mutable_source_code_info()->CopyFrom(*source_code_info_);
+  }
+}
+
+void Descriptor::CopyTo(DescriptorProto* proto) const {
+  proto->set_name(name());
+
+  for (int i = 0; i < field_count(); i++) {
+    field(i)->CopyTo(proto->add_field());
+  }
+  for (int i = 0; i < oneof_decl_count(); i++) {
+    oneof_decl(i)->CopyTo(proto->add_oneof_decl());
+  }
+  for (int i = 0; i < nested_type_count(); i++) {
+    nested_type(i)->CopyTo(proto->add_nested_type());
+  }
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->CopyTo(proto->add_enum_type());
+  }
+  for (int i = 0; i < extension_range_count(); i++) {
+    extension_range(i)->CopyTo(proto->add_extension_range());
+  }
+  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());
+  }
+  if (proto3_optional_) {
+    proto->set_proto3_optional(true);
+  }
+  // Some compilers do not allow static_cast directly between two enum types,
+  // so we must cast to int first.
+  proto->set_label(static_cast<FieldDescriptorProto::Label>(
+      implicit_cast<int>(label())));
+  proto->set_type(static_cast<FieldDescriptorProto::Type>(
+      implicit_cast<int>(type())));
+
+  if (is_extension()) {
+    if (!containing_type()->is_unqualified_placeholder_) {
+      proto->set_extendee(".");
+    }
+    proto->mutable_extendee()->append(containing_type()->full_name());
+  }
+
+  if (cpp_type() == CPPTYPE_MESSAGE) {
+    if (message_type()->is_placeholder_) {
+      // We don't actually know if the type is a message type.  It could be
+      // an enum.
+      proto->clear_type();
+    }
+
+    if (!message_type()->is_unqualified_placeholder_) {
+      proto->set_type_name(".");
+    }
+    proto->mutable_type_name()->append(message_type()->full_name());
+  } else if (cpp_type() == CPPTYPE_ENUM) {
+    if (!enum_type()->is_unqualified_placeholder_) {
+      proto->set_type_name(".");
+    }
+    proto->mutable_type_name()->append(enum_type()->full_name());
+  }
+
+  if (has_default_value()) {
+    proto->set_default_value(DefaultValueAsString(false));
+  }
+
+  if (containing_oneof() != nullptr && !is_extension()) {
+    proto->set_oneof_index(containing_oneof()->index());
+  }
+
+  if (&options() != &FieldOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
+  proto->set_json_name(json_name());
+}
+
+void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
+  proto->set_name(name());
+  if (&options() != &OneofOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const {
+  proto->set_name(name());
+
+  for (int i = 0; i < value_count(); i++) {
+    value(i)->CopyTo(proto->add_value());
+  }
+  for (int i = 0; i < reserved_range_count(); i++) {
+    EnumDescriptorProto::EnumReservedRange* 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() != &EnumOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void EnumValueDescriptor::CopyTo(EnumValueDescriptorProto* proto) const {
+  proto->set_name(name());
+  proto->set_number(number());
+
+  if (&options() != &EnumValueOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void ServiceDescriptor::CopyTo(ServiceDescriptorProto* proto) const {
+  proto->set_name(name());
+
+  for (int i = 0; i < method_count(); i++) {
+    method(i)->CopyTo(proto->add_method());
+  }
+
+  if (&options() != &ServiceOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const {
+  proto->set_name(name());
+
+  if (!input_type()->is_unqualified_placeholder_) {
+    proto->set_input_type(".");
+  }
+  proto->mutable_input_type()->append(input_type()->full_name());
+
+  if (!output_type()->is_unqualified_placeholder_) {
+    proto->set_output_type(".");
+  }
+  proto->mutable_output_type()->append(output_type()->full_name());
+
+  if (&options() != &MethodOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+
+  if (client_streaming_) {
+    proto->set_client_streaming(true);
+  }
+  if (server_streaming_) {
+    proto->set_server_streaming(true);
+  }
+}
+
+// DebugString methods ===============================================
+
+namespace {
+
+bool RetrieveOptionsAssumingRightPool(
+    int depth, const Message& options,
+    std::vector<std::string>* option_entries) {
+  option_entries->clear();
+  const Reflection* reflection = options.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(options, &fields);
+  for (const FieldDescriptor* field : fields) {
+    int count = 1;
+    bool repeated = false;
+    if (field->is_repeated()) {
+      count = reflection->FieldSize(options, field);
+      repeated = true;
+    }
+    for (int j = 0; j < count; j++) {
+      std::string fieldval;
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        std::string tmp;
+        TextFormat::Printer printer;
+        printer.SetExpandAny(true);
+        printer.SetInitialIndentLevel(depth + 1);
+        printer.PrintFieldValueToString(options, field, repeated ? j : -1,
+                                        &tmp);
+        fieldval.append("{\n");
+        fieldval.append(tmp);
+        fieldval.append(depth * 2, ' ');
+        fieldval.append("}");
+      } else {
+        TextFormat::PrintFieldValueToString(options, field, repeated ? j : -1,
+                                            &fieldval);
+      }
+      std::string name;
+      if (field->is_extension()) {
+        name = "(." + field->full_name() + ")";
+      } else {
+        name = field->name();
+      }
+      option_entries->push_back(name + " = " + fieldval);
+    }
+  }
+  return !option_entries->empty();
+}
+
+// Used by each of the option formatters.
+bool RetrieveOptions(int depth, const Message& options,
+                     const DescriptorPool* pool,
+                     std::vector<std::string>* option_entries) {
+  // When printing custom options for a descriptor, we must use an options
+  // message built on top of the same DescriptorPool where the descriptor
+  // is coming from. This is to ensure we are interpreting custom options
+  // against the right pool.
+  if (options.GetDescriptor()->file()->pool() == pool) {
+    return RetrieveOptionsAssumingRightPool(depth, options, option_entries);
+  } else {
+    const Descriptor* option_descriptor =
+        pool->FindMessageTypeByName(options.GetDescriptor()->full_name());
+    if (option_descriptor == nullptr) {
+      // descriptor.proto is not in the pool. This means no custom options are
+      // used so we are safe to proceed with the compiled options message type.
+      return RetrieveOptionsAssumingRightPool(depth, options, option_entries);
+    }
+    DynamicMessageFactory factory;
+    std::unique_ptr<Message> dynamic_options(
+        factory.GetPrototype(option_descriptor)->New());
+    std::string serialized = options.SerializeAsString();
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8_t*>(serialized.c_str()),
+        serialized.size());
+    input.SetExtensionRegistry(pool, &factory);
+    if (dynamic_options->ParseFromCodedStream(&input)) {
+      return RetrieveOptionsAssumingRightPool(depth, *dynamic_options,
+                                              option_entries);
+    } else {
+      GOOGLE_LOG(ERROR) << "Found invalid proto option data for: "
+                 << options.GetDescriptor()->full_name();
+      return RetrieveOptionsAssumingRightPool(depth, options, option_entries);
+    }
+  }
+}
+
+// Formats options that all appear together in brackets. Does not include
+// brackets.
+bool FormatBracketedOptions(int depth, const Message& options,
+                            const DescriptorPool* pool, std::string* output) {
+  std::vector<std::string> all_options;
+  if (RetrieveOptions(depth, options, pool, &all_options)) {
+    output->append(Join(all_options, ", "));
+  }
+  return !all_options.empty();
+}
+
+// Formats options one per line
+bool FormatLineOptions(int depth, const Message& options,
+                       const DescriptorPool* pool, std::string* output) {
+  std::string prefix(depth * 2, ' ');
+  std::vector<std::string> all_options;
+  if (RetrieveOptions(depth, options, pool, &all_options)) {
+    for (const std::string& option : all_options) {
+      strings::SubstituteAndAppend(output, "$0option $1;\n", prefix, option);
+    }
+  }
+  return !all_options.empty();
+}
+
+class SourceLocationCommentPrinter {
+ public:
+  template <typename DescType>
+  SourceLocationCommentPrinter(const DescType* desc, const std::string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ =
+        options.include_comments && desc->GetSourceLocation(&source_loc_);
+  }
+  SourceLocationCommentPrinter(const FileDescriptor* file,
+                               const std::vector<int>& path,
+                               const std::string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ =
+        options.include_comments && file->GetSourceLocation(path, &source_loc_);
+  }
+  void AddPreComment(std::string* output) {
+    if (have_source_loc_) {
+      // Detached leading comments.
+      for (const std::string& leading_detached_comment :
+           source_loc_.leading_detached_comments) {
+        *output += FormatComment(leading_detached_comment);
+        *output += "\n";
+      }
+      // Attached leading comments.
+      if (!source_loc_.leading_comments.empty()) {
+        *output += FormatComment(source_loc_.leading_comments);
+      }
+    }
+  }
+  void AddPostComment(std::string* output) {
+    if (have_source_loc_ && source_loc_.trailing_comments.size() > 0) {
+      *output += FormatComment(source_loc_.trailing_comments);
+    }
+  }
+
+  // Format comment such that each line becomes a full-line C++-style comment in
+  // the DebugString() output.
+  std::string FormatComment(const std::string& comment_text) {
+    std::string stripped_comment = comment_text;
+    StripWhitespace(&stripped_comment);
+    std::vector<std::string> lines = Split(stripped_comment, "\n");
+    std::string output;
+    for (const std::string& line : lines) {
+      strings::SubstituteAndAppend(&output, "$0// $1\n", prefix_, line);
+    }
+    return output;
+  }
+
+ private:
+
+  bool have_source_loc_;
+  SourceLocation source_loc_;
+  DebugStringOptions options_;
+  std::string prefix_;
+};
+
+}  // anonymous namespace
+
+std::string FileDescriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+std::string FileDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& debug_string_options) const {
+  std::string contents;
+  {
+    std::vector<int> path;
+    path.push_back(FileDescriptorProto::kSyntaxFieldNumber);
+    SourceLocationCommentPrinter syntax_comment(this, path, "",
+                                                debug_string_options);
+    syntax_comment.AddPreComment(&contents);
+    strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
+                              SyntaxName(syntax()));
+    syntax_comment.AddPostComment(&contents);
+  }
+
+  SourceLocationCommentPrinter comment_printer(this, "", debug_string_options);
+  comment_printer.AddPreComment(&contents);
+
+  std::set<int> public_dependencies;
+  std::set<int> weak_dependencies;
+  public_dependencies.insert(public_dependencies_,
+                             public_dependencies_ + public_dependency_count_);
+  weak_dependencies.insert(weak_dependencies_,
+                           weak_dependencies_ + weak_dependency_count_);
+
+  for (int i = 0; i < dependency_count(); i++) {
+    if (public_dependencies.count(i) > 0) {
+      strings::SubstituteAndAppend(&contents, "import public \"$0\";\n",
+                                dependency(i)->name());
+    } else if (weak_dependencies.count(i) > 0) {
+      strings::SubstituteAndAppend(&contents, "import weak \"$0\";\n",
+                                dependency(i)->name());
+    } else {
+      strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
+                                dependency(i)->name());
+    }
+  }
+
+  if (!package().empty()) {
+    std::vector<int> path;
+    path.push_back(FileDescriptorProto::kPackageFieldNumber);
+    SourceLocationCommentPrinter package_comment(this, path, "",
+                                                 debug_string_options);
+    package_comment.AddPreComment(&contents);
+    strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
+    package_comment.AddPostComment(&contents);
+  }
+
+  if (FormatLineOptions(0, options(), pool(), &contents)) {
+    contents.append("\n");  // add some space if we had options
+  }
+
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->DebugString(0, &contents, debug_string_options);
+    contents.append("\n");
+  }
+
+  // Find all the 'group' type extensions; we will not output their nested
+  // definitions (those will be done with their group field descriptor).
+  std::set<const Descriptor*> groups;
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(extension(i)->message_type());
+    }
+  }
+
+  for (int i = 0; i < message_type_count(); i++) {
+    if (groups.count(message_type(i)) == 0) {
+      message_type(i)->DebugString(0, &contents, debug_string_options,
+                                   /* include_opening_clause */ true);
+      contents.append("\n");
+    }
+  }
+
+  for (int i = 0; i < service_count(); i++) {
+    service(i)->DebugString(&contents, debug_string_options);
+    contents.append("\n");
+  }
+
+  const Descriptor* containing_type = nullptr;
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->containing_type() != containing_type) {
+      if (i > 0) contents.append("}\n\n");
+      containing_type = extension(i)->containing_type();
+      strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
+                                containing_type->full_name());
+    }
+    extension(i)->DebugString(1, &contents, debug_string_options);
+  }
+  if (extension_count() > 0) contents.append("}\n\n");
+
+  comment_printer.AddPostComment(&contents);
+
+  return contents;
+}
+
+std::string Descriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+std::string Descriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options, /* include_opening_clause */ true);
+  return contents;
+}
+
+void Descriptor::DebugString(int depth, std::string* contents,
+                             const DebugStringOptions& debug_string_options,
+                             bool include_opening_clause) const {
+  if (options().map_entry()) {
+    // Do not generate debug string for auto-generated map-entry type.
+    return;
+  }
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  if (include_opening_clause) {
+    strings::SubstituteAndAppend(contents, "$0message $1", prefix, name());
+  }
+  contents->append(" {\n");
+
+  FormatLineOptions(depth, options(), file()->pool(), contents);
+
+  // Find all the 'group' types for fields and extensions; we will not output
+  // their nested definitions (those will be done with their group field
+  // descriptor).
+  std::set<const Descriptor*> groups;
+  for (int i = 0; i < field_count(); i++) {
+    if (field(i)->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(field(i)->message_type());
+    }
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(extension(i)->message_type());
+    }
+  }
+
+  for (int i = 0; i < nested_type_count(); i++) {
+    if (groups.count(nested_type(i)) == 0) {
+      nested_type(i)->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ true);
+    }
+  }
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->DebugString(depth, contents, debug_string_options);
+  }
+  for (int i = 0; i < field_count(); i++) {
+    if (field(i)->real_containing_oneof() == nullptr) {
+      field(i)->DebugString(depth, contents, debug_string_options);
+    } else if (field(i)->containing_oneof()->field(0) == field(i)) {
+      // This is the first field in this oneof, so print the whole oneof.
+      field(i)->containing_oneof()->DebugString(depth, contents,
+                                                debug_string_options);
+    }
+  }
+
+  for (int i = 0; i < extension_range_count(); i++) {
+    strings::SubstituteAndAppend(contents, "$0  extensions $1 to $2;\n", prefix,
+                              extension_range(i)->start,
+                              extension_range(i)->end - 1);
+  }
+
+  // Group extensions by what they extend, so they can be printed out together.
+  const Descriptor* containing_type = nullptr;
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->containing_type() != containing_type) {
+      if (i > 0) strings::SubstituteAndAppend(contents, "$0  }\n", prefix);
+      containing_type = extension(i)->containing_type();
+      strings::SubstituteAndAppend(contents, "$0  extend .$1 {\n", prefix,
+                                containing_type->full_name());
+    }
+    extension(i)->DebugString(depth + 1, contents, debug_string_options);
+  }
+  if (extension_count() > 0)
+    strings::SubstituteAndAppend(contents, "$0  }\n", prefix);
+
+  if (reserved_range_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_range_count(); i++) {
+      const Descriptor::ReservedRange* range = reserved_range(i);
+      if (range->end == range->start + 1) {
+        strings::SubstituteAndAppend(contents, "$0, ", range->start);
+      } else if (range->end > FieldDescriptor::kMaxNumber) {
+        strings::SubstituteAndAppend(contents, "$0 to max, ", 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);
+}
+
+std::string FieldDescriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+std::string FieldDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& debug_string_options) const {
+  std::string contents;
+  int depth = 0;
+  if (is_extension()) {
+    strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
+                              containing_type()->full_name());
+    depth = 1;
+  }
+  DebugString(depth, &contents, debug_string_options);
+  if (is_extension()) {
+    contents.append("}\n");
+  }
+  return contents;
+}
+
+// The field type string used in FieldDescriptor::DebugString()
+std::string FieldDescriptor::FieldTypeNameDebugString() const {
+  switch (type()) {
+    case TYPE_MESSAGE:
+      return "." + message_type()->full_name();
+    case TYPE_ENUM:
+      return "." + enum_type()->full_name();
+    default:
+      return kTypeToName[type()];
+  }
+}
+
+void FieldDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  std::string field_type;
+
+  // Special case map fields.
+  if (is_map()) {
+    strings::SubstituteAndAppend(
+        &field_type, "map<$0, $1>",
+        message_type()->field(0)->FieldTypeNameDebugString(),
+        message_type()->field(1)->FieldTypeNameDebugString());
+  } else {
+    field_type = FieldTypeNameDebugString();
+  }
+
+  std::string label = StrCat(kLabelToName[this->label()], " ");
+
+  // Label is omitted for maps, oneof, and plain proto3 fields.
+  if (is_map() || real_containing_oneof() ||
+      (is_optional() && !has_optional_keyword())) {
+    label.clear();
+  }
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(
+      contents, "$0$1$2 $3 = $4", prefix, label, field_type,
+      type() == TYPE_GROUP ? message_type()->name() : name(), number());
+
+  bool bracketed = false;
+  if (has_default_value()) {
+    bracketed = true;
+    strings::SubstituteAndAppend(contents, " [default = $0",
+                              DefaultValueAsString(true));
+  }
+  if (has_json_name_) {
+    if (!bracketed) {
+      bracketed = true;
+      contents->append(" [");
+    } else {
+      contents->append(", ");
+    }
+    contents->append("json_name = \"");
+    contents->append(CEscape(json_name()));
+    contents->append("\"");
+  }
+
+  std::string formatted_options;
+  if (FormatBracketedOptions(depth, options(), file()->pool(),
+                             &formatted_options)) {
+    contents->append(bracketed ? ", " : " [");
+    bracketed = true;
+    contents->append(formatted_options);
+  }
+
+  if (bracketed) {
+    contents->append("]");
+  }
+
+  if (type() == TYPE_GROUP) {
+    if (debug_string_options.elide_group_body) {
+      contents->append(" { ... };\n");
+    } else {
+      message_type()->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ false);
+    }
+  } else {
+    contents->append(";\n");
+  }
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string OneofDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string OneofDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void OneofDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+  strings::SubstituteAndAppend(contents, "$0oneof $1 {", prefix, name());
+
+  FormatLineOptions(depth, options(), containing_type()->file()->pool(),
+                    contents);
+
+  if (debug_string_options.elide_oneof_body) {
+    contents->append(" ... }\n");
+  } else {
+    contents->append("\n");
+    for (int i = 0; i < field_count(); i++) {
+      field(i)->DebugString(depth, contents, debug_string_options);
+    }
+    strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+  }
+  comment_printer.AddPostComment(contents);
+}
+
+std::string EnumDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string EnumDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void EnumDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "$0enum $1 {\n", prefix, name());
+
+  FormatLineOptions(depth, options(), file()->pool(), contents);
+
+  for (int i = 0; i < value_count(); i++) {
+    value(i)->DebugString(depth, contents, debug_string_options);
+  }
+
+  if (reserved_range_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_range_count(); i++) {
+      const EnumDescriptor::ReservedRange* range = reserved_range(i);
+      if (range->end == range->start) {
+        strings::SubstituteAndAppend(contents, "$0, ", range->start);
+      } else if (range->end == INT_MAX) {
+        strings::SubstituteAndAppend(contents, "$0 to max, ", range->start);
+      } else {
+        strings::SubstituteAndAppend(contents, "$0 to $1, ", range->start,
+                                  range->end);
+      }
+    }
+    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);
+}
+
+std::string EnumValueDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string EnumValueDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void EnumValueDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "$0$1 = $2", prefix, name(), number());
+
+  std::string formatted_options;
+  if (FormatBracketedOptions(depth, options(), type()->file()->pool(),
+                             &formatted_options)) {
+    strings::SubstituteAndAppend(contents, " [$0]", formatted_options);
+  }
+  contents->append(";\n");
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string ServiceDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string ServiceDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(&contents, options);
+  return contents;
+}
+
+void ServiceDescriptor::DebugString(
+    std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  SourceLocationCommentPrinter comment_printer(this, /* prefix */ "",
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "service $0 {\n", name());
+
+  FormatLineOptions(1, options(), file()->pool(), contents);
+
+  for (int i = 0; i < method_count(); i++) {
+    method(i)->DebugString(1, contents, debug_string_options);
+  }
+
+  contents->append("}\n");
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string MethodDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string MethodDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void MethodDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(
+      contents, "$0rpc $1($4.$2) returns ($5.$3)", prefix, name(),
+      input_type()->full_name(), output_type()->full_name(),
+      client_streaming() ? "stream " : "", server_streaming() ? "stream " : "");
+
+  std::string formatted_options;
+  if (FormatLineOptions(depth, options(), service()->file()->pool(),
+                        &formatted_options)) {
+    strings::SubstituteAndAppend(contents, " {\n$0$1}\n", formatted_options,
+                              prefix);
+  } else {
+    contents->append(";\n");
+  }
+
+  comment_printer.AddPostComment(contents);
+}
+
+// Location methods ===============================================
+
+bool FileDescriptor::GetSourceLocation(const std::vector<int>& path,
+                                       SourceLocation* out_location) const {
+  GOOGLE_CHECK(out_location != nullptr);
+  if (source_code_info_) {
+    if (const SourceCodeInfo_Location* loc =
+            tables_->GetSourceLocation(path, source_code_info_)) {
+      const RepeatedField<int32_t>& span = loc->span();
+      if (span.size() == 3 || span.size() == 4) {
+        out_location->start_line = span.Get(0);
+        out_location->start_column = span.Get(1);
+        out_location->end_line = span.Get(span.size() == 3 ? 0 : 2);
+        out_location->end_column = span.Get(span.size() - 1);
+
+        out_location->leading_comments = loc->leading_comments();
+        out_location->trailing_comments = loc->trailing_comments();
+        out_location->leading_detached_comments.assign(
+            loc->leading_detached_comments().begin(),
+            loc->leading_detached_comments().end());
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;  // empty path for root FileDescriptor
+  return GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::is_packed() const {
+  if (!is_packable()) return false;
+  if (file_->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+    return (options_ != nullptr) && options_->packed();
+  } else {
+    return options_ == nullptr || !options_->has_packed() || options_->packed();
+  }
+}
+
+bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool OneofDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return containing_type()->file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool MethodDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return service()->file()->GetSourceLocation(path, out_location);
+}
+
+bool ServiceDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumValueDescriptor::GetSourceLocation(
+    SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return type()->file()->GetSourceLocation(path, out_location);
+}
+
+void Descriptor::GetLocationPath(std::vector<int>* output) const {
+  if (containing_type()) {
+    containing_type()->GetLocationPath(output);
+    output->push_back(DescriptorProto::kNestedTypeFieldNumber);
+    output->push_back(index());
+  } else {
+    output->push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+    output->push_back(index());
+  }
+}
+
+void FieldDescriptor::GetLocationPath(std::vector<int>* output) const {
+  if (is_extension()) {
+    if (extension_scope() == nullptr) {
+      output->push_back(FileDescriptorProto::kExtensionFieldNumber);
+      output->push_back(index());
+    } else {
+      extension_scope()->GetLocationPath(output);
+      output->push_back(DescriptorProto::kExtensionFieldNumber);
+      output->push_back(index());
+    }
+  } else {
+    containing_type()->GetLocationPath(output);
+    output->push_back(DescriptorProto::kFieldFieldNumber);
+    output->push_back(index());
+  }
+}
+
+void OneofDescriptor::GetLocationPath(std::vector<int>* output) const {
+  containing_type()->GetLocationPath(output);
+  output->push_back(DescriptorProto::kOneofDeclFieldNumber);
+  output->push_back(index());
+}
+
+void EnumDescriptor::GetLocationPath(std::vector<int>* output) const {
+  if (containing_type()) {
+    containing_type()->GetLocationPath(output);
+    output->push_back(DescriptorProto::kEnumTypeFieldNumber);
+    output->push_back(index());
+  } else {
+    output->push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+    output->push_back(index());
+  }
+}
+
+void EnumValueDescriptor::GetLocationPath(std::vector<int>* output) const {
+  type()->GetLocationPath(output);
+  output->push_back(EnumDescriptorProto::kValueFieldNumber);
+  output->push_back(index());
+}
+
+void ServiceDescriptor::GetLocationPath(std::vector<int>* output) const {
+  output->push_back(FileDescriptorProto::kServiceFieldNumber);
+  output->push_back(index());
+}
+
+void MethodDescriptor::GetLocationPath(std::vector<int>* output) const {
+  service()->GetLocationPath(output);
+  output->push_back(ServiceDescriptorProto::kMethodFieldNumber);
+  output->push_back(index());
+}
+
+// ===================================================================
+
+namespace {
+
+// Represents an options message to interpret. Extension names in the option
+// 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.
+struct OptionsToInterpret {
+  OptionsToInterpret(const std::string& ns, const std::string& el,
+                     const std::vector<int>& path, const Message* orig_opt,
+                     Message* opt)
+      : name_scope(ns),
+        element_name(el),
+        element_path(path),
+        original_options(orig_opt),
+        options(opt) {}
+  std::string name_scope;
+  std::string element_name;
+  std::vector<int> element_path;
+  const Message* original_options;
+  Message* options;
+};
+
+}  // namespace
+
+class DescriptorBuilder {
+ public:
+  DescriptorBuilder(const DescriptorPool* pool, DescriptorPool::Tables* tables,
+                    DescriptorPool::ErrorCollector* error_collector);
+  ~DescriptorBuilder();
+
+  const FileDescriptor* BuildFile(const FileDescriptorProto& proto);
+
+ private:
+  friend class OptionInterpreter;
+
+  // Non-recursive part of BuildFile functionality.
+  FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto,
+                                internal::FlatAllocator& alloc);
+
+  const DescriptorPool* pool_;
+  DescriptorPool::Tables* tables_;  // for convenience
+  DescriptorPool::ErrorCollector* error_collector_;
+
+  // As we build descriptors we store copies of the options messages in
+  // them. We put pointers to those copies in this vector, as we build, so we
+  // can later (after cross-linking) interpret those options.
+  std::vector<OptionsToInterpret> options_to_interpret_;
+
+  bool had_errors_;
+  std::string filename_;
+  FileDescriptor* file_;
+  FileDescriptorTables* file_tables_;
+  std::set<const FileDescriptor*> dependencies_;
+
+  struct MessageHints {
+    int fields_to_suggest = 0;
+    const Message* first_reason = nullptr;
+    DescriptorPool::ErrorCollector::ErrorLocation first_reason_location =
+        DescriptorPool::ErrorCollector::ErrorLocation::OTHER;
+
+    void RequestHintOnFieldNumbers(
+        const Message& reason,
+        DescriptorPool::ErrorCollector::ErrorLocation reason_location,
+        int range_start = 0, int range_end = 1) {
+      auto fit = [](int value) {
+        return std::min(std::max(value, 0), FieldDescriptor::kMaxNumber);
+      };
+      fields_to_suggest =
+          fit(fields_to_suggest + fit(fit(range_end) - fit(range_start)));
+      if (first_reason) return;
+      first_reason = &reason;
+      first_reason_location = reason_location;
+    }
+  };
+
+  std::unordered_map<const Descriptor*, MessageHints> message_hints_;
+
+  // unused_dependency_ is used to record the unused imported files.
+  // Note: public import is not considered.
+  std::set<const FileDescriptor*> unused_dependency_;
+
+  // If LookupSymbol() finds a symbol that is in a file which is not a declared
+  // dependency of this file, it will fail, but will set
+  // possible_undeclared_dependency_ to point at that file.  This is only used
+  // by AddNotDefinedError() to report a more useful error message.
+  // possible_undeclared_dependency_name_ is the name of the symbol that was
+  // actually found in possible_undeclared_dependency_, which may be a parent
+  // of the symbol actually looked for.
+  const FileDescriptor* possible_undeclared_dependency_;
+  std::string possible_undeclared_dependency_name_;
+
+  // If LookupSymbol() could resolve a symbol which is not defined,
+  // record the resolved name.  This is only used by AddNotDefinedError()
+  // to report a more useful error message.
+  std::string undefine_resolved_name_;
+
+  // Tracker for current recursion depth to implement recursion protection.
+  //
+  // Counts down to 0 when there is no depth remaining.
+  //
+  // Maximum recursion depth corresponds to 32 nested message declarations.
+  int recursion_depth_ = 32;
+
+  void AddError(const std::string& element_name, const Message& descriptor,
+                DescriptorPool::ErrorCollector::ErrorLocation location,
+                const std::string& error);
+  void AddError(const std::string& element_name, const Message& descriptor,
+                DescriptorPool::ErrorCollector::ErrorLocation location,
+                const char* error);
+  void AddRecursiveImportError(const FileDescriptorProto& proto, int from_here);
+  void AddTwiceListedError(const FileDescriptorProto& proto, int index);
+  void AddImportError(const FileDescriptorProto& proto, int index);
+
+  // Adds an error indicating that undefined_symbol was not defined.  Must
+  // only be called after LookupSymbol() fails.
+  void AddNotDefinedError(
+      const std::string& element_name, const Message& descriptor,
+      DescriptorPool::ErrorCollector::ErrorLocation location,
+      const std::string& undefined_symbol);
+
+  void AddWarning(const std::string& element_name, const Message& descriptor,
+                  DescriptorPool::ErrorCollector::ErrorLocation location,
+                  const std::string& error);
+
+  // Silly helper which determines if the given file is in the given package.
+  // I.e., either file->package() == package_name or file->package() is a
+  // nested package within package_name.
+  bool IsInPackage(const FileDescriptor* file, const std::string& package_name);
+
+  // Helper function which finds all public dependencies of the given file, and
+  // stores the them in the dependencies_ set in the builder.
+  void RecordPublicDependencies(const FileDescriptor* file);
+
+  // Like tables_->FindSymbol(), but additionally:
+  // - Search the pool's underlay if not found in tables_.
+  // - Insure that the resulting Symbol is from one of the file's declared
+  //   dependencies.
+  Symbol FindSymbol(const std::string& name, bool build_it = true);
+
+  // Like FindSymbol() but does not require that the symbol is in one of the
+  // file's declared dependencies.
+  Symbol FindSymbolNotEnforcingDeps(const std::string& name,
+                                    bool build_it = true);
+
+  // This implements the body of FindSymbolNotEnforcingDeps().
+  Symbol FindSymbolNotEnforcingDepsHelper(const DescriptorPool* pool,
+                                          const std::string& name,
+                                          bool build_it = true);
+
+  // Like FindSymbol(), but looks up the name relative to some other symbol
+  // name.  This first searches siblings of relative_to, then siblings of its
+  // parents, etc.  For example, LookupSymbol("foo.bar", "baz.moo.corge") makes
+  // the following calls, returning the first non-null result:
+  // FindSymbol("baz.moo.foo.bar"), FindSymbol("baz.foo.bar"),
+  // FindSymbol("foo.bar").  If AllowUnknownDependencies() has been called
+  // on the DescriptorPool, this will generate a placeholder type if
+  // the name is not found (unless the name itself is malformed).  The
+  // placeholder_type parameter indicates what kind of placeholder should be
+  // constructed in this case.  The resolve_mode parameter determines whether
+  // any symbol is returned, or only symbols that are types.  Note, however,
+  // that LookupSymbol may still return a non-type symbol in LOOKUP_TYPES mode,
+  // if it believes that's all it could refer to.  The caller should always
+  // check that it receives the type of symbol it was expecting.
+  enum ResolveMode { LOOKUP_ALL, LOOKUP_TYPES };
+  Symbol LookupSymbol(const std::string& name, const std::string& relative_to,
+                      DescriptorPool::PlaceholderType placeholder_type =
+                          DescriptorPool::PLACEHOLDER_MESSAGE,
+                      ResolveMode resolve_mode = LOOKUP_ALL,
+                      bool build_it = true);
+
+  // Like LookupSymbol() but will not return a placeholder even if
+  // AllowUnknownDependencies() has been used.
+  Symbol LookupSymbolNoPlaceholder(const std::string& name,
+                                   const std::string& relative_to,
+                                   ResolveMode resolve_mode = LOOKUP_ALL,
+                                   bool build_it = true);
+
+  // Calls tables_->AddSymbol() and records an error if it fails.  Returns
+  // true if successful or false if failed, though most callers can ignore
+  // the return value since an error has already been recorded.
+  bool AddSymbol(const std::string& full_name, const void* parent,
+                 const std::string& name, const Message& proto, Symbol symbol);
+
+  // Like AddSymbol(), but succeeds if the symbol is already defined as long
+  // as the existing definition is also a package (because it's OK to define
+  // the same package in two different files).  Also adds all parents of the
+  // package to the symbol table (e.g. AddPackage("foo.bar", ...) will add
+  // "foo.bar" and "foo" to the table).
+  void AddPackage(const std::string& name, const Message& proto,
+                  FileDescriptor* file);
+
+  // Checks that the symbol name contains only alphanumeric characters and
+  // underscores.  Records an error otherwise.
+  void ValidateSymbolName(const std::string& name, const std::string& full_name,
+                          const Message& proto);
+
+  // Allocates a copy of orig_options in tables_ and stores it in the
+  // descriptor. Remembers its uninterpreted options, to be interpreted
+  // later. DescriptorT must be one of the Descriptor messages from
+  // descriptor.proto.
+  template <class DescriptorT>
+  void AllocateOptions(const typename DescriptorT::OptionsType& orig_options,
+                       DescriptorT* descriptor, int options_field_tag,
+                       const std::string& option_name,
+                       internal::FlatAllocator& alloc);
+  // Specialization for FileOptions.
+  void AllocateOptions(const FileOptions& orig_options,
+                       FileDescriptor* descriptor,
+                       internal::FlatAllocator& alloc);
+
+  // Implementation for AllocateOptions(). Don't call this directly.
+  template <class DescriptorT>
+  void AllocateOptionsImpl(
+      const std::string& name_scope, const std::string& element_name,
+      const typename DescriptorT::OptionsType& orig_options,
+      DescriptorT* descriptor, const std::vector<int>& options_path,
+      const std::string& option_name, internal::FlatAllocator& alloc);
+
+  // Allocates an array of two strings, the first one is a copy of `proto_name`,
+  // and the second one is the full name.
+  // Full proto name is "scope.proto_name" if scope is non-empty and
+  // "proto_name" otherwise.
+  const std::string* AllocateNameStrings(const std::string& scope,
+                                         const std::string& proto_name,
+                                         internal::FlatAllocator& alloc);
+
+  // These methods all have the same signature for the sake of the BUILD_ARRAY
+  // macro, below.
+  void BuildMessage(const DescriptorProto& proto, const Descriptor* parent,
+                    Descriptor* result, internal::FlatAllocator& alloc);
+  void BuildFieldOrExtension(const FieldDescriptorProto& proto,
+                             Descriptor* parent, FieldDescriptor* result,
+                             bool is_extension, internal::FlatAllocator& alloc);
+  void BuildField(const FieldDescriptorProto& proto, Descriptor* parent,
+                  FieldDescriptor* result, internal::FlatAllocator& alloc) {
+    BuildFieldOrExtension(proto, parent, result, false, alloc);
+  }
+  void BuildExtension(const FieldDescriptorProto& proto, Descriptor* parent,
+                      FieldDescriptor* result, internal::FlatAllocator& alloc) {
+    BuildFieldOrExtension(proto, parent, result, true, alloc);
+  }
+  void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
+                           const Descriptor* parent,
+                           Descriptor::ExtensionRange* result,
+                           internal::FlatAllocator& alloc);
+  void BuildReservedRange(const DescriptorProto::ReservedRange& proto,
+                          const Descriptor* parent,
+                          Descriptor::ReservedRange* result,
+                          internal::FlatAllocator& alloc);
+  void BuildReservedRange(const EnumDescriptorProto::EnumReservedRange& proto,
+                          const EnumDescriptor* parent,
+                          EnumDescriptor::ReservedRange* result,
+                          internal::FlatAllocator& alloc);
+  void BuildOneof(const OneofDescriptorProto& proto, Descriptor* parent,
+                  OneofDescriptor* result, internal::FlatAllocator& alloc);
+  void CheckEnumValueUniqueness(const EnumDescriptorProto& proto,
+                                const EnumDescriptor* result);
+  void BuildEnum(const EnumDescriptorProto& proto, const Descriptor* parent,
+                 EnumDescriptor* result, internal::FlatAllocator& alloc);
+  void BuildEnumValue(const EnumValueDescriptorProto& proto,
+                      const EnumDescriptor* parent, EnumValueDescriptor* result,
+                      internal::FlatAllocator& alloc);
+  void BuildService(const ServiceDescriptorProto& proto, const void* dummy,
+                    ServiceDescriptor* result, internal::FlatAllocator& alloc);
+  void BuildMethod(const MethodDescriptorProto& proto,
+                   const ServiceDescriptor* parent, MethodDescriptor* result,
+                   internal::FlatAllocator& alloc);
+
+  void LogUnusedDependency(const FileDescriptorProto& proto,
+                           const FileDescriptor* result);
+
+  // Must be run only after building.
+  //
+  // NOTE: Options will not be available during cross-linking, as they
+  // have not yet been interpreted. Defer any handling of options to the
+  // Validate*Options methods.
+  void CrossLinkFile(FileDescriptor* file, const FileDescriptorProto& proto);
+  void CrossLinkMessage(Descriptor* message, const DescriptorProto& proto);
+  void CrossLinkField(FieldDescriptor* field,
+                      const FieldDescriptorProto& proto);
+  void CrossLinkExtensionRange(Descriptor::ExtensionRange* range,
+                               const DescriptorProto::ExtensionRange& proto);
+  void CrossLinkEnum(EnumDescriptor* enum_type,
+                     const EnumDescriptorProto& proto);
+  void CrossLinkEnumValue(EnumValueDescriptor* enum_value,
+                          const EnumValueDescriptorProto& proto);
+  void CrossLinkService(ServiceDescriptor* service,
+                        const ServiceDescriptorProto& proto);
+  void CrossLinkMethod(MethodDescriptor* method,
+                       const MethodDescriptorProto& proto);
+  void SuggestFieldNumbers(FileDescriptor* file,
+                           const FileDescriptorProto& proto);
+
+  // Must be run only after cross-linking.
+  void InterpretOptions();
+
+  // A helper class for interpreting options.
+  class OptionInterpreter {
+   public:
+    // Creates an interpreter that operates in the context of the pool of the
+    // specified builder, which must not be nullptr. We don't take ownership of
+    // the builder.
+    explicit OptionInterpreter(DescriptorBuilder* builder);
+
+    ~OptionInterpreter();
+
+    // Interprets the uninterpreted options in the specified Options message.
+    // On error, calls AddError() on the underlying builder and returns false.
+    // Otherwise returns true.
+    bool InterpretOptions(OptionsToInterpret* options_to_interpret);
+
+    // Updates the given source code info by re-writing uninterpreted option
+    // locations to refer to the corresponding interpreted option.
+    void UpdateSourceCodeInfo(SourceCodeInfo* info);
+
+    class AggregateOptionFinder;
+
+   private:
+    // Interprets uninterpreted_option_ on the specified message, which
+    // must be the mutable copy of the original options message to which
+    // uninterpreted_option_ belongs. The given src_path is the source
+    // location path to the uninterpreted option, and options_path is the
+    // source location path to the options message. The location paths are
+    // recorded and then used in UpdateSourceCodeInfo.
+    bool InterpretSingleOption(Message* options,
+                               const std::vector<int>& src_path,
+                               const std::vector<int>& options_path);
+
+    // Adds the uninterpreted_option to the given options message verbatim.
+    // Used when AllowUnknownDependencies() is in effect and we can't find
+    // the option's definition.
+    void AddWithoutInterpreting(const UninterpretedOption& uninterpreted_option,
+                                Message* options);
+
+    // A recursive helper function that drills into the intermediate fields
+    // in unknown_fields to check if field innermost_field is set on the
+    // innermost message. Returns false and sets an error if so.
+    bool ExamineIfOptionIsSet(
+        std::vector<const FieldDescriptor*>::const_iterator
+            intermediate_fields_iter,
+        std::vector<const FieldDescriptor*>::const_iterator
+            intermediate_fields_end,
+        const FieldDescriptor* innermost_field,
+        const std::string& debug_msg_name,
+        const UnknownFieldSet& unknown_fields);
+
+    // Validates the value for the option field of the currently interpreted
+    // option and then sets it on the unknown_field.
+    bool SetOptionValue(const FieldDescriptor* option_field,
+                        UnknownFieldSet* unknown_fields);
+
+    // Parses an aggregate value for a CPPTYPE_MESSAGE option and
+    // saves it into *unknown_fields.
+    bool SetAggregateOption(const FieldDescriptor* option_field,
+                            UnknownFieldSet* unknown_fields);
+
+    // Convenience functions to set an int field the right way, depending on
+    // its wire type (a single int CppType can represent multiple wire types).
+    void SetInt32(int number, int32_t value, FieldDescriptor::Type type,
+                  UnknownFieldSet* unknown_fields);
+    void SetInt64(int number, int64_t value, FieldDescriptor::Type type,
+                  UnknownFieldSet* unknown_fields);
+    void SetUInt32(int number, uint32_t value, FieldDescriptor::Type type,
+                   UnknownFieldSet* unknown_fields);
+    void SetUInt64(int number, uint64_t value, FieldDescriptor::Type type,
+                   UnknownFieldSet* unknown_fields);
+
+    // A helper function that adds an error at the specified location of the
+    // option we're currently interpreting, and returns false.
+    bool AddOptionError(DescriptorPool::ErrorCollector::ErrorLocation location,
+                        const std::string& msg) {
+      builder_->AddError(options_to_interpret_->element_name,
+                         *uninterpreted_option_, location, msg);
+      return false;
+    }
+
+    // A helper function that adds an error at the location of the option name
+    // and returns false.
+    bool AddNameError(const std::string& msg) {
+#ifdef PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+      return true;
+#else   // PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+      return AddOptionError(DescriptorPool::ErrorCollector::OPTION_NAME, msg);
+#endif  // PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+    }
+
+    // A helper function that adds an error at the location of the option name
+    // and returns false.
+    bool AddValueError(const std::string& msg) {
+      return AddOptionError(DescriptorPool::ErrorCollector::OPTION_VALUE, msg);
+    }
+
+    // We interpret against this builder's pool. Is never nullptr. We don't own
+    // this pointer.
+    DescriptorBuilder* builder_;
+
+    // The options we're currently interpreting, or nullptr if we're not in a
+    // call to InterpretOptions.
+    const OptionsToInterpret* options_to_interpret_;
+
+    // The option we're currently interpreting within options_to_interpret_, or
+    // nullptr if we're not in a call to InterpretOptions(). This points to a
+    // submessage of the original option, not the mutable copy. Therefore we
+    // can use it to find locations recorded by the parser.
+    const UninterpretedOption* uninterpreted_option_;
+
+    // This maps the element path of uninterpreted options to the element path
+    // of the resulting interpreted option. This is used to modify a file's
+    // source code info to account for option interpretation.
+    std::map<std::vector<int>, std::vector<int>> interpreted_paths_;
+
+    // This maps the path to a repeated option field to the known number of
+    // elements the field contains. This is used to track the compute the
+    // index portion of the element path when interpreting a single option.
+    std::map<std::vector<int>, int> repeated_option_counts_;
+
+    // Factory used to create the dynamic messages we need to parse
+    // any aggregate option values we encounter.
+    DynamicMessageFactory dynamic_factory_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OptionInterpreter);
+  };
+
+  // Work-around for broken compilers:  According to the C++ standard,
+  // OptionInterpreter should have access to the private members of any class
+  // which has declared DescriptorBuilder as a friend.  Unfortunately some old
+  // versions of GCC and other compilers do not implement this correctly.  So,
+  // we have to have these intermediate methods to provide access.  We also
+  // redundantly declare OptionInterpreter a friend just to make things extra
+  // clear for these bad compilers.
+  friend class OptionInterpreter;
+  friend class OptionInterpreter::AggregateOptionFinder;
+
+  static inline bool get_allow_unknown(const DescriptorPool* pool) {
+    return pool->allow_unknown_;
+  }
+  static inline bool get_enforce_weak(const DescriptorPool* pool) {
+    return pool->enforce_weak_;
+  }
+  static inline bool get_is_placeholder(const Descriptor* descriptor) {
+    return descriptor != nullptr && descriptor->is_placeholder_;
+  }
+  static inline void assert_mutex_held(const DescriptorPool* pool) {
+    if (pool->mutex_ != nullptr) {
+      pool->mutex_->AssertHeld();
+    }
+  }
+
+  // Must be run only after options have been interpreted.
+  //
+  // NOTE: Validation code must only reference the options in the mutable
+  // descriptors, which are the ones that have been interpreted. The const
+  // proto references are passed in only so they can be provided to calls to
+  // AddError(). Do not look at their options, which have not been interpreted.
+  void ValidateFileOptions(FileDescriptor* file,
+                           const FileDescriptorProto& proto);
+  void ValidateMessageOptions(Descriptor* message,
+                              const DescriptorProto& proto);
+  void ValidateFieldOptions(FieldDescriptor* field,
+                            const FieldDescriptorProto& proto);
+  void ValidateEnumOptions(EnumDescriptor* enm,
+                           const EnumDescriptorProto& proto);
+  void ValidateEnumValueOptions(EnumValueDescriptor* enum_value,
+                                const EnumValueDescriptorProto& proto);
+  void ValidateExtensionRangeOptions(
+      const std::string& full_name, Descriptor::ExtensionRange* extension_range,
+      const DescriptorProto_ExtensionRange& proto);
+  void ValidateServiceOptions(ServiceDescriptor* service,
+                              const ServiceDescriptorProto& proto);
+  void ValidateMethodOptions(MethodDescriptor* method,
+                             const MethodDescriptorProto& proto);
+  void ValidateProto3(FileDescriptor* file, const FileDescriptorProto& proto);
+  void ValidateProto3Message(Descriptor* message, const DescriptorProto& proto);
+  void ValidateProto3Field(FieldDescriptor* field,
+                           const FieldDescriptorProto& proto);
+  void ValidateProto3Enum(EnumDescriptor* enm,
+                          const EnumDescriptorProto& proto);
+
+  // Returns true if the map entry message is compatible with the
+  // auto-generated entry message from map fields syntax.
+  bool ValidateMapEntry(FieldDescriptor* field,
+                        const FieldDescriptorProto& proto);
+
+  // Recursively detects naming conflicts with map entry types for a
+  // better error message.
+  void DetectMapConflicts(const Descriptor* message,
+                          const DescriptorProto& proto);
+
+  void ValidateJSType(FieldDescriptor* field,
+                      const FieldDescriptorProto& proto);
+};
+
+const FileDescriptor* DescriptorPool::BuildFile(
+    const FileDescriptorProto& proto) {
+  GOOGLE_CHECK(fallback_database_ == nullptr)
+      << "Cannot call BuildFile on a DescriptorPool that uses a "
+         "DescriptorDatabase.  You must instead find a way to get your file "
+         "into the underlying database.";
+  GOOGLE_CHECK(mutex_ == nullptr);  // Implied by the above GOOGLE_CHECK.
+  tables_->known_bad_symbols_.clear();
+  tables_->known_bad_files_.clear();
+  return DescriptorBuilder(this, tables_.get(), nullptr).BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::BuildFileCollectingErrors(
+    const FileDescriptorProto& proto, ErrorCollector* error_collector) {
+  GOOGLE_CHECK(fallback_database_ == nullptr)
+      << "Cannot call BuildFile on a DescriptorPool that uses a "
+         "DescriptorDatabase.  You must instead find a way to get your file "
+         "into the underlying database.";
+  GOOGLE_CHECK(mutex_ == nullptr);  // Implied by the above GOOGLE_CHECK.
+  tables_->known_bad_symbols_.clear();
+  tables_->known_bad_files_.clear();
+  return DescriptorBuilder(this, tables_.get(), error_collector)
+      .BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::BuildFileFromDatabase(
+    const FileDescriptorProto& proto) const {
+  mutex_->AssertHeld();
+  if (tables_->known_bad_files_.count(proto.name()) > 0) {
+    return nullptr;
+  }
+  const FileDescriptor* result =
+      DescriptorBuilder(this, tables_.get(), default_error_collector_)
+          .BuildFile(proto);
+  if (result == nullptr) {
+    tables_->known_bad_files_.insert(proto.name());
+  }
+  return result;
+}
+
+DescriptorBuilder::DescriptorBuilder(
+    const DescriptorPool* pool, DescriptorPool::Tables* tables,
+    DescriptorPool::ErrorCollector* error_collector)
+    : pool_(pool),
+      tables_(tables),
+      error_collector_(error_collector),
+      had_errors_(false),
+      possible_undeclared_dependency_(nullptr),
+      undefine_resolved_name_("") {}
+
+DescriptorBuilder::~DescriptorBuilder() {}
+
+void DescriptorBuilder::AddError(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location,
+    const std::string& error) {
+  if (error_collector_ == nullptr) {
+    if (!had_errors_) {
+      GOOGLE_LOG(ERROR) << "Invalid proto descriptor for file \"" << filename_
+                 << "\":";
+    }
+    GOOGLE_LOG(ERROR) << "  " << element_name << ": " << error;
+  } else {
+    error_collector_->AddError(filename_, element_name, &descriptor, location,
+                               error);
+  }
+  had_errors_ = true;
+}
+
+void DescriptorBuilder::AddError(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location, const char* error) {
+  AddError(element_name, descriptor, location, std::string(error));
+}
+
+void DescriptorBuilder::AddNotDefinedError(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location,
+    const std::string& undefined_symbol) {
+  if (possible_undeclared_dependency_ == nullptr &&
+      undefine_resolved_name_.empty()) {
+    AddError(element_name, descriptor, location,
+             "\"" + undefined_symbol + "\" is not defined.");
+  } else {
+    if (possible_undeclared_dependency_ != nullptr) {
+      AddError(element_name, descriptor, location,
+               "\"" + possible_undeclared_dependency_name_ +
+                   "\" seems to be defined in \"" +
+                   possible_undeclared_dependency_->name() +
+                   "\", which is not "
+                   "imported by \"" +
+                   filename_ +
+                   "\".  To use it here, please "
+                   "add the necessary import.");
+    }
+    if (!undefine_resolved_name_.empty()) {
+      AddError(element_name, descriptor, location,
+               "\"" + undefined_symbol + "\" is resolved to \"" +
+                   undefine_resolved_name_ +
+                   "\", which is not defined. "
+                   "The innermost scope is searched first in name resolution. "
+                   "Consider using a leading '.'(i.e., \"." +
+                   undefined_symbol + "\") to start from the outermost scope.");
+    }
+  }
+}
+
+void DescriptorBuilder::AddWarning(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location,
+    const std::string& error) {
+  if (error_collector_ == nullptr) {
+    GOOGLE_LOG(WARNING) << filename_ << " " << element_name << ": " << error;
+  } else {
+    error_collector_->AddWarning(filename_, element_name, &descriptor, location,
+                                 error);
+  }
+}
+
+bool DescriptorBuilder::IsInPackage(const FileDescriptor* file,
+                                    const std::string& package_name) {
+  return HasPrefixString(file->package(), package_name) &&
+         (file->package().size() == package_name.size() ||
+          file->package()[package_name.size()] == '.');
+}
+
+void DescriptorBuilder::RecordPublicDependencies(const FileDescriptor* file) {
+  if (file == nullptr || !dependencies_.insert(file).second) return;
+  for (int i = 0; file != nullptr && i < file->public_dependency_count(); i++) {
+    RecordPublicDependencies(file->public_dependency(i));
+  }
+}
+
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDepsHelper(
+    const DescriptorPool* pool, const std::string& name, bool build_it) {
+  // If we are looking at an underlay, we must lock its mutex_, since we are
+  // accessing the underlay's tables_ directly.
+  MutexLockMaybe lock((pool == pool_) ? nullptr : pool->mutex_);
+
+  Symbol result = pool->tables_->FindSymbol(name);
+  if (result.IsNull() && pool->underlay_ != nullptr) {
+    // Symbol not found; check the underlay.
+    result = FindSymbolNotEnforcingDepsHelper(pool->underlay_, name);
+  }
+
+  if (result.IsNull()) {
+    // With lazily_build_dependencies_, a symbol lookup at cross link time is
+    // not guaranteed to be successful. In most cases, build_it will be false,
+    // which intentionally prevents us from building an import until it's
+    // actually needed. In some cases, like registering an extension, we want
+    // to build the file containing the symbol, and build_it will be set.
+    // Also, build_it will be true when !lazily_build_dependencies_, to provide
+    // better error reporting of missing dependencies.
+    if (build_it && pool->TryFindSymbolInFallbackDatabase(name)) {
+      result = pool->tables_->FindSymbol(name);
+    }
+  }
+
+  return result;
+}
+
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const std::string& name,
+                                                     bool build_it) {
+  Symbol result = FindSymbolNotEnforcingDepsHelper(pool_, name, build_it);
+  // Only find symbols which were defined in this file or one of its
+  // dependencies.
+  const FileDescriptor* file = result.GetFile();
+  if (file == file_ || dependencies_.count(file) > 0) {
+    unused_dependency_.erase(file);
+  }
+  return result;
+}
+
+Symbol DescriptorBuilder::FindSymbol(const std::string& name, bool build_it) {
+  Symbol result = FindSymbolNotEnforcingDeps(name, build_it);
+
+  if (result.IsNull()) return result;
+
+  if (!pool_->enforce_dependencies_) {
+    // Hack for CompilerUpgrader, and also used for lazily_build_dependencies_
+    return result;
+  }
+
+  // Only find symbols which were defined in this file or one of its
+  // dependencies.
+  const FileDescriptor* file = result.GetFile();
+  if (file == file_ || dependencies_.count(file) > 0) {
+    return result;
+  }
+
+  if (result.IsPackage()) {
+    // Arg, this is overcomplicated.  The symbol is a package name.  It could
+    // be that the package was defined in multiple files.  result.GetFile()
+    // returns the first file we saw that used this package.  We've determined
+    // that that file is not a direct dependency of the file we are currently
+    // building, but it could be that some other file which *is* a direct
+    // dependency also defines the same package.  We can't really rule out this
+    // symbol unless none of the dependencies define it.
+    if (IsInPackage(file_, name)) return result;
+    for (std::set<const FileDescriptor*>::const_iterator it =
+             dependencies_.begin();
+         it != dependencies_.end(); ++it) {
+      // Note:  A dependency may be nullptr if it was not found or had errors.
+      if (*it != nullptr && IsInPackage(*it, name)) return result;
+    }
+  }
+
+  possible_undeclared_dependency_ = file;
+  possible_undeclared_dependency_name_ = name;
+  return Symbol();
+}
+
+Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
+    const std::string& name, const std::string& relative_to,
+    ResolveMode resolve_mode, bool build_it) {
+  possible_undeclared_dependency_ = nullptr;
+  undefine_resolved_name_.clear();
+
+  if (!name.empty() && name[0] == '.') {
+    // Fully-qualified name.
+    return FindSymbol(name.substr(1), build_it);
+  }
+
+  // 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.
+  std::string::size_type name_dot_pos = name.find_first_of('.');
+  std::string first_part_of_name;
+  if (name_dot_pos == std::string::npos) {
+    first_part_of_name = name;
+  } else {
+    first_part_of_name = name.substr(0, name_dot_pos);
+  }
+
+  std::string scope_to_try(relative_to);
+
+  while (true) {
+    // Chop off the last component of the scope.
+    std::string::size_type dot_pos = scope_to_try.find_last_of('.');
+    if (dot_pos == std::string::npos) {
+      return FindSymbol(name, build_it);
+    } else {
+      scope_to_try.erase(dot_pos);
+    }
+
+    // Append ".first_part_of_name" and try to find.
+    std::string::size_type old_size = scope_to_try.size();
+    scope_to_try.append(1, '.');
+    scope_to_try.append(first_part_of_name);
+    Symbol result = FindSymbol(scope_to_try, build_it);
+    if (!result.IsNull()) {
+      if (first_part_of_name.size() < name.size()) {
+        // name is a compound symbol, of which we only found the first part.
+        // Now try to look up the rest of it.
+        if (result.IsAggregate()) {
+          scope_to_try.append(name, first_part_of_name.size(),
+                              name.size() - first_part_of_name.size());
+          result = FindSymbol(scope_to_try, build_it);
+          if (result.IsNull()) {
+            undefine_resolved_name_ = scope_to_try;
+          }
+          return result;
+        } else {
+          // We found a symbol but it's not an aggregate.  Continue the loop.
+        }
+      } else {
+        if (resolve_mode == LOOKUP_TYPES && !result.IsType()) {
+          // We found a symbol but it's not a type.  Continue the loop.
+        } else {
+          return result;
+        }
+      }
+    }
+
+    // Not found.  Remove the name so we can try again.
+    scope_to_try.erase(old_size);
+  }
+}
+
+Symbol DescriptorBuilder::LookupSymbol(
+    const std::string& name, const std::string& relative_to,
+    DescriptorPool::PlaceholderType placeholder_type, ResolveMode resolve_mode,
+    bool build_it) {
+  Symbol result =
+      LookupSymbolNoPlaceholder(name, relative_to, resolve_mode, build_it);
+  if (result.IsNull() && pool_->allow_unknown_) {
+    // Not found, but AllowUnknownDependencies() is enabled.  Return a
+    // placeholder instead.
+    result = pool_->NewPlaceholderWithMutexHeld(name, placeholder_type);
+  }
+  return result;
+}
+
+static bool ValidateQualifiedName(StringPiece name) {
+  bool last_was_period = false;
+
+  for (char character : name) {
+    // I don't trust isalnum() due to locales.  :(
+    if (('a' <= character && character <= 'z') ||
+        ('A' <= character && character <= 'Z') ||
+        ('0' <= character && character <= '9') || (character == '_')) {
+      last_was_period = false;
+    } else if (character == '.') {
+      if (last_was_period) return false;
+      last_was_period = true;
+    } else {
+      return false;
+    }
+  }
+
+  return !name.empty() && !last_was_period;
+}
+
+Symbol DescriptorPool::NewPlaceholder(StringPiece name,
+                                      PlaceholderType placeholder_type) const {
+  MutexLockMaybe lock(mutex_);
+  return NewPlaceholderWithMutexHeld(name, placeholder_type);
+}
+
+Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
+    StringPiece name, PlaceholderType placeholder_type) const {
+  if (mutex_) {
+    mutex_->AssertHeld();
+  }
+  // Compute names.
+  StringPiece placeholder_full_name;
+  StringPiece placeholder_name;
+  const std::string* placeholder_package;
+
+  if (!ValidateQualifiedName(name)) return Symbol();
+  if (name[0] == '.') {
+    // Fully-qualified.
+    placeholder_full_name = name.substr(1);
+  } else {
+    placeholder_full_name = name;
+  }
+
+  // Create the placeholders.
+  internal::FlatAllocator alloc;
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<std::string>(2);
+  if (placeholder_type == PLACEHOLDER_ENUM) {
+    alloc.PlanArray<EnumDescriptor>(1);
+    alloc.PlanArray<EnumValueDescriptor>(1);
+    alloc.PlanArray<std::string>(2);  // names for the descriptor.
+    alloc.PlanArray<std::string>(2);  // names for the value.
+  } else {
+    alloc.PlanArray<Descriptor>(1);
+    alloc.PlanArray<std::string>(2);  // names for the descriptor.
+    if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
+      alloc.PlanArray<Descriptor::ExtensionRange>(1);
+    }
+  }
+  alloc.FinalizePlanning(tables_);
+
+  const std::string::size_type dotpos = placeholder_full_name.find_last_of('.');
+  if (dotpos != std::string::npos) {
+    placeholder_package =
+        alloc.AllocateStrings(placeholder_full_name.substr(0, dotpos));
+    placeholder_name = placeholder_full_name.substr(dotpos + 1);
+  } else {
+    placeholder_package = alloc.AllocateStrings("");
+    placeholder_name = placeholder_full_name;
+  }
+
+  FileDescriptor* placeholder_file = NewPlaceholderFileWithMutexHeld(
+      StrCat(placeholder_full_name, ".placeholder.proto"), alloc);
+  placeholder_file->package_ = placeholder_package;
+
+  if (placeholder_type == PLACEHOLDER_ENUM) {
+    placeholder_file->enum_type_count_ = 1;
+    placeholder_file->enum_types_ = alloc.AllocateArray<EnumDescriptor>(1);
+
+    EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
+    memset(static_cast<void*>(placeholder_enum), 0, sizeof(*placeholder_enum));
+
+    placeholder_enum->all_names_ =
+        alloc.AllocateStrings(placeholder_name, placeholder_full_name);
+    placeholder_enum->file_ = placeholder_file;
+    placeholder_enum->options_ = &EnumOptions::default_instance();
+    placeholder_enum->is_placeholder_ = true;
+    placeholder_enum->is_unqualified_placeholder_ = (name[0] != '.');
+
+    // Enums must have at least one value.
+    placeholder_enum->value_count_ = 1;
+    placeholder_enum->values_ = alloc.AllocateArray<EnumValueDescriptor>(1);
+    // Disable fast-path lookup for this enum.
+    placeholder_enum->sequential_value_limit_ = -1;
+
+    EnumValueDescriptor* placeholder_value = &placeholder_enum->values_[0];
+    memset(static_cast<void*>(placeholder_value), 0,
+           sizeof(*placeholder_value));
+
+    // Note that enum value names are siblings of their type, not children.
+    placeholder_value->all_names_ = alloc.AllocateStrings(
+        "PLACEHOLDER_VALUE", placeholder_package->empty()
+                                 ? "PLACEHOLDER_VALUE"
+                                 : *placeholder_package + ".PLACEHOLDER_VALUE");
+
+    placeholder_value->number_ = 0;
+    placeholder_value->type_ = placeholder_enum;
+    placeholder_value->options_ = &EnumValueOptions::default_instance();
+
+    return Symbol(placeholder_enum);
+  } else {
+    placeholder_file->message_type_count_ = 1;
+    placeholder_file->message_types_ = alloc.AllocateArray<Descriptor>(1);
+
+    Descriptor* placeholder_message = &placeholder_file->message_types_[0];
+    memset(static_cast<void*>(placeholder_message), 0,
+           sizeof(*placeholder_message));
+
+    placeholder_message->all_names_ =
+        alloc.AllocateStrings(placeholder_name, placeholder_full_name);
+    placeholder_message->file_ = placeholder_file;
+    placeholder_message->options_ = &MessageOptions::default_instance();
+    placeholder_message->is_placeholder_ = true;
+    placeholder_message->is_unqualified_placeholder_ = (name[0] != '.');
+
+    if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
+      placeholder_message->extension_range_count_ = 1;
+      placeholder_message->extension_ranges_ =
+          alloc.AllocateArray<Descriptor::ExtensionRange>(1);
+      placeholder_message->extension_ranges_[0].start = 1;
+      // kMaxNumber + 1 because ExtensionRange::end is exclusive.
+      placeholder_message->extension_ranges_[0].end =
+          FieldDescriptor::kMaxNumber + 1;
+      placeholder_message->extension_ranges_[0].options_ = nullptr;
+    }
+
+    return Symbol(placeholder_message);
+  }
+}
+
+FileDescriptor* DescriptorPool::NewPlaceholderFile(
+    StringPiece name) const {
+  MutexLockMaybe lock(mutex_);
+  internal::FlatAllocator alloc;
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<std::string>(1);
+  alloc.FinalizePlanning(tables_);
+
+  return NewPlaceholderFileWithMutexHeld(name, alloc);
+}
+
+FileDescriptor* DescriptorPool::NewPlaceholderFileWithMutexHeld(
+    StringPiece name, internal::FlatAllocator& alloc) const {
+  if (mutex_) {
+    mutex_->AssertHeld();
+  }
+  FileDescriptor* placeholder = alloc.AllocateArray<FileDescriptor>(1);
+  memset(static_cast<void*>(placeholder), 0, sizeof(*placeholder));
+
+  placeholder->name_ = alloc.AllocateStrings(name);
+  placeholder->package_ = &internal::GetEmptyString();
+  placeholder->pool_ = this;
+  placeholder->options_ = &FileOptions::default_instance();
+  placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
+  placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
+  placeholder->is_placeholder_ = true;
+  placeholder->syntax_ = FileDescriptor::SYNTAX_UNKNOWN;
+  placeholder->finished_building_ = true;
+  // All other fields are zero or nullptr.
+
+  return placeholder;
+}
+
+bool DescriptorBuilder::AddSymbol(const std::string& full_name,
+                                  const void* parent, const std::string& name,
+                                  const Message& proto, Symbol symbol) {
+  // If the caller passed nullptr for the parent, the symbol is at file scope.
+  // Use its file as the parent instead.
+  if (parent == nullptr) parent = file_;
+
+  if (full_name.find('\0') != std::string::npos) {
+    AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + full_name + "\" contains null character.");
+    return false;
+  }
+  if (tables_->AddSymbol(full_name, symbol)) {
+    if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) {
+      // This is only possible if there was already an error adding something of
+      // the same name.
+      if (!had_errors_) {
+        GOOGLE_LOG(DFATAL) << "\"" << full_name
+                    << "\" not previously defined in "
+                       "symbols_by_name_, but was defined in "
+                       "symbols_by_parent_; this shouldn't be possible.";
+      }
+      return false;
+    }
+    return true;
+  } else {
+    const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile();
+    if (other_file == file_) {
+      std::string::size_type dot_pos = full_name.find_last_of('.');
+      if (dot_pos == std::string::npos) {
+        AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+                 "\"" + full_name + "\" is already defined.");
+      } else {
+        AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+                 "\"" + full_name.substr(dot_pos + 1) +
+                     "\" is already defined in \"" +
+                     full_name.substr(0, dot_pos) + "\".");
+      }
+    } else {
+      // Symbol seems to have been defined in a different file.
+      AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+               "\"" + full_name + "\" is already defined in file \"" +
+                   (other_file == nullptr ? "null" : other_file->name()) +
+                   "\".");
+    }
+    return false;
+  }
+}
+
+void DescriptorBuilder::AddPackage(const std::string& name,
+                                   const Message& proto, FileDescriptor* file) {
+  if (name.find('\0') != std::string::npos) {
+    AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + name + "\" contains null character.");
+    return;
+  }
+
+  Symbol existing_symbol = tables_->FindSymbol(name);
+  // It's OK to redefine a package.
+  if (existing_symbol.IsNull()) {
+    if (&name == &file->package()) {
+      // It is the toplevel package name, so insert the descriptor directly.
+      tables_->AddSymbol(file->package(), Symbol(file));
+    } else {
+      auto* package = tables_->Allocate<Symbol::Subpackage>();
+      // If the name is the package name, then it is already in the arena.
+      // If not, copy it there. It came from the call to AddPackage below.
+      package->name_size = static_cast<int>(name.size());
+      package->file = file;
+      tables_->AddSymbol(name, Symbol(package));
+    }
+    // Also add parent package, if any.
+    std::string::size_type dot_pos = name.find_last_of('.');
+    if (dot_pos == std::string::npos) {
+      // No parents.
+      ValidateSymbolName(name, name, proto);
+    } else {
+      // Has parent.
+      AddPackage(name.substr(0, dot_pos), proto, file);
+      ValidateSymbolName(name.substr(dot_pos + 1), name, proto);
+    }
+  } else if (!existing_symbol.IsPackage()) {
+    // Symbol seems to have been defined in a different file.
+    const FileDescriptor* other_file = existing_symbol.GetFile();
+    AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + name +
+                 "\" is already defined (as something other than "
+                 "a package) in file \"" +
+                 (other_file == nullptr ? "null" : other_file->name()) + "\".");
+  }
+}
+
+void DescriptorBuilder::ValidateSymbolName(const std::string& name,
+                                           const std::string& full_name,
+                                           const Message& proto) {
+  if (name.empty()) {
+    AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+             "Missing name.");
+  } else {
+    for (char character : name) {
+      // I don't trust isalnum() due to locales.  :(
+      if ((character < 'a' || 'z' < character) &&
+          (character < 'A' || 'Z' < character) &&
+          (character < '0' || '9' < character) && (character != '_')) {
+        AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+                 "\"" + name + "\" is not a valid identifier.");
+        return;
+      }
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+
+// This generic implementation is good for all descriptors except
+// FileDescriptor.
+template <class DescriptorT>
+void DescriptorBuilder::AllocateOptions(
+    const typename DescriptorT::OptionsType& orig_options,
+    DescriptorT* descriptor, int options_field_tag,
+    const std::string& option_name, internal::FlatAllocator& alloc) {
+  std::vector<int> options_path;
+  descriptor->GetLocationPath(&options_path);
+  options_path.push_back(options_field_tag);
+  AllocateOptionsImpl(descriptor->full_name(), descriptor->full_name(),
+                      orig_options, descriptor, options_path, option_name,
+                      alloc);
+}
+
+// We specialize for FileDescriptor.
+void DescriptorBuilder::AllocateOptions(const FileOptions& orig_options,
+                                        FileDescriptor* descriptor,
+                                        internal::FlatAllocator& alloc) {
+  std::vector<int> options_path;
+  options_path.push_back(FileDescriptorProto::kOptionsFieldNumber);
+  // We add the dummy token so that LookupSymbol does the right thing.
+  AllocateOptionsImpl(descriptor->package() + ".dummy", descriptor->name(),
+                      orig_options, descriptor, options_path,
+                      "google.protobuf.FileOptions", alloc);
+}
+
+template <class DescriptorT>
+void DescriptorBuilder::AllocateOptionsImpl(
+    const std::string& name_scope, const std::string& element_name,
+    const typename DescriptorT::OptionsType& orig_options,
+    DescriptorT* descriptor, const std::vector<int>& options_path,
+    const std::string& option_name, internal::FlatAllocator& alloc) {
+  auto* options = alloc.AllocateArray<typename DescriptorT::OptionsType>(1);
+
+  if (!orig_options.IsInitialized()) {
+    AddError(name_scope + "." + element_name, orig_options,
+             DescriptorPool::ErrorCollector::OPTION_NAME,
+             "Uninterpreted option is missing name or value.");
+    return;
+  }
+
+  // Avoid using MergeFrom()/CopyFrom() in this class to make it -fno-rtti
+  // friendly. Without RTTI, MergeFrom() and CopyFrom() will fallback to the
+  // reflection based method, which requires the Descriptor. However, we are in
+  // the middle of building the descriptors, thus the deadlock.
+  options->ParseFromString(orig_options.SerializeAsString());
+  descriptor->options_ = options;
+
+  // Don't add to options_to_interpret_ unless there were uninterpreted
+  // options.  This not only avoids unnecessary work, but prevents a
+  // bootstrapping problem when building descriptors for descriptor.proto.
+  // descriptor.proto does not contain any uninterpreted options, but
+  // attempting to interpret options anyway will cause
+  // OptionsType::GetDescriptor() to be called which may then deadlock since
+  // we're still trying to build it.
+  if (options->uninterpreted_option_size() > 0) {
+    options_to_interpret_.push_back(OptionsToInterpret(
+        name_scope, element_name, options_path, &orig_options, options));
+  }
+
+  // If the custom option is in unknown fields, no need to interpret it.
+  // Remove the dependency file from unused_dependency.
+  const UnknownFieldSet& unknown_fields = orig_options.unknown_fields();
+  if (!unknown_fields.empty()) {
+    // Can not use options->GetDescriptor() which may case deadlock.
+    Symbol msg_symbol = tables_->FindSymbol(option_name);
+    if (msg_symbol.type() == Symbol::MESSAGE) {
+      for (int i = 0; i < unknown_fields.field_count(); ++i) {
+        assert_mutex_held(pool_);
+        const FieldDescriptor* field =
+            pool_->InternalFindExtensionByNumberNoLock(
+                msg_symbol.descriptor(), unknown_fields.field(i).number());
+        if (field) {
+          unused_dependency_.erase(field->file());
+        }
+      }
+    }
+  }
+}
+
+// A common pattern:  We want to convert a repeated field in the descriptor
+// to an array of values, calling some method to build each value.
+#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT)               \
+  OUTPUT->NAME##_count_ = INPUT.NAME##_size();                         \
+  OUTPUT->NAME##s_ = alloc.AllocateArray<                              \
+      typename std::remove_pointer<decltype(OUTPUT->NAME##s_)>::type>( \
+      INPUT.NAME##_size());                                            \
+  for (int i = 0; i < INPUT.NAME##_size(); i++) {                      \
+    METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc);        \
+  }
+
+void DescriptorBuilder::AddRecursiveImportError(
+    const FileDescriptorProto& proto, int from_here) {
+  std::string error_message("File recursively imports itself: ");
+  for (size_t i = from_here; i < tables_->pending_files_.size(); i++) {
+    error_message.append(tables_->pending_files_[i]);
+    error_message.append(" -> ");
+  }
+  error_message.append(proto.name());
+
+  if (static_cast<size_t>(from_here) < tables_->pending_files_.size() - 1) {
+    AddError(tables_->pending_files_[from_here + 1], proto,
+             DescriptorPool::ErrorCollector::IMPORT, error_message);
+  } else {
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::IMPORT,
+             error_message);
+  }
+}
+
+void DescriptorBuilder::AddTwiceListedError(const FileDescriptorProto& proto,
+                                            int index) {
+  AddError(proto.dependency(index), proto,
+           DescriptorPool::ErrorCollector::IMPORT,
+           "Import \"" + proto.dependency(index) + "\" was listed twice.");
+}
+
+void DescriptorBuilder::AddImportError(const FileDescriptorProto& proto,
+                                       int index) {
+  std::string message;
+  if (pool_->fallback_database_ == nullptr) {
+    message = "Import \"" + proto.dependency(index) + "\" has not been loaded.";
+  } else {
+    message = "Import \"" + proto.dependency(index) +
+              "\" was not found or had errors.";
+  }
+  AddError(proto.dependency(index), proto,
+           DescriptorPool::ErrorCollector::IMPORT, message);
+}
+
+static bool ExistingFileMatchesProto(const FileDescriptor* existing_file,
+                                     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();
+}
+
+// These PlanAllocationSize functions will gather into the FlatAllocator all the
+// necessary memory allocations that BuildXXX functions below will do on the
+// Tables object.
+// They *must* be kept in sync. If we miss some PlanArray call we won't have
+// enough memory and will GOOGLE_CHECK-fail.
+static void PlanAllocationSize(
+    const RepeatedPtrField<EnumValueDescriptorProto>& values,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<EnumValueDescriptor>(values.size());
+  alloc.PlanArray<std::string>(2 * values.size());  // name + full_name
+  for (const auto& v : values) {
+    if (v.has_options()) alloc.PlanArray<EnumValueOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<EnumDescriptorProto>& enums,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<EnumDescriptor>(enums.size());
+  alloc.PlanArray<std::string>(2 * enums.size());  // name + full_name
+  for (const auto& e : enums) {
+    if (e.has_options()) alloc.PlanArray<EnumOptions>(1);
+    PlanAllocationSize(e.value(), alloc);
+    alloc.PlanArray<EnumDescriptor::ReservedRange>(e.reserved_range_size());
+    alloc.PlanArray<const std::string*>(e.reserved_name_size());
+    alloc.PlanArray<std::string>(e.reserved_name_size());
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<OneofDescriptorProto>& oneofs,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<OneofDescriptor>(oneofs.size());
+  alloc.PlanArray<std::string>(2 * oneofs.size());  // name + full_name
+  for (const auto& oneof : oneofs) {
+    if (oneof.has_options()) alloc.PlanArray<OneofOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<FieldDescriptorProto>& fields,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<FieldDescriptor>(fields.size());
+  for (const auto& field : fields) {
+    if (field.has_options()) alloc.PlanArray<FieldOptions>(1);
+    alloc.PlanFieldNames(field.name(),
+                         field.has_json_name() ? &field.json_name() : nullptr);
+    if (field.has_default_value() && field.has_type() &&
+        (field.type() == FieldDescriptorProto::TYPE_STRING ||
+         field.type() == FieldDescriptorProto::TYPE_BYTES)) {
+      // For the default string value.
+      alloc.PlanArray<std::string>(1);
+    }
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<DescriptorProto::ExtensionRange>& ranges,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<Descriptor::ExtensionRange>(ranges.size());
+  for (const auto& r : ranges) {
+    if (r.has_options()) alloc.PlanArray<ExtensionRangeOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<DescriptorProto>& messages,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<Descriptor>(messages.size());
+  alloc.PlanArray<std::string>(2 * messages.size());  // name + full_name
+
+  for (const auto& message : messages) {
+    if (message.has_options()) alloc.PlanArray<MessageOptions>(1);
+    PlanAllocationSize(message.nested_type(), alloc);
+    PlanAllocationSize(message.field(), alloc);
+    PlanAllocationSize(message.extension(), alloc);
+    PlanAllocationSize(message.extension_range(), alloc);
+    alloc.PlanArray<Descriptor::ReservedRange>(message.reserved_range_size());
+    alloc.PlanArray<const std::string*>(message.reserved_name_size());
+    alloc.PlanArray<std::string>(message.reserved_name_size());
+    PlanAllocationSize(message.enum_type(), alloc);
+    PlanAllocationSize(message.oneof_decl(), alloc);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<MethodDescriptorProto>& methods,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<MethodDescriptor>(methods.size());
+  alloc.PlanArray<std::string>(2 * methods.size());  // name + full_name
+  for (const auto& m : methods) {
+    if (m.has_options()) alloc.PlanArray<MethodOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<ServiceDescriptorProto>& services,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<ServiceDescriptor>(services.size());
+  alloc.PlanArray<std::string>(2 * services.size());  // name + full_name
+  for (const auto& service : services) {
+    if (service.has_options()) alloc.PlanArray<ServiceOptions>(1);
+    PlanAllocationSize(service.method(), alloc);
+  }
+}
+
+static void PlanAllocationSize(const FileDescriptorProto& proto,
+                               internal::FlatAllocator& alloc) {
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<FileDescriptorTables>(1);
+  alloc.PlanArray<std::string>(2);  // name + package
+  if (proto.has_options()) alloc.PlanArray<FileOptions>(1);
+  if (proto.has_source_code_info()) alloc.PlanArray<SourceCodeInfo>(1);
+
+  PlanAllocationSize(proto.service(), alloc);
+  PlanAllocationSize(proto.message_type(), alloc);
+  PlanAllocationSize(proto.enum_type(), alloc);
+  PlanAllocationSize(proto.extension(), alloc);
+
+  alloc.PlanArray<int>(proto.weak_dependency_size());
+  alloc.PlanArray<int>(proto.public_dependency_size());
+  alloc.PlanArray<const FileDescriptor*>(proto.dependency_size());
+}
+
+const FileDescriptor* DescriptorBuilder::BuildFile(
+    const FileDescriptorProto& proto) {
+  filename_ = proto.name();
+
+  // Check if the file already exists and is identical to the one being built.
+  // Note:  This only works if the input is canonical -- that is, it
+  //   fully-qualifies all type names, has no UninterpretedOptions, etc.
+  //   This is fine, because this idempotency "feature" really only exists to
+  //   accommodate one hack in the proto1->proto2 migration layer.
+  const FileDescriptor* existing_file = tables_->FindFile(filename_);
+  if (existing_file != nullptr) {
+    // File already in pool.  Compare the existing one to the input.
+    if (ExistingFileMatchesProto(existing_file, proto)) {
+      // They're identical.  Return the existing descriptor.
+      return existing_file;
+    }
+
+    // Not a match.  The error will be detected and handled later.
+  }
+
+  // Check to see if this file is already on the pending files list.
+  // TODO(kenton):  Allow recursive imports?  It may not work with some
+  //   (most?) programming languages.  E.g., in C++, a forward declaration
+  //   of a type is not sufficient to allow it to be used even in a
+  //   generated header file due to inlining.  This could perhaps be
+  //   worked around using tricks involving inserting #include statements
+  //   mid-file, but that's pretty ugly, and I'm pretty sure there are
+  //   some languages out there that do not allow recursive dependencies
+  //   at all.
+  for (size_t i = 0; i < tables_->pending_files_.size(); i++) {
+    if (tables_->pending_files_[i] == proto.name()) {
+      AddRecursiveImportError(proto, i);
+      return nullptr;
+    }
+  }
+
+  static const int kMaximumPackageLength = 511;
+  if (proto.package().size() > kMaximumPackageLength) {
+    AddError(proto.package(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Package name is too long");
+    return nullptr;
+  }
+
+  // If we have a fallback_database_, and we aren't doing lazy import building,
+  // attempt to load all dependencies now, before checkpointing tables_.  This
+  // avoids confusion with recursive checkpoints.
+  if (!pool_->lazily_build_dependencies_) {
+    if (pool_->fallback_database_ != nullptr) {
+      tables_->pending_files_.push_back(proto.name());
+      for (int i = 0; i < proto.dependency_size(); i++) {
+        if (tables_->FindFile(proto.dependency(i)) == nullptr &&
+            (pool_->underlay_ == nullptr ||
+             pool_->underlay_->FindFileByName(proto.dependency(i)) ==
+                 nullptr)) {
+          // We don't care what this returns since we'll find out below anyway.
+          pool_->TryFindFileInFallbackDatabase(proto.dependency(i));
+        }
+      }
+      tables_->pending_files_.pop_back();
+    }
+  }
+
+  // Checkpoint the tables so that we can roll back if something goes wrong.
+  tables_->AddCheckpoint();
+
+  internal::FlatAllocator alloc;
+  PlanAllocationSize(proto, alloc);
+  alloc.FinalizePlanning(tables_);
+  FileDescriptor* result = BuildFileImpl(proto, alloc);
+
+  file_tables_->FinalizeTables();
+  if (result) {
+    tables_->ClearLastCheckpoint();
+    result->finished_building_ = true;
+    alloc.ExpectConsumed();
+  } else {
+    tables_->RollbackToLastCheckpoint();
+  }
+
+  return result;
+}
+
+FileDescriptor* DescriptorBuilder::BuildFileImpl(
+    const FileDescriptorProto& proto, internal::FlatAllocator& alloc) {
+  FileDescriptor* result = alloc.AllocateArray<FileDescriptor>(1);
+  file_ = result;
+
+  result->is_placeholder_ = false;
+  result->finished_building_ = false;
+  SourceCodeInfo* info = nullptr;
+  if (proto.has_source_code_info()) {
+    info = alloc.AllocateArray<SourceCodeInfo>(1);
+    info->CopyFrom(proto.source_code_info());
+    result->source_code_info_ = info;
+  } else {
+    result->source_code_info_ = &SourceCodeInfo::default_instance();
+  }
+
+  file_tables_ = alloc.AllocateArray<FileDescriptorTables>(1);
+  file_->tables_ = file_tables_;
+
+  if (!proto.has_name()) {
+    AddError("", proto, DescriptorPool::ErrorCollector::OTHER,
+             "Missing field: FileDescriptorProto.name.");
+  }
+
+  // TODO(liujisi): Report error when the syntax is empty after all the protos
+  // have added the syntax statement.
+  if (proto.syntax().empty() || proto.syntax() == "proto2") {
+    file_->syntax_ = FileDescriptor::SYNTAX_PROTO2;
+  } else if (proto.syntax() == "proto3") {
+    file_->syntax_ = FileDescriptor::SYNTAX_PROTO3;
+  } else {
+    file_->syntax_ = FileDescriptor::SYNTAX_UNKNOWN;
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "Unrecognized syntax: " + proto.syntax());
+  }
+
+  result->name_ = alloc.AllocateStrings(proto.name());
+  if (proto.has_package()) {
+    result->package_ = alloc.AllocateStrings(proto.package());
+  } else {
+    // We cannot rely on proto.package() returning a valid string if
+    // proto.has_package() is false, because we might be running at static
+    // initialization time, in which case default values have not yet been
+    // initialized.
+    result->package_ = alloc.AllocateStrings("");
+  }
+  result->pool_ = pool_;
+
+  if (result->name().find('\0') != std::string::npos) {
+    AddError(result->name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + result->name() + "\" contains null character.");
+    return nullptr;
+  }
+
+  // Add to tables.
+  if (!tables_->AddFile(result)) {
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "A file with this name is already in the pool.");
+    // Bail out early so that if this is actually the exact same file, we
+    // don't end up reporting that every single symbol is already defined.
+    return nullptr;
+  }
+  if (!result->package().empty()) {
+    if (std::count(result->package().begin(), result->package().end(), '.') >
+        kPackageLimit) {
+      AddError(result->package(), proto, DescriptorPool::ErrorCollector::NAME,
+               "Exceeds Maximum Package Depth");
+      return nullptr;
+    }
+    AddPackage(result->package(), proto, result);
+  }
+
+  // Make sure all dependencies are loaded.
+  std::set<std::string> seen_dependencies;
+  result->dependency_count_ = proto.dependency_size();
+  result->dependencies_ =
+      alloc.AllocateArray<const FileDescriptor*>(proto.dependency_size());
+  result->dependencies_once_ = nullptr;
+  unused_dependency_.clear();
+  std::set<int> weak_deps;
+  for (int i = 0; i < proto.weak_dependency_size(); ++i) {
+    weak_deps.insert(proto.weak_dependency(i));
+  }
+
+  bool need_lazy_deps = false;
+  for (int i = 0; i < proto.dependency_size(); i++) {
+    if (!seen_dependencies.insert(proto.dependency(i)).second) {
+      AddTwiceListedError(proto, i);
+    }
+
+    const FileDescriptor* dependency = tables_->FindFile(proto.dependency(i));
+    if (dependency == nullptr && pool_->underlay_ != nullptr) {
+      dependency = pool_->underlay_->FindFileByName(proto.dependency(i));
+    }
+
+    if (dependency == result) {
+      // Recursive import.  dependency/result is not fully initialized, and it's
+      // dangerous to try to do anything with it.  The recursive import error
+      // will be detected and reported in DescriptorBuilder::BuildFile().
+      return nullptr;
+    }
+
+    if (dependency == nullptr) {
+      if (!pool_->lazily_build_dependencies_) {
+        if (pool_->allow_unknown_ ||
+            (!pool_->enforce_weak_ && weak_deps.find(i) != weak_deps.end())) {
+          internal::FlatAllocator lazy_dep_alloc;
+          lazy_dep_alloc.PlanArray<FileDescriptor>(1);
+          lazy_dep_alloc.PlanArray<std::string>(1);
+          lazy_dep_alloc.FinalizePlanning(tables_);
+          dependency = pool_->NewPlaceholderFileWithMutexHeld(
+              proto.dependency(i), lazy_dep_alloc);
+        } else {
+          AddImportError(proto, i);
+        }
+      }
+    } else {
+      // Add to unused_dependency_ to track unused imported files.
+      // Note: do not track unused imported files for public import.
+      if (pool_->enforce_dependencies_ &&
+          (pool_->unused_import_track_files_.find(proto.name()) !=
+           pool_->unused_import_track_files_.end()) &&
+          (dependency->public_dependency_count() == 0)) {
+        unused_dependency_.insert(dependency);
+      }
+    }
+
+    result->dependencies_[i] = dependency;
+    if (pool_->lazily_build_dependencies_ && !dependency) {
+      need_lazy_deps = true;
+    }
+  }
+  if (need_lazy_deps) {
+    int total_char_size = 0;
+    for (int i = 0; i < proto.dependency_size(); i++) {
+      if (result->dependencies_[i] == nullptr) {
+        total_char_size += static_cast<int>(proto.dependency(i).size());
+      }
+      ++total_char_size;  // For NUL char
+    }
+
+    void* data = tables_->AllocateBytes(
+        static_cast<int>(sizeof(internal::once_flag) + total_char_size));
+    result->dependencies_once_ = ::new (data) internal::once_flag{};
+    char* name_data = reinterpret_cast<char*>(result->dependencies_once_ + 1);
+
+    for (int i = 0; i < proto.dependency_size(); i++) {
+      if (result->dependencies_[i] == nullptr) {
+        memcpy(name_data, proto.dependency(i).c_str(),
+               proto.dependency(i).size());
+        name_data += proto.dependency(i).size();
+      }
+      *name_data++ = '\0';
+    }
+  }
+
+  // Check public dependencies.
+  int public_dependency_count = 0;
+  result->public_dependencies_ =
+      alloc.AllocateArray<int>(proto.public_dependency_size());
+  for (int i = 0; i < proto.public_dependency_size(); i++) {
+    // Only put valid public dependency indexes.
+    int index = proto.public_dependency(i);
+    if (index >= 0 && index < proto.dependency_size()) {
+      result->public_dependencies_[public_dependency_count++] = index;
+      // Do not track unused imported files for public import.
+      // Calling dependency(i) builds that file when doing lazy imports,
+      // need to avoid doing this. Unused dependency detection isn't done
+      // when building lazily, anyways.
+      if (!pool_->lazily_build_dependencies_) {
+        unused_dependency_.erase(result->dependency(index));
+      }
+    } else {
+      AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+               "Invalid public dependency index.");
+    }
+  }
+  result->public_dependency_count_ = public_dependency_count;
+
+  // Build dependency set
+  dependencies_.clear();
+  // We don't/can't do proper dependency error checking when
+  // lazily_build_dependencies_, and calling dependency(i) will force
+  // a dependency to be built, which we don't want.
+  if (!pool_->lazily_build_dependencies_) {
+    for (int i = 0; i < result->dependency_count(); i++) {
+      RecordPublicDependencies(result->dependency(i));
+    }
+  }
+
+  // Check weak dependencies.
+  int weak_dependency_count = 0;
+  result->weak_dependencies_ =
+      alloc.AllocateArray<int>(proto.weak_dependency_size());
+  for (int i = 0; i < proto.weak_dependency_size(); i++) {
+    int index = proto.weak_dependency(i);
+    if (index >= 0 && index < proto.dependency_size()) {
+      result->weak_dependencies_[weak_dependency_count++] = index;
+    } else {
+      AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+               "Invalid weak dependency index.");
+    }
+  }
+  result->weak_dependency_count_ = weak_dependency_count;
+
+  // Convert children.
+  BUILD_ARRAY(proto, result, message_type, BuildMessage, nullptr);
+  BUILD_ARRAY(proto, result, enum_type, BuildEnum, nullptr);
+  BUILD_ARRAY(proto, result, service, BuildService, nullptr);
+  BUILD_ARRAY(proto, result, extension, BuildExtension, nullptr);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result, alloc);
+  }
+
+  // Note that the following steps must occur in exactly the specified order.
+
+  // Cross-link.
+  CrossLinkFile(result, proto);
+
+  if (!message_hints_.empty()) {
+    SuggestFieldNumbers(result, proto);
+  }
+
+  // Interpret any remaining uninterpreted options gathered into
+  // options_to_interpret_ during descriptor building.  Cross-linking has made
+  // extension options known, so all interpretations should now succeed.
+  if (!had_errors_) {
+    OptionInterpreter option_interpreter(this);
+    for (std::vector<OptionsToInterpret>::iterator iter =
+             options_to_interpret_.begin();
+         iter != options_to_interpret_.end(); ++iter) {
+      option_interpreter.InterpretOptions(&(*iter));
+    }
+    options_to_interpret_.clear();
+    if (info != nullptr) {
+      option_interpreter.UpdateSourceCodeInfo(info);
+    }
+  }
+
+  // Validate options. See comments at InternalSetLazilyBuildDependencies about
+  // error checking and lazy import building.
+  if (!had_errors_ && !pool_->lazily_build_dependencies_) {
+    ValidateFileOptions(result, proto);
+  }
+
+  // Additional naming conflict check for map entry types. Only need to check
+  // this if there are already errors.
+  if (had_errors_) {
+    for (int i = 0; i < proto.message_type_size(); ++i) {
+      DetectMapConflicts(result->message_type(i), proto.message_type(i));
+    }
+  }
+
+
+  // Again, see comments at InternalSetLazilyBuildDependencies about error
+  // checking. Also, don't log unused dependencies if there were previous
+  // errors, since the results might be inaccurate.
+  if (!had_errors_ && !unused_dependency_.empty() &&
+      !pool_->lazily_build_dependencies_) {
+    LogUnusedDependency(proto, result);
+  }
+
+  if (had_errors_) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+
+const std::string* DescriptorBuilder::AllocateNameStrings(
+    const std::string& scope, const std::string& proto_name,
+    internal::FlatAllocator& alloc) {
+  if (scope.empty()) {
+    return alloc.AllocateStrings(proto_name, proto_name);
+  } else {
+    return alloc.AllocateStrings(proto_name,
+                                 StrCat(scope, ".", proto_name));
+  }
+}
+
+namespace {
+
+// Helper for BuildMessage below.
+struct IncrementWhenDestroyed {
+  ~IncrementWhenDestroyed() { ++to_increment; }
+  int& to_increment;
+};
+
+}  // namespace
+
+void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
+                                     const Descriptor* parent,
+                                     Descriptor* result,
+                                     internal::FlatAllocator& alloc) {
+  const std::string& scope =
+      (parent == nullptr) ? file_->package() : parent->full_name();
+  result->all_names_ = AllocateNameStrings(scope, proto.name(), alloc);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  result->file_ = file_;
+  result->containing_type_ = parent;
+  result->is_placeholder_ = false;
+  result->is_unqualified_placeholder_ = false;
+  result->well_known_type_ = Descriptor::WELLKNOWNTYPE_UNSPECIFIED;
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+
+  auto it = pool_->tables_->well_known_types_.find(result->full_name());
+  if (it != pool_->tables_->well_known_types_.end()) {
+    result->well_known_type_ = it->second;
+  }
+
+  // Calculate the continuous sequence of fields.
+  // These can be fast-path'd during lookup and don't need to be added to the
+  // tables.
+  // We use uint16_t to save space for sequential_field_limit_, so stop before
+  // overflowing it. Worst case, we are not taking full advantage on huge
+  // messages, but it is unlikely.
+  result->sequential_field_limit_ = 0;
+  for (int i = 0; i < std::numeric_limits<uint16_t>::max() &&
+                  i < proto.field_size() && proto.field(i).number() == i + 1;
+       ++i) {
+    result->sequential_field_limit_ = i + 1;
+  }
+
+  // Build oneofs first so that fields and extension ranges can refer to them.
+  BUILD_ARRAY(proto, result, oneof_decl, BuildOneof, result);
+  BUILD_ARRAY(proto, result, field, BuildField, result);
+  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);
+
+  // Before building submessages, check recursion limit.
+  --recursion_depth_;
+  IncrementWhenDestroyed revert{recursion_depth_};
+  if (recursion_depth_ <= 0) {
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "Reached maximum recursion limit for nested messages.");
+    result->nested_types_ = nullptr;
+    result->nested_type_count_ = 0;
+    return;
+  }
+  BUILD_ARRAY(proto, result, nested_type, BuildMessage, result);
+
+  // Copy reserved names.
+  int reserved_name_count = proto.reserved_name_size();
+  result->reserved_name_count_ = reserved_name_count;
+  result->reserved_names_ =
+      alloc.AllocateArray<const std::string*>(reserved_name_count);
+  for (int i = 0; i < reserved_name_count; ++i) {
+    result->reserved_names_[i] =
+        alloc.AllocateStrings(proto.reserved_name(i));
+  }
+
+  // Copy options.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    DescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.MessageOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+
+  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<std::string> reserved_name_set;
+  for (int i = 0; i < proto.reserved_name_size(); i++) {
+    const std::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++) {
+      const Descriptor::ExtensionRange* range = result->extension_range(j);
+      if (range->start <= field->number() && field->number() < range->end) {
+        message_hints_[result].RequestHintOnFieldNumbers(
+            proto.extension_range(j), DescriptorPool::ErrorCollector::NUMBER);
+        AddError(
+            field->full_name(), proto.extension_range(j),
+            DescriptorPool::ErrorCollector::NUMBER,
+            strings::Substitute(
+                "Extension range $0 to $1 includes field \"$2\" ($3).",
+                range->start, range->end - 1, 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) {
+        message_hints_[result].RequestHintOnFieldNumbers(
+            proto.reserved_range(j), DescriptorPool::ErrorCollector::NUMBER);
+        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 and don't include
+  // reserved field numbers or names.
+  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(i),
+                 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) {
+        AddError(result->full_name(), proto.extension_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Extension range $0 to $1 overlaps with "
+                                  "already-defined range $2 to $3.",
+                                  range2->start, range2->end - 1, range1->start,
+                                  range1->end - 1));
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
+                                              Descriptor* parent,
+                                              FieldDescriptor* result,
+                                              bool is_extension,
+                                              internal::FlatAllocator& alloc) {
+  const std::string& scope =
+      (parent == nullptr) ? file_->package() : parent->full_name();
+
+  // We allocate all names in a single array, and dedup them.
+  // We remember the indices for the potentially deduped values.
+  auto all_names = alloc.AllocateFieldNames(
+      proto.name(), scope,
+      proto.has_json_name() ? &proto.json_name() : nullptr);
+  result->all_names_ = all_names.array;
+  result->lowercase_name_index_ = all_names.lowercase_index;
+  result->camelcase_name_index_ = all_names.camelcase_index;
+  result->json_name_index_ = all_names.json_index;
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  result->file_ = file_;
+  result->number_ = proto.number();
+  result->is_extension_ = is_extension;
+  result->is_oneof_ = false;
+  result->proto3_optional_ = proto.proto3_optional();
+
+  if (proto.proto3_optional() &&
+      file_->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "The [proto3_optional=true] option may only be set on proto3"
+             "fields, not " +
+                 result->full_name());
+  }
+
+  result->has_json_name_ = proto.has_json_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>(
+      implicit_cast<int>(proto.type()));
+  result->label_ = static_cast<FieldDescriptor::Label>(
+      implicit_cast<int>(proto.label()));
+
+  if (result->label_ == FieldDescriptor::LABEL_REQUIRED) {
+    // An extension cannot have a required field (b/13365836).
+    if (result->is_extension_) {
+      AddError(result->full_name(), proto,
+               // Error location `TYPE`: we would really like to indicate
+               // `LABEL`, but the `ErrorLocation` enum has no entry for this,
+               // and we don't necessarily know about all implementations of the
+               // `ErrorCollector` interface to extend them to handle the new
+               // error location type properly.
+               DescriptorPool::ErrorCollector::TYPE,
+               "The extension " + result->full_name() + " cannot be required.");
+    }
+  }
+
+  // Some of these may be filled in when cross-linking.
+  result->containing_type_ = nullptr;
+  result->type_once_ = nullptr;
+  result->default_value_enum_ = nullptr;
+
+  result->has_default_value_ = proto.has_default_value();
+  if (proto.has_default_value() && result->is_repeated()) {
+    AddError(result->full_name(), proto,
+             DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+             "Repeated fields can't have default values.");
+  }
+
+  if (proto.has_type()) {
+    if (proto.has_default_value()) {
+      char* end_pos = nullptr;
+      switch (result->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+          result->default_value_int32_t_ =
+              strtol(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_INT64:
+          result->default_value_int64_t_ =
+              strto64(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_UINT32:
+          result->default_value_uint32_t_ =
+              strtoul(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_UINT64:
+          result->default_value_uint64_t_ =
+              strtou64(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_FLOAT:
+          if (proto.default_value() == "inf") {
+            result->default_value_float_ =
+                std::numeric_limits<float>::infinity();
+          } else if (proto.default_value() == "-inf") {
+            result->default_value_float_ =
+                -std::numeric_limits<float>::infinity();
+          } else if (proto.default_value() == "nan") {
+            result->default_value_float_ =
+                std::numeric_limits<float>::quiet_NaN();
+          } else {
+            result->default_value_float_ = io::SafeDoubleToFloat(
+                io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos));
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          if (proto.default_value() == "inf") {
+            result->default_value_double_ =
+                std::numeric_limits<double>::infinity();
+          } else if (proto.default_value() == "-inf") {
+            result->default_value_double_ =
+                -std::numeric_limits<double>::infinity();
+          } else if (proto.default_value() == "nan") {
+            result->default_value_double_ =
+                std::numeric_limits<double>::quiet_NaN();
+          } else {
+            result->default_value_double_ =
+                io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          if (proto.default_value() == "true") {
+            result->default_value_bool_ = true;
+          } else if (proto.default_value() == "false") {
+            result->default_value_bool_ = false;
+          } else {
+            AddError(result->full_name(), proto,
+                     DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                     "Boolean default must be true or false.");
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_ENUM:
+          // This will be filled in when cross-linking.
+          result->default_value_enum_ = nullptr;
+          break;
+        case FieldDescriptor::CPPTYPE_STRING:
+          if (result->type() == FieldDescriptor::TYPE_BYTES) {
+            result->default_value_string_ = alloc.AllocateStrings(
+                UnescapeCEscapeString(proto.default_value()));
+          } else {
+            result->default_value_string_ =
+                alloc.AllocateStrings(proto.default_value());
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          AddError(result->full_name(), proto,
+                   DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                   "Messages can't have default values.");
+          result->has_default_value_ = false;
+          result->default_generated_instance_ = nullptr;
+          break;
+      }
+
+      if (end_pos != nullptr) {
+        // end_pos is only set non-null by the parsers for numeric types,
+        // above. This checks that the default was non-empty and had no extra
+        // junk after the end of the number.
+        if (proto.default_value().empty() || *end_pos != '\0') {
+          AddError(result->full_name(), proto,
+                   DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                   "Couldn't parse default value \"" + proto.default_value() +
+                       "\".");
+        }
+      }
+    } else {
+      // No explicit default value
+      switch (result->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+          result->default_value_int32_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_INT64:
+          result->default_value_int64_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_UINT32:
+          result->default_value_uint32_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_UINT64:
+          result->default_value_uint64_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_FLOAT:
+          result->default_value_float_ = 0.0f;
+          break;
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          result->default_value_double_ = 0.0;
+          break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          result->default_value_bool_ = false;
+          break;
+        case FieldDescriptor::CPPTYPE_ENUM:
+          // This will be filled in when cross-linking.
+          result->default_value_enum_ = nullptr;
+          break;
+        case FieldDescriptor::CPPTYPE_STRING:
+          result->default_value_string_ = &internal::GetEmptyString();
+          break;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          result->default_generated_instance_ = nullptr;
+          break;
+      }
+    }
+  }
+
+  if (result->number() <= 0) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER);
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Field numbers must be positive integers.");
+  } else if (!is_extension && result->number() > FieldDescriptor::kMaxNumber) {
+    // Only validate that the number is within the valid field range if it is
+    // not an extension. Since extension numbers are validated with the
+    // extendee's valid set of extension numbers, and those are in turn
+    // validated against the max allowed number, the check is unnecessary for
+    // extension fields.
+    // This avoids cross-linking issues that arise when attempting to check if
+    // the extendee is a message_set_wire_format message, which has a higher max
+    // on extension numbers.
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER);
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             strings::Substitute("Field numbers cannot be greater than $0.",
+                              FieldDescriptor::kMaxNumber));
+  } else if (result->number() >= FieldDescriptor::kFirstReservedNumber &&
+             result->number() <= FieldDescriptor::kLastReservedNumber) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER);
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             strings::Substitute(
+                 "Field numbers $0 through $1 are reserved for the protocol "
+                 "buffer library implementation.",
+                 FieldDescriptor::kFirstReservedNumber,
+                 FieldDescriptor::kLastReservedNumber));
+  }
+
+  if (is_extension) {
+    if (!proto.has_extendee()) {
+      AddError(result->full_name(), proto,
+               DescriptorPool::ErrorCollector::EXTENDEE,
+               "FieldDescriptorProto.extendee not set for extension field.");
+    }
+
+    result->scope_.extension_scope = parent;
+
+    if (proto.has_oneof_index()) {
+      AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "FieldDescriptorProto.oneof_index should not be set for "
+               "extensions.");
+    }
+  } else {
+    if (proto.has_extendee()) {
+      AddError(result->full_name(), proto,
+               DescriptorPool::ErrorCollector::EXTENDEE,
+               "FieldDescriptorProto.extendee set for non-extension field.");
+    }
+
+    result->containing_type_ = parent;
+
+    if (proto.has_oneof_index()) {
+      if (proto.oneof_index() < 0 ||
+          proto.oneof_index() >= parent->oneof_decl_count()) {
+        AddError(result->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 strings::Substitute("FieldDescriptorProto.oneof_index $0 is "
+                                  "out of range for type \"$1\".",
+                                  proto.oneof_index(), parent->name()));
+      } else {
+        result->is_oneof_ = true;
+        result->scope_.containing_oneof =
+            parent->oneof_decl(proto.oneof_index());
+      }
+    }
+  }
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    FieldDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.FieldOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+}
+
+void DescriptorBuilder::BuildExtensionRange(
+    const DescriptorProto::ExtensionRange& proto, const Descriptor* parent,
+    Descriptor::ExtensionRange* result, internal::FlatAllocator& alloc) {
+  result->start = proto.start();
+  result->end = proto.end();
+  if (result->start <= 0) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER, result->start,
+        result->end);
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Extension numbers must be positive integers.");
+  }
+
+  // Checking of the upper bound of the extension range is deferred until after
+  // options interpreting. This allows messages with message_set_wire_format to
+  // have extensions beyond FieldDescriptor::kMaxNumber, since the extension
+  // numbers are actually used as int32s in the message_set_wire_format.
+
+  if (result->start >= result->end) {
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Extension range end number must be greater than start number.");
+  }
+
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    std::vector<int> options_path;
+    parent->GetLocationPath(&options_path);
+    options_path.push_back(DescriptorProto::kExtensionRangeFieldNumber);
+    // find index of this extension range in order to compute path
+    int index;
+    for (index = 0; parent->extension_ranges_ + index != result; index++) {
+    }
+    options_path.push_back(index);
+    options_path.push_back(DescriptorProto_ExtensionRange::kOptionsFieldNumber);
+    AllocateOptionsImpl(parent->full_name(), parent->full_name(),
+                        proto.options(), result, options_path,
+                        "google.protobuf.ExtensionRangeOptions", alloc);
+  }
+}
+
+void DescriptorBuilder::BuildReservedRange(
+    const DescriptorProto::ReservedRange& proto, const Descriptor* parent,
+    Descriptor::ReservedRange* result, internal::FlatAllocator&) {
+  result->start = proto.start();
+  result->end = proto.end();
+  if (result->start <= 0) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER, result->start,
+        result->end);
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Reserved numbers must be positive integers.");
+  }
+}
+
+void DescriptorBuilder::BuildReservedRange(
+    const EnumDescriptorProto::EnumReservedRange& proto,
+    const EnumDescriptor* parent, EnumDescriptor::ReservedRange* result,
+    internal::FlatAllocator&) {
+  result->start = proto.start();
+  result->end = proto.end();
+
+  if (result->start > result->end) {
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Reserved range end number must be greater than start number.");
+  }
+}
+
+void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
+                                   Descriptor* parent, OneofDescriptor* result,
+                                   internal::FlatAllocator& alloc) {
+  result->all_names_ =
+      AllocateNameStrings(parent->full_name(), proto.name(), alloc);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  result->containing_type_ = parent;
+
+  // We need to fill these in later.
+  result->field_count_ = 0;
+  result->fields_ = nullptr;
+  result->options_ = nullptr;
+
+  // Copy options.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    OneofDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.OneofOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+}
+
+void DescriptorBuilder::CheckEnumValueUniqueness(
+    const EnumDescriptorProto& proto, const EnumDescriptor* result) {
+
+  // Check that enum labels are still unique when we remove the enum prefix from
+  // values that have it.
+  //
+  // This will fail for something like:
+  //
+  //   enum MyEnum {
+  //     MY_ENUM_FOO = 0;
+  //     FOO = 1;
+  //   }
+  //
+  // By enforcing this reasonable constraint, we allow code generators to strip
+  // the prefix and/or PascalCase it without creating conflicts.  This can lead
+  // to much nicer language-specific enums like:
+  //
+  //   enum NameType {
+  //     FirstName = 1,
+  //     LastName = 2,
+  //   }
+  //
+  // Instead of:
+  //
+  //   enum NameType {
+  //     NAME_TYPE_FIRST_NAME = 1,
+  //     NAME_TYPE_LAST_NAME = 2,
+  //   }
+  PrefixRemover remover(result->name());
+  std::map<std::string, const EnumValueDescriptor*> values;
+  for (int i = 0; i < result->value_count(); i++) {
+    const EnumValueDescriptor* value = result->value(i);
+    std::string stripped =
+        EnumValueToPascalCase(remover.MaybeRemove(value->name()));
+    std::pair<std::map<std::string, const EnumValueDescriptor*>::iterator, bool>
+        insert_result = values.insert(std::make_pair(stripped, value));
+    bool inserted = insert_result.second;
+
+    // We don't throw the error if the two conflicting symbols are identical, or
+    // if they map to the same number.  In the former case, the normal symbol
+    // duplication error will fire so we don't need to (and its error message
+    // will make more sense). We allow the latter case so users can create
+    // aliases which add or remove the prefix (code generators that do prefix
+    // stripping should de-dup the labels in this case).
+    if (!inserted && insert_result.first->second->name() != value->name() &&
+        insert_result.first->second->number() != value->number()) {
+      std::string error_message =
+          "Enum name " + value->name() + " has the same name as " +
+          values[stripped]->name() +
+          " if you ignore case and strip out the enum name prefix (if any). "
+          "This is error-prone and can lead to undefined behavior. "
+          "Please avoid doing this. If you are using allow_alias, please "
+          "assign the same numeric value to both enums.";
+      // There are proto2 enums out there with conflicting names, so to preserve
+      // compatibility we issue only a warning for proto2.
+      if (result->file()->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+        AddWarning(value->full_name(), proto.value(i),
+                   DescriptorPool::ErrorCollector::NAME, error_message);
+      } else {
+        AddError(value->full_name(), proto.value(i),
+                 DescriptorPool::ErrorCollector::NAME, error_message);
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
+                                  const Descriptor* parent,
+                                  EnumDescriptor* result,
+                                  internal::FlatAllocator& alloc) {
+  const std::string& scope =
+      (parent == nullptr) ? file_->package() : parent->full_name();
+
+  result->all_names_ = AllocateNameStrings(scope, proto.name(), alloc);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+  result->file_ = file_;
+  result->containing_type_ = parent;
+  result->is_placeholder_ = false;
+  result->is_unqualified_placeholder_ = false;
+
+  if (proto.value_size() == 0) {
+    // We cannot allow enums with no values because this would mean there
+    // would be no valid default value for fields of this type.
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Enums must contain at least one value.");
+  }
+
+  // Calculate the continuous sequence of the labels.
+  // These can be fast-path'd during lookup and don't need to be added to the
+  // tables.
+  // We use uint16_t to save space for sequential_value_limit_, so stop before
+  // overflowing it. Worst case, we are not taking full advantage on huge
+  // enums, but it is unlikely.
+  for (int i = 0;
+       i < std::numeric_limits<uint16_t>::max() && i < proto.value_size() &&
+       // We do the math in int64_t to avoid overflows.
+       proto.value(i).number() ==
+           static_cast<int64_t>(i) + proto.value(0).number();
+       ++i) {
+    result->sequential_value_limit_ = i;
+  }
+
+  BUILD_ARRAY(proto, result, value, BuildEnumValue, 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_ =
+      alloc.AllocateArray<const std::string*>(reserved_name_count);
+  for (int i = 0; i < reserved_name_count; ++i) {
+    result->reserved_names_[i] =
+        alloc.AllocateStrings(proto.reserved_name(i));
+  }
+
+  CheckEnumValueUniqueness(proto, result);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    EnumDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.EnumOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+
+  for (int i = 0; i < proto.reserved_range_size(); i++) {
+    const EnumDescriptorProto_EnumReservedRange& range1 =
+        proto.reserved_range(i);
+    for (int j = i + 1; j < proto.reserved_range_size(); j++) {
+      const EnumDescriptorProto_EnumReservedRange& 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(), range1.start(),
+                                  range1.end()));
+      }
+    }
+  }
+
+  HASH_SET<std::string> reserved_name_set;
+  for (int i = 0; i < proto.reserved_name_size(); i++) {
+    const std::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("Enum value \"$0\" is reserved multiple times.",
+                                name));
+    }
+  }
+
+  for (int i = 0; i < result->value_count(); i++) {
+    const EnumValueDescriptor* value = result->value(i);
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const EnumDescriptor::ReservedRange* range = result->reserved_range(j);
+      if (range->start <= value->number() && value->number() <= range->end) {
+        AddError(value->full_name(), proto.reserved_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Enum value \"$0\" uses reserved number $1.",
+                                  value->name(), value->number()));
+      }
+    }
+    if (reserved_name_set.find(value->name()) != reserved_name_set.end()) {
+      AddError(
+          value->full_name(), proto.value(i),
+          DescriptorPool::ErrorCollector::NAME,
+          strings::Substitute("Enum value \"$0\" is reserved.", value->name()));
+    }
+  }
+}
+
+void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
+                                       const EnumDescriptor* parent,
+                                       EnumValueDescriptor* result,
+                                       internal::FlatAllocator& alloc) {
+  // Note:  full_name for enum values is a sibling to the parent's name, not a
+  //   child of it.
+  std::string full_name;
+  size_t scope_len = parent->full_name().size() - parent->name().size();
+  full_name.reserve(scope_len + proto.name().size());
+  full_name.append(parent->full_name().data(), scope_len);
+  full_name.append(proto.name());
+
+  result->all_names_ =
+      alloc.AllocateStrings(proto.name(), std::move(full_name));
+  result->number_ = proto.number();
+  result->type_ = parent;
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    EnumValueDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.EnumValueOptions", alloc);
+  }
+
+  // Again, enum values are weird because we makes them appear as siblings
+  // of the enum type instead of children of it.  So, we use
+  // parent->containing_type() as the value's parent.
+  bool added_to_outer_scope =
+      AddSymbol(result->full_name(), parent->containing_type(), result->name(),
+                proto, Symbol::EnumValue(result, 0));
+
+  // However, we also want to be able to search for values within a single
+  // enum type, so we add it as a child of the enum type itself, too.
+  // Note:  This could fail, but if it does, the error has already been
+  //   reported by the above AddSymbol() call, so we ignore the return code.
+  bool added_to_inner_scope = file_tables_->AddAliasUnderParent(
+      parent, result->name(), Symbol::EnumValue(result, 1));
+
+  if (added_to_inner_scope && !added_to_outer_scope) {
+    // This value did not conflict with any values defined in the same enum,
+    // but it did conflict with some other symbol defined in the enum type's
+    // scope.  Let's print an additional error to explain this.
+    std::string outer_scope;
+    if (parent->containing_type() == nullptr) {
+      outer_scope = file_->package();
+    } else {
+      outer_scope = parent->containing_type()->full_name();
+    }
+
+    if (outer_scope.empty()) {
+      outer_scope = "the global scope";
+    } else {
+      outer_scope = "\"" + outer_scope + "\"";
+    }
+
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Note that enum values use C++ scoping rules, meaning that "
+             "enum values are siblings of their type, not children of it.  "
+             "Therefore, \"" +
+                 result->name() + "\" must be unique within " + outer_scope +
+                 ", not just within \"" + parent->name() + "\".");
+  }
+
+  // An enum is allowed to define two numbers that refer to the same value.
+  // FindValueByNumber() should return the first such value, so we simply
+  // ignore AddEnumValueByNumber()'s return code.
+  file_tables_->AddEnumValueByNumber(result);
+}
+
+void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
+                                     const void* /* dummy */,
+                                     ServiceDescriptor* result,
+                                     internal::FlatAllocator& alloc) {
+  result->all_names_ =
+      AllocateNameStrings(file_->package(), proto.name(), alloc);
+  result->file_ = file_;
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  BUILD_ARRAY(proto, result, method, BuildMethod, result);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    ServiceDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.ServiceOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), nullptr, result->name(), proto,
+            Symbol(result));
+}
+
+void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
+                                    const ServiceDescriptor* parent,
+                                    MethodDescriptor* result,
+                                    internal::FlatAllocator& alloc) {
+  result->service_ = parent;
+  result->all_names_ =
+      AllocateNameStrings(parent->full_name(), proto.name(), alloc);
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  // These will be filled in when cross-linking.
+  result->input_type_.Init();
+  result->output_type_.Init();
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    MethodDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.MethodOptions", alloc);
+  }
+
+  result->client_streaming_ = proto.client_streaming();
+  result->server_streaming_ = proto.server_streaming();
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+}
+
+#undef BUILD_ARRAY
+
+// -------------------------------------------------------------------
+
+void DescriptorBuilder::CrossLinkFile(FileDescriptor* file,
+                                      const FileDescriptorProto& proto) {
+  if (file->options_ == nullptr) {
+    file->options_ = &FileOptions::default_instance();
+  }
+
+  for (int i = 0; i < file->message_type_count(); i++) {
+    CrossLinkMessage(&file->message_types_[i], proto.message_type(i));
+  }
+
+  for (int i = 0; i < file->extension_count(); i++) {
+    CrossLinkField(&file->extensions_[i], proto.extension(i));
+  }
+
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    CrossLinkEnum(&file->enum_types_[i], proto.enum_type(i));
+  }
+
+  for (int i = 0; i < file->service_count(); i++) {
+    CrossLinkService(&file->services_[i], proto.service(i));
+  }
+}
+
+void DescriptorBuilder::CrossLinkMessage(Descriptor* message,
+                                         const DescriptorProto& proto) {
+  if (message->options_ == nullptr) {
+    message->options_ = &MessageOptions::default_instance();
+  }
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    CrossLinkMessage(&message->nested_types_[i], proto.nested_type(i));
+  }
+
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    CrossLinkEnum(&message->enum_types_[i], proto.enum_type(i));
+  }
+
+  for (int i = 0; i < message->field_count(); i++) {
+    CrossLinkField(&message->fields_[i], proto.field(i));
+  }
+
+  for (int i = 0; i < message->extension_count(); i++) {
+    CrossLinkField(&message->extensions_[i], proto.extension(i));
+  }
+
+  for (int i = 0; i < message->extension_range_count(); i++) {
+    CrossLinkExtensionRange(&message->extension_ranges_[i],
+                            proto.extension_range(i));
+  }
+
+  // Set up field array for each oneof.
+
+  // First count the number of fields per oneof.
+  for (int i = 0; i < message->field_count(); i++) {
+    const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
+    if (oneof_decl != nullptr) {
+      // 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::TYPE,
+                 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.
+      auto& out_oneof_decl = message->oneof_decls_[oneof_decl->index()];
+      if (out_oneof_decl.field_count_ == 0) {
+        out_oneof_decl.fields_ = message->field(i);
+      }
+
+      if (!had_errors_) {
+        // Verify that they are contiguous.
+        // This is assumed by OneofDescriptor::field(i).
+        // But only if there are no errors.
+        GOOGLE_CHECK_EQ(out_oneof_decl.fields_ + out_oneof_decl.field_count_,
+                 message->field(i));
+      }
+      ++out_oneof_decl.field_count_;
+    }
+  }
+
+  // Then verify the sizes.
+  for (int i = 0; i < message->oneof_decl_count(); i++) {
+    OneofDescriptor* oneof_decl = &message->oneof_decls_[i];
+
+    if (oneof_decl->field_count() == 0) {
+      AddError(message->full_name() + "." + oneof_decl->name(),
+               proto.oneof_decl(i), DescriptorPool::ErrorCollector::NAME,
+               "Oneof must have at least one field.");
+    }
+
+    if (oneof_decl->options_ == nullptr) {
+      oneof_decl->options_ = &OneofOptions::default_instance();
+    }
+  }
+
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    if (field->proto3_optional_) {
+      if (!field->containing_oneof() ||
+          !field->containing_oneof()->is_synthetic()) {
+        AddError(message->full_name(), proto.field(i),
+                 DescriptorPool::ErrorCollector::OTHER,
+                 "Fields with proto3_optional set must be "
+                 "a member of a one-field oneof");
+      }
+    }
+  }
+
+  // Synthetic oneofs must be last.
+  int first_synthetic = -1;
+  for (int i = 0; i < message->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    if (oneof->is_synthetic()) {
+      if (first_synthetic == -1) {
+        first_synthetic = i;
+      }
+    } else {
+      if (first_synthetic != -1) {
+        AddError(message->full_name(), proto.oneof_decl(i),
+                 DescriptorPool::ErrorCollector::OTHER,
+                 "Synthetic oneofs must be after all other oneofs");
+      }
+    }
+  }
+
+  if (first_synthetic == -1) {
+    message->real_oneof_decl_count_ = message->oneof_decl_count_;
+  } else {
+    message->real_oneof_decl_count_ = first_synthetic;
+  }
+}
+
+void DescriptorBuilder::CrossLinkExtensionRange(
+    Descriptor::ExtensionRange* range,
+    const DescriptorProto::ExtensionRange& /*proto*/) {
+  if (range->options_ == nullptr) {
+    range->options_ = &ExtensionRangeOptions::default_instance();
+  }
+}
+
+void DescriptorBuilder::CrossLinkField(FieldDescriptor* field,
+                                       const FieldDescriptorProto& proto) {
+  if (field->options_ == nullptr) {
+    field->options_ = &FieldOptions::default_instance();
+  }
+
+  if (proto.has_extendee()) {
+    Symbol extendee =
+        LookupSymbol(proto.extendee(), field->full_name(),
+                     DescriptorPool::PLACEHOLDER_EXTENDABLE_MESSAGE);
+    if (extendee.IsNull()) {
+      AddNotDefinedError(field->full_name(), proto,
+                         DescriptorPool::ErrorCollector::EXTENDEE,
+                         proto.extendee());
+      return;
+    } else if (extendee.type() != Symbol::MESSAGE) {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::EXTENDEE,
+               "\"" + proto.extendee() + "\" is not a message type.");
+      return;
+    }
+    field->containing_type_ = extendee.descriptor();
+
+    const Descriptor::ExtensionRange* extension_range =
+        field->containing_type()->FindExtensionRangeContainingNumber(
+            field->number());
+
+    if (extension_range == nullptr) {
+      // Set of valid extension numbers for MessageSet is different (< 2^32)
+      // from other extendees (< 2^29). If unknown deps are allowed, we may not
+      // have that information, and wrongly deem the extension as invalid.
+      auto skip_check = get_allow_unknown(pool_) &&
+                        proto.extendee() == "google.protobuf.bridge.MessageSet";
+      if (!skip_check) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("\"$0\" does not declare $1 as an "
+                                  "extension number.",
+                                  field->containing_type()->full_name(),
+                                  field->number()));
+      }
+    }
+  }
+
+  if (field->containing_oneof() != nullptr) {
+    if (field->label() != FieldDescriptor::LABEL_OPTIONAL) {
+      // Note that this error will never happen when parsing .proto files.
+      // It can only happen if you manually construct a FileDescriptorProto
+      // that is incorrect.
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+               "Fields of oneofs must themselves have label LABEL_OPTIONAL.");
+    }
+  }
+
+  if (proto.has_type_name()) {
+    // Assume we are expecting a message type unless the proto contains some
+    // evidence that it expects an enum type.  This only makes a difference if
+    // we end up creating a placeholder.
+    bool expecting_enum = (proto.type() == FieldDescriptorProto::TYPE_ENUM) ||
+                          proto.has_default_value();
+
+    // In case of weak fields we force building the dependency. We need to know
+    // if the type exist or not. If it doesn't exist we substitute Empty which
+    // should only be done if the type can't be found in the generated pool.
+    // TODO(gerbens) Ideally we should query the database directly to check
+    // if weak fields exist or not so that we don't need to force building
+    // weak dependencies. However the name lookup rules for symbols are
+    // somewhat complicated, so I defer it too another CL.
+    bool is_weak = !pool_->enforce_weak_ && proto.options().weak();
+    bool is_lazy = pool_->lazily_build_dependencies_ && !is_weak;
+
+    Symbol type =
+        LookupSymbol(proto.type_name(), field->full_name(),
+                     expecting_enum ? DescriptorPool::PLACEHOLDER_ENUM
+                                    : DescriptorPool::PLACEHOLDER_MESSAGE,
+                     LOOKUP_TYPES, !is_lazy);
+
+    if (type.IsNull()) {
+      if (is_lazy) {
+        // Save the symbol names for later for lookup, and allocate the once
+        // object needed for the accessors.
+        const std::string& name = proto.type_name();
+
+        int name_sizes = static_cast<int>(name.size() + 1 +
+                                          proto.default_value().size() + 1);
+
+        field->type_once_ = ::new (tables_->AllocateBytes(static_cast<int>(
+            sizeof(internal::once_flag) + name_sizes))) internal::once_flag{};
+        char* names = reinterpret_cast<char*>(field->type_once_ + 1);
+
+        memcpy(names, name.c_str(), name.size() + 1);
+        memcpy(names + name.size() + 1, proto.default_value().c_str(),
+               proto.default_value().size() + 1);
+
+        // AddFieldByNumber and AddExtension are done later in this function,
+        // and can/must be done if the field type was not found. The related
+        // error checking is not necessary when in lazily_build_dependencies_
+        // mode, and can't be done without building the type's descriptor,
+        // which we don't want to do.
+        file_tables_->AddFieldByNumber(field);
+        if (field->is_extension()) {
+          tables_->AddExtension(field);
+        }
+        return;
+      } else {
+        // If the type is a weak type, we change the type to a google.protobuf.Empty
+        // field.
+        if (is_weak) {
+          type = FindSymbol(kNonLinkedWeakMessageReplacementName);
+        }
+        if (type.IsNull()) {
+          AddNotDefinedError(field->full_name(), proto,
+                             DescriptorPool::ErrorCollector::TYPE,
+                             proto.type_name());
+          return;
+        }
+      }
+    }
+
+    if (!proto.has_type()) {
+      // Choose field type based on symbol.
+      if (type.type() == Symbol::MESSAGE) {
+        field->type_ = FieldDescriptor::TYPE_MESSAGE;
+      } else if (type.type() == Symbol::ENUM) {
+        field->type_ = FieldDescriptor::TYPE_ENUM;
+      } else {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "\"" + proto.type_name() + "\" is not a type.");
+        return;
+      }
+    }
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      field->type_descriptor_.message_type = type.descriptor();
+      if (field->type_descriptor_.message_type == nullptr) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "\"" + proto.type_name() + "\" is not a message type.");
+        return;
+      }
+
+      if (field->has_default_value()) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                 "Messages can't have default values.");
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      field->type_descriptor_.enum_type = type.enum_descriptor();
+      if (field->type_descriptor_.enum_type == nullptr) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "\"" + proto.type_name() + "\" is not an enum type.");
+        return;
+      }
+
+      if (field->enum_type()->is_placeholder_) {
+        // We can't look up default values for placeholder types.  We'll have
+        // to just drop them.
+        field->has_default_value_ = false;
+      }
+
+      if (field->has_default_value()) {
+        // Ensure that the default value is an identifier. Parser cannot always
+        // verify this because it does not have complete type information.
+        // N.B. that this check yields better error messages but is not
+        // necessary for correctness (an enum symbol must be a valid identifier
+        // anyway), only for better errors.
+        if (!io::Tokenizer::IsIdentifier(proto.default_value())) {
+          AddError(field->full_name(), proto,
+                   DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                   "Default value for an enum field must be an identifier.");
+        } else {
+          // We can't just use field->enum_type()->FindValueByName() here
+          // because that locks the pool's mutex, which we have already locked
+          // at this point.
+          const EnumValueDescriptor* default_value =
+              LookupSymbolNoPlaceholder(proto.default_value(),
+                                        field->enum_type()->full_name())
+                  .enum_value_descriptor();
+
+          if (default_value != nullptr &&
+              default_value->type() == field->enum_type()) {
+            field->default_value_enum_ = default_value;
+          } else {
+            AddError(field->full_name(), proto,
+                     DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                     "Enum type \"" + field->enum_type()->full_name() +
+                         "\" has no value named \"" + proto.default_value() +
+                         "\".");
+          }
+        }
+      } else if (field->enum_type()->value_count() > 0) {
+        // All enums must have at least one value, or we would have reported
+        // an error elsewhere.  We use the first defined value as the default
+        // if a default is not explicitly defined.
+        field->default_value_enum_ = field->enum_type()->value(0);
+      }
+    } else {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Field with primitive type has type_name.");
+    }
+  } else {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+        field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Field with message or enum type missing type_name.");
+    }
+  }
+
+  // Add the field to the fields-by-number table.
+  // Note:  We have to do this *after* cross-linking because extensions do not
+  // know their containing type until now. If we're in
+  // lazily_build_dependencies_ mode, we're guaranteed there's no errors, so no
+  // risk to calling containing_type() or other accessors that will build
+  // dependencies.
+  if (!file_tables_->AddFieldByNumber(field)) {
+    const FieldDescriptor* conflicting_field = file_tables_->FindFieldByNumber(
+        field->containing_type(), field->number());
+    std::string containing_type_name =
+        field->containing_type() == nullptr
+            ? "unknown"
+            : field->containing_type()->full_name();
+    if (field->is_extension()) {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::NUMBER,
+               strings::Substitute("Extension number $0 has already been used "
+                                "in \"$1\" by extension \"$2\".",
+                                field->number(), containing_type_name,
+                                conflicting_field->full_name()));
+    } else {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::NUMBER,
+               strings::Substitute("Field number $0 has already been used in "
+                                "\"$1\" by field \"$2\".",
+                                field->number(), containing_type_name,
+                                conflicting_field->name()));
+    }
+  } else {
+    if (field->is_extension()) {
+      if (!tables_->AddExtension(field)) {
+        const FieldDescriptor* conflicting_field =
+            tables_->FindExtension(field->containing_type(), field->number());
+        std::string containing_type_name =
+            field->containing_type() == nullptr
+                ? "unknown"
+                : field->containing_type()->full_name();
+        std::string error_msg = strings::Substitute(
+            "Extension number $0 has already been used in \"$1\" by extension "
+            "\"$2\" defined in $3.",
+            field->number(), containing_type_name,
+            conflicting_field->full_name(), conflicting_field->file()->name());
+        // Conflicting extension numbers should be an error. However, before
+        // turning this into an error we need to fix all existing broken
+        // protos first.
+        // TODO(xiaofeng): Change this to an error.
+        AddWarning(field->full_name(), proto,
+                   DescriptorPool::ErrorCollector::NUMBER, error_msg);
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::CrossLinkEnum(EnumDescriptor* enum_type,
+                                      const EnumDescriptorProto& proto) {
+  if (enum_type->options_ == nullptr) {
+    enum_type->options_ = &EnumOptions::default_instance();
+  }
+
+  for (int i = 0; i < enum_type->value_count(); i++) {
+    CrossLinkEnumValue(&enum_type->values_[i], proto.value(i));
+  }
+}
+
+void DescriptorBuilder::CrossLinkEnumValue(
+    EnumValueDescriptor* enum_value,
+    const EnumValueDescriptorProto& /* proto */) {
+  if (enum_value->options_ == nullptr) {
+    enum_value->options_ = &EnumValueOptions::default_instance();
+  }
+}
+
+void DescriptorBuilder::CrossLinkService(ServiceDescriptor* service,
+                                         const ServiceDescriptorProto& proto) {
+  if (service->options_ == nullptr) {
+    service->options_ = &ServiceOptions::default_instance();
+  }
+
+  for (int i = 0; i < service->method_count(); i++) {
+    CrossLinkMethod(&service->methods_[i], proto.method(i));
+  }
+}
+
+void DescriptorBuilder::CrossLinkMethod(MethodDescriptor* method,
+                                        const MethodDescriptorProto& proto) {
+  if (method->options_ == nullptr) {
+    method->options_ = &MethodOptions::default_instance();
+  }
+
+  Symbol input_type =
+      LookupSymbol(proto.input_type(), method->full_name(),
+                   DescriptorPool::PLACEHOLDER_MESSAGE, LOOKUP_ALL,
+                   !pool_->lazily_build_dependencies_);
+  if (input_type.IsNull()) {
+    if (!pool_->lazily_build_dependencies_) {
+      AddNotDefinedError(method->full_name(), proto,
+                         DescriptorPool::ErrorCollector::INPUT_TYPE,
+                         proto.input_type());
+    } else {
+      method->input_type_.SetLazy(proto.input_type(), file_);
+    }
+  } else if (input_type.type() != Symbol::MESSAGE) {
+    AddError(method->full_name(), proto,
+             DescriptorPool::ErrorCollector::INPUT_TYPE,
+             "\"" + proto.input_type() + "\" is not a message type.");
+  } else {
+    method->input_type_.Set(input_type.descriptor());
+  }
+
+  Symbol output_type =
+      LookupSymbol(proto.output_type(), method->full_name(),
+                   DescriptorPool::PLACEHOLDER_MESSAGE, LOOKUP_ALL,
+                   !pool_->lazily_build_dependencies_);
+  if (output_type.IsNull()) {
+    if (!pool_->lazily_build_dependencies_) {
+      AddNotDefinedError(method->full_name(), proto,
+                         DescriptorPool::ErrorCollector::OUTPUT_TYPE,
+                         proto.output_type());
+    } else {
+      method->output_type_.SetLazy(proto.output_type(), file_);
+    }
+  } else if (output_type.type() != Symbol::MESSAGE) {
+    AddError(method->full_name(), proto,
+             DescriptorPool::ErrorCollector::OUTPUT_TYPE,
+             "\"" + proto.output_type() + "\" is not a message type.");
+  } else {
+    method->output_type_.Set(output_type.descriptor());
+  }
+}
+
+void DescriptorBuilder::SuggestFieldNumbers(FileDescriptor* file,
+                                            const FileDescriptorProto& proto) {
+  for (int message_index = 0; message_index < file->message_type_count();
+       message_index++) {
+    const Descriptor* message = &file->message_types_[message_index];
+    auto* hints = FindOrNull(message_hints_, message);
+    if (!hints) continue;
+    constexpr int kMaxSuggestions = 3;
+    int fields_to_suggest = std::min(kMaxSuggestions, hints->fields_to_suggest);
+    if (fields_to_suggest <= 0) continue;
+    struct Range {
+      int from;
+      int to;
+    };
+    std::vector<Range> used_ordinals;
+    auto add_ordinal = [&](int ordinal) {
+      if (ordinal <= 0 || ordinal > FieldDescriptor::kMaxNumber) return;
+      if (!used_ordinals.empty() &&
+          ordinal == used_ordinals.back().to) {
+        used_ordinals.back().to = ordinal + 1;
+      } else {
+        used_ordinals.push_back({ordinal, ordinal + 1});
+      }
+    };
+    auto add_range = [&](int from, int to) {
+      from = std::max(0, std::min(FieldDescriptor::kMaxNumber + 1, from));
+      to = std::max(0, std::min(FieldDescriptor::kMaxNumber + 1, to));
+      if (from >= to) return;
+      used_ordinals.push_back({from, to});
+    };
+    for (int i = 0; i < message->field_count(); i++) {
+      add_ordinal(message->field(i)->number());
+    }
+    for (int i = 0; i < message->extension_count(); i++) {
+      add_ordinal(message->extension(i)->number());
+    }
+    for (int i = 0; i < message->reserved_range_count(); i++) {
+      auto range = message->reserved_range(i);
+      add_range(range->start, range->end);
+    }
+    for (int i = 0; i < message->extension_range_count(); i++) {
+      auto range = message->extension_range(i);
+      add_range(range->start, range->end);
+    }
+    used_ordinals.push_back(
+        {FieldDescriptor::kMaxNumber, FieldDescriptor::kMaxNumber + 1});
+    used_ordinals.push_back({FieldDescriptor::kFirstReservedNumber,
+                             FieldDescriptor::kLastReservedNumber});
+    std::sort(used_ordinals.begin(), used_ordinals.end(),
+              [](Range lhs, Range rhs) {
+                return std::tie(lhs.from, lhs.to) < std::tie(rhs.from, rhs.to);
+              });
+    int current_ordinal = 1;
+    std::stringstream id_list;
+    id_list << "Suggested field numbers for " << message->full_name() << ": ";
+    const char* separator = "";
+    for (auto& current_range : used_ordinals) {
+      while (current_ordinal < current_range.from && fields_to_suggest > 0) {
+        id_list << separator << current_ordinal++;
+        separator = ", ";
+        fields_to_suggest--;
+      }
+      if (fields_to_suggest == 0) break;
+      current_ordinal = std::max(current_ordinal, current_range.to);
+    }
+    if (hints->first_reason) {
+      AddError(message->full_name(), *hints->first_reason,
+               hints->first_reason_location, id_list.str());
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+
+#define VALIDATE_OPTIONS_FROM_ARRAY(descriptor, array_name, type) \
+  for (int i = 0; i < descriptor->array_name##_count(); ++i) {    \
+    Validate##type##Options(descriptor->array_name##s_ + i,       \
+                            proto.array_name(i));                 \
+  }
+
+// Determine if the file uses optimize_for = LITE_RUNTIME, being careful to
+// avoid problems that exist at init time.
+static bool IsLite(const FileDescriptor* file) {
+  // TODO(kenton):  I don't even remember how many of these conditions are
+  //   actually possible.  I'm just being super-safe.
+  return file != nullptr &&
+         &file->options() != &FileOptions::default_instance() &&
+         file->options().optimize_for() == FileOptions::LITE_RUNTIME;
+}
+
+void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file,
+                                            const FileDescriptorProto& proto) {
+  VALIDATE_OPTIONS_FROM_ARRAY(file, message_type, Message);
+  VALIDATE_OPTIONS_FROM_ARRAY(file, enum_type, Enum);
+  VALIDATE_OPTIONS_FROM_ARRAY(file, service, Service);
+  VALIDATE_OPTIONS_FROM_ARRAY(file, extension, Field);
+
+  // Lite files can only be imported by other Lite files.
+  if (!IsLite(file)) {
+    for (int i = 0; i < file->dependency_count(); i++) {
+      if (IsLite(file->dependency(i))) {
+        AddError(
+            file->dependency(i)->name(), proto,
+            DescriptorPool::ErrorCollector::IMPORT,
+            "Files that do not use optimize_for = LITE_RUNTIME cannot import "
+            "files which do use this option.  This file is not lite, but it "
+            "imports \"" +
+                file->dependency(i)->name() + "\" which is.");
+        break;
+      }
+    }
+  }
+  if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    ValidateProto3(file, proto);
+  }
+}
+
+void DescriptorBuilder::ValidateProto3(FileDescriptor* file,
+                                       const FileDescriptorProto& proto) {
+  for (int i = 0; i < file->extension_count(); ++i) {
+    ValidateProto3Field(file->extensions_ + i, proto.extension(i));
+  }
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    ValidateProto3Message(file->message_types_ + i, proto.message_type(i));
+  }
+  for (int i = 0; i < file->enum_type_count(); ++i) {
+    ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i));
+  }
+}
+
+static std::string ToLowercaseWithoutUnderscores(const std::string& name) {
+  std::string result;
+  for (char character : name) {
+    if (character != '_') {
+      if (character >= 'A' && character <= 'Z') {
+        result.push_back(character - 'A' + 'a');
+      } else {
+        result.push_back(character);
+      }
+    }
+  }
+  return result;
+}
+
+void DescriptorBuilder::ValidateProto3Message(Descriptor* message,
+                                              const DescriptorProto& proto) {
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    ValidateProto3Message(message->nested_types_ + i, proto.nested_type(i));
+  }
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    ValidateProto3Enum(message->enum_types_ + i, proto.enum_type(i));
+  }
+  for (int i = 0; i < message->field_count(); ++i) {
+    ValidateProto3Field(message->fields_ + i, proto.field(i));
+  }
+  for (int i = 0; i < message->extension_count(); ++i) {
+    ValidateProto3Field(message->extensions_ + i, proto.extension(i));
+  }
+  if (message->extension_range_count() > 0) {
+    AddError(message->full_name(), proto.extension_range(0),
+             DescriptorPool::ErrorCollector::NUMBER,
+             "Extension ranges are not allowed in proto3.");
+  }
+  if (message->options().message_set_wire_format()) {
+    // Using MessageSet doesn't make sense since we disallow extensions.
+    AddError(message->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "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.
+  std::map<std::string, const FieldDescriptor*> name_to_field;
+  for (int i = 0; i < message->field_count(); ++i) {
+    std::string lowercase_name =
+        ToLowercaseWithoutUnderscores(message->field(i)->name());
+    if (name_to_field.find(lowercase_name) != name_to_field.end()) {
+      AddError(message->full_name(), proto.field(i),
+               DescriptorPool::ErrorCollector::NAME,
+               "The JSON camel-case name of field \"" +
+                   message->field(i)->name() + "\" conflicts with field \"" +
+                   name_to_field[lowercase_name]->name() + "\". This is not " +
+                   "allowed in proto3.");
+    } else {
+      name_to_field[lowercase_name] = message->field(i);
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateProto3Field(FieldDescriptor* field,
+                                            const FieldDescriptorProto& proto) {
+  if (field->is_extension() &&
+      !AllowedExtendeeInProto3(field->containing_type()->full_name())) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::EXTENDEE,
+             "Extensions in proto3 are only allowed for defining options.");
+  }
+  if (field->is_required()) {
+    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "Required fields are not allowed in proto3.");
+  }
+  if (field->has_default_value()) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+             "Explicit default values are not allowed in proto3.");
+  }
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+      field->enum_type() &&
+      field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
+      field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_UNKNOWN) {
+    // Proto3 messages can only use Proto3 enum types; otherwise we can't
+    // guarantee that the default value is zero.
+    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "Enum type \"" + field->enum_type()->full_name() +
+                 "\" is not a proto3 enum, but is used in \"" +
+                 field->containing_type()->full_name() +
+                 "\" which is a proto3 message type.");
+  }
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "Groups are not supported in proto3 syntax.");
+  }
+}
+
+void DescriptorBuilder::ValidateProto3Enum(EnumDescriptor* enm,
+                                           const EnumDescriptorProto& proto) {
+  if (enm->value_count() > 0 && enm->value(0)->number() != 0) {
+    AddError(enm->full_name(), proto.value(0),
+             DescriptorPool::ErrorCollector::NUMBER,
+             "The first enum value must be zero in proto3.");
+  }
+}
+
+void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
+                                               const DescriptorProto& proto) {
+  VALIDATE_OPTIONS_FROM_ARRAY(message, field, Field);
+  VALIDATE_OPTIONS_FROM_ARRAY(message, nested_type, Message);
+  VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum);
+  VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field);
+
+  const int64_t max_extension_range =
+      static_cast<int64_t>(message->options().message_set_wire_format()
+                               ? std::numeric_limits<int32_t>::max()
+                               : FieldDescriptor::kMaxNumber);
+  for (int i = 0; i < message->extension_range_count(); ++i) {
+    if (message->extension_range(i)->end > max_extension_range + 1) {
+      AddError(message->full_name(), proto.extension_range(i),
+               DescriptorPool::ErrorCollector::NUMBER,
+               strings::Substitute("Extension numbers cannot be greater than $0.",
+                                max_extension_range));
+    }
+
+    ValidateExtensionRangeOptions(message->full_name(),
+                                  message->extension_ranges_ + i,
+                                  proto.extension_range(i));
+  }
+}
+
+
+void DescriptorBuilder::ValidateFieldOptions(
+    FieldDescriptor* field, const FieldDescriptorProto& proto) {
+  if (pool_->lazily_build_dependencies_ && (!field || !field->message_type())) {
+    return;
+  }
+  // Only message type fields may be lazy.
+  if (field->options().lazy() || field->options().unverified_lazy()) {
+    if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "[lazy = true] can only be specified for submessage fields.");
+    }
+  }
+
+  // Only repeated primitive fields may be packed.
+  if (field->options().packed() && !field->is_packable()) {
+    AddError(
+        field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+        "[packed = true] can only be specified for repeated primitive fields.");
+  }
+
+  // Note:  Default instance may not yet be initialized here, so we have to
+  //   avoid reading from it.
+  if (field->containing_type_ != nullptr &&
+      &field->containing_type()->options() !=
+          &MessageOptions::default_instance() &&
+      field->containing_type()->options().message_set_wire_format()) {
+    if (field->is_extension()) {
+      if (!field->is_optional() ||
+          field->type() != FieldDescriptor::TYPE_MESSAGE) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "Extensions of MessageSets must be optional messages.");
+      }
+    } else {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+               "MessageSets cannot have fields, only extensions.");
+    }
+  }
+
+  // Lite extensions can only be of Lite types.
+  if (IsLite(field->file()) && field->containing_type_ != nullptr &&
+      !IsLite(field->containing_type()->file())) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::EXTENDEE,
+             "Extensions to non-lite types can only be declared in non-lite "
+             "files.  Note that you cannot extend a non-lite type to contain "
+             "a lite type, but the reverse is allowed.");
+  }
+
+  // Validate map types.
+  if (field->is_map()) {
+    if (!ValidateMapEntry(field, proto)) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "map_entry should not be set explicitly. Use map<KeyType, "
+               "ValueType> instead.");
+    }
+  }
+
+  ValidateJSType(field, proto);
+
+  // json_name option is not allowed on extension fields. Note that the
+  // json_name field in FieldDescriptorProto is always populated by protoc
+  // when it sends descriptor data to plugins (calculated from field name if
+  // the option is not explicitly set) so we can't rely on its presence to
+  // determine whether the json_name option is set on the field. Here we
+  // compare it against the default calculated json_name value and consider
+  // the option set if they are different. This won't catch the case when
+  // an user explicitly sets json_name to the default value, but should be
+  // good enough to catch common misuses.
+  if (field->is_extension() &&
+      (field->has_json_name() &&
+       field->json_name() != ToJsonName(field->name()))) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::OPTION_NAME,
+             "option json_name is not allowed on extension fields.");
+  }
+
+}
+
+void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
+                                            const EnumDescriptorProto& proto) {
+  VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue);
+  if (!enm->options().has_allow_alias() || !enm->options().allow_alias()) {
+    std::map<int, std::string> used_values;
+    for (int i = 0; i < enm->value_count(); ++i) {
+      const EnumValueDescriptor* enum_value = enm->value(i);
+      if (used_values.find(enum_value->number()) != used_values.end()) {
+        std::string error =
+            "\"" + enum_value->full_name() +
+            "\" uses the same enum value as \"" +
+            used_values[enum_value->number()] +
+            "\". If this is intended, set "
+            "'option allow_alias = true;' to the enum definition.";
+        if (!enm->options().allow_alias()) {
+          // Generate error if duplicated enum values are explicitly disallowed.
+          AddError(enm->full_name(), proto.value(i),
+                   DescriptorPool::ErrorCollector::NUMBER, error);
+        }
+      } else {
+        used_values[enum_value->number()] = enum_value->full_name();
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateEnumValueOptions(
+    EnumValueDescriptor* /* enum_value */,
+    const EnumValueDescriptorProto& /* proto */) {
+  // Nothing to do so far.
+}
+
+void DescriptorBuilder::ValidateExtensionRangeOptions(
+    const std::string& full_name, Descriptor::ExtensionRange* extension_range,
+    const DescriptorProto_ExtensionRange& proto) {
+  (void)full_name;        // Parameter is used by Google-internal code.
+  (void)extension_range;  // Parameter is used by Google-internal code.
+}
+
+void DescriptorBuilder::ValidateServiceOptions(
+    ServiceDescriptor* service, const ServiceDescriptorProto& proto) {
+  if (IsLite(service->file()) &&
+      (service->file()->options().cc_generic_services() ||
+       service->file()->options().java_generic_services())) {
+    AddError(service->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Files with optimize_for = LITE_RUNTIME cannot define services "
+             "unless you set both options cc_generic_services and "
+             "java_generic_services to false.");
+  }
+
+  VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method);
+}
+
+void DescriptorBuilder::ValidateMethodOptions(
+    MethodDescriptor* /* method */, const MethodDescriptorProto& /* proto */) {
+  // Nothing to do so far.
+}
+
+bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field,
+                                         const FieldDescriptorProto& proto) {
+  const Descriptor* message = field->message_type();
+  if (  // Must not contain extensions, extension range or nested message or
+        // enums
+      message->extension_count() != 0 ||
+      field->label() != FieldDescriptor::LABEL_REPEATED ||
+      message->extension_range_count() != 0 ||
+      message->nested_type_count() != 0 || message->enum_type_count() != 0 ||
+      // Must contain exactly two fields
+      message->field_count() != 2 ||
+      // Field name and message name must match
+      message->name() != ToCamelCase(field->name(), false) + "Entry" ||
+      // Entry message must be in the same containing type of the field.
+      field->containing_type() != message->containing_type()) {
+    return false;
+  }
+
+  const FieldDescriptor* key = message->map_key();
+  const FieldDescriptor* value = message->map_value();
+  if (key->label() != FieldDescriptor::LABEL_OPTIONAL || key->number() != 1 ||
+      key->name() != "key") {
+    return false;
+  }
+  if (value->label() != FieldDescriptor::LABEL_OPTIONAL ||
+      value->number() != 2 || value->name() != "value") {
+    return false;
+  }
+
+  // Check key types are legal.
+  switch (key->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Key in map fields cannot be enum types.");
+      break;
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_BYTES:
+      AddError(
+          field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+          "Key in map fields cannot be float/double, bytes or message types.");
+      break;
+    case FieldDescriptor::TYPE_BOOL:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_SFIXED64:
+      // Legal cases
+      break;
+      // Do not add a default, so that the compiler will complain when new types
+      // are added.
+  }
+
+  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;
+}
+
+void DescriptorBuilder::DetectMapConflicts(const Descriptor* message,
+                                           const DescriptorProto& proto) {
+  std::map<std::string, const Descriptor*> seen_types;
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    const Descriptor* nested = message->nested_type(i);
+    std::pair<std::map<std::string, const Descriptor*>::iterator, bool> result =
+        seen_types.insert(std::make_pair(nested->name(), nested));
+    if (!result.second) {
+      if (result.first->second->options().map_entry() ||
+          nested->options().map_entry()) {
+        AddError(message->full_name(), proto,
+                 DescriptorPool::ErrorCollector::NAME,
+                 "Expanded map entry type " + nested->name() +
+                     " conflicts with an existing nested message type.");
+        break;
+      }
+    }
+    // Recursively test on the nested types.
+    DetectMapConflicts(message->nested_type(i), proto.nested_type(i));
+  }
+  // Check for conflicted field names.
+  for (int i = 0; i < message->field_count(); ++i) {
+    const FieldDescriptor* field = message->field(i);
+    std::map<std::string, const Descriptor*>::iterator iter =
+        seen_types.find(field->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+                   " conflicts with an existing field.");
+    }
+  }
+  // Check for conflicted enum names.
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    const EnumDescriptor* enum_desc = message->enum_type(i);
+    std::map<std::string, const Descriptor*>::iterator iter =
+        seen_types.find(enum_desc->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+                   " conflicts with an existing enum type.");
+    }
+  }
+  // Check for conflicted oneof names.
+  for (int i = 0; i < message->oneof_decl_count(); ++i) {
+    const OneofDescriptor* oneof_desc = message->oneof_decl(i);
+    std::map<std::string, const Descriptor*>::iterator iter =
+        seen_types.find(oneof_desc->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+                   " conflicts with an existing oneof type.");
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateJSType(FieldDescriptor* field,
+                                       const FieldDescriptorProto& proto) {
+  FieldOptions::JSType jstype = field->options().jstype();
+  // The default is always acceptable.
+  if (jstype == FieldOptions::JS_NORMAL) {
+    return;
+  }
+
+  switch (field->type()) {
+    // Integral 64-bit types may be represented as JavaScript numbers or
+    // strings.
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+      if (jstype == FieldOptions::JS_STRING ||
+          jstype == FieldOptions::JS_NUMBER) {
+        return;
+      }
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Illegal jstype for int64, uint64, sint64, fixed64 "
+               "or sfixed64 field: " +
+                   FieldOptions_JSType_descriptor()->value(jstype)->name());
+      break;
+
+    // No other types permit a jstype option.
+    default:
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "jstype is only allowed on int64, uint64, sint64, fixed64 "
+               "or sfixed64 fields.");
+      break;
+  }
+}
+
+#undef VALIDATE_OPTIONS_FROM_ARRAY
+
+// -------------------------------------------------------------------
+
+DescriptorBuilder::OptionInterpreter::OptionInterpreter(
+    DescriptorBuilder* builder)
+    : builder_(builder) {
+  GOOGLE_CHECK(builder_);
+}
+
+DescriptorBuilder::OptionInterpreter::~OptionInterpreter() {}
+
+bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
+    OptionsToInterpret* options_to_interpret) {
+  // Note that these may be in different pools, so we can't use the same
+  // descriptor and reflection objects on both.
+  Message* options = options_to_interpret->options;
+  const Message* original_options = options_to_interpret->original_options;
+
+  bool failed = false;
+  options_to_interpret_ = options_to_interpret;
+
+  // Find the uninterpreted_option field in the mutable copy of the options
+  // and clear them, since we're about to interpret them.
+  const FieldDescriptor* uninterpreted_options_field =
+      options->GetDescriptor()->FindFieldByName("uninterpreted_option");
+  GOOGLE_CHECK(uninterpreted_options_field != nullptr)
+      << "No field named \"uninterpreted_option\" in the Options proto.";
+  options->GetReflection()->ClearField(options, uninterpreted_options_field);
+
+  std::vector<int> src_path = options_to_interpret->element_path;
+  src_path.push_back(uninterpreted_options_field->number());
+
+  // Find the uninterpreted_option field in the original options.
+  const FieldDescriptor* original_uninterpreted_options_field =
+      original_options->GetDescriptor()->FindFieldByName(
+          "uninterpreted_option");
+  GOOGLE_CHECK(original_uninterpreted_options_field != nullptr)
+      << "No field named \"uninterpreted_option\" in the Options proto.";
+
+  const int num_uninterpreted_options =
+      original_options->GetReflection()->FieldSize(
+          *original_options, original_uninterpreted_options_field);
+  for (int i = 0; i < num_uninterpreted_options; ++i) {
+    src_path.push_back(i);
+    uninterpreted_option_ = down_cast<const UninterpretedOption*>(
+        &original_options->GetReflection()->GetRepeatedMessage(
+            *original_options, original_uninterpreted_options_field, i));
+    if (!InterpretSingleOption(options, src_path,
+                               options_to_interpret->element_path)) {
+      // Error already added by InterpretSingleOption().
+      failed = true;
+      break;
+    }
+    src_path.pop_back();
+  }
+  // Reset these, so we don't have any dangling pointers.
+  uninterpreted_option_ = nullptr;
+  options_to_interpret_ = nullptr;
+
+  if (!failed) {
+    // InterpretSingleOption() added the interpreted options in the
+    // UnknownFieldSet, in case the option isn't yet known to us.  Now we
+    // serialize the options message and deserialize it back.  That way, any
+    // option fields that we do happen to know about will get moved from the
+    // UnknownFieldSet into the real fields, and thus be available right away.
+    // If they are not known, that's OK too. They will get reparsed into the
+    // UnknownFieldSet and wait there until the message is parsed by something
+    // that does know about the options.
+
+    // Keep the unparsed options around in case the reparsing fails.
+    std::unique_ptr<Message> unparsed_options(options->New());
+    options->GetReflection()->Swap(unparsed_options.get(), options);
+
+    std::string buf;
+    if (!unparsed_options->AppendToString(&buf) ||
+        !options->ParseFromString(buf)) {
+      builder_->AddError(
+          options_to_interpret->element_name, *original_options,
+          DescriptorPool::ErrorCollector::OTHER,
+          "Some options could not be correctly parsed using the proto "
+          "descriptors compiled into this binary.\n"
+          "Unparsed options: " +
+              unparsed_options->ShortDebugString() +
+              "\n"
+              "Parsing attempt:  " +
+              options->ShortDebugString());
+      // Restore the unparsed options.
+      options->GetReflection()->Swap(unparsed_options.get(), options);
+    }
+  }
+
+  return !failed;
+}
+
+bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
+    Message* options, const std::vector<int>& src_path,
+    const std::vector<int>& options_path) {
+  // First do some basic validation.
+  if (uninterpreted_option_->name_size() == 0) {
+    // This should never happen unless the parser has gone seriously awry or
+    // someone has manually created the uninterpreted option badly.
+    return AddNameError("Option must have a name.");
+  }
+  if (uninterpreted_option_->name(0).name_part() == "uninterpreted_option") {
+    return AddNameError(
+        "Option must not use reserved name "
+        "\"uninterpreted_option\".");
+  }
+
+  const Descriptor* options_descriptor = nullptr;
+  // Get the options message's descriptor from the builder's pool, so that we
+  // get the version that knows about any extension options declared in the file
+  // we're currently building. The descriptor should be there as long as the
+  // file we're building imported descriptor.proto.
+
+  // Note that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
+  // DescriptorPool::FindMessageTypeByName() because we're already holding the
+  // pool's mutex, and the latter method locks it again.  We don't use
+  // FindSymbol() because files that use custom options only need to depend on
+  // the file that defines the option, not descriptor.proto itself.
+  Symbol symbol = builder_->FindSymbolNotEnforcingDeps(
+      options->GetDescriptor()->full_name());
+  options_descriptor = symbol.descriptor();
+  if (options_descriptor == nullptr) {
+    // The options message's descriptor was not in the builder's pool, so use
+    // the standard version from the generated pool. We're not holding the
+    // generated pool's mutex, so we can search it the straightforward way.
+    options_descriptor = options->GetDescriptor();
+  }
+  GOOGLE_CHECK(options_descriptor);
+
+  // We iterate over the name parts to drill into the submessages until we find
+  // the leaf field for the option. As we drill down we remember the current
+  // submessage's descriptor in |descriptor| and the next field in that
+  // submessage in |field|. We also track the fields we're drilling down
+  // through in |intermediate_fields|. As we go, we reconstruct the full option
+  // name in |debug_msg_name|, for use in error messages.
+  const Descriptor* descriptor = options_descriptor;
+  const FieldDescriptor* field = nullptr;
+  std::vector<const FieldDescriptor*> intermediate_fields;
+  std::string debug_msg_name = "";
+
+  std::vector<int> dest_path = options_path;
+
+  for (int i = 0; i < uninterpreted_option_->name_size(); ++i) {
+    builder_->undefine_resolved_name_.clear();
+    const std::string& name_part = uninterpreted_option_->name(i).name_part();
+    if (debug_msg_name.size() > 0) {
+      debug_msg_name += ".";
+    }
+    if (uninterpreted_option_->name(i).is_extension()) {
+      debug_msg_name += "(" + name_part + ")";
+      // Search for the extension's descriptor as an extension in the builder's
+      // pool. Note that we use DescriptorBuilder::LookupSymbol(), not
+      // DescriptorPool::FindExtensionByName(), for two reasons: 1) It allows
+      // relative lookups, and 2) because we're already holding the pool's
+      // mutex, and the latter method locks it again.
+      symbol =
+          builder_->LookupSymbol(name_part, options_to_interpret_->name_scope);
+      field = symbol.field_descriptor();
+      // If we don't find the field then the field's descriptor was not in the
+      // builder's pool, but there's no point in looking in the generated
+      // pool. We require that you import the file that defines any extensions
+      // you use, so they must be present in the builder's pool.
+    } else {
+      debug_msg_name += name_part;
+      // Search for the field's descriptor as a regular field.
+      field = descriptor->FindFieldByName(name_part);
+    }
+
+    if (field == nullptr) {
+      if (get_allow_unknown(builder_->pool_)) {
+        // We can't find the option, but AllowUnknownDependencies() is enabled,
+        // so we will just leave it as uninterpreted.
+        AddWithoutInterpreting(*uninterpreted_option_, options);
+        return true;
+      } else if (!(builder_->undefine_resolved_name_).empty()) {
+        // Option is resolved to a name which is not defined.
+        return AddNameError(
+            "Option \"" + debug_msg_name + "\" is resolved to \"(" +
+            builder_->undefine_resolved_name_ +
+            ")\", which is not defined. The innermost scope is searched first "
+            "in name resolution. Consider using a leading '.'(i.e., \"(." +
+            debug_msg_name.substr(1) +
+            "\") to start from the outermost scope.");
+      } else {
+        return AddNameError(
+            "Option \"" + debug_msg_name +
+            "\" unknown. Ensure that your proto" +
+            " definition file imports the proto which defines the option.");
+      }
+    } else if (field->containing_type() != descriptor) {
+      if (get_is_placeholder(field->containing_type())) {
+        // The field is an extension of a placeholder type, so we can't
+        // reliably verify whether it is a valid extension to use here (e.g.
+        // we don't know if it is an extension of the correct *Options message,
+        // or if it has a valid field number, etc.).  Just leave it as
+        // uninterpreted instead.
+        AddWithoutInterpreting(*uninterpreted_option_, options);
+        return true;
+      } else {
+        // This can only happen if, due to some insane misconfiguration of the
+        // pools, we find the options message in one pool but the field in
+        // another. This would probably imply a hefty bug somewhere.
+        return AddNameError("Option field \"" + debug_msg_name +
+                            "\" is not a field or extension of message \"" +
+                            descriptor->name() + "\".");
+      }
+    } else {
+      // accumulate field numbers to form path to interpreted option
+      dest_path.push_back(field->number());
+
+      if (i < uninterpreted_option_->name_size() - 1) {
+        if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+          return AddNameError("Option \"" + debug_msg_name +
+                              "\" is an atomic type, not a message.");
+        } else if (field->is_repeated()) {
+          return AddNameError("Option field \"" + debug_msg_name +
+                              "\" is a repeated message. Repeated message "
+                              "options must be initialized using an "
+                              "aggregate value.");
+        } else {
+          // Drill down into the submessage.
+          intermediate_fields.push_back(field);
+          descriptor = field->message_type();
+        }
+      }
+    }
+  }
+
+  // We've found the leaf field. Now we use UnknownFieldSets to set its value
+  // on the options message. We do so because the message may not yet know
+  // about its extension fields, so we may not be able to set the fields
+  // directly. But the UnknownFieldSets will serialize to the same wire-format
+  // message, so reading that message back in once the extension fields are
+  // known will populate them correctly.
+
+  // First see if the option is already set.
+  if (!field->is_repeated() &&
+      !ExamineIfOptionIsSet(
+          intermediate_fields.begin(), intermediate_fields.end(), field,
+          debug_msg_name,
+          options->GetReflection()->GetUnknownFields(*options))) {
+    return false;  // ExamineIfOptionIsSet() already added the error.
+  }
+
+  // First set the value on the UnknownFieldSet corresponding to the
+  // innermost message.
+  std::unique_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
+  if (!SetOptionValue(field, unknown_fields.get())) {
+    return false;  // SetOptionValue() already added the error.
+  }
+
+  // Now wrap the UnknownFieldSet with UnknownFieldSets corresponding to all
+  // the intermediate messages.
+  for (std::vector<const FieldDescriptor*>::reverse_iterator iter =
+           intermediate_fields.rbegin();
+       iter != intermediate_fields.rend(); ++iter) {
+    std::unique_ptr<UnknownFieldSet> parent_unknown_fields(
+        new UnknownFieldSet());
+    switch ((*iter)->type()) {
+      case FieldDescriptor::TYPE_MESSAGE: {
+        std::string* outstr =
+            parent_unknown_fields->AddLengthDelimited((*iter)->number());
+        GOOGLE_CHECK(unknown_fields->SerializeToString(outstr))
+            << "Unexpected failure while serializing option submessage "
+            << debug_msg_name << "\".";
+        break;
+      }
+
+      case FieldDescriptor::TYPE_GROUP: {
+        parent_unknown_fields->AddGroup((*iter)->number())
+            ->MergeFrom(*unknown_fields);
+        break;
+      }
+
+      default:
+        GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: "
+                   << (*iter)->type();
+        return false;
+    }
+    unknown_fields.reset(parent_unknown_fields.release());
+  }
+
+  // Now merge the UnknownFieldSet corresponding to the top-level message into
+  // the options message.
+  options->GetReflection()->MutableUnknownFields(options)->MergeFrom(
+      *unknown_fields);
+
+  // record the element path of the interpreted option
+  if (field->is_repeated()) {
+    int index = repeated_option_counts_[dest_path]++;
+    dest_path.push_back(index);
+  }
+  interpreted_paths_[src_path] = dest_path;
+
+  return true;
+}
+
+void DescriptorBuilder::OptionInterpreter::UpdateSourceCodeInfo(
+    SourceCodeInfo* info) {
+  if (interpreted_paths_.empty()) {
+    // nothing to do!
+    return;
+  }
+
+  // We find locations that match keys in interpreted_paths_ and
+  // 1) replace the path with the corresponding value in interpreted_paths_
+  // 2) remove any subsequent sub-locations (sub-location is one whose path
+  //    has the parent path as a prefix)
+  //
+  // To avoid quadratic behavior of removing interior rows as we go,
+  // we keep a copy. But we don't actually copy anything until we've
+  // found the first match (so if the source code info has no locations
+  // that need to be changed, there is zero copy overhead).
+
+  RepeatedPtrField<SourceCodeInfo_Location>* locs = info->mutable_location();
+  RepeatedPtrField<SourceCodeInfo_Location> new_locs;
+  bool copying = false;
+
+  std::vector<int> pathv;
+  bool matched = false;
+
+  for (RepeatedPtrField<SourceCodeInfo_Location>::iterator loc = locs->begin();
+       loc != locs->end(); loc++) {
+    if (matched) {
+      // see if this location is in the range to remove
+      bool loc_matches = true;
+      if (loc->path_size() < static_cast<int64_t>(pathv.size())) {
+        loc_matches = false;
+      } else {
+        for (size_t j = 0; j < pathv.size(); j++) {
+          if (loc->path(j) != pathv[j]) {
+            loc_matches = false;
+            break;
+          }
+        }
+      }
+
+      if (loc_matches) {
+        // don't copy this row since it is a sub-location that we're removing
+        continue;
+      }
+
+      matched = false;
+    }
+
+    pathv.clear();
+    for (int j = 0; j < loc->path_size(); j++) {
+      pathv.push_back(loc->path(j));
+    }
+
+    std::map<std::vector<int>, std::vector<int>>::iterator entry =
+        interpreted_paths_.find(pathv);
+
+    if (entry == interpreted_paths_.end()) {
+      // not a match
+      if (copying) {
+        *new_locs.Add() = *loc;
+      }
+      continue;
+    }
+
+    matched = true;
+
+    if (!copying) {
+      // initialize the copy we are building
+      copying = true;
+      new_locs.Reserve(locs->size());
+      for (RepeatedPtrField<SourceCodeInfo_Location>::iterator it =
+               locs->begin();
+           it != loc; it++) {
+        *new_locs.Add() = *it;
+      }
+    }
+
+    // add replacement and update its path
+    SourceCodeInfo_Location* replacement = new_locs.Add();
+    *replacement = *loc;
+    replacement->clear_path();
+    for (std::vector<int>::iterator rit = entry->second.begin();
+         rit != entry->second.end(); rit++) {
+      replacement->add_path(*rit);
+    }
+  }
+
+  // if we made a changed copy, put it in place
+  if (copying) {
+    *locs = new_locs;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting(
+    const UninterpretedOption& uninterpreted_option, Message* options) {
+  const FieldDescriptor* field =
+      options->GetDescriptor()->FindFieldByName("uninterpreted_option");
+  GOOGLE_CHECK(field != nullptr);
+
+  options->GetReflection()
+      ->AddMessage(options, field)
+      ->CopyFrom(uninterpreted_option);
+}
+
+bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
+    std::vector<const FieldDescriptor*>::const_iterator
+        intermediate_fields_iter,
+    std::vector<const FieldDescriptor*>::const_iterator intermediate_fields_end,
+    const FieldDescriptor* innermost_field, const std::string& debug_msg_name,
+    const UnknownFieldSet& unknown_fields) {
+  // We do linear searches of the UnknownFieldSet and its sub-groups.  This
+  // should be fine since it's unlikely that any one options structure will
+  // contain more than a handful of options.
+
+  if (intermediate_fields_iter == intermediate_fields_end) {
+    // We're at the innermost submessage.
+    for (int i = 0; i < unknown_fields.field_count(); i++) {
+      if (unknown_fields.field(i).number() == innermost_field->number()) {
+        return AddNameError("Option \"" + debug_msg_name +
+                            "\" was already set.");
+      }
+    }
+    return true;
+  }
+
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    if (unknown_fields.field(i).number() ==
+        (*intermediate_fields_iter)->number()) {
+      const UnknownField* unknown_field = &unknown_fields.field(i);
+      FieldDescriptor::Type type = (*intermediate_fields_iter)->type();
+      // Recurse into the next submessage.
+      switch (type) {
+        case FieldDescriptor::TYPE_MESSAGE:
+          if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+            UnknownFieldSet intermediate_unknown_fields;
+            if (intermediate_unknown_fields.ParseFromString(
+                    unknown_field->length_delimited()) &&
+                !ExamineIfOptionIsSet(intermediate_fields_iter + 1,
+                                      intermediate_fields_end, innermost_field,
+                                      debug_msg_name,
+                                      intermediate_unknown_fields)) {
+              return false;  // Error already added.
+            }
+          }
+          break;
+
+        case FieldDescriptor::TYPE_GROUP:
+          if (unknown_field->type() == UnknownField::TYPE_GROUP) {
+            if (!ExamineIfOptionIsSet(intermediate_fields_iter + 1,
+                                      intermediate_fields_end, innermost_field,
+                                      debug_msg_name, unknown_field->group())) {
+              return false;  // Error already added.
+            }
+          }
+          break;
+
+        default:
+          GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type;
+          return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
+    const FieldDescriptor* option_field, UnknownFieldSet* unknown_fields) {
+  // We switch on the CppType to validate.
+  switch (option_field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        if (uninterpreted_option_->positive_int_value() >
+            static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
+          return AddValueError("Value out of range for int32 option \"" +
+                               option_field->full_name() + "\".");
+        } else {
+          SetInt32(option_field->number(),
+                   uninterpreted_option_->positive_int_value(),
+                   option_field->type(), unknown_fields);
+        }
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        if (uninterpreted_option_->negative_int_value() <
+            static_cast<int64_t>(std::numeric_limits<int32_t>::min())) {
+          return AddValueError("Value out of range for int32 option \"" +
+                               option_field->full_name() + "\".");
+        } else {
+          SetInt32(option_field->number(),
+                   uninterpreted_option_->negative_int_value(),
+                   option_field->type(), unknown_fields);
+        }
+      } else {
+        return AddValueError("Value must be integer for int32 option \"" +
+                             option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_INT64:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        if (uninterpreted_option_->positive_int_value() >
+            static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+          return AddValueError("Value out of range for int64 option \"" +
+                               option_field->full_name() + "\".");
+        } else {
+          SetInt64(option_field->number(),
+                   uninterpreted_option_->positive_int_value(),
+                   option_field->type(), unknown_fields);
+        }
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        SetInt64(option_field->number(),
+                 uninterpreted_option_->negative_int_value(),
+                 option_field->type(), unknown_fields);
+      } else {
+        return AddValueError("Value must be integer for int64 option \"" +
+                             option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_UINT32:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        if (uninterpreted_option_->positive_int_value() >
+            std::numeric_limits<uint32_t>::max()) {
+          return AddValueError("Value out of range for uint32 option \"" +
+                               option_field->name() + "\".");
+        } else {
+          SetUInt32(option_field->number(),
+                    uninterpreted_option_->positive_int_value(),
+                    option_field->type(), unknown_fields);
+        }
+      } else {
+        return AddValueError(
+            "Value must be non-negative integer for uint32 "
+            "option \"" +
+            option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_UINT64:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        SetUInt64(option_field->number(),
+                  uninterpreted_option_->positive_int_value(),
+                  option_field->type(), unknown_fields);
+      } else {
+        return AddValueError(
+            "Value must be non-negative integer for uint64 "
+            "option \"" +
+            option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value;
+      if (uninterpreted_option_->has_double_value()) {
+        value = uninterpreted_option_->double_value();
+      } else if (uninterpreted_option_->has_positive_int_value()) {
+        value = uninterpreted_option_->positive_int_value();
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        value = uninterpreted_option_->negative_int_value();
+      } else {
+        return AddValueError("Value must be number for float option \"" +
+                             option_field->full_name() + "\".");
+      }
+      unknown_fields->AddFixed32(option_field->number(),
+                                 internal::WireFormatLite::EncodeFloat(value));
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value;
+      if (uninterpreted_option_->has_double_value()) {
+        value = uninterpreted_option_->double_value();
+      } else if (uninterpreted_option_->has_positive_int_value()) {
+        value = uninterpreted_option_->positive_int_value();
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        value = uninterpreted_option_->negative_int_value();
+      } else {
+        return AddValueError("Value must be number for double option \"" +
+                             option_field->full_name() + "\".");
+      }
+      unknown_fields->AddFixed64(option_field->number(),
+                                 internal::WireFormatLite::EncodeDouble(value));
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      uint64_t value;
+      if (!uninterpreted_option_->has_identifier_value()) {
+        return AddValueError(
+            "Value must be identifier for boolean option "
+            "\"" +
+            option_field->full_name() + "\".");
+      }
+      if (uninterpreted_option_->identifier_value() == "true") {
+        value = 1;
+      } else if (uninterpreted_option_->identifier_value() == "false") {
+        value = 0;
+      } else {
+        return AddValueError(
+            "Value must be \"true\" or \"false\" for boolean "
+            "option \"" +
+            option_field->full_name() + "\".");
+      }
+      unknown_fields->AddVarint(option_field->number(), value);
+      break;
+
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      if (!uninterpreted_option_->has_identifier_value()) {
+        return AddValueError(
+            "Value must be identifier for enum-valued option "
+            "\"" +
+            option_field->full_name() + "\".");
+      }
+      const EnumDescriptor* enum_type = option_field->enum_type();
+      const std::string& value_name = uninterpreted_option_->identifier_value();
+      const EnumValueDescriptor* enum_value = nullptr;
+
+      if (enum_type->file()->pool() != DescriptorPool::generated_pool()) {
+        // Note that the enum value's fully-qualified name is a sibling of the
+        // enum's name, not a child of it.
+        std::string fully_qualified_name = enum_type->full_name();
+        fully_qualified_name.resize(fully_qualified_name.size() -
+                                    enum_type->name().size());
+        fully_qualified_name += value_name;
+
+        // Search for the enum value's descriptor in the builder's pool. Note
+        // that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
+        // DescriptorPool::FindEnumValueByName() because we're already holding
+        // the pool's mutex, and the latter method locks it again.
+        Symbol symbol =
+            builder_->FindSymbolNotEnforcingDeps(fully_qualified_name);
+        if (auto* candicate_descriptor = symbol.enum_value_descriptor()) {
+          if (candicate_descriptor->type() != enum_type) {
+            return AddValueError(
+                "Enum type \"" + enum_type->full_name() +
+                "\" has no value named \"" + value_name + "\" for option \"" +
+                option_field->full_name() +
+                "\". This appears to be a value from a sibling type.");
+          } else {
+            enum_value = candicate_descriptor;
+          }
+        }
+      } else {
+        // The enum type is in the generated pool, so we can search for the
+        // value there.
+        enum_value = enum_type->FindValueByName(value_name);
+      }
+
+      if (enum_value == nullptr) {
+        return AddValueError("Enum type \"" +
+                             option_field->enum_type()->full_name() +
+                             "\" has no value named \"" + value_name +
+                             "\" for "
+                             "option \"" +
+                             option_field->full_name() + "\".");
+      } else {
+        // Sign-extension is not a problem, since we cast directly from int32_t
+        // to uint64_t, without first going through uint32_t.
+        unknown_fields->AddVarint(
+            option_field->number(),
+            static_cast<uint64_t>(static_cast<int64_t>(enum_value->number())));
+      }
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (!uninterpreted_option_->has_string_value()) {
+        return AddValueError(
+            "Value must be quoted string for string option "
+            "\"" +
+            option_field->full_name() + "\".");
+      }
+      // The string has already been unquoted and unescaped by the parser.
+      unknown_fields->AddLengthDelimited(option_field->number(),
+                                         uninterpreted_option_->string_value());
+      break;
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      if (!SetAggregateOption(option_field, unknown_fields)) {
+        return false;
+      }
+      break;
+  }
+
+  return true;
+}
+
+class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder
+    : public TextFormat::Finder {
+ public:
+  DescriptorBuilder* builder_;
+
+  const Descriptor* FindAnyType(const Message& /*message*/,
+                                const std::string& prefix,
+                                const std::string& name) const override {
+    if (prefix != internal::kTypeGoogleApisComPrefix &&
+        prefix != internal::kTypeGoogleProdComPrefix) {
+      return nullptr;
+    }
+    assert_mutex_held(builder_->pool_);
+    return builder_->FindSymbol(name).descriptor();
+  }
+
+  const FieldDescriptor* FindExtension(Message* message,
+                                       const std::string& name) const override {
+    assert_mutex_held(builder_->pool_);
+    const Descriptor* descriptor = message->GetDescriptor();
+    Symbol result =
+        builder_->LookupSymbolNoPlaceholder(name, descriptor->full_name());
+    if (auto* field = result.field_descriptor()) {
+      return field;
+    } else if (result.type() == Symbol::MESSAGE &&
+               descriptor->options().message_set_wire_format()) {
+      const Descriptor* foreign_type = result.descriptor();
+      // The text format allows MessageSet items to be specified using
+      // the type name, rather than the extension identifier. If the symbol
+      // lookup returned a Message, and the enclosing Message has
+      // message_set_wire_format = true, then return the message set
+      // extension, if one exists.
+      for (int i = 0; i < foreign_type->extension_count(); i++) {
+        const FieldDescriptor* extension = foreign_type->extension(i);
+        if (extension->containing_type() == descriptor &&
+            extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+            extension->is_optional() &&
+            extension->message_type() == foreign_type) {
+          // Found it.
+          return extension;
+        }
+      }
+    }
+    return nullptr;
+  }
+};
+
+// A custom error collector to record any text-format parsing errors
+namespace {
+class AggregateErrorCollector : public io::ErrorCollector {
+ public:
+  std::string error_;
+
+  void AddError(int /* line */, int /* column */,
+                const std::string& message) override {
+    if (!error_.empty()) {
+      error_ += "; ";
+    }
+    error_ += message;
+  }
+
+  void AddWarning(int /* line */, int /* column */,
+                  const std::string& /* message */) override {
+    // Ignore warnings
+  }
+};
+}  // namespace
+
+// We construct a dynamic message of the type corresponding to
+// option_field, parse the supplied text-format string into this
+// message, and serialize the resulting message to produce the value.
+bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
+    const FieldDescriptor* option_field, UnknownFieldSet* unknown_fields) {
+  if (!uninterpreted_option_->has_aggregate_value()) {
+    return AddValueError("Option \"" + option_field->full_name() +
+                         "\" is a message. To set the entire message, use "
+                         "syntax like \"" +
+                         option_field->name() +
+                         " = { <proto text format> }\". "
+                         "To set fields within it, use "
+                         "syntax like \"" +
+                         option_field->name() + ".foo = value\".");
+  }
+
+  const Descriptor* type = option_field->message_type();
+  std::unique_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
+  GOOGLE_CHECK(dynamic.get() != nullptr)
+      << "Could not create an instance of " << option_field->DebugString();
+
+  AggregateErrorCollector collector;
+  AggregateOptionFinder finder;
+  finder.builder_ = builder_;
+  TextFormat::Parser parser;
+  parser.RecordErrorsTo(&collector);
+  parser.SetFinder(&finder);
+  if (!parser.ParseFromString(uninterpreted_option_->aggregate_value(),
+                              dynamic.get())) {
+    AddValueError("Error while parsing option value for \"" +
+                  option_field->name() + "\": " + collector.error_);
+    return false;
+  } else {
+    std::string serial;
+    dynamic->SerializeToString(&serial);  // Never fails
+    if (option_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      unknown_fields->AddLengthDelimited(option_field->number(), serial);
+    } else {
+      GOOGLE_CHECK_EQ(option_field->type(), FieldDescriptor::TYPE_GROUP);
+      UnknownFieldSet* group = unknown_fields->AddGroup(option_field->number());
+      group->ParseFromString(serial);
+    }
+    return true;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetInt32(
+    int number, int32_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT32:
+      unknown_fields->AddVarint(
+          number, static_cast<uint64_t>(static_cast<int64_t>(value)));
+      break;
+
+    case FieldDescriptor::TYPE_SFIXED32:
+      unknown_fields->AddFixed32(number, static_cast<uint32_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_SINT32:
+      unknown_fields->AddVarint(
+          number, internal::WireFormatLite::ZigZagEncode32(value));
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT32: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetInt64(
+    int number, int64_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT64:
+      unknown_fields->AddVarint(number, static_cast<uint64_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_SFIXED64:
+      unknown_fields->AddFixed64(number, static_cast<uint64_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_SINT64:
+      unknown_fields->AddVarint(
+          number, internal::WireFormatLite::ZigZagEncode64(value));
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT64: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetUInt32(
+    int number, uint32_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_UINT32:
+      unknown_fields->AddVarint(number, static_cast<uint64_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_FIXED32:
+      unknown_fields->AddFixed32(number, static_cast<uint32_t>(value));
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT32: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetUInt64(
+    int number, uint64_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_UINT64:
+      unknown_fields->AddVarint(number, value);
+      break;
+
+    case FieldDescriptor::TYPE_FIXED64:
+      unknown_fields->AddFixed64(number, value);
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT64: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
+                                            const FileDescriptor* result) {
+  (void)result;  // Parameter is used by Google-internal code.
+
+  if (!unused_dependency_.empty()) {
+    auto itr = pool_->unused_import_track_files_.find(proto.name());
+    bool is_error =
+        itr != pool_->unused_import_track_files_.end() && itr->second;
+    for (std::set<const FileDescriptor*>::const_iterator it =
+             unused_dependency_.begin();
+         it != unused_dependency_.end(); ++it) {
+      std::string error_message = "Import " + (*it)->name() + " is unused.";
+      if (is_error) {
+        AddError((*it)->name(), proto, DescriptorPool::ErrorCollector::IMPORT,
+                 error_message);
+      } else {
+        AddWarning((*it)->name(), proto, DescriptorPool::ErrorCollector::IMPORT,
+                   error_message);
+      }
+    }
+  }
+}
+
+Symbol DescriptorPool::CrossLinkOnDemandHelper(StringPiece name,
+                                               bool expecting_enum) const {
+  (void)expecting_enum;  // Parameter is used by Google-internal code.
+  auto lookup_name = std::string(name);
+  if (!lookup_name.empty() && lookup_name[0] == '.') {
+    lookup_name = lookup_name.substr(1);
+  }
+  Symbol result = tables_->FindByNameHelper(this, lookup_name);
+  return result;
+}
+
+// Handle the lazy import building for a message field whose type wasn't built
+// at cross link time. If that was the case, we saved the name of the type to
+// be looked up when the accessor for the type was called. Set type_,
+// enum_type_, message_type_, and default_value_enum_ appropriately.
+void FieldDescriptor::InternalTypeOnceInit() const {
+  GOOGLE_CHECK(file()->finished_building_ == true);
+  const EnumDescriptor* enum_type = nullptr;
+  const char* lazy_type_name = reinterpret_cast<const char*>(type_once_ + 1);
+  const char* lazy_default_value_enum_name =
+      lazy_type_name + strlen(lazy_type_name) + 1;
+  Symbol result = file()->pool()->CrossLinkOnDemandHelper(
+      lazy_type_name, type_ == FieldDescriptor::TYPE_ENUM);
+  if (result.type() == Symbol::MESSAGE) {
+    type_ = FieldDescriptor::TYPE_MESSAGE;
+    type_descriptor_.message_type = result.descriptor();
+  } else if (result.type() == Symbol::ENUM) {
+    type_ = FieldDescriptor::TYPE_ENUM;
+    enum_type = type_descriptor_.enum_type = result.enum_descriptor();
+  }
+
+  if (enum_type) {
+    if (lazy_default_value_enum_name[0] != '\0') {
+      // Have to build the full name now instead of at CrossLink time,
+      // because enum_type may not be known at the time.
+      std::string name = enum_type->full_name();
+      // Enum values reside in the same scope as the enum type.
+      std::string::size_type last_dot = name.find_last_of('.');
+      if (last_dot != std::string::npos) {
+        name = name.substr(0, last_dot) + "." + lazy_default_value_enum_name;
+      } else {
+        name = lazy_default_value_enum_name;
+      }
+      Symbol result = file()->pool()->CrossLinkOnDemandHelper(name, true);
+      default_value_enum_ = result.enum_value_descriptor();
+    } else {
+      default_value_enum_ = nullptr;
+    }
+    if (!default_value_enum_) {
+      // We use the first defined value as the default
+      // if a default is not explicitly defined.
+      GOOGLE_CHECK(enum_type->value_count());
+      default_value_enum_ = enum_type->value(0);
+    }
+  }
+}
+
+void FieldDescriptor::TypeOnceInit(const FieldDescriptor* to_init) {
+  to_init->InternalTypeOnceInit();
+}
+
+// message_type(), enum_type(), default_value_enum(), and type()
+// all share the same internal::call_once init path to do lazy
+// import building and cross linking of a field of a message.
+const Descriptor* FieldDescriptor::message_type() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+  }
+  return type_ == TYPE_MESSAGE || type_ == TYPE_GROUP
+             ? type_descriptor_.message_type
+             : nullptr;
+}
+
+const EnumDescriptor* FieldDescriptor::enum_type() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+  }
+  return type_ == TYPE_ENUM ? type_descriptor_.enum_type : nullptr;
+}
+
+const EnumValueDescriptor* FieldDescriptor::default_value_enum() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+  }
+  return default_value_enum_;
+}
+
+const std::string& FieldDescriptor::PrintableNameForExtension() const {
+  const bool is_message_set_extension =
+      is_extension() &&
+      containing_type()->options().message_set_wire_format() &&
+      type() == FieldDescriptor::TYPE_MESSAGE && is_optional() &&
+      extension_scope() == message_type();
+  return is_message_set_extension ? message_type()->full_name() : full_name();
+}
+
+void FileDescriptor::InternalDependenciesOnceInit() const {
+  GOOGLE_CHECK(finished_building_ == true);
+  const char* names_ptr = reinterpret_cast<const char*>(dependencies_once_ + 1);
+  for (int i = 0; i < dependency_count(); i++) {
+    const char* name = names_ptr;
+    names_ptr += strlen(name) + 1;
+    if (name[0] != '\0') {
+      dependencies_[i] = pool_->FindFileByName(name);
+    }
+  }
+}
+
+void FileDescriptor::DependenciesOnceInit(const FileDescriptor* to_init) {
+  to_init->InternalDependenciesOnceInit();
+}
+
+const FileDescriptor* FileDescriptor::dependency(int index) const {
+  if (dependencies_once_) {
+    // Do once init for all indices, as it's unlikely only a single index would
+    // be called, and saves on internal::call_once allocations.
+    internal::call_once(*dependencies_once_,
+                        FileDescriptor::DependenciesOnceInit, this);
+  }
+  return dependencies_[index];
+}
+
+const Descriptor* MethodDescriptor::input_type() const {
+  return input_type_.Get(service());
+}
+
+const Descriptor* MethodDescriptor::output_type() const {
+  return output_type_.Get(service());
+}
+
+namespace internal {
+void LazyDescriptor::Set(const Descriptor* descriptor) {
+  GOOGLE_CHECK(!once_);
+  descriptor_ = descriptor;
+}
+
+void LazyDescriptor::SetLazy(StringPiece name,
+                             const FileDescriptor* file) {
+  // verify Init() has been called and Set hasn't been called yet.
+  GOOGLE_CHECK(!descriptor_);
+  GOOGLE_CHECK(!once_);
+  GOOGLE_CHECK(file && file->pool_);
+  GOOGLE_CHECK(file->pool_->lazily_build_dependencies_);
+  GOOGLE_CHECK(!file->finished_building_);
+  once_ = ::new (file->pool_->tables_->AllocateBytes(static_cast<int>(
+      sizeof(internal::once_flag) + name.size() + 1))) internal::once_flag{};
+  char* lazy_name = reinterpret_cast<char*>(once_ + 1);
+  memcpy(lazy_name, name.data(), name.size());
+  lazy_name[name.size()] = 0;
+}
+
+void LazyDescriptor::Once(const ServiceDescriptor* service) {
+  if (once_) {
+    internal::call_once(*once_, [&] {
+      auto* file = service->file();
+      GOOGLE_CHECK(file->finished_building_);
+      const char* lazy_name = reinterpret_cast<const char*>(once_ + 1);
+      descriptor_ =
+          file->pool_->CrossLinkOnDemandHelper(lazy_name, false).descriptor();
+    });
+  }
+}
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
new file mode 100644
index 0000000..6e536e5
--- /dev/null
+++ b/src/google/protobuf/descriptor.h
@@ -0,0 +1,2440 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 classes which describe a type of protocol message.
+// You can use a message's descriptor to learn at runtime what fields
+// it contains and what the types of those fields are.  The Message
+// interface also allows you to dynamically access and modify individual
+// fields by passing the FieldDescriptor of the field you are interested
+// in.
+//
+// Most users will not care about descriptors, because they will write
+// code specific to certain protocol types and will simply use the classes
+// generated by the protocol compiler directly.  Advanced users who want
+// to operate on arbitrary types (not known at compile time) may want to
+// read descriptors in order to learn about the contents of a message.
+// A very small number of users will want to construct their own
+// Descriptors, either because they are implementing Message manually or
+// because they are writing something like the protocol compiler.
+//
+// For an example of how you might use descriptors, see the code example
+// at the top of message.h.
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
+#define GOOGLE_PROTOBUF_DESCRIPTOR_H__
+
+
+#include <atomic>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#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/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
+#ifdef TYPE_BOOL
+#undef TYPE_BOOL
+#endif  // TYPE_BOOL
+
+#ifdef SWIG
+#define PROTOBUF_EXPORT
+#endif
+
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Descriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class ServiceDescriptor;
+class MethodDescriptor;
+class FileDescriptor;
+class DescriptorDatabase;
+class DescriptorPool;
+
+// Defined in descriptor.proto
+class DescriptorProto;
+class DescriptorProto_ExtensionRange;
+class FieldDescriptorProto;
+class OneofDescriptorProto;
+class EnumDescriptorProto;
+class EnumValueDescriptorProto;
+class ServiceDescriptorProto;
+class MethodDescriptorProto;
+class FileDescriptorProto;
+class MessageOptions;
+class FieldOptions;
+class OneofOptions;
+class EnumOptions;
+class EnumValueOptions;
+class ExtensionRangeOptions;
+class ServiceOptions;
+class MethodOptions;
+class FileOptions;
+class UninterpretedOption;
+class SourceCodeInfo;
+
+// Defined in message.h
+class Message;
+class Reflection;
+
+// Defined in descriptor.cc
+class DescriptorBuilder;
+class FileDescriptorTables;
+class Symbol;
+
+// Defined in unknown_field_set.h.
+class UnknownField;
+
+// Defined in command_line_interface.cc
+namespace compiler {
+class CommandLineInterface;
+namespace cpp {
+// Defined in helpers.h
+class Formatter;
+}  // namespace cpp
+}  // namespace compiler
+
+namespace descriptor_unittest {
+class DescriptorTest;
+}  // namespace descriptor_unittest
+
+// Defined in printer.h
+namespace io {
+class Printer;
+}  // namespace io
+
+// NB, all indices are zero-based.
+struct SourceLocation {
+  int start_line;
+  int end_line;
+  int start_column;
+  int end_column;
+
+  // Doc comments found at the source location.
+  // See the comments in SourceCodeInfo.Location (descriptor.proto) for details.
+  std::string leading_comments;
+  std::string trailing_comments;
+  std::vector<std::string> leading_detached_comments;
+};
+
+// Options when generating machine-parsable output from a descriptor with
+// DebugString().
+struct DebugStringOptions {
+  // include original user comments as recorded in SourceLocation entries. N.B.
+  // that this must be |false| by default: several other pieces of code (for
+  // example, the C++ code generation for fields in the proto compiler) rely on
+  // DebugString() output being unobstructed by user comments.
+  bool include_comments;
+  // If true, elide the braced body in the debug string.
+  bool elide_group_body;
+  bool elide_oneof_body;
+
+  DebugStringOptions()
+      : include_comments(false),
+        elide_group_body(false),
+        elide_oneof_body(false) {
+  }
+};
+
+// A class to handle the simplest cases of a lazily linked descriptor
+// for a message type that isn't built at the time of cross linking,
+// which is needed when a pool has lazily_build_dependencies_ set.
+// Must be instantiated as mutable in a descriptor.
+namespace internal {
+
+// The classes in this file represent a significant memory footprint for the
+// library. We make sure we are not accidentally making them larger by
+// hardcoding the struct size for a specific platform. Use as:
+//
+//   PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(type, expected_size_in_x84-64);
+//
+
+#if !defined(PROTOBUF_INTERNAL_CHECK_CLASS_SIZE)
+#define PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(t, expected)
+#endif
+
+class FlatAllocator;
+
+class PROTOBUF_EXPORT LazyDescriptor {
+ public:
+  // Init function to be called at init time of a descriptor containing
+  // a LazyDescriptor.
+  void Init() {
+    descriptor_ = nullptr;
+    once_ = nullptr;
+  }
+
+  // Sets the value of the descriptor if it is known during the descriptor
+  // building process. Not thread safe, should only be called during the
+  // descriptor build process. Should not be called after SetLazy has been
+  // called.
+  void Set(const Descriptor* descriptor);
+
+  // Sets the information needed to lazily cross link the descriptor at a later
+  // time, SetLazy is not thread safe, should be called only once at descriptor
+  // build time if the symbol wasn't found and building of the file containing
+  // that type is delayed because lazily_build_dependencies_ is set on the pool.
+  // Should not be called after Set() has been called.
+  void SetLazy(StringPiece name, const FileDescriptor* file);
+
+  // Returns the current value of the descriptor, thread-safe. If SetLazy(...)
+  // has been called, will do a one-time cross link of the type specified,
+  // building the descriptor file that contains the type if necessary.
+  inline const Descriptor* Get(const ServiceDescriptor* service) {
+    Once(service);
+    return descriptor_;
+  }
+
+ private:
+  void Once(const ServiceDescriptor* service);
+
+  const Descriptor* descriptor_;
+  // The once_ flag is followed by a NUL terminated string for the type name.
+  internal::once_flag* once_;
+};
+
+class PROTOBUF_EXPORT SymbolBase {
+ private:
+  friend class google::protobuf::Symbol;
+  uint8_t symbol_type_;
+};
+
+// Some types have more than one SymbolBase because they have multiple
+// identities in the table. We can't have duplicate direct bases, so we use this
+// intermediate base to do so.
+// See BuildEnumValue for details.
+template <int N>
+class PROTOBUF_EXPORT SymbolBaseN : public SymbolBase {};
+
+}  // namespace internal
+
+// Describes a type of protocol message, or a particular group within a
+// message.  To obtain the Descriptor for a given message object, call
+// Message::GetDescriptor().  Generated message classes also have a
+// static method called descriptor() which returns the type's descriptor.
+// Use DescriptorPool to construct your own descriptors.
+class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
+ public:
+  typedef DescriptorProto Proto;
+
+  // The name of the message type, not including its scope.
+  const std::string& name() const;
+
+  // The fully-qualified name of the message type, scope delimited by
+  // periods.  For example, message type "Foo" which is declared in package
+  // "bar" has full name "bar.Foo".  If a type "Baz" is nested within
+  // Foo, Baz's full_name is "bar.Foo.Baz".  To get only the part that
+  // comes after the last '.', use name().
+  const std::string& full_name() const;
+
+  // Index of this descriptor within the file or containing type's message
+  // type array.
+  int index() const;
+
+  // The .proto file in which this message type was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+
+  // If this Descriptor describes a nested type, this returns the type
+  // in which it is nested.  Otherwise, returns nullptr.
+  const Descriptor* containing_type() const;
+
+  // Get options for this message type.  These are specified in the .proto file
+  // by placing lines like "option foo = 1234;" in the message definition.
+  // Allowed options are defined by MessageOptions in descriptor.proto, and any
+  // available extensions of that message.
+  const MessageOptions& options() const;
+
+  // Write the contents of this Descriptor into the given DescriptorProto.
+  // The target DescriptorProto must be clear before calling this; if it
+  // isn't, the result may be garbage.
+  void CopyTo(DescriptorProto* proto) const;
+
+  // Write the contents of this descriptor in a human-readable form. Output
+  // will be suitable for re-parsing.
+  std::string DebugString() const;
+
+  // Similar to DebugString(), but additionally takes options (e.g.,
+  // include original user comments in output).
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Returns true if this is a placeholder for an unknown type. This will
+  // only be the case if this descriptor comes from a DescriptorPool
+  // with AllowUnknownDependencies() set.
+  bool is_placeholder() const;
+
+  enum WellKnownType {
+    WELLKNOWNTYPE_UNSPECIFIED,  // Not a well-known type.
+
+    // Wrapper types.
+    WELLKNOWNTYPE_DOUBLEVALUE,  // google.protobuf.DoubleValue
+    WELLKNOWNTYPE_FLOATVALUE,   // google.protobuf.FloatValue
+    WELLKNOWNTYPE_INT64VALUE,   // google.protobuf.Int64Value
+    WELLKNOWNTYPE_UINT64VALUE,  // google.protobuf.UInt64Value
+    WELLKNOWNTYPE_INT32VALUE,   // google.protobuf.Int32Value
+    WELLKNOWNTYPE_UINT32VALUE,  // google.protobuf.UInt32Value
+    WELLKNOWNTYPE_STRINGVALUE,  // google.protobuf.StringValue
+    WELLKNOWNTYPE_BYTESVALUE,   // google.protobuf.BytesValue
+    WELLKNOWNTYPE_BOOLVALUE,    // google.protobuf.BoolValue
+
+    // Other well known types.
+    WELLKNOWNTYPE_ANY,        // google.protobuf.Any
+    WELLKNOWNTYPE_FIELDMASK,  // google.protobuf.FieldMask
+    WELLKNOWNTYPE_DURATION,   // google.protobuf.Duration
+    WELLKNOWNTYPE_TIMESTAMP,  // google.protobuf.Timestamp
+    WELLKNOWNTYPE_VALUE,      // google.protobuf.Value
+    WELLKNOWNTYPE_LISTVALUE,  // google.protobuf.ListValue
+    WELLKNOWNTYPE_STRUCT,     // google.protobuf.Struct
+
+    // New well-known types may be added in the future.
+    // Please make sure any switch() statements have a 'default' case.
+    __WELLKNOWNTYPE__DO_NOT_USE__ADD_DEFAULT_INSTEAD__,
+  };
+
+  WellKnownType well_known_type() const;
+
+  // Field stuff -----------------------------------------------------
+
+  // The number of fields in this message type.
+  int field_count() const;
+  // Gets a field by index, where 0 <= index < field_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FieldDescriptor* field(int index) const;
+
+  // Looks up a field by declared tag number.  Returns nullptr if no such field
+  // exists.
+  const FieldDescriptor* FindFieldByNumber(int number) const;
+  // Looks up a field by name.  Returns nullptr if no such field exists.
+  const FieldDescriptor* FindFieldByName(ConstStringParam name) const;
+
+  // Looks up a field by lowercased name (as returned by lowercase_name()).
+  // This lookup may be ambiguous if multiple field names differ only by case,
+  // in which case the field returned is chosen arbitrarily from the matches.
+  const FieldDescriptor* FindFieldByLowercaseName(
+      ConstStringParam lowercase_name) const;
+
+  // Looks up a field by camel-case name (as returned by camelcase_name()).
+  // This lookup may be ambiguous if multiple field names differ in a way that
+  // leads them to have identical camel-case names, in which case the field
+  // returned is chosen arbitrarily from the matches.
+  const FieldDescriptor* FindFieldByCamelcaseName(
+      ConstStringParam camelcase_name) const;
+
+  // The number of oneofs in this message type.
+  int oneof_decl_count() const;
+  // The number of oneofs in this message type, excluding synthetic oneofs.
+  // Real oneofs always come first, so iterating up to real_oneof_decl_cout()
+  // will yield all real oneofs.
+  int real_oneof_decl_count() const;
+  // Get a oneof by index, where 0 <= index < oneof_decl_count().
+  // These are returned in the order they were defined in the .proto file.
+  const OneofDescriptor* oneof_decl(int index) const;
+
+  // Looks up a oneof by name.  Returns nullptr if no such oneof exists.
+  const OneofDescriptor* FindOneofByName(ConstStringParam name) const;
+
+  // Nested type stuff -----------------------------------------------
+
+  // The number of nested types in this message type.
+  int nested_type_count() const;
+  // Gets a nested type by index, where 0 <= index < nested_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const Descriptor* nested_type(int index) const;
+
+  // Looks up a nested type by name.  Returns nullptr if no such nested type
+  // exists.
+  const Descriptor* FindNestedTypeByName(ConstStringParam name) const;
+
+  // Enum stuff ------------------------------------------------------
+
+  // The number of enum types in this message type.
+  int enum_type_count() const;
+  // Gets an enum type by index, where 0 <= index < enum_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const EnumDescriptor* enum_type(int index) const;
+
+  // Looks up an enum type by name.  Returns nullptr if no such enum type
+  // exists.
+  const EnumDescriptor* FindEnumTypeByName(ConstStringParam name) const;
+
+  // Looks up an enum value by name, among all enum types in this message.
+  // Returns nullptr if no such value exists.
+  const EnumValueDescriptor* FindEnumValueByName(ConstStringParam name) const;
+
+  // Extensions ------------------------------------------------------
+
+  // A range of field numbers which are designated for third-party
+  // extensions.
+  struct ExtensionRange {
+    typedef DescriptorProto_ExtensionRange Proto;
+
+    typedef ExtensionRangeOptions OptionsType;
+
+    // See Descriptor::CopyTo().
+    void CopyTo(DescriptorProto_ExtensionRange* proto) const;
+
+    int start;  // inclusive
+    int end;    // exclusive
+
+    const ExtensionRangeOptions* options_;
+  };
+
+  // The number of extension ranges in this message type.
+  int extension_range_count() const;
+  // Gets an extension range by index, where 0 <= index <
+  // extension_range_count(). These are returned in the order they were defined
+  // in the .proto file.
+  const ExtensionRange* extension_range(int index) const;
+
+  // Returns true if the number is in one of the extension ranges.
+  bool IsExtensionNumber(int number) const;
+
+  // Returns nullptr if no extension range contains the given number.
+  const ExtensionRange* FindExtensionRangeContainingNumber(int number) const;
+
+  // The number of extensions defined nested within this message type's scope.
+  // See doc:
+  // https://developers.google.com/protocol-buffers/docs/proto#nested-extensions
+  //
+  // Note that the extensions may be extending *other* messages.
+  //
+  // For example:
+  // message M1 {
+  //   extensions 1 to max;
+  // }
+  //
+  // message M2 {
+  //   extend M1 {
+  //     optional int32 foo = 1;
+  //   }
+  // }
+  //
+  // In this case,
+  // DescriptorPool::generated_pool()
+  //     ->FindMessageTypeByName("M2")
+  //     ->extension(0)
+  // will return "foo", even though "foo" is an extension of M1.
+  // To find all known extensions of a given message, instead use
+  // DescriptorPool::FindAllExtensions.
+  int extension_count() const;
+  // Get an extension by index, where 0 <= index < extension_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FieldDescriptor* extension(int index) const;
+
+  // Looks up a named extension (which extends some *other* message type)
+  // defined within this message type's scope.
+  const FieldDescriptor* FindExtensionByName(ConstStringParam name) const;
+
+  // Similar to FindFieldByLowercaseName(), but finds extensions defined within
+  // this message type's scope.
+  const FieldDescriptor* FindExtensionByLowercaseName(
+      ConstStringParam name) const;
+
+  // Similar to FindFieldByCamelcaseName(), but finds extensions defined within
+  // this message type's scope.
+  const FieldDescriptor* FindExtensionByCamelcaseName(
+      ConstStringParam 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 nullptr 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 std::string& reserved_name(int index) const;
+
+  // Returns true if the field name is reserved.
+  bool IsReservedName(ConstStringParam name) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this message declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+  // Maps --------------------------------------------------------------
+
+  // Returns the FieldDescriptor for the "key" field. If this isn't a map entry
+  // field, returns nullptr.
+  const FieldDescriptor* map_key() const;
+
+  // Returns the FieldDescriptor for the "value" field. If this isn't a map
+  // entry field, returns nullptr.
+  const FieldDescriptor* map_value() const;
+
+ private:
+  friend class Symbol;
+  typedef MessageOptions OptionsType;
+
+  // Allows tests to test CopyTo(proto, true).
+  friend class descriptor_unittest::DescriptorTest;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // 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
+  // clause has already been generated (this varies depending on context).
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options,
+                   bool include_opening_clause) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // True if this is a placeholder for an unknown type.
+  bool is_placeholder_ : 1;
+  // True if this is a placeholder and the type name wasn't fully-qualified.
+  bool is_unqualified_placeholder_ : 1;
+  // Well known type.  Stored like this to conserve space.
+  uint8_t well_known_type_ : 5;
+
+  // This points to the last field _number_ that is part of the sequence
+  // starting at 1, where
+  //     `desc->field(i)->number() == i + 1`
+  // A value of `0` means no field matches. That is, there are no fields or the
+  // first field is not field `1`.
+  // Uses 16-bit to avoid extra padding. Unlikely to have more than 2^16
+  // sequentially numbered fields in a message.
+  uint16_t sequential_field_limit_;
+
+  int field_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const Descriptor* containing_type_;
+  const MessageOptions* options_;
+
+  // These arrays are separated from their sizes to minimize padding on 64-bit.
+  FieldDescriptor* fields_;
+  OneofDescriptor* oneof_decls_;
+  Descriptor* nested_types_;
+  EnumDescriptor* enum_types_;
+  ExtensionRange* extension_ranges_;
+  FieldDescriptor* extensions_;
+  ReservedRange* reserved_ranges_;
+  const std::string** reserved_names_;
+
+  int oneof_decl_count_;
+  int real_oneof_decl_count_;
+  int nested_type_count_;
+  int enum_type_count_;
+  int extension_range_count_;
+  int extension_count_;
+  int reserved_range_count_;
+  int reserved_name_count_;
+
+  // 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.
+
+  // Must be constructed using DescriptorPool.
+  Descriptor() {}
+  friend class DescriptorBuilder;
+  friend class DescriptorPool;
+  friend class EnumDescriptor;
+  friend class FieldDescriptor;
+  friend class FileDescriptorTables;
+  friend class OneofDescriptor;
+  friend class MethodDescriptor;
+  friend class FileDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 136);
+
+// Describes a single field of a message.  To get the descriptor for a given
+// field, first get the Descriptor for the message in which it is defined,
+// then call Descriptor::FindFieldByName().  To get a FieldDescriptor for
+// an extension, do one of the following:
+// - Get the Descriptor or FileDescriptor for its containing scope, then
+//   call Descriptor::FindExtensionByName() or
+//   FileDescriptor::FindExtensionByName().
+// - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber() or
+//   DescriptorPool::FindExtensionByPrintableName().
+// Use DescriptorPool to construct your own descriptors.
+class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase {
+ public:
+  typedef FieldDescriptorProto Proto;
+
+  // Identifies a field type.  0 is reserved for errors.  The order is weird
+  // for historical reasons.  Types 12 and up are new in proto2.
+  enum Type {
+    TYPE_DOUBLE = 1,    // double, exactly eight bytes on the wire.
+    TYPE_FLOAT = 2,     // float, exactly four bytes on the wire.
+    TYPE_INT64 = 3,     // int64, varint on the wire.  Negative numbers
+                        // take 10 bytes.  Use TYPE_SINT64 if negative
+                        // values are likely.
+    TYPE_UINT64 = 4,    // uint64, varint on the wire.
+    TYPE_INT32 = 5,     // int32, varint on the wire.  Negative numbers
+                        // take 10 bytes.  Use TYPE_SINT32 if negative
+                        // values are likely.
+    TYPE_FIXED64 = 6,   // uint64, exactly eight bytes on the wire.
+    TYPE_FIXED32 = 7,   // uint32, exactly four bytes on the wire.
+    TYPE_BOOL = 8,      // bool, varint on the wire.
+    TYPE_STRING = 9,    // UTF-8 text.
+    TYPE_GROUP = 10,    // Tag-delimited message.  Deprecated.
+    TYPE_MESSAGE = 11,  // Length-delimited message.
+
+    TYPE_BYTES = 12,     // Arbitrary byte array.
+    TYPE_UINT32 = 13,    // uint32, varint on the wire
+    TYPE_ENUM = 14,      // Enum, varint on the wire
+    TYPE_SFIXED32 = 15,  // int32, exactly four bytes on the wire
+    TYPE_SFIXED64 = 16,  // int64, exactly eight bytes on the wire
+    TYPE_SINT32 = 17,    // int32, ZigZag-encoded varint on the wire
+    TYPE_SINT64 = 18,    // int64, ZigZag-encoded varint on the wire
+
+    MAX_TYPE = 18,  // Constant useful for defining lookup tables
+                    // indexed by Type.
+  };
+
+  // Specifies the C++ data type used to represent the field.  There is a
+  // fixed mapping from Type to CppType where each Type maps to exactly one
+  // CppType.  0 is reserved for errors.
+  enum CppType {
+    CPPTYPE_INT32 = 1,     // TYPE_INT32, TYPE_SINT32, TYPE_SFIXED32
+    CPPTYPE_INT64 = 2,     // TYPE_INT64, TYPE_SINT64, TYPE_SFIXED64
+    CPPTYPE_UINT32 = 3,    // TYPE_UINT32, TYPE_FIXED32
+    CPPTYPE_UINT64 = 4,    // TYPE_UINT64, TYPE_FIXED64
+    CPPTYPE_DOUBLE = 5,    // TYPE_DOUBLE
+    CPPTYPE_FLOAT = 6,     // TYPE_FLOAT
+    CPPTYPE_BOOL = 7,      // TYPE_BOOL
+    CPPTYPE_ENUM = 8,      // TYPE_ENUM
+    CPPTYPE_STRING = 9,    // TYPE_STRING, TYPE_BYTES
+    CPPTYPE_MESSAGE = 10,  // TYPE_MESSAGE, TYPE_GROUP
+
+    MAX_CPPTYPE = 10,  // Constant useful for defining lookup tables
+                       // indexed by CppType.
+  };
+
+  // Identifies whether the field is optional, required, or repeated.  0 is
+  // reserved for errors.
+  enum Label {
+    LABEL_OPTIONAL = 1,  // optional
+    LABEL_REQUIRED = 2,  // required
+    LABEL_REPEATED = 3,  // repeated
+
+    MAX_LABEL = 3,  // Constant useful for defining lookup tables
+                    // indexed by Label.
+  };
+
+  // Valid field numbers are positive integers up to kMaxNumber.
+  static const int kMaxNumber = (1 << 29) - 1;
+
+  // First field number reserved for the protocol buffer library implementation.
+  // Users may not declare fields that use reserved numbers.
+  static const int kFirstReservedNumber = 19000;
+  // Last field number reserved for the protocol buffer library implementation.
+  // Users may not declare fields that use reserved numbers.
+  static const int kLastReservedNumber = 19999;
+
+  const std::string& name() const;  // Name of this field within the message.
+  const std::string& full_name() const;  // Fully-qualified name of the field.
+  const std::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.
+
+  // Same as name() except converted to lower-case.  This (and especially the
+  // FindFieldByLowercaseName() method) can be useful when parsing formats
+  // which prefer to use lowercase naming style.  (Although, technically
+  // field names should be lowercased anyway according to the protobuf style
+  // guide, so this only makes a difference when dealing with old .proto files
+  // which do not follow the guide.)
+  const std::string& lowercase_name() const;
+
+  // Same as name() except converted to camel-case.  In this conversion, any
+  // time an underscore appears in the name, it is removed and the next
+  // letter is capitalized.  Furthermore, the first letter of the name is
+  // lower-cased.  Examples:
+  //   FooBar -> fooBar
+  //   foo_bar -> fooBar
+  //   fooBar -> fooBar
+  // This (and especially the FindFieldByCamelcaseName() method) can be useful
+  // when parsing formats which prefer to use camel-case naming style.
+  const std::string& camelcase_name() const;
+
+  Type type() const;                  // Declared type of this field.
+  const char* type_name() const;      // Name of the declared type.
+  CppType cpp_type() const;           // C++ type of this field.
+  const char* cpp_type_name() const;  // Name of the C++ type.
+  Label label() const;                // optional/required/repeated
+
+  bool is_required() const;  // shorthand for label() == LABEL_REQUIRED
+  bool is_optional() const;  // shorthand for label() == LABEL_OPTIONAL
+  bool is_repeated() const;  // shorthand for label() == LABEL_REPEATED
+  bool is_packable() const;  // shorthand for is_repeated() &&
+                             //               IsTypePackable(type())
+  bool is_packed() const;    // shorthand for is_packable() &&
+                             //               options().packed()
+  bool is_map() const;       // shorthand for type() == TYPE_MESSAGE &&
+                             // message_type()->options().map_entry()
+
+  // Returns true if this field was syntactically written with "optional" in the
+  // .proto file. Excludes singular proto3 fields that do not have a label.
+  bool has_optional_keyword() const;
+
+  // Returns true if this field tracks presence, ie. does the field
+  // distinguish between "unset" and "present with default value."
+  // This includes required, optional, and oneof fields. It excludes maps,
+  // repeated fields, and singular proto3 fields without "optional".
+  //
+  // For fields where has_presence() == true, the return value of
+  // Reflection::HasField() is semantically meaningful.
+  bool has_presence() const;
+
+  // Index of this field within the message's field array, or the file or
+  // extension scope's extensions array.
+  int index() const;
+
+  // Does this field have an explicitly-declared default value?
+  bool has_default_value() const;
+
+  // Whether the user has specified the json_name field option in the .proto
+  // file.
+  bool has_json_name() const;
+
+  // Get the field default value if cpp_type() == CPPTYPE_INT32.  If no
+  // explicit default was defined, the default is 0.
+  int32_t default_value_int32_t() const;
+  int32_t default_value_int32() const { return default_value_int32_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_INT64.  If no
+  // explicit default was defined, the default is 0.
+  int64_t default_value_int64_t() const;
+  int64_t default_value_int64() const { return default_value_int64_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_UINT32.  If no
+  // explicit default was defined, the default is 0.
+  uint32_t default_value_uint32_t() const;
+  uint32_t default_value_uint32() const { return default_value_uint32_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_UINT64.  If no
+  // explicit default was defined, the default is 0.
+  uint64_t default_value_uint64_t() const;
+  uint64_t default_value_uint64() const { return default_value_uint64_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_FLOAT.  If no
+  // explicit default was defined, the default is 0.0.
+  float default_value_float() const;
+  // Get the field default value if cpp_type() == CPPTYPE_DOUBLE.  If no
+  // explicit default was defined, the default is 0.0.
+  double default_value_double() const;
+  // Get the field default value if cpp_type() == CPPTYPE_BOOL.  If no
+  // explicit default was defined, the default is false.
+  bool default_value_bool() const;
+  // Get the field default value if cpp_type() == CPPTYPE_ENUM.  If no
+  // explicit default was defined, the default is the first value defined
+  // in the enum type (all enum types are required to have at least one value).
+  // This never returns nullptr.
+  const EnumValueDescriptor* default_value_enum() const;
+  // Get the field default value if cpp_type() == CPPTYPE_STRING.  If no
+  // explicit default was defined, the default is the empty string.
+  const std::string& default_value_string() const;
+
+  // The Descriptor for the message of which this is a field.  For extensions,
+  // this is the extended type.  Never nullptr.
+  const Descriptor* containing_type() const;
+
+  // If the field is a member of a oneof, this is the one, otherwise this is
+  // nullptr.
+  const OneofDescriptor* containing_oneof() const;
+
+  // If the field is a member of a non-synthetic oneof, returns the descriptor
+  // for the oneof, otherwise returns nullptr.
+  const OneofDescriptor* real_containing_oneof() const;
+
+  // If the field is a member of a oneof, returns the index in that oneof.
+  int index_in_oneof() const;
+
+  // An extension may be declared within the scope of another message.  If this
+  // field is an extension (is_extension() is true), then extension_scope()
+  // returns that message, or nullptr if the extension was declared at global
+  // scope.  If this is not an extension, extension_scope() is undefined (may
+  // assert-fail).
+  const Descriptor* extension_scope() const;
+
+  // If type is TYPE_MESSAGE or TYPE_GROUP, returns a descriptor for the
+  // message or the group type.  Otherwise, returns null.
+  const Descriptor* message_type() const;
+  // If type is TYPE_ENUM, returns a descriptor for the enum.  Otherwise,
+  // returns null.
+  const EnumDescriptor* enum_type() const;
+
+  // Get the FieldOptions for this field.  This includes things listed in
+  // square brackets after the field definition.  E.g., the field:
+  //   optional string text = 1 [ctype=CORD];
+  // has the "ctype" option set.  Allowed options are defined by FieldOptions in
+  // descriptor.proto, and any available extensions of that message.
+  const FieldOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(FieldDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Helper method to get the CppType for a particular Type.
+  static CppType TypeToCppType(Type type);
+
+  // Helper method to get the name of a Type.
+  static const char* TypeName(Type type);
+
+  // Helper method to get the name of a CppType.
+  static const char* CppTypeName(CppType cpp_type);
+
+  // Return true iff [packed = true] is valid for fields of this type.
+  static inline bool IsTypePackable(Type field_type);
+
+  // Returns full_name() except if the field is a MessageSet extension,
+  // in which case it returns the full_name() of the containing message type
+  // for backwards compatibility with proto1.
+  //
+  // A MessageSet extension is defined as an optional message extension
+  // whose containing type has the message_set_wire_format option set.
+  // This should be true of extensions of google.protobuf.bridge.MessageSet;
+  // by convention, such extensions are named "message_set_extension".
+  //
+  // The opposite operation (looking up an extension's FieldDescriptor given
+  // its printable name) can be accomplished with
+  //     message->file()->pool()->FindExtensionByPrintableName(message, name)
+  // where the extension extends "message".
+  const std::string& PrintableNameForExtension() const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this field declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef FieldOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+  friend class Reflection;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(FieldDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // formats the default value appropriately and returns it as a string.
+  // Must have a default value to call this. If quote_string_type is true, then
+  // types of CPPTYPE_STRING will be surrounded by quotes and CEscaped.
+  std::string DefaultValueAsString(bool quote_string_type) const;
+
+  // Helper function that returns the field type name for DebugString.
+  std::string FieldTypeNameDebugString() const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // Returns true if this is a map message type.
+  bool is_map_message_type() const;
+
+  bool has_default_value_ : 1;
+  bool proto3_optional_ : 1;
+  // Whether the user has specified the json_name field option in the .proto
+  // file.
+  bool has_json_name_ : 1;
+  bool is_extension_ : 1;
+  bool is_oneof_ : 1;
+
+  // Actually a `Label` but stored as uint8_t to save space.
+  uint8_t label_ : 2;
+
+  // Actually a `Type`, but stored as uint8_t to save space.
+  mutable uint8_t type_;
+
+  // Logically:
+  //   all_names_ = [name, full_name, lower, camel, json]
+  // However:
+  //   duplicates will be omitted, so lower/camel/json might be in the same
+  //   position.
+  // We store the true offset for each name here, and the bit width must be
+  // large enough to account for the worst case where all names are present.
+  uint8_t lowercase_name_index_ : 2;
+  uint8_t camelcase_name_index_ : 2;
+  uint8_t json_name_index_ : 3;
+  // Sadly, `number_` located here to reduce padding. Unrelated to all_names_
+  // and its indices above.
+  int number_;
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+
+  // The once_flag is followed by a NUL terminated string for the type name and
+  // enum default value (or empty string if no default enum).
+  internal::once_flag* type_once_;
+  static void TypeOnceInit(const FieldDescriptor* to_init);
+  void InternalTypeOnceInit() const;
+  const Descriptor* containing_type_;
+  union {
+    const OneofDescriptor* containing_oneof;
+    const Descriptor* extension_scope;
+  } scope_;
+  union {
+    mutable const Descriptor* message_type;
+    mutable const EnumDescriptor* enum_type;
+  } type_descriptor_;
+  const FieldOptions* options_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  union {
+    int32_t default_value_int32_t_;
+    int64_t default_value_int64_t_;
+    uint32_t default_value_uint32_t_;
+    uint64_t default_value_uint64_t_;
+    float default_value_float_;
+    double default_value_double_;
+    bool default_value_bool_;
+
+    mutable const EnumValueDescriptor* default_value_enum_;
+    const std::string* default_value_string_;
+    mutable std::atomic<const Message*> default_generated_instance_;
+  };
+
+  static const CppType kTypeToCppTypeMap[MAX_TYPE + 1];
+
+  static const char* const kTypeToName[MAX_TYPE + 1];
+
+  static const char* const kCppTypeToName[MAX_CPPTYPE + 1];
+
+  static const char* const kLabelToName[MAX_LABEL + 1];
+
+  // Must be constructed using DescriptorPool.
+  FieldDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class FileDescriptor;
+  friend class Descriptor;
+  friend class OneofDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 72);
+
+// Describes a oneof defined in a message type.
+class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
+ public:
+  typedef OneofDescriptorProto Proto;
+
+  const std::string& name() const;       // Name of this oneof.
+  const std::string& full_name() const;  // Fully-qualified name of the oneof.
+
+  // Index of this oneof within the message's oneof array.
+  int index() const;
+
+  // Returns whether this oneof was inserted by the compiler to wrap a proto3
+  // optional field. If this returns true, code generators should *not* emit it.
+  bool is_synthetic() const;
+
+  // The .proto file in which this oneof was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+  // The Descriptor for the message containing this oneof.
+  const Descriptor* containing_type() const;
+
+  // The number of (non-extension) fields which are members of this oneof.
+  int field_count() const;
+  // Get a member of this oneof, in the order in which they were declared in the
+  // .proto file.  Does not include extensions.
+  const FieldDescriptor* field(int index) const;
+
+  const OneofOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(OneofDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this oneof declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef OneofOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  int field_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const Descriptor* containing_type_;
+  const OneofOptions* options_;
+  const FieldDescriptor* fields_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
+  // in descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  OneofDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class Descriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 40);
+
+// Describes an enum type defined in a .proto file.  To get the EnumDescriptor
+// for a generated enum type, call TypeName_descriptor().  Use DescriptorPool
+// to construct your own descriptors.
+class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
+ public:
+  typedef EnumDescriptorProto Proto;
+
+  // The name of this enum type in the containing scope.
+  const std::string& name() const;
+
+  // The fully-qualified name of the enum type, scope delimited by periods.
+  const std::string& full_name() const;
+
+  // Index of this enum within the file or containing message's enum array.
+  int index() const;
+
+  // The .proto file in which this enum type was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+
+  // The number of values for this EnumDescriptor.  Guaranteed to be greater
+  // than zero.
+  int value_count() const;
+  // Gets a value by index, where 0 <= index < value_count().
+  // These are returned in the order they were defined in the .proto file.
+  const EnumValueDescriptor* value(int index) const;
+
+  // Looks up a value by name.  Returns nullptr if no such value exists.
+  const EnumValueDescriptor* FindValueByName(ConstStringParam name) const;
+  // Looks up a value by number.  Returns nullptr if no such value exists.  If
+  // multiple values have this number, the first one defined is returned.
+  const EnumValueDescriptor* FindValueByNumber(int number) const;
+
+  // If this enum type is nested in a message type, this is that message type.
+  // Otherwise, nullptr.
+  const Descriptor* containing_type() const;
+
+  // Get options for this enum type.  These are specified in the .proto file by
+  // placing lines like "option foo = 1234;" in the enum definition.  Allowed
+  // options are defined by EnumOptions in descriptor.proto, and any available
+  // extensions of that message.
+  const EnumOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(EnumDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Returns true if this is a placeholder for an unknown enum. This will
+  // only be the case if this descriptor comes from a DescriptorPool
+  // with AllowUnknownDependencies() set.
+  bool is_placeholder() const;
+
+  // Reserved fields -------------------------------------------------
+
+  // A range of reserved field numbers.
+  struct ReservedRange {
+    int start;  // inclusive
+    int end;    // inclusive
+  };
+
+  // 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 EnumDescriptor::ReservedRange* reserved_range(int index) const;
+
+  // Returns true if the number is in one of the reserved ranges.
+  bool IsReservedNumber(int number) const;
+
+  // Returns nullptr if no reserved range contains the given number.
+  const EnumDescriptor::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 std::string& reserved_name(int index) const;
+
+  // Returns true if the field name is reserved.
+  bool IsReservedName(ConstStringParam name) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this enum declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef EnumOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // Allow access to FindValueByNumberCreatingIfUnknown.
+  friend class descriptor_unittest::DescriptorTest;
+
+  // Looks up a value by number.  If the value does not exist, dynamically
+  // creates a new EnumValueDescriptor for that value, assuming that it was
+  // unknown. If a new descriptor is created, this is done in a thread-safe way,
+  // and future calls will return the same value descriptor pointer.
+  //
+  // This is private but is used by Reflection (which is friended below) to
+  // return a valid EnumValueDescriptor from GetEnum() when this feature is
+  // enabled.
+  const EnumValueDescriptor* FindValueByNumberCreatingIfUnknown(
+      int number) const;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // True if this is a placeholder for an unknown type.
+  bool is_placeholder_ : 1;
+  // True if this is a placeholder and the type name wasn't fully-qualified.
+  bool is_unqualified_placeholder_ : 1;
+
+  // This points to the last value _index_ that is part of the sequence starting
+  // with the first label, where
+  //   `enum->value(i)->number() == enum->value(0)->number() + i`
+  // We measure relative to the first label to adapt to enum labels starting at
+  // 0 or 1.
+  // Uses 16-bit to avoid extra padding. Unlikely to have more than 2^15
+  // sequentially numbered labels in an enum.
+  int16_t sequential_value_limit_;
+
+  int value_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const Descriptor* containing_type_;
+  const EnumOptions* options_;
+  EnumValueDescriptor* values_;
+
+  int reserved_range_count_;
+  int reserved_name_count_;
+  EnumDescriptor::ReservedRange* reserved_ranges_;
+  const std::string** reserved_names_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<EnumDescriptor>() and AllocateArray<EnumDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  EnumDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class Descriptor;
+  friend class FieldDescriptor;
+  friend class FileDescriptorTables;
+  friend class EnumValueDescriptor;
+  friend class FileDescriptor;
+  friend class DescriptorPool;
+  friend class Reflection;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 72);
+
+// Describes an individual enum constant of a particular type.  To get the
+// EnumValueDescriptor for a given enum value, first get the EnumDescriptor
+// for its type, then use EnumDescriptor::FindValueByName() or
+// EnumDescriptor::FindValueByNumber().  Use DescriptorPool to construct
+// your own descriptors.
+class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
+                                            private internal::SymbolBaseN<1> {
+ public:
+  typedef EnumValueDescriptorProto Proto;
+
+  const std::string& name() const;  // Name of this enum constant.
+  int index() const;                // Index within the enums's Descriptor.
+  int number() const;               // Numeric value of this enum constant.
+
+  // The full_name of an enum value is a sibling symbol of the enum type.
+  // e.g. the full name of FieldDescriptorProto::TYPE_INT32 is actually
+  // "google.protobuf.FieldDescriptorProto.TYPE_INT32", NOT
+  // "google.protobuf.FieldDescriptorProto.Type.TYPE_INT32".  This is to conform
+  // with C++ scoping rules for enums.
+  const std::string& full_name() const;
+
+  // The .proto file in which this value was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+  // The type of this value.  Never nullptr.
+  const EnumDescriptor* type() const;
+
+  // Get options for this enum value.  These are specified in the .proto file by
+  // adding text like "[foo = 1234]" after an enum value definition.  Allowed
+  // options are defined by EnumValueOptions in descriptor.proto, and any
+  // available extensions of that message.
+  const EnumValueOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(EnumValueDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this enum value declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef EnumValueOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  int number_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const EnumDescriptor* type_;
+  const EnumValueOptions* options_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<EnumValueDescriptor>() and AllocateArray<EnumValueDescriptor>()
+  // in descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  EnumValueDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class EnumDescriptor;
+  friend class DescriptorPool;
+  friend class FileDescriptorTables;
+  friend class Reflection;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 32);
+
+// Describes an RPC service. Use DescriptorPool to construct your own
+// descriptors.
+class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
+ public:
+  typedef ServiceDescriptorProto Proto;
+
+  // The name of the service, not including its containing scope.
+  const std::string& name() const;
+  // The fully-qualified name of the service, scope delimited by periods.
+  const std::string& full_name() const;
+  // Index of this service within the file's services array.
+  int index() const;
+
+  // The .proto file in which this service was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+
+  // Get options for this service type.  These are specified in the .proto file
+  // by placing lines like "option foo = 1234;" in the service definition.
+  // Allowed options are defined by ServiceOptions in descriptor.proto, and any
+  // available extensions of that message.
+  const ServiceOptions& options() const;
+
+  // The number of methods this service defines.
+  int method_count() const;
+  // Gets a MethodDescriptor by index, where 0 <= index < method_count().
+  // These are returned in the order they were defined in the .proto file.
+  const MethodDescriptor* method(int index) const;
+
+  // Look up a MethodDescriptor by name.
+  const MethodDescriptor* FindMethodByName(ConstStringParam name) const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(ServiceDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this service declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef ServiceOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const ServiceOptions* options_;
+  MethodDescriptor* methods_;
+  int method_count_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<ServiceDescriptor>() and AllocateArray<ServiceDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  ServiceDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class FileDescriptor;
+  friend class MethodDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 48);
+
+// Describes an individual service method.  To obtain a MethodDescriptor given
+// a service, first get its ServiceDescriptor, then call
+// ServiceDescriptor::FindMethodByName().  Use DescriptorPool to construct your
+// own descriptors.
+class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
+ public:
+  typedef MethodDescriptorProto Proto;
+
+  // Name of this method, not including containing scope.
+  const std::string& name() const;
+  // The fully-qualified name of the method, scope delimited by periods.
+  const std::string& full_name() const;
+  // Index within the service's Descriptor.
+  int index() const;
+
+  // The .proto file in which this method was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+  // Gets the service to which this method belongs.  Never nullptr.
+  const ServiceDescriptor* service() const;
+
+  // Gets the type of protocol message which this method accepts as input.
+  const Descriptor* input_type() const;
+  // Gets the type of protocol message which this message produces as output.
+  const Descriptor* output_type() const;
+
+  // Gets whether the client streams multiple requests.
+  bool client_streaming() const;
+  // Gets whether the server streams multiple responses.
+  bool server_streaming() const;
+
+  // Get options for this method.  These are specified in the .proto file by
+  // placing lines like "option foo = 1234;" in curly-braces after a method
+  // declaration.  Allowed options are defined by MethodOptions in
+  // descriptor.proto, and any available extensions of that message.
+  const MethodOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(MethodDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this method declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef MethodOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  bool client_streaming_;
+  bool server_streaming_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const ServiceDescriptor* service_;
+  mutable internal::LazyDescriptor input_type_;
+  mutable internal::LazyDescriptor output_type_;
+  const MethodOptions* options_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<MethodDescriptor>() and AllocateArray<MethodDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  MethodDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class ServiceDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 64);
+
+// Describes a whole .proto file.  To get the FileDescriptor for a compiled-in
+// file, get the descriptor for something defined in that file and call
+// descriptor->file().  Use DescriptorPool to construct your own descriptors.
+class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
+ public:
+  typedef FileDescriptorProto Proto;
+
+  // The filename, relative to the source tree.
+  // e.g. "foo/bar/baz.proto"
+  const std::string& name() const;
+
+  // The package, e.g. "google.protobuf.compiler".
+  const std::string& package() const;
+
+  // The DescriptorPool in which this FileDescriptor and all its contents were
+  // allocated.  Never nullptr.
+  const DescriptorPool* pool() const;
+
+  // The number of files imported by this one.
+  int dependency_count() const;
+  // Gets an imported file by index, where 0 <= index < dependency_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FileDescriptor* dependency(int index) const;
+
+  // The number of files public imported by this one.
+  // The public dependency list is a subset of the dependency list.
+  int public_dependency_count() const;
+  // Gets a public imported file by index, where 0 <= index <
+  // public_dependency_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FileDescriptor* public_dependency(int index) const;
+
+  // The number of files that are imported for weak fields.
+  // The weak dependency list is a subset of the dependency list.
+  int weak_dependency_count() const;
+  // Gets a weak imported file by index, where 0 <= index <
+  // weak_dependency_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FileDescriptor* weak_dependency(int index) const;
+
+  // Number of top-level message types defined in this file.  (This does not
+  // include nested types.)
+  int message_type_count() const;
+  // Gets a top-level message type, where 0 <= index < message_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const Descriptor* message_type(int index) const;
+
+  // Number of top-level enum types defined in this file.  (This does not
+  // include nested types.)
+  int enum_type_count() const;
+  // Gets a top-level enum type, where 0 <= index < enum_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const EnumDescriptor* enum_type(int index) const;
+
+  // Number of services defined in this file.
+  int service_count() const;
+  // Gets a service, where 0 <= index < service_count().
+  // These are returned in the order they were defined in the .proto file.
+  const ServiceDescriptor* service(int index) const;
+
+  // Number of extensions defined at file scope.  (This does not include
+  // extensions nested within message types.)
+  int extension_count() const;
+  // Gets an extension's descriptor, where 0 <= index < extension_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FieldDescriptor* extension(int index) const;
+
+  // Get options for this file.  These are specified in the .proto file by
+  // placing lines like "option foo = 1234;" at the top level, outside of any
+  // other definitions.  Allowed options are defined by FileOptions in
+  // descriptor.proto, and any available extensions of that message.
+  const FileOptions& options() const;
+
+  // Syntax of this file.
+  enum Syntax {
+    SYNTAX_UNKNOWN = 0,
+    SYNTAX_PROTO2 = 2,
+    SYNTAX_PROTO3 = 3,
+  };
+  Syntax syntax() const;
+  static const char* SyntaxName(Syntax syntax);
+
+  // Find a top-level message type by name (not full_name).  Returns nullptr if
+  // not found.
+  const Descriptor* FindMessageTypeByName(ConstStringParam name) const;
+  // Find a top-level enum type by name.  Returns nullptr if not found.
+  const EnumDescriptor* FindEnumTypeByName(ConstStringParam name) const;
+  // Find an enum value defined in any top-level enum by name.  Returns nullptr
+  // if not found.
+  const EnumValueDescriptor* FindEnumValueByName(ConstStringParam name) const;
+  // Find a service definition by name.  Returns nullptr if not found.
+  const ServiceDescriptor* FindServiceByName(ConstStringParam name) const;
+  // Find a top-level extension definition by name.  Returns nullptr if not
+  // found.
+  const FieldDescriptor* FindExtensionByName(ConstStringParam name) const;
+  // Similar to FindExtensionByName(), but searches by lowercased-name.  See
+  // Descriptor::FindFieldByLowercaseName().
+  const FieldDescriptor* FindExtensionByLowercaseName(
+      ConstStringParam name) const;
+  // Similar to FindExtensionByName(), but searches by camelcased-name.  See
+  // Descriptor::FindFieldByCamelcaseName().
+  const FieldDescriptor* FindExtensionByCamelcaseName(
+      ConstStringParam name) const;
+
+  // See Descriptor::CopyTo().
+  // Notes:
+  // - This method does NOT copy source code information since it is relatively
+  //   large and rarely needed.  See CopySourceCodeInfoTo() below.
+  void CopyTo(FileDescriptorProto* proto) const;
+  // 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().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Returns true if this is a placeholder for an unknown file. This will
+  // only be the case if this descriptor comes from a DescriptorPool
+  // with AllowUnknownDependencies() set.
+  bool is_placeholder() const;
+
+  // Updates |*out_location| to the source location of the complete extent of
+  // this file declaration (namely, the empty path).
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of the declaration or declaration-part denoted by |path|.
+  // Returns false and leaves |*out_location| unchanged iff location
+  // information was not available.  (See SourceCodeInfo for
+  // description of path encoding.)
+  bool GetSourceLocation(const std::vector<int>& path,
+                         SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef FileOptions OptionsType;
+
+  bool is_placeholder_;
+  // Indicates the FileDescriptor is completed building. Used to verify
+  // that type accessor functions that can possibly build a dependent file
+  // aren't called during the process of building the file.
+  bool finished_building_;
+  // Actually a `Syntax` but stored as uint8_t to save space.
+  uint8_t syntax_;
+  // This one is here to fill the padding.
+  int extension_count_;
+
+  const std::string* name_;
+  const std::string* package_;
+  const DescriptorPool* pool_;
+
+  // dependencies_once_ contain a once_flag followed by N NUL terminated
+  // strings. Dependencies that do not need to be loaded will be empty. ie just
+  // {'\0'}
+  internal::once_flag* dependencies_once_;
+  static void DependenciesOnceInit(const FileDescriptor* to_init);
+  void InternalDependenciesOnceInit() const;
+
+  // These are arranged to minimize padding on 64-bit.
+  int dependency_count_;
+  int public_dependency_count_;
+  int weak_dependency_count_;
+  int message_type_count_;
+  int enum_type_count_;
+  int service_count_;
+
+  mutable const FileDescriptor** dependencies_;
+  int* public_dependencies_;
+  int* weak_dependencies_;
+  Descriptor* message_types_;
+  EnumDescriptor* enum_types_;
+  ServiceDescriptor* services_;
+  FieldDescriptor* extensions_;
+  const FileOptions* options_;
+
+  const FileDescriptorTables* tables_;
+  const SourceCodeInfo* source_code_info_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  FileDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class DescriptorPool;
+  friend class Descriptor;
+  friend class FieldDescriptor;
+  friend class internal::LazyDescriptor;
+  friend class OneofDescriptor;
+  friend class EnumDescriptor;
+  friend class EnumValueDescriptor;
+  friend class MethodDescriptor;
+  friend class ServiceDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 144);
+
+// ===================================================================
+
+// Used to construct descriptors.
+//
+// Normally you won't want to build your own descriptors.  Message classes
+// constructed by the protocol compiler will provide them for you.  However,
+// if you are implementing Message on your own, or if you are writing a
+// program which can operate on totally arbitrary types and needs to load
+// them from some sort of database, you might need to.
+//
+// Since Descriptors are composed of a whole lot of cross-linked bits of
+// data that would be a pain to put together manually, the
+// DescriptorPool class is provided to make the process easier.  It can
+// take a FileDescriptorProto (defined in descriptor.proto), validate it,
+// and convert it to a set of nicely cross-linked Descriptors.
+//
+// DescriptorPool also helps with memory management.  Descriptors are
+// composed of many objects containing static data and pointers to each
+// other.  In all likelihood, when it comes time to delete this data,
+// you'll want to delete it all at once.  In fact, it is not uncommon to
+// have a whole pool of descriptors all cross-linked with each other which
+// you wish to delete all at once.  This class represents such a pool, and
+// handles the memory management for you.
+//
+// You can also search for descriptors within a DescriptorPool by name, and
+// extensions by number.
+class PROTOBUF_EXPORT DescriptorPool {
+ public:
+  // Create a normal, empty DescriptorPool.
+  DescriptorPool();
+
+  // Constructs a DescriptorPool that, when it can't find something among the
+  // descriptors already in the pool, looks for it in the given
+  // DescriptorDatabase.
+  // Notes:
+  // - If a DescriptorPool is constructed this way, its BuildFile*() methods
+  //   must not be called (they will assert-fail).  The only way to populate
+  //   the pool with descriptors is to call the Find*By*() methods.
+  // - The Find*By*() methods may block the calling thread if the
+  //   DescriptorDatabase blocks.  This in turn means that parsing messages
+  //   may block if they need to look up extensions.
+  // - The Find*By*() methods will use mutexes for thread-safety, thus making
+  //   them slower even when they don't have to fall back to the database.
+  //   In fact, even the Find*By*() methods of descriptor objects owned by
+  //   this pool will be slower, since they will have to obtain locks too.
+  // - An ErrorCollector may optionally be given to collect validation errors
+  //   in files loaded from the database.  If not given, errors will be printed
+  //   to GOOGLE_LOG(ERROR).  Remember that files are built on-demand, so this
+  //   ErrorCollector may be called from any thread that calls one of the
+  //   Find*By*() methods.
+  // - The DescriptorDatabase must not be mutated during the lifetime of
+  //   the DescriptorPool. Even if the client takes care to avoid data races,
+  //   changes to the content of the DescriptorDatabase may not be reflected
+  //   in subsequent lookups in the DescriptorPool.
+  class ErrorCollector;
+  explicit DescriptorPool(DescriptorDatabase* fallback_database,
+                          ErrorCollector* error_collector = nullptr);
+
+  ~DescriptorPool();
+
+  // Get a pointer to the generated pool.  Generated protocol message classes
+  // which are compiled into the binary will allocate their descriptors in
+  // 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 nullptr if not
+  // found.
+  const FileDescriptor* FindFileByName(ConstStringParam name) const;
+
+  // Find the FileDescriptor in the pool which defines the given symbol.
+  // If any of the Find*ByName() methods below would succeed, then this is
+  // equivalent to calling that method and calling the result's file() method.
+  // Otherwise this returns nullptr.
+  const FileDescriptor* FindFileContainingSymbol(
+      ConstStringParam symbol_name) const;
+
+  // Looking up descriptors ------------------------------------------
+  // These find descriptors by fully-qualified name.  These will find both
+  // top-level descriptors and nested descriptors.  They return nullptr if not
+  // found.
+
+  const Descriptor* FindMessageTypeByName(ConstStringParam name) const;
+  const FieldDescriptor* FindFieldByName(ConstStringParam name) const;
+  const FieldDescriptor* FindExtensionByName(ConstStringParam name) const;
+  const OneofDescriptor* FindOneofByName(ConstStringParam name) const;
+  const EnumDescriptor* FindEnumTypeByName(ConstStringParam name) const;
+  const EnumValueDescriptor* FindEnumValueByName(ConstStringParam name) const;
+  const ServiceDescriptor* FindServiceByName(ConstStringParam name) const;
+  const MethodDescriptor* FindMethodByName(ConstStringParam name) const;
+
+  // Finds an extension of the given type by number.  The extendee must be
+  // a member of this DescriptorPool or one of its underlays.
+  const FieldDescriptor* FindExtensionByNumber(const Descriptor* extendee,
+                                               int number) const;
+
+  // Finds an extension of the given type by its printable name.
+  // See comments above PrintableNameForExtension() for the definition of
+  // "printable name".  The extendee must be a member of this DescriptorPool
+  // or one of its underlays.  Returns nullptr if there is no known message
+  // extension with the given printable name.
+  const FieldDescriptor* FindExtensionByPrintableName(
+      const Descriptor* extendee, ConstStringParam printable_name) const;
+
+  // Finds extensions of extendee. The extensions will be appended to
+  // out in an undefined order. Only extensions defined directly in
+  // this DescriptorPool or one of its underlays are guaranteed to be
+  // found: extensions defined in the fallback database might not be found
+  // depending on the database implementation.
+  void FindAllExtensions(const Descriptor* extendee,
+                         std::vector<const FieldDescriptor*>* out) const;
+
+  // Building descriptors --------------------------------------------
+
+  // When converting a FileDescriptorProto to a FileDescriptor, various
+  // errors might be detected in the input.  The caller may handle these
+  // programmatically by implementing an ErrorCollector.
+  class PROTOBUF_EXPORT ErrorCollector {
+   public:
+    inline ErrorCollector() {}
+    virtual ~ErrorCollector();
+
+    // These constants specify what exact part of the construct is broken.
+    // This is useful e.g. for mapping the error back to an exact location
+    // in a .proto file.
+    enum ErrorLocation {
+      NAME,           // the symbol name, or the package name for files
+      NUMBER,         // field or extension range number
+      TYPE,           // field type
+      EXTENDEE,       // field extendee
+      DEFAULT_VALUE,  // field default value
+      INPUT_TYPE,     // method input type
+      OUTPUT_TYPE,    // method output type
+      OPTION_NAME,    // name in assignment
+      OPTION_VALUE,   // value in option assignment
+      IMPORT,         // import error
+      OTHER           // some other problem
+    };
+
+    // Reports an error in the FileDescriptorProto. Use this function if the
+    // problem occurred should interrupt building the FileDescriptorProto.
+    virtual void AddError(
+        const std::string& filename,  // File name in which the error occurred.
+        const std::string& element_name,  // Full name of the erroneous element.
+        const Message* descriptor,  // Descriptor of the erroneous element.
+        ErrorLocation location,     // One of the location constants, above.
+        const std::string& message  // Human-readable error message.
+        ) = 0;
+
+    // Reports a warning in the FileDescriptorProto. Use this function if the
+    // problem occurred should NOT interrupt building the FileDescriptorProto.
+    virtual void AddWarning(
+        const std::string& /*filename*/,      // File name in which the error
+                                              // occurred.
+        const std::string& /*element_name*/,  // Full name of the erroneous
+                                              // element.
+        const Message* /*descriptor*/,  // Descriptor of the erroneous element.
+        ErrorLocation /*location*/,     // One of the location constants, above.
+        const std::string& /*message*/  // Human-readable error message.
+    ) {}
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
+  };
+
+  // Convert the FileDescriptorProto to real descriptors and place them in
+  // this DescriptorPool.  All dependencies of the file must already be in
+  // the pool.  Returns the resulting FileDescriptor, or nullptr if there were
+  // problems with the input (e.g. the message was invalid, or dependencies
+  // were missing).  Details about the errors are written to GOOGLE_LOG(ERROR).
+  const FileDescriptor* BuildFile(const FileDescriptorProto& proto);
+
+  // Same as BuildFile() except errors are sent to the given ErrorCollector.
+  const FileDescriptor* BuildFileCollectingErrors(
+      const FileDescriptorProto& proto, ErrorCollector* error_collector);
+
+  // By default, it is an error if a FileDescriptorProto contains references
+  // to types or other files that are not found in the DescriptorPool (or its
+  // backing DescriptorDatabase, if any).  If you call
+  // AllowUnknownDependencies(), however, then unknown types and files
+  // will be replaced by placeholder descriptors (which can be identified by
+  // the is_placeholder() method).  This can allow you to
+  // perform some useful operations with a .proto file even if you do not
+  // have access to other .proto files on which it depends.  However, some
+  // heuristics must be used to fill in the gaps in information, and these
+  // can lead to descriptors which are inaccurate.  For example, the
+  // DescriptorPool may be forced to guess whether an unknown type is a message
+  // or an enum, as well as what package it resides in.  Furthermore,
+  // placeholder types will not be discoverable via FindMessageTypeByName()
+  // and similar methods, which could confuse some descriptor-based algorithms.
+  // Generally, the results of this option should be handled with extreme care.
+  void AllowUnknownDependencies() { allow_unknown_ = true; }
+
+  // By default, weak imports are allowed to be missing, in which case we will
+  // use a placeholder for the dependency and convert the field to be an Empty
+  // message field. If you call EnforceWeakDependencies(true), however, the
+  // DescriptorPool will report a import not found error.
+  void EnforceWeakDependencies(bool enforce) { enforce_weak_ = enforce; }
+
+  // Internal stuff --------------------------------------------------
+  // These methods MUST NOT be called from outside the proto2 library.
+  // These methods may contain hidden pitfalls and may be removed in a
+  // future library version.
+
+  // Create a DescriptorPool which is overlaid on top of some other pool.
+  // If you search for a descriptor in the overlay and it is not found, the
+  // underlay will be searched as a backup.  If the underlay has its own
+  // underlay, that will be searched next, and so on.  This also means that
+  // files built in the overlay will be cross-linked with the underlay's
+  // descriptors if necessary.  The underlay remains property of the caller;
+  // it must remain valid for the lifetime of the newly-constructed pool.
+  //
+  // Example:  Say you want to parse a .proto file at runtime in order to use
+  // its type with a DynamicMessage.  Say this .proto file has dependencies,
+  // but you know that all the dependencies will be things that are already
+  // compiled into the binary.  For ease of use, you'd like to load the types
+  // right out of generated_pool() rather than have to parse redundant copies
+  // of all these .protos and runtime.  But, you don't want to add the parsed
+  // types directly into generated_pool(): this is not allowed, and would be
+  // bad design anyway.  So, instead, you could use generated_pool() as an
+  // underlay for a new DescriptorPool in which you add only the new file.
+  //
+  // WARNING:  Use of underlays can lead to many subtle gotchas.  Instead,
+  //   try to formulate what you want to do in terms of DescriptorDatabases.
+  explicit DescriptorPool(const DescriptorPool* underlay);
+
+  // Called by generated classes at init time to add their descriptors to
+  // generated_pool.  Do NOT call this in your own code!  filename must be a
+  // permanent string (e.g. a string literal).
+  static void InternalAddGeneratedFile(const void* encoded_file_descriptor,
+                                       int size);
+
+  // Disallow [enforce_utf8 = false] in .proto files.
+  void DisallowEnforceUtf8() { disallow_enforce_utf8_ = true; }
+
+
+  // For internal use only:  Gets a non-const pointer to the generated pool.
+  // This is called at static-initialization time only, so thread-safety is
+  // not a concern.  If both an underlay and a fallback database are present,
+  // the underlay takes precedence.
+  static DescriptorPool* internal_generated_pool();
+
+  // For internal use only:  Gets a non-const pointer to the generated
+  // descriptor database.
+  // Only used for testing.
+  static DescriptorDatabase* internal_generated_database();
+
+  // For internal use only:  Changes the behavior of BuildFile() such that it
+  // allows the file to make reference to message types declared in other files
+  // which it did not officially declare as dependencies.
+  void InternalDontEnforceDependencies();
+
+  // For internal use only: Enables lazy building of dependencies of a file.
+  // Delay the building of dependencies of a file descriptor until absolutely
+  // necessary, like when message_type() is called on a field that is defined
+  // in that dependency's file. This will cause functional issues if a proto
+  // or one of its dependencies has errors. Should only be enabled for the
+  // generated_pool_ (because no descriptor build errors are guaranteed by
+  // the compilation generation process), testing, or if a lack of descriptor
+  // build errors can be guaranteed for a pool.
+  void InternalSetLazilyBuildDependencies() {
+    lazily_build_dependencies_ = true;
+    // This needs to be set when lazily building dependencies, as it breaks
+    // dependency checking.
+    InternalDontEnforceDependencies();
+  }
+
+  // For internal use only.
+  void internal_set_underlay(const DescriptorPool* underlay) {
+    underlay_ = underlay;
+  }
+
+  // For internal (unit test) use only:  Returns true if a FileDescriptor has
+  // been constructed for the given file, false otherwise.  Useful for testing
+  // lazy descriptor initialization behavior.
+  bool InternalIsFileLoaded(ConstStringParam filename) const;
+
+  // Add a file to unused_import_track_files_. DescriptorBuilder will log
+  // warnings or errors for those files if there is any unused import.
+  void AddUnusedImportTrackFile(ConstStringParam file_name,
+                                bool is_error = false);
+  void ClearUnusedImportTrackFiles();
+
+ private:
+  friend class Descriptor;
+  friend class internal::LazyDescriptor;
+  friend class FieldDescriptor;
+  friend class EnumDescriptor;
+  friend class ServiceDescriptor;
+  friend class MethodDescriptor;
+  friend class FileDescriptor;
+  friend class DescriptorBuilder;
+  friend class FileDescriptorTables;
+
+  // Return true if the given name is a sub-symbol of any non-package
+  // descriptor that already exists in the descriptor pool.  (The full
+  // definition of such types is already known.)
+  bool IsSubSymbolOfBuiltType(StringPiece name) const;
+
+  // Tries to find something in the fallback database and link in the
+  // corresponding proto file.  Returns true if successful, in which case
+  // the caller should search for the thing again.  These are declared
+  // const because they are called by (semantically) const methods.
+  bool TryFindFileInFallbackDatabase(StringPiece name) const;
+  bool TryFindSymbolInFallbackDatabase(StringPiece name) const;
+  bool TryFindExtensionInFallbackDatabase(const Descriptor* containing_type,
+                                          int field_number) const;
+
+  // This internal find extension method only check with its table and underlay
+  // descriptor_pool's table. It does not check with fallback DB and no
+  // additional proto file will be build in this method.
+  const FieldDescriptor* InternalFindExtensionByNumberNoLock(
+      const Descriptor* extendee, int number) const;
+
+  // Like BuildFile() but called internally when the file has been loaded from
+  // fallback_database_.  Declared const because it is called by (semantically)
+  // const methods.
+  const FileDescriptor* BuildFileFromDatabase(
+      const FileDescriptorProto& proto) const;
+
+  // Helper for when lazily_build_dependencies_ is set, can look up a symbol
+  // after the file's descriptor is built, and can build the file where that
+  // symbol is defined if necessary. Will create a placeholder if the type
+  // doesn't exist in the fallback database, or the file doesn't build
+  // successfully.
+  Symbol CrossLinkOnDemandHelper(StringPiece name,
+                                 bool expecting_enum) const;
+
+  // Create a placeholder FileDescriptor of the specified name
+  FileDescriptor* NewPlaceholderFile(StringPiece name) const;
+  FileDescriptor* NewPlaceholderFileWithMutexHeld(
+      StringPiece name, internal::FlatAllocator& alloc) const;
+
+  enum PlaceholderType {
+    PLACEHOLDER_MESSAGE,
+    PLACEHOLDER_ENUM,
+    PLACEHOLDER_EXTENDABLE_MESSAGE
+  };
+  // Create a placeholder Descriptor of the specified name
+  Symbol NewPlaceholder(StringPiece name,
+                        PlaceholderType placeholder_type) const;
+  Symbol NewPlaceholderWithMutexHeld(StringPiece name,
+                                     PlaceholderType placeholder_type) const;
+
+  // If fallback_database_ is nullptr, this is nullptr.  Otherwise, this is a
+  // mutex which must be locked while accessing tables_.
+  internal::WrappedMutex* mutex_;
+
+  // See constructor.
+  DescriptorDatabase* fallback_database_;
+  ErrorCollector* default_error_collector_;
+  const DescriptorPool* underlay_;
+
+  // This class contains a lot of hash maps with complicated types that
+  // we'd like to keep out of the header.
+  class Tables;
+  std::unique_ptr<Tables> tables_;
+
+  bool enforce_dependencies_;
+  bool lazily_build_dependencies_;
+  bool allow_unknown_;
+  bool enforce_weak_;
+  bool disallow_enforce_utf8_;
+
+  // Set of files to track for unused imports. The bool value when true means
+  // unused imports are treated as errors (and as warnings when false).
+  std::map<std::string, bool> unused_import_track_files_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPool);
+};
+
+
+// inline methods ====================================================
+
+// These macros makes this repetitive code more readable.
+#define PROTOBUF_DEFINE_ACCESSOR(CLASS, FIELD, TYPE) \
+  inline TYPE CLASS::FIELD() const { return FIELD##_; }
+
+// Strings fields are stored as pointers but returned as const references.
+#define PROTOBUF_DEFINE_STRING_ACCESSOR(CLASS, FIELD) \
+  inline const std::string& CLASS::FIELD() const { return *FIELD##_; }
+
+// Name and full name are stored in a single array to save space.
+#define PROTOBUF_DEFINE_NAME_ACCESSOR(CLASS)                              \
+  inline const std::string& CLASS::name() const { return all_names_[0]; } \
+  inline const std::string& CLASS::full_name() const { return all_names_[1]; }
+
+// Arrays take an index parameter, obviously.
+#define PROTOBUF_DEFINE_ARRAY_ACCESSOR(CLASS, FIELD, TYPE) \
+  inline TYPE CLASS::FIELD(int index) const { return FIELD##s_ + index; }
+
+#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
+  inline const TYPE& CLASS::options() const { return *options_; }
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(Descriptor)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*)
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, field_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, oneof_decl_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, real_oneof_decl_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, nested_type_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, enum_type_count, int)
+
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, field, const FieldDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, oneof_decl, const OneofDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, nested_type, const Descriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, enum_type, const EnumDescriptor*)
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_range_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range,
+                               const Descriptor::ExtensionRange*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension, const FieldDescriptor*)
+
+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_NAME_ACCESSOR(FieldDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_json_name, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32_t, int32_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64_t, int64_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32_t, uint32_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64_t, uint64_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_float, float)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_double, double)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_bool, bool)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(OneofDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(OneofDescriptor, field, const FieldDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(EnumDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
+                               const EnumValueDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_range_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, reserved_range,
+                               const EnumDescriptor::ReservedRange*)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_name_count, int)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(EnumValueDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
+PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(ServiceDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
+                               const MethodDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(MethodDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
+
+PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, public_dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, weak_dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
+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_ACCESSOR(FileDescriptor, is_placeholder, bool)
+
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, service,
+                               const ServiceDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, extension,
+                               const FieldDescriptor*)
+
+#undef PROTOBUF_DEFINE_ACCESSOR
+#undef PROTOBUF_DEFINE_STRING_ACCESSOR
+#undef PROTOBUF_DEFINE_ARRAY_ACCESSOR
+
+// A few accessors differ from the macros...
+
+inline Descriptor::WellKnownType Descriptor::well_known_type() const {
+  return static_cast<Descriptor::WellKnownType>(well_known_type_);
+}
+
+inline bool Descriptor::IsExtensionNumber(int number) const {
+  return FindExtensionRangeContainingNumber(number) != nullptr;
+}
+
+inline bool Descriptor::IsReservedNumber(int number) const {
+  return FindReservedRangeContainingNumber(number) != nullptr;
+}
+
+inline bool Descriptor::IsReservedName(ConstStringParam name) const {
+  for (int i = 0; i < reserved_name_count(); i++) {
+    if (name == static_cast<ConstStringParam>(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 std::string& Descriptor::reserved_name(int index) const {
+  return *reserved_names_[index];
+}
+
+inline bool EnumDescriptor::IsReservedNumber(int number) const {
+  return FindReservedRangeContainingNumber(number) != nullptr;
+}
+
+inline bool EnumDescriptor::IsReservedName(ConstStringParam name) const {
+  for (int i = 0; i < reserved_name_count(); i++) {
+    if (name == static_cast<ConstStringParam>(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 std::string& EnumDescriptor::reserved_name(int index) const {
+  return *reserved_names_[index];
+}
+
+inline const std::string& FieldDescriptor::lowercase_name() const {
+  return all_names_[lowercase_name_index_];
+}
+
+inline const std::string& FieldDescriptor::camelcase_name() const {
+  return all_names_[camelcase_name_index_];
+}
+
+inline const std::string& FieldDescriptor::json_name() const {
+  return all_names_[json_name_index_];
+}
+
+inline const OneofDescriptor* FieldDescriptor::containing_oneof() const {
+  return is_oneof_ ? scope_.containing_oneof : nullptr;
+}
+
+inline int FieldDescriptor::index_in_oneof() const {
+  GOOGLE_DCHECK(is_oneof_);
+  return static_cast<int>(this - scope_.containing_oneof->field(0));
+}
+
+inline const Descriptor* FieldDescriptor::extension_scope() const {
+  GOOGLE_CHECK(is_extension_);
+  return scope_.extension_scope;
+}
+
+inline FieldDescriptor::Label FieldDescriptor::label() const {
+  return static_cast<Label>(label_);
+}
+
+inline FieldDescriptor::Type FieldDescriptor::type() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, &FieldDescriptor::TypeOnceInit, this);
+  }
+  return static_cast<Type>(type_);
+}
+
+inline bool FieldDescriptor::is_required() const {
+  return label() == LABEL_REQUIRED;
+}
+
+inline bool FieldDescriptor::is_optional() const {
+  return label() == LABEL_OPTIONAL;
+}
+
+inline bool FieldDescriptor::is_repeated() const {
+  return label() == LABEL_REPEATED;
+}
+
+inline bool FieldDescriptor::is_packable() const {
+  return is_repeated() && IsTypePackable(type());
+}
+
+inline bool FieldDescriptor::is_map() const {
+  return type() == TYPE_MESSAGE && is_map_message_type();
+}
+
+inline bool FieldDescriptor::has_optional_keyword() const {
+  return proto3_optional_ ||
+         (file()->syntax() == FileDescriptor::SYNTAX_PROTO2 && is_optional() &&
+          !containing_oneof());
+}
+
+inline const OneofDescriptor* FieldDescriptor::real_containing_oneof() const {
+  auto* oneof = containing_oneof();
+  return oneof && !oneof->is_synthetic() ? oneof : nullptr;
+}
+
+inline bool FieldDescriptor::has_presence() const {
+  if (is_repeated()) return false;
+  return cpp_type() == CPPTYPE_MESSAGE || containing_oneof() ||
+         file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
+// To save space, index() is computed by looking at the descriptor's position
+// in the parent's array of children.
+inline int FieldDescriptor::index() const {
+  if (!is_extension_) {
+    return static_cast<int>(this - containing_type()->fields_);
+  } else if (extension_scope() != nullptr) {
+    return static_cast<int>(this - extension_scope()->extensions_);
+  } else {
+    return static_cast<int>(this - file_->extensions_);
+  }
+}
+
+inline int Descriptor::index() const {
+  if (containing_type_ == nullptr) {
+    return static_cast<int>(this - file_->message_types_);
+  } else {
+    return static_cast<int>(this - containing_type_->nested_types_);
+  }
+}
+
+inline const FileDescriptor* OneofDescriptor::file() const {
+  return containing_type()->file();
+}
+
+inline int OneofDescriptor::index() const {
+  return static_cast<int>(this - containing_type_->oneof_decls_);
+}
+
+inline bool OneofDescriptor::is_synthetic() const {
+  return field_count() == 1 && field(0)->proto3_optional_;
+}
+
+inline int EnumDescriptor::index() const {
+  if (containing_type_ == nullptr) {
+    return static_cast<int>(this - file_->enum_types_);
+  } else {
+    return static_cast<int>(this - containing_type_->enum_types_);
+  }
+}
+
+inline const FileDescriptor* EnumValueDescriptor::file() const {
+  return type()->file();
+}
+
+inline int EnumValueDescriptor::index() const {
+  return static_cast<int>(this - type_->values_);
+}
+
+inline int ServiceDescriptor::index() const {
+  return static_cast<int>(this - file_->services_);
+}
+
+inline const FileDescriptor* MethodDescriptor::file() const {
+  return service()->file();
+}
+
+inline int MethodDescriptor::index() const {
+  return static_cast<int>(this - service_->methods_);
+}
+
+inline const char* FieldDescriptor::type_name() const {
+  return kTypeToName[type()];
+}
+
+inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const {
+  return kTypeToCppTypeMap[type()];
+}
+
+inline const char* FieldDescriptor::cpp_type_name() const {
+  return kCppTypeToName[kTypeToCppTypeMap[type()]];
+}
+
+inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) {
+  return kTypeToCppTypeMap[type];
+}
+
+inline const char* FieldDescriptor::TypeName(Type type) {
+  return kTypeToName[type];
+}
+
+inline const char* FieldDescriptor::CppTypeName(CppType cpp_type) {
+  return kCppTypeToName[cpp_type];
+}
+
+inline bool FieldDescriptor::IsTypePackable(Type field_type) {
+  return (field_type != FieldDescriptor::TYPE_STRING &&
+          field_type != FieldDescriptor::TYPE_GROUP &&
+          field_type != FieldDescriptor::TYPE_MESSAGE &&
+          field_type != FieldDescriptor::TYPE_BYTES);
+}
+
+inline const FileDescriptor* FileDescriptor::public_dependency(
+    int index) const {
+  return dependency(public_dependencies_[index]);
+}
+
+inline const FileDescriptor* FileDescriptor::weak_dependency(int index) const {
+  return dependency(weak_dependencies_[index]);
+}
+
+inline FileDescriptor::Syntax FileDescriptor::syntax() const {
+  return static_cast<Syntax>(syntax_);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#undef PROTOBUF_INTERNAL_CHECK_CLASS_SIZE
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_DESCRIPTOR_H__
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
new file mode 100644
index 0000000..d3bfb46
--- /dev/null
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -0,0 +1,11351 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+
+#include <google/protobuf/descriptor.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR FileDescriptorSet::FileDescriptorSet(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.file_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FileDescriptorSetDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FileDescriptorSetDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FileDescriptorSetDefaultTypeInternal() {}
+  union {
+    FileDescriptorSet _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileDescriptorSetDefaultTypeInternal _FileDescriptorSet_default_instance_;
+PROTOBUF_CONSTEXPR FileDescriptorProto::FileDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.dependency_)*/{}
+  , /*decltype(_impl_.message_type_)*/{}
+  , /*decltype(_impl_.enum_type_)*/{}
+  , /*decltype(_impl_.service_)*/{}
+  , /*decltype(_impl_.extension_)*/{}
+  , /*decltype(_impl_.public_dependency_)*/{}
+  , /*decltype(_impl_.weak_dependency_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.syntax_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.source_code_info_)*/nullptr} {}
+struct FileDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FileDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FileDescriptorProtoDefaultTypeInternal() {}
+  union {
+    FileDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileDescriptorProtoDefaultTypeInternal _FileDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.start_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct DescriptorProto_ExtensionRangeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DescriptorProto_ExtensionRangeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DescriptorProto_ExtensionRangeDefaultTypeInternal() {}
+  union {
+    DescriptorProto_ExtensionRange _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProto_ExtensionRangeDefaultTypeInternal _DescriptorProto_ExtensionRange_default_instance_;
+PROTOBUF_CONSTEXPR DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.start_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct DescriptorProto_ReservedRangeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DescriptorProto_ReservedRangeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DescriptorProto_ReservedRangeDefaultTypeInternal() {}
+  union {
+    DescriptorProto_ReservedRange _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProto_ReservedRangeDefaultTypeInternal _DescriptorProto_ReservedRange_default_instance_;
+PROTOBUF_CONSTEXPR DescriptorProto::DescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.field_)*/{}
+  , /*decltype(_impl_.nested_type_)*/{}
+  , /*decltype(_impl_.enum_type_)*/{}
+  , /*decltype(_impl_.extension_range_)*/{}
+  , /*decltype(_impl_.extension_)*/{}
+  , /*decltype(_impl_.oneof_decl_)*/{}
+  , /*decltype(_impl_.reserved_range_)*/{}
+  , /*decltype(_impl_.reserved_name_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct DescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DescriptorProtoDefaultTypeInternal() {}
+  union {
+    DescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProtoDefaultTypeInternal _DescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR ExtensionRangeOptions::ExtensionRangeOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct ExtensionRangeOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ExtensionRangeOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ExtensionRangeOptionsDefaultTypeInternal() {}
+  union {
+    ExtensionRangeOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExtensionRangeOptionsDefaultTypeInternal _ExtensionRangeOptions_default_instance_;
+PROTOBUF_CONSTEXPR FieldDescriptorProto::FieldDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.extendee_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.type_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.default_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.json_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.number_)*/0
+  , /*decltype(_impl_.oneof_index_)*/0
+  , /*decltype(_impl_.proto3_optional_)*/false
+  , /*decltype(_impl_.label_)*/1
+  , /*decltype(_impl_.type_)*/1} {}
+struct FieldDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldDescriptorProtoDefaultTypeInternal() {}
+  union {
+    FieldDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldDescriptorProtoDefaultTypeInternal _FieldDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR OneofDescriptorProto::OneofDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct OneofDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR OneofDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~OneofDescriptorProtoDefaultTypeInternal() {}
+  union {
+    OneofDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OneofDescriptorProtoDefaultTypeInternal _OneofDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.start_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal() {}
+  union {
+    EnumDescriptorProto_EnumReservedRange _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal _EnumDescriptorProto_EnumReservedRange_default_instance_;
+PROTOBUF_CONSTEXPR EnumDescriptorProto::EnumDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.value_)*/{}
+  , /*decltype(_impl_.reserved_range_)*/{}
+  , /*decltype(_impl_.reserved_name_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct EnumDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumDescriptorProtoDefaultTypeInternal() {}
+  union {
+    EnumDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDescriptorProtoDefaultTypeInternal _EnumDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR EnumValueDescriptorProto::EnumValueDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.number_)*/0} {}
+struct EnumValueDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumValueDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumValueDescriptorProtoDefaultTypeInternal() {}
+  union {
+    EnumValueDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueDescriptorProtoDefaultTypeInternal _EnumValueDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR ServiceDescriptorProto::ServiceDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.method_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct ServiceDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ServiceDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ServiceDescriptorProtoDefaultTypeInternal() {}
+  union {
+    ServiceDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ServiceDescriptorProtoDefaultTypeInternal _ServiceDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR MethodDescriptorProto::MethodDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.input_type_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.output_type_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.client_streaming_)*/false
+  , /*decltype(_impl_.server_streaming_)*/false} {}
+struct MethodDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MethodDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MethodDescriptorProtoDefaultTypeInternal() {}
+  union {
+    MethodDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodDescriptorProtoDefaultTypeInternal _MethodDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR FileOptions::FileOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.java_package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.java_outer_classname_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.go_package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.objc_class_prefix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.csharp_namespace_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.swift_prefix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.php_class_prefix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.php_namespace_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.php_metadata_namespace_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.ruby_package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.java_multiple_files_)*/false
+  , /*decltype(_impl_.java_generate_equals_and_hash_)*/false
+  , /*decltype(_impl_.java_string_check_utf8_)*/false
+  , /*decltype(_impl_.cc_generic_services_)*/false
+  , /*decltype(_impl_.java_generic_services_)*/false
+  , /*decltype(_impl_.py_generic_services_)*/false
+  , /*decltype(_impl_.php_generic_services_)*/false
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.optimize_for_)*/1
+  , /*decltype(_impl_.cc_enable_arenas_)*/true} {}
+struct FileOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FileOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FileOptionsDefaultTypeInternal() {}
+  union {
+    FileOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileOptionsDefaultTypeInternal _FileOptions_default_instance_;
+PROTOBUF_CONSTEXPR MessageOptions::MessageOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.message_set_wire_format_)*/false
+  , /*decltype(_impl_.no_standard_descriptor_accessor_)*/false
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.map_entry_)*/false} {}
+struct MessageOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MessageOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MessageOptionsDefaultTypeInternal() {}
+  union {
+    MessageOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MessageOptionsDefaultTypeInternal _MessageOptions_default_instance_;
+PROTOBUF_CONSTEXPR FieldOptions::FieldOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.ctype_)*/0
+  , /*decltype(_impl_.jstype_)*/0
+  , /*decltype(_impl_.packed_)*/false
+  , /*decltype(_impl_.lazy_)*/false
+  , /*decltype(_impl_.unverified_lazy_)*/false
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.weak_)*/false} {}
+struct FieldOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldOptionsDefaultTypeInternal() {}
+  union {
+    FieldOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldOptionsDefaultTypeInternal _FieldOptions_default_instance_;
+PROTOBUF_CONSTEXPR OneofOptions::OneofOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct OneofOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR OneofOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~OneofOptionsDefaultTypeInternal() {}
+  union {
+    OneofOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OneofOptionsDefaultTypeInternal _OneofOptions_default_instance_;
+PROTOBUF_CONSTEXPR EnumOptions::EnumOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.allow_alias_)*/false
+  , /*decltype(_impl_.deprecated_)*/false} {}
+struct EnumOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumOptionsDefaultTypeInternal() {}
+  union {
+    EnumOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumOptionsDefaultTypeInternal _EnumOptions_default_instance_;
+PROTOBUF_CONSTEXPR EnumValueOptions::EnumValueOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.deprecated_)*/false} {}
+struct EnumValueOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumValueOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumValueOptionsDefaultTypeInternal() {}
+  union {
+    EnumValueOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueOptionsDefaultTypeInternal _EnumValueOptions_default_instance_;
+PROTOBUF_CONSTEXPR ServiceOptions::ServiceOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.deprecated_)*/false} {}
+struct ServiceOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ServiceOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ServiceOptionsDefaultTypeInternal() {}
+  union {
+    ServiceOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ServiceOptionsDefaultTypeInternal _ServiceOptions_default_instance_;
+PROTOBUF_CONSTEXPR MethodOptions::MethodOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.idempotency_level_)*/0} {}
+struct MethodOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MethodOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MethodOptionsDefaultTypeInternal() {}
+  union {
+    MethodOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodOptionsDefaultTypeInternal _MethodOptions_default_instance_;
+PROTOBUF_CONSTEXPR UninterpretedOption_NamePart::UninterpretedOption_NamePart(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_part_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.is_extension_)*/false} {}
+struct UninterpretedOption_NamePartDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UninterpretedOption_NamePartDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UninterpretedOption_NamePartDefaultTypeInternal() {}
+  union {
+    UninterpretedOption_NamePart _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UninterpretedOption_NamePartDefaultTypeInternal _UninterpretedOption_NamePart_default_instance_;
+PROTOBUF_CONSTEXPR UninterpretedOption::UninterpretedOption(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{}
+  , /*decltype(_impl_.identifier_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.string_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.aggregate_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.positive_int_value_)*/uint64_t{0u}
+  , /*decltype(_impl_.negative_int_value_)*/int64_t{0}
+  , /*decltype(_impl_.double_value_)*/0} {}
+struct UninterpretedOptionDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UninterpretedOptionDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UninterpretedOptionDefaultTypeInternal() {}
+  union {
+    UninterpretedOption _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UninterpretedOptionDefaultTypeInternal _UninterpretedOption_default_instance_;
+PROTOBUF_CONSTEXPR SourceCodeInfo_Location::SourceCodeInfo_Location(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.path_)*/{}
+  , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+  , /*decltype(_impl_.span_)*/{}
+  , /*decltype(_impl_._span_cached_byte_size_)*/{0}
+  , /*decltype(_impl_.leading_detached_comments_)*/{}
+  , /*decltype(_impl_.leading_comments_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.trailing_comments_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}} {}
+struct SourceCodeInfo_LocationDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR SourceCodeInfo_LocationDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~SourceCodeInfo_LocationDefaultTypeInternal() {}
+  union {
+    SourceCodeInfo_Location _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceCodeInfo_LocationDefaultTypeInternal _SourceCodeInfo_Location_default_instance_;
+PROTOBUF_CONSTEXPR SourceCodeInfo::SourceCodeInfo(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.location_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct SourceCodeInfoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR SourceCodeInfoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~SourceCodeInfoDefaultTypeInternal() {}
+  union {
+    SourceCodeInfo _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceCodeInfoDefaultTypeInternal _SourceCodeInfo_default_instance_;
+PROTOBUF_CONSTEXPR GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.path_)*/{}
+  , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+  , /*decltype(_impl_.source_file_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.begin_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct GeneratedCodeInfo_AnnotationDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR GeneratedCodeInfo_AnnotationDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~GeneratedCodeInfo_AnnotationDefaultTypeInternal() {}
+  union {
+    GeneratedCodeInfo_Annotation _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfo_AnnotationDefaultTypeInternal _GeneratedCodeInfo_Annotation_default_instance_;
+PROTOBUF_CONSTEXPR GeneratedCodeInfo::GeneratedCodeInfo(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.annotation_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct GeneratedCodeInfoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR GeneratedCodeInfoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~GeneratedCodeInfoDefaultTypeInternal() {}
+  union {
+    GeneratedCodeInfo _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet, _impl_.file_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.dependency_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.public_dependency_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.weak_dependency_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.message_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.enum_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.service_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.extension_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.source_code_info_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.syntax_),
+  0,
+  1,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  3,
+  4,
+  2,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.start_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.end_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.options_),
+  1,
+  2,
+  0,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_.start_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_.end_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.field_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.extension_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.nested_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.enum_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.extension_range_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.oneof_decl_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.reserved_range_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.reserved_name_),
+  0,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  1,
+  ~0u,
+  ~0u,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _impl_.uninterpreted_option_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.label_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.type_name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.extendee_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.default_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.oneof_index_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.json_name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.proto3_optional_),
+  0,
+  6,
+  9,
+  10,
+  2,
+  1,
+  3,
+  7,
+  4,
+  5,
+  8,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_.options_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_.start_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_.end_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.reserved_range_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.reserved_name_),
+  0,
+  ~0u,
+  1,
+  ~0u,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.options_),
+  0,
+  2,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.method_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.options_),
+  0,
+  ~0u,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.input_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.output_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.client_streaming_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.server_streaming_),
+  0,
+  1,
+  2,
+  3,
+  4,
+  5,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_outer_classname_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_multiple_files_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_generate_equals_and_hash_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_string_check_utf8_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.optimize_for_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.go_package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.cc_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.py_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.cc_enable_arenas_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.objc_class_prefix_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.csharp_namespace_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.swift_prefix_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_class_prefix_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_namespace_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_metadata_namespace_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.ruby_package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  10,
+  11,
+  12,
+  18,
+  2,
+  13,
+  14,
+  15,
+  16,
+  17,
+  19,
+  3,
+  4,
+  5,
+  6,
+  7,
+  8,
+  9,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.message_set_wire_format_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.no_standard_descriptor_accessor_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.map_entry_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  2,
+  3,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.ctype_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.packed_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.jstype_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.lazy_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.unverified_lazy_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.weak_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.uninterpreted_option_),
+  0,
+  2,
+  1,
+  3,
+  4,
+  5,
+  6,
+  ~0u,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _impl_.uninterpreted_option_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.allow_alias_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_.uninterpreted_option_),
+  0,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_.uninterpreted_option_),
+  0,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.idempotency_level_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_.name_part_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_.is_extension_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.identifier_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.positive_int_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.negative_int_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.double_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.string_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.aggregate_value_),
+  ~0u,
+  0,
+  3,
+  4,
+  5,
+  1,
+  2,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.path_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.span_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.leading_comments_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.trailing_comments_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.leading_detached_comments_),
+  ~0u,
+  ~0u,
+  0,
+  1,
+  ~0u,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo, _impl_.location_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.path_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.source_file_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.begin_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.end_),
+  ~0u,
+  0,
+  1,
+  2,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, _impl_.annotation_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet)},
+  { 7, 25, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto)},
+  { 37, 46, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange)},
+  { 49, 57, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange)},
+  { 59, 75, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto)},
+  { 85, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions)},
+  { 92, 109, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto)},
+  { 120, 128, -1, sizeof(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto)},
+  { 130, 138, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange)},
+  { 140, 151, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto)},
+  { 156, 165, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto)},
+  { 168, 177, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto)},
+  { 180, 192, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto)},
+  { 198, 225, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileOptions)},
+  { 246, 257, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MessageOptions)},
+  { 262, 276, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldOptions)},
+  { 284, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::OneofOptions)},
+  { 291, 300, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumOptions)},
+  { 303, 311, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValueOptions)},
+  { 313, 321, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ServiceOptions)},
+  { 323, 332, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodOptions)},
+  { 335, 343, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart)},
+  { 345, 358, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
+  { 365, 376, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
+  { 381, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
+  { 388, 398, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
+  { 402, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_FileDescriptorSet_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FileDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ExtensionRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ReservedRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ExtensionRangeOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FieldDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_OneofDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_EnumReservedRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValueDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ServiceDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MethodDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FileOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MessageOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FieldOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_OneofOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValueOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ServiceOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MethodOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_NamePart_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_Location_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_Annotation_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n google/protobuf/descriptor.proto\022\017goog"
+  "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file"
+  "\030\001 \003(\0132$.google.protobuf.FileDescriptorP"
+  "roto\"\333\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001"
+  "(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency\030\003 \003(\t\022"
+  "\031\n\021public_dependency\030\n \003(\005\022\027\n\017weak_depen"
+  "dency\030\013 \003(\005\0226\n\014message_type\030\004 \003(\0132 .goog"
+  "le.protobuf.DescriptorProto\0227\n\tenum_type"
+  "\030\005 \003(\0132$.google.protobuf.EnumDescriptorP"
+  "roto\0228\n\007service\030\006 \003(\0132\'.google.protobuf."
+  "ServiceDescriptorProto\0228\n\textension\030\007 \003("
+  "\0132%.google.protobuf.FieldDescriptorProto"
+  "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File"
+  "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog"
+  "le.protobuf.SourceCodeInfo\022\016\n\006syntax\030\014 \001"
+  "(\t\"\251\005\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005"
+  "field\030\002 \003(\0132%.google.protobuf.FieldDescr"
+  "iptorProto\0228\n\textension\030\006 \003(\0132%.google.p"
+  "rotobuf.FieldDescriptorProto\0225\n\013nested_t"
+  "ype\030\003 \003(\0132 .google.protobuf.DescriptorPr"
+  "oto\0227\n\tenum_type\030\004 \003(\0132$.google.protobuf"
+  ".EnumDescriptorProto\022H\n\017extension_range\030"
+  "\005 \003(\0132/.google.protobuf.DescriptorProto."
+  "ExtensionRange\0229\n\noneof_decl\030\010 \003(\0132%.goo"
+  "gle.protobuf.OneofDescriptorProto\0220\n\007opt"
+  "ions\030\007 \001(\0132\037.google.protobuf.MessageOpti"
+  "ons\022F\n\016reserved_range\030\t \003(\0132..google.pro"
+  "tobuf.DescriptorProto.ReservedRange\022\025\n\rr"
+  "eserved_name\030\n \003(\t\032e\n\016ExtensionRange\022\r\n\005"
+  "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\0227\n\007options\030\003 \001("
+  "\0132&.google.protobuf.ExtensionRangeOption"
+  "s\032+\n\rReservedRange\022\r\n\005start\030\001 \001(\005\022\013\n\003end"
+  "\030\002 \001(\005\"g\n\025ExtensionRangeOptions\022C\n\024unint"
+  "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
+  ".UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\325\005\n\024Fiel"
+  "dDescriptorProto\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."
+  "FieldDescriptorProto.Label\0228\n\004type\030\005 \001(\016"
+  "2*.google.protobuf.FieldDescriptorProto."
+  "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\021\n\tjson_name\030\n \001(\t\022.\n\007options\030\010 \001("
+  "\0132\035.google.protobuf.FieldOptions\022\027\n\017prot"
+  "o3_optional\030\021 \001(\010\"\266\002\n\004Type\022\017\n\013TYPE_DOUBL"
+  "E\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013T"
+  "YPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIX"
+  "ED64\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\013TYPE_UINT3"
+  "2\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_SINT32\020\021\022\017\n\013TYP"
+  "E_SINT64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022"
+  "\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\""
+  "T\n\024OneofDescriptorProto\022\014\n\004name\030\001 \001(\t\022.\n"
+  "\007options\030\002 \001(\0132\035.google.protobuf.OneofOp"
+  "tions\"\244\002\n\023EnumDescriptorProto\022\014\n\004name\030\001 "
+  "\001(\t\0228\n\005value\030\002 \003(\0132).google.protobuf.Enu"
+  "mValueDescriptorProto\022-\n\007options\030\003 \001(\0132\034"
+  ".google.protobuf.EnumOptions\022N\n\016reserved"
+  "_range\030\004 \003(\01326.google.protobuf.EnumDescr"
+  "iptorProto.EnumReservedRange\022\025\n\rreserved"
+  "_name\030\005 \003(\t\032/\n\021EnumReservedRange\022\r\n\005star"
+  "t\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"l\n\030EnumValueDescrip"
+  "torProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222"
+  "\n\007options\030\003 \001(\0132!.google.protobuf.EnumVa"
+  "lueOptions\"\220\001\n\026ServiceDescriptorProto\022\014\n"
+  "\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.pro"
+  "tobuf.MethodDescriptorProto\0220\n\007options\030\003"
+  " \001(\0132\037.google.protobuf.ServiceOptions\"\301\001"
+  "\n\025MethodDescriptorProto\022\014\n\004name\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.protobuf.Method"
+  "Options\022\037\n\020client_streaming\030\005 \001(\010:\005false"
+  "\022\037\n\020server_streaming\030\006 \001(\010:\005false\"\245\006\n\013Fi"
+  "leOptions\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_"
+  "outer_classname\030\010 \001(\t\022\"\n\023java_multiple_f"
+  "iles\030\n \001(\010:\005false\022)\n\035java_generate_equal"
+  "s_and_hash\030\024 \001(\010B\002\030\001\022%\n\026java_string_chec"
+  "k_utf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001("
+  "\0162).google.protobuf.FileOptions.Optimize"
+  "Mode:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_ge"
+  "neric_services\030\020 \001(\010:\005false\022$\n\025java_gene"
+  "ric_services\030\021 \001(\010:\005false\022\"\n\023py_generic_"
+  "services\030\022 \001(\010:\005false\022#\n\024php_generic_ser"
+  "vices\030* \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005"
+  "false\022\036\n\020cc_enable_arenas\030\037 \001(\010:\004true\022\031\n"
+  "\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_names"
+  "pace\030% \001(\t\022\024\n\014swift_prefix\030\' \001(\t\022\030\n\020php_"
+  "class_prefix\030( \001(\t\022\025\n\rphp_namespace\030) \001("
+  "\t\022\036\n\026php_metadata_namespace\030, \001(\t\022\024\n\014rub"
+  "y_package\030- \001(\t\022C\n\024uninterpreted_option\030"
+  "\347\007 \003(\0132$.google.protobuf.UninterpretedOp"
+  "tion\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_"
+  "SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002J\004\010&\020"
+  "\'\"\204\002\n\016MessageOptions\022&\n\027message_set_wire"
+  "_format\030\001 \001(\010:\005false\022.\n\037no_standard_desc"
+  "riptor_accessor\030\002 \001(\010:\005false\022\031\n\ndeprecat"
+  "ed\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024un"
+  "interpreted_option\030\347\007 \003(\0132$.google.proto"
+  "buf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\004\020\005"
+  "J\004\010\005\020\006J\004\010\006\020\007J\004\010\010\020\tJ\004\010\t\020\n\"\276\003\n\014FieldOption"
+  "s\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Field"
+  "Options.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n"
+  "\006jstype\030\006 \001(\0162$.google.protobuf.FieldOpt"
+  "ions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005fa"
+  "lse\022\036\n\017unverified_lazy\030\017 \001(\010:\005false\022\031\n\nd"
+  "eprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005fa"
+  "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
+  "gle.protobuf.UninterpretedOption\"/\n\005CTyp"
+  "e\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020"
+  "\002\"5\n\006JSType\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\002J\004\010\004\020\005\"^\n\014One"
+  "ofOptions\022C\n\024uninterpreted_option\030\347\007 \003(\013"
+  "2$.google.protobuf.UninterpretedOption*\t"
+  "\010\350\007\020\200\200\200\200\002\"\223\001\n\013EnumOptions\022\023\n\013allow_alias"
+  "\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024uni"
+  "nterpreted_option\030\347\007 \003(\0132$.google.protob"
+  "uf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\005\020\006\""
+  "}\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\ndeprecated\030!"
+  " \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\"\255\002\n\rMethodOptions\022\031\n\ndepreca"
+  "ted\030! \001(\010:\005false\022_\n\021idempotency_level\030\" "
+  "\001(\0162/.google.protobuf.MethodOptions.Idem"
+  "potencyLevel:\023IDEMPOTENCY_UNKNOWN\022C\n\024uni"
+  "nterpreted_option\030\347\007 \003(\0132$.google.protob"
+  "uf.UninterpretedOption\"P\n\020IdempotencyLev"
+  "el\022\027\n\023IDEMPOTENCY_UNKNOWN\020\000\022\023\n\017NO_SIDE_E"
+  "FFECTS\020\001\022\016\n\nIDEMPOTENT\020\002*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023"
+  "UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goog"
+  "le.protobuf.UninterpretedOption.NamePart"
+  "\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_i"
+  "nt_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001"
+  "(\003\022\024\n\014double_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\010NameP"
+  "art\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(.google.protobuf.SourceCodeInfo.Locat"
+  "ion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004sp"
+  "an\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022\031"
+  "\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_det"
+  "ached_comments\030\006 \003(\t\"\247\001\n\021GeneratedCodeIn"
+  "fo\022A\n\nannotation\030\001 \003(\0132-.google.protobuf"
+  ".GeneratedCodeInfo.Annotation\032O\n\nAnnotat"
+  "ion\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(\005B~\n\023com.go"
+  "ogle.protobufB\020DescriptorProtosH\001Z-googl"
+  "e.golang.org/protobuf/types/descriptorpb"
+  "\370\001\001\242\002\003GPB\252\002\032Google.Protobuf.Reflection"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
+    false, false, 6078, descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
+    "google/protobuf/descriptor.proto",
+    &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, nullptr, 0, 27,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fdescriptor_2eproto(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[0];
+}
+bool FieldDescriptorProto_Type_IsValid(int value) {
+  switch (value) {
+    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 (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BOOL;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_STRING;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_GROUP;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_MESSAGE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BYTES;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_ENUM;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
+constexpr int FieldDescriptorProto::Type_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[1];
+}
+bool FieldDescriptorProto_Label_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
+constexpr int FieldDescriptorProto::Label_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[2];
+}
+bool FileOptions_OptimizeMode_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FileOptions_OptimizeMode FileOptions::SPEED;
+constexpr FileOptions_OptimizeMode FileOptions::CODE_SIZE;
+constexpr FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
+constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
+constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
+constexpr int FileOptions::OptimizeMode_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[3];
+}
+bool FieldOptions_CType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldOptions_CType FieldOptions::STRING;
+constexpr FieldOptions_CType FieldOptions::CORD;
+constexpr FieldOptions_CType FieldOptions::STRING_PIECE;
+constexpr FieldOptions_CType FieldOptions::CType_MIN;
+constexpr FieldOptions_CType FieldOptions::CType_MAX;
+constexpr int FieldOptions::CType_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[4];
+}
+bool FieldOptions_JSType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldOptions_JSType FieldOptions::JS_NORMAL;
+constexpr FieldOptions_JSType FieldOptions::JS_STRING;
+constexpr FieldOptions_JSType FieldOptions::JS_NUMBER;
+constexpr FieldOptions_JSType FieldOptions::JSType_MIN;
+constexpr FieldOptions_JSType FieldOptions::JSType_MAX;
+constexpr int FieldOptions::JSType_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[5];
+}
+bool MethodOptions_IdempotencyLevel_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENCY_UNKNOWN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::NO_SIDE_EFFECTS;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENT;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX;
+constexpr int MethodOptions::IdempotencyLevel_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+
+// ===================================================================
+
+class FileDescriptorSet::_Internal {
+ public:
+};
+
+FileDescriptorSet::FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorSet)
+}
+FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FileDescriptorSet* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_){from._impl_.file_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorSet)
+}
+
+inline void FileDescriptorSet::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+FileDescriptorSet::~FileDescriptorSet() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorSet)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FileDescriptorSet::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.file_.~RepeatedPtrField();
+}
+
+void FileDescriptorSet::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FileDescriptorSet::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorSet)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.file_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FileDescriptorSet::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.FileDescriptorProto file = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_file(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FileDescriptorSet::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.FileDescriptorProto file = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_file(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorSet)
+  return target;
+}
+
+size_t FileDescriptorSet::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.FileDescriptorProto file = 1;
+  total_size += 1UL * this->_internal_file_size();
+  for (const auto& msg : this->_impl_.file_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileDescriptorSet::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FileDescriptorSet::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorSet::GetClassData() const { return &_class_data_; }
+
+
+void FileDescriptorSet::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FileDescriptorSet*>(&to_msg);
+  auto& from = static_cast<const FileDescriptorSet&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.file_.MergeFrom(from._impl_.file_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorSet)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FileDescriptorSet::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.file_))
+    return false;
+  return true;
+}
+
+void FileDescriptorSet::InternalSwap(FileDescriptorSet* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.file_.InternalSwap(&other->_impl_.file_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorSet::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[0]);
+}
+
+// ===================================================================
+
+class FileDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FileDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::FileOptions& options(const FileDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& source_code_info(const FileDescriptorProto* msg);
+  static void set_has_source_code_info(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_syntax(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::FileOptions&
+FileDescriptorProto::_Internal::options(const FileDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo&
+FileDescriptorProto::_Internal::source_code_info(const FileDescriptorProto* msg) {
+  return *msg->_impl_.source_code_info_;
+}
+FileDescriptorProto::FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorProto)
+}
+FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FileDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.dependency_){from._impl_.dependency_}
+    , decltype(_impl_.message_type_){from._impl_.message_type_}
+    , decltype(_impl_.enum_type_){from._impl_.enum_type_}
+    , decltype(_impl_.service_){from._impl_.service_}
+    , decltype(_impl_.extension_){from._impl_.extension_}
+    , decltype(_impl_.public_dependency_){from._impl_.public_dependency_}
+    , decltype(_impl_.weak_dependency_){from._impl_.weak_dependency_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.package_){}
+    , decltype(_impl_.syntax_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.source_code_info_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_package()) {
+    _this->_impl_.package_.Set(from._internal_package(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.syntax_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_syntax()) {
+    _this->_impl_.syntax_.Set(from._internal_syntax(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::FileOptions(*from._impl_.options_);
+  }
+  if (from._internal_has_source_code_info()) {
+    _this->_impl_.source_code_info_ = new ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo(*from._impl_.source_code_info_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorProto)
+}
+
+inline void FileDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.dependency_){arena}
+    , decltype(_impl_.message_type_){arena}
+    , decltype(_impl_.enum_type_){arena}
+    , decltype(_impl_.service_){arena}
+    , decltype(_impl_.extension_){arena}
+    , decltype(_impl_.public_dependency_){arena}
+    , decltype(_impl_.weak_dependency_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.package_){}
+    , decltype(_impl_.syntax_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.source_code_info_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.syntax_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+FileDescriptorProto::~FileDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FileDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.dependency_.~RepeatedPtrField();
+  _impl_.message_type_.~RepeatedPtrField();
+  _impl_.enum_type_.~RepeatedPtrField();
+  _impl_.service_.~RepeatedPtrField();
+  _impl_.extension_.~RepeatedPtrField();
+  _impl_.public_dependency_.~RepeatedField();
+  _impl_.weak_dependency_.~RepeatedField();
+  _impl_.name_.Destroy();
+  _impl_.package_.Destroy();
+  _impl_.syntax_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+  if (this != internal_default_instance()) delete _impl_.source_code_info_;
+}
+
+void FileDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FileDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.dependency_.Clear();
+  _impl_.message_type_.Clear();
+  _impl_.enum_type_.Clear();
+  _impl_.service_.Clear();
+  _impl_.extension_.Clear();
+  _impl_.public_dependency_.Clear();
+  _impl_.weak_dependency_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000001fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.package_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.syntax_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+    if (cached_has_bits & 0x00000010u) {
+      GOOGLE_DCHECK(_impl_.source_code_info_ != nullptr);
+      _impl_.source_code_info_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FileDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string package = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string dependency = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_dependency();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.dependency");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto message_type = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_message_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_enum_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_service(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_extension(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<58>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FileOptions options = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_code_info(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated int32 public_dependency = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            _internal_add_public_dependency(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<80>(ptr));
+        } else if (static_cast<uint8_t>(tag) == 82) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_public_dependency(), ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated int32 weak_dependency = 11;
+      case 11:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 88)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            _internal_add_weak_dependency(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<88>(ptr));
+        } else if (static_cast<uint8_t>(tag) == 90) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_weak_dependency(), ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string syntax = 12;
+      case 12:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 98)) {
+          auto str = _internal_mutable_syntax();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.syntax");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FileDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string package = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_package().data(), static_cast<int>(this->_internal_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.package");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_package(), target);
+  }
+
+  // repeated string dependency = 3;
+  for (int i = 0, n = this->_internal_dependency_size(); i < n; i++) {
+    const auto& s = this->_internal_dependency(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.dependency");
+    target = stream->WriteString(3, s, target);
+  }
+
+  // repeated .google.protobuf.DescriptorProto message_type = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_message_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_message_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enum_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enum_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(5, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_service_size()); i < n; i++) {
+    const auto& repfield = this->_internal_service(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(7, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.FileOptions options = 8;
+  if (cached_has_bits & 0x00000008u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(8, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+  if (cached_has_bits & 0x00000010u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(9, _Internal::source_code_info(this),
+        _Internal::source_code_info(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated int32 public_dependency = 10;
+  for (int i = 0, n = this->_internal_public_dependency_size(); i < n; i++) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(10, this->_internal_public_dependency(i), target);
+  }
+
+  // repeated int32 weak_dependency = 11;
+  for (int i = 0, n = this->_internal_weak_dependency_size(); i < n; i++) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(11, this->_internal_weak_dependency(i), target);
+  }
+
+  // optional string syntax = 12;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_syntax().data(), static_cast<int>(this->_internal_syntax().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.syntax");
+    target = stream->WriteStringMaybeAliased(
+        12, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorProto)
+  return target;
+}
+
+size_t FileDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated string dependency = 3;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.dependency_.size());
+  for (int i = 0, n = _impl_.dependency_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.dependency_.Get(i));
+  }
+
+  // repeated .google.protobuf.DescriptorProto message_type = 4;
+  total_size += 1UL * this->_internal_message_type_size();
+  for (const auto& msg : this->_impl_.message_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+  total_size += 1UL * this->_internal_enum_type_size();
+  for (const auto& msg : this->_impl_.enum_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+  total_size += 1UL * this->_internal_service_size();
+  for (const auto& msg : this->_impl_.service_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+  total_size += 1UL * this->_internal_extension_size();
+  for (const auto& msg : this->_impl_.extension_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated int32 public_dependency = 10;
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.public_dependency_);
+    total_size += 1 *
+                  ::_pbi::FromIntSize(this->_internal_public_dependency_size());
+    total_size += data_size;
+  }
+
+  // repeated int32 weak_dependency = 11;
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.weak_dependency_);
+    total_size += 1 *
+                  ::_pbi::FromIntSize(this->_internal_weak_dependency_size());
+    total_size += data_size;
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000001fu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string package = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_package());
+    }
+
+    // optional string syntax = 12;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_syntax());
+    }
+
+    // optional .google.protobuf.FileOptions options = 8;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.source_code_info_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FileDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void FileDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FileDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const FileDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.dependency_.MergeFrom(from._impl_.dependency_);
+  _this->_impl_.message_type_.MergeFrom(from._impl_.message_type_);
+  _this->_impl_.enum_type_.MergeFrom(from._impl_.enum_type_);
+  _this->_impl_.service_.MergeFrom(from._impl_.service_);
+  _this->_impl_.extension_.MergeFrom(from._impl_.extension_);
+  _this->_impl_.public_dependency_.MergeFrom(from._impl_.public_dependency_);
+  _this->_impl_.weak_dependency_.MergeFrom(from._impl_.weak_dependency_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000001fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_package(from._internal_package());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_syntax(from._internal_syntax());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::FileOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_internal_mutable_source_code_info()->::PROTOBUF_NAMESPACE_ID::SourceCodeInfo::MergeFrom(
+          from._internal_source_code_info());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FileDescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.message_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.enum_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.service_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.extension_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.dependency_.InternalSwap(&other->_impl_.dependency_);
+  _impl_.message_type_.InternalSwap(&other->_impl_.message_type_);
+  _impl_.enum_type_.InternalSwap(&other->_impl_.enum_type_);
+  _impl_.service_.InternalSwap(&other->_impl_.service_);
+  _impl_.extension_.InternalSwap(&other->_impl_.extension_);
+  _impl_.public_dependency_.InternalSwap(&other->_impl_.public_dependency_);
+  _impl_.weak_dependency_.InternalSwap(&other->_impl_.weak_dependency_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.package_, lhs_arena,
+      &other->_impl_.package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.syntax_, lhs_arena,
+      &other->_impl_.syntax_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FileDescriptorProto, _impl_.source_code_info_)
+      + sizeof(FileDescriptorProto::_impl_.source_code_info_)
+      - PROTOBUF_FIELD_OFFSET(FileDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[1]);
+}
+
+// ===================================================================
+
+class DescriptorProto_ExtensionRange::_Internal {
+ public:
+  using HasBits = decltype(std::declval<DescriptorProto_ExtensionRange>()._impl_._has_bits_);
+  static void set_has_start(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& options(const DescriptorProto_ExtensionRange* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions&
+DescriptorProto_ExtensionRange::_Internal::options(const DescriptorProto_ExtensionRange* msg) {
+  return *msg->_impl_.options_;
+}
+DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ExtensionRange)
+}
+DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DescriptorProto_ExtensionRange* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.start_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions(*from._impl_.options_);
+  }
+  ::memcpy(&_impl_.start_, &from._impl_.start_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ExtensionRange)
+}
+
+inline void DescriptorProto_ExtensionRange::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.start_){0}
+    , decltype(_impl_.end_){0}
+  };
+}
+
+DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ExtensionRange)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DescriptorProto_ExtensionRange::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void DescriptorProto_ExtensionRange::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DescriptorProto_ExtensionRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ExtensionRange)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    GOOGLE_DCHECK(_impl_.options_ != nullptr);
+    _impl_.options_->Clear();
+  }
+  if (cached_has_bits & 0x00000006u) {
+    ::memset(&_impl_.start_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 start = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_start(&has_bits);
+          _impl_.start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.ExtensionRangeOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DescriptorProto_ExtensionRange::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 start = 1;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+  }
+
+  // optional .google.protobuf.ExtensionRangeOptions options = 3;
+  if (cached_has_bits & 0x00000001u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ExtensionRange)
+  return target;
+}
+
+size_t DescriptorProto_ExtensionRange::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    // optional .google.protobuf.ExtensionRangeOptions options = 3;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional int32 start = 1;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+    }
+
+    // optional int32 end = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto_ExtensionRange::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DescriptorProto_ExtensionRange::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ExtensionRange::GetClassData() const { return &_class_data_; }
+
+
+void DescriptorProto_ExtensionRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DescriptorProto_ExtensionRange*>(&to_msg);
+  auto& from = static_cast<const DescriptorProto_ExtensionRange&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.start_ = from._impl_.start_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto_ExtensionRange::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(DescriptorProto_ExtensionRange, _impl_.end_)
+      + sizeof(DescriptorProto_ExtensionRange::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(DescriptorProto_ExtensionRange, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ExtensionRange::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[2]);
+}
+
+// ===================================================================
+
+class DescriptorProto_ReservedRange::_Internal {
+ public:
+  using HasBits = decltype(std::declval<DescriptorProto_ReservedRange>()._impl_._has_bits_);
+  static void set_has_start(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DescriptorProto_ReservedRange* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.start_, &from._impl_.start_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+inline void DescriptorProto_ReservedRange::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){0}
+    , decltype(_impl_.end_){0}
+  };
+}
+
+DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ReservedRange)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DescriptorProto_ReservedRange::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void DescriptorProto_ReservedRange::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DescriptorProto_ReservedRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ReservedRange)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    ::memset(&_impl_.start_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 start = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_start(&has_bits);
+          _impl_.start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DescriptorProto_ReservedRange::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 start = 1;
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange)
+  return target;
+}
+
+size_t DescriptorProto_ReservedRange::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional int32 start = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+    }
+
+    // optional int32 end = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto_ReservedRange::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DescriptorProto_ReservedRange::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ReservedRange::GetClassData() const { return &_class_data_; }
+
+
+void DescriptorProto_ReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DescriptorProto_ReservedRange*>(&to_msg);
+  auto& from = static_cast<const DescriptorProto_ReservedRange&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.start_ = from._impl_.start_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto_ReservedRange::IsInitialized() const {
+  return true;
+}
+
+void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(DescriptorProto_ReservedRange, _impl_.end_)
+      + sizeof(DescriptorProto_ReservedRange::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(DescriptorProto_ReservedRange, _impl_.start_)>(
+          reinterpret_cast<char*>(&_impl_.start_),
+          reinterpret_cast<char*>(&other->_impl_.start_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ReservedRange::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[3]);
+}
+
+// ===================================================================
+
+class DescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<DescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::MessageOptions& options(const DescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::MessageOptions&
+DescriptorProto::_Internal::options(const DescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+DescriptorProto::DescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto)
+}
+DescriptorProto::DescriptorProto(const DescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.field_){from._impl_.field_}
+    , decltype(_impl_.nested_type_){from._impl_.nested_type_}
+    , decltype(_impl_.enum_type_){from._impl_.enum_type_}
+    , decltype(_impl_.extension_range_){from._impl_.extension_range_}
+    , decltype(_impl_.extension_){from._impl_.extension_}
+    , decltype(_impl_.oneof_decl_){from._impl_.oneof_decl_}
+    , decltype(_impl_.reserved_range_){from._impl_.reserved_range_}
+    , decltype(_impl_.reserved_name_){from._impl_.reserved_name_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::MessageOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto)
+}
+
+inline void DescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.field_){arena}
+    , decltype(_impl_.nested_type_){arena}
+    , decltype(_impl_.enum_type_){arena}
+    , decltype(_impl_.extension_range_){arena}
+    , decltype(_impl_.extension_){arena}
+    , decltype(_impl_.oneof_decl_){arena}
+    , decltype(_impl_.reserved_range_){arena}
+    , decltype(_impl_.reserved_name_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+DescriptorProto::~DescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.field_.~RepeatedPtrField();
+  _impl_.nested_type_.~RepeatedPtrField();
+  _impl_.enum_type_.~RepeatedPtrField();
+  _impl_.extension_range_.~RepeatedPtrField();
+  _impl_.extension_.~RepeatedPtrField();
+  _impl_.oneof_decl_.~RepeatedPtrField();
+  _impl_.reserved_range_.~RepeatedPtrField();
+  _impl_.reserved_name_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void DescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.field_.Clear();
+  _impl_.nested_type_.Clear();
+  _impl_.enum_type_.Clear();
+  _impl_.extension_range_.Clear();
+  _impl_.extension_.Clear();
+  _impl_.oneof_decl_.Clear();
+  _impl_.reserved_range_.Clear();
+  _impl_.reserved_name_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.DescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FieldDescriptorProto field = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_field(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto nested_type = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_nested_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_enum_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_extension_range(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_extension(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.MessageOptions options = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_oneof_decl(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<66>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_reserved_range(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<74>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string reserved_name = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_reserved_name();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.DescriptorProto.reserved_name");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<82>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto field = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_field_size()); i < n; i++) {
+    const auto& repfield = this->_internal_field(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.DescriptorProto nested_type = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_nested_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_nested_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enum_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enum_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension_range(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(5, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.MessageOptions options = 7;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(7, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_oneof_decl_size()); i < n; i++) {
+    const auto& repfield = this->_internal_oneof_decl(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(8, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_reserved_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_reserved_range(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(9, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated string reserved_name = 10;
+  for (int i = 0, n = this->_internal_reserved_name_size(); i < n; i++) {
+    const auto& s = this->_internal_reserved_name(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.reserved_name");
+    target = stream->WriteString(10, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto)
+  return target;
+}
+
+size_t DescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.FieldDescriptorProto field = 2;
+  total_size += 1UL * this->_internal_field_size();
+  for (const auto& msg : this->_impl_.field_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.DescriptorProto nested_type = 3;
+  total_size += 1UL * this->_internal_nested_type_size();
+  for (const auto& msg : this->_impl_.nested_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+  total_size += 1UL * this->_internal_enum_type_size();
+  for (const auto& msg : this->_impl_.enum_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+  total_size += 1UL * this->_internal_extension_range_size();
+  for (const auto& msg : this->_impl_.extension_range_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+  total_size += 1UL * this->_internal_extension_size();
+  for (const auto& msg : this->_impl_.extension_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+  total_size += 1UL * this->_internal_oneof_decl_size();
+  for (const auto& msg : this->_impl_.oneof_decl_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  total_size += 1UL * this->_internal_reserved_range_size();
+  for (const auto& msg : this->_impl_.reserved_range_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated string reserved_name = 10;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.reserved_name_.size());
+  for (int i = 0, n = _impl_.reserved_name_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.reserved_name_.Get(i));
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.MessageOptions options = 7;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void DescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DescriptorProto*>(&to_msg);
+  auto& from = static_cast<const DescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.field_.MergeFrom(from._impl_.field_);
+  _this->_impl_.nested_type_.MergeFrom(from._impl_.nested_type_);
+  _this->_impl_.enum_type_.MergeFrom(from._impl_.enum_type_);
+  _this->_impl_.extension_range_.MergeFrom(from._impl_.extension_range_);
+  _this->_impl_.extension_.MergeFrom(from._impl_.extension_);
+  _this->_impl_.oneof_decl_.MergeFrom(from._impl_.oneof_decl_);
+  _this->_impl_.reserved_range_.MergeFrom(from._impl_.reserved_range_);
+  _this->_impl_.reserved_name_.MergeFrom(from._impl_.reserved_name_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::MessageOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DescriptorProto::CopyFrom(const DescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.field_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.nested_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.enum_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.extension_range_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.extension_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.oneof_decl_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void DescriptorProto::InternalSwap(DescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.field_.InternalSwap(&other->_impl_.field_);
+  _impl_.nested_type_.InternalSwap(&other->_impl_.nested_type_);
+  _impl_.enum_type_.InternalSwap(&other->_impl_.enum_type_);
+  _impl_.extension_range_.InternalSwap(&other->_impl_.extension_range_);
+  _impl_.extension_.InternalSwap(&other->_impl_.extension_);
+  _impl_.oneof_decl_.InternalSwap(&other->_impl_.oneof_decl_);
+  _impl_.reserved_range_.InternalSwap(&other->_impl_.reserved_range_);
+  _impl_.reserved_name_.InternalSwap(&other->_impl_.reserved_name_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[4]);
+}
+
+// ===================================================================
+
+class ExtensionRangeOptions::_Internal {
+ public:
+};
+
+ExtensionRangeOptions::ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ExtensionRangeOptions)
+}
+ExtensionRangeOptions::ExtensionRangeOptions(const ExtensionRangeOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ExtensionRangeOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ExtensionRangeOptions)
+}
+
+inline void ExtensionRangeOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+ExtensionRangeOptions::~ExtensionRangeOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ExtensionRangeOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ExtensionRangeOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void ExtensionRangeOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ExtensionRangeOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ExtensionRangeOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ExtensionRangeOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ExtensionRangeOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ExtensionRangeOptions)
+  return target;
+}
+
+size_t ExtensionRangeOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ExtensionRangeOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ExtensionRangeOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ExtensionRangeOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ExtensionRangeOptions::GetClassData() const { return &_class_data_; }
+
+
+void ExtensionRangeOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ExtensionRangeOptions*>(&to_msg);
+  auto& from = static_cast<const ExtensionRangeOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ExtensionRangeOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ExtensionRangeOptions::CopyFrom(const ExtensionRangeOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ExtensionRangeOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ExtensionRangeOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void ExtensionRangeOptions::InternalSwap(ExtensionRangeOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ExtensionRangeOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[5]);
+}
+
+// ===================================================================
+
+class FieldDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FieldDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_number(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
+  static void set_has_label(HasBits* has_bits) {
+    (*has_bits)[0] |= 512u;
+  }
+  static void set_has_type(HasBits* has_bits) {
+    (*has_bits)[0] |= 1024u;
+  }
+  static void set_has_type_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_extendee(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_default_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_oneof_index(HasBits* has_bits) {
+    (*has_bits)[0] |= 128u;
+  }
+  static void set_has_json_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::FieldOptions& options(const FieldDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_proto3_optional(HasBits* has_bits) {
+    (*has_bits)[0] |= 256u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::FieldOptions&
+FieldDescriptorProto::_Internal::options(const FieldDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+FieldDescriptorProto::FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldDescriptorProto)
+}
+FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FieldDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.extendee_){}
+    , decltype(_impl_.type_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){}
+    , decltype(_impl_.oneof_index_){}
+    , decltype(_impl_.proto3_optional_){}
+    , decltype(_impl_.label_){}
+    , decltype(_impl_.type_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.extendee_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_extendee()) {
+    _this->_impl_.extendee_.Set(from._internal_extendee(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.type_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_type_name()) {
+    _this->_impl_.type_name_.Set(from._internal_type_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_default_value()) {
+    _this->_impl_.default_value_.Set(from._internal_default_value(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_json_name()) {
+    _this->_impl_.json_name_.Set(from._internal_json_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::FieldOptions(*from._impl_.options_);
+  }
+  ::memcpy(&_impl_.number_, &from._impl_.number_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.type_) -
+    reinterpret_cast<char*>(&_impl_.number_)) + sizeof(_impl_.type_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldDescriptorProto)
+}
+
+inline void FieldDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.extendee_){}
+    , decltype(_impl_.type_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){0}
+    , decltype(_impl_.oneof_index_){0}
+    , decltype(_impl_.proto3_optional_){false}
+    , decltype(_impl_.label_){1}
+    , decltype(_impl_.type_){1}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.extendee_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.type_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+FieldDescriptorProto::~FieldDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FieldDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.extendee_.Destroy();
+  _impl_.type_name_.Destroy();
+  _impl_.default_value_.Destroy();
+  _impl_.json_name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void FieldDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FieldDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.extendee_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.type_name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _impl_.default_value_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _impl_.json_name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000020u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  if (cached_has_bits & 0x000000c0u) {
+    ::memset(&_impl_.number_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.oneof_index_) -
+        reinterpret_cast<char*>(&_impl_.number_)) + sizeof(_impl_.oneof_index_));
+  }
+  if (cached_has_bits & 0x00000700u) {
+    _impl_.proto3_optional_ = false;
+    _impl_.label_ = 1;
+    _impl_.type_ = 1;
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string extendee = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_extendee();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.extendee");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 number = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_number(&has_bits);
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_IsValid(val))) {
+            _internal_set_label(static_cast<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(4, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_IsValid(val))) {
+            _internal_set_type(static_cast<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(5, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string type_name = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          auto str = _internal_mutable_type_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.type_name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string default_value = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          auto str = _internal_mutable_default_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.default_value");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldOptions options = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 oneof_index = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 72)) {
+          _Internal::set_has_oneof_index(&has_bits);
+          _impl_.oneof_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string json_name = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
+          auto str = _internal_mutable_json_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.json_name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool proto3_optional = 17;
+      case 17:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 136)) {
+          _Internal::set_has_proto3_optional(&has_bits);
+          _impl_.proto3_optional_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FieldDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string extendee = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_extendee().data(), static_cast<int>(this->_internal_extendee().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.extendee");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_extendee(), target);
+  }
+
+  // optional int32 number = 3;
+  if (cached_has_bits & 0x00000040u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
+  }
+
+  // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+  if (cached_has_bits & 0x00000200u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      4, this->_internal_label(), target);
+  }
+
+  // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+  if (cached_has_bits & 0x00000400u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      5, this->_internal_type(), target);
+  }
+
+  // optional string type_name = 6;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_type_name().data(), static_cast<int>(this->_internal_type_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.type_name");
+    target = stream->WriteStringMaybeAliased(
+        6, this->_internal_type_name(), target);
+  }
+
+  // optional string default_value = 7;
+  if (cached_has_bits & 0x00000008u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_default_value().data(), static_cast<int>(this->_internal_default_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.default_value");
+    target = stream->WriteStringMaybeAliased(
+        7, this->_internal_default_value(), target);
+  }
+
+  // optional .google.protobuf.FieldOptions options = 8;
+  if (cached_has_bits & 0x00000020u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(8, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // optional int32 oneof_index = 9;
+  if (cached_has_bits & 0x00000080u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(9, this->_internal_oneof_index(), target);
+  }
+
+  // optional string json_name = 10;
+  if (cached_has_bits & 0x00000010u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_json_name().data(), static_cast<int>(this->_internal_json_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.json_name");
+    target = stream->WriteStringMaybeAliased(
+        10, this->_internal_json_name(), target);
+  }
+
+  // optional bool proto3_optional = 17;
+  if (cached_has_bits & 0x00000100u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(17, this->_internal_proto3_optional(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldDescriptorProto)
+  return target;
+}
+
+size_t FieldDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string extendee = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_extendee());
+    }
+
+    // optional string type_name = 6;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_type_name());
+    }
+
+    // optional string default_value = 7;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_default_value());
+    }
+
+    // optional string json_name = 10;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_json_name());
+    }
+
+    // optional .google.protobuf.FieldOptions options = 8;
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional int32 number = 3;
+    if (cached_has_bits & 0x00000040u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+    }
+
+    // optional int32 oneof_index = 9;
+    if (cached_has_bits & 0x00000080u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
+    }
+
+  }
+  if (cached_has_bits & 0x00000700u) {
+    // optional bool proto3_optional = 17;
+    if (cached_has_bits & 0x00000100u) {
+      total_size += 2 + 1;
+    }
+
+    // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+    if (cached_has_bits & 0x00000200u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_label());
+    }
+
+    // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+    if (cached_has_bits & 0x00000400u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_type());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FieldDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void FieldDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FieldDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const FieldDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_extendee(from._internal_extendee());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_type_name(from._internal_type_name());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_set_default_value(from._internal_default_value());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_internal_set_json_name(from._internal_json_name());
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::FieldOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _this->_impl_.number_ = from._impl_.number_;
+    }
+    if (cached_has_bits & 0x00000080u) {
+      _this->_impl_.oneof_index_ = from._impl_.oneof_index_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  if (cached_has_bits & 0x00000700u) {
+    if (cached_has_bits & 0x00000100u) {
+      _this->_impl_.proto3_optional_ = from._impl_.proto3_optional_;
+    }
+    if (cached_has_bits & 0x00000200u) {
+      _this->_impl_.label_ = from._impl_.label_;
+    }
+    if (cached_has_bits & 0x00000400u) {
+      _this->_impl_.type_ = from._impl_.type_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.extendee_, lhs_arena,
+      &other->_impl_.extendee_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.type_name_, lhs_arena,
+      &other->_impl_.type_name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.default_value_, lhs_arena,
+      &other->_impl_.default_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.json_name_, lhs_arena,
+      &other->_impl_.json_name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FieldDescriptorProto, _impl_.proto3_optional_)
+      + sizeof(FieldDescriptorProto::_impl_.proto3_optional_)
+      - PROTOBUF_FIELD_OFFSET(FieldDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+  swap(_impl_.label_, other->_impl_.label_);
+  swap(_impl_.type_, other->_impl_.type_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FieldDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[6]);
+}
+
+// ===================================================================
+
+class OneofDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<OneofDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::OneofOptions& options(const OneofDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::OneofOptions&
+OneofDescriptorProto::_Internal::options(const OneofDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+OneofDescriptorProto::OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofDescriptorProto)
+}
+OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  OneofDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::OneofOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofDescriptorProto)
+}
+
+inline void OneofDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+OneofDescriptorProto::~OneofDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.OneofDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void OneofDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void OneofDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void OneofDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.OneofDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.OneofOptions options = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* OneofDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.OneofDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional .google.protobuf.OneofOptions options = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(2, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofDescriptorProto)
+  return target;
+}
+
+size_t OneofDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.OneofOptions options = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData OneofDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    OneofDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void OneofDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<OneofDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const OneofDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::OneofOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool OneofDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata OneofDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[7]);
+}
+
+// ===================================================================
+
+class EnumDescriptorProto_EnumReservedRange::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumDescriptorProto_EnumReservedRange>()._impl_._has_bits_);
+  static void set_has_start(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+}
+EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(const EnumDescriptorProto_EnumReservedRange& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumDescriptorProto_EnumReservedRange* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.start_, &from._impl_.start_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+}
+
+inline void EnumDescriptorProto_EnumReservedRange::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){0}
+    , decltype(_impl_.end_){0}
+  };
+}
+
+EnumDescriptorProto_EnumReservedRange::~EnumDescriptorProto_EnumReservedRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumDescriptorProto_EnumReservedRange::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void EnumDescriptorProto_EnumReservedRange::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumDescriptorProto_EnumReservedRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    ::memset(&_impl_.start_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 start = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_start(&has_bits);
+          _impl_.start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumDescriptorProto_EnumReservedRange::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 start = 1;
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  return target;
+}
+
+size_t EnumDescriptorProto_EnumReservedRange::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional int32 start = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+    }
+
+    // optional int32 end = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumDescriptorProto_EnumReservedRange::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumDescriptorProto_EnumReservedRange::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto_EnumReservedRange::GetClassData() const { return &_class_data_; }
+
+
+void EnumDescriptorProto_EnumReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumDescriptorProto_EnumReservedRange*>(&to_msg);
+  auto& from = static_cast<const EnumDescriptorProto_EnumReservedRange&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.start_ = from._impl_.start_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumDescriptorProto_EnumReservedRange::CopyFrom(const EnumDescriptorProto_EnumReservedRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumDescriptorProto_EnumReservedRange::IsInitialized() const {
+  return true;
+}
+
+void EnumDescriptorProto_EnumReservedRange::InternalSwap(EnumDescriptorProto_EnumReservedRange* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(EnumDescriptorProto_EnumReservedRange, _impl_.end_)
+      + sizeof(EnumDescriptorProto_EnumReservedRange::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(EnumDescriptorProto_EnumReservedRange, _impl_.start_)>(
+          reinterpret_cast<char*>(&_impl_.start_),
+          reinterpret_cast<char*>(&other->_impl_.start_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto_EnumReservedRange::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[8]);
+}
+
+// ===================================================================
+
+class EnumDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::EnumOptions& options(const EnumDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::EnumOptions&
+EnumDescriptorProto::_Internal::options(const EnumDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+EnumDescriptorProto::EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto)
+}
+EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.value_){from._impl_.value_}
+    , decltype(_impl_.reserved_range_){from._impl_.reserved_range_}
+    , decltype(_impl_.reserved_name_){from._impl_.reserved_name_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::EnumOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto)
+}
+
+inline void EnumDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.value_){arena}
+    , decltype(_impl_.reserved_range_){arena}
+    , decltype(_impl_.reserved_name_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+EnumDescriptorProto::~EnumDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.value_.~RepeatedPtrField();
+  _impl_.reserved_range_.~RepeatedPtrField();
+  _impl_.reserved_name_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void EnumDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_.Clear();
+  _impl_.reserved_range_.Clear();
+  _impl_.reserved_name_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_value(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.EnumOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_reserved_range(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string reserved_name = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_reserved_name();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.reserved_name");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.EnumDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_value_size()); i < n; i++) {
+    const auto& repfield = this->_internal_value(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.EnumOptions options = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_reserved_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_reserved_range(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated string reserved_name = 5;
+  for (int i = 0, n = this->_internal_reserved_name_size(); i < n; i++) {
+    const auto& s = this->_internal_reserved_name(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.EnumDescriptorProto.reserved_name");
+    target = stream->WriteString(5, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto)
+  return target;
+}
+
+size_t EnumDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+  total_size += 1UL * this->_internal_value_size();
+  for (const auto& msg : this->_impl_.value_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+  total_size += 1UL * this->_internal_reserved_range_size();
+  for (const auto& msg : this->_impl_.reserved_range_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated string reserved_name = 5;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.reserved_name_.size());
+  for (int i = 0, n = _impl_.reserved_name_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.reserved_name_.Get(i));
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.EnumOptions options = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void EnumDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const EnumDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.value_.MergeFrom(from._impl_.value_);
+  _this->_impl_.reserved_range_.MergeFrom(from._impl_.reserved_range_);
+  _this->_impl_.reserved_name_.MergeFrom(from._impl_.reserved_name_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::EnumOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumDescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.value_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.value_.InternalSwap(&other->_impl_.value_);
+  _impl_.reserved_range_.InternalSwap(&other->_impl_.reserved_range_);
+  _impl_.reserved_name_.InternalSwap(&other->_impl_.reserved_name_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[9]);
+}
+
+// ===================================================================
+
+class EnumValueDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumValueDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_number(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& options(const EnumValueDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions&
+EnumValueDescriptorProto::_Internal::options(const EnumValueDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+EnumValueDescriptorProto::EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueDescriptorProto)
+}
+EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumValueDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::EnumValueOptions(*from._impl_.options_);
+  }
+  _this->_impl_.number_ = from._impl_.number_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueDescriptorProto)
+}
+
+inline void EnumValueDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){0}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+EnumValueDescriptorProto::~EnumValueDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValueDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumValueDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void EnumValueDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumValueDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_.number_ = 0;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.EnumValueDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 number = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_number(&has_bits);
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.EnumValueOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumValueDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.EnumValueDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional int32 number = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
+  }
+
+  // optional .google.protobuf.EnumValueOptions options = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueDescriptorProto)
+  return target;
+}
+
+size_t EnumValueDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.EnumValueOptions options = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional int32 number = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValueDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumValueDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void EnumValueDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumValueDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const EnumValueDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::EnumValueOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.number_ = from._impl_.number_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValueDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(EnumValueDescriptorProto, _impl_.number_)
+      + sizeof(EnumValueDescriptorProto::_impl_.number_)
+      - PROTOBUF_FIELD_OFFSET(EnumValueDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumValueDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[10]);
+}
+
+// ===================================================================
+
+class ServiceDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<ServiceDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& options(const ServiceDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::ServiceOptions&
+ServiceDescriptorProto::_Internal::options(const ServiceDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+ServiceDescriptorProto::ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceDescriptorProto)
+}
+ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ServiceDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.method_){from._impl_.method_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::ServiceOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceDescriptorProto)
+}
+
+inline void ServiceDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.method_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+ServiceDescriptorProto::~ServiceDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ServiceDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ServiceDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.method_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void ServiceDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ServiceDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.method_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.ServiceDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.MethodDescriptorProto method = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_method(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.ServiceOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ServiceDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.ServiceDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.MethodDescriptorProto method = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_method_size()); i < n; i++) {
+    const auto& repfield = this->_internal_method(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.ServiceOptions options = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceDescriptorProto)
+  return target;
+}
+
+size_t ServiceDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.MethodDescriptorProto method = 2;
+  total_size += 1UL * this->_internal_method_size();
+  for (const auto& msg : this->_impl_.method_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.ServiceOptions options = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ServiceDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ServiceDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void ServiceDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ServiceDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const ServiceDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.method_.MergeFrom(from._impl_.method_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::ServiceOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ServiceDescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.method_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.method_.InternalSwap(&other->_impl_.method_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ServiceDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[11]);
+}
+
+// ===================================================================
+
+class MethodDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<MethodDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_input_type(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_output_type(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::MethodOptions& options(const MethodDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_client_streaming(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_server_streaming(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::MethodOptions&
+MethodDescriptorProto::_Internal::options(const MethodDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+MethodDescriptorProto::MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodDescriptorProto)
+}
+MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MethodDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.input_type_){}
+    , decltype(_impl_.output_type_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.client_streaming_){}
+    , decltype(_impl_.server_streaming_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.input_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_input_type()) {
+    _this->_impl_.input_type_.Set(from._internal_input_type(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.output_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_output_type()) {
+    _this->_impl_.output_type_.Set(from._internal_output_type(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::MethodOptions(*from._impl_.options_);
+  }
+  ::memcpy(&_impl_.client_streaming_, &from._impl_.client_streaming_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.server_streaming_) -
+    reinterpret_cast<char*>(&_impl_.client_streaming_)) + sizeof(_impl_.server_streaming_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodDescriptorProto)
+}
+
+inline void MethodDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.input_type_){}
+    , decltype(_impl_.output_type_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.client_streaming_){false}
+    , decltype(_impl_.server_streaming_){false}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.input_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.output_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+MethodDescriptorProto::~MethodDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.MethodDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MethodDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.input_type_.Destroy();
+  _impl_.output_type_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void MethodDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MethodDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.input_type_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.output_type_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  ::memset(&_impl_.client_streaming_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.server_streaming_) -
+      reinterpret_cast<char*>(&_impl_.client_streaming_)) + sizeof(_impl_.server_streaming_));
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string input_type = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_input_type();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.input_type");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string output_type = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_output_type();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.output_type");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.MethodOptions options = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool client_streaming = 5 [default = false];
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _Internal::set_has_client_streaming(&has_bits);
+          _impl_.client_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool server_streaming = 6 [default = false];
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 48)) {
+          _Internal::set_has_server_streaming(&has_bits);
+          _impl_.server_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* MethodDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.MethodDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string input_type = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_input_type().data(), static_cast<int>(this->_internal_input_type().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.MethodDescriptorProto.input_type");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_input_type(), target);
+  }
+
+  // optional string output_type = 3;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_output_type().data(), static_cast<int>(this->_internal_output_type().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.MethodDescriptorProto.output_type");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_output_type(), target);
+  }
+
+  // optional .google.protobuf.MethodOptions options = 4;
+  if (cached_has_bits & 0x00000008u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(4, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // optional bool client_streaming = 5 [default = false];
+  if (cached_has_bits & 0x00000010u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_client_streaming(), target);
+  }
+
+  // optional bool server_streaming = 6 [default = false];
+  if (cached_has_bits & 0x00000020u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(6, this->_internal_server_streaming(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodDescriptorProto)
+  return target;
+}
+
+size_t MethodDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string input_type = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_input_type());
+    }
+
+    // optional string output_type = 3;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_output_type());
+    }
+
+    // optional .google.protobuf.MethodOptions options = 4;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional bool client_streaming = 5 [default = false];
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool server_streaming = 6 [default = false];
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MethodDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MethodDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void MethodDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MethodDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const MethodDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_input_type(from._internal_input_type());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_output_type(from._internal_output_type());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::MethodOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_impl_.client_streaming_ = from._impl_.client_streaming_;
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_impl_.server_streaming_ = from._impl_.server_streaming_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MethodDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.input_type_, lhs_arena,
+      &other->_impl_.input_type_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.output_type_, lhs_arena,
+      &other->_impl_.output_type_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(MethodDescriptorProto, _impl_.server_streaming_)
+      + sizeof(MethodDescriptorProto::_impl_.server_streaming_)
+      - PROTOBUF_FIELD_OFFSET(MethodDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MethodDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[12]);
+}
+
+// ===================================================================
+
+class FileOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FileOptions>()._impl_._has_bits_);
+  static void set_has_java_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_java_outer_classname(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_java_multiple_files(HasBits* has_bits) {
+    (*has_bits)[0] |= 1024u;
+  }
+  static void set_has_java_generate_equals_and_hash(HasBits* has_bits) {
+    (*has_bits)[0] |= 2048u;
+  }
+  static void set_has_java_string_check_utf8(HasBits* has_bits) {
+    (*has_bits)[0] |= 4096u;
+  }
+  static void set_has_optimize_for(HasBits* has_bits) {
+    (*has_bits)[0] |= 262144u;
+  }
+  static void set_has_go_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_cc_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 8192u;
+  }
+  static void set_has_java_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 16384u;
+  }
+  static void set_has_py_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 32768u;
+  }
+  static void set_has_php_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 65536u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 131072u;
+  }
+  static void set_has_cc_enable_arenas(HasBits* has_bits) {
+    (*has_bits)[0] |= 524288u;
+  }
+  static void set_has_objc_class_prefix(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_csharp_namespace(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_swift_prefix(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_php_class_prefix(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
+  static void set_has_php_namespace(HasBits* has_bits) {
+    (*has_bits)[0] |= 128u;
+  }
+  static void set_has_php_metadata_namespace(HasBits* has_bits) {
+    (*has_bits)[0] |= 256u;
+  }
+  static void set_has_ruby_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 512u;
+  }
+};
+
+FileOptions::FileOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FileOptions)
+}
+FileOptions::FileOptions(const FileOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FileOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.java_package_){}
+    , decltype(_impl_.java_outer_classname_){}
+    , decltype(_impl_.go_package_){}
+    , decltype(_impl_.objc_class_prefix_){}
+    , decltype(_impl_.csharp_namespace_){}
+    , decltype(_impl_.swift_prefix_){}
+    , decltype(_impl_.php_class_prefix_){}
+    , decltype(_impl_.php_namespace_){}
+    , decltype(_impl_.php_metadata_namespace_){}
+    , decltype(_impl_.ruby_package_){}
+    , decltype(_impl_.java_multiple_files_){}
+    , decltype(_impl_.java_generate_equals_and_hash_){}
+    , decltype(_impl_.java_string_check_utf8_){}
+    , decltype(_impl_.cc_generic_services_){}
+    , decltype(_impl_.java_generic_services_){}
+    , decltype(_impl_.py_generic_services_){}
+    , decltype(_impl_.php_generic_services_){}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.optimize_for_){}
+    , decltype(_impl_.cc_enable_arenas_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _impl_.java_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_java_package()) {
+    _this->_impl_.java_package_.Set(from._internal_java_package(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.java_outer_classname_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_java_outer_classname()) {
+    _this->_impl_.java_outer_classname_.Set(from._internal_java_outer_classname(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.go_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_go_package()) {
+    _this->_impl_.go_package_.Set(from._internal_go_package(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.objc_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_objc_class_prefix()) {
+    _this->_impl_.objc_class_prefix_.Set(from._internal_objc_class_prefix(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.csharp_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_csharp_namespace()) {
+    _this->_impl_.csharp_namespace_.Set(from._internal_csharp_namespace(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.swift_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_swift_prefix()) {
+    _this->_impl_.swift_prefix_.Set(from._internal_swift_prefix(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.php_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_php_class_prefix()) {
+    _this->_impl_.php_class_prefix_.Set(from._internal_php_class_prefix(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.php_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_php_namespace()) {
+    _this->_impl_.php_namespace_.Set(from._internal_php_namespace(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.php_metadata_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_php_metadata_namespace()) {
+    _this->_impl_.php_metadata_namespace_.Set(from._internal_php_metadata_namespace(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.ruby_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_ruby_package()) {
+    _this->_impl_.ruby_package_.Set(from._internal_ruby_package(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.java_multiple_files_, &from._impl_.java_multiple_files_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.cc_enable_arenas_) -
+    reinterpret_cast<char*>(&_impl_.java_multiple_files_)) + sizeof(_impl_.cc_enable_arenas_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FileOptions)
+}
+
+inline void FileOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.java_package_){}
+    , decltype(_impl_.java_outer_classname_){}
+    , decltype(_impl_.go_package_){}
+    , decltype(_impl_.objc_class_prefix_){}
+    , decltype(_impl_.csharp_namespace_){}
+    , decltype(_impl_.swift_prefix_){}
+    , decltype(_impl_.php_class_prefix_){}
+    , decltype(_impl_.php_namespace_){}
+    , decltype(_impl_.php_metadata_namespace_){}
+    , decltype(_impl_.ruby_package_){}
+    , decltype(_impl_.java_multiple_files_){false}
+    , decltype(_impl_.java_generate_equals_and_hash_){false}
+    , decltype(_impl_.java_string_check_utf8_){false}
+    , decltype(_impl_.cc_generic_services_){false}
+    , decltype(_impl_.java_generic_services_){false}
+    , decltype(_impl_.py_generic_services_){false}
+    , decltype(_impl_.php_generic_services_){false}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.optimize_for_){1}
+    , decltype(_impl_.cc_enable_arenas_){true}
+  };
+  _impl_.java_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.java_outer_classname_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.go_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.objc_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.csharp_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.swift_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.php_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.php_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.php_metadata_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.ruby_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+FileOptions::~FileOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FileOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FileOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+  _impl_.java_package_.Destroy();
+  _impl_.java_outer_classname_.Destroy();
+  _impl_.go_package_.Destroy();
+  _impl_.objc_class_prefix_.Destroy();
+  _impl_.csharp_namespace_.Destroy();
+  _impl_.swift_prefix_.Destroy();
+  _impl_.php_class_prefix_.Destroy();
+  _impl_.php_namespace_.Destroy();
+  _impl_.php_metadata_namespace_.Destroy();
+  _impl_.ruby_package_.Destroy();
+}
+
+void FileOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FileOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.java_package_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.java_outer_classname_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.go_package_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _impl_.objc_class_prefix_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _impl_.csharp_namespace_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _impl_.swift_prefix_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _impl_.php_class_prefix_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000080u) {
+      _impl_.php_namespace_.ClearNonDefaultToEmpty();
+    }
+  }
+  if (cached_has_bits & 0x00000300u) {
+    if (cached_has_bits & 0x00000100u) {
+      _impl_.php_metadata_namespace_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000200u) {
+      _impl_.ruby_package_.ClearNonDefaultToEmpty();
+    }
+  }
+  if (cached_has_bits & 0x0000fc00u) {
+    ::memset(&_impl_.java_multiple_files_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.py_generic_services_) -
+        reinterpret_cast<char*>(&_impl_.java_multiple_files_)) + sizeof(_impl_.py_generic_services_));
+  }
+  if (cached_has_bits & 0x000f0000u) {
+    ::memset(&_impl_.php_generic_services_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.deprecated_) -
+        reinterpret_cast<char*>(&_impl_.php_generic_services_)) + sizeof(_impl_.deprecated_));
+    _impl_.optimize_for_ = 1;
+    _impl_.cc_enable_arenas_ = true;
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FileOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string java_package = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_java_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.java_package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string java_outer_classname = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          auto str = _internal_mutable_java_outer_classname();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.java_outer_classname");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 72)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_IsValid(val))) {
+            _internal_set_optimize_for(static_cast<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(9, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_multiple_files = 10 [default = false];
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          _Internal::set_has_java_multiple_files(&has_bits);
+          _impl_.java_multiple_files_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string go_package = 11;
+      case 11:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 90)) {
+          auto str = _internal_mutable_go_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.go_package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool cc_generic_services = 16 [default = false];
+      case 16:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 128)) {
+          _Internal::set_has_cc_generic_services(&has_bits);
+          _impl_.cc_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_generic_services = 17 [default = false];
+      case 17:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 136)) {
+          _Internal::set_has_java_generic_services(&has_bits);
+          _impl_.java_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool py_generic_services = 18 [default = false];
+      case 18:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 144)) {
+          _Internal::set_has_py_generic_services(&has_bits);
+          _impl_.py_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+      case 20:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 160)) {
+          _Internal::set_has_java_generate_equals_and_hash(&has_bits);
+          _impl_.java_generate_equals_and_hash_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 23 [default = false];
+      case 23:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 184)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_string_check_utf8 = 27 [default = false];
+      case 27:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 216)) {
+          _Internal::set_has_java_string_check_utf8(&has_bits);
+          _impl_.java_string_check_utf8_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool cc_enable_arenas = 31 [default = true];
+      case 31:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 248)) {
+          _Internal::set_has_cc_enable_arenas(&has_bits);
+          _impl_.cc_enable_arenas_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string objc_class_prefix = 36;
+      case 36:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_objc_class_prefix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.objc_class_prefix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string csharp_namespace = 37;
+      case 37:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          auto str = _internal_mutable_csharp_namespace();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.csharp_namespace");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string swift_prefix = 39;
+      case 39:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          auto str = _internal_mutable_swift_prefix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.swift_prefix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string php_class_prefix = 40;
+      case 40:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          auto str = _internal_mutable_php_class_prefix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_class_prefix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string php_namespace = 41;
+      case 41:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          auto str = _internal_mutable_php_namespace();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_namespace");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool php_generic_services = 42 [default = false];
+      case 42:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          _Internal::set_has_php_generic_services(&has_bits);
+          _impl_.php_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string php_metadata_namespace = 44;
+      case 44:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 98)) {
+          auto str = _internal_mutable_php_metadata_namespace();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_metadata_namespace");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string ruby_package = 45;
+      case 45:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 106)) {
+          auto str = _internal_mutable_ruby_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.ruby_package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FileOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string java_package = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_java_package().data(), static_cast<int>(this->_internal_java_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.java_package");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_java_package(), target);
+  }
+
+  // optional string java_outer_classname = 8;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_java_outer_classname().data(), static_cast<int>(this->_internal_java_outer_classname().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.java_outer_classname");
+    target = stream->WriteStringMaybeAliased(
+        8, this->_internal_java_outer_classname(), target);
+  }
+
+  // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+  if (cached_has_bits & 0x00040000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      9, this->_internal_optimize_for(), target);
+  }
+
+  // optional bool java_multiple_files = 10 [default = false];
+  if (cached_has_bits & 0x00000400u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(10, this->_internal_java_multiple_files(), target);
+  }
+
+  // optional string go_package = 11;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_go_package().data(), static_cast<int>(this->_internal_go_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.go_package");
+    target = stream->WriteStringMaybeAliased(
+        11, this->_internal_go_package(), target);
+  }
+
+  // optional bool cc_generic_services = 16 [default = false];
+  if (cached_has_bits & 0x00002000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(16, this->_internal_cc_generic_services(), target);
+  }
+
+  // optional bool java_generic_services = 17 [default = false];
+  if (cached_has_bits & 0x00004000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(17, this->_internal_java_generic_services(), target);
+  }
+
+  // optional bool py_generic_services = 18 [default = false];
+  if (cached_has_bits & 0x00008000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(18, this->_internal_py_generic_services(), target);
+  }
+
+  // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+  if (cached_has_bits & 0x00000800u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(20, this->_internal_java_generate_equals_and_hash(), target);
+  }
+
+  // optional bool deprecated = 23 [default = false];
+  if (cached_has_bits & 0x00020000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(23, this->_internal_deprecated(), target);
+  }
+
+  // optional bool java_string_check_utf8 = 27 [default = false];
+  if (cached_has_bits & 0x00001000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(27, this->_internal_java_string_check_utf8(), target);
+  }
+
+  // optional bool cc_enable_arenas = 31 [default = true];
+  if (cached_has_bits & 0x00080000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(31, this->_internal_cc_enable_arenas(), target);
+  }
+
+  // optional string objc_class_prefix = 36;
+  if (cached_has_bits & 0x00000008u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_objc_class_prefix().data(), static_cast<int>(this->_internal_objc_class_prefix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.objc_class_prefix");
+    target = stream->WriteStringMaybeAliased(
+        36, this->_internal_objc_class_prefix(), target);
+  }
+
+  // optional string csharp_namespace = 37;
+  if (cached_has_bits & 0x00000010u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_csharp_namespace().data(), static_cast<int>(this->_internal_csharp_namespace().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.csharp_namespace");
+    target = stream->WriteStringMaybeAliased(
+        37, this->_internal_csharp_namespace(), target);
+  }
+
+  // optional string swift_prefix = 39;
+  if (cached_has_bits & 0x00000020u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_swift_prefix().data(), static_cast<int>(this->_internal_swift_prefix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.swift_prefix");
+    target = stream->WriteStringMaybeAliased(
+        39, this->_internal_swift_prefix(), target);
+  }
+
+  // optional string php_class_prefix = 40;
+  if (cached_has_bits & 0x00000040u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_php_class_prefix().data(), static_cast<int>(this->_internal_php_class_prefix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.php_class_prefix");
+    target = stream->WriteStringMaybeAliased(
+        40, this->_internal_php_class_prefix(), target);
+  }
+
+  // optional string php_namespace = 41;
+  if (cached_has_bits & 0x00000080u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_php_namespace().data(), static_cast<int>(this->_internal_php_namespace().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.php_namespace");
+    target = stream->WriteStringMaybeAliased(
+        41, this->_internal_php_namespace(), target);
+  }
+
+  // optional bool php_generic_services = 42 [default = false];
+  if (cached_has_bits & 0x00010000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(42, this->_internal_php_generic_services(), target);
+  }
+
+  // optional string php_metadata_namespace = 44;
+  if (cached_has_bits & 0x00000100u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_php_metadata_namespace().data(), static_cast<int>(this->_internal_php_metadata_namespace().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.php_metadata_namespace");
+    target = stream->WriteStringMaybeAliased(
+        44, this->_internal_php_metadata_namespace(), target);
+  }
+
+  // optional string ruby_package = 45;
+  if (cached_has_bits & 0x00000200u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_ruby_package().data(), static_cast<int>(this->_internal_ruby_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.ruby_package");
+    target = stream->WriteStringMaybeAliased(
+        45, this->_internal_ruby_package(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileOptions)
+  return target;
+}
+
+size_t FileOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    // optional string java_package = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_java_package());
+    }
+
+    // optional string java_outer_classname = 8;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_java_outer_classname());
+    }
+
+    // optional string go_package = 11;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_go_package());
+    }
+
+    // optional string objc_class_prefix = 36;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_objc_class_prefix());
+    }
+
+    // optional string csharp_namespace = 37;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_csharp_namespace());
+    }
+
+    // optional string swift_prefix = 39;
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_swift_prefix());
+    }
+
+    // optional string php_class_prefix = 40;
+    if (cached_has_bits & 0x00000040u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_php_class_prefix());
+    }
+
+    // optional string php_namespace = 41;
+    if (cached_has_bits & 0x00000080u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_php_namespace());
+    }
+
+  }
+  if (cached_has_bits & 0x0000ff00u) {
+    // optional string php_metadata_namespace = 44;
+    if (cached_has_bits & 0x00000100u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_php_metadata_namespace());
+    }
+
+    // optional string ruby_package = 45;
+    if (cached_has_bits & 0x00000200u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_ruby_package());
+    }
+
+    // optional bool java_multiple_files = 10 [default = false];
+    if (cached_has_bits & 0x00000400u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+    if (cached_has_bits & 0x00000800u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool java_string_check_utf8 = 27 [default = false];
+    if (cached_has_bits & 0x00001000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool cc_generic_services = 16 [default = false];
+    if (cached_has_bits & 0x00002000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool java_generic_services = 17 [default = false];
+    if (cached_has_bits & 0x00004000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool py_generic_services = 18 [default = false];
+    if (cached_has_bits & 0x00008000u) {
+      total_size += 2 + 1;
+    }
+
+  }
+  if (cached_has_bits & 0x000f0000u) {
+    // optional bool php_generic_services = 42 [default = false];
+    if (cached_has_bits & 0x00010000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool deprecated = 23 [default = false];
+    if (cached_has_bits & 0x00020000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+    if (cached_has_bits & 0x00040000u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_optimize_for());
+    }
+
+    // optional bool cc_enable_arenas = 31 [default = true];
+    if (cached_has_bits & 0x00080000u) {
+      total_size += 2 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FileOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileOptions::GetClassData() const { return &_class_data_; }
+
+
+void FileOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FileOptions*>(&to_msg);
+  auto& from = static_cast<const FileOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_java_package(from._internal_java_package());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_java_outer_classname(from._internal_java_outer_classname());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_go_package(from._internal_go_package());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_set_objc_class_prefix(from._internal_objc_class_prefix());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_internal_set_csharp_namespace(from._internal_csharp_namespace());
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_internal_set_swift_prefix(from._internal_swift_prefix());
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _this->_internal_set_php_class_prefix(from._internal_php_class_prefix());
+    }
+    if (cached_has_bits & 0x00000080u) {
+      _this->_internal_set_php_namespace(from._internal_php_namespace());
+    }
+  }
+  if (cached_has_bits & 0x0000ff00u) {
+    if (cached_has_bits & 0x00000100u) {
+      _this->_internal_set_php_metadata_namespace(from._internal_php_metadata_namespace());
+    }
+    if (cached_has_bits & 0x00000200u) {
+      _this->_internal_set_ruby_package(from._internal_ruby_package());
+    }
+    if (cached_has_bits & 0x00000400u) {
+      _this->_impl_.java_multiple_files_ = from._impl_.java_multiple_files_;
+    }
+    if (cached_has_bits & 0x00000800u) {
+      _this->_impl_.java_generate_equals_and_hash_ = from._impl_.java_generate_equals_and_hash_;
+    }
+    if (cached_has_bits & 0x00001000u) {
+      _this->_impl_.java_string_check_utf8_ = from._impl_.java_string_check_utf8_;
+    }
+    if (cached_has_bits & 0x00002000u) {
+      _this->_impl_.cc_generic_services_ = from._impl_.cc_generic_services_;
+    }
+    if (cached_has_bits & 0x00004000u) {
+      _this->_impl_.java_generic_services_ = from._impl_.java_generic_services_;
+    }
+    if (cached_has_bits & 0x00008000u) {
+      _this->_impl_.py_generic_services_ = from._impl_.py_generic_services_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  if (cached_has_bits & 0x000f0000u) {
+    if (cached_has_bits & 0x00010000u) {
+      _this->_impl_.php_generic_services_ = from._impl_.php_generic_services_;
+    }
+    if (cached_has_bits & 0x00020000u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00040000u) {
+      _this->_impl_.optimize_for_ = from._impl_.optimize_for_;
+    }
+    if (cached_has_bits & 0x00080000u) {
+      _this->_impl_.cc_enable_arenas_ = from._impl_.cc_enable_arenas_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FileOptions::CopyFrom(const FileOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FileOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void FileOptions::InternalSwap(FileOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.java_package_, lhs_arena,
+      &other->_impl_.java_package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.java_outer_classname_, lhs_arena,
+      &other->_impl_.java_outer_classname_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.go_package_, lhs_arena,
+      &other->_impl_.go_package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.objc_class_prefix_, lhs_arena,
+      &other->_impl_.objc_class_prefix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.csharp_namespace_, lhs_arena,
+      &other->_impl_.csharp_namespace_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.swift_prefix_, lhs_arena,
+      &other->_impl_.swift_prefix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.php_class_prefix_, lhs_arena,
+      &other->_impl_.php_class_prefix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.php_namespace_, lhs_arena,
+      &other->_impl_.php_namespace_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.php_metadata_namespace_, lhs_arena,
+      &other->_impl_.php_metadata_namespace_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.ruby_package_, lhs_arena,
+      &other->_impl_.ruby_package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FileOptions, _impl_.deprecated_)
+      + sizeof(FileOptions::_impl_.deprecated_)
+      - PROTOBUF_FIELD_OFFSET(FileOptions, _impl_.java_multiple_files_)>(
+          reinterpret_cast<char*>(&_impl_.java_multiple_files_),
+          reinterpret_cast<char*>(&other->_impl_.java_multiple_files_));
+  swap(_impl_.optimize_for_, other->_impl_.optimize_for_);
+  swap(_impl_.cc_enable_arenas_, other->_impl_.cc_enable_arenas_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FileOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[13]);
+}
+
+// ===================================================================
+
+class MessageOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<MessageOptions>()._impl_._has_bits_);
+  static void set_has_message_set_wire_format(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_no_standard_descriptor_accessor(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_map_entry(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+};
+
+MessageOptions::MessageOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.MessageOptions)
+}
+MessageOptions::MessageOptions(const MessageOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MessageOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.message_set_wire_format_){}
+    , decltype(_impl_.no_standard_descriptor_accessor_){}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.map_entry_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.message_set_wire_format_, &from._impl_.message_set_wire_format_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.map_entry_) -
+    reinterpret_cast<char*>(&_impl_.message_set_wire_format_)) + sizeof(_impl_.map_entry_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.MessageOptions)
+}
+
+inline void MessageOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.message_set_wire_format_){false}
+    , decltype(_impl_.no_standard_descriptor_accessor_){false}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.map_entry_){false}
+  };
+}
+
+MessageOptions::~MessageOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.MessageOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MessageOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void MessageOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MessageOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MessageOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  ::memset(&_impl_.message_set_wire_format_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.map_entry_) -
+      reinterpret_cast<char*>(&_impl_.message_set_wire_format_)) + sizeof(_impl_.map_entry_));
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MessageOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool message_set_wire_format = 1 [default = false];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_message_set_wire_format(&has_bits);
+          _impl_.message_set_wire_format_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool no_standard_descriptor_accessor = 2 [default = false];
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_no_standard_descriptor_accessor(&has_bits);
+          _impl_.no_standard_descriptor_accessor_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 3 [default = false];
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool map_entry = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          _Internal::set_has_map_entry(&has_bits);
+          _impl_.map_entry_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* MessageOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool message_set_wire_format = 1 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_message_set_wire_format(), target);
+  }
+
+  // optional bool no_standard_descriptor_accessor = 2 [default = false];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_no_standard_descriptor_accessor(), target);
+  }
+
+  // optional bool deprecated = 3 [default = false];
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+  }
+
+  // optional bool map_entry = 7;
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(7, this->_internal_map_entry(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MessageOptions)
+  return target;
+}
+
+size_t MessageOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    // optional bool message_set_wire_format = 1 [default = false];
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool no_standard_descriptor_accessor = 2 [default = false];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool deprecated = 3 [default = false];
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool map_entry = 7;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MessageOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MessageOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MessageOptions::GetClassData() const { return &_class_data_; }
+
+
+void MessageOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MessageOptions*>(&to_msg);
+  auto& from = static_cast<const MessageOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.message_set_wire_format_ = from._impl_.message_set_wire_format_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.no_standard_descriptor_accessor_ = from._impl_.no_standard_descriptor_accessor_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.map_entry_ = from._impl_.map_entry_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MessageOptions::CopyFrom(const MessageOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MessageOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MessageOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void MessageOptions::InternalSwap(MessageOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(MessageOptions, _impl_.map_entry_)
+      + sizeof(MessageOptions::_impl_.map_entry_)
+      - PROTOBUF_FIELD_OFFSET(MessageOptions, _impl_.message_set_wire_format_)>(
+          reinterpret_cast<char*>(&_impl_.message_set_wire_format_),
+          reinterpret_cast<char*>(&other->_impl_.message_set_wire_format_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MessageOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[14]);
+}
+
+// ===================================================================
+
+class FieldOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FieldOptions>()._impl_._has_bits_);
+  static void set_has_ctype(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_packed(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_jstype(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_lazy(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_unverified_lazy(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_weak(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
+};
+
+FieldOptions::FieldOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldOptions)
+}
+FieldOptions::FieldOptions(const FieldOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FieldOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.ctype_){}
+    , decltype(_impl_.jstype_){}
+    , decltype(_impl_.packed_){}
+    , decltype(_impl_.lazy_){}
+    , decltype(_impl_.unverified_lazy_){}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.weak_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.ctype_, &from._impl_.ctype_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.weak_) -
+    reinterpret_cast<char*>(&_impl_.ctype_)) + sizeof(_impl_.weak_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldOptions)
+}
+
+inline void FieldOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.ctype_){0}
+    , decltype(_impl_.jstype_){0}
+    , decltype(_impl_.packed_){false}
+    , decltype(_impl_.lazy_){false}
+    , decltype(_impl_.unverified_lazy_){false}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.weak_){false}
+  };
+}
+
+FieldOptions::~FieldOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FieldOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void FieldOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FieldOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000007fu) {
+    ::memset(&_impl_.ctype_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.weak_) -
+        reinterpret_cast<char*>(&_impl_.ctype_)) + sizeof(_impl_.weak_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FieldOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_IsValid(val))) {
+            _internal_set_ctype(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(1, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool packed = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_packed(&has_bits);
+          _impl_.packed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 3 [default = false];
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool lazy = 5 [default = false];
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _Internal::set_has_lazy(&has_bits);
+          _impl_.lazy_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 48)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_IsValid(val))) {
+            _internal_set_jstype(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(6, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool weak = 10 [default = false];
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          _Internal::set_has_weak(&has_bits);
+          _impl_.weak_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool unverified_lazy = 15 [default = false];
+      case 15:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 120)) {
+          _Internal::set_has_unverified_lazy(&has_bits);
+          _impl_.unverified_lazy_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FieldOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      1, this->_internal_ctype(), target);
+  }
+
+  // optional bool packed = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_packed(), target);
+  }
+
+  // optional bool deprecated = 3 [default = false];
+  if (cached_has_bits & 0x00000020u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+  }
+
+  // optional bool lazy = 5 [default = false];
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_lazy(), target);
+  }
+
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      6, this->_internal_jstype(), target);
+  }
+
+  // optional bool weak = 10 [default = false];
+  if (cached_has_bits & 0x00000040u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(10, this->_internal_weak(), target);
+  }
+
+  // optional bool unverified_lazy = 15 [default = false];
+  if (cached_has_bits & 0x00000010u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(15, this->_internal_unverified_lazy(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldOptions)
+  return target;
+}
+
+size_t FieldOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000007fu) {
+    // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_ctype());
+    }
+
+    // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_jstype());
+    }
+
+    // optional bool packed = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool lazy = 5 [default = false];
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool unverified_lazy = 15 [default = false];
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool deprecated = 3 [default = false];
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool weak = 10 [default = false];
+    if (cached_has_bits & 0x00000040u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FieldOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldOptions::GetClassData() const { return &_class_data_; }
+
+
+void FieldOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FieldOptions*>(&to_msg);
+  auto& from = static_cast<const FieldOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000007fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.ctype_ = from._impl_.ctype_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.jstype_ = from._impl_.jstype_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.packed_ = from._impl_.packed_;
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.lazy_ = from._impl_.lazy_;
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_impl_.unverified_lazy_ = from._impl_.unverified_lazy_;
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _this->_impl_.weak_ = from._impl_.weak_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FieldOptions::CopyFrom(const FieldOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void FieldOptions::InternalSwap(FieldOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FieldOptions, _impl_.weak_)
+      + sizeof(FieldOptions::_impl_.weak_)
+      - PROTOBUF_FIELD_OFFSET(FieldOptions, _impl_.ctype_)>(
+          reinterpret_cast<char*>(&_impl_.ctype_),
+          reinterpret_cast<char*>(&other->_impl_.ctype_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FieldOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[15]);
+}
+
+// ===================================================================
+
+class OneofOptions::_Internal {
+ public:
+};
+
+OneofOptions::OneofOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofOptions)
+}
+OneofOptions::OneofOptions(const OneofOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  OneofOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofOptions)
+}
+
+inline void OneofOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+OneofOptions::~OneofOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.OneofOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void OneofOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void OneofOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void OneofOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* OneofOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* OneofOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofOptions)
+  return target;
+}
+
+size_t OneofOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData OneofOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    OneofOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofOptions::GetClassData() const { return &_class_data_; }
+
+
+void OneofOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<OneofOptions*>(&to_msg);
+  auto& from = static_cast<const OneofOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void OneofOptions::CopyFrom(const OneofOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool OneofOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void OneofOptions::InternalSwap(OneofOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata OneofOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[16]);
+}
+
+// ===================================================================
+
+class EnumOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumOptions>()._impl_._has_bits_);
+  static void set_has_allow_alias(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+EnumOptions::EnumOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumOptions)
+}
+EnumOptions::EnumOptions(const EnumOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.allow_alias_){}
+    , decltype(_impl_.deprecated_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.allow_alias_, &from._impl_.allow_alias_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.deprecated_) -
+    reinterpret_cast<char*>(&_impl_.allow_alias_)) + sizeof(_impl_.deprecated_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumOptions)
+}
+
+inline void EnumOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.allow_alias_){false}
+    , decltype(_impl_.deprecated_){false}
+  };
+}
+
+EnumOptions::~EnumOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void EnumOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  ::memset(&_impl_.allow_alias_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.deprecated_) -
+      reinterpret_cast<char*>(&_impl_.allow_alias_)) + sizeof(_impl_.deprecated_));
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool allow_alias = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_allow_alias(&has_bits);
+          _impl_.allow_alias_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 3 [default = false];
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool allow_alias = 2;
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_allow_alias(), target);
+  }
+
+  // optional bool deprecated = 3 [default = false];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumOptions)
+  return target;
+}
+
+size_t EnumOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional bool allow_alias = 2;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool deprecated = 3 [default = false];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumOptions::GetClassData() const { return &_class_data_; }
+
+
+void EnumOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumOptions*>(&to_msg);
+  auto& from = static_cast<const EnumOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.allow_alias_ = from._impl_.allow_alias_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumOptions::CopyFrom(const EnumOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void EnumOptions::InternalSwap(EnumOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(EnumOptions, _impl_.deprecated_)
+      + sizeof(EnumOptions::_impl_.deprecated_)
+      - PROTOBUF_FIELD_OFFSET(EnumOptions, _impl_.allow_alias_)>(
+          reinterpret_cast<char*>(&_impl_.allow_alias_),
+          reinterpret_cast<char*>(&other->_impl_.allow_alias_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[17]);
+}
+
+// ===================================================================
+
+class EnumValueOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumValueOptions>()._impl_._has_bits_);
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+EnumValueOptions::EnumValueOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueOptions)
+}
+EnumValueOptions::EnumValueOptions(const EnumValueOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumValueOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.deprecated_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_impl_.deprecated_ = from._impl_.deprecated_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueOptions)
+}
+
+inline void EnumValueOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.deprecated_){false}
+  };
+}
+
+EnumValueOptions::~EnumValueOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValueOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumValueOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void EnumValueOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumValueOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumValueOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool deprecated = 1 [default = false];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumValueOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool deprecated = 1 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_deprecated(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueOptions)
+  return target;
+}
+
+size_t EnumValueOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // optional bool deprecated = 1 [default = false];
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    total_size += 1 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValueOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumValueOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueOptions::GetClassData() const { return &_class_data_; }
+
+
+void EnumValueOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumValueOptions*>(&to_msg);
+  auto& from = static_cast<const EnumValueOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  if (from._internal_has_deprecated()) {
+    _this->_internal_set_deprecated(from._internal_deprecated());
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumValueOptions::CopyFrom(const EnumValueOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValueOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void EnumValueOptions::InternalSwap(EnumValueOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  swap(_impl_.deprecated_, other->_impl_.deprecated_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumValueOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[18]);
+}
+
+// ===================================================================
+
+class ServiceOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<ServiceOptions>()._impl_._has_bits_);
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+ServiceOptions::ServiceOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceOptions)
+}
+ServiceOptions::ServiceOptions(const ServiceOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ServiceOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.deprecated_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_impl_.deprecated_ = from._impl_.deprecated_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceOptions)
+}
+
+inline void ServiceOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.deprecated_){false}
+  };
+}
+
+ServiceOptions::~ServiceOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ServiceOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ServiceOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void ServiceOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ServiceOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ServiceOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool deprecated = 33 [default = false];
+      case 33:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ServiceOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool deprecated = 33 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceOptions)
+  return target;
+}
+
+size_t ServiceOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // optional bool deprecated = 33 [default = false];
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    total_size += 2 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ServiceOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ServiceOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceOptions::GetClassData() const { return &_class_data_; }
+
+
+void ServiceOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ServiceOptions*>(&to_msg);
+  auto& from = static_cast<const ServiceOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  if (from._internal_has_deprecated()) {
+    _this->_internal_set_deprecated(from._internal_deprecated());
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ServiceOptions::CopyFrom(const ServiceOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ServiceOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void ServiceOptions::InternalSwap(ServiceOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  swap(_impl_.deprecated_, other->_impl_.deprecated_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ServiceOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[19]);
+}
+
+// ===================================================================
+
+class MethodOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<MethodOptions>()._impl_._has_bits_);
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_idempotency_level(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+MethodOptions::MethodOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodOptions)
+}
+MethodOptions::MethodOptions(const MethodOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MethodOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.idempotency_level_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.deprecated_, &from._impl_.deprecated_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.idempotency_level_) -
+    reinterpret_cast<char*>(&_impl_.deprecated_)) + sizeof(_impl_.idempotency_level_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodOptions)
+}
+
+inline void MethodOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.idempotency_level_){0}
+  };
+}
+
+MethodOptions::~MethodOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.MethodOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MethodOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void MethodOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MethodOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    ::memset(&_impl_.deprecated_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.idempotency_level_) -
+        reinterpret_cast<char*>(&_impl_.deprecated_)) + sizeof(_impl_.idempotency_level_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MethodOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool deprecated = 33 [default = false];
+      case 33:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+      case 34:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_IsValid(val))) {
+            _internal_set_idempotency_level(static_cast<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(34, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* MethodOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool deprecated = 33 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
+  }
+
+  // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      34, this->_internal_idempotency_level(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodOptions)
+  return target;
+}
+
+size_t MethodOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional bool deprecated = 33 [default = false];
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 2 + 1;
+    }
+
+    // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 2 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_idempotency_level());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MethodOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MethodOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodOptions::GetClassData() const { return &_class_data_; }
+
+
+void MethodOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MethodOptions*>(&to_msg);
+  auto& from = static_cast<const MethodOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.idempotency_level_ = from._impl_.idempotency_level_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MethodOptions::CopyFrom(const MethodOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MethodOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void MethodOptions::InternalSwap(MethodOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(MethodOptions, _impl_.idempotency_level_)
+      + sizeof(MethodOptions::_impl_.idempotency_level_)
+      - PROTOBUF_FIELD_OFFSET(MethodOptions, _impl_.deprecated_)>(
+          reinterpret_cast<char*>(&_impl_.deprecated_),
+          reinterpret_cast<char*>(&other->_impl_.deprecated_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MethodOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[20]);
+}
+
+// ===================================================================
+
+class UninterpretedOption_NamePart::_Internal {
+ public:
+  using HasBits = decltype(std::declval<UninterpretedOption_NamePart>()._impl_._has_bits_);
+  static void set_has_name_part(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_is_extension(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static bool MissingRequiredFields(const HasBits& has_bits) {
+    return ((has_bits[0] & 0x00000003) ^ 0x00000003) != 0;
+  }
+};
+
+UninterpretedOption_NamePart::UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption.NamePart)
+}
+UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UninterpretedOption_NamePart* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_part_){}
+    , decltype(_impl_.is_extension_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_part_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name_part()) {
+    _this->_impl_.name_part_.Set(from._internal_name_part(), 
+      _this->GetArenaForAllocation());
+  }
+  _this->_impl_.is_extension_ = from._impl_.is_extension_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption.NamePart)
+}
+
+inline void UninterpretedOption_NamePart::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_part_){}
+    , decltype(_impl_.is_extension_){false}
+  };
+  _impl_.name_part_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+UninterpretedOption_NamePart::~UninterpretedOption_NamePart() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption.NamePart)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UninterpretedOption_NamePart::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_part_.Destroy();
+}
+
+void UninterpretedOption_NamePart::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UninterpretedOption_NamePart::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption.NamePart)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    _impl_.name_part_.ClearNonDefaultToEmpty();
+  }
+  _impl_.is_extension_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // required string name_part = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name_part();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.NamePart.name_part");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // required bool is_extension = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_is_extension(&has_bits);
+          _impl_.is_extension_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UninterpretedOption_NamePart::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // required string name_part = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name_part().data(), static_cast<int>(this->_internal_name_part().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.UninterpretedOption.NamePart.name_part");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name_part(), target);
+  }
+
+  // required bool is_extension = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_is_extension(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption.NamePart)
+  return target;
+}
+
+size_t UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const {
+// @@protoc_insertion_point(required_fields_byte_size_fallback_start:google.protobuf.UninterpretedOption.NamePart)
+  size_t total_size = 0;
+
+  if (_internal_has_name_part()) {
+    // required string name_part = 1;
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name_part());
+  }
+
+  if (_internal_has_is_extension()) {
+    // required bool is_extension = 2;
+    total_size += 1 + 1;
+  }
+
+  return total_size;
+}
+size_t UninterpretedOption_NamePart::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart)
+  size_t total_size = 0;
+
+  if (((_impl_._has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) {  // All required fields are present.
+    // required string name_part = 1;
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name_part());
+
+    // required bool is_extension = 2;
+    total_size += 1 + 1;
+
+  } else {
+    total_size += RequiredFieldsByteSizeFallback();
+  }
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UninterpretedOption_NamePart::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UninterpretedOption_NamePart::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption_NamePart::GetClassData() const { return &_class_data_; }
+
+
+void UninterpretedOption_NamePart::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UninterpretedOption_NamePart*>(&to_msg);
+  auto& from = static_cast<const UninterpretedOption_NamePart&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name_part(from._internal_name_part());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.is_extension_ = from._impl_.is_extension_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption.NamePart)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UninterpretedOption_NamePart::IsInitialized() const {
+  if (_Internal::MissingRequiredFields(_impl_._has_bits_)) return false;
+  return true;
+}
+
+void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_part_, lhs_arena,
+      &other->_impl_.name_part_, rhs_arena
+  );
+  swap(_impl_.is_extension_, other->_impl_.is_extension_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption_NamePart::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[21]);
+}
+
+// ===================================================================
+
+class UninterpretedOption::_Internal {
+ public:
+  using HasBits = decltype(std::declval<UninterpretedOption>()._impl_._has_bits_);
+  static void set_has_identifier_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_positive_int_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_negative_int_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_double_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_string_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_aggregate_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+};
+
+UninterpretedOption::UninterpretedOption(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption)
+}
+UninterpretedOption::UninterpretedOption(const UninterpretedOption& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UninterpretedOption* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){from._impl_.name_}
+    , decltype(_impl_.identifier_value_){}
+    , decltype(_impl_.string_value_){}
+    , decltype(_impl_.aggregate_value_){}
+    , decltype(_impl_.positive_int_value_){}
+    , decltype(_impl_.negative_int_value_){}
+    , decltype(_impl_.double_value_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.identifier_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_identifier_value()) {
+    _this->_impl_.identifier_value_.Set(from._internal_identifier_value(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.string_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_string_value()) {
+    _this->_impl_.string_value_.Set(from._internal_string_value(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.aggregate_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_aggregate_value()) {
+    _this->_impl_.aggregate_value_.Set(from._internal_aggregate_value(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.positive_int_value_, &from._impl_.positive_int_value_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.double_value_) -
+    reinterpret_cast<char*>(&_impl_.positive_int_value_)) + sizeof(_impl_.double_value_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption)
+}
+
+inline void UninterpretedOption::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){arena}
+    , decltype(_impl_.identifier_value_){}
+    , decltype(_impl_.string_value_){}
+    , decltype(_impl_.aggregate_value_){}
+    , decltype(_impl_.positive_int_value_){uint64_t{0u}}
+    , decltype(_impl_.negative_int_value_){int64_t{0}}
+    , decltype(_impl_.double_value_){0}
+  };
+  _impl_.identifier_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.string_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.aggregate_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+UninterpretedOption::~UninterpretedOption() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UninterpretedOption::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.~RepeatedPtrField();
+  _impl_.identifier_value_.Destroy();
+  _impl_.string_value_.Destroy();
+  _impl_.aggregate_value_.Destroy();
+}
+
+void UninterpretedOption::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UninterpretedOption::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.name_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.identifier_value_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.string_value_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.aggregate_value_.ClearNonDefaultToEmpty();
+    }
+  }
+  if (cached_has_bits & 0x00000038u) {
+    ::memset(&_impl_.positive_int_value_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.double_value_) -
+        reinterpret_cast<char*>(&_impl_.positive_int_value_)) + sizeof(_impl_.double_value_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UninterpretedOption::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_name(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string identifier_value = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_identifier_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.identifier_value");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional uint64 positive_int_value = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          _Internal::set_has_positive_int_value(&has_bits);
+          _impl_.positive_int_value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int64 negative_int_value = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _Internal::set_has_negative_int_value(&has_bits);
+          _impl_.negative_int_value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional double double_value = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 49)) {
+          _Internal::set_has_double_value(&has_bits);
+          _impl_.double_value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr);
+          ptr += sizeof(double);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bytes string_value = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          auto str = _internal_mutable_string_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string aggregate_value = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          auto str = _internal_mutable_aggregate_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.aggregate_value");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UninterpretedOption::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_name_size()); i < n; i++) {
+    const auto& repfield = this->_internal_name(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string identifier_value = 3;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_identifier_value().data(), static_cast<int>(this->_internal_identifier_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.UninterpretedOption.identifier_value");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_identifier_value(), target);
+  }
+
+  // optional uint64 positive_int_value = 4;
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(4, this->_internal_positive_int_value(), target);
+  }
+
+  // optional int64 negative_int_value = 5;
+  if (cached_has_bits & 0x00000010u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(5, this->_internal_negative_int_value(), target);
+  }
+
+  // optional double double_value = 6;
+  if (cached_has_bits & 0x00000020u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(6, this->_internal_double_value(), target);
+  }
+
+  // optional bytes string_value = 7;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->WriteBytesMaybeAliased(
+        7, this->_internal_string_value(), target);
+  }
+
+  // optional string aggregate_value = 8;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_aggregate_value().data(), static_cast<int>(this->_internal_aggregate_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.UninterpretedOption.aggregate_value");
+    target = stream->WriteStringMaybeAliased(
+        8, this->_internal_aggregate_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption)
+  return target;
+}
+
+size_t UninterpretedOption::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+  total_size += 1UL * this->_internal_name_size();
+  for (const auto& msg : this->_impl_.name_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    // optional string identifier_value = 3;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_identifier_value());
+    }
+
+    // optional bytes string_value = 7;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
+          this->_internal_string_value());
+    }
+
+    // optional string aggregate_value = 8;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_aggregate_value());
+    }
+
+    // optional uint64 positive_int_value = 4;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_positive_int_value());
+    }
+
+    // optional int64 negative_int_value = 5;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_negative_int_value());
+    }
+
+    // optional double double_value = 6;
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 + 8;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UninterpretedOption::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UninterpretedOption::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption::GetClassData() const { return &_class_data_; }
+
+
+void UninterpretedOption::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UninterpretedOption*>(&to_msg);
+  auto& from = static_cast<const UninterpretedOption&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.name_.MergeFrom(from._impl_.name_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_identifier_value(from._internal_identifier_value());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_string_value(from._internal_string_value());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_aggregate_value(from._internal_aggregate_value());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.positive_int_value_ = from._impl_.positive_int_value_;
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_impl_.negative_int_value_ = from._impl_.negative_int_value_;
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_impl_.double_value_ = from._impl_.double_value_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UninterpretedOption::CopyFrom(const UninterpretedOption& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UninterpretedOption::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.name_))
+    return false;
+  return true;
+}
+
+void UninterpretedOption::InternalSwap(UninterpretedOption* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.name_.InternalSwap(&other->_impl_.name_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.identifier_value_, lhs_arena,
+      &other->_impl_.identifier_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.string_value_, lhs_arena,
+      &other->_impl_.string_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.aggregate_value_, lhs_arena,
+      &other->_impl_.aggregate_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(UninterpretedOption, _impl_.double_value_)
+      + sizeof(UninterpretedOption::_impl_.double_value_)
+      - PROTOBUF_FIELD_OFFSET(UninterpretedOption, _impl_.positive_int_value_)>(
+          reinterpret_cast<char*>(&_impl_.positive_int_value_),
+          reinterpret_cast<char*>(&other->_impl_.positive_int_value_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[22]);
+}
+
+// ===================================================================
+
+class SourceCodeInfo_Location::_Internal {
+ public:
+  using HasBits = decltype(std::declval<SourceCodeInfo_Location>()._impl_._has_bits_);
+  static void set_has_leading_comments(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_trailing_comments(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+SourceCodeInfo_Location::SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo.Location)
+}
+SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  SourceCodeInfo_Location* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){from._impl_.path_}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.span_){from._impl_.span_}
+    , /*decltype(_impl_._span_cached_byte_size_)*/{0}
+    , decltype(_impl_.leading_detached_comments_){from._impl_.leading_detached_comments_}
+    , decltype(_impl_.leading_comments_){}
+    , decltype(_impl_.trailing_comments_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.leading_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_leading_comments()) {
+    _this->_impl_.leading_comments_.Set(from._internal_leading_comments(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.trailing_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_trailing_comments()) {
+    _this->_impl_.trailing_comments_.Set(from._internal_trailing_comments(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo.Location)
+}
+
+inline void SourceCodeInfo_Location::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){arena}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.span_){arena}
+    , /*decltype(_impl_._span_cached_byte_size_)*/{0}
+    , decltype(_impl_.leading_detached_comments_){arena}
+    , decltype(_impl_.leading_comments_){}
+    , decltype(_impl_.trailing_comments_){}
+  };
+  _impl_.leading_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.trailing_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+SourceCodeInfo_Location::~SourceCodeInfo_Location() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo.Location)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void SourceCodeInfo_Location::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.path_.~RepeatedField();
+  _impl_.span_.~RepeatedField();
+  _impl_.leading_detached_comments_.~RepeatedPtrField();
+  _impl_.leading_comments_.Destroy();
+  _impl_.trailing_comments_.Destroy();
+}
+
+void SourceCodeInfo_Location::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void SourceCodeInfo_Location::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo.Location)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.path_.Clear();
+  _impl_.span_.Clear();
+  _impl_.leading_detached_comments_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.leading_comments_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.trailing_comments_.ClearNonDefaultToEmpty();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated int32 path = 1 [packed = true];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_path(), ptr, ctx);
+          CHK_(ptr);
+        } else if (static_cast<uint8_t>(tag) == 8) {
+          _internal_add_path(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated int32 span = 2 [packed = true];
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_span(), ptr, ctx);
+          CHK_(ptr);
+        } else if (static_cast<uint8_t>(tag) == 16) {
+          _internal_add_span(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string leading_comments = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_leading_comments();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_comments");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string trailing_comments = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_trailing_comments();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string leading_detached_comments = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_leading_detached_comments();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* SourceCodeInfo_Location::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    int byte_size = _impl_._path_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          1, _internal_path(), byte_size, target);
+    }
+  }
+
+  // repeated int32 span = 2 [packed = true];
+  {
+    int byte_size = _impl_._span_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          2, _internal_span(), byte_size, target);
+    }
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string leading_comments = 3;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_leading_comments().data(), static_cast<int>(this->_internal_leading_comments().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.leading_comments");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_leading_comments(), target);
+  }
+
+  // optional string trailing_comments = 4;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_trailing_comments().data(), static_cast<int>(this->_internal_trailing_comments().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_trailing_comments(), target);
+  }
+
+  // repeated string leading_detached_comments = 6;
+  for (int i = 0, n = this->_internal_leading_detached_comments_size(); i < n; i++) {
+    const auto& s = this->_internal_leading_detached_comments(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+    target = stream->WriteString(6, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo.Location)
+  return target;
+}
+
+size_t SourceCodeInfo_Location::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.path_);
+    if (data_size > 0) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
+    }
+    int cached_size = ::_pbi::ToCachedSize(data_size);
+    _impl_._path_cached_byte_size_.store(cached_size,
+                                    std::memory_order_relaxed);
+    total_size += data_size;
+  }
+
+  // repeated int32 span = 2 [packed = true];
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.span_);
+    if (data_size > 0) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
+    }
+    int cached_size = ::_pbi::ToCachedSize(data_size);
+    _impl_._span_cached_byte_size_.store(cached_size,
+                                    std::memory_order_relaxed);
+    total_size += data_size;
+  }
+
+  // repeated string leading_detached_comments = 6;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.leading_detached_comments_.size());
+  for (int i = 0, n = _impl_.leading_detached_comments_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.leading_detached_comments_.Get(i));
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string leading_comments = 3;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_leading_comments());
+    }
+
+    // optional string trailing_comments = 4;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_trailing_comments());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceCodeInfo_Location::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    SourceCodeInfo_Location::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo_Location::GetClassData() const { return &_class_data_; }
+
+
+void SourceCodeInfo_Location::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<SourceCodeInfo_Location*>(&to_msg);
+  auto& from = static_cast<const SourceCodeInfo_Location&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.path_.MergeFrom(from._impl_.path_);
+  _this->_impl_.span_.MergeFrom(from._impl_.span_);
+  _this->_impl_.leading_detached_comments_.MergeFrom(from._impl_.leading_detached_comments_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_leading_comments(from._internal_leading_comments());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_trailing_comments(from._internal_trailing_comments());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo.Location)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceCodeInfo_Location::IsInitialized() const {
+  return true;
+}
+
+void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.path_.InternalSwap(&other->_impl_.path_);
+  _impl_.span_.InternalSwap(&other->_impl_.span_);
+  _impl_.leading_detached_comments_.InternalSwap(&other->_impl_.leading_detached_comments_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.leading_comments_, lhs_arena,
+      &other->_impl_.leading_comments_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.trailing_comments_, lhs_arena,
+      &other->_impl_.trailing_comments_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo_Location::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[23]);
+}
+
+// ===================================================================
+
+class SourceCodeInfo::_Internal {
+ public:
+};
+
+SourceCodeInfo::SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo)
+}
+SourceCodeInfo::SourceCodeInfo(const SourceCodeInfo& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  SourceCodeInfo* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.location_){from._impl_.location_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo)
+}
+
+inline void SourceCodeInfo::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.location_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+SourceCodeInfo::~SourceCodeInfo() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void SourceCodeInfo::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.location_.~RepeatedPtrField();
+}
+
+void SourceCodeInfo::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void SourceCodeInfo::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.location_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* SourceCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_location(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* SourceCodeInfo::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_location_size()); i < n; i++) {
+    const auto& repfield = this->_internal_location(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo)
+  return target;
+}
+
+size_t SourceCodeInfo::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+  total_size += 1UL * this->_internal_location_size();
+  for (const auto& msg : this->_impl_.location_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceCodeInfo::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    SourceCodeInfo::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo::GetClassData() const { return &_class_data_; }
+
+
+void SourceCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<SourceCodeInfo*>(&to_msg);
+  auto& from = static_cast<const SourceCodeInfo&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.location_.MergeFrom(from._impl_.location_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceCodeInfo::IsInitialized() const {
+  return true;
+}
+
+void SourceCodeInfo::InternalSwap(SourceCodeInfo* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.location_.InternalSwap(&other->_impl_.location_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[24]);
+}
+
+// ===================================================================
+
+class GeneratedCodeInfo_Annotation::_Internal {
+ public:
+  using HasBits = decltype(std::declval<GeneratedCodeInfo_Annotation>()._impl_._has_bits_);
+  static void set_has_source_file(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_begin(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+};
+
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  GeneratedCodeInfo_Annotation* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){from._impl_.path_}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.source_file_){}
+    , decltype(_impl_.begin_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.source_file_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_source_file()) {
+    _this->_impl_.source_file_.Set(from._internal_source_file(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.begin_, &from._impl_.begin_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+inline void GeneratedCodeInfo_Annotation::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){arena}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.source_file_){}
+    , decltype(_impl_.begin_){0}
+    , decltype(_impl_.end_){0}
+  };
+  _impl_.source_file_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+GeneratedCodeInfo_Annotation::~GeneratedCodeInfo_Annotation() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void GeneratedCodeInfo_Annotation::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.path_.~RepeatedField();
+  _impl_.source_file_.Destroy();
+}
+
+void GeneratedCodeInfo_Annotation::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void GeneratedCodeInfo_Annotation::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.path_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    _impl_.source_file_.ClearNonDefaultToEmpty();
+  }
+  if (cached_has_bits & 0x00000006u) {
+    ::memset(&_impl_.begin_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated int32 path = 1 [packed = true];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_path(), ptr, ctx);
+          CHK_(ptr);
+        } else if (static_cast<uint8_t>(tag) == 8) {
+          _internal_add_path(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string source_file = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_source_file();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 begin = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_begin(&has_bits);
+          _impl_.begin_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* GeneratedCodeInfo_Annotation::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    int byte_size = _impl_._path_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          1, _internal_path(), byte_size, target);
+    }
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string source_file = 2;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_source_file().data(), static_cast<int>(this->_internal_source_file().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_source_file(), target);
+  }
+
+  // optional int32 begin = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_begin(), target);
+  }
+
+  // optional int32 end = 4;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(4, this->_internal_end(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation)
+  return target;
+}
+
+size_t GeneratedCodeInfo_Annotation::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.path_);
+    if (data_size > 0) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
+    }
+    int cached_size = ::_pbi::ToCachedSize(data_size);
+    _impl_._path_cached_byte_size_.store(cached_size,
+                                    std::memory_order_relaxed);
+    total_size += data_size;
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    // optional string source_file = 2;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_source_file());
+    }
+
+    // optional int32 begin = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_begin());
+    }
+
+    // optional int32 end = 4;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData GeneratedCodeInfo_Annotation::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    GeneratedCodeInfo_Annotation::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo_Annotation::GetClassData() const { return &_class_data_; }
+
+
+void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<GeneratedCodeInfo_Annotation*>(&to_msg);
+  auto& from = static_cast<const GeneratedCodeInfo_Annotation&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.path_.MergeFrom(from._impl_.path_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_source_file(from._internal_source_file());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.begin_ = from._impl_.begin_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo_Annotation::IsInitialized() const {
+  return true;
+}
+
+void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.path_.InternalSwap(&other->_impl_.path_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.source_file_, lhs_arena,
+      &other->_impl_.source_file_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.end_)
+      + sizeof(GeneratedCodeInfo_Annotation::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.begin_)>(
+          reinterpret_cast<char*>(&_impl_.begin_),
+          reinterpret_cast<char*>(&other->_impl_.begin_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[25]);
+}
+
+// ===================================================================
+
+class GeneratedCodeInfo::_Internal {
+ public:
+};
+
+GeneratedCodeInfo::GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.GeneratedCodeInfo)
+}
+GeneratedCodeInfo::GeneratedCodeInfo(const GeneratedCodeInfo& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  GeneratedCodeInfo* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.annotation_){from._impl_.annotation_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo)
+}
+
+inline void GeneratedCodeInfo::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.annotation_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+GeneratedCodeInfo::~GeneratedCodeInfo() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void GeneratedCodeInfo::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.annotation_.~RepeatedPtrField();
+}
+
+void GeneratedCodeInfo::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void GeneratedCodeInfo::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.annotation_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_annotation(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* GeneratedCodeInfo::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_annotation_size()); i < n; i++) {
+    const auto& repfield = this->_internal_annotation(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo)
+  return target;
+}
+
+size_t GeneratedCodeInfo::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  total_size += 1UL * this->_internal_annotation_size();
+  for (const auto& msg : this->_impl_.annotation_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData GeneratedCodeInfo::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    GeneratedCodeInfo::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo::GetClassData() const { return &_class_data_; }
+
+
+void GeneratedCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<GeneratedCodeInfo*>(&to_msg);
+  auto& from = static_cast<const GeneratedCodeInfo&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.annotation_.MergeFrom(from._impl_.annotation_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo::IsInitialized() const {
+  return true;
+}
+
+void GeneratedCodeInfo::InternalSwap(GeneratedCodeInfo* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.annotation_.InternalSwap(&other->_impl_.annotation_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[26]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MessageOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
new file mode 100644
index 0000000..27282da
--- /dev/null
+++ b/src/google/protobuf/descriptor.pb.h
@@ -0,0 +1,14821 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fdescriptor_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fdescriptor_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class DescriptorProto;
+struct DescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern DescriptorProtoDefaultTypeInternal _DescriptorProto_default_instance_;
+class DescriptorProto_ExtensionRange;
+struct DescriptorProto_ExtensionRangeDefaultTypeInternal;
+PROTOBUF_EXPORT extern DescriptorProto_ExtensionRangeDefaultTypeInternal _DescriptorProto_ExtensionRange_default_instance_;
+class DescriptorProto_ReservedRange;
+struct DescriptorProto_ReservedRangeDefaultTypeInternal;
+PROTOBUF_EXPORT extern DescriptorProto_ReservedRangeDefaultTypeInternal _DescriptorProto_ReservedRange_default_instance_;
+class EnumDescriptorProto;
+struct EnumDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumDescriptorProtoDefaultTypeInternal _EnumDescriptorProto_default_instance_;
+class EnumDescriptorProto_EnumReservedRange;
+struct EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal _EnumDescriptorProto_EnumReservedRange_default_instance_;
+class EnumOptions;
+struct EnumOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumOptionsDefaultTypeInternal _EnumOptions_default_instance_;
+class EnumValueDescriptorProto;
+struct EnumValueDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumValueDescriptorProtoDefaultTypeInternal _EnumValueDescriptorProto_default_instance_;
+class EnumValueOptions;
+struct EnumValueOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumValueOptionsDefaultTypeInternal _EnumValueOptions_default_instance_;
+class ExtensionRangeOptions;
+struct ExtensionRangeOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern ExtensionRangeOptionsDefaultTypeInternal _ExtensionRangeOptions_default_instance_;
+class FieldDescriptorProto;
+struct FieldDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldDescriptorProtoDefaultTypeInternal _FieldDescriptorProto_default_instance_;
+class FieldOptions;
+struct FieldOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldOptionsDefaultTypeInternal _FieldOptions_default_instance_;
+class FileDescriptorProto;
+struct FileDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern FileDescriptorProtoDefaultTypeInternal _FileDescriptorProto_default_instance_;
+class FileDescriptorSet;
+struct FileDescriptorSetDefaultTypeInternal;
+PROTOBUF_EXPORT extern FileDescriptorSetDefaultTypeInternal _FileDescriptorSet_default_instance_;
+class FileOptions;
+struct FileOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern FileOptionsDefaultTypeInternal _FileOptions_default_instance_;
+class GeneratedCodeInfo;
+struct GeneratedCodeInfoDefaultTypeInternal;
+PROTOBUF_EXPORT extern GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
+class GeneratedCodeInfo_Annotation;
+struct GeneratedCodeInfo_AnnotationDefaultTypeInternal;
+PROTOBUF_EXPORT extern GeneratedCodeInfo_AnnotationDefaultTypeInternal _GeneratedCodeInfo_Annotation_default_instance_;
+class MessageOptions;
+struct MessageOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern MessageOptionsDefaultTypeInternal _MessageOptions_default_instance_;
+class MethodDescriptorProto;
+struct MethodDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern MethodDescriptorProtoDefaultTypeInternal _MethodDescriptorProto_default_instance_;
+class MethodOptions;
+struct MethodOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern MethodOptionsDefaultTypeInternal _MethodOptions_default_instance_;
+class OneofDescriptorProto;
+struct OneofDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern OneofDescriptorProtoDefaultTypeInternal _OneofDescriptorProto_default_instance_;
+class OneofOptions;
+struct OneofOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern OneofOptionsDefaultTypeInternal _OneofOptions_default_instance_;
+class ServiceDescriptorProto;
+struct ServiceDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern ServiceDescriptorProtoDefaultTypeInternal _ServiceDescriptorProto_default_instance_;
+class ServiceOptions;
+struct ServiceOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern ServiceOptionsDefaultTypeInternal _ServiceOptions_default_instance_;
+class SourceCodeInfo;
+struct SourceCodeInfoDefaultTypeInternal;
+PROTOBUF_EXPORT extern SourceCodeInfoDefaultTypeInternal _SourceCodeInfo_default_instance_;
+class SourceCodeInfo_Location;
+struct SourceCodeInfo_LocationDefaultTypeInternal;
+PROTOBUF_EXPORT extern SourceCodeInfo_LocationDefaultTypeInternal _SourceCodeInfo_Location_default_instance_;
+class UninterpretedOption;
+struct UninterpretedOptionDefaultTypeInternal;
+PROTOBUF_EXPORT extern UninterpretedOptionDefaultTypeInternal _UninterpretedOption_default_instance_;
+class UninterpretedOption_NamePart;
+struct UninterpretedOption_NamePartDefaultTypeInternal;
+PROTOBUF_EXPORT extern UninterpretedOption_NamePartDefaultTypeInternal _UninterpretedOption_NamePart_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValueOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileDescriptorSet>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FileOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::MessageOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MessageOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::MethodOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MethodOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::OneofOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::OneofOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ServiceOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ServiceOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceCodeInfo>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UninterpretedOption>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+enum FieldDescriptorProto_Type : int {
+  FieldDescriptorProto_Type_TYPE_DOUBLE = 1,
+  FieldDescriptorProto_Type_TYPE_FLOAT = 2,
+  FieldDescriptorProto_Type_TYPE_INT64 = 3,
+  FieldDescriptorProto_Type_TYPE_UINT64 = 4,
+  FieldDescriptorProto_Type_TYPE_INT32 = 5,
+  FieldDescriptorProto_Type_TYPE_FIXED64 = 6,
+  FieldDescriptorProto_Type_TYPE_FIXED32 = 7,
+  FieldDescriptorProto_Type_TYPE_BOOL = 8,
+  FieldDescriptorProto_Type_TYPE_STRING = 9,
+  FieldDescriptorProto_Type_TYPE_GROUP = 10,
+  FieldDescriptorProto_Type_TYPE_MESSAGE = 11,
+  FieldDescriptorProto_Type_TYPE_BYTES = 12,
+  FieldDescriptorProto_Type_TYPE_UINT32 = 13,
+  FieldDescriptorProto_Type_TYPE_ENUM = 14,
+  FieldDescriptorProto_Type_TYPE_SFIXED32 = 15,
+  FieldDescriptorProto_Type_TYPE_SFIXED64 = 16,
+  FieldDescriptorProto_Type_TYPE_SINT32 = 17,
+  FieldDescriptorProto_Type_TYPE_SINT64 = 18
+};
+PROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
+constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
+constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
+template<typename T>
+inline const std::string& FieldDescriptorProto_Type_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldDescriptorProto_Type>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldDescriptorProto_Type_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldDescriptorProto_Type_descriptor(), enum_t_value);
+}
+inline bool FieldDescriptorProto_Type_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldDescriptorProto_Type* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldDescriptorProto_Type>(
+    FieldDescriptorProto_Type_descriptor(), name, value);
+}
+enum FieldDescriptorProto_Label : int {
+  FieldDescriptorProto_Label_LABEL_OPTIONAL = 1,
+  FieldDescriptorProto_Label_LABEL_REQUIRED = 2,
+  FieldDescriptorProto_Label_LABEL_REPEATED = 3
+};
+PROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
+constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
+constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
+template<typename T>
+inline const std::string& FieldDescriptorProto_Label_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldDescriptorProto_Label>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldDescriptorProto_Label_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldDescriptorProto_Label_descriptor(), enum_t_value);
+}
+inline bool FieldDescriptorProto_Label_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldDescriptorProto_Label* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldDescriptorProto_Label>(
+    FieldDescriptorProto_Label_descriptor(), name, value);
+}
+enum FileOptions_OptimizeMode : int {
+  FileOptions_OptimizeMode_SPEED = 1,
+  FileOptions_OptimizeMode_CODE_SIZE = 2,
+  FileOptions_OptimizeMode_LITE_RUNTIME = 3
+};
+PROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
+constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
+constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
+constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
+template<typename T>
+inline const std::string& FileOptions_OptimizeMode_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FileOptions_OptimizeMode>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FileOptions_OptimizeMode_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FileOptions_OptimizeMode_descriptor(), enum_t_value);
+}
+inline bool FileOptions_OptimizeMode_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FileOptions_OptimizeMode* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FileOptions_OptimizeMode>(
+    FileOptions_OptimizeMode_descriptor(), name, value);
+}
+enum FieldOptions_CType : int {
+  FieldOptions_CType_STRING = 0,
+  FieldOptions_CType_CORD = 1,
+  FieldOptions_CType_STRING_PIECE = 2
+};
+PROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
+constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING;
+constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
+constexpr int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor();
+template<typename T>
+inline const std::string& FieldOptions_CType_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldOptions_CType>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldOptions_CType_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldOptions_CType_descriptor(), enum_t_value);
+}
+inline bool FieldOptions_CType_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldOptions_CType* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldOptions_CType>(
+    FieldOptions_CType_descriptor(), name, value);
+}
+enum FieldOptions_JSType : int {
+  FieldOptions_JSType_JS_NORMAL = 0,
+  FieldOptions_JSType_JS_STRING = 1,
+  FieldOptions_JSType_JS_NUMBER = 2
+};
+PROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value);
+constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
+constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
+constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor();
+template<typename T>
+inline const std::string& FieldOptions_JSType_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldOptions_JSType>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldOptions_JSType_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldOptions_JSType_descriptor(), enum_t_value);
+}
+inline bool FieldOptions_JSType_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldOptions_JSType* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldOptions_JSType>(
+    FieldOptions_JSType_descriptor(), name, value);
+}
+enum MethodOptions_IdempotencyLevel : int {
+  MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN = 0,
+  MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS = 1,
+  MethodOptions_IdempotencyLevel_IDEMPOTENT = 2
+};
+PROTOBUF_EXPORT bool MethodOptions_IdempotencyLevel_IsValid(int value);
+constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IDEMPOTENT;
+constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor();
+template<typename T>
+inline const std::string& MethodOptions_IdempotencyLevel_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, MethodOptions_IdempotencyLevel>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function MethodOptions_IdempotencyLevel_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    MethodOptions_IdempotencyLevel_descriptor(), enum_t_value);
+}
+inline bool MethodOptions_IdempotencyLevel_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, MethodOptions_IdempotencyLevel* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<MethodOptions_IdempotencyLevel>(
+    MethodOptions_IdempotencyLevel_descriptor(), name, value);
+}
+// ===================================================================
+
+class PROTOBUF_EXPORT FileDescriptorSet final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorSet) */ {
+ public:
+  inline FileDescriptorSet() : FileDescriptorSet(nullptr) {}
+  ~FileDescriptorSet() override;
+  explicit PROTOBUF_CONSTEXPR FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FileDescriptorSet(const FileDescriptorSet& from);
+  FileDescriptorSet(FileDescriptorSet&& from) noexcept
+    : FileDescriptorSet() {
+    *this = ::std::move(from);
+  }
+
+  inline FileDescriptorSet& operator=(const FileDescriptorSet& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FileDescriptorSet& operator=(FileDescriptorSet&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FileDescriptorSet& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FileDescriptorSet* internal_default_instance() {
+    return reinterpret_cast<const FileDescriptorSet*>(
+               &_FileDescriptorSet_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(FileDescriptorSet& a, FileDescriptorSet& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FileDescriptorSet* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FileDescriptorSet* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FileDescriptorSet* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FileDescriptorSet>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FileDescriptorSet& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FileDescriptorSet& from) {
+    FileDescriptorSet::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FileDescriptorSet* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FileDescriptorSet";
+  }
+  protected:
+  explicit FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFileFieldNumber = 1,
+  };
+  // repeated .google.protobuf.FileDescriptorProto file = 1;
+  int file_size() const;
+  private:
+  int _internal_file_size() const;
+  public:
+  void clear_file();
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* mutable_file(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
+      mutable_file();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& _internal_file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _internal_add_file();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* add_file();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >&
+      file() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto > file_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FileDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorProto) */ {
+ public:
+  inline FileDescriptorProto() : FileDescriptorProto(nullptr) {}
+  ~FileDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FileDescriptorProto(const FileDescriptorProto& from);
+  FileDescriptorProto(FileDescriptorProto&& from) noexcept
+    : FileDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline FileDescriptorProto& operator=(const FileDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FileDescriptorProto& operator=(FileDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FileDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FileDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const FileDescriptorProto*>(
+               &_FileDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(FileDescriptorProto& a, FileDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FileDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FileDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FileDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FileDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FileDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FileDescriptorProto& from) {
+    FileDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FileDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FileDescriptorProto";
+  }
+  protected:
+  explicit FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kDependencyFieldNumber = 3,
+    kMessageTypeFieldNumber = 4,
+    kEnumTypeFieldNumber = 5,
+    kServiceFieldNumber = 6,
+    kExtensionFieldNumber = 7,
+    kPublicDependencyFieldNumber = 10,
+    kWeakDependencyFieldNumber = 11,
+    kNameFieldNumber = 1,
+    kPackageFieldNumber = 2,
+    kSyntaxFieldNumber = 12,
+    kOptionsFieldNumber = 8,
+    kSourceCodeInfoFieldNumber = 9,
+  };
+  // repeated string dependency = 3;
+  int dependency_size() const;
+  private:
+  int _internal_dependency_size() const;
+  public:
+  void clear_dependency();
+  const std::string& dependency(int index) const;
+  std::string* mutable_dependency(int index);
+  void set_dependency(int index, const std::string& value);
+  void set_dependency(int index, std::string&& value);
+  void set_dependency(int index, const char* value);
+  void set_dependency(int index, const char* value, size_t size);
+  std::string* add_dependency();
+  void add_dependency(const std::string& value);
+  void add_dependency(std::string&& value);
+  void add_dependency(const char* value);
+  void add_dependency(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& dependency() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_dependency();
+  private:
+  const std::string& _internal_dependency(int index) const;
+  std::string* _internal_add_dependency();
+  public:
+
+  // repeated .google.protobuf.DescriptorProto message_type = 4;
+  int message_type_size() const;
+  private:
+  int _internal_message_type_size() const;
+  public:
+  void clear_message_type();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* mutable_message_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+      mutable_message_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& _internal_message_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _internal_add_message_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& message_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* add_message_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+      message_type() const;
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+  int enum_type_size() const;
+  private:
+  int _internal_enum_type_size() const;
+  public:
+  void clear_enum_type();
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* mutable_enum_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+      mutable_enum_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& _internal_enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _internal_add_enum_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* add_enum_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+      enum_type() const;
+
+  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+  int service_size() const;
+  private:
+  int _internal_service_size() const;
+  public:
+  void clear_service();
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* mutable_service(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >*
+      mutable_service();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& _internal_service(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* _internal_add_service();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& service(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* add_service();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >&
+      service() const;
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+  int extension_size() const;
+  private:
+  int _internal_extension_size() const;
+  public:
+  void clear_extension();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* mutable_extension(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+      mutable_extension();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& _internal_extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _internal_add_extension();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* add_extension();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+      extension() const;
+
+  // repeated int32 public_dependency = 10;
+  int public_dependency_size() const;
+  private:
+  int _internal_public_dependency_size() const;
+  public:
+  void clear_public_dependency();
+  private:
+  int32_t _internal_public_dependency(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_public_dependency() const;
+  void _internal_add_public_dependency(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_public_dependency();
+  public:
+  int32_t public_dependency(int index) const;
+  void set_public_dependency(int index, int32_t value);
+  void add_public_dependency(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      public_dependency() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_public_dependency();
+
+  // repeated int32 weak_dependency = 11;
+  int weak_dependency_size() const;
+  private:
+  int _internal_weak_dependency_size() const;
+  public:
+  void clear_weak_dependency();
+  private:
+  int32_t _internal_weak_dependency(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_weak_dependency() const;
+  void _internal_add_weak_dependency(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_weak_dependency();
+  public:
+  int32_t weak_dependency(int index) const;
+  void set_weak_dependency(int index, int32_t value);
+  void add_weak_dependency(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      weak_dependency() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_weak_dependency();
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string package = 2;
+  bool has_package() const;
+  private:
+  bool _internal_has_package() const;
+  public:
+  void clear_package();
+  const std::string& package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_package();
+  PROTOBUF_NODISCARD std::string* release_package();
+  void set_allocated_package(std::string* package);
+  private:
+  const std::string& _internal_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_package(const std::string& value);
+  std::string* _internal_mutable_package();
+  public:
+
+  // optional string syntax = 12;
+  bool has_syntax() const;
+  private:
+  bool _internal_has_syntax() const;
+  public:
+  void clear_syntax();
+  const std::string& syntax() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_syntax(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_syntax();
+  PROTOBUF_NODISCARD std::string* release_syntax();
+  void set_allocated_syntax(std::string* syntax);
+  private:
+  const std::string& _internal_syntax() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_syntax(const std::string& value);
+  std::string* _internal_mutable_syntax();
+  public:
+
+  // optional .google.protobuf.FileOptions options = 8;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::FileOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::FileOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::FileOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FileOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::FileOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* unsafe_arena_release_options();
+
+  // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+  bool has_source_code_info() const;
+  private:
+  bool _internal_has_source_code_info() const;
+  public:
+  void clear_source_code_info();
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& source_code_info() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* release_source_code_info();
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* mutable_source_code_info();
+  void set_allocated_source_code_info(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& _internal_source_code_info() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* _internal_mutable_source_code_info();
+  public:
+  void unsafe_arena_set_allocated_source_code_info(
+      ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info);
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* unsafe_arena_release_source_code_info();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> dependency_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto > message_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto > enum_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto > service_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto > extension_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > public_dependency_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > weak_dependency_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr package_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr syntax_;
+    ::PROTOBUF_NAMESPACE_ID::FileOptions* options_;
+    ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT DescriptorProto_ExtensionRange final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ExtensionRange) */ {
+ public:
+  inline DescriptorProto_ExtensionRange() : DescriptorProto_ExtensionRange(nullptr) {}
+  ~DescriptorProto_ExtensionRange() override;
+  explicit PROTOBUF_CONSTEXPR DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from);
+  DescriptorProto_ExtensionRange(DescriptorProto_ExtensionRange&& from) noexcept
+    : DescriptorProto_ExtensionRange() {
+    *this = ::std::move(from);
+  }
+
+  inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DescriptorProto_ExtensionRange& operator=(DescriptorProto_ExtensionRange&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DescriptorProto_ExtensionRange& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DescriptorProto_ExtensionRange* internal_default_instance() {
+    return reinterpret_cast<const DescriptorProto_ExtensionRange*>(
+               &_DescriptorProto_ExtensionRange_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(DescriptorProto_ExtensionRange& a, DescriptorProto_ExtensionRange& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DescriptorProto_ExtensionRange* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DescriptorProto_ExtensionRange* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DescriptorProto_ExtensionRange* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DescriptorProto_ExtensionRange>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DescriptorProto_ExtensionRange& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DescriptorProto_ExtensionRange& from) {
+    DescriptorProto_ExtensionRange::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DescriptorProto_ExtensionRange* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto.ExtensionRange";
+  }
+  protected:
+  explicit DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 3,
+    kStartFieldNumber = 1,
+    kEndFieldNumber = 2,
+  };
+  // optional .google.protobuf.ExtensionRangeOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* unsafe_arena_release_options();
+
+  // optional int32 start = 1;
+  bool has_start() const;
+  private:
+  bool _internal_has_start() const;
+  public:
+  void clear_start();
+  int32_t start() const;
+  void set_start(int32_t value);
+  private:
+  int32_t _internal_start() const;
+  void _internal_set_start(int32_t value);
+  public:
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options_;
+    int32_t start_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT DescriptorProto_ReservedRange final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ReservedRange) */ {
+ public:
+  inline DescriptorProto_ReservedRange() : DescriptorProto_ReservedRange(nullptr) {}
+  ~DescriptorProto_ReservedRange() override;
+  explicit PROTOBUF_CONSTEXPR DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from);
+  DescriptorProto_ReservedRange(DescriptorProto_ReservedRange&& from) noexcept
+    : DescriptorProto_ReservedRange() {
+    *this = ::std::move(from);
+  }
+
+  inline DescriptorProto_ReservedRange& operator=(const DescriptorProto_ReservedRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DescriptorProto_ReservedRange& operator=(DescriptorProto_ReservedRange&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DescriptorProto_ReservedRange& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DescriptorProto_ReservedRange* internal_default_instance() {
+    return reinterpret_cast<const DescriptorProto_ReservedRange*>(
+               &_DescriptorProto_ReservedRange_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(DescriptorProto_ReservedRange& a, DescriptorProto_ReservedRange& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DescriptorProto_ReservedRange* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DescriptorProto_ReservedRange* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DescriptorProto_ReservedRange* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DescriptorProto_ReservedRange>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DescriptorProto_ReservedRange& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DescriptorProto_ReservedRange& from) {
+    DescriptorProto_ReservedRange::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DescriptorProto_ReservedRange* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto.ReservedRange";
+  }
+  protected:
+  explicit DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kStartFieldNumber = 1,
+    kEndFieldNumber = 2,
+  };
+  // optional int32 start = 1;
+  bool has_start() const;
+  private:
+  bool _internal_has_start() const;
+  public:
+  void clear_start();
+  int32_t start() const;
+  void set_start(int32_t value);
+  private:
+  int32_t _internal_start() const;
+  void _internal_set_start(int32_t value);
+  public:
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ReservedRange)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    int32_t start_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT DescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto) */ {
+ public:
+  inline DescriptorProto() : DescriptorProto(nullptr) {}
+  ~DescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR DescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DescriptorProto(const DescriptorProto& from);
+  DescriptorProto(DescriptorProto&& from) noexcept
+    : DescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline DescriptorProto& operator=(const DescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DescriptorProto& operator=(DescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const DescriptorProto*>(
+               &_DescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    4;
+
+  friend void swap(DescriptorProto& a, DescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DescriptorProto& from) {
+    DescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto";
+  }
+  protected:
+  explicit DescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef DescriptorProto_ExtensionRange ExtensionRange;
+  typedef DescriptorProto_ReservedRange ReservedRange;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFieldFieldNumber = 2,
+    kNestedTypeFieldNumber = 3,
+    kEnumTypeFieldNumber = 4,
+    kExtensionRangeFieldNumber = 5,
+    kExtensionFieldNumber = 6,
+    kOneofDeclFieldNumber = 8,
+    kReservedRangeFieldNumber = 9,
+    kReservedNameFieldNumber = 10,
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 7,
+  };
+  // repeated .google.protobuf.FieldDescriptorProto field = 2;
+  int field_size() const;
+  private:
+  int _internal_field_size() const;
+  public:
+  void clear_field();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* mutable_field(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+      mutable_field();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& _internal_field(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _internal_add_field();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& field(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* add_field();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+      field() const;
+
+  // repeated .google.protobuf.DescriptorProto nested_type = 3;
+  int nested_type_size() const;
+  private:
+  int _internal_nested_type_size() const;
+  public:
+  void clear_nested_type();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* mutable_nested_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+      mutable_nested_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& _internal_nested_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _internal_add_nested_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& nested_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* add_nested_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+      nested_type() const;
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+  int enum_type_size() const;
+  private:
+  int _internal_enum_type_size() const;
+  public:
+  void clear_enum_type();
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* mutable_enum_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+      mutable_enum_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& _internal_enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _internal_add_enum_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* add_enum_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+      enum_type() const;
+
+  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+  int extension_range_size() const;
+  private:
+  int _internal_extension_range_size() const;
+  public:
+  void clear_extension_range();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >*
+      mutable_extension_range();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& _internal_extension_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* _internal_add_extension_range();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& extension_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* add_extension_range();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >&
+      extension_range() const;
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+  int extension_size() const;
+  private:
+  int _internal_extension_size() const;
+  public:
+  void clear_extension();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* mutable_extension(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+      mutable_extension();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& _internal_extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _internal_add_extension();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* add_extension();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+      extension() const;
+
+  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+  int oneof_decl_size() const;
+  private:
+  int _internal_oneof_decl_size() const;
+  public:
+  void clear_oneof_decl();
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* mutable_oneof_decl(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >*
+      mutable_oneof_decl();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& _internal_oneof_decl(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* _internal_add_oneof_decl();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& oneof_decl(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* add_oneof_decl();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >&
+      oneof_decl() const;
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  int reserved_range_size() const;
+  private:
+  int _internal_reserved_range_size() const;
+  public:
+  void clear_reserved_range();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* mutable_reserved_range(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >*
+      mutable_reserved_range();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& _internal_reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* _internal_add_reserved_range();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* add_reserved_range();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >&
+      reserved_range() const;
+
+  // repeated string reserved_name = 10;
+  int reserved_name_size() const;
+  private:
+  int _internal_reserved_name_size() const;
+  public:
+  void clear_reserved_name();
+  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, 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(std::string&& value);
+  void add_reserved_name(const char* value);
+  void add_reserved_name(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& reserved_name() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_reserved_name();
+  private:
+  const std::string& _internal_reserved_name(int index) const;
+  std::string* _internal_add_reserved_name();
+  public:
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.MessageOptions options = 7;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::MessageOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::MessageOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::MessageOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::MessageOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::MessageOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto > field_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto > nested_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto > enum_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange > extension_range_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto > extension_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto > oneof_decl_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange > reserved_range_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> reserved_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::MessageOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ExtensionRangeOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ExtensionRangeOptions) */ {
+ public:
+  inline ExtensionRangeOptions() : ExtensionRangeOptions(nullptr) {}
+  ~ExtensionRangeOptions() override;
+  explicit PROTOBUF_CONSTEXPR ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ExtensionRangeOptions(const ExtensionRangeOptions& from);
+  ExtensionRangeOptions(ExtensionRangeOptions&& from) noexcept
+    : ExtensionRangeOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline ExtensionRangeOptions& operator=(const ExtensionRangeOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ExtensionRangeOptions& operator=(ExtensionRangeOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ExtensionRangeOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ExtensionRangeOptions* internal_default_instance() {
+    return reinterpret_cast<const ExtensionRangeOptions*>(
+               &_ExtensionRangeOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    5;
+
+  friend void swap(ExtensionRangeOptions& a, ExtensionRangeOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ExtensionRangeOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ExtensionRangeOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ExtensionRangeOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ExtensionRangeOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ExtensionRangeOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ExtensionRangeOptions& from) {
+    ExtensionRangeOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ExtensionRangeOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ExtensionRangeOptions";
+  }
+  protected:
+  explicit ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ExtensionRangeOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FieldDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldDescriptorProto) */ {
+ public:
+  inline FieldDescriptorProto() : FieldDescriptorProto(nullptr) {}
+  ~FieldDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FieldDescriptorProto(const FieldDescriptorProto& from);
+  FieldDescriptorProto(FieldDescriptorProto&& from) noexcept
+    : FieldDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FieldDescriptorProto& operator=(FieldDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FieldDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FieldDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const FieldDescriptorProto*>(
+               &_FieldDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    6;
+
+  friend void swap(FieldDescriptorProto& a, FieldDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FieldDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FieldDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FieldDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FieldDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FieldDescriptorProto& from) {
+    FieldDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FieldDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FieldDescriptorProto";
+  }
+  protected:
+  explicit FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef FieldDescriptorProto_Type Type;
+  static constexpr Type TYPE_DOUBLE =
+    FieldDescriptorProto_Type_TYPE_DOUBLE;
+  static constexpr Type TYPE_FLOAT =
+    FieldDescriptorProto_Type_TYPE_FLOAT;
+  static constexpr Type TYPE_INT64 =
+    FieldDescriptorProto_Type_TYPE_INT64;
+  static constexpr Type TYPE_UINT64 =
+    FieldDescriptorProto_Type_TYPE_UINT64;
+  static constexpr Type TYPE_INT32 =
+    FieldDescriptorProto_Type_TYPE_INT32;
+  static constexpr Type TYPE_FIXED64 =
+    FieldDescriptorProto_Type_TYPE_FIXED64;
+  static constexpr Type TYPE_FIXED32 =
+    FieldDescriptorProto_Type_TYPE_FIXED32;
+  static constexpr Type TYPE_BOOL =
+    FieldDescriptorProto_Type_TYPE_BOOL;
+  static constexpr Type TYPE_STRING =
+    FieldDescriptorProto_Type_TYPE_STRING;
+  static constexpr Type TYPE_GROUP =
+    FieldDescriptorProto_Type_TYPE_GROUP;
+  static constexpr Type TYPE_MESSAGE =
+    FieldDescriptorProto_Type_TYPE_MESSAGE;
+  static constexpr Type TYPE_BYTES =
+    FieldDescriptorProto_Type_TYPE_BYTES;
+  static constexpr Type TYPE_UINT32 =
+    FieldDescriptorProto_Type_TYPE_UINT32;
+  static constexpr Type TYPE_ENUM =
+    FieldDescriptorProto_Type_TYPE_ENUM;
+  static constexpr Type TYPE_SFIXED32 =
+    FieldDescriptorProto_Type_TYPE_SFIXED32;
+  static constexpr Type TYPE_SFIXED64 =
+    FieldDescriptorProto_Type_TYPE_SFIXED64;
+  static constexpr Type TYPE_SINT32 =
+    FieldDescriptorProto_Type_TYPE_SINT32;
+  static constexpr Type TYPE_SINT64 =
+    FieldDescriptorProto_Type_TYPE_SINT64;
+  static inline bool Type_IsValid(int value) {
+    return FieldDescriptorProto_Type_IsValid(value);
+  }
+  static constexpr Type Type_MIN =
+    FieldDescriptorProto_Type_Type_MIN;
+  static constexpr Type Type_MAX =
+    FieldDescriptorProto_Type_Type_MAX;
+  static constexpr int Type_ARRAYSIZE =
+    FieldDescriptorProto_Type_Type_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Type_descriptor() {
+    return FieldDescriptorProto_Type_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Type_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Type>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Type_Name.");
+    return FieldDescriptorProto_Type_Name(enum_t_value);
+  }
+  static inline bool Type_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Type* value) {
+    return FieldDescriptorProto_Type_Parse(name, value);
+  }
+
+  typedef FieldDescriptorProto_Label Label;
+  static constexpr Label LABEL_OPTIONAL =
+    FieldDescriptorProto_Label_LABEL_OPTIONAL;
+  static constexpr Label LABEL_REQUIRED =
+    FieldDescriptorProto_Label_LABEL_REQUIRED;
+  static constexpr Label LABEL_REPEATED =
+    FieldDescriptorProto_Label_LABEL_REPEATED;
+  static inline bool Label_IsValid(int value) {
+    return FieldDescriptorProto_Label_IsValid(value);
+  }
+  static constexpr Label Label_MIN =
+    FieldDescriptorProto_Label_Label_MIN;
+  static constexpr Label Label_MAX =
+    FieldDescriptorProto_Label_Label_MAX;
+  static constexpr int Label_ARRAYSIZE =
+    FieldDescriptorProto_Label_Label_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Label_descriptor() {
+    return FieldDescriptorProto_Label_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Label_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Label>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Label_Name.");
+    return FieldDescriptorProto_Label_Name(enum_t_value);
+  }
+  static inline bool Label_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Label* value) {
+    return FieldDescriptorProto_Label_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kExtendeeFieldNumber = 2,
+    kTypeNameFieldNumber = 6,
+    kDefaultValueFieldNumber = 7,
+    kJsonNameFieldNumber = 10,
+    kOptionsFieldNumber = 8,
+    kNumberFieldNumber = 3,
+    kOneofIndexFieldNumber = 9,
+    kProto3OptionalFieldNumber = 17,
+    kLabelFieldNumber = 4,
+    kTypeFieldNumber = 5,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string extendee = 2;
+  bool has_extendee() const;
+  private:
+  bool _internal_has_extendee() const;
+  public:
+  void clear_extendee();
+  const std::string& extendee() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_extendee(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_extendee();
+  PROTOBUF_NODISCARD std::string* release_extendee();
+  void set_allocated_extendee(std::string* extendee);
+  private:
+  const std::string& _internal_extendee() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_extendee(const std::string& value);
+  std::string* _internal_mutable_extendee();
+  public:
+
+  // optional string type_name = 6;
+  bool has_type_name() const;
+  private:
+  bool _internal_has_type_name() const;
+  public:
+  void clear_type_name();
+  const std::string& type_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_type_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_type_name();
+  PROTOBUF_NODISCARD std::string* release_type_name();
+  void set_allocated_type_name(std::string* type_name);
+  private:
+  const std::string& _internal_type_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_name(const std::string& value);
+  std::string* _internal_mutable_type_name();
+  public:
+
+  // optional string default_value = 7;
+  bool has_default_value() const;
+  private:
+  bool _internal_has_default_value() const;
+  public:
+  void clear_default_value();
+  const std::string& default_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_default_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_default_value();
+  PROTOBUF_NODISCARD std::string* release_default_value();
+  void set_allocated_default_value(std::string* default_value);
+  private:
+  const std::string& _internal_default_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_default_value(const std::string& value);
+  std::string* _internal_mutable_default_value();
+  public:
+
+  // optional string json_name = 10;
+  bool has_json_name() const;
+  private:
+  bool _internal_has_json_name() const;
+  public:
+  void clear_json_name();
+  const std::string& json_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_json_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_json_name();
+  PROTOBUF_NODISCARD std::string* release_json_name();
+  void set_allocated_json_name(std::string* json_name);
+  private:
+  const std::string& _internal_json_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_json_name(const std::string& value);
+  std::string* _internal_mutable_json_name();
+  public:
+
+  // optional .google.protobuf.FieldOptions options = 8;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::FieldOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::FieldOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::FieldOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::FieldOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* unsafe_arena_release_options();
+
+  // optional int32 number = 3;
+  bool has_number() const;
+  private:
+  bool _internal_has_number() const;
+  public:
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // optional int32 oneof_index = 9;
+  bool has_oneof_index() const;
+  private:
+  bool _internal_has_oneof_index() const;
+  public:
+  void clear_oneof_index();
+  int32_t oneof_index() const;
+  void set_oneof_index(int32_t value);
+  private:
+  int32_t _internal_oneof_index() const;
+  void _internal_set_oneof_index(int32_t value);
+  public:
+
+  // optional bool proto3_optional = 17;
+  bool has_proto3_optional() const;
+  private:
+  bool _internal_has_proto3_optional() const;
+  public:
+  void clear_proto3_optional();
+  bool proto3_optional() const;
+  void set_proto3_optional(bool value);
+  private:
+  bool _internal_proto3_optional() const;
+  void _internal_set_proto3_optional(bool value);
+  public:
+
+  // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+  bool has_label() const;
+  private:
+  bool _internal_has_label() const;
+  public:
+  void clear_label();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label label() const;
+  void set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label _internal_label() const;
+  void _internal_set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value);
+  public:
+
+  // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+  bool has_type() const;
+  private:
+  bool _internal_has_type() const;
+  public:
+  void clear_type();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type type() const;
+  void set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type _internal_type() const;
+  void _internal_set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr extendee_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr default_value_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr json_name_;
+    ::PROTOBUF_NAMESPACE_ID::FieldOptions* options_;
+    int32_t number_;
+    int32_t oneof_index_;
+    bool proto3_optional_;
+    int label_;
+    int type_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT OneofDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofDescriptorProto) */ {
+ public:
+  inline OneofDescriptorProto() : OneofDescriptorProto(nullptr) {}
+  ~OneofDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  OneofDescriptorProto(const OneofDescriptorProto& from);
+  OneofDescriptorProto(OneofDescriptorProto&& from) noexcept
+    : OneofDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline OneofDescriptorProto& operator=(const OneofDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline OneofDescriptorProto& operator=(OneofDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const OneofDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const OneofDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const OneofDescriptorProto*>(
+               &_OneofDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    7;
+
+  friend void swap(OneofDescriptorProto& a, OneofDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(OneofDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(OneofDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  OneofDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<OneofDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const OneofDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const OneofDescriptorProto& from) {
+    OneofDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(OneofDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.OneofDescriptorProto";
+  }
+  protected:
+  explicit OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 2,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.OneofOptions options = 2;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::OneofOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::OneofOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::OneofOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::OneofOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::OneofOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::OneofOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumDescriptorProto_EnumReservedRange final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumDescriptorProto.EnumReservedRange) */ {
+ public:
+  inline EnumDescriptorProto_EnumReservedRange() : EnumDescriptorProto_EnumReservedRange(nullptr) {}
+  ~EnumDescriptorProto_EnumReservedRange() override;
+  explicit PROTOBUF_CONSTEXPR EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumDescriptorProto_EnumReservedRange(const EnumDescriptorProto_EnumReservedRange& from);
+  EnumDescriptorProto_EnumReservedRange(EnumDescriptorProto_EnumReservedRange&& from) noexcept
+    : EnumDescriptorProto_EnumReservedRange() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumDescriptorProto_EnumReservedRange& operator=(const EnumDescriptorProto_EnumReservedRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumDescriptorProto_EnumReservedRange& operator=(EnumDescriptorProto_EnumReservedRange&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumDescriptorProto_EnumReservedRange& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumDescriptorProto_EnumReservedRange* internal_default_instance() {
+    return reinterpret_cast<const EnumDescriptorProto_EnumReservedRange*>(
+               &_EnumDescriptorProto_EnumReservedRange_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    8;
+
+  friend void swap(EnumDescriptorProto_EnumReservedRange& a, EnumDescriptorProto_EnumReservedRange& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumDescriptorProto_EnumReservedRange* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumDescriptorProto_EnumReservedRange* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumDescriptorProto_EnumReservedRange* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumDescriptorProto_EnumReservedRange>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumDescriptorProto_EnumReservedRange& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumDescriptorProto_EnumReservedRange& from) {
+    EnumDescriptorProto_EnumReservedRange::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumDescriptorProto_EnumReservedRange* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumDescriptorProto.EnumReservedRange";
+  }
+  protected:
+  explicit EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kStartFieldNumber = 1,
+    kEndFieldNumber = 2,
+  };
+  // optional int32 start = 1;
+  bool has_start() const;
+  private:
+  bool _internal_has_start() const;
+  public:
+  void clear_start();
+  int32_t start() const;
+  void set_start(int32_t value);
+  private:
+  int32_t _internal_start() const;
+  void _internal_set_start(int32_t value);
+  public:
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    int32_t start_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumDescriptorProto) */ {
+ public:
+  inline EnumDescriptorProto() : EnumDescriptorProto(nullptr) {}
+  ~EnumDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumDescriptorProto(const EnumDescriptorProto& from);
+  EnumDescriptorProto(EnumDescriptorProto&& from) noexcept
+    : EnumDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumDescriptorProto& operator=(EnumDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const EnumDescriptorProto*>(
+               &_EnumDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    9;
+
+  friend void swap(EnumDescriptorProto& a, EnumDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumDescriptorProto& from) {
+    EnumDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumDescriptorProto";
+  }
+  protected:
+  explicit EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef EnumDescriptorProto_EnumReservedRange EnumReservedRange;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 2,
+    kReservedRangeFieldNumber = 4,
+    kReservedNameFieldNumber = 5,
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 3,
+  };
+  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+  int value_size() const;
+  private:
+  int _internal_value_size() const;
+  public:
+  void clear_value();
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* mutable_value(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >*
+      mutable_value();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& _internal_value(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* _internal_add_value();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& value(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* add_value();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >&
+      value() const;
+
+  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+  int reserved_range_size() const;
+  private:
+  int _internal_reserved_range_size() const;
+  public:
+  void clear_reserved_range();
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* mutable_reserved_range(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >*
+      mutable_reserved_range();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& _internal_reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* _internal_add_reserved_range();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* add_reserved_range();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >&
+      reserved_range() const;
+
+  // repeated string reserved_name = 5;
+  int reserved_name_size() const;
+  private:
+  int _internal_reserved_name_size() const;
+  public:
+  void clear_reserved_name();
+  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, 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(std::string&& value);
+  void add_reserved_name(const char* value);
+  void add_reserved_name(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& reserved_name() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_reserved_name();
+  private:
+  const std::string& _internal_reserved_name(int index) const;
+  std::string* _internal_add_reserved_name();
+  public:
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.EnumOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::EnumOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::EnumOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::EnumOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto > value_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange > reserved_range_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> reserved_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::EnumOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumValueDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueDescriptorProto) */ {
+ public:
+  inline EnumValueDescriptorProto() : EnumValueDescriptorProto(nullptr) {}
+  ~EnumValueDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumValueDescriptorProto(const EnumValueDescriptorProto& from);
+  EnumValueDescriptorProto(EnumValueDescriptorProto&& from) noexcept
+    : EnumValueDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumValueDescriptorProto& operator=(EnumValueDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumValueDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumValueDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const EnumValueDescriptorProto*>(
+               &_EnumValueDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    10;
+
+  friend void swap(EnumValueDescriptorProto& a, EnumValueDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumValueDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValueDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumValueDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumValueDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumValueDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumValueDescriptorProto& from) {
+    EnumValueDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumValueDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValueDescriptorProto";
+  }
+  protected:
+  explicit EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 3,
+    kNumberFieldNumber = 2,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.EnumValueOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* unsafe_arena_release_options();
+
+  // optional int32 number = 2;
+  bool has_number() const;
+  private:
+  bool _internal_has_number() const;
+  public:
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options_;
+    int32_t number_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ServiceDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceDescriptorProto) */ {
+ public:
+  inline ServiceDescriptorProto() : ServiceDescriptorProto(nullptr) {}
+  ~ServiceDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ServiceDescriptorProto(const ServiceDescriptorProto& from);
+  ServiceDescriptorProto(ServiceDescriptorProto&& from) noexcept
+    : ServiceDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ServiceDescriptorProto& operator=(ServiceDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ServiceDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ServiceDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const ServiceDescriptorProto*>(
+               &_ServiceDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    11;
+
+  friend void swap(ServiceDescriptorProto& a, ServiceDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ServiceDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ServiceDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ServiceDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ServiceDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ServiceDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ServiceDescriptorProto& from) {
+    ServiceDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ServiceDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ServiceDescriptorProto";
+  }
+  protected:
+  explicit ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kMethodFieldNumber = 2,
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 3,
+  };
+  // repeated .google.protobuf.MethodDescriptorProto method = 2;
+  int method_size() const;
+  private:
+  int _internal_method_size() const;
+  public:
+  void clear_method();
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* mutable_method(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >*
+      mutable_method();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& _internal_method(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* _internal_add_method();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& method(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* add_method();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >&
+      method() const;
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.ServiceOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::ServiceOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::ServiceOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::ServiceOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto > method_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::ServiceOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT MethodDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodDescriptorProto) */ {
+ public:
+  inline MethodDescriptorProto() : MethodDescriptorProto(nullptr) {}
+  ~MethodDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MethodDescriptorProto(const MethodDescriptorProto& from);
+  MethodDescriptorProto(MethodDescriptorProto&& from) noexcept
+    : MethodDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MethodDescriptorProto& operator=(MethodDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MethodDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MethodDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const MethodDescriptorProto*>(
+               &_MethodDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    12;
+
+  friend void swap(MethodDescriptorProto& a, MethodDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MethodDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MethodDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MethodDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MethodDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MethodDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MethodDescriptorProto& from) {
+    MethodDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MethodDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.MethodDescriptorProto";
+  }
+  protected:
+  explicit MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kInputTypeFieldNumber = 2,
+    kOutputTypeFieldNumber = 3,
+    kOptionsFieldNumber = 4,
+    kClientStreamingFieldNumber = 5,
+    kServerStreamingFieldNumber = 6,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string input_type = 2;
+  bool has_input_type() const;
+  private:
+  bool _internal_has_input_type() const;
+  public:
+  void clear_input_type();
+  const std::string& input_type() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_input_type(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_input_type();
+  PROTOBUF_NODISCARD std::string* release_input_type();
+  void set_allocated_input_type(std::string* input_type);
+  private:
+  const std::string& _internal_input_type() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_input_type(const std::string& value);
+  std::string* _internal_mutable_input_type();
+  public:
+
+  // optional string output_type = 3;
+  bool has_output_type() const;
+  private:
+  bool _internal_has_output_type() const;
+  public:
+  void clear_output_type();
+  const std::string& output_type() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_output_type(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_output_type();
+  PROTOBUF_NODISCARD std::string* release_output_type();
+  void set_allocated_output_type(std::string* output_type);
+  private:
+  const std::string& _internal_output_type() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_output_type(const std::string& value);
+  std::string* _internal_mutable_output_type();
+  public:
+
+  // optional .google.protobuf.MethodOptions options = 4;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::MethodOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::MethodOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::MethodOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::MethodOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::MethodOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* unsafe_arena_release_options();
+
+  // optional bool client_streaming = 5 [default = false];
+  bool has_client_streaming() const;
+  private:
+  bool _internal_has_client_streaming() const;
+  public:
+  void clear_client_streaming();
+  bool client_streaming() const;
+  void set_client_streaming(bool value);
+  private:
+  bool _internal_client_streaming() const;
+  void _internal_set_client_streaming(bool value);
+  public:
+
+  // optional bool server_streaming = 6 [default = false];
+  bool has_server_streaming() const;
+  private:
+  bool _internal_has_server_streaming() const;
+  public:
+  void clear_server_streaming();
+  bool server_streaming() const;
+  void set_server_streaming(bool value);
+  private:
+  bool _internal_server_streaming() const;
+  void _internal_set_server_streaming(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr input_type_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr output_type_;
+    ::PROTOBUF_NAMESPACE_ID::MethodOptions* options_;
+    bool client_streaming_;
+    bool server_streaming_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FileOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileOptions) */ {
+ public:
+  inline FileOptions() : FileOptions(nullptr) {}
+  ~FileOptions() override;
+  explicit PROTOBUF_CONSTEXPR FileOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FileOptions(const FileOptions& from);
+  FileOptions(FileOptions&& from) noexcept
+    : FileOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline FileOptions& operator=(const FileOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FileOptions& operator=(FileOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FileOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FileOptions* internal_default_instance() {
+    return reinterpret_cast<const FileOptions*>(
+               &_FileOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    13;
+
+  friend void swap(FileOptions& a, FileOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FileOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FileOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FileOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FileOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FileOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FileOptions& from) {
+    FileOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FileOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FileOptions";
+  }
+  protected:
+  explicit FileOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef FileOptions_OptimizeMode OptimizeMode;
+  static constexpr OptimizeMode SPEED =
+    FileOptions_OptimizeMode_SPEED;
+  static constexpr OptimizeMode CODE_SIZE =
+    FileOptions_OptimizeMode_CODE_SIZE;
+  static constexpr OptimizeMode LITE_RUNTIME =
+    FileOptions_OptimizeMode_LITE_RUNTIME;
+  static inline bool OptimizeMode_IsValid(int value) {
+    return FileOptions_OptimizeMode_IsValid(value);
+  }
+  static constexpr OptimizeMode OptimizeMode_MIN =
+    FileOptions_OptimizeMode_OptimizeMode_MIN;
+  static constexpr OptimizeMode OptimizeMode_MAX =
+    FileOptions_OptimizeMode_OptimizeMode_MAX;
+  static constexpr int OptimizeMode_ARRAYSIZE =
+    FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  OptimizeMode_descriptor() {
+    return FileOptions_OptimizeMode_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& OptimizeMode_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, OptimizeMode>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function OptimizeMode_Name.");
+    return FileOptions_OptimizeMode_Name(enum_t_value);
+  }
+  static inline bool OptimizeMode_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      OptimizeMode* value) {
+    return FileOptions_OptimizeMode_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kJavaPackageFieldNumber = 1,
+    kJavaOuterClassnameFieldNumber = 8,
+    kGoPackageFieldNumber = 11,
+    kObjcClassPrefixFieldNumber = 36,
+    kCsharpNamespaceFieldNumber = 37,
+    kSwiftPrefixFieldNumber = 39,
+    kPhpClassPrefixFieldNumber = 40,
+    kPhpNamespaceFieldNumber = 41,
+    kPhpMetadataNamespaceFieldNumber = 44,
+    kRubyPackageFieldNumber = 45,
+    kJavaMultipleFilesFieldNumber = 10,
+    kJavaGenerateEqualsAndHashFieldNumber = 20,
+    kJavaStringCheckUtf8FieldNumber = 27,
+    kCcGenericServicesFieldNumber = 16,
+    kJavaGenericServicesFieldNumber = 17,
+    kPyGenericServicesFieldNumber = 18,
+    kPhpGenericServicesFieldNumber = 42,
+    kDeprecatedFieldNumber = 23,
+    kOptimizeForFieldNumber = 9,
+    kCcEnableArenasFieldNumber = 31,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional string java_package = 1;
+  bool has_java_package() const;
+  private:
+  bool _internal_has_java_package() const;
+  public:
+  void clear_java_package();
+  const std::string& java_package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_java_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_java_package();
+  PROTOBUF_NODISCARD std::string* release_java_package();
+  void set_allocated_java_package(std::string* java_package);
+  private:
+  const std::string& _internal_java_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_java_package(const std::string& value);
+  std::string* _internal_mutable_java_package();
+  public:
+
+  // optional string java_outer_classname = 8;
+  bool has_java_outer_classname() const;
+  private:
+  bool _internal_has_java_outer_classname() const;
+  public:
+  void clear_java_outer_classname();
+  const std::string& java_outer_classname() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_java_outer_classname(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_java_outer_classname();
+  PROTOBUF_NODISCARD std::string* release_java_outer_classname();
+  void set_allocated_java_outer_classname(std::string* java_outer_classname);
+  private:
+  const std::string& _internal_java_outer_classname() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_java_outer_classname(const std::string& value);
+  std::string* _internal_mutable_java_outer_classname();
+  public:
+
+  // optional string go_package = 11;
+  bool has_go_package() const;
+  private:
+  bool _internal_has_go_package() const;
+  public:
+  void clear_go_package();
+  const std::string& go_package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_go_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_go_package();
+  PROTOBUF_NODISCARD std::string* release_go_package();
+  void set_allocated_go_package(std::string* go_package);
+  private:
+  const std::string& _internal_go_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_go_package(const std::string& value);
+  std::string* _internal_mutable_go_package();
+  public:
+
+  // optional string objc_class_prefix = 36;
+  bool has_objc_class_prefix() const;
+  private:
+  bool _internal_has_objc_class_prefix() const;
+  public:
+  void clear_objc_class_prefix();
+  const std::string& objc_class_prefix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_objc_class_prefix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_objc_class_prefix();
+  PROTOBUF_NODISCARD std::string* release_objc_class_prefix();
+  void set_allocated_objc_class_prefix(std::string* objc_class_prefix);
+  private:
+  const std::string& _internal_objc_class_prefix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_objc_class_prefix(const std::string& value);
+  std::string* _internal_mutable_objc_class_prefix();
+  public:
+
+  // optional string csharp_namespace = 37;
+  bool has_csharp_namespace() const;
+  private:
+  bool _internal_has_csharp_namespace() const;
+  public:
+  void clear_csharp_namespace();
+  const std::string& csharp_namespace() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_csharp_namespace(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_csharp_namespace();
+  PROTOBUF_NODISCARD std::string* release_csharp_namespace();
+  void set_allocated_csharp_namespace(std::string* csharp_namespace);
+  private:
+  const std::string& _internal_csharp_namespace() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_csharp_namespace(const std::string& value);
+  std::string* _internal_mutable_csharp_namespace();
+  public:
+
+  // optional string swift_prefix = 39;
+  bool has_swift_prefix() const;
+  private:
+  bool _internal_has_swift_prefix() const;
+  public:
+  void clear_swift_prefix();
+  const std::string& swift_prefix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_swift_prefix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_swift_prefix();
+  PROTOBUF_NODISCARD std::string* release_swift_prefix();
+  void set_allocated_swift_prefix(std::string* swift_prefix);
+  private:
+  const std::string& _internal_swift_prefix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_swift_prefix(const std::string& value);
+  std::string* _internal_mutable_swift_prefix();
+  public:
+
+  // optional string php_class_prefix = 40;
+  bool has_php_class_prefix() const;
+  private:
+  bool _internal_has_php_class_prefix() const;
+  public:
+  void clear_php_class_prefix();
+  const std::string& php_class_prefix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_php_class_prefix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_php_class_prefix();
+  PROTOBUF_NODISCARD std::string* release_php_class_prefix();
+  void set_allocated_php_class_prefix(std::string* php_class_prefix);
+  private:
+  const std::string& _internal_php_class_prefix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_php_class_prefix(const std::string& value);
+  std::string* _internal_mutable_php_class_prefix();
+  public:
+
+  // optional string php_namespace = 41;
+  bool has_php_namespace() const;
+  private:
+  bool _internal_has_php_namespace() const;
+  public:
+  void clear_php_namespace();
+  const std::string& php_namespace() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_php_namespace(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_php_namespace();
+  PROTOBUF_NODISCARD std::string* release_php_namespace();
+  void set_allocated_php_namespace(std::string* php_namespace);
+  private:
+  const std::string& _internal_php_namespace() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_php_namespace(const std::string& value);
+  std::string* _internal_mutable_php_namespace();
+  public:
+
+  // optional string php_metadata_namespace = 44;
+  bool has_php_metadata_namespace() const;
+  private:
+  bool _internal_has_php_metadata_namespace() const;
+  public:
+  void clear_php_metadata_namespace();
+  const std::string& php_metadata_namespace() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_php_metadata_namespace(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_php_metadata_namespace();
+  PROTOBUF_NODISCARD std::string* release_php_metadata_namespace();
+  void set_allocated_php_metadata_namespace(std::string* php_metadata_namespace);
+  private:
+  const std::string& _internal_php_metadata_namespace() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_php_metadata_namespace(const std::string& value);
+  std::string* _internal_mutable_php_metadata_namespace();
+  public:
+
+  // optional string ruby_package = 45;
+  bool has_ruby_package() const;
+  private:
+  bool _internal_has_ruby_package() const;
+  public:
+  void clear_ruby_package();
+  const std::string& ruby_package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_ruby_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_ruby_package();
+  PROTOBUF_NODISCARD std::string* release_ruby_package();
+  void set_allocated_ruby_package(std::string* ruby_package);
+  private:
+  const std::string& _internal_ruby_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_ruby_package(const std::string& value);
+  std::string* _internal_mutable_ruby_package();
+  public:
+
+  // optional bool java_multiple_files = 10 [default = false];
+  bool has_java_multiple_files() const;
+  private:
+  bool _internal_has_java_multiple_files() const;
+  public:
+  void clear_java_multiple_files();
+  bool java_multiple_files() const;
+  void set_java_multiple_files(bool value);
+  private:
+  bool _internal_java_multiple_files() const;
+  void _internal_set_java_multiple_files(bool value);
+  public:
+
+  // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+  PROTOBUF_DEPRECATED bool has_java_generate_equals_and_hash() const;
+  private:
+  bool _internal_has_java_generate_equals_and_hash() const;
+  public:
+  PROTOBUF_DEPRECATED void clear_java_generate_equals_and_hash();
+  PROTOBUF_DEPRECATED bool java_generate_equals_and_hash() const;
+  PROTOBUF_DEPRECATED void set_java_generate_equals_and_hash(bool value);
+  private:
+  bool _internal_java_generate_equals_and_hash() const;
+  void _internal_set_java_generate_equals_and_hash(bool value);
+  public:
+
+  // optional bool java_string_check_utf8 = 27 [default = false];
+  bool has_java_string_check_utf8() const;
+  private:
+  bool _internal_has_java_string_check_utf8() const;
+  public:
+  void clear_java_string_check_utf8();
+  bool java_string_check_utf8() const;
+  void set_java_string_check_utf8(bool value);
+  private:
+  bool _internal_java_string_check_utf8() const;
+  void _internal_set_java_string_check_utf8(bool value);
+  public:
+
+  // optional bool cc_generic_services = 16 [default = false];
+  bool has_cc_generic_services() const;
+  private:
+  bool _internal_has_cc_generic_services() const;
+  public:
+  void clear_cc_generic_services();
+  bool cc_generic_services() const;
+  void set_cc_generic_services(bool value);
+  private:
+  bool _internal_cc_generic_services() const;
+  void _internal_set_cc_generic_services(bool value);
+  public:
+
+  // optional bool java_generic_services = 17 [default = false];
+  bool has_java_generic_services() const;
+  private:
+  bool _internal_has_java_generic_services() const;
+  public:
+  void clear_java_generic_services();
+  bool java_generic_services() const;
+  void set_java_generic_services(bool value);
+  private:
+  bool _internal_java_generic_services() const;
+  void _internal_set_java_generic_services(bool value);
+  public:
+
+  // optional bool py_generic_services = 18 [default = false];
+  bool has_py_generic_services() const;
+  private:
+  bool _internal_has_py_generic_services() const;
+  public:
+  void clear_py_generic_services();
+  bool py_generic_services() const;
+  void set_py_generic_services(bool value);
+  private:
+  bool _internal_py_generic_services() const;
+  void _internal_set_py_generic_services(bool value);
+  public:
+
+  // optional bool php_generic_services = 42 [default = false];
+  bool has_php_generic_services() const;
+  private:
+  bool _internal_has_php_generic_services() const;
+  public:
+  void clear_php_generic_services();
+  bool php_generic_services() const;
+  void set_php_generic_services(bool value);
+  private:
+  bool _internal_php_generic_services() const;
+  void _internal_set_php_generic_services(bool value);
+  public:
+
+  // optional bool deprecated = 23 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+  bool has_optimize_for() const;
+  private:
+  bool _internal_has_optimize_for() const;
+  public:
+  void clear_optimize_for();
+  ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode optimize_for() const;
+  void set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode _internal_optimize_for() const;
+  void _internal_set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value);
+  public:
+
+  // optional bool cc_enable_arenas = 31 [default = true];
+  bool has_cc_enable_arenas() const;
+  private:
+  bool _internal_has_cc_enable_arenas() const;
+  public:
+  void clear_cc_enable_arenas();
+  bool cc_enable_arenas() const;
+  void set_cc_enable_arenas(bool value);
+  private:
+  bool _internal_cc_enable_arenas() const;
+  void _internal_set_cc_enable_arenas(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr java_package_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr java_outer_classname_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr go_package_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr objc_class_prefix_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr csharp_namespace_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr swift_prefix_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr php_class_prefix_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr php_namespace_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr php_metadata_namespace_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr ruby_package_;
+    bool java_multiple_files_;
+    bool java_generate_equals_and_hash_;
+    bool java_string_check_utf8_;
+    bool cc_generic_services_;
+    bool java_generic_services_;
+    bool py_generic_services_;
+    bool php_generic_services_;
+    bool deprecated_;
+    int optimize_for_;
+    bool cc_enable_arenas_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT MessageOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MessageOptions) */ {
+ public:
+  inline MessageOptions() : MessageOptions(nullptr) {}
+  ~MessageOptions() override;
+  explicit PROTOBUF_CONSTEXPR MessageOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MessageOptions(const MessageOptions& from);
+  MessageOptions(MessageOptions&& from) noexcept
+    : MessageOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline MessageOptions& operator=(const MessageOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MessageOptions& operator=(MessageOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MessageOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MessageOptions* internal_default_instance() {
+    return reinterpret_cast<const MessageOptions*>(
+               &_MessageOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    14;
+
+  friend void swap(MessageOptions& a, MessageOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MessageOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MessageOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MessageOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MessageOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MessageOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MessageOptions& from) {
+    MessageOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MessageOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.MessageOptions";
+  }
+  protected:
+  explicit MessageOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kMessageSetWireFormatFieldNumber = 1,
+    kNoStandardDescriptorAccessorFieldNumber = 2,
+    kDeprecatedFieldNumber = 3,
+    kMapEntryFieldNumber = 7,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool message_set_wire_format = 1 [default = false];
+  bool has_message_set_wire_format() const;
+  private:
+  bool _internal_has_message_set_wire_format() const;
+  public:
+  void clear_message_set_wire_format();
+  bool message_set_wire_format() const;
+  void set_message_set_wire_format(bool value);
+  private:
+  bool _internal_message_set_wire_format() const;
+  void _internal_set_message_set_wire_format(bool value);
+  public:
+
+  // optional bool no_standard_descriptor_accessor = 2 [default = false];
+  bool has_no_standard_descriptor_accessor() const;
+  private:
+  bool _internal_has_no_standard_descriptor_accessor() const;
+  public:
+  void clear_no_standard_descriptor_accessor();
+  bool no_standard_descriptor_accessor() const;
+  void set_no_standard_descriptor_accessor(bool value);
+  private:
+  bool _internal_no_standard_descriptor_accessor() const;
+  void _internal_set_no_standard_descriptor_accessor(bool value);
+  public:
+
+  // optional bool deprecated = 3 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional bool map_entry = 7;
+  bool has_map_entry() const;
+  private:
+  bool _internal_has_map_entry() const;
+  public:
+  void clear_map_entry();
+  bool map_entry() const;
+  void set_map_entry(bool value);
+  private:
+  bool _internal_map_entry() const;
+  void _internal_set_map_entry(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool message_set_wire_format_;
+    bool no_standard_descriptor_accessor_;
+    bool deprecated_;
+    bool map_entry_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FieldOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldOptions) */ {
+ public:
+  inline FieldOptions() : FieldOptions(nullptr) {}
+  ~FieldOptions() override;
+  explicit PROTOBUF_CONSTEXPR FieldOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FieldOptions(const FieldOptions& from);
+  FieldOptions(FieldOptions&& from) noexcept
+    : FieldOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline FieldOptions& operator=(const FieldOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FieldOptions& operator=(FieldOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FieldOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FieldOptions* internal_default_instance() {
+    return reinterpret_cast<const FieldOptions*>(
+               &_FieldOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    15;
+
+  friend void swap(FieldOptions& a, FieldOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FieldOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FieldOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FieldOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FieldOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FieldOptions& from) {
+    FieldOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FieldOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FieldOptions";
+  }
+  protected:
+  explicit FieldOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef FieldOptions_CType CType;
+  static constexpr CType STRING =
+    FieldOptions_CType_STRING;
+  static constexpr CType CORD =
+    FieldOptions_CType_CORD;
+  static constexpr CType STRING_PIECE =
+    FieldOptions_CType_STRING_PIECE;
+  static inline bool CType_IsValid(int value) {
+    return FieldOptions_CType_IsValid(value);
+  }
+  static constexpr CType CType_MIN =
+    FieldOptions_CType_CType_MIN;
+  static constexpr CType CType_MAX =
+    FieldOptions_CType_CType_MAX;
+  static constexpr int CType_ARRAYSIZE =
+    FieldOptions_CType_CType_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  CType_descriptor() {
+    return FieldOptions_CType_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& CType_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, CType>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function CType_Name.");
+    return FieldOptions_CType_Name(enum_t_value);
+  }
+  static inline bool CType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      CType* value) {
+    return FieldOptions_CType_Parse(name, value);
+  }
+
+  typedef FieldOptions_JSType JSType;
+  static constexpr JSType JS_NORMAL =
+    FieldOptions_JSType_JS_NORMAL;
+  static constexpr JSType JS_STRING =
+    FieldOptions_JSType_JS_STRING;
+  static constexpr JSType JS_NUMBER =
+    FieldOptions_JSType_JS_NUMBER;
+  static inline bool JSType_IsValid(int value) {
+    return FieldOptions_JSType_IsValid(value);
+  }
+  static constexpr JSType JSType_MIN =
+    FieldOptions_JSType_JSType_MIN;
+  static constexpr JSType JSType_MAX =
+    FieldOptions_JSType_JSType_MAX;
+  static constexpr int JSType_ARRAYSIZE =
+    FieldOptions_JSType_JSType_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  JSType_descriptor() {
+    return FieldOptions_JSType_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& JSType_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, JSType>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function JSType_Name.");
+    return FieldOptions_JSType_Name(enum_t_value);
+  }
+  static inline bool JSType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      JSType* value) {
+    return FieldOptions_JSType_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kCtypeFieldNumber = 1,
+    kJstypeFieldNumber = 6,
+    kPackedFieldNumber = 2,
+    kLazyFieldNumber = 5,
+    kUnverifiedLazyFieldNumber = 15,
+    kDeprecatedFieldNumber = 3,
+    kWeakFieldNumber = 10,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+  bool has_ctype() const;
+  private:
+  bool _internal_has_ctype() const;
+  public:
+  void clear_ctype();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType ctype() const;
+  void set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType _internal_ctype() const;
+  void _internal_set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value);
+  public:
+
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  bool has_jstype() const;
+  private:
+  bool _internal_has_jstype() const;
+  public:
+  void clear_jstype();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType jstype() const;
+  void set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType _internal_jstype() const;
+  void _internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
+  public:
+
+  // optional bool packed = 2;
+  bool has_packed() const;
+  private:
+  bool _internal_has_packed() const;
+  public:
+  void clear_packed();
+  bool packed() const;
+  void set_packed(bool value);
+  private:
+  bool _internal_packed() const;
+  void _internal_set_packed(bool value);
+  public:
+
+  // optional bool lazy = 5 [default = false];
+  bool has_lazy() const;
+  private:
+  bool _internal_has_lazy() const;
+  public:
+  void clear_lazy();
+  bool lazy() const;
+  void set_lazy(bool value);
+  private:
+  bool _internal_lazy() const;
+  void _internal_set_lazy(bool value);
+  public:
+
+  // optional bool unverified_lazy = 15 [default = false];
+  bool has_unverified_lazy() const;
+  private:
+  bool _internal_has_unverified_lazy() const;
+  public:
+  void clear_unverified_lazy();
+  bool unverified_lazy() const;
+  void set_unverified_lazy(bool value);
+  private:
+  bool _internal_unverified_lazy() const;
+  void _internal_set_unverified_lazy(bool value);
+  public:
+
+  // optional bool deprecated = 3 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional bool weak = 10 [default = false];
+  bool has_weak() const;
+  private:
+  bool _internal_has_weak() const;
+  public:
+  void clear_weak();
+  bool weak() const;
+  void set_weak(bool value);
+  private:
+  bool _internal_weak() const;
+  void _internal_set_weak(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    int ctype_;
+    int jstype_;
+    bool packed_;
+    bool lazy_;
+    bool unverified_lazy_;
+    bool deprecated_;
+    bool weak_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT OneofOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofOptions) */ {
+ public:
+  inline OneofOptions() : OneofOptions(nullptr) {}
+  ~OneofOptions() override;
+  explicit PROTOBUF_CONSTEXPR OneofOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  OneofOptions(const OneofOptions& from);
+  OneofOptions(OneofOptions&& from) noexcept
+    : OneofOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline OneofOptions& operator=(const OneofOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline OneofOptions& operator=(OneofOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const OneofOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const OneofOptions* internal_default_instance() {
+    return reinterpret_cast<const OneofOptions*>(
+               &_OneofOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    16;
+
+  friend void swap(OneofOptions& a, OneofOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(OneofOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(OneofOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  OneofOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<OneofOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const OneofOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const OneofOptions& from) {
+    OneofOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(OneofOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.OneofOptions";
+  }
+  protected:
+  explicit OneofOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.OneofOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumOptions) */ {
+ public:
+  inline EnumOptions() : EnumOptions(nullptr) {}
+  ~EnumOptions() override;
+  explicit PROTOBUF_CONSTEXPR EnumOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumOptions(const EnumOptions& from);
+  EnumOptions(EnumOptions&& from) noexcept
+    : EnumOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumOptions& operator=(const EnumOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumOptions& operator=(EnumOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumOptions* internal_default_instance() {
+    return reinterpret_cast<const EnumOptions*>(
+               &_EnumOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    17;
+
+  friend void swap(EnumOptions& a, EnumOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumOptions& from) {
+    EnumOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumOptions";
+  }
+  protected:
+  explicit EnumOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kAllowAliasFieldNumber = 2,
+    kDeprecatedFieldNumber = 3,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool allow_alias = 2;
+  bool has_allow_alias() const;
+  private:
+  bool _internal_has_allow_alias() const;
+  public:
+  void clear_allow_alias();
+  bool allow_alias() const;
+  void set_allow_alias(bool value);
+  private:
+  bool _internal_allow_alias() const;
+  void _internal_set_allow_alias(bool value);
+  public:
+
+  // optional bool deprecated = 3 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool allow_alias_;
+    bool deprecated_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumValueOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueOptions) */ {
+ public:
+  inline EnumValueOptions() : EnumValueOptions(nullptr) {}
+  ~EnumValueOptions() override;
+  explicit PROTOBUF_CONSTEXPR EnumValueOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumValueOptions(const EnumValueOptions& from);
+  EnumValueOptions(EnumValueOptions&& from) noexcept
+    : EnumValueOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumValueOptions& operator=(const EnumValueOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumValueOptions& operator=(EnumValueOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumValueOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumValueOptions* internal_default_instance() {
+    return reinterpret_cast<const EnumValueOptions*>(
+               &_EnumValueOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    18;
+
+  friend void swap(EnumValueOptions& a, EnumValueOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumValueOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValueOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumValueOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumValueOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumValueOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumValueOptions& from) {
+    EnumValueOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumValueOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValueOptions";
+  }
+  protected:
+  explicit EnumValueOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kDeprecatedFieldNumber = 1,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool deprecated = 1 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool deprecated_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ServiceOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceOptions) */ {
+ public:
+  inline ServiceOptions() : ServiceOptions(nullptr) {}
+  ~ServiceOptions() override;
+  explicit PROTOBUF_CONSTEXPR ServiceOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ServiceOptions(const ServiceOptions& from);
+  ServiceOptions(ServiceOptions&& from) noexcept
+    : ServiceOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline ServiceOptions& operator=(const ServiceOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ServiceOptions& operator=(ServiceOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ServiceOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ServiceOptions* internal_default_instance() {
+    return reinterpret_cast<const ServiceOptions*>(
+               &_ServiceOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    19;
+
+  friend void swap(ServiceOptions& a, ServiceOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ServiceOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ServiceOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ServiceOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ServiceOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ServiceOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ServiceOptions& from) {
+    ServiceOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ServiceOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ServiceOptions";
+  }
+  protected:
+  explicit ServiceOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kDeprecatedFieldNumber = 33,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool deprecated = 33 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool deprecated_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT MethodOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodOptions) */ {
+ public:
+  inline MethodOptions() : MethodOptions(nullptr) {}
+  ~MethodOptions() override;
+  explicit PROTOBUF_CONSTEXPR MethodOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MethodOptions(const MethodOptions& from);
+  MethodOptions(MethodOptions&& from) noexcept
+    : MethodOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline MethodOptions& operator=(const MethodOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MethodOptions& operator=(MethodOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MethodOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MethodOptions* internal_default_instance() {
+    return reinterpret_cast<const MethodOptions*>(
+               &_MethodOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    20;
+
+  friend void swap(MethodOptions& a, MethodOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MethodOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MethodOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MethodOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MethodOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MethodOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MethodOptions& from) {
+    MethodOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MethodOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.MethodOptions";
+  }
+  protected:
+  explicit MethodOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef MethodOptions_IdempotencyLevel IdempotencyLevel;
+  static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN =
+    MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
+  static constexpr IdempotencyLevel NO_SIDE_EFFECTS =
+    MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS;
+  static constexpr IdempotencyLevel IDEMPOTENT =
+    MethodOptions_IdempotencyLevel_IDEMPOTENT;
+  static inline bool IdempotencyLevel_IsValid(int value) {
+    return MethodOptions_IdempotencyLevel_IsValid(value);
+  }
+  static constexpr IdempotencyLevel IdempotencyLevel_MIN =
+    MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN;
+  static constexpr IdempotencyLevel IdempotencyLevel_MAX =
+    MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX;
+  static constexpr int IdempotencyLevel_ARRAYSIZE =
+    MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  IdempotencyLevel_descriptor() {
+    return MethodOptions_IdempotencyLevel_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& IdempotencyLevel_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, IdempotencyLevel>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function IdempotencyLevel_Name.");
+    return MethodOptions_IdempotencyLevel_Name(enum_t_value);
+  }
+  static inline bool IdempotencyLevel_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      IdempotencyLevel* value) {
+    return MethodOptions_IdempotencyLevel_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kDeprecatedFieldNumber = 33,
+    kIdempotencyLevelFieldNumber = 34,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool deprecated = 33 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+  bool has_idempotency_level() const;
+  private:
+  bool _internal_has_idempotency_level() const;
+  public:
+  void clear_idempotency_level();
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel idempotency_level() const;
+  void set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel _internal_idempotency_level() const;
+  void _internal_set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool deprecated_;
+    int idempotency_level_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UninterpretedOption_NamePart final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption.NamePart) */ {
+ public:
+  inline UninterpretedOption_NamePart() : UninterpretedOption_NamePart(nullptr) {}
+  ~UninterpretedOption_NamePart() override;
+  explicit PROTOBUF_CONSTEXPR UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from);
+  UninterpretedOption_NamePart(UninterpretedOption_NamePart&& from) noexcept
+    : UninterpretedOption_NamePart() {
+    *this = ::std::move(from);
+  }
+
+  inline UninterpretedOption_NamePart& operator=(const UninterpretedOption_NamePart& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UninterpretedOption_NamePart& operator=(UninterpretedOption_NamePart&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UninterpretedOption_NamePart& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UninterpretedOption_NamePart* internal_default_instance() {
+    return reinterpret_cast<const UninterpretedOption_NamePart*>(
+               &_UninterpretedOption_NamePart_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    21;
+
+  friend void swap(UninterpretedOption_NamePart& a, UninterpretedOption_NamePart& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UninterpretedOption_NamePart* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UninterpretedOption_NamePart* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UninterpretedOption_NamePart* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UninterpretedOption_NamePart>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UninterpretedOption_NamePart& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UninterpretedOption_NamePart& from) {
+    UninterpretedOption_NamePart::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UninterpretedOption_NamePart* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UninterpretedOption.NamePart";
+  }
+  protected:
+  explicit UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNamePartFieldNumber = 1,
+    kIsExtensionFieldNumber = 2,
+  };
+  // required string name_part = 1;
+  bool has_name_part() const;
+  private:
+  bool _internal_has_name_part() const;
+  public:
+  void clear_name_part();
+  const std::string& name_part() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name_part(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name_part();
+  PROTOBUF_NODISCARD std::string* release_name_part();
+  void set_allocated_name_part(std::string* name_part);
+  private:
+  const std::string& _internal_name_part() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name_part(const std::string& value);
+  std::string* _internal_mutable_name_part();
+  public:
+
+  // required bool is_extension = 2;
+  bool has_is_extension() const;
+  private:
+  bool _internal_has_is_extension() const;
+  public:
+  void clear_is_extension();
+  bool is_extension() const;
+  void set_is_extension(bool value);
+  private:
+  bool _internal_is_extension() const;
+  void _internal_set_is_extension(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
+ private:
+  class _Internal;
+
+  // helper for ByteSizeLong()
+  size_t RequiredFieldsByteSizeFallback() const;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_part_;
+    bool is_extension_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UninterpretedOption final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption) */ {
+ public:
+  inline UninterpretedOption() : UninterpretedOption(nullptr) {}
+  ~UninterpretedOption() override;
+  explicit PROTOBUF_CONSTEXPR UninterpretedOption(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UninterpretedOption(const UninterpretedOption& from);
+  UninterpretedOption(UninterpretedOption&& from) noexcept
+    : UninterpretedOption() {
+    *this = ::std::move(from);
+  }
+
+  inline UninterpretedOption& operator=(const UninterpretedOption& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UninterpretedOption& operator=(UninterpretedOption&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UninterpretedOption& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UninterpretedOption* internal_default_instance() {
+    return reinterpret_cast<const UninterpretedOption*>(
+               &_UninterpretedOption_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    22;
+
+  friend void swap(UninterpretedOption& a, UninterpretedOption& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UninterpretedOption* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UninterpretedOption* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UninterpretedOption* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UninterpretedOption>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UninterpretedOption& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UninterpretedOption& from) {
+    UninterpretedOption::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UninterpretedOption* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UninterpretedOption";
+  }
+  protected:
+  explicit UninterpretedOption(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef UninterpretedOption_NamePart NamePart;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 2,
+    kIdentifierValueFieldNumber = 3,
+    kStringValueFieldNumber = 7,
+    kAggregateValueFieldNumber = 8,
+    kPositiveIntValueFieldNumber = 4,
+    kNegativeIntValueFieldNumber = 5,
+    kDoubleValueFieldNumber = 6,
+  };
+  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+  int name_size() const;
+  private:
+  int _internal_name_size() const;
+  public:
+  void clear_name();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* mutable_name(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >*
+      mutable_name();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& _internal_name(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* _internal_add_name();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& name(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* add_name();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >&
+      name() const;
+
+  // optional string identifier_value = 3;
+  bool has_identifier_value() const;
+  private:
+  bool _internal_has_identifier_value() const;
+  public:
+  void clear_identifier_value();
+  const std::string& identifier_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_identifier_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_identifier_value();
+  PROTOBUF_NODISCARD std::string* release_identifier_value();
+  void set_allocated_identifier_value(std::string* identifier_value);
+  private:
+  const std::string& _internal_identifier_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_identifier_value(const std::string& value);
+  std::string* _internal_mutable_identifier_value();
+  public:
+
+  // optional bytes string_value = 7;
+  bool has_string_value() const;
+  private:
+  bool _internal_has_string_value() const;
+  public:
+  void clear_string_value();
+  const std::string& string_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_string_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_string_value();
+  PROTOBUF_NODISCARD std::string* release_string_value();
+  void set_allocated_string_value(std::string* string_value);
+  private:
+  const std::string& _internal_string_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_string_value(const std::string& value);
+  std::string* _internal_mutable_string_value();
+  public:
+
+  // optional string aggregate_value = 8;
+  bool has_aggregate_value() const;
+  private:
+  bool _internal_has_aggregate_value() const;
+  public:
+  void clear_aggregate_value();
+  const std::string& aggregate_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_aggregate_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_aggregate_value();
+  PROTOBUF_NODISCARD std::string* release_aggregate_value();
+  void set_allocated_aggregate_value(std::string* aggregate_value);
+  private:
+  const std::string& _internal_aggregate_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_aggregate_value(const std::string& value);
+  std::string* _internal_mutable_aggregate_value();
+  public:
+
+  // optional uint64 positive_int_value = 4;
+  bool has_positive_int_value() const;
+  private:
+  bool _internal_has_positive_int_value() const;
+  public:
+  void clear_positive_int_value();
+  uint64_t positive_int_value() const;
+  void set_positive_int_value(uint64_t value);
+  private:
+  uint64_t _internal_positive_int_value() const;
+  void _internal_set_positive_int_value(uint64_t value);
+  public:
+
+  // optional int64 negative_int_value = 5;
+  bool has_negative_int_value() const;
+  private:
+  bool _internal_has_negative_int_value() const;
+  public:
+  void clear_negative_int_value();
+  int64_t negative_int_value() const;
+  void set_negative_int_value(int64_t value);
+  private:
+  int64_t _internal_negative_int_value() const;
+  void _internal_set_negative_int_value(int64_t value);
+  public:
+
+  // optional double double_value = 6;
+  bool has_double_value() const;
+  private:
+  bool _internal_has_double_value() const;
+  public:
+  void clear_double_value();
+  double double_value() const;
+  void set_double_value(double value);
+  private:
+  double _internal_double_value() const;
+  void _internal_set_double_value(double value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart > name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr identifier_value_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr string_value_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr aggregate_value_;
+    uint64_t positive_int_value_;
+    int64_t negative_int_value_;
+    double double_value_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT SourceCodeInfo_Location final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo.Location) */ {
+ public:
+  inline SourceCodeInfo_Location() : SourceCodeInfo_Location(nullptr) {}
+  ~SourceCodeInfo_Location() override;
+  explicit PROTOBUF_CONSTEXPR SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  SourceCodeInfo_Location(const SourceCodeInfo_Location& from);
+  SourceCodeInfo_Location(SourceCodeInfo_Location&& from) noexcept
+    : SourceCodeInfo_Location() {
+    *this = ::std::move(from);
+  }
+
+  inline SourceCodeInfo_Location& operator=(const SourceCodeInfo_Location& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline SourceCodeInfo_Location& operator=(SourceCodeInfo_Location&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const SourceCodeInfo_Location& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const SourceCodeInfo_Location* internal_default_instance() {
+    return reinterpret_cast<const SourceCodeInfo_Location*>(
+               &_SourceCodeInfo_Location_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    23;
+
+  friend void swap(SourceCodeInfo_Location& a, SourceCodeInfo_Location& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(SourceCodeInfo_Location* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(SourceCodeInfo_Location* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  SourceCodeInfo_Location* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<SourceCodeInfo_Location>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const SourceCodeInfo_Location& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const SourceCodeInfo_Location& from) {
+    SourceCodeInfo_Location::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(SourceCodeInfo_Location* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.SourceCodeInfo.Location";
+  }
+  protected:
+  explicit SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPathFieldNumber = 1,
+    kSpanFieldNumber = 2,
+    kLeadingDetachedCommentsFieldNumber = 6,
+    kLeadingCommentsFieldNumber = 3,
+    kTrailingCommentsFieldNumber = 4,
+  };
+  // repeated int32 path = 1 [packed = true];
+  int path_size() const;
+  private:
+  int _internal_path_size() const;
+  public:
+  void clear_path();
+  private:
+  int32_t _internal_path(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_path() const;
+  void _internal_add_path(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_path();
+  public:
+  int32_t path(int index) const;
+  void set_path(int index, int32_t value);
+  void add_path(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      path() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_path();
+
+  // repeated int32 span = 2 [packed = true];
+  int span_size() const;
+  private:
+  int _internal_span_size() const;
+  public:
+  void clear_span();
+  private:
+  int32_t _internal_span(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_span() const;
+  void _internal_add_span(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_span();
+  public:
+  int32_t span(int index) const;
+  void set_span(int index, int32_t value);
+  void add_span(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      span() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_span();
+
+  // repeated string leading_detached_comments = 6;
+  int leading_detached_comments_size() const;
+  private:
+  int _internal_leading_detached_comments_size() const;
+  public:
+  void clear_leading_detached_comments();
+  const std::string& leading_detached_comments(int index) const;
+  std::string* mutable_leading_detached_comments(int index);
+  void set_leading_detached_comments(int index, const std::string& value);
+  void set_leading_detached_comments(int index, std::string&& value);
+  void set_leading_detached_comments(int index, const char* value);
+  void set_leading_detached_comments(int index, const char* value, size_t size);
+  std::string* add_leading_detached_comments();
+  void add_leading_detached_comments(const std::string& value);
+  void add_leading_detached_comments(std::string&& value);
+  void add_leading_detached_comments(const char* value);
+  void add_leading_detached_comments(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& leading_detached_comments() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_leading_detached_comments();
+  private:
+  const std::string& _internal_leading_detached_comments(int index) const;
+  std::string* _internal_add_leading_detached_comments();
+  public:
+
+  // optional string leading_comments = 3;
+  bool has_leading_comments() const;
+  private:
+  bool _internal_has_leading_comments() const;
+  public:
+  void clear_leading_comments();
+  const std::string& leading_comments() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_leading_comments(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_leading_comments();
+  PROTOBUF_NODISCARD std::string* release_leading_comments();
+  void set_allocated_leading_comments(std::string* leading_comments);
+  private:
+  const std::string& _internal_leading_comments() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_leading_comments(const std::string& value);
+  std::string* _internal_mutable_leading_comments();
+  public:
+
+  // optional string trailing_comments = 4;
+  bool has_trailing_comments() const;
+  private:
+  bool _internal_has_trailing_comments() const;
+  public:
+  void clear_trailing_comments();
+  const std::string& trailing_comments() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_trailing_comments(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_trailing_comments();
+  PROTOBUF_NODISCARD std::string* release_trailing_comments();
+  void set_allocated_trailing_comments(std::string* trailing_comments);
+  private:
+  const std::string& _internal_trailing_comments() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_trailing_comments(const std::string& value);
+  std::string* _internal_mutable_trailing_comments();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > path_;
+    mutable std::atomic<int> _path_cached_byte_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > span_;
+    mutable std::atomic<int> _span_cached_byte_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> leading_detached_comments_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr leading_comments_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr trailing_comments_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT SourceCodeInfo final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo) */ {
+ public:
+  inline SourceCodeInfo() : SourceCodeInfo(nullptr) {}
+  ~SourceCodeInfo() override;
+  explicit PROTOBUF_CONSTEXPR SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  SourceCodeInfo(const SourceCodeInfo& from);
+  SourceCodeInfo(SourceCodeInfo&& from) noexcept
+    : SourceCodeInfo() {
+    *this = ::std::move(from);
+  }
+
+  inline SourceCodeInfo& operator=(const SourceCodeInfo& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline SourceCodeInfo& operator=(SourceCodeInfo&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const SourceCodeInfo& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const SourceCodeInfo* internal_default_instance() {
+    return reinterpret_cast<const SourceCodeInfo*>(
+               &_SourceCodeInfo_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    24;
+
+  friend void swap(SourceCodeInfo& a, SourceCodeInfo& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(SourceCodeInfo* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(SourceCodeInfo* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  SourceCodeInfo* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<SourceCodeInfo>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const SourceCodeInfo& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const SourceCodeInfo& from) {
+    SourceCodeInfo::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(SourceCodeInfo* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.SourceCodeInfo";
+  }
+  protected:
+  explicit SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef SourceCodeInfo_Location Location;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kLocationFieldNumber = 1,
+  };
+  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+  int location_size() const;
+  private:
+  int _internal_location_size() const;
+  public:
+  void clear_location();
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* mutable_location(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >*
+      mutable_location();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& _internal_location(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* _internal_add_location();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& location(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* add_location();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >&
+      location() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location > location_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo.Annotation) */ {
+ public:
+  inline GeneratedCodeInfo_Annotation() : GeneratedCodeInfo_Annotation(nullptr) {}
+  ~GeneratedCodeInfo_Annotation() override;
+  explicit PROTOBUF_CONSTEXPR GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from);
+  GeneratedCodeInfo_Annotation(GeneratedCodeInfo_Annotation&& from) noexcept
+    : GeneratedCodeInfo_Annotation() {
+    *this = ::std::move(from);
+  }
+
+  inline GeneratedCodeInfo_Annotation& operator=(const GeneratedCodeInfo_Annotation& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline GeneratedCodeInfo_Annotation& operator=(GeneratedCodeInfo_Annotation&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const GeneratedCodeInfo_Annotation& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const GeneratedCodeInfo_Annotation* internal_default_instance() {
+    return reinterpret_cast<const GeneratedCodeInfo_Annotation*>(
+               &_GeneratedCodeInfo_Annotation_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    25;
+
+  friend void swap(GeneratedCodeInfo_Annotation& a, GeneratedCodeInfo_Annotation& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(GeneratedCodeInfo_Annotation* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(GeneratedCodeInfo_Annotation* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  GeneratedCodeInfo_Annotation* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<GeneratedCodeInfo_Annotation>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const GeneratedCodeInfo_Annotation& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const GeneratedCodeInfo_Annotation& from) {
+    GeneratedCodeInfo_Annotation::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(GeneratedCodeInfo_Annotation* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.GeneratedCodeInfo.Annotation";
+  }
+  protected:
+  explicit GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPathFieldNumber = 1,
+    kSourceFileFieldNumber = 2,
+    kBeginFieldNumber = 3,
+    kEndFieldNumber = 4,
+  };
+  // repeated int32 path = 1 [packed = true];
+  int path_size() const;
+  private:
+  int _internal_path_size() const;
+  public:
+  void clear_path();
+  private:
+  int32_t _internal_path(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_path() const;
+  void _internal_add_path(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_path();
+  public:
+  int32_t path(int index) const;
+  void set_path(int index, int32_t value);
+  void add_path(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      path() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_path();
+
+  // optional string source_file = 2;
+  bool has_source_file() const;
+  private:
+  bool _internal_has_source_file() const;
+  public:
+  void clear_source_file();
+  const std::string& source_file() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_source_file(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_source_file();
+  PROTOBUF_NODISCARD std::string* release_source_file();
+  void set_allocated_source_file(std::string* source_file);
+  private:
+  const std::string& _internal_source_file() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_source_file(const std::string& value);
+  std::string* _internal_mutable_source_file();
+  public:
+
+  // optional int32 begin = 3;
+  bool has_begin() const;
+  private:
+  bool _internal_has_begin() const;
+  public:
+  void clear_begin();
+  int32_t begin() const;
+  void set_begin(int32_t value);
+  private:
+  int32_t _internal_begin() const;
+  void _internal_set_begin(int32_t value);
+  public:
+
+  // optional int32 end = 4;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > path_;
+    mutable std::atomic<int> _path_cached_byte_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr source_file_;
+    int32_t begin_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT GeneratedCodeInfo final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo) */ {
+ public:
+  inline GeneratedCodeInfo() : GeneratedCodeInfo(nullptr) {}
+  ~GeneratedCodeInfo() override;
+  explicit PROTOBUF_CONSTEXPR GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  GeneratedCodeInfo(const GeneratedCodeInfo& from);
+  GeneratedCodeInfo(GeneratedCodeInfo&& from) noexcept
+    : GeneratedCodeInfo() {
+    *this = ::std::move(from);
+  }
+
+  inline GeneratedCodeInfo& operator=(const GeneratedCodeInfo& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline GeneratedCodeInfo& operator=(GeneratedCodeInfo&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const GeneratedCodeInfo& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const GeneratedCodeInfo* internal_default_instance() {
+    return reinterpret_cast<const GeneratedCodeInfo*>(
+               &_GeneratedCodeInfo_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    26;
+
+  friend void swap(GeneratedCodeInfo& a, GeneratedCodeInfo& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(GeneratedCodeInfo* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(GeneratedCodeInfo* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  GeneratedCodeInfo* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<GeneratedCodeInfo>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const GeneratedCodeInfo& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const GeneratedCodeInfo& from) {
+    GeneratedCodeInfo::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(GeneratedCodeInfo* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.GeneratedCodeInfo";
+  }
+  protected:
+  explicit GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef GeneratedCodeInfo_Annotation Annotation;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kAnnotationFieldNumber = 1,
+  };
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  int annotation_size() const;
+  private:
+  int _internal_annotation_size() const;
+  public:
+  void clear_annotation();
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* mutable_annotation(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >*
+      mutable_annotation();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& _internal_annotation(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* _internal_add_annotation();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& annotation(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* add_annotation();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >&
+      annotation() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation > annotation_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// FileDescriptorSet
+
+// repeated .google.protobuf.FileDescriptorProto file = 1;
+inline int FileDescriptorSet::_internal_file_size() const {
+  return _impl_.file_.size();
+}
+inline int FileDescriptorSet::file_size() const {
+  return _internal_file_size();
+}
+inline void FileDescriptorSet::clear_file() {
+  _impl_.file_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorSet.file)
+  return _impl_.file_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
+FileDescriptorSet::mutable_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file)
+  return &_impl_.file_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& FileDescriptorSet::_internal_file(int index) const {
+  return _impl_.file_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& FileDescriptorSet::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorSet.file)
+  return _internal_file(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* FileDescriptorSet::_internal_add_file() {
+  return _impl_.file_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* FileDescriptorSet::add_file() {
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _add = _internal_add_file();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >&
+FileDescriptorSet::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
+  return _impl_.file_;
+}
+
+// -------------------------------------------------------------------
+
+// FileDescriptorProto
+
+// optional string name = 1;
+inline bool FileDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FileDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void FileDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& FileDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.name)
+}
+inline std::string* FileDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void FileDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.name)
+}
+
+// optional string package = 2;
+inline bool FileDescriptorProto::_internal_has_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FileDescriptorProto::has_package() const {
+  return _internal_has_package();
+}
+inline void FileDescriptorProto::clear_package() {
+  _impl_.package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& FileDescriptorProto::package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package)
+  return _internal_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileDescriptorProto::set_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.package)
+}
+inline std::string* FileDescriptorProto::mutable_package() {
+  std::string* _s = _internal_mutable_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_package() const {
+  return _impl_.package_.Get();
+}
+inline void FileDescriptorProto::_internal_set_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::_internal_mutable_package() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::release_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package)
+  if (!_internal_has_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.package_.IsDefault()) {
+    _impl_.package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileDescriptorProto::set_allocated_package(std::string* package) {
+  if (package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.package_.SetAllocated(package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.package_.IsDefault()) {
+    _impl_.package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package)
+}
+
+// repeated string dependency = 3;
+inline int FileDescriptorProto::_internal_dependency_size() const {
+  return _impl_.dependency_.size();
+}
+inline int FileDescriptorProto::dependency_size() const {
+  return _internal_dependency_size();
+}
+inline void FileDescriptorProto::clear_dependency() {
+  _impl_.dependency_.Clear();
+}
+inline std::string* FileDescriptorProto::add_dependency() {
+  std::string* _s = _internal_add_dependency();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_dependency(int index) const {
+  return _impl_.dependency_.Get(index);
+}
+inline const std::string& FileDescriptorProto::dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.dependency)
+  return _internal_dependency(index);
+}
+inline std::string* FileDescriptorProto::mutable_dependency(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.dependency)
+  return _impl_.dependency_.Mutable(index);
+}
+inline void FileDescriptorProto::set_dependency(int index, const std::string& value) {
+  _impl_.dependency_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::set_dependency(int index, std::string&& value) {
+  _impl_.dependency_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::set_dependency(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.dependency_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) {
+  _impl_.dependency_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+inline std::string* FileDescriptorProto::_internal_add_dependency() {
+  return _impl_.dependency_.Add();
+}
+inline void FileDescriptorProto::add_dependency(const std::string& value) {
+  _impl_.dependency_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::add_dependency(std::string&& value) {
+  _impl_.dependency_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::add_dependency(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.dependency_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::add_dependency(const char* value, size_t size) {
+  _impl_.dependency_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+FileDescriptorProto::dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.dependency)
+  return _impl_.dependency_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+FileDescriptorProto::mutable_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.dependency)
+  return &_impl_.dependency_;
+}
+
+// repeated int32 public_dependency = 10;
+inline int FileDescriptorProto::_internal_public_dependency_size() const {
+  return _impl_.public_dependency_.size();
+}
+inline int FileDescriptorProto::public_dependency_size() const {
+  return _internal_public_dependency_size();
+}
+inline void FileDescriptorProto::clear_public_dependency() {
+  _impl_.public_dependency_.Clear();
+}
+inline int32_t FileDescriptorProto::_internal_public_dependency(int index) const {
+  return _impl_.public_dependency_.Get(index);
+}
+inline int32_t FileDescriptorProto::public_dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.public_dependency)
+  return _internal_public_dependency(index);
+}
+inline void FileDescriptorProto::set_public_dependency(int index, int32_t value) {
+  _impl_.public_dependency_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.public_dependency)
+}
+inline void FileDescriptorProto::_internal_add_public_dependency(int32_t value) {
+  _impl_.public_dependency_.Add(value);
+}
+inline void FileDescriptorProto::add_public_dependency(int32_t value) {
+  _internal_add_public_dependency(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.public_dependency)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::_internal_public_dependency() const {
+  return _impl_.public_dependency_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::public_dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.public_dependency)
+  return _internal_public_dependency();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::_internal_mutable_public_dependency() {
+  return &_impl_.public_dependency_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::mutable_public_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.public_dependency)
+  return _internal_mutable_public_dependency();
+}
+
+// repeated int32 weak_dependency = 11;
+inline int FileDescriptorProto::_internal_weak_dependency_size() const {
+  return _impl_.weak_dependency_.size();
+}
+inline int FileDescriptorProto::weak_dependency_size() const {
+  return _internal_weak_dependency_size();
+}
+inline void FileDescriptorProto::clear_weak_dependency() {
+  _impl_.weak_dependency_.Clear();
+}
+inline int32_t FileDescriptorProto::_internal_weak_dependency(int index) const {
+  return _impl_.weak_dependency_.Get(index);
+}
+inline int32_t FileDescriptorProto::weak_dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.weak_dependency)
+  return _internal_weak_dependency(index);
+}
+inline void FileDescriptorProto::set_weak_dependency(int index, int32_t value) {
+  _impl_.weak_dependency_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+inline void FileDescriptorProto::_internal_add_weak_dependency(int32_t value) {
+  _impl_.weak_dependency_.Add(value);
+}
+inline void FileDescriptorProto::add_weak_dependency(int32_t value) {
+  _internal_add_weak_dependency(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::_internal_weak_dependency() const {
+  return _impl_.weak_dependency_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::weak_dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.weak_dependency)
+  return _internal_weak_dependency();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::_internal_mutable_weak_dependency() {
+  return &_impl_.weak_dependency_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::mutable_weak_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.weak_dependency)
+  return _internal_mutable_weak_dependency();
+}
+
+// repeated .google.protobuf.DescriptorProto message_type = 4;
+inline int FileDescriptorProto::_internal_message_type_size() const {
+  return _impl_.message_type_.size();
+}
+inline int FileDescriptorProto::message_type_size() const {
+  return _internal_message_type_size();
+}
+inline void FileDescriptorProto::clear_message_type() {
+  _impl_.message_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.message_type)
+  return _impl_.message_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+FileDescriptorProto::mutable_message_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type)
+  return &_impl_.message_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& FileDescriptorProto::_internal_message_type(int index) const {
+  return _impl_.message_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.message_type)
+  return _internal_message_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* FileDescriptorProto::_internal_add_message_type() {
+  return _impl_.message_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* FileDescriptorProto::add_message_type() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _add = _internal_add_message_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+FileDescriptorProto::message_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
+  return _impl_.message_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+inline int FileDescriptorProto::_internal_enum_type_size() const {
+  return _impl_.enum_type_.size();
+}
+inline int FileDescriptorProto::enum_type_size() const {
+  return _internal_enum_type_size();
+}
+inline void FileDescriptorProto::clear_enum_type() {
+  _impl_.enum_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.enum_type)
+  return _impl_.enum_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+FileDescriptorProto::mutable_enum_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type)
+  return &_impl_.enum_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& FileDescriptorProto::_internal_enum_type(int index) const {
+  return _impl_.enum_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.enum_type)
+  return _internal_enum_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* FileDescriptorProto::_internal_add_enum_type() {
+  return _impl_.enum_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _add = _internal_add_enum_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+FileDescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
+  return _impl_.enum_type_;
+}
+
+// repeated .google.protobuf.ServiceDescriptorProto service = 6;
+inline int FileDescriptorProto::_internal_service_size() const {
+  return _impl_.service_.size();
+}
+inline int FileDescriptorProto::service_size() const {
+  return _internal_service_size();
+}
+inline void FileDescriptorProto::clear_service() {
+  _impl_.service_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.service)
+  return _impl_.service_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >*
+FileDescriptorProto::mutable_service() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service)
+  return &_impl_.service_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& FileDescriptorProto::_internal_service(int index) const {
+  return _impl_.service_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.service)
+  return _internal_service(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* FileDescriptorProto::_internal_add_service() {
+  return _impl_.service_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* FileDescriptorProto::add_service() {
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* _add = _internal_add_service();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >&
+FileDescriptorProto::service() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
+  return _impl_.service_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 7;
+inline int FileDescriptorProto::_internal_extension_size() const {
+  return _impl_.extension_.size();
+}
+inline int FileDescriptorProto::extension_size() const {
+  return _internal_extension_size();
+}
+inline void FileDescriptorProto::clear_extension() {
+  _impl_.extension_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.extension)
+  return _impl_.extension_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+FileDescriptorProto::mutable_extension() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension)
+  return &_impl_.extension_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& FileDescriptorProto::_internal_extension(int index) const {
+  return _impl_.extension_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.extension)
+  return _internal_extension(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* FileDescriptorProto::_internal_add_extension() {
+  return _impl_.extension_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* FileDescriptorProto::add_extension() {
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _add = _internal_add_extension();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+FileDescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
+  return _impl_.extension_;
+}
+
+// optional .google.protobuf.FileOptions options = 8;
+inline bool FileDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool FileDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void FileDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileOptions& FileDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::FileOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::FileOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_FileOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileOptions& FileDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.options)
+  return _internal_options();
+}
+inline void FileDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::FileOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
+  return _msg;
+}
+inline void FileDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::FileOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
+
+// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+inline bool FileDescriptorProto::_internal_has_source_code_info() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.source_code_info_ != nullptr);
+  return value;
+}
+inline bool FileDescriptorProto::has_source_code_info() const {
+  return _internal_has_source_code_info();
+}
+inline void FileDescriptorProto::clear_source_code_info() {
+  if (_impl_.source_code_info_ != nullptr) _impl_.source_code_info_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& FileDescriptorProto::_internal_source_code_info() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* p = _impl_.source_code_info_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& FileDescriptorProto::source_code_info() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.source_code_info)
+  return _internal_source_code_info();
+}
+inline void FileDescriptorProto::unsafe_arena_set_allocated_source_code_info(
+    ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_code_info_);
+  }
+  _impl_.source_code_info_ = source_code_info;
+  if (source_code_info) {
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* temp = _impl_.source_code_info_;
+  _impl_.source_code_info_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::unsafe_arena_release_source_code_info() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info)
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* temp = _impl_.source_code_info_;
+  _impl_.source_code_info_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::_internal_mutable_source_code_info() {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  if (_impl_.source_code_info_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceCodeInfo>(GetArenaForAllocation());
+    _impl_.source_code_info_ = p;
+  }
+  return _impl_.source_code_info_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() {
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* _msg = _internal_mutable_source_code_info();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
+  return _msg;
+}
+inline void FileDescriptorProto::set_allocated_source_code_info(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.source_code_info_;
+  }
+  if (source_code_info) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(source_code_info);
+    if (message_arena != submessage_arena) {
+      source_code_info = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_code_info, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  _impl_.source_code_info_ = source_code_info;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
+}
+
+// optional string syntax = 12;
+inline bool FileDescriptorProto::_internal_has_syntax() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FileDescriptorProto::has_syntax() const {
+  return _internal_has_syntax();
+}
+inline void FileDescriptorProto::clear_syntax() {
+  _impl_.syntax_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& FileDescriptorProto::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax)
+  return _internal_syntax();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileDescriptorProto::set_syntax(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.syntax_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax)
+}
+inline std::string* FileDescriptorProto::mutable_syntax() {
+  std::string* _s = _internal_mutable_syntax();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.syntax)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_syntax() const {
+  return _impl_.syntax_.Get();
+}
+inline void FileDescriptorProto::_internal_set_syntax(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.syntax_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::_internal_mutable_syntax() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.syntax_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::release_syntax() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax)
+  if (!_internal_has_syntax()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.syntax_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.syntax_.IsDefault()) {
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileDescriptorProto::set_allocated_syntax(std::string* syntax) {
+  if (syntax != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.syntax_.SetAllocated(syntax, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.syntax_.IsDefault()) {
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto_ExtensionRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ExtensionRange::_internal_has_start() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ExtensionRange::has_start() const {
+  return _internal_has_start();
+}
+inline void DescriptorProto_ExtensionRange::clear_start() {
+  _impl_.start_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t DescriptorProto_ExtensionRange::_internal_start() const {
+  return _impl_.start_;
+}
+inline int32_t DescriptorProto_ExtensionRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.start)
+  return _internal_start();
+}
+inline void DescriptorProto_ExtensionRange::_internal_set_start(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.start_ = value;
+}
+inline void DescriptorProto_ExtensionRange::set_start(int32_t value) {
+  _internal_set_start(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.start)
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ExtensionRange::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ExtensionRange::has_end() const {
+  return _internal_has_end();
+}
+inline void DescriptorProto_ExtensionRange::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t DescriptorProto_ExtensionRange::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t DescriptorProto_ExtensionRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.end)
+  return _internal_end();
+}
+inline void DescriptorProto_ExtensionRange::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.end_ = value;
+}
+inline void DescriptorProto_ExtensionRange::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.end)
+}
+
+// optional .google.protobuf.ExtensionRangeOptions options = 3;
+inline bool DescriptorProto_ExtensionRange::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool DescriptorProto_ExtensionRange::has_options() const {
+  return _internal_has_options();
+}
+inline void DescriptorProto_ExtensionRange::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& DescriptorProto_ExtensionRange::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_ExtensionRangeOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& DescriptorProto_ExtensionRange::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.options)
+  return _internal_options();
+}
+inline void DescriptorProto_ExtensionRange::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.DescriptorProto.ExtensionRange.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.ExtensionRange.options)
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.ExtensionRange.options)
+  return _msg;
+}
+inline void DescriptorProto_ExtensionRange::set_allocated_options(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.ExtensionRange.options)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto_ReservedRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ReservedRange::_internal_has_start() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ReservedRange::has_start() const {
+  return _internal_has_start();
+}
+inline void DescriptorProto_ReservedRange::clear_start() {
+  _impl_.start_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline int32_t DescriptorProto_ReservedRange::_internal_start() const {
+  return _impl_.start_;
+}
+inline int32_t DescriptorProto_ReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start)
+  return _internal_start();
+}
+inline void DescriptorProto_ReservedRange::_internal_set_start(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.start_ = value;
+}
+inline void DescriptorProto_ReservedRange::set_start(int32_t value) {
+  _internal_set_start(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start)
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ReservedRange::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ReservedRange::has_end() const {
+  return _internal_has_end();
+}
+inline void DescriptorProto_ReservedRange::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t DescriptorProto_ReservedRange::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t DescriptorProto_ReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end)
+  return _internal_end();
+}
+inline void DescriptorProto_ReservedRange::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.end_ = value;
+}
+inline void DescriptorProto_ReservedRange::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto
+
+// optional string name = 1;
+inline bool DescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool DescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void DescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& DescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void DescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.name)
+}
+inline std::string* DescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name)
+  return _s;
+}
+inline const std::string& DescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void DescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* DescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* DescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void DescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.name)
+}
+
+// repeated .google.protobuf.FieldDescriptorProto field = 2;
+inline int DescriptorProto::_internal_field_size() const {
+  return _impl_.field_.size();
+}
+inline int DescriptorProto::field_size() const {
+  return _internal_field_size();
+}
+inline void DescriptorProto::clear_field() {
+  _impl_.field_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::mutable_field(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.field)
+  return _impl_.field_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+DescriptorProto::mutable_field() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field)
+  return &_impl_.field_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::_internal_field(int index) const {
+  return _impl_.field_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::field(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.field)
+  return _internal_field(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::_internal_add_field() {
+  return _impl_.field_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::add_field() {
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _add = _internal_add_field();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+DescriptorProto::field() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
+  return _impl_.field_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 6;
+inline int DescriptorProto::_internal_extension_size() const {
+  return _impl_.extension_.size();
+}
+inline int DescriptorProto::extension_size() const {
+  return _internal_extension_size();
+}
+inline void DescriptorProto::clear_extension() {
+  _impl_.extension_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension)
+  return _impl_.extension_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+DescriptorProto::mutable_extension() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension)
+  return &_impl_.extension_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::_internal_extension(int index) const {
+  return _impl_.extension_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension)
+  return _internal_extension(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::_internal_add_extension() {
+  return _impl_.extension_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::add_extension() {
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _add = _internal_add_extension();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+DescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
+  return _impl_.extension_;
+}
+
+// repeated .google.protobuf.DescriptorProto nested_type = 3;
+inline int DescriptorProto::_internal_nested_type_size() const {
+  return _impl_.nested_type_.size();
+}
+inline int DescriptorProto::nested_type_size() const {
+  return _internal_nested_type_size();
+}
+inline void DescriptorProto::clear_nested_type() {
+  _impl_.nested_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* DescriptorProto::mutable_nested_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.nested_type)
+  return _impl_.nested_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+DescriptorProto::mutable_nested_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type)
+  return &_impl_.nested_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& DescriptorProto::_internal_nested_type(int index) const {
+  return _impl_.nested_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& DescriptorProto::nested_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.nested_type)
+  return _internal_nested_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* DescriptorProto::_internal_add_nested_type() {
+  return _impl_.nested_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* DescriptorProto::add_nested_type() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _add = _internal_add_nested_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+DescriptorProto::nested_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
+  return _impl_.nested_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+inline int DescriptorProto::_internal_enum_type_size() const {
+  return _impl_.enum_type_.size();
+}
+inline int DescriptorProto::enum_type_size() const {
+  return _internal_enum_type_size();
+}
+inline void DescriptorProto::clear_enum_type() {
+  _impl_.enum_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.enum_type)
+  return _impl_.enum_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+DescriptorProto::mutable_enum_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type)
+  return &_impl_.enum_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& DescriptorProto::_internal_enum_type(int index) const {
+  return _impl_.enum_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.enum_type)
+  return _internal_enum_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* DescriptorProto::_internal_add_enum_type() {
+  return _impl_.enum_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* DescriptorProto::add_enum_type() {
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _add = _internal_add_enum_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+DescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
+  return _impl_.enum_type_;
+}
+
+// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+inline int DescriptorProto::_internal_extension_range_size() const {
+  return _impl_.extension_range_.size();
+}
+inline int DescriptorProto::extension_range_size() const {
+  return _internal_extension_range_size();
+}
+inline void DescriptorProto::clear_extension_range() {
+  _impl_.extension_range_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension_range)
+  return _impl_.extension_range_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >*
+DescriptorProto::mutable_extension_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range)
+  return &_impl_.extension_range_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& DescriptorProto::_internal_extension_range(int index) const {
+  return _impl_.extension_range_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension_range)
+  return _internal_extension_range(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* DescriptorProto::_internal_add_extension_range() {
+  return _impl_.extension_range_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* _add = _internal_add_extension_range();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >&
+DescriptorProto::extension_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
+  return _impl_.extension_range_;
+}
+
+// repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+inline int DescriptorProto::_internal_oneof_decl_size() const {
+  return _impl_.oneof_decl_.size();
+}
+inline int DescriptorProto::oneof_decl_size() const {
+  return _internal_oneof_decl_size();
+}
+inline void DescriptorProto::clear_oneof_decl() {
+  _impl_.oneof_decl_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.oneof_decl)
+  return _impl_.oneof_decl_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >*
+DescriptorProto::mutable_oneof_decl() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl)
+  return &_impl_.oneof_decl_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& DescriptorProto::_internal_oneof_decl(int index) const {
+  return _impl_.oneof_decl_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.oneof_decl)
+  return _internal_oneof_decl(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* DescriptorProto::_internal_add_oneof_decl() {
+  return _impl_.oneof_decl_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* DescriptorProto::add_oneof_decl() {
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* _add = _internal_add_oneof_decl();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >&
+DescriptorProto::oneof_decl() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
+  return _impl_.oneof_decl_;
+}
+
+// optional .google.protobuf.MessageOptions options = 7;
+inline bool DescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool DescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void DescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MessageOptions& DescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::MessageOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::MessageOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_MessageOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MessageOptions& DescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.options)
+  return _internal_options();
+}
+inline void DescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::MessageOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.DescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MessageOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
+  return _msg;
+}
+inline void DescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::MessageOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
+}
+
+// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+inline int DescriptorProto::_internal_reserved_range_size() const {
+  return _impl_.reserved_range_.size();
+}
+inline int DescriptorProto::reserved_range_size() const {
+  return _internal_reserved_range_size();
+}
+inline void DescriptorProto::clear_reserved_range() {
+  _impl_.reserved_range_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range)
+  return _impl_.reserved_range_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >*
+DescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range)
+  return &_impl_.reserved_range_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& DescriptorProto::_internal_reserved_range(int index) const {
+  return _impl_.reserved_range_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range)
+  return _internal_reserved_range(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* DescriptorProto::_internal_add_reserved_range() {
+  return _impl_.reserved_range_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* _add = _internal_add_reserved_range();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >&
+DescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range)
+  return _impl_.reserved_range_;
+}
+
+// repeated string reserved_name = 10;
+inline int DescriptorProto::_internal_reserved_name_size() const {
+  return _impl_.reserved_name_.size();
+}
+inline int DescriptorProto::reserved_name_size() const {
+  return _internal_reserved_name_size();
+}
+inline void DescriptorProto::clear_reserved_name() {
+  _impl_.reserved_name_.Clear();
+}
+inline std::string* DescriptorProto::add_reserved_name() {
+  std::string* _s = _internal_add_reserved_name();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return _s;
+}
+inline const std::string& DescriptorProto::_internal_reserved_name(int index) const {
+  return _impl_.reserved_name_.Get(index);
+}
+inline const std::string& DescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name)
+  return _internal_reserved_name(index);
+}
+inline std::string* DescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return _impl_.reserved_name_.Mutable(index);
+}
+inline void DescriptorProto::set_reserved_name(int index, const std::string& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, std::string&& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.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) {
+  _impl_.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::_internal_add_reserved_name() {
+  return _impl_.reserved_name_.Add();
+}
+inline void DescriptorProto::add_reserved_name(const std::string& value) {
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(std::string&& value) {
+  _impl_.reserved_name_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.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) {
+  _impl_.reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+DescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name)
+  return _impl_.reserved_name_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+DescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name)
+  return &_impl_.reserved_name_;
+}
+
+// -------------------------------------------------------------------
+
+// ExtensionRangeOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int ExtensionRangeOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int ExtensionRangeOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void ExtensionRangeOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ExtensionRangeOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+ExtensionRangeOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ExtensionRangeOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ExtensionRangeOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ExtensionRangeOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ExtensionRangeOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+ExtensionRangeOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// FieldDescriptorProto
+
+// optional string name = 1;
+inline bool FieldDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void FieldDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& FieldDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.name)
+}
+inline std::string* FieldDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.name)
+}
+
+// optional int32 number = 3;
+inline bool FieldDescriptorProto::_internal_has_number() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000040u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_number() const {
+  return _internal_has_number();
+}
+inline void FieldDescriptorProto::clear_number() {
+  _impl_.number_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000040u;
+}
+inline int32_t FieldDescriptorProto::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t FieldDescriptorProto::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.number)
+  return _internal_number();
+}
+inline void FieldDescriptorProto::_internal_set_number(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  _impl_.number_ = value;
+}
+inline void FieldDescriptorProto::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.number)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+inline bool FieldDescriptorProto::_internal_has_label() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000200u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_label() const {
+  return _internal_has_label();
+}
+inline void FieldDescriptorProto::clear_label() {
+  _impl_.label_ = 1;
+  _impl_._has_bits_[0] &= ~0x00000200u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label FieldDescriptorProto::_internal_label() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label >(_impl_.label_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label FieldDescriptorProto::label() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.label)
+  return _internal_label();
+}
+inline void FieldDescriptorProto::_internal_set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000200u;
+  _impl_.label_ = value;
+}
+inline void FieldDescriptorProto::set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value) {
+  _internal_set_label(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.label)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+inline bool FieldDescriptorProto::_internal_has_type() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000400u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_type() const {
+  return _internal_has_type();
+}
+inline void FieldDescriptorProto::clear_type() {
+  _impl_.type_ = 1;
+  _impl_._has_bits_[0] &= ~0x00000400u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type FieldDescriptorProto::_internal_type() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type >(_impl_.type_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type FieldDescriptorProto::type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type)
+  return _internal_type();
+}
+inline void FieldDescriptorProto::_internal_set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000400u;
+  _impl_.type_ = value;
+}
+inline void FieldDescriptorProto::set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value) {
+  _internal_set_type(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type)
+}
+
+// optional string type_name = 6;
+inline bool FieldDescriptorProto::_internal_has_type_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_type_name() const {
+  return _internal_has_type_name();
+}
+inline void FieldDescriptorProto::clear_type_name() {
+  _impl_.type_name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& FieldDescriptorProto::type_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name)
+  return _internal_type_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_type_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.type_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type_name)
+}
+inline std::string* FieldDescriptorProto::mutable_type_name() {
+  std::string* _s = _internal_mutable_type_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_type_name() const {
+  return _impl_.type_name_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_type_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.type_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_type_name() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.type_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_type_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name)
+  if (!_internal_has_type_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.type_name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_name_.IsDefault()) {
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_type_name(std::string* type_name) {
+  if (type_name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.type_name_.SetAllocated(type_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_name_.IsDefault()) {
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name)
+}
+
+// optional string extendee = 2;
+inline bool FieldDescriptorProto::_internal_has_extendee() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_extendee() const {
+  return _internal_has_extendee();
+}
+inline void FieldDescriptorProto::clear_extendee() {
+  _impl_.extendee_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& FieldDescriptorProto::extendee() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee)
+  return _internal_extendee();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_extendee(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.extendee_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.extendee)
+}
+inline std::string* FieldDescriptorProto::mutable_extendee() {
+  std::string* _s = _internal_mutable_extendee();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_extendee() const {
+  return _impl_.extendee_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_extendee(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.extendee_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_extendee() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.extendee_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_extendee() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee)
+  if (!_internal_has_extendee()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.extendee_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.extendee_.IsDefault()) {
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_extendee(std::string* extendee) {
+  if (extendee != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.extendee_.SetAllocated(extendee, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.extendee_.IsDefault()) {
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee)
+}
+
+// optional string default_value = 7;
+inline bool FieldDescriptorProto::_internal_has_default_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_default_value() const {
+  return _internal_has_default_value();
+}
+inline void FieldDescriptorProto::clear_default_value() {
+  _impl_.default_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const std::string& FieldDescriptorProto::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value)
+  return _internal_default_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_default_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000008u;
+ _impl_.default_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.default_value)
+}
+inline std::string* FieldDescriptorProto::mutable_default_value() {
+  std::string* _s = _internal_mutable_default_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_default_value() const {
+  return _impl_.default_value_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_default_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.default_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_default_value() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  return _impl_.default_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value)
+  if (!_internal_has_default_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  auto* p = _impl_.default_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.default_value_.IsDefault()) {
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_default_value(std::string* default_value) {
+  if (default_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.default_value_.SetAllocated(default_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.default_value_.IsDefault()) {
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value)
+}
+
+// optional int32 oneof_index = 9;
+inline bool FieldDescriptorProto::_internal_has_oneof_index() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000080u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_oneof_index() const {
+  return _internal_has_oneof_index();
+}
+inline void FieldDescriptorProto::clear_oneof_index() {
+  _impl_.oneof_index_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000080u;
+}
+inline int32_t FieldDescriptorProto::_internal_oneof_index() const {
+  return _impl_.oneof_index_;
+}
+inline int32_t FieldDescriptorProto::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.oneof_index)
+  return _internal_oneof_index();
+}
+inline void FieldDescriptorProto::_internal_set_oneof_index(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000080u;
+  _impl_.oneof_index_ = value;
+}
+inline void FieldDescriptorProto::set_oneof_index(int32_t value) {
+  _internal_set_oneof_index(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
+}
+
+// optional string json_name = 10;
+inline bool FieldDescriptorProto::_internal_has_json_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_json_name() const {
+  return _internal_has_json_name();
+}
+inline void FieldDescriptorProto::clear_json_name() {
+  _impl_.json_name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline const std::string& FieldDescriptorProto::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
+  return _internal_json_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_json_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000010u;
+ _impl_.json_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline std::string* FieldDescriptorProto::mutable_json_name() {
+  std::string* _s = _internal_mutable_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_json_name() const {
+  return _impl_.json_name_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_json_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.json_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_json_name() {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  return _impl_.json_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name)
+  if (!_internal_has_json_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  auto* p = _impl_.json_name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.json_name_.IsDefault()) {
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_json_name(std::string* json_name) {
+  if (json_name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  _impl_.json_name_.SetAllocated(json_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.json_name_.IsDefault()) {
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+inline bool FieldDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool FieldDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void FieldDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldOptions& FieldDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::FieldOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::FieldOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_FieldOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldOptions& FieldDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.options)
+  return _internal_options();
+}
+inline void FieldDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::FieldOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000020u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000020u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000020u;
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000020u;
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
+  return _msg;
+}
+inline void FieldDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::FieldOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000020u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000020u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+
+// optional bool proto3_optional = 17;
+inline bool FieldDescriptorProto::_internal_has_proto3_optional() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000100u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_proto3_optional() const {
+  return _internal_has_proto3_optional();
+}
+inline void FieldDescriptorProto::clear_proto3_optional() {
+  _impl_.proto3_optional_ = false;
+  _impl_._has_bits_[0] &= ~0x00000100u;
+}
+inline bool FieldDescriptorProto::_internal_proto3_optional() const {
+  return _impl_.proto3_optional_;
+}
+inline bool FieldDescriptorProto::proto3_optional() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.proto3_optional)
+  return _internal_proto3_optional();
+}
+inline void FieldDescriptorProto::_internal_set_proto3_optional(bool value) {
+  _impl_._has_bits_[0] |= 0x00000100u;
+  _impl_.proto3_optional_ = value;
+}
+inline void FieldDescriptorProto::set_proto3_optional(bool value) {
+  _internal_set_proto3_optional(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.proto3_optional)
+}
+
+// -------------------------------------------------------------------
+
+// OneofDescriptorProto
+
+// optional string name = 1;
+inline bool OneofDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool OneofDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void OneofDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& OneofDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void OneofDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.OneofDescriptorProto.name)
+}
+inline std::string* OneofDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name)
+  return _s;
+}
+inline const std::string& OneofDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void OneofDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* OneofDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* OneofDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void OneofDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
+}
+
+// optional .google.protobuf.OneofOptions options = 2;
+inline bool OneofDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool OneofDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void OneofDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofOptions& OneofDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::OneofOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::OneofOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_OneofOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofOptions& OneofDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.options)
+  return _internal_options();
+}
+inline void OneofDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::OneofOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::OneofOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.options)
+  return _msg;
+}
+inline void OneofDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::OneofOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// EnumDescriptorProto_EnumReservedRange
+
+// optional int32 start = 1;
+inline bool EnumDescriptorProto_EnumReservedRange::_internal_has_start() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumDescriptorProto_EnumReservedRange::has_start() const {
+  return _internal_has_start();
+}
+inline void EnumDescriptorProto_EnumReservedRange::clear_start() {
+  _impl_.start_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::_internal_start() const {
+  return _impl_.start_;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.EnumReservedRange.start)
+  return _internal_start();
+}
+inline void EnumDescriptorProto_EnumReservedRange::_internal_set_start(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.start_ = value;
+}
+inline void EnumDescriptorProto_EnumReservedRange::set_start(int32_t value) {
+  _internal_set_start(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.EnumReservedRange.start)
+}
+
+// optional int32 end = 2;
+inline bool EnumDescriptorProto_EnumReservedRange::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool EnumDescriptorProto_EnumReservedRange::has_end() const {
+  return _internal_has_end();
+}
+inline void EnumDescriptorProto_EnumReservedRange::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.EnumReservedRange.end)
+  return _internal_end();
+}
+inline void EnumDescriptorProto_EnumReservedRange::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.end_ = value;
+}
+inline void EnumDescriptorProto_EnumReservedRange::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.EnumReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// EnumDescriptorProto
+
+// optional string name = 1;
+inline bool EnumDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void EnumDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& EnumDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void EnumDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.name)
+}
+inline std::string* EnumDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name)
+  return _s;
+}
+inline const std::string& EnumDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void EnumDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* EnumDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* EnumDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void EnumDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.name)
+}
+
+// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+inline int EnumDescriptorProto::_internal_value_size() const {
+  return _impl_.value_.size();
+}
+inline int EnumDescriptorProto::value_size() const {
+  return _internal_value_size();
+}
+inline void EnumDescriptorProto::clear_value() {
+  _impl_.value_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.value)
+  return _impl_.value_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >*
+EnumDescriptorProto::mutable_value() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value)
+  return &_impl_.value_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& EnumDescriptorProto::_internal_value(int index) const {
+  return _impl_.value_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.value)
+  return _internal_value(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* EnumDescriptorProto::_internal_add_value() {
+  return _impl_.value_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* _add = _internal_add_value();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >&
+EnumDescriptorProto::value() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
+  return _impl_.value_;
+}
+
+// optional .google.protobuf.EnumOptions options = 3;
+inline bool EnumDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool EnumDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void EnumDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumOptions& EnumDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::EnumOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::EnumOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_EnumOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumOptions& EnumDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.options)
+  return _internal_options();
+}
+inline void EnumDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::EnumOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
+  return _msg;
+}
+inline void EnumDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
+
+// repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+inline int EnumDescriptorProto::_internal_reserved_range_size() const {
+  return _impl_.reserved_range_.size();
+}
+inline int EnumDescriptorProto::reserved_range_size() const {
+  return _internal_reserved_range_size();
+}
+inline void EnumDescriptorProto::clear_reserved_range() {
+  _impl_.reserved_range_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* EnumDescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _impl_.reserved_range_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >*
+EnumDescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.reserved_range)
+  return &_impl_.reserved_range_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& EnumDescriptorProto::_internal_reserved_range(int index) const {
+  return _impl_.reserved_range_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& EnumDescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _internal_reserved_range(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* EnumDescriptorProto::_internal_add_reserved_range() {
+  return _impl_.reserved_range_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* EnumDescriptorProto::add_reserved_range() {
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* _add = _internal_add_reserved_range();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >&
+EnumDescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _impl_.reserved_range_;
+}
+
+// repeated string reserved_name = 5;
+inline int EnumDescriptorProto::_internal_reserved_name_size() const {
+  return _impl_.reserved_name_.size();
+}
+inline int EnumDescriptorProto::reserved_name_size() const {
+  return _internal_reserved_name_size();
+}
+inline void EnumDescriptorProto::clear_reserved_name() {
+  _impl_.reserved_name_.Clear();
+}
+inline std::string* EnumDescriptorProto::add_reserved_name() {
+  std::string* _s = _internal_add_reserved_name();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _s;
+}
+inline const std::string& EnumDescriptorProto::_internal_reserved_name(int index) const {
+  return _impl_.reserved_name_.Get(index);
+}
+inline const std::string& EnumDescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _internal_reserved_name(index);
+}
+inline std::string* EnumDescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _impl_.reserved_name_.Mutable(index);
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, const std::string& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, std::string&& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  _impl_.reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline std::string* EnumDescriptorProto::_internal_add_reserved_name() {
+  return _impl_.reserved_name_.Add();
+}
+inline void EnumDescriptorProto::add_reserved_name(const std::string& value) {
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::add_reserved_name(std::string&& value) {
+  _impl_.reserved_name_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::add_reserved_name(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::add_reserved_name(const char* value, size_t size) {
+  _impl_.reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+EnumDescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _impl_.reserved_name_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+EnumDescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.reserved_name)
+  return &_impl_.reserved_name_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumValueDescriptorProto
+
+// optional string name = 1;
+inline bool EnumValueDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumValueDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void EnumValueDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& EnumValueDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void EnumValueDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.name)
+}
+inline std::string* EnumValueDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name)
+  return _s;
+}
+inline const std::string& EnumValueDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void EnumValueDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* EnumValueDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* EnumValueDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void EnumValueDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.name)
+}
+
+// optional int32 number = 2;
+inline bool EnumValueDescriptorProto::_internal_has_number() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool EnumValueDescriptorProto::has_number() const {
+  return _internal_has_number();
+}
+inline void EnumValueDescriptorProto::clear_number() {
+  _impl_.number_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t EnumValueDescriptorProto::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t EnumValueDescriptorProto::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.number)
+  return _internal_number();
+}
+inline void EnumValueDescriptorProto::_internal_set_number(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.number_ = value;
+}
+inline void EnumValueDescriptorProto::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.number)
+}
+
+// optional .google.protobuf.EnumValueOptions options = 3;
+inline bool EnumValueDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool EnumValueDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void EnumValueDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& EnumValueDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_EnumValueOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& EnumValueDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.options)
+  return _internal_options();
+}
+inline void EnumValueDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValueOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
+  return _msg;
+}
+inline void EnumValueDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// ServiceDescriptorProto
+
+// optional string name = 1;
+inline bool ServiceDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool ServiceDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void ServiceDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& ServiceDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void ServiceDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.ServiceDescriptorProto.name)
+}
+inline std::string* ServiceDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name)
+  return _s;
+}
+inline const std::string& ServiceDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void ServiceDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* ServiceDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* ServiceDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void ServiceDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.name)
+}
+
+// repeated .google.protobuf.MethodDescriptorProto method = 2;
+inline int ServiceDescriptorProto::_internal_method_size() const {
+  return _impl_.method_.size();
+}
+inline int ServiceDescriptorProto::method_size() const {
+  return _internal_method_size();
+}
+inline void ServiceDescriptorProto::clear_method() {
+  _impl_.method_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.method)
+  return _impl_.method_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >*
+ServiceDescriptorProto::mutable_method() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method)
+  return &_impl_.method_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& ServiceDescriptorProto::_internal_method(int index) const {
+  return _impl_.method_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.method)
+  return _internal_method(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* ServiceDescriptorProto::_internal_add_method() {
+  return _impl_.method_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* _add = _internal_add_method();
+  // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >&
+ServiceDescriptorProto::method() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
+  return _impl_.method_;
+}
+
+// optional .google.protobuf.ServiceOptions options = 3;
+inline bool ServiceDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool ServiceDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void ServiceDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& ServiceDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::ServiceOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::ServiceOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_ServiceOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& ServiceDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.options)
+  return _internal_options();
+}
+inline void ServiceDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::ServiceOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ServiceOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
+  return _msg;
+}
+inline void ServiceDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::ServiceOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// MethodDescriptorProto
+
+// optional string name = 1;
+inline bool MethodDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void MethodDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& MethodDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void MethodDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.name)
+}
+inline std::string* MethodDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name)
+  return _s;
+}
+inline const std::string& MethodDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void MethodDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void MethodDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.name)
+}
+
+// optional string input_type = 2;
+inline bool MethodDescriptorProto::_internal_has_input_type() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_input_type() const {
+  return _internal_has_input_type();
+}
+inline void MethodDescriptorProto::clear_input_type() {
+  _impl_.input_type_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& MethodDescriptorProto::input_type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type)
+  return _internal_input_type();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void MethodDescriptorProto::set_input_type(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.input_type_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.input_type)
+}
+inline std::string* MethodDescriptorProto::mutable_input_type() {
+  std::string* _s = _internal_mutable_input_type();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type)
+  return _s;
+}
+inline const std::string& MethodDescriptorProto::_internal_input_type() const {
+  return _impl_.input_type_.Get();
+}
+inline void MethodDescriptorProto::_internal_set_input_type(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.input_type_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::_internal_mutable_input_type() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.input_type_.Mutable(GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::release_input_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type)
+  if (!_internal_has_input_type()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.input_type_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.input_type_.IsDefault()) {
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void MethodDescriptorProto::set_allocated_input_type(std::string* input_type) {
+  if (input_type != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.input_type_.SetAllocated(input_type, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.input_type_.IsDefault()) {
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type)
+}
+
+// optional string output_type = 3;
+inline bool MethodDescriptorProto::_internal_has_output_type() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_output_type() const {
+  return _internal_has_output_type();
+}
+inline void MethodDescriptorProto::clear_output_type() {
+  _impl_.output_type_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& MethodDescriptorProto::output_type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type)
+  return _internal_output_type();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void MethodDescriptorProto::set_output_type(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.output_type_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.output_type)
+}
+inline std::string* MethodDescriptorProto::mutable_output_type() {
+  std::string* _s = _internal_mutable_output_type();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type)
+  return _s;
+}
+inline const std::string& MethodDescriptorProto::_internal_output_type() const {
+  return _impl_.output_type_.Get();
+}
+inline void MethodDescriptorProto::_internal_set_output_type(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.output_type_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::_internal_mutable_output_type() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.output_type_.Mutable(GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::release_output_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type)
+  if (!_internal_has_output_type()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.output_type_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.output_type_.IsDefault()) {
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void MethodDescriptorProto::set_allocated_output_type(std::string* output_type) {
+  if (output_type != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.output_type_.SetAllocated(output_type, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.output_type_.IsDefault()) {
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type)
+}
+
+// optional .google.protobuf.MethodOptions options = 4;
+inline bool MethodDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool MethodDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void MethodDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodOptions& MethodDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::MethodOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::MethodOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_MethodOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodOptions& MethodDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.options)
+  return _internal_options();
+}
+inline void MethodDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::MethodOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MethodOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
+  return _msg;
+}
+inline void MethodDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::MethodOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+
+// optional bool client_streaming = 5 [default = false];
+inline bool MethodDescriptorProto::_internal_has_client_streaming() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_client_streaming() const {
+  return _internal_has_client_streaming();
+}
+inline void MethodDescriptorProto::clear_client_streaming() {
+  _impl_.client_streaming_ = false;
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline bool MethodDescriptorProto::_internal_client_streaming() const {
+  return _impl_.client_streaming_;
+}
+inline bool MethodDescriptorProto::client_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming)
+  return _internal_client_streaming();
+}
+inline void MethodDescriptorProto::_internal_set_client_streaming(bool value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.client_streaming_ = value;
+}
+inline void MethodDescriptorProto::set_client_streaming(bool value) {
+  _internal_set_client_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming)
+}
+
+// optional bool server_streaming = 6 [default = false];
+inline bool MethodDescriptorProto::_internal_has_server_streaming() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_server_streaming() const {
+  return _internal_has_server_streaming();
+}
+inline void MethodDescriptorProto::clear_server_streaming() {
+  _impl_.server_streaming_ = false;
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline bool MethodDescriptorProto::_internal_server_streaming() const {
+  return _impl_.server_streaming_;
+}
+inline bool MethodDescriptorProto::server_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming)
+  return _internal_server_streaming();
+}
+inline void MethodDescriptorProto::_internal_set_server_streaming(bool value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.server_streaming_ = value;
+}
+inline void MethodDescriptorProto::set_server_streaming(bool value) {
+  _internal_set_server_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming)
+}
+
+// -------------------------------------------------------------------
+
+// FileOptions
+
+// optional string java_package = 1;
+inline bool FileOptions::_internal_has_java_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_package() const {
+  return _internal_has_java_package();
+}
+inline void FileOptions::clear_java_package() {
+  _impl_.java_package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& FileOptions::java_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package)
+  return _internal_java_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_java_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.java_package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_package)
+}
+inline std::string* FileOptions::mutable_java_package() {
+  std::string* _s = _internal_mutable_java_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_java_package() const {
+  return _impl_.java_package_.Get();
+}
+inline void FileOptions::_internal_set_java_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.java_package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_java_package() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.java_package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_java_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package)
+  if (!_internal_has_java_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.java_package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_package_.IsDefault()) {
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_java_package(std::string* java_package) {
+  if (java_package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.java_package_.SetAllocated(java_package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_package_.IsDefault()) {
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package)
+}
+
+// optional string java_outer_classname = 8;
+inline bool FileOptions::_internal_has_java_outer_classname() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_outer_classname() const {
+  return _internal_has_java_outer_classname();
+}
+inline void FileOptions::clear_java_outer_classname() {
+  _impl_.java_outer_classname_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& FileOptions::java_outer_classname() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname)
+  return _internal_java_outer_classname();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_java_outer_classname(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.java_outer_classname_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_outer_classname)
+}
+inline std::string* FileOptions::mutable_java_outer_classname() {
+  std::string* _s = _internal_mutable_java_outer_classname();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_java_outer_classname() const {
+  return _impl_.java_outer_classname_.Get();
+}
+inline void FileOptions::_internal_set_java_outer_classname(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.java_outer_classname_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_java_outer_classname() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.java_outer_classname_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_java_outer_classname() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname)
+  if (!_internal_has_java_outer_classname()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.java_outer_classname_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_outer_classname_.IsDefault()) {
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_java_outer_classname(std::string* java_outer_classname) {
+  if (java_outer_classname != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.java_outer_classname_.SetAllocated(java_outer_classname, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_outer_classname_.IsDefault()) {
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname)
+}
+
+// optional bool java_multiple_files = 10 [default = false];
+inline bool FileOptions::_internal_has_java_multiple_files() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000400u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_multiple_files() const {
+  return _internal_has_java_multiple_files();
+}
+inline void FileOptions::clear_java_multiple_files() {
+  _impl_.java_multiple_files_ = false;
+  _impl_._has_bits_[0] &= ~0x00000400u;
+}
+inline bool FileOptions::_internal_java_multiple_files() const {
+  return _impl_.java_multiple_files_;
+}
+inline bool FileOptions::java_multiple_files() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_multiple_files)
+  return _internal_java_multiple_files();
+}
+inline void FileOptions::_internal_set_java_multiple_files(bool value) {
+  _impl_._has_bits_[0] |= 0x00000400u;
+  _impl_.java_multiple_files_ = value;
+}
+inline void FileOptions::set_java_multiple_files(bool value) {
+  _internal_set_java_multiple_files(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_multiple_files)
+}
+
+// optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+inline bool FileOptions::_internal_has_java_generate_equals_and_hash() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000800u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_generate_equals_and_hash() const {
+  return _internal_has_java_generate_equals_and_hash();
+}
+inline void FileOptions::clear_java_generate_equals_and_hash() {
+  _impl_.java_generate_equals_and_hash_ = false;
+  _impl_._has_bits_[0] &= ~0x00000800u;
+}
+inline bool FileOptions::_internal_java_generate_equals_and_hash() const {
+  return _impl_.java_generate_equals_and_hash_;
+}
+inline bool FileOptions::java_generate_equals_and_hash() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generate_equals_and_hash)
+  return _internal_java_generate_equals_and_hash();
+}
+inline void FileOptions::_internal_set_java_generate_equals_and_hash(bool value) {
+  _impl_._has_bits_[0] |= 0x00000800u;
+  _impl_.java_generate_equals_and_hash_ = value;
+}
+inline void FileOptions::set_java_generate_equals_and_hash(bool value) {
+  _internal_set_java_generate_equals_and_hash(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generate_equals_and_hash)
+}
+
+// optional bool java_string_check_utf8 = 27 [default = false];
+inline bool FileOptions::_internal_has_java_string_check_utf8() const {
+  bool value = (_impl_._has_bits_[0] & 0x00001000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_string_check_utf8() const {
+  return _internal_has_java_string_check_utf8();
+}
+inline void FileOptions::clear_java_string_check_utf8() {
+  _impl_.java_string_check_utf8_ = false;
+  _impl_._has_bits_[0] &= ~0x00001000u;
+}
+inline bool FileOptions::_internal_java_string_check_utf8() const {
+  return _impl_.java_string_check_utf8_;
+}
+inline bool FileOptions::java_string_check_utf8() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_string_check_utf8)
+  return _internal_java_string_check_utf8();
+}
+inline void FileOptions::_internal_set_java_string_check_utf8(bool value) {
+  _impl_._has_bits_[0] |= 0x00001000u;
+  _impl_.java_string_check_utf8_ = value;
+}
+inline void FileOptions::set_java_string_check_utf8(bool value) {
+  _internal_set_java_string_check_utf8(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_string_check_utf8)
+}
+
+// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+inline bool FileOptions::_internal_has_optimize_for() const {
+  bool value = (_impl_._has_bits_[0] & 0x00040000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_optimize_for() const {
+  return _internal_has_optimize_for();
+}
+inline void FileOptions::clear_optimize_for() {
+  _impl_.optimize_for_ = 1;
+  _impl_._has_bits_[0] &= ~0x00040000u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode FileOptions::_internal_optimize_for() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode >(_impl_.optimize_for_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode FileOptions::optimize_for() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.optimize_for)
+  return _internal_optimize_for();
+}
+inline void FileOptions::_internal_set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00040000u;
+  _impl_.optimize_for_ = value;
+}
+inline void FileOptions::set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value) {
+  _internal_set_optimize_for(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.optimize_for)
+}
+
+// optional string go_package = 11;
+inline bool FileOptions::_internal_has_go_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FileOptions::has_go_package() const {
+  return _internal_has_go_package();
+}
+inline void FileOptions::clear_go_package() {
+  _impl_.go_package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& FileOptions::go_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.go_package)
+  return _internal_go_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_go_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.go_package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package)
+}
+inline std::string* FileOptions::mutable_go_package() {
+  std::string* _s = _internal_mutable_go_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_go_package() const {
+  return _impl_.go_package_.Get();
+}
+inline void FileOptions::_internal_set_go_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.go_package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_go_package() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.go_package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_go_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package)
+  if (!_internal_has_go_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.go_package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.go_package_.IsDefault()) {
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_go_package(std::string* go_package) {
+  if (go_package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.go_package_.SetAllocated(go_package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.go_package_.IsDefault()) {
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package)
+}
+
+// optional bool cc_generic_services = 16 [default = false];
+inline bool FileOptions::_internal_has_cc_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00002000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_cc_generic_services() const {
+  return _internal_has_cc_generic_services();
+}
+inline void FileOptions::clear_cc_generic_services() {
+  _impl_.cc_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00002000u;
+}
+inline bool FileOptions::_internal_cc_generic_services() const {
+  return _impl_.cc_generic_services_;
+}
+inline bool FileOptions::cc_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_generic_services)
+  return _internal_cc_generic_services();
+}
+inline void FileOptions::_internal_set_cc_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00002000u;
+  _impl_.cc_generic_services_ = value;
+}
+inline void FileOptions::set_cc_generic_services(bool value) {
+  _internal_set_cc_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_generic_services)
+}
+
+// optional bool java_generic_services = 17 [default = false];
+inline bool FileOptions::_internal_has_java_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00004000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_generic_services() const {
+  return _internal_has_java_generic_services();
+}
+inline void FileOptions::clear_java_generic_services() {
+  _impl_.java_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00004000u;
+}
+inline bool FileOptions::_internal_java_generic_services() const {
+  return _impl_.java_generic_services_;
+}
+inline bool FileOptions::java_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generic_services)
+  return _internal_java_generic_services();
+}
+inline void FileOptions::_internal_set_java_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00004000u;
+  _impl_.java_generic_services_ = value;
+}
+inline void FileOptions::set_java_generic_services(bool value) {
+  _internal_set_java_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generic_services)
+}
+
+// optional bool py_generic_services = 18 [default = false];
+inline bool FileOptions::_internal_has_py_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00008000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_py_generic_services() const {
+  return _internal_has_py_generic_services();
+}
+inline void FileOptions::clear_py_generic_services() {
+  _impl_.py_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00008000u;
+}
+inline bool FileOptions::_internal_py_generic_services() const {
+  return _impl_.py_generic_services_;
+}
+inline bool FileOptions::py_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.py_generic_services)
+  return _internal_py_generic_services();
+}
+inline void FileOptions::_internal_set_py_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00008000u;
+  _impl_.py_generic_services_ = value;
+}
+inline void FileOptions::set_py_generic_services(bool value) {
+  _internal_set_py_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
+}
+
+// optional bool php_generic_services = 42 [default = false];
+inline bool FileOptions::_internal_has_php_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00010000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_generic_services() const {
+  return _internal_has_php_generic_services();
+}
+inline void FileOptions::clear_php_generic_services() {
+  _impl_.php_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00010000u;
+}
+inline bool FileOptions::_internal_php_generic_services() const {
+  return _impl_.php_generic_services_;
+}
+inline bool FileOptions::php_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_generic_services)
+  return _internal_php_generic_services();
+}
+inline void FileOptions::_internal_set_php_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00010000u;
+  _impl_.php_generic_services_ = value;
+}
+inline void FileOptions::set_php_generic_services(bool value) {
+  _internal_set_php_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_generic_services)
+}
+
+// optional bool deprecated = 23 [default = false];
+inline bool FileOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00020000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void FileOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00020000u;
+}
+inline bool FileOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool FileOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void FileOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00020000u;
+  _impl_.deprecated_ = value;
+}
+inline void FileOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.deprecated)
+}
+
+// optional bool cc_enable_arenas = 31 [default = true];
+inline bool FileOptions::_internal_has_cc_enable_arenas() const {
+  bool value = (_impl_._has_bits_[0] & 0x00080000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_cc_enable_arenas() const {
+  return _internal_has_cc_enable_arenas();
+}
+inline void FileOptions::clear_cc_enable_arenas() {
+  _impl_.cc_enable_arenas_ = true;
+  _impl_._has_bits_[0] &= ~0x00080000u;
+}
+inline bool FileOptions::_internal_cc_enable_arenas() const {
+  return _impl_.cc_enable_arenas_;
+}
+inline bool FileOptions::cc_enable_arenas() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_enable_arenas)
+  return _internal_cc_enable_arenas();
+}
+inline void FileOptions::_internal_set_cc_enable_arenas(bool value) {
+  _impl_._has_bits_[0] |= 0x00080000u;
+  _impl_.cc_enable_arenas_ = value;
+}
+inline void FileOptions::set_cc_enable_arenas(bool value) {
+  _internal_set_cc_enable_arenas(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_enable_arenas)
+}
+
+// optional string objc_class_prefix = 36;
+inline bool FileOptions::_internal_has_objc_class_prefix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool FileOptions::has_objc_class_prefix() const {
+  return _internal_has_objc_class_prefix();
+}
+inline void FileOptions::clear_objc_class_prefix() {
+  _impl_.objc_class_prefix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const std::string& FileOptions::objc_class_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.objc_class_prefix)
+  return _internal_objc_class_prefix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_objc_class_prefix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000008u;
+ _impl_.objc_class_prefix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline std::string* FileOptions::mutable_objc_class_prefix() {
+  std::string* _s = _internal_mutable_objc_class_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.objc_class_prefix)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_objc_class_prefix() const {
+  return _impl_.objc_class_prefix_.Get();
+}
+inline void FileOptions::_internal_set_objc_class_prefix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.objc_class_prefix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_objc_class_prefix() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  return _impl_.objc_class_prefix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_objc_class_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix)
+  if (!_internal_has_objc_class_prefix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  auto* p = _impl_.objc_class_prefix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.objc_class_prefix_.IsDefault()) {
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_objc_class_prefix(std::string* objc_class_prefix) {
+  if (objc_class_prefix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.objc_class_prefix_.SetAllocated(objc_class_prefix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.objc_class_prefix_.IsDefault()) {
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix)
+}
+
+// optional string csharp_namespace = 37;
+inline bool FileOptions::_internal_has_csharp_namespace() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FileOptions::has_csharp_namespace() const {
+  return _internal_has_csharp_namespace();
+}
+inline void FileOptions::clear_csharp_namespace() {
+  _impl_.csharp_namespace_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline const std::string& FileOptions::csharp_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.csharp_namespace)
+  return _internal_csharp_namespace();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_csharp_namespace(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000010u;
+ _impl_.csharp_namespace_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.csharp_namespace)
+}
+inline std::string* FileOptions::mutable_csharp_namespace() {
+  std::string* _s = _internal_mutable_csharp_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.csharp_namespace)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_csharp_namespace() const {
+  return _impl_.csharp_namespace_.Get();
+}
+inline void FileOptions::_internal_set_csharp_namespace(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.csharp_namespace_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_csharp_namespace() {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  return _impl_.csharp_namespace_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_csharp_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace)
+  if (!_internal_has_csharp_namespace()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  auto* p = _impl_.csharp_namespace_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.csharp_namespace_.IsDefault()) {
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_csharp_namespace(std::string* csharp_namespace) {
+  if (csharp_namespace != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  _impl_.csharp_namespace_.SetAllocated(csharp_namespace, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.csharp_namespace_.IsDefault()) {
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace)
+}
+
+// optional string swift_prefix = 39;
+inline bool FileOptions::_internal_has_swift_prefix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool FileOptions::has_swift_prefix() const {
+  return _internal_has_swift_prefix();
+}
+inline void FileOptions::clear_swift_prefix() {
+  _impl_.swift_prefix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline const std::string& FileOptions::swift_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.swift_prefix)
+  return _internal_swift_prefix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_swift_prefix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000020u;
+ _impl_.swift_prefix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.swift_prefix)
+}
+inline std::string* FileOptions::mutable_swift_prefix() {
+  std::string* _s = _internal_mutable_swift_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.swift_prefix)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_swift_prefix() const {
+  return _impl_.swift_prefix_.Get();
+}
+inline void FileOptions::_internal_set_swift_prefix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.swift_prefix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_swift_prefix() {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  return _impl_.swift_prefix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_swift_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.swift_prefix)
+  if (!_internal_has_swift_prefix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000020u;
+  auto* p = _impl_.swift_prefix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.swift_prefix_.IsDefault()) {
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_swift_prefix(std::string* swift_prefix) {
+  if (swift_prefix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000020u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000020u;
+  }
+  _impl_.swift_prefix_.SetAllocated(swift_prefix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.swift_prefix_.IsDefault()) {
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.swift_prefix)
+}
+
+// optional string php_class_prefix = 40;
+inline bool FileOptions::_internal_has_php_class_prefix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000040u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_class_prefix() const {
+  return _internal_has_php_class_prefix();
+}
+inline void FileOptions::clear_php_class_prefix() {
+  _impl_.php_class_prefix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000040u;
+}
+inline const std::string& FileOptions::php_class_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_class_prefix)
+  return _internal_php_class_prefix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_php_class_prefix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000040u;
+ _impl_.php_class_prefix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_class_prefix)
+}
+inline std::string* FileOptions::mutable_php_class_prefix() {
+  std::string* _s = _internal_mutable_php_class_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.php_class_prefix)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_php_class_prefix() const {
+  return _impl_.php_class_prefix_.Get();
+}
+inline void FileOptions::_internal_set_php_class_prefix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  _impl_.php_class_prefix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_php_class_prefix() {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  return _impl_.php_class_prefix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_php_class_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.php_class_prefix)
+  if (!_internal_has_php_class_prefix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000040u;
+  auto* p = _impl_.php_class_prefix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_class_prefix_.IsDefault()) {
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_php_class_prefix(std::string* php_class_prefix) {
+  if (php_class_prefix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000040u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000040u;
+  }
+  _impl_.php_class_prefix_.SetAllocated(php_class_prefix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_class_prefix_.IsDefault()) {
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.php_class_prefix)
+}
+
+// optional string php_namespace = 41;
+inline bool FileOptions::_internal_has_php_namespace() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000080u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_namespace() const {
+  return _internal_has_php_namespace();
+}
+inline void FileOptions::clear_php_namespace() {
+  _impl_.php_namespace_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000080u;
+}
+inline const std::string& FileOptions::php_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_namespace)
+  return _internal_php_namespace();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_php_namespace(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000080u;
+ _impl_.php_namespace_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_namespace)
+}
+inline std::string* FileOptions::mutable_php_namespace() {
+  std::string* _s = _internal_mutable_php_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.php_namespace)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_php_namespace() const {
+  return _impl_.php_namespace_.Get();
+}
+inline void FileOptions::_internal_set_php_namespace(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000080u;
+  _impl_.php_namespace_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_php_namespace() {
+  _impl_._has_bits_[0] |= 0x00000080u;
+  return _impl_.php_namespace_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_php_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.php_namespace)
+  if (!_internal_has_php_namespace()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000080u;
+  auto* p = _impl_.php_namespace_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_namespace_.IsDefault()) {
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_php_namespace(std::string* php_namespace) {
+  if (php_namespace != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000080u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000080u;
+  }
+  _impl_.php_namespace_.SetAllocated(php_namespace, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_namespace_.IsDefault()) {
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.php_namespace)
+}
+
+// optional string php_metadata_namespace = 44;
+inline bool FileOptions::_internal_has_php_metadata_namespace() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000100u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_metadata_namespace() const {
+  return _internal_has_php_metadata_namespace();
+}
+inline void FileOptions::clear_php_metadata_namespace() {
+  _impl_.php_metadata_namespace_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000100u;
+}
+inline const std::string& FileOptions::php_metadata_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_metadata_namespace)
+  return _internal_php_metadata_namespace();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_php_metadata_namespace(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000100u;
+ _impl_.php_metadata_namespace_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_metadata_namespace)
+}
+inline std::string* FileOptions::mutable_php_metadata_namespace() {
+  std::string* _s = _internal_mutable_php_metadata_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.php_metadata_namespace)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_php_metadata_namespace() const {
+  return _impl_.php_metadata_namespace_.Get();
+}
+inline void FileOptions::_internal_set_php_metadata_namespace(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000100u;
+  _impl_.php_metadata_namespace_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_php_metadata_namespace() {
+  _impl_._has_bits_[0] |= 0x00000100u;
+  return _impl_.php_metadata_namespace_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_php_metadata_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.php_metadata_namespace)
+  if (!_internal_has_php_metadata_namespace()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000100u;
+  auto* p = _impl_.php_metadata_namespace_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_metadata_namespace_.IsDefault()) {
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_php_metadata_namespace(std::string* php_metadata_namespace) {
+  if (php_metadata_namespace != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000100u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000100u;
+  }
+  _impl_.php_metadata_namespace_.SetAllocated(php_metadata_namespace, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_metadata_namespace_.IsDefault()) {
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.php_metadata_namespace)
+}
+
+// optional string ruby_package = 45;
+inline bool FileOptions::_internal_has_ruby_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000200u) != 0;
+  return value;
+}
+inline bool FileOptions::has_ruby_package() const {
+  return _internal_has_ruby_package();
+}
+inline void FileOptions::clear_ruby_package() {
+  _impl_.ruby_package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000200u;
+}
+inline const std::string& FileOptions::ruby_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.ruby_package)
+  return _internal_ruby_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_ruby_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000200u;
+ _impl_.ruby_package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.ruby_package)
+}
+inline std::string* FileOptions::mutable_ruby_package() {
+  std::string* _s = _internal_mutable_ruby_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.ruby_package)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_ruby_package() const {
+  return _impl_.ruby_package_.Get();
+}
+inline void FileOptions::_internal_set_ruby_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000200u;
+  _impl_.ruby_package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_ruby_package() {
+  _impl_._has_bits_[0] |= 0x00000200u;
+  return _impl_.ruby_package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_ruby_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.ruby_package)
+  if (!_internal_has_ruby_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000200u;
+  auto* p = _impl_.ruby_package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.ruby_package_.IsDefault()) {
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_ruby_package(std::string* ruby_package) {
+  if (ruby_package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000200u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000200u;
+  }
+  _impl_.ruby_package_.SetAllocated(ruby_package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.ruby_package_.IsDefault()) {
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.ruby_package)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int FileOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int FileOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void FileOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+FileOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FileOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FileOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FileOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+FileOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// MessageOptions
+
+// optional bool message_set_wire_format = 1 [default = false];
+inline bool MessageOptions::_internal_has_message_set_wire_format() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_message_set_wire_format() const {
+  return _internal_has_message_set_wire_format();
+}
+inline void MessageOptions::clear_message_set_wire_format() {
+  _impl_.message_set_wire_format_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool MessageOptions::_internal_message_set_wire_format() const {
+  return _impl_.message_set_wire_format_;
+}
+inline bool MessageOptions::message_set_wire_format() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.message_set_wire_format)
+  return _internal_message_set_wire_format();
+}
+inline void MessageOptions::_internal_set_message_set_wire_format(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.message_set_wire_format_ = value;
+}
+inline void MessageOptions::set_message_set_wire_format(bool value) {
+  _internal_set_message_set_wire_format(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.message_set_wire_format)
+}
+
+// optional bool no_standard_descriptor_accessor = 2 [default = false];
+inline bool MessageOptions::_internal_has_no_standard_descriptor_accessor() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_no_standard_descriptor_accessor() const {
+  return _internal_has_no_standard_descriptor_accessor();
+}
+inline void MessageOptions::clear_no_standard_descriptor_accessor() {
+  _impl_.no_standard_descriptor_accessor_ = false;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline bool MessageOptions::_internal_no_standard_descriptor_accessor() const {
+  return _impl_.no_standard_descriptor_accessor_;
+}
+inline bool MessageOptions::no_standard_descriptor_accessor() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+  return _internal_no_standard_descriptor_accessor();
+}
+inline void MessageOptions::_internal_set_no_standard_descriptor_accessor(bool value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.no_standard_descriptor_accessor_ = value;
+}
+inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
+  _internal_set_no_standard_descriptor_accessor(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool MessageOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void MessageOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline bool MessageOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool MessageOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void MessageOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.deprecated_ = value;
+}
+inline void MessageOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.deprecated)
+}
+
+// optional bool map_entry = 7;
+inline bool MessageOptions::_internal_has_map_entry() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_map_entry() const {
+  return _internal_has_map_entry();
+}
+inline void MessageOptions::clear_map_entry() {
+  _impl_.map_entry_ = false;
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline bool MessageOptions::_internal_map_entry() const {
+  return _impl_.map_entry_;
+}
+inline bool MessageOptions::map_entry() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.map_entry)
+  return _internal_map_entry();
+}
+inline void MessageOptions::_internal_set_map_entry(bool value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.map_entry_ = value;
+}
+inline void MessageOptions::set_map_entry(bool value) {
+  _internal_set_map_entry(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.map_entry)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int MessageOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int MessageOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void MessageOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MessageOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+MessageOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MessageOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MessageOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MessageOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+MessageOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// FieldOptions
+
+// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+inline bool FieldOptions::_internal_has_ctype() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_ctype() const {
+  return _internal_has_ctype();
+}
+inline void FieldOptions::clear_ctype() {
+  _impl_.ctype_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType FieldOptions::_internal_ctype() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType >(_impl_.ctype_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType FieldOptions::ctype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.ctype)
+  return _internal_ctype();
+}
+inline void FieldOptions::_internal_set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.ctype_ = value;
+}
+inline void FieldOptions::set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value) {
+  _internal_set_ctype(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.ctype)
+}
+
+// optional bool packed = 2;
+inline bool FieldOptions::_internal_has_packed() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_packed() const {
+  return _internal_has_packed();
+}
+inline void FieldOptions::clear_packed() {
+  _impl_.packed_ = false;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline bool FieldOptions::_internal_packed() const {
+  return _impl_.packed_;
+}
+inline bool FieldOptions::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.packed)
+  return _internal_packed();
+}
+inline void FieldOptions::_internal_set_packed(bool value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.packed_ = value;
+}
+inline void FieldOptions::set_packed(bool value) {
+  _internal_set_packed(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
+}
+
+// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+inline bool FieldOptions::_internal_has_jstype() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_jstype() const {
+  return _internal_has_jstype();
+}
+inline void FieldOptions::clear_jstype() {
+  _impl_.jstype_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType FieldOptions::_internal_jstype() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType >(_impl_.jstype_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType FieldOptions::jstype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype)
+  return _internal_jstype();
+}
+inline void FieldOptions::_internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.jstype_ = value;
+}
+inline void FieldOptions::set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value) {
+  _internal_set_jstype(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype)
+}
+
+// optional bool lazy = 5 [default = false];
+inline bool FieldOptions::_internal_has_lazy() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_lazy() const {
+  return _internal_has_lazy();
+}
+inline void FieldOptions::clear_lazy() {
+  _impl_.lazy_ = false;
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline bool FieldOptions::_internal_lazy() const {
+  return _impl_.lazy_;
+}
+inline bool FieldOptions::lazy() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.lazy)
+  return _internal_lazy();
+}
+inline void FieldOptions::_internal_set_lazy(bool value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.lazy_ = value;
+}
+inline void FieldOptions::set_lazy(bool value) {
+  _internal_set_lazy(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.lazy)
+}
+
+// optional bool unverified_lazy = 15 [default = false];
+inline bool FieldOptions::_internal_has_unverified_lazy() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_unverified_lazy() const {
+  return _internal_has_unverified_lazy();
+}
+inline void FieldOptions::clear_unverified_lazy() {
+  _impl_.unverified_lazy_ = false;
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline bool FieldOptions::_internal_unverified_lazy() const {
+  return _impl_.unverified_lazy_;
+}
+inline bool FieldOptions::unverified_lazy() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.unverified_lazy)
+  return _internal_unverified_lazy();
+}
+inline void FieldOptions::_internal_set_unverified_lazy(bool value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.unverified_lazy_ = value;
+}
+inline void FieldOptions::set_unverified_lazy(bool value) {
+  _internal_set_unverified_lazy(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.unverified_lazy)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool FieldOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void FieldOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline bool FieldOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool FieldOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void FieldOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.deprecated_ = value;
+}
+inline void FieldOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.deprecated)
+}
+
+// optional bool weak = 10 [default = false];
+inline bool FieldOptions::_internal_has_weak() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000040u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_weak() const {
+  return _internal_has_weak();
+}
+inline void FieldOptions::clear_weak() {
+  _impl_.weak_ = false;
+  _impl_._has_bits_[0] &= ~0x00000040u;
+}
+inline bool FieldOptions::_internal_weak() const {
+  return _impl_.weak_;
+}
+inline bool FieldOptions::weak() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.weak)
+  return _internal_weak();
+}
+inline void FieldOptions::_internal_set_weak(bool value) {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  _impl_.weak_ = value;
+}
+inline void FieldOptions::set_weak(bool value) {
+  _internal_set_weak(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.weak)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int FieldOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int FieldOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void FieldOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+FieldOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FieldOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FieldOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FieldOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+FieldOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// OneofOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int OneofOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int OneofOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void OneofOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* OneofOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+OneofOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& OneofOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& OneofOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* OneofOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* OneofOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.OneofOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+OneofOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumOptions
+
+// optional bool allow_alias = 2;
+inline bool EnumOptions::_internal_has_allow_alias() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumOptions::has_allow_alias() const {
+  return _internal_has_allow_alias();
+}
+inline void EnumOptions::clear_allow_alias() {
+  _impl_.allow_alias_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool EnumOptions::_internal_allow_alias() const {
+  return _impl_.allow_alias_;
+}
+inline bool EnumOptions::allow_alias() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.allow_alias)
+  return _internal_allow_alias();
+}
+inline void EnumOptions::_internal_set_allow_alias(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.allow_alias_ = value;
+}
+inline void EnumOptions::set_allow_alias(bool value) {
+  _internal_set_allow_alias(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.allow_alias)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool EnumOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool EnumOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void EnumOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline bool EnumOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool EnumOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void EnumOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.deprecated_ = value;
+}
+inline void EnumOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int EnumOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int EnumOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void EnumOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+EnumOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+EnumOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumValueOptions
+
+// optional bool deprecated = 1 [default = false];
+inline bool EnumValueOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumValueOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void EnumValueOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool EnumValueOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool EnumValueOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void EnumValueOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.deprecated_ = value;
+}
+inline void EnumValueOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int EnumValueOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int EnumValueOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void EnumValueOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+EnumValueOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumValueOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumValueOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+EnumValueOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// ServiceOptions
+
+// optional bool deprecated = 33 [default = false];
+inline bool ServiceOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool ServiceOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void ServiceOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool ServiceOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool ServiceOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void ServiceOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.deprecated_ = value;
+}
+inline void ServiceOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.ServiceOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int ServiceOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int ServiceOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void ServiceOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+ServiceOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ServiceOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ServiceOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ServiceOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+ServiceOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// MethodOptions
+
+// optional bool deprecated = 33 [default = false];
+inline bool MethodOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool MethodOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void MethodOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool MethodOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool MethodOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void MethodOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.deprecated_ = value;
+}
+inline void MethodOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.deprecated)
+}
+
+// optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+inline bool MethodOptions::_internal_has_idempotency_level() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool MethodOptions::has_idempotency_level() const {
+  return _internal_has_idempotency_level();
+}
+inline void MethodOptions::clear_idempotency_level() {
+  _impl_.idempotency_level_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel MethodOptions::_internal_idempotency_level() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel >(_impl_.idempotency_level_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel MethodOptions::idempotency_level() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.idempotency_level)
+  return _internal_idempotency_level();
+}
+inline void MethodOptions::_internal_set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value) {
+  assert(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.idempotency_level_ = value;
+}
+inline void MethodOptions::set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value) {
+  _internal_set_idempotency_level(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.idempotency_level)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int MethodOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int MethodOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void MethodOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+MethodOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MethodOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MethodOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MethodOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+MethodOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// UninterpretedOption_NamePart
+
+// required string name_part = 1;
+inline bool UninterpretedOption_NamePart::_internal_has_name_part() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool UninterpretedOption_NamePart::has_name_part() const {
+  return _internal_has_name_part();
+}
+inline void UninterpretedOption_NamePart::clear_name_part() {
+  _impl_.name_part_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& UninterpretedOption_NamePart::name_part() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part)
+  return _internal_name_part();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption_NamePart::set_name_part(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_part_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+inline std::string* UninterpretedOption_NamePart::mutable_name_part() {
+  std::string* _s = _internal_mutable_name_part();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part)
+  return _s;
+}
+inline const std::string& UninterpretedOption_NamePart::_internal_name_part() const {
+  return _impl_.name_part_.Get();
+}
+inline void UninterpretedOption_NamePart::_internal_set_name_part(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_part_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption_NamePart::_internal_mutable_name_part() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_part_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption_NamePart::release_name_part() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part)
+  if (!_internal_has_name_part()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_part_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_part_.IsDefault()) {
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption_NamePart::set_allocated_name_part(std::string* name_part) {
+  if (name_part != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_part_.SetAllocated(name_part, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_part_.IsDefault()) {
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+
+// required bool is_extension = 2;
+inline bool UninterpretedOption_NamePart::_internal_has_is_extension() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool UninterpretedOption_NamePart::has_is_extension() const {
+  return _internal_has_is_extension();
+}
+inline void UninterpretedOption_NamePart::clear_is_extension() {
+  _impl_.is_extension_ = false;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline bool UninterpretedOption_NamePart::_internal_is_extension() const {
+  return _impl_.is_extension_;
+}
+inline bool UninterpretedOption_NamePart::is_extension() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.is_extension)
+  return _internal_is_extension();
+}
+inline void UninterpretedOption_NamePart::_internal_set_is_extension(bool value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.is_extension_ = value;
+}
+inline void UninterpretedOption_NamePart::set_is_extension(bool value) {
+  _internal_set_is_extension(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.is_extension)
+}
+
+// -------------------------------------------------------------------
+
+// UninterpretedOption
+
+// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+inline int UninterpretedOption::_internal_name_size() const {
+  return _impl_.name_.size();
+}
+inline int UninterpretedOption::name_size() const {
+  return _internal_name_size();
+}
+inline void UninterpretedOption::clear_name() {
+  _impl_.name_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.name)
+  return _impl_.name_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >*
+UninterpretedOption::mutable_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name)
+  return &_impl_.name_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& UninterpretedOption::_internal_name(int index) const {
+  return _impl_.name_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.name)
+  return _internal_name(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* UninterpretedOption::_internal_add_name() {
+  return _impl_.name_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* UninterpretedOption::add_name() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* _add = _internal_add_name();
+  // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >&
+UninterpretedOption::name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
+  return _impl_.name_;
+}
+
+// optional string identifier_value = 3;
+inline bool UninterpretedOption::_internal_has_identifier_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_identifier_value() const {
+  return _internal_has_identifier_value();
+}
+inline void UninterpretedOption::clear_identifier_value() {
+  _impl_.identifier_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& UninterpretedOption::identifier_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value)
+  return _internal_identifier_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption::set_identifier_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.identifier_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.identifier_value)
+}
+inline std::string* UninterpretedOption::mutable_identifier_value() {
+  std::string* _s = _internal_mutable_identifier_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value)
+  return _s;
+}
+inline const std::string& UninterpretedOption::_internal_identifier_value() const {
+  return _impl_.identifier_value_.Get();
+}
+inline void UninterpretedOption::_internal_set_identifier_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.identifier_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::_internal_mutable_identifier_value() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.identifier_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::release_identifier_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value)
+  if (!_internal_has_identifier_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.identifier_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.identifier_value_.IsDefault()) {
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption::set_allocated_identifier_value(std::string* identifier_value) {
+  if (identifier_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.identifier_value_.SetAllocated(identifier_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.identifier_value_.IsDefault()) {
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value)
+}
+
+// optional uint64 positive_int_value = 4;
+inline bool UninterpretedOption::_internal_has_positive_int_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_positive_int_value() const {
+  return _internal_has_positive_int_value();
+}
+inline void UninterpretedOption::clear_positive_int_value() {
+  _impl_.positive_int_value_ = uint64_t{0u};
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline uint64_t UninterpretedOption::_internal_positive_int_value() const {
+  return _impl_.positive_int_value_;
+}
+inline uint64_t UninterpretedOption::positive_int_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.positive_int_value)
+  return _internal_positive_int_value();
+}
+inline void UninterpretedOption::_internal_set_positive_int_value(uint64_t value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.positive_int_value_ = value;
+}
+inline void UninterpretedOption::set_positive_int_value(uint64_t value) {
+  _internal_set_positive_int_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.positive_int_value)
+}
+
+// optional int64 negative_int_value = 5;
+inline bool UninterpretedOption::_internal_has_negative_int_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_negative_int_value() const {
+  return _internal_has_negative_int_value();
+}
+inline void UninterpretedOption::clear_negative_int_value() {
+  _impl_.negative_int_value_ = int64_t{0};
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline int64_t UninterpretedOption::_internal_negative_int_value() const {
+  return _impl_.negative_int_value_;
+}
+inline int64_t UninterpretedOption::negative_int_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.negative_int_value)
+  return _internal_negative_int_value();
+}
+inline void UninterpretedOption::_internal_set_negative_int_value(int64_t value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.negative_int_value_ = value;
+}
+inline void UninterpretedOption::set_negative_int_value(int64_t value) {
+  _internal_set_negative_int_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.negative_int_value)
+}
+
+// optional double double_value = 6;
+inline bool UninterpretedOption::_internal_has_double_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_double_value() const {
+  return _internal_has_double_value();
+}
+inline void UninterpretedOption::clear_double_value() {
+  _impl_.double_value_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline double UninterpretedOption::_internal_double_value() const {
+  return _impl_.double_value_;
+}
+inline double UninterpretedOption::double_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.double_value)
+  return _internal_double_value();
+}
+inline void UninterpretedOption::_internal_set_double_value(double value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.double_value_ = value;
+}
+inline void UninterpretedOption::set_double_value(double value) {
+  _internal_set_double_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.double_value)
+}
+
+// optional bytes string_value = 7;
+inline bool UninterpretedOption::_internal_has_string_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_string_value() const {
+  return _internal_has_string_value();
+}
+inline void UninterpretedOption::clear_string_value() {
+  _impl_.string_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& UninterpretedOption::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value)
+  return _internal_string_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption::set_string_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.string_value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.string_value)
+}
+inline std::string* UninterpretedOption::mutable_string_value() {
+  std::string* _s = _internal_mutable_string_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value)
+  return _s;
+}
+inline const std::string& UninterpretedOption::_internal_string_value() const {
+  return _impl_.string_value_.Get();
+}
+inline void UninterpretedOption::_internal_set_string_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.string_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::_internal_mutable_string_value() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.string_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value)
+  if (!_internal_has_string_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.string_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.string_value_.IsDefault()) {
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption::set_allocated_string_value(std::string* string_value) {
+  if (string_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.string_value_.SetAllocated(string_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.string_value_.IsDefault()) {
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value)
+}
+
+// optional string aggregate_value = 8;
+inline bool UninterpretedOption::_internal_has_aggregate_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_aggregate_value() const {
+  return _internal_has_aggregate_value();
+}
+inline void UninterpretedOption::clear_aggregate_value() {
+  _impl_.aggregate_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& UninterpretedOption::aggregate_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value)
+  return _internal_aggregate_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption::set_aggregate_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.aggregate_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.aggregate_value)
+}
+inline std::string* UninterpretedOption::mutable_aggregate_value() {
+  std::string* _s = _internal_mutable_aggregate_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value)
+  return _s;
+}
+inline const std::string& UninterpretedOption::_internal_aggregate_value() const {
+  return _impl_.aggregate_value_.Get();
+}
+inline void UninterpretedOption::_internal_set_aggregate_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.aggregate_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::_internal_mutable_aggregate_value() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.aggregate_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::release_aggregate_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value)
+  if (!_internal_has_aggregate_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.aggregate_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.aggregate_value_.IsDefault()) {
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption::set_allocated_aggregate_value(std::string* aggregate_value) {
+  if (aggregate_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.aggregate_value_.SetAllocated(aggregate_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.aggregate_value_.IsDefault()) {
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value)
+}
+
+// -------------------------------------------------------------------
+
+// SourceCodeInfo_Location
+
+// repeated int32 path = 1 [packed = true];
+inline int SourceCodeInfo_Location::_internal_path_size() const {
+  return _impl_.path_.size();
+}
+inline int SourceCodeInfo_Location::path_size() const {
+  return _internal_path_size();
+}
+inline void SourceCodeInfo_Location::clear_path() {
+  _impl_.path_.Clear();
+}
+inline int32_t SourceCodeInfo_Location::_internal_path(int index) const {
+  return _impl_.path_.Get(index);
+}
+inline int32_t SourceCodeInfo_Location::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.path)
+  return _internal_path(index);
+}
+inline void SourceCodeInfo_Location::set_path(int index, int32_t value) {
+  _impl_.path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.path)
+}
+inline void SourceCodeInfo_Location::_internal_add_path(int32_t value) {
+  _impl_.path_.Add(value);
+}
+inline void SourceCodeInfo_Location::add_path(int32_t value) {
+  _internal_add_path(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.path)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::_internal_path() const {
+  return _impl_.path_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.path)
+  return _internal_path();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::_internal_mutable_path() {
+  return &_impl_.path_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.path)
+  return _internal_mutable_path();
+}
+
+// repeated int32 span = 2 [packed = true];
+inline int SourceCodeInfo_Location::_internal_span_size() const {
+  return _impl_.span_.size();
+}
+inline int SourceCodeInfo_Location::span_size() const {
+  return _internal_span_size();
+}
+inline void SourceCodeInfo_Location::clear_span() {
+  _impl_.span_.Clear();
+}
+inline int32_t SourceCodeInfo_Location::_internal_span(int index) const {
+  return _impl_.span_.Get(index);
+}
+inline int32_t SourceCodeInfo_Location::span(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.span)
+  return _internal_span(index);
+}
+inline void SourceCodeInfo_Location::set_span(int index, int32_t value) {
+  _impl_.span_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.span)
+}
+inline void SourceCodeInfo_Location::_internal_add_span(int32_t value) {
+  _impl_.span_.Add(value);
+}
+inline void SourceCodeInfo_Location::add_span(int32_t value) {
+  _internal_add_span(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.span)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::_internal_span() const {
+  return _impl_.span_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::span() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.span)
+  return _internal_span();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::_internal_mutable_span() {
+  return &_impl_.span_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::mutable_span() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.span)
+  return _internal_mutable_span();
+}
+
+// optional string leading_comments = 3;
+inline bool SourceCodeInfo_Location::_internal_has_leading_comments() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool SourceCodeInfo_Location::has_leading_comments() const {
+  return _internal_has_leading_comments();
+}
+inline void SourceCodeInfo_Location::clear_leading_comments() {
+  _impl_.leading_comments_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& SourceCodeInfo_Location::leading_comments() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  return _internal_leading_comments();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void SourceCodeInfo_Location::set_leading_comments(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.leading_comments_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+inline std::string* SourceCodeInfo_Location::mutable_leading_comments() {
+  std::string* _s = _internal_mutable_leading_comments();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  return _s;
+}
+inline const std::string& SourceCodeInfo_Location::_internal_leading_comments() const {
+  return _impl_.leading_comments_.Get();
+}
+inline void SourceCodeInfo_Location::_internal_set_leading_comments(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.leading_comments_.Set(value, GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::_internal_mutable_leading_comments() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.leading_comments_.Mutable(GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::release_leading_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  if (!_internal_has_leading_comments()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.leading_comments_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.leading_comments_.IsDefault()) {
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void SourceCodeInfo_Location::set_allocated_leading_comments(std::string* leading_comments) {
+  if (leading_comments != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.leading_comments_.SetAllocated(leading_comments, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.leading_comments_.IsDefault()) {
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+
+// optional string trailing_comments = 4;
+inline bool SourceCodeInfo_Location::_internal_has_trailing_comments() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool SourceCodeInfo_Location::has_trailing_comments() const {
+  return _internal_has_trailing_comments();
+}
+inline void SourceCodeInfo_Location::clear_trailing_comments() {
+  _impl_.trailing_comments_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& SourceCodeInfo_Location::trailing_comments() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  return _internal_trailing_comments();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void SourceCodeInfo_Location::set_trailing_comments(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.trailing_comments_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+inline std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
+  std::string* _s = _internal_mutable_trailing_comments();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  return _s;
+}
+inline const std::string& SourceCodeInfo_Location::_internal_trailing_comments() const {
+  return _impl_.trailing_comments_.Get();
+}
+inline void SourceCodeInfo_Location::_internal_set_trailing_comments(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.trailing_comments_.Set(value, GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::_internal_mutable_trailing_comments() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.trailing_comments_.Mutable(GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::release_trailing_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  if (!_internal_has_trailing_comments()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.trailing_comments_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.trailing_comments_.IsDefault()) {
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void SourceCodeInfo_Location::set_allocated_trailing_comments(std::string* trailing_comments) {
+  if (trailing_comments != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.trailing_comments_.SetAllocated(trailing_comments, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.trailing_comments_.IsDefault()) {
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+
+// repeated string leading_detached_comments = 6;
+inline int SourceCodeInfo_Location::_internal_leading_detached_comments_size() const {
+  return _impl_.leading_detached_comments_.size();
+}
+inline int SourceCodeInfo_Location::leading_detached_comments_size() const {
+  return _internal_leading_detached_comments_size();
+}
+inline void SourceCodeInfo_Location::clear_leading_detached_comments() {
+  _impl_.leading_detached_comments_.Clear();
+}
+inline std::string* SourceCodeInfo_Location::add_leading_detached_comments() {
+  std::string* _s = _internal_add_leading_detached_comments();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _s;
+}
+inline const std::string& SourceCodeInfo_Location::_internal_leading_detached_comments(int index) const {
+  return _impl_.leading_detached_comments_.Get(index);
+}
+inline const std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _internal_leading_detached_comments(index);
+}
+inline std::string* SourceCodeInfo_Location::mutable_leading_detached_comments(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _impl_.leading_detached_comments_.Mutable(index);
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const std::string& value) {
+  _impl_.leading_detached_comments_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, std::string&& value) {
+  _impl_.leading_detached_comments_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.leading_detached_comments_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value, size_t size) {
+  _impl_.leading_detached_comments_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline std::string* SourceCodeInfo_Location::_internal_add_leading_detached_comments() {
+  return _impl_.leading_detached_comments_.Add();
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const std::string& value) {
+  _impl_.leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(std::string&& value) {
+  _impl_.leading_detached_comments_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value, size_t size) {
+  _impl_.leading_detached_comments_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+SourceCodeInfo_Location::leading_detached_comments() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _impl_.leading_detached_comments_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+SourceCodeInfo_Location::mutable_leading_detached_comments() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return &_impl_.leading_detached_comments_;
+}
+
+// -------------------------------------------------------------------
+
+// SourceCodeInfo
+
+// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+inline int SourceCodeInfo::_internal_location_size() const {
+  return _impl_.location_.size();
+}
+inline int SourceCodeInfo::location_size() const {
+  return _internal_location_size();
+}
+inline void SourceCodeInfo::clear_location() {
+  _impl_.location_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.location)
+  return _impl_.location_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >*
+SourceCodeInfo::mutable_location() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location)
+  return &_impl_.location_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& SourceCodeInfo::_internal_location(int index) const {
+  return _impl_.location_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.location)
+  return _internal_location(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* SourceCodeInfo::_internal_add_location() {
+  return _impl_.location_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* SourceCodeInfo::add_location() {
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* _add = _internal_add_location();
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >&
+SourceCodeInfo::location() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
+  return _impl_.location_;
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo_Annotation
+
+// repeated int32 path = 1 [packed = true];
+inline int GeneratedCodeInfo_Annotation::_internal_path_size() const {
+  return _impl_.path_.size();
+}
+inline int GeneratedCodeInfo_Annotation::path_size() const {
+  return _internal_path_size();
+}
+inline void GeneratedCodeInfo_Annotation::clear_path() {
+  _impl_.path_.Clear();
+}
+inline int32_t GeneratedCodeInfo_Annotation::_internal_path(int index) const {
+  return _impl_.path_.Get(index);
+}
+inline int32_t GeneratedCodeInfo_Annotation::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return _internal_path(index);
+}
+inline void GeneratedCodeInfo_Annotation::set_path(int index, int32_t value) {
+  _impl_.path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline void GeneratedCodeInfo_Annotation::_internal_add_path(int32_t value) {
+  _impl_.path_.Add(value);
+}
+inline void GeneratedCodeInfo_Annotation::add_path(int32_t value) {
+  _internal_add_path(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+GeneratedCodeInfo_Annotation::_internal_path() const {
+  return _impl_.path_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+GeneratedCodeInfo_Annotation::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return _internal_path();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+GeneratedCodeInfo_Annotation::_internal_mutable_path() {
+  return &_impl_.path_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+GeneratedCodeInfo_Annotation::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return _internal_mutable_path();
+}
+
+// optional string source_file = 2;
+inline bool GeneratedCodeInfo_Annotation::_internal_has_source_file() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool GeneratedCodeInfo_Annotation::has_source_file() const {
+  return _internal_has_source_file();
+}
+inline void GeneratedCodeInfo_Annotation::clear_source_file() {
+  _impl_.source_file_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& GeneratedCodeInfo_Annotation::source_file() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return _internal_source_file();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void GeneratedCodeInfo_Annotation::set_source_file(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.source_file_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline std::string* GeneratedCodeInfo_Annotation::mutable_source_file() {
+  std::string* _s = _internal_mutable_source_file();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return _s;
+}
+inline const std::string& GeneratedCodeInfo_Annotation::_internal_source_file() const {
+  return _impl_.source_file_.Get();
+}
+inline void GeneratedCodeInfo_Annotation::_internal_set_source_file(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.source_file_.Set(value, GetArenaForAllocation());
+}
+inline std::string* GeneratedCodeInfo_Annotation::_internal_mutable_source_file() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.source_file_.Mutable(GetArenaForAllocation());
+}
+inline std::string* GeneratedCodeInfo_Annotation::release_source_file() {
+  // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  if (!_internal_has_source_file()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.source_file_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.source_file_.IsDefault()) {
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void GeneratedCodeInfo_Annotation::set_allocated_source_file(std::string* source_file) {
+  if (source_file != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.source_file_.SetAllocated(source_file, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.source_file_.IsDefault()) {
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+
+// optional int32 begin = 3;
+inline bool GeneratedCodeInfo_Annotation::_internal_has_begin() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool GeneratedCodeInfo_Annotation::has_begin() const {
+  return _internal_has_begin();
+}
+inline void GeneratedCodeInfo_Annotation::clear_begin() {
+  _impl_.begin_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t GeneratedCodeInfo_Annotation::_internal_begin() const {
+  return _impl_.begin_;
+}
+inline int32_t GeneratedCodeInfo_Annotation::begin() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+  return _internal_begin();
+}
+inline void GeneratedCodeInfo_Annotation::_internal_set_begin(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.begin_ = value;
+}
+inline void GeneratedCodeInfo_Annotation::set_begin(int32_t value) {
+  _internal_set_begin(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+}
+
+// optional int32 end = 4;
+inline bool GeneratedCodeInfo_Annotation::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool GeneratedCodeInfo_Annotation::has_end() const {
+  return _internal_has_end();
+}
+inline void GeneratedCodeInfo_Annotation::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t GeneratedCodeInfo_Annotation::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t GeneratedCodeInfo_Annotation::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end)
+  return _internal_end();
+}
+inline void GeneratedCodeInfo_Annotation::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.end_ = value;
+}
+inline void GeneratedCodeInfo_Annotation::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo
+
+// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+inline int GeneratedCodeInfo::_internal_annotation_size() const {
+  return _impl_.annotation_.size();
+}
+inline int GeneratedCodeInfo::annotation_size() const {
+  return _internal_annotation_size();
+}
+inline void GeneratedCodeInfo::clear_annotation() {
+  _impl_.annotation_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation)
+  return _impl_.annotation_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >*
+GeneratedCodeInfo::mutable_annotation() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return &_impl_.annotation_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::_internal_annotation(int index) const {
+  return _impl_.annotation_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation)
+  return _internal_annotation(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::_internal_add_annotation() {
+  return _impl_.annotation_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() {
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* _add = _internal_add_annotation();
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >&
+GeneratedCodeInfo::annotation() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return _impl_.annotation_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>() {
+  return ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>() {
+  return ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
new file mode 100644
index 0000000..f8eb216
--- /dev/null
+++ b/src/google/protobuf/descriptor.proto
@@ -0,0 +1,921 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+syntax = "proto2";
+
+package google.protobuf;
+
+option go_package = "google.golang.org/protobuf/types/descriptorpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+  repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+  optional string name = 1;     // file name, relative to root of source tree
+  optional string package = 2;  // e.g. "foo", "foo.bar", etc.
+
+  // Names of files imported by this file.
+  repeated string dependency = 3;
+  // Indexes of the public imported files in the dependency list above.
+  repeated int32 public_dependency = 10;
+  // Indexes of the weak imported files in the dependency list.
+  // For Google-internal migration only. Do not use.
+  repeated int32 weak_dependency = 11;
+
+  // All top-level definitions in this file.
+  repeated DescriptorProto message_type = 4;
+  repeated EnumDescriptorProto enum_type = 5;
+  repeated ServiceDescriptorProto service = 6;
+  repeated FieldDescriptorProto extension = 7;
+
+  optional FileOptions options = 8;
+
+  // 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.
+  optional SourceCodeInfo source_code_info = 9;
+
+  // The syntax of the proto file.
+  // The supported values are "proto2" and "proto3".
+  optional string syntax = 12;
+}
+
+// Describes a message type.
+message DescriptorProto {
+  optional string name = 1;
+
+  repeated FieldDescriptorProto field = 2;
+  repeated FieldDescriptorProto extension = 6;
+
+  repeated DescriptorProto nested_type = 3;
+  repeated EnumDescriptorProto enum_type = 4;
+
+  message ExtensionRange {
+    optional int32 start = 1;  // Inclusive.
+    optional int32 end = 2;    // Exclusive.
+
+    optional ExtensionRangeOptions options = 3;
+  }
+  repeated ExtensionRange extension_range = 5;
+
+  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;
+}
+
+message ExtensionRangeOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+  enum Type {
+    // 0 is reserved for errors.
+    // Order is weird for historical reasons.
+    TYPE_DOUBLE = 1;
+    TYPE_FLOAT = 2;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+    // negative values are likely.
+    TYPE_INT64 = 3;
+    TYPE_UINT64 = 4;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+    // negative values are likely.
+    TYPE_INT32 = 5;
+    TYPE_FIXED64 = 6;
+    TYPE_FIXED32 = 7;
+    TYPE_BOOL = 8;
+    TYPE_STRING = 9;
+    // Tag-delimited aggregate.
+    // Group type is deprecated and not supported in proto3. However, Proto3
+    // implementations should still be able to parse the group wire format and
+    // treat group fields as unknown fields.
+    TYPE_GROUP = 10;
+    TYPE_MESSAGE = 11;  // Length-delimited aggregate.
+
+    // New in version 2.
+    TYPE_BYTES = 12;
+    TYPE_UINT32 = 13;
+    TYPE_ENUM = 14;
+    TYPE_SFIXED32 = 15;
+    TYPE_SFIXED64 = 16;
+    TYPE_SINT32 = 17;  // Uses ZigZag encoding.
+    TYPE_SINT64 = 18;  // Uses ZigZag encoding.
+  }
+
+  enum Label {
+    // 0 is reserved for errors
+    LABEL_OPTIONAL = 1;
+    LABEL_REQUIRED = 2;
+    LABEL_REPEATED = 3;
+  }
+
+  optional string name = 1;
+  optional int32 number = 3;
+  optional Label label = 4;
+
+  // 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.
+  optional Type type = 5;
+
+  // 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).
+  optional string type_name = 6;
+
+  // For extensions, this is the name of the type being extended.  It is
+  // resolved in the same manner as type_name.
+  optional string extendee = 2;
+
+  // 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.
+  optional string default_value = 7;
+
+  // If set, gives the index of a oneof in the containing type's oneof_decl
+  // list.  This field is a member of that oneof.
+  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;
+
+  // If true, this is a proto3 "optional". When a proto3 field is optional, it
+  // tracks presence regardless of field type.
+  //
+  // When proto3_optional is true, this field must be belong to a oneof to
+  // signal to old proto3 clients that presence is tracked for this field. This
+  // oneof is known as a "synthetic" oneof, and this field must be its sole
+  // member (each proto3 optional field gets its own synthetic oneof). Synthetic
+  // oneofs exist in the descriptor only, and do not generate any API. Synthetic
+  // oneofs must be ordered after all "real" oneofs.
+  //
+  // For message fields, proto3_optional doesn't create any semantic change,
+  // since non-repeated message fields always track presence. However it still
+  // indicates the semantic detail of whether the user wrote "optional" or not.
+  // This can be useful for round-tripping the .proto file. For consistency we
+  // give message fields a synthetic oneof also, even though it is not required
+  // to track presence. This is especially important because the parser can't
+  // tell if a field is a message or an enum, so it must always create a
+  // synthetic oneof.
+  //
+  // Proto2 optional fields do not set this flag, because they already indicate
+  // optional with `LABEL_OPTIONAL`.
+  optional bool proto3_optional = 17;
+}
+
+// Describes a oneof.
+message OneofDescriptorProto {
+  optional string name = 1;
+  optional OneofOptions options = 2;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+  optional string name = 1;
+
+  repeated EnumValueDescriptorProto value = 2;
+
+  optional EnumOptions options = 3;
+
+  // Range of reserved numeric values. Reserved values may not be used by
+  // entries in the same enum. Reserved ranges may not overlap.
+  //
+  // Note that this is distinct from DescriptorProto.ReservedRange in that it
+  // is inclusive such that it can appropriately represent the entire int32
+  // domain.
+  message EnumReservedRange {
+    optional int32 start = 1;  // Inclusive.
+    optional int32 end = 2;    // Inclusive.
+  }
+
+  // Range of reserved numeric values. Reserved numeric values may not be used
+  // by enum values in the same enum declaration. Reserved ranges may not
+  // overlap.
+  repeated EnumReservedRange reserved_range = 4;
+
+  // Reserved enum value names, which may not be reused. A given name may only
+  // be reserved once.
+  repeated string reserved_name = 5;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+  optional string name = 1;
+  optional int32 number = 2;
+
+  optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+  optional string name = 1;
+  repeated MethodDescriptorProto method = 2;
+
+  optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+  optional string name = 1;
+
+  // Input and output type names.  These are resolved in the same way as
+  // FieldDescriptorProto.type_name, but must refer to a message type.
+  optional string input_type = 2;
+  optional string output_type = 3;
+
+  optional MethodOptions options = 4;
+
+  // Identifies if client streams multiple client messages
+  optional bool client_streaming = 5 [default = false];
+  // Identifies if server streams multiple server messages
+  optional bool server_streaming = 6 [default = false];
+}
+
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached.  These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them.  Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+//   organization, or for experimental options, use field numbers 50000
+//   through 99999.  It is up to you to ensure that you do not use the
+//   same number for multiple options.
+// * 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.
+//   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.
+
+message FileOptions {
+
+  // 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.
+  optional string java_package = 1;
+
+
+  // Controls the name of the wrapper Java class generated for the .proto file.
+  // That class will always contain the .proto file's getDescriptor() method as
+  // well as any top-level extensions defined in the .proto file.
+  // If java_multiple_files is disabled, then all the other classes from the
+  // .proto file will be nested inside the single wrapper outer class.
+  optional string java_outer_classname = 8;
+
+  // If enabled, 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 wrapper class
+  // named by java_outer_classname.  However, the wrapper class will still be
+  // generated to contain the file's getDescriptor() method as well as any
+  // top-level extensions defined in the file.
+  optional bool java_multiple_files = 10 [default = false];
+
+  // This option does nothing.
+  optional bool java_generate_equals_and_hash = 20 [deprecated=true];
+
+  // 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.
+  optional bool java_string_check_utf8 = 27 [default = false];
+
+
+  // Generated classes can be optimized for speed or code size.
+  enum OptimizeMode {
+    SPEED = 1;         // Generate complete code for parsing, serialization,
+                       // etc.
+    CODE_SIZE = 2;     // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3;  // Generate code using MessageLite and the lite runtime.
+  }
+  optional OptimizeMode optimize_for = 9 [default = SPEED];
+
+  // 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.
+  optional string go_package = 11;
+
+
+
+
+  // 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.
+  optional bool cc_generic_services = 16 [default = false];
+  optional bool java_generic_services = 17 [default = false];
+  optional bool py_generic_services = 18 [default = false];
+  optional bool php_generic_services = 42 [default = false];
+
+  // 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.
+  optional bool deprecated = 23 [default = false];
+
+  // Enables the use of arenas for the proto messages in this file. This applies
+  // only to generated classes for C++.
+  optional bool cc_enable_arenas = 31 [default = true];
+
+
+  // Sets the objective c class prefix which is prepended to all objective c
+  // generated classes from this .proto. There is no default.
+  optional string objc_class_prefix = 36;
+
+  // Namespace for generated classes; defaults to the package.
+  optional string csharp_namespace = 37;
+
+  // By default Swift generators will take the proto package and CamelCase it
+  // replacing '.' with underscore and use that to prefix the types/symbols
+  // defined. When this options is provided, they will use this value instead
+  // to prefix the types/symbols defined.
+  optional string swift_prefix = 39;
+
+  // Sets the php class prefix which is prepended to all php generated classes
+  // from this .proto. Default is empty.
+  optional string php_class_prefix = 40;
+
+  // Use this option to change the namespace of php generated classes. Default
+  // is empty. When this option is empty, the package name will be used for
+  // determining the namespace.
+  optional string php_namespace = 41;
+
+  // Use this option to change the namespace of php generated metadata classes.
+  // Default is empty. When this option is empty, the proto file name will be
+  // used for determining the namespace.
+  optional string php_metadata_namespace = 44;
+
+  // Use this option to change the package of ruby generated classes. Default
+  // is empty. When this option is not set, the package name will be used for
+  // determining the ruby package.
+  optional string ruby_package = 45;
+
+
+  // The parser stores options it doesn't recognize here.
+  // See the documentation for the "Options" section above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message.
+  // See the documentation for the "Options" section above.
+  extensions 1000 to max;
+
+  reserved 38;
+}
+
+message MessageOptions {
+  // 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.
+  optional bool message_set_wire_format = 1 [default = false];
+
+  // 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".
+  optional bool no_standard_descriptor_accessor = 2 [default = false];
+
+  // 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.
+  optional bool deprecated = 3 [default = false];
+
+  reserved 4, 5, 6;
+
+  // 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 implementations still need to work as
+  // if the field is a repeated message field.
+  //
+  // NOTE: Do not set the option in .proto files. Always use the maps syntax
+  // instead. The option should only be implicitly set by the proto compiler
+  // parser.
+  optional bool map_entry = 7;
+
+  reserved 8;  // javalite_serializable
+  reserved 9;  // javanano_as_lite
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message FieldOptions {
+  // 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!
+  optional CType ctype = 1 [default = STRING];
+  enum CType {
+    // Default mode.
+    STRING = 0;
+
+    CORD = 1;
+
+    STRING_PIECE = 2;
+  }
+  // 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.
+  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).  A field with jstype JS_STRING
+  // is represented as JavaScript string, which avoids loss of precision that
+  // can happen when a large value is converted to a floating point JavaScript.
+  // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+  // use the JavaScript "number" type.  The behavior of the default option
+  // JS_NORMAL is implementation dependent.
+  //
+  // 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
+  // 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 outer 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.
+  //
+  // As of 2021, lazy does no correctness checks on the byte stream during
+  // parsing.  This may lead to crashes if and when an invalid byte stream is
+  // finally parsed upon access.
+  //
+  // TODO(b/211906113):  Enable validation on lazy fields.
+  optional bool lazy = 5 [default = false];
+
+  // unverified_lazy does no correctness checks on the byte stream. This should
+  // only be used where lazy with verification is prohibitive for performance
+  // reasons.
+  optional bool unverified_lazy = 15 [default = false];
+
+  // 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.
+  optional bool deprecated = 3 [default = false];
+
+  // For Google-internal migration only. Do not use.
+  optional bool weak = 10 [default = false];
+
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+
+  reserved 4;  // removed jtype
+}
+
+message OneofOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumOptions {
+
+  // Set this option to true to allow mapping different tag names to the same
+  // value.
+  optional bool allow_alias = 2;
+
+  // 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.
+  optional bool deprecated = 3 [default = false];
+
+  reserved 5;  // javanano_as_lite
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumValueOptions {
+  // 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.
+  optional bool deprecated = 1 [default = false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // 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.
+  optional bool deprecated = 33 [default = false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MethodOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // 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.
+  optional bool deprecated = 33 [default = false];
+
+  // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
+  // or neither? HTTP based RPC implementation may choose GET verb for safe
+  // methods, and PUT verb for idempotent methods instead of the default POST.
+  enum IdempotencyLevel {
+    IDEMPOTENCY_UNKNOWN = 0;
+    NO_SIDE_EFFECTS = 1;  // implies idempotent
+    IDEMPOTENT = 2;       // idempotent, but may have side effects
+  }
+  optional IdempotencyLevel idempotency_level = 34
+      [default = IDEMPOTENCY_UNKNOWN];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+
+// 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.
+message UninterpretedOption {
+  // 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], ["moo", false] } represents
+  // "foo.(bar.baz).moo".
+  message NamePart {
+    required string name_part = 1;
+    required bool is_extension = 2;
+  }
+  repeated NamePart name = 2;
+
+  // The value of the uninterpreted option, in whatever type the tokenizer
+  // identified it as during parsing. Exactly one of these should be set.
+  optional string identifier_value = 3;
+  optional uint64 positive_int_value = 4;
+  optional int64 negative_int_value = 5;
+  optional double double_value = 6;
+  optional bytes string_value = 7;
+  optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+  // 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 descendant.  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.
+  repeated Location location = 1;
+  message Location {
+    // 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 occurs.
+    // 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).
+    repeated int32 path = 1 [packed = true];
+
+    // 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.
+    repeated int32 span = 2 [packed = true];
+
+    // 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 moo.
+    //   //
+    //   // Another line attached to moo.
+    //   optional double moo = 4;
+    //
+    //   // Detached comment for corge. This is not leading or trailing comments
+    //   // to moo 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.
+    optional string leading_comments = 3;
+    optional string trailing_comments = 4;
+    repeated string leading_detached_comments = 6;
+  }
+}
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+  // An Annotation connects some span of text in generated code to an element
+  // of its generating .proto file.
+  repeated Annotation annotation = 1;
+  message Annotation {
+    // Identifies the element in the original source .proto file. This field
+    // is formatted the same as SourceCodeInfo.Location.path.
+    repeated int32 path = 1 [packed = true];
+
+    // Identifies the filesystem path to the original source .proto.
+    optional string source_file = 2;
+
+    // Identifies the starting offset in bytes in the generated code
+    // that relates to the identified object.
+    optional int32 begin = 3;
+
+    // Identifies the ending offset in bytes in the generated code that
+    // relates to the identified offset. The end offset should be one past
+    // the last relevant byte (so the length of the text = end - begin).
+    optional int32 end = 4;
+  }
+}
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
new file mode 100644
index 0000000..203000d
--- /dev/null
+++ b/src/google/protobuf/descriptor_database.cc
@@ -0,0 +1,1048 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/descriptor_database.h>
+
+#include <algorithm>
+#include <set>
+
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+namespace google {
+namespace protobuf {
+
+namespace {
+void RecordMessageNames(const DescriptorProto& desc_proto,
+                        const std::string& prefix,
+                        std::set<std::string>* output) {
+  GOOGLE_CHECK(desc_proto.has_name());
+  std::string full_name = prefix.empty()
+                              ? desc_proto.name()
+                              : StrCat(prefix, ".", desc_proto.name());
+  output->insert(full_name);
+
+  for (const auto& d : desc_proto.nested_type()) {
+    RecordMessageNames(d, full_name, output);
+  }
+}
+
+void RecordMessageNames(const FileDescriptorProto& file_proto,
+                        std::set<std::string>* output) {
+  for (const auto& d : file_proto.message_type()) {
+    RecordMessageNames(d, file_proto.package(), output);
+  }
+}
+
+template <typename Fn>
+bool ForAllFileProtos(DescriptorDatabase* db, Fn callback,
+                      std::vector<std::string>* output) {
+  std::vector<std::string> file_names;
+  if (!db->FindAllFileNames(&file_names)) {
+    return false;
+  }
+  std::set<std::string> set;
+  FileDescriptorProto file_proto;
+  for (const auto& f : file_names) {
+    file_proto.Clear();
+    if (!db->FindFileByName(f, &file_proto)) {
+      GOOGLE_LOG(ERROR) << "File not found in database (unexpected): " << f;
+      return false;
+    }
+    callback(file_proto, &set);
+  }
+  output->insert(output->end(), set.begin(), set.end());
+  return true;
+}
+}  // namespace
+
+DescriptorDatabase::~DescriptorDatabase() {}
+
+bool DescriptorDatabase::FindAllPackageNames(std::vector<std::string>* output) {
+  return ForAllFileProtos(
+      this,
+      [](const FileDescriptorProto& file_proto, std::set<std::string>* set) {
+        set->insert(file_proto.package());
+      },
+      output);
+}
+
+bool DescriptorDatabase::FindAllMessageNames(std::vector<std::string>* output) {
+  return ForAllFileProtos(
+      this,
+      [](const FileDescriptorProto& file_proto, std::set<std::string>* set) {
+        RecordMessageNames(file_proto, set);
+      },
+      output);
+}
+
+// ===================================================================
+
+SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
+SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
+    const FileDescriptorProto& file, Value value) {
+  if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
+    GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
+    return false;
+  }
+
+  // We must be careful here -- calling file.package() if file.has_package() is
+  // false could access an uninitialized static-storage variable if we are being
+  // run at startup time.
+  std::string path = file.has_package() ? file.package() : std::string();
+  if (!path.empty()) path += '.';
+
+  for (int i = 0; i < file.message_type_size(); i++) {
+    if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
+    if (!AddNestedExtensions(file.name(), file.message_type(i), value))
+      return false;
+  }
+  for (int i = 0; i < file.enum_type_size(); i++) {
+    if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
+  }
+  for (int i = 0; i < file.extension_size(); i++) {
+    if (!AddSymbol(path + file.extension(i).name(), value)) return false;
+    if (!AddExtension(file.name(), file.extension(i), value)) return false;
+  }
+  for (int i = 0; i < file.service_size(); i++) {
+    if (!AddSymbol(path + file.service(i).name(), value)) return false;
+  }
+
+  return true;
+}
+
+namespace {
+
+// Returns true if and only if all characters in the name are alphanumerics,
+// underscores, or periods.
+bool ValidateSymbolName(StringPiece name) {
+  for (char c : name) {
+    // I don't trust ctype.h due to locales.  :(
+    if (c != '.' && c != '_' && (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
+        (c < 'a' || c > 'z')) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Find the last key in the container which sorts less than or equal to the
+// symbol name.  Since upper_bound() returns the *first* key that sorts
+// *greater* than the input, we want the element immediately before that.
+template <typename Container, typename Key>
+typename Container::const_iterator FindLastLessOrEqual(
+    const Container* container, const Key& key) {
+  auto iter = container->upper_bound(key);
+  if (iter != container->begin()) --iter;
+  return iter;
+}
+
+// As above, but using std::upper_bound instead.
+template <typename Container, typename Key, typename Cmp>
+typename Container::const_iterator FindLastLessOrEqual(
+    const Container* container, const Key& key, const Cmp& cmp) {
+  auto iter = std::upper_bound(container->begin(), container->end(), key, cmp);
+  if (iter != container->begin()) --iter;
+  return iter;
+}
+
+// True if either the arguments are equal or super_symbol identifies a
+// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
+// "foo.bar.baz", but not a parent of "foo.barbaz").
+bool IsSubSymbol(StringPiece sub_symbol, StringPiece super_symbol) {
+  return sub_symbol == super_symbol ||
+         (HasPrefixString(super_symbol, sub_symbol) &&
+          super_symbol[sub_symbol.size()] == '.');
+}
+
+}  // namespace
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
+    const std::string& name, Value value) {
+  // We need to make sure not to violate our map invariant.
+
+  // If the symbol name is invalid it could break our lookup algorithm (which
+  // relies on the fact that '.' sorts before all other characters that are
+  // valid in symbol names).
+  if (!ValidateSymbolName(name)) {
+    GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
+    return false;
+  }
+
+  // Try to look up the symbol to make sure a super-symbol doesn't already
+  // exist.
+  auto iter = FindLastLessOrEqual(&by_symbol_, name);
+
+  if (iter == by_symbol_.end()) {
+    // Apparently the map is currently empty.  Just insert and be done with it.
+    by_symbol_.insert(
+        typename std::map<std::string, Value>::value_type(name, value));
+    return true;
+  }
+
+  if (IsSubSymbol(iter->first, name)) {
+    GOOGLE_LOG(ERROR) << "Symbol name \"" << name
+               << "\" conflicts with the existing "
+                  "symbol \""
+               << iter->first << "\".";
+    return false;
+  }
+
+  // OK, that worked.  Now we have to make sure that no symbol in the map is
+  // a sub-symbol of the one we are inserting.  The only symbol which could
+  // be so is the first symbol that is greater than the new symbol.  Since
+  // |iter| points at the last symbol that is less than or equal, we just have
+  // to increment it.
+  ++iter;
+
+  if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
+    GOOGLE_LOG(ERROR) << "Symbol name \"" << name
+               << "\" conflicts with the existing "
+                  "symbol \""
+               << iter->first << "\".";
+    return false;
+  }
+
+  // OK, no conflicts.
+
+  // Insert the new symbol using the iterator as a hint, the new entry will
+  // appear immediately before the one the iterator is pointing at.
+  by_symbol_.insert(
+      iter, typename std::map<std::string, Value>::value_type(name, value));
+
+  return true;
+}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
+    const std::string& filename, const DescriptorProto& message_type,
+    Value value) {
+  for (int i = 0; i < message_type.nested_type_size(); i++) {
+    if (!AddNestedExtensions(filename, message_type.nested_type(i), value))
+      return false;
+  }
+  for (int i = 0; i < message_type.extension_size(); i++) {
+    if (!AddExtension(filename, message_type.extension(i), value)) return false;
+  }
+  return true;
+}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
+    const std::string& filename, const FieldDescriptorProto& field,
+    Value value) {
+  if (!field.extendee().empty() && field.extendee()[0] == '.') {
+    // The extension is fully-qualified.  We can use it as a lookup key in
+    // the by_symbol_ table.
+    if (!InsertIfNotPresent(
+            &by_extension_,
+            std::make_pair(field.extendee().substr(1), field.number()),
+            value)) {
+      GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
+                    "extend "
+                 << field.extendee() << " { " << field.name() << " = "
+                 << field.number() << " } from:" << filename;
+      return false;
+    }
+  } else {
+    // Not fully-qualified.  We can't really do anything here, unfortunately.
+    // We don't consider this an error, though, because the descriptor is
+    // valid.
+  }
+  return true;
+}
+
+template <typename Value>
+Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
+    const std::string& filename) {
+  return FindWithDefault(by_name_, filename, Value());
+}
+
+template <typename Value>
+Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
+    const std::string& name) {
+  auto iter = FindLastLessOrEqual(&by_symbol_, name);
+
+  return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name))
+             ? iter->second
+             : Value();
+}
+
+template <typename Value>
+Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
+    const std::string& containing_type, int field_number) {
+  return FindWithDefault(
+      by_extension_, std::make_pair(containing_type, field_number), Value());
+}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
+    const std::string& containing_type, std::vector<int>* output) {
+  typename std::map<std::pair<std::string, int>, Value>::const_iterator it =
+      by_extension_.lower_bound(std::make_pair(containing_type, 0));
+  bool success = false;
+
+  for (; it != by_extension_.end() && it->first.first == containing_type;
+       ++it) {
+    output->push_back(it->first.second);
+    success = true;
+  }
+
+  return success;
+}
+
+template <typename Value>
+void SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllFileNames(
+    std::vector<std::string>* output) {
+  output->resize(by_name_.size());
+  int i = 0;
+  for (const auto& kv : by_name_) {
+    (*output)[i] = kv.first;
+    i++;
+  }
+}
+
+// -------------------------------------------------------------------
+
+bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
+  FileDescriptorProto* new_file = new FileDescriptorProto;
+  new_file->CopyFrom(file);
+  return AddAndOwn(new_file);
+}
+
+bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
+  files_to_delete_.emplace_back(file);
+  return index_.AddFile(*file, file);
+}
+
+bool SimpleDescriptorDatabase::FindFileByName(const std::string& filename,
+                                              FileDescriptorProto* output) {
+  return MaybeCopy(index_.FindFile(filename), output);
+}
+
+bool SimpleDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  return MaybeCopy(index_.FindSymbol(symbol_name), output);
+}
+
+bool SimpleDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
+}
+
+bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  return index_.FindAllExtensionNumbers(extendee_type, output);
+}
+
+
+bool SimpleDescriptorDatabase::FindAllFileNames(
+    std::vector<std::string>* output) {
+  index_.FindAllFileNames(output);
+  return true;
+}
+
+bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
+                                         FileDescriptorProto* output) {
+  if (file == nullptr) return false;
+  output->CopyFrom(*file);
+  return true;
+}
+
+// -------------------------------------------------------------------
+
+class EncodedDescriptorDatabase::DescriptorIndex {
+ public:
+  using Value = std::pair<const void*, int>;
+  // Helpers to recursively add particular descriptors and all their contents
+  // to the index.
+  template <typename FileProto>
+  bool AddFile(const FileProto& file, Value value);
+
+  Value FindFile(StringPiece filename);
+  Value FindSymbol(StringPiece name);
+  Value FindSymbolOnlyFlat(StringPiece name) const;
+  Value FindExtension(StringPiece containing_type, int field_number);
+  bool FindAllExtensionNumbers(StringPiece containing_type,
+                               std::vector<int>* output);
+  void FindAllFileNames(std::vector<std::string>* output) const;
+
+ private:
+  friend class EncodedDescriptorDatabase;
+
+  bool AddSymbol(StringPiece symbol);
+
+  template <typename DescProto>
+  bool AddNestedExtensions(StringPiece filename,
+                           const DescProto& message_type);
+  template <typename FieldProto>
+  bool AddExtension(StringPiece filename, const FieldProto& field);
+
+  // All the maps below have two representations:
+  //  - a std::set<> where we insert initially.
+  //  - a std::vector<> where we flatten the structure on demand.
+  // The initial tree helps avoid O(N) behavior of inserting into a sorted
+  // vector, while the vector reduces the heap requirements of the data
+  // structure.
+
+  void EnsureFlat();
+
+  using String = std::string;
+
+  String EncodeString(StringPiece str) const { return String(str); }
+  StringPiece DecodeString(const String& str, int) const { return str; }
+
+  struct EncodedEntry {
+    // Do not use `Value` here to avoid the padding of that object.
+    const void* data;
+    int size;
+    // Keep the package here instead of each SymbolEntry to save space.
+    String encoded_package;
+
+    Value value() const { return {data, size}; }
+  };
+  std::vector<EncodedEntry> all_values_;
+
+  struct FileEntry {
+    int data_offset;
+    String encoded_name;
+
+    StringPiece name(const DescriptorIndex& index) const {
+      return index.DecodeString(encoded_name, data_offset);
+    }
+  };
+  struct FileCompare {
+    const DescriptorIndex& index;
+
+    bool operator()(const FileEntry& a, const FileEntry& b) const {
+      return a.name(index) < b.name(index);
+    }
+    bool operator()(const FileEntry& a, StringPiece b) const {
+      return a.name(index) < b;
+    }
+    bool operator()(StringPiece a, const FileEntry& b) const {
+      return a < b.name(index);
+    }
+  };
+  std::set<FileEntry, FileCompare> by_name_{FileCompare{*this}};
+  std::vector<FileEntry> by_name_flat_;
+
+  struct SymbolEntry {
+    int data_offset;
+    String encoded_symbol;
+
+    StringPiece package(const DescriptorIndex& index) const {
+      return index.DecodeString(index.all_values_[data_offset].encoded_package,
+                                data_offset);
+    }
+    StringPiece symbol(const DescriptorIndex& index) const {
+      return index.DecodeString(encoded_symbol, data_offset);
+    }
+
+    std::string AsString(const DescriptorIndex& index) const {
+      auto p = package(index);
+      return StrCat(p, p.empty() ? "" : ".", symbol(index));
+    }
+  };
+
+  struct SymbolCompare {
+    const DescriptorIndex& index;
+
+    std::string AsString(const SymbolEntry& entry) const {
+      return entry.AsString(index);
+    }
+    static StringPiece AsString(StringPiece str) { return str; }
+
+    std::pair<StringPiece, StringPiece> GetParts(
+        const SymbolEntry& entry) const {
+      auto package = entry.package(index);
+      if (package.empty()) return {entry.symbol(index), StringPiece{}};
+      return {package, entry.symbol(index)};
+    }
+    std::pair<StringPiece, StringPiece> GetParts(
+        StringPiece str) const {
+      return {str, {}};
+    }
+
+    template <typename T, typename U>
+    bool operator()(const T& lhs, const U& rhs) const {
+      auto lhs_parts = GetParts(lhs);
+      auto rhs_parts = GetParts(rhs);
+
+      // Fast path to avoid making the whole string for common cases.
+      if (int res =
+              lhs_parts.first.substr(0, rhs_parts.first.size())
+                  .compare(rhs_parts.first.substr(0, lhs_parts.first.size()))) {
+        // If the packages already differ, exit early.
+        return res < 0;
+      } else if (lhs_parts.first.size() == rhs_parts.first.size()) {
+        return lhs_parts.second < rhs_parts.second;
+      }
+      return AsString(lhs) < AsString(rhs);
+    }
+  };
+  std::set<SymbolEntry, SymbolCompare> by_symbol_{SymbolCompare{*this}};
+  std::vector<SymbolEntry> by_symbol_flat_;
+
+  struct ExtensionEntry {
+    int data_offset;
+    String encoded_extendee;
+    StringPiece extendee(const DescriptorIndex& index) const {
+      return index.DecodeString(encoded_extendee, data_offset).substr(1);
+    }
+    int extension_number;
+  };
+  struct ExtensionCompare {
+    const DescriptorIndex& index;
+
+    bool operator()(const ExtensionEntry& a, const ExtensionEntry& b) const {
+      return std::make_tuple(a.extendee(index), a.extension_number) <
+             std::make_tuple(b.extendee(index), b.extension_number);
+    }
+    bool operator()(const ExtensionEntry& a,
+                    std::tuple<StringPiece, int> b) const {
+      return std::make_tuple(a.extendee(index), a.extension_number) < b;
+    }
+    bool operator()(std::tuple<StringPiece, int> a,
+                    const ExtensionEntry& b) const {
+      return a < std::make_tuple(b.extendee(index), b.extension_number);
+    }
+  };
+  std::set<ExtensionEntry, ExtensionCompare> by_extension_{
+      ExtensionCompare{*this}};
+  std::vector<ExtensionEntry> by_extension_flat_;
+};
+
+bool EncodedDescriptorDatabase::Add(const void* encoded_file_descriptor,
+                                    int size) {
+  FileDescriptorProto file;
+  if (file.ParseFromArray(encoded_file_descriptor, size)) {
+    return index_->AddFile(file, std::make_pair(encoded_file_descriptor, size));
+  } else {
+    GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
+                  "EncodedDescriptorDatabase::Add().";
+    return false;
+  }
+}
+
+bool EncodedDescriptorDatabase::AddCopy(const void* encoded_file_descriptor,
+                                        int size) {
+  void* copy = operator new(size);
+  memcpy(copy, encoded_file_descriptor, size);
+  files_to_delete_.push_back(copy);
+  return Add(copy, size);
+}
+
+bool EncodedDescriptorDatabase::FindFileByName(const std::string& filename,
+                                               FileDescriptorProto* output) {
+  return MaybeParse(index_->FindFile(filename), output);
+}
+
+bool EncodedDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  return MaybeParse(index_->FindSymbol(symbol_name), output);
+}
+
+bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
+    const std::string& symbol_name, std::string* output) {
+  auto encoded_file = index_->FindSymbol(symbol_name);
+  if (encoded_file.first == nullptr) return false;
+
+  // Optimization:  The name should be the first field in the encoded message.
+  //   Try to just read it directly.
+  io::CodedInputStream input(static_cast<const uint8_t*>(encoded_file.first),
+                             encoded_file.second);
+
+  const uint32_t kNameTag = internal::WireFormatLite::MakeTag(
+      FileDescriptorProto::kNameFieldNumber,
+      internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+
+  if (input.ReadTagNoLastTag() == kNameTag) {
+    // Success!
+    return internal::WireFormatLite::ReadString(&input, output);
+  } else {
+    // Slow path.  Parse whole message.
+    FileDescriptorProto file_proto;
+    if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
+      return false;
+    }
+    *output = file_proto.name();
+    return true;
+  }
+}
+
+bool EncodedDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  return MaybeParse(index_->FindExtension(containing_type, field_number),
+                    output);
+}
+
+bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  return index_->FindAllExtensionNumbers(extendee_type, output);
+}
+
+template <typename FileProto>
+bool EncodedDescriptorDatabase::DescriptorIndex::AddFile(const FileProto& file,
+                                                         Value value) {
+  // We push `value` into the array first. This is important because the AddXXX
+  // functions below will expect it to be there.
+  all_values_.push_back({value.first, value.second, {}});
+
+  if (!ValidateSymbolName(file.package())) {
+    GOOGLE_LOG(ERROR) << "Invalid package name: " << file.package();
+    return false;
+  }
+  all_values_.back().encoded_package = EncodeString(file.package());
+
+  if (!InsertIfNotPresent(
+          &by_name_, FileEntry{static_cast<int>(all_values_.size() - 1),
+                               EncodeString(file.name())}) ||
+      std::binary_search(by_name_flat_.begin(), by_name_flat_.end(),
+                         file.name(), by_name_.key_comp())) {
+    GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
+    return false;
+  }
+
+  for (const auto& message_type : file.message_type()) {
+    if (!AddSymbol(message_type.name())) return false;
+    if (!AddNestedExtensions(file.name(), message_type)) return false;
+  }
+  for (const auto& enum_type : file.enum_type()) {
+    if (!AddSymbol(enum_type.name())) return false;
+  }
+  for (const auto& extension : file.extension()) {
+    if (!AddSymbol(extension.name())) return false;
+    if (!AddExtension(file.name(), extension)) return false;
+  }
+  for (const auto& service : file.service()) {
+    if (!AddSymbol(service.name())) return false;
+  }
+
+  return true;
+}
+
+template <typename Iter, typename Iter2, typename Index>
+static bool CheckForMutualSubsymbols(StringPiece symbol_name, Iter* iter,
+                                     Iter2 end, const Index& index) {
+  if (*iter != end) {
+    if (IsSubSymbol((*iter)->AsString(index), symbol_name)) {
+      GOOGLE_LOG(ERROR) << "Symbol name \"" << symbol_name
+                 << "\" conflicts with the existing symbol \""
+                 << (*iter)->AsString(index) << "\".";
+      return false;
+    }
+
+    // OK, that worked.  Now we have to make sure that no symbol in the map is
+    // a sub-symbol of the one we are inserting.  The only symbol which could
+    // be so is the first symbol that is greater than the new symbol.  Since
+    // |iter| points at the last symbol that is less than or equal, we just have
+    // to increment it.
+    ++*iter;
+
+    if (*iter != end && IsSubSymbol(symbol_name, (*iter)->AsString(index))) {
+      GOOGLE_LOG(ERROR) << "Symbol name \"" << symbol_name
+                 << "\" conflicts with the existing symbol \""
+                 << (*iter)->AsString(index) << "\".";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool EncodedDescriptorDatabase::DescriptorIndex::AddSymbol(
+    StringPiece symbol) {
+  SymbolEntry entry = {static_cast<int>(all_values_.size() - 1),
+                       EncodeString(symbol)};
+  std::string entry_as_string = entry.AsString(*this);
+
+  // We need to make sure not to violate our map invariant.
+
+  // If the symbol name is invalid it could break our lookup algorithm (which
+  // relies on the fact that '.' sorts before all other characters that are
+  // valid in symbol names).
+  if (!ValidateSymbolName(symbol)) {
+    GOOGLE_LOG(ERROR) << "Invalid symbol name: " << entry_as_string;
+    return false;
+  }
+
+  auto iter = FindLastLessOrEqual(&by_symbol_, entry);
+  if (!CheckForMutualSubsymbols(entry_as_string, &iter, by_symbol_.end(),
+                                *this)) {
+    return false;
+  }
+
+  // Same, but on by_symbol_flat_
+  auto flat_iter =
+      FindLastLessOrEqual(&by_symbol_flat_, entry, by_symbol_.key_comp());
+  if (!CheckForMutualSubsymbols(entry_as_string, &flat_iter,
+                                by_symbol_flat_.end(), *this)) {
+    return false;
+  }
+
+  // OK, no conflicts.
+
+  // Insert the new symbol using the iterator as a hint, the new entry will
+  // appear immediately before the one the iterator is pointing at.
+  by_symbol_.insert(iter, entry);
+
+  return true;
+}
+
+template <typename DescProto>
+bool EncodedDescriptorDatabase::DescriptorIndex::AddNestedExtensions(
+    StringPiece filename, const DescProto& message_type) {
+  for (const auto& nested_type : message_type.nested_type()) {
+    if (!AddNestedExtensions(filename, nested_type)) return false;
+  }
+  for (const auto& extension : message_type.extension()) {
+    if (!AddExtension(filename, extension)) return false;
+  }
+  return true;
+}
+
+template <typename FieldProto>
+bool EncodedDescriptorDatabase::DescriptorIndex::AddExtension(
+    StringPiece filename, const FieldProto& field) {
+  if (!field.extendee().empty() && field.extendee()[0] == '.') {
+    // The extension is fully-qualified.  We can use it as a lookup key in
+    // the by_symbol_ table.
+    if (!InsertIfNotPresent(
+            &by_extension_,
+            ExtensionEntry{static_cast<int>(all_values_.size() - 1),
+                           EncodeString(field.extendee()), field.number()}) ||
+        std::binary_search(
+            by_extension_flat_.begin(), by_extension_flat_.end(),
+            std::make_pair(field.extendee().substr(1), field.number()),
+            by_extension_.key_comp())) {
+      GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
+                    "extend "
+                 << field.extendee() << " { " << field.name() << " = "
+                 << field.number() << " } from:" << filename;
+      return false;
+    }
+  } else {
+    // Not fully-qualified.  We can't really do anything here, unfortunately.
+    // We don't consider this an error, though, because the descriptor is
+    // valid.
+  }
+  return true;
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindSymbol(StringPiece name) {
+  EnsureFlat();
+  return FindSymbolOnlyFlat(name);
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindSymbolOnlyFlat(
+    StringPiece name) const {
+  auto iter =
+      FindLastLessOrEqual(&by_symbol_flat_, name, by_symbol_.key_comp());
+
+  return iter != by_symbol_flat_.end() &&
+                 IsSubSymbol(iter->AsString(*this), name)
+             ? all_values_[iter->data_offset].value()
+             : Value();
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindExtension(
+    StringPiece containing_type, int field_number) {
+  EnsureFlat();
+
+  auto it = std::lower_bound(
+      by_extension_flat_.begin(), by_extension_flat_.end(),
+      std::make_tuple(containing_type, field_number), by_extension_.key_comp());
+  return it == by_extension_flat_.end() ||
+                 it->extendee(*this) != containing_type ||
+                 it->extension_number != field_number
+             ? std::make_pair(nullptr, 0)
+             : all_values_[it->data_offset].value();
+}
+
+template <typename T, typename Less>
+static void MergeIntoFlat(std::set<T, Less>* s, std::vector<T>* flat) {
+  if (s->empty()) return;
+  std::vector<T> new_flat(s->size() + flat->size());
+  std::merge(s->begin(), s->end(), flat->begin(), flat->end(), &new_flat[0],
+             s->key_comp());
+  *flat = std::move(new_flat);
+  s->clear();
+}
+
+void EncodedDescriptorDatabase::DescriptorIndex::EnsureFlat() {
+  all_values_.shrink_to_fit();
+  // Merge each of the sets into their flat counterpart.
+  MergeIntoFlat(&by_name_, &by_name_flat_);
+  MergeIntoFlat(&by_symbol_, &by_symbol_flat_);
+  MergeIntoFlat(&by_extension_, &by_extension_flat_);
+}
+
+bool EncodedDescriptorDatabase::DescriptorIndex::FindAllExtensionNumbers(
+    StringPiece containing_type, std::vector<int>* output) {
+  EnsureFlat();
+
+  bool success = false;
+  auto it = std::lower_bound(
+      by_extension_flat_.begin(), by_extension_flat_.end(),
+      std::make_tuple(containing_type, 0), by_extension_.key_comp());
+  for (;
+       it != by_extension_flat_.end() && it->extendee(*this) == containing_type;
+       ++it) {
+    output->push_back(it->extension_number);
+    success = true;
+  }
+
+  return success;
+}
+
+void EncodedDescriptorDatabase::DescriptorIndex::FindAllFileNames(
+    std::vector<std::string>* output) const {
+  output->resize(by_name_.size() + by_name_flat_.size());
+  int i = 0;
+  for (const auto& entry : by_name_) {
+    (*output)[i] = std::string(entry.name(*this));
+    i++;
+  }
+  for (const auto& entry : by_name_flat_) {
+    (*output)[i] = std::string(entry.name(*this));
+    i++;
+  }
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindFile(
+    StringPiece filename) {
+  EnsureFlat();
+
+  auto it = std::lower_bound(by_name_flat_.begin(), by_name_flat_.end(),
+                             filename, by_name_.key_comp());
+  return it == by_name_flat_.end() || it->name(*this) != filename
+             ? std::make_pair(nullptr, 0)
+             : all_values_[it->data_offset].value();
+}
+
+
+bool EncodedDescriptorDatabase::FindAllFileNames(
+    std::vector<std::string>* output) {
+  index_->FindAllFileNames(output);
+  return true;
+}
+
+bool EncodedDescriptorDatabase::MaybeParse(
+    std::pair<const void*, int> encoded_file, FileDescriptorProto* output) {
+  if (encoded_file.first == nullptr) return false;
+  return output->ParseFromArray(encoded_file.first, encoded_file.second);
+}
+
+EncodedDescriptorDatabase::EncodedDescriptorDatabase()
+    : index_(new DescriptorIndex()) {}
+
+EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
+  for (void* p : files_to_delete_) {
+    operator delete(p);
+  }
+}
+
+// ===================================================================
+
+DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
+    : pool_(pool) {}
+DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
+
+bool DescriptorPoolDatabase::FindFileByName(const std::string& filename,
+                                            FileDescriptorProto* output) {
+  const FileDescriptor* file = pool_.FindFileByName(filename);
+  if (file == nullptr) return false;
+  output->Clear();
+  file->CopyTo(output);
+  return true;
+}
+
+bool DescriptorPoolDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
+  if (file == nullptr) return false;
+  output->Clear();
+  file->CopyTo(output);
+  return true;
+}
+
+bool DescriptorPoolDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
+  if (extendee == nullptr) return false;
+
+  const FieldDescriptor* extension =
+      pool_.FindExtensionByNumber(extendee, field_number);
+  if (extension == nullptr) return false;
+
+  output->Clear();
+  extension->file()->CopyTo(output);
+  return true;
+}
+
+bool DescriptorPoolDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
+  if (extendee == nullptr) return false;
+
+  std::vector<const FieldDescriptor*> extensions;
+  pool_.FindAllExtensions(extendee, &extensions);
+
+  for (const FieldDescriptor* extension : extensions) {
+    output->push_back(extension->number());
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+MergedDescriptorDatabase::MergedDescriptorDatabase(
+    DescriptorDatabase* source1, DescriptorDatabase* source2) {
+  sources_.push_back(source1);
+  sources_.push_back(source2);
+}
+MergedDescriptorDatabase::MergedDescriptorDatabase(
+    const std::vector<DescriptorDatabase*>& sources)
+    : sources_(sources) {}
+MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
+
+bool MergedDescriptorDatabase::FindFileByName(const std::string& filename,
+                                              FileDescriptorProto* output) {
+  for (DescriptorDatabase* source : sources_) {
+    if (source->FindFileByName(filename, output)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MergedDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  for (size_t i = 0; i < sources_.size(); i++) {
+    if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
+      // The symbol was found in source i.  However, if one of the previous
+      // sources defines a file with the same name (which presumably doesn't
+      // contain the symbol, since it wasn't found in that source), then we
+      // must hide it from the caller.
+      FileDescriptorProto temp;
+      for (size_t j = 0; j < i; j++) {
+        if (sources_[j]->FindFileByName(output->name(), &temp)) {
+          // Found conflicting file in a previous source.
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MergedDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  for (size_t i = 0; i < sources_.size(); i++) {
+    if (sources_[i]->FindFileContainingExtension(containing_type, field_number,
+                                                 output)) {
+      // The symbol was found in source i.  However, if one of the previous
+      // sources defines a file with the same name (which presumably doesn't
+      // contain the symbol, since it wasn't found in that source), then we
+      // must hide it from the caller.
+      FileDescriptorProto temp;
+      for (size_t j = 0; j < i; j++) {
+        if (sources_[j]->FindFileByName(output->name(), &temp)) {
+          // Found conflicting file in a previous source.
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MergedDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  std::set<int> merged_results;
+  std::vector<int> results;
+  bool success = false;
+
+  for (DescriptorDatabase* source : sources_) {
+    if (source->FindAllExtensionNumbers(extendee_type, &results)) {
+      std::copy(results.begin(), results.end(),
+                std::insert_iterator<std::set<int> >(merged_results,
+                                                     merged_results.begin()));
+      success = true;
+    }
+    results.clear();
+  }
+
+  std::copy(merged_results.begin(), merged_results.end(),
+            std::insert_iterator<std::vector<int> >(*output, output->end()));
+
+  return success;
+}
+
+
+bool MergedDescriptorDatabase::FindAllFileNames(
+    std::vector<std::string>* output) {
+  bool implemented = false;
+  for (DescriptorDatabase* source : sources_) {
+    std::vector<std::string> source_output;
+    if (source->FindAllFileNames(&source_output)) {
+      output->reserve(output->size() + source_output.size());
+      for (auto& source : source_output) {
+        output->push_back(std::move(source));
+      }
+      implemented = true;
+    }
+  }
+  return implemented;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
new file mode 100644
index 0000000..f4f06bb
--- /dev/null
+++ b/src/google/protobuf/descriptor_database.h
@@ -0,0 +1,398 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Interface for manipulating databases of descriptors.
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
+#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
+
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class DescriptorDatabase;
+class SimpleDescriptorDatabase;
+class EncodedDescriptorDatabase;
+class DescriptorPoolDatabase;
+class MergedDescriptorDatabase;
+
+// Abstract interface for a database of descriptors.
+//
+// This is useful if you want to create a DescriptorPool which loads
+// descriptors on-demand from some sort of large database.  If the database
+// is large, it may be inefficient to enumerate every .proto file inside it
+// calling DescriptorPool::BuildFile() for each one.  Instead, a DescriptorPool
+// can be created which wraps a DescriptorDatabase and only builds particular
+// descriptors when they are needed.
+class PROTOBUF_EXPORT DescriptorDatabase {
+ public:
+  inline DescriptorDatabase() {}
+  virtual ~DescriptorDatabase();
+
+  // Find a file by file name.  Fills in in *output and returns true if found.
+  // Otherwise, returns false, leaving the contents of *output undefined.
+  virtual bool FindFileByName(const std::string& filename,
+                              FileDescriptorProto* output) = 0;
+
+  // Find the file that declares the given fully-qualified symbol name.
+  // If found, fills in *output and returns true, otherwise returns false
+  // and leaves *output undefined.
+  virtual bool FindFileContainingSymbol(const std::string& symbol_name,
+                                        FileDescriptorProto* output) = 0;
+
+  // Find the file which defines an extension extending the given message type
+  // with the given field number.  If found, fills in *output and returns true,
+  // otherwise returns false and leaves *output undefined.  containing_type
+  // must be a fully-qualified type name.
+  virtual bool FindFileContainingExtension(const std::string& containing_type,
+                                           int field_number,
+                                           FileDescriptorProto* output) = 0;
+
+  // Finds the tag numbers used by all known extensions of
+  // extendee_type, and appends them to output in an undefined
+  // order. This method is best-effort: it's not guaranteed that the
+  // database will find all extensions, and it's not guaranteed that
+  // FindFileContainingExtension will return true on all of the found
+  // numbers. Returns true if the search was successful, otherwise
+  // returns false and leaves output unchanged.
+  //
+  // This method has a default implementation that always returns
+  // false.
+  virtual bool FindAllExtensionNumbers(const std::string& /* extendee_type */,
+                                       std::vector<int>* /* output */) {
+    return false;
+  }
+
+
+  // Finds the file names and appends them to the output in an
+  // undefined order. This method is best-effort: it's not guaranteed that the
+  // database will find all files. Returns true if the database supports
+  // searching all file names, otherwise returns false and leaves output
+  // unchanged.
+  //
+  // This method has a default implementation that always returns
+  // false.
+  virtual bool FindAllFileNames(std::vector<std::string>* /*output*/) {
+    return false;
+  }
+
+  // Finds the package names and appends them to the output in an
+  // undefined order. This method is best-effort: it's not guaranteed that the
+  // database will find all packages. Returns true if the database supports
+  // searching all package names, otherwise returns false and leaves output
+  // unchanged.
+  bool FindAllPackageNames(std::vector<std::string>* output);
+
+  // Finds the message names and appends them to the output in an
+  // undefined order. This method is best-effort: it's not guaranteed that the
+  // database will find all messages. Returns true if the database supports
+  // searching all message names, otherwise returns false and leaves output
+  // unchanged.
+  bool FindAllMessageNames(std::vector<std::string>* output);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
+};
+
+// A DescriptorDatabase into which you can insert files manually.
+//
+// FindFileContainingSymbol() is fully-implemented.  When you add a file, its
+// symbols will be indexed for this purpose.  Note that the implementation
+// may return false positives, but only if it isn't possible for the symbol
+// to be defined in any other file.  In particular, if a file defines a symbol
+// "Foo", then searching for "Foo.[anything]" will match that file.  This way,
+// the database does not need to aggressively index all children of a symbol.
+//
+// FindFileContainingExtension() is mostly-implemented.  It works if and only
+// if the original FieldDescriptorProto defining the extension has a
+// fully-qualified type name in its "extendee" field (i.e. starts with a '.').
+// If the extendee is a relative name, SimpleDescriptorDatabase will not
+// attempt to resolve the type, so it will not know what type the extension is
+// extending.  Therefore, calling FindFileContainingExtension() with the
+// extension's containing type will never actually find that extension.  Note
+// that this is an unlikely problem, as all FileDescriptorProtos created by the
+// protocol compiler (as well as ones created by calling
+// FileDescriptor::CopyTo()) will always use fully-qualified names for all
+// types.  You only need to worry if you are constructing FileDescriptorProtos
+// yourself, or are calling compiler::Parser directly.
+class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
+ public:
+  SimpleDescriptorDatabase();
+  ~SimpleDescriptorDatabase() override;
+
+  // Adds the FileDescriptorProto to the database, making a copy.  The object
+  // can be deleted after Add() returns.  Returns false if the file conflicted
+  // with a file already in the database, in which case an error will have
+  // been written to GOOGLE_LOG(ERROR).
+  bool Add(const FileDescriptorProto& file);
+
+  // Adds the FileDescriptorProto to the database and takes ownership of it.
+  bool AddAndOwn(const FileDescriptorProto* file);
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+
+  bool FindAllFileNames(std::vector<std::string>* output) override;
+
+ private:
+  // An index mapping file names, symbol names, and extension numbers to
+  // some sort of values.
+  template <typename Value>
+  class DescriptorIndex {
+   public:
+    // Helpers to recursively add particular descriptors and all their contents
+    // to the index.
+    bool AddFile(const FileDescriptorProto& file, Value value);
+    bool AddSymbol(const std::string& name, Value value);
+    bool AddNestedExtensions(const std::string& filename,
+                             const DescriptorProto& message_type, Value value);
+    bool AddExtension(const std::string& filename,
+                      const FieldDescriptorProto& field, Value value);
+
+    Value FindFile(const std::string& filename);
+    Value FindSymbol(const std::string& name);
+    Value FindExtension(const std::string& containing_type, int field_number);
+    bool FindAllExtensionNumbers(const std::string& containing_type,
+                                 std::vector<int>* output);
+    void FindAllFileNames(std::vector<std::string>* output);
+
+   private:
+    std::map<std::string, Value> by_name_;
+    std::map<std::string, Value> by_symbol_;
+    std::map<std::pair<std::string, int>, Value> by_extension_;
+
+    // Invariant:  The by_symbol_ map does not contain any symbols which are
+    // prefixes of other symbols in the map.  For example, "foo.bar" is a
+    // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
+    //
+    // This invariant is important because it means that given a symbol name,
+    // we can find a key in the map which is a prefix of the symbol in O(lg n)
+    // time, and we know that there is at most one such key.
+    //
+    // The prefix lookup algorithm works like so:
+    // 1) Find the last key in the map which is less than or equal to the
+    //    search key.
+    // 2) If the found key is a prefix of the search key, then return it.
+    //    Otherwise, there is no match.
+    //
+    // I am sure this algorithm has been described elsewhere, but since I
+    // wasn't able to find it quickly I will instead prove that it works
+    // myself.  The key to the algorithm is that if a match exists, step (1)
+    // will find it.  Proof:
+    // 1) Define the "search key" to be the key we are looking for, the "found
+    //    key" to be the key found in step (1), and the "match key" to be the
+    //    key which actually matches the search key (i.e. the key we're trying
+    //    to find).
+    // 2) The found key must be less than or equal to the search key by
+    //    definition.
+    // 3) The match key must also be less than or equal to the search key
+    //    (because it is a prefix).
+    // 4) The match key cannot be greater than the found key, because if it
+    //    were, then step (1) of the algorithm would have returned the match
+    //    key instead (since it finds the *greatest* key which is less than or
+    //    equal to the search key).
+    // 5) Therefore, the found key must be between the match key and the search
+    //    key, inclusive.
+    // 6) Since the search key must be a sub-symbol of the match key, if it is
+    //    not equal to the match key, then search_key[match_key.size()] must
+    //    be '.'.
+    // 7) Since '.' sorts before any other character that is valid in a symbol
+    //    name, then if the found key is not equal to the match key, then
+    //    found_key[match_key.size()] must also be '.', because any other value
+    //    would make it sort after the search key.
+    // 8) Therefore, if the found key is not equal to the match key, then the
+    //    found key must be a sub-symbol of the match key.  However, this would
+    //    contradict our map invariant which says that no symbol in the map is
+    //    a sub-symbol of any other.
+    // 9) Therefore, the found key must match the match key.
+    //
+    // The above proof assumes the match key exists.  In the case that the
+    // match key does not exist, then step (1) will return some other symbol.
+    // That symbol cannot be a super-symbol of the search key since if it were,
+    // then it would be a match, and we're assuming the match key doesn't exist.
+    // Therefore, step 2 will correctly return no match.
+  };
+
+  DescriptorIndex<const FileDescriptorProto*> index_;
+  std::vector<std::unique_ptr<const FileDescriptorProto>> files_to_delete_;
+
+  // If file is non-nullptr, copy it into *output and return true, otherwise
+  // return false.
+  bool MaybeCopy(const FileDescriptorProto* file, FileDescriptorProto* output);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
+};
+
+// Very similar to SimpleDescriptorDatabase, but stores all the descriptors
+// as raw bytes and generally tries to use as little memory as possible.
+//
+// The same caveats regarding FindFileContainingExtension() apply as with
+// SimpleDescriptorDatabase.
+class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
+ public:
+  EncodedDescriptorDatabase();
+  ~EncodedDescriptorDatabase() override;
+
+  // Adds the FileDescriptorProto to the database.  The descriptor is provided
+  // in encoded form.  The database does not make a copy of the bytes, nor
+  // does it take ownership; it's up to the caller to make sure the bytes
+  // remain valid for the life of the database.  Returns false and logs an error
+  // if the bytes are not a valid FileDescriptorProto or if the file conflicted
+  // with a file already in the database.
+  bool Add(const void* encoded_file_descriptor, int size);
+
+  // Like Add(), but makes a copy of the data, so that the caller does not
+  // need to keep it around.
+  bool AddCopy(const void* encoded_file_descriptor, int size);
+
+  // Like FindFileContainingSymbol but returns only the name of the file.
+  bool FindNameOfFileContainingSymbol(const std::string& symbol_name,
+                                      std::string* output);
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+  bool FindAllFileNames(std::vector<std::string>* output) override;
+
+ private:
+  class DescriptorIndex;
+  // Keep DescriptorIndex by pointer to hide the implementation to keep a
+  // cleaner header.
+  std::unique_ptr<DescriptorIndex> index_;
+  std::vector<void*> files_to_delete_;
+
+  // If encoded_file.first is non-nullptr, parse the data into *output and
+  // return true, otherwise return false.
+  bool MaybeParse(std::pair<const void*, int> encoded_file,
+                  FileDescriptorProto* output);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase);
+};
+
+// A DescriptorDatabase that fetches files from a given pool.
+class PROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
+ public:
+  explicit DescriptorPoolDatabase(const DescriptorPool& pool);
+  ~DescriptorPoolDatabase() override;
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+
+ private:
+  const DescriptorPool& pool_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase);
+};
+
+// A DescriptorDatabase that wraps two or more others.  It first searches the
+// first database and, if that fails, tries the second, and so on.
+class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
+ public:
+  // Merge just two databases.  The sources remain property of the caller.
+  MergedDescriptorDatabase(DescriptorDatabase* source1,
+                           DescriptorDatabase* source2);
+  // 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.
+  explicit MergedDescriptorDatabase(
+      const std::vector<DescriptorDatabase*>& sources);
+  ~MergedDescriptorDatabase() override;
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  // Merges the results of calling all databases. Returns true iff any
+  // of the databases returned true.
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+
+
+  // This function is best-effort. Returns true if at least one underlying
+  // DescriptorDatabase returns true.
+  bool FindAllFileNames(std::vector<std::string>* output) override;
+
+ private:
+  std::vector<DescriptorDatabase*> sources_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
new file mode 100644
index 0000000..f582448
--- /dev/null
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -0,0 +1,812 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 makes extensive use of RFC 3092.  :)
+
+#include <google/protobuf/descriptor_database.h>
+
+#include <algorithm>
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/text_format.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+
+namespace google {
+namespace protobuf {
+namespace {
+
+static void AddToDatabase(SimpleDescriptorDatabase* database,
+                          const char* file_text) {
+  FileDescriptorProto file_proto;
+  EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+  database->Add(file_proto);
+}
+
+static void ExpectContainsType(const FileDescriptorProto& proto,
+                               const std::string& type_name) {
+  for (int i = 0; i < proto.message_type_size(); i++) {
+    if (proto.message_type(i).name() == type_name) return;
+  }
+  ADD_FAILURE() << "\"" << proto.name() << "\" did not contain expected type \""
+                << type_name << "\".";
+}
+
+// ===================================================================
+
+#if GTEST_HAS_PARAM_TEST
+
+// SimpleDescriptorDatabase, EncodedDescriptorDatabase, and
+// DescriptorPoolDatabase call for very similar tests.  Instead of writing
+// three nearly-identical sets of tests, we use parameterized tests to apply
+// the same code to all three.
+
+// The parameterized test runs against a DescriptorDatabaseTestCase.  We have
+// implementations for each of the three classes we want to test.
+class DescriptorDatabaseTestCase {
+ public:
+  virtual ~DescriptorDatabaseTestCase() {}
+
+  virtual DescriptorDatabase* GetDatabase() = 0;
+  virtual bool AddToDatabase(const FileDescriptorProto& file) = 0;
+};
+
+// Factory function type.
+typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory();
+
+// Specialization for SimpleDescriptorDatabase.
+class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
+ public:
+  static DescriptorDatabaseTestCase* New() {
+    return new SimpleDescriptorDatabaseTestCase;
+  }
+
+  virtual ~SimpleDescriptorDatabaseTestCase() {}
+
+  virtual DescriptorDatabase* GetDatabase() { return &database_; }
+  virtual bool AddToDatabase(const FileDescriptorProto& file) {
+    return database_.Add(file);
+  }
+
+ private:
+  SimpleDescriptorDatabase database_;
+};
+
+// Specialization for EncodedDescriptorDatabase.
+class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
+ public:
+  static DescriptorDatabaseTestCase* New() {
+    return new EncodedDescriptorDatabaseTestCase;
+  }
+
+  virtual ~EncodedDescriptorDatabaseTestCase() {}
+
+  virtual DescriptorDatabase* GetDatabase() { return &database_; }
+  virtual bool AddToDatabase(const FileDescriptorProto& file) {
+    std::string data;
+    file.SerializeToString(&data);
+    return database_.AddCopy(data.data(), data.size());
+  }
+
+ private:
+  EncodedDescriptorDatabase database_;
+};
+
+// Specialization for DescriptorPoolDatabase.
+class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase {
+ public:
+  static DescriptorDatabaseTestCase* New() {
+    return new EncodedDescriptorDatabaseTestCase;
+  }
+
+  DescriptorPoolDatabaseTestCase() : database_(pool_) {}
+  virtual ~DescriptorPoolDatabaseTestCase() {}
+
+  virtual DescriptorDatabase* GetDatabase() { return &database_; }
+  virtual bool AddToDatabase(const FileDescriptorProto& file) {
+    return pool_.BuildFile(file);
+  }
+
+ private:
+  DescriptorPool pool_;
+  DescriptorPoolDatabase database_;
+};
+
+// -------------------------------------------------------------------
+
+class DescriptorDatabaseTest
+    : public testing::TestWithParam<DescriptorDatabaseTestCaseFactory*> {
+ protected:
+  virtual void SetUp() {
+    test_case_.reset(GetParam()());
+    database_ = test_case_->GetDatabase();
+  }
+
+  void AddToDatabase(const char* file_descriptor_text) {
+    FileDescriptorProto file_proto;
+    EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
+    EXPECT_TRUE(test_case_->AddToDatabase(file_proto));
+  }
+
+  void AddToDatabaseWithError(const char* file_descriptor_text) {
+    FileDescriptorProto file_proto;
+    EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
+    EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
+  }
+
+  std::unique_ptr<DescriptorDatabaseTestCase> test_case_;
+  DescriptorDatabase* database_;
+};
+
+TEST_P(DescriptorDatabaseTest, FindFileByName) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "message_type { name:\"Foo\" }");
+  AddToDatabase(
+      "name: \"bar.proto\" "
+      "message_type { name:\"Bar\" }");
+
+  {
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileByName("foo.proto", &file));
+    EXPECT_EQ("foo.proto", file.name());
+    ExpectContainsType(file, "Foo");
+  }
+
+  {
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileByName("bar.proto", &file));
+    EXPECT_EQ("bar.proto", file.name());
+    ExpectContainsType(file, "Bar");
+  }
+
+  {
+    // Fails to find undefined files.
+    FileDescriptorProto file;
+    EXPECT_FALSE(database_->FindFileByName("baz.proto", &file));
+  }
+}
+
+TEST_P(DescriptorDatabaseTest, FindFileContainingSymbol) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "  field { name:\"qux\" }"
+      "  nested_type { name: \"Grault\" } "
+      "  enum_type { name: \"Garply\" } "
+      "} "
+      "enum_type { "
+      "  name: \"Waldo\" "
+      "  value { name:\"FRED\" } "
+      "} "
+      "extension { name: \"plugh\" } "
+      "service { "
+      "  name: \"Xyzzy\" "
+      "  method { name: \"Thud\" } "
+      "}");
+  AddToDatabase(
+      "name: \"bar.proto\" "
+      "package: \"corge\" "
+      "message_type { name: \"Bar\" }");
+
+  {
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Foo", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find fields.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.qux", &file));
+    EXPECT_EQ("foo.proto", file.name());
+    // Non-existent field under a valid top level symbol can also be
+    // found.
+    EXPECT_TRUE(
+        database_->FindFileContainingSymbol("Foo.none_field.none", &file));
+  }
+
+  {
+    // Can find nested types.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Grault", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find nested enums.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Garply", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find enum types.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find enum values.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo.FRED", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find extensions.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("plugh", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find services.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find methods.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy.Thud", &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    // Can find things in packages.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingSymbol("corge.Bar", &file));
+    EXPECT_EQ("bar.proto", file.name());
+  }
+
+  {
+    // Fails to find undefined symbols.
+    FileDescriptorProto file;
+    EXPECT_FALSE(database_->FindFileContainingSymbol("Baz", &file));
+  }
+
+  {
+    // Names must be fully-qualified.
+    FileDescriptorProto file;
+    EXPECT_FALSE(database_->FindFileContainingSymbol("Bar", &file));
+  }
+}
+
+TEST_P(DescriptorDatabaseTest, FindFileContainingExtension) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "  extension_range { start: 1 end: 1000 } "
+      "  extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "number:5 "
+      "              extendee: \".Foo\" }"
+      "}");
+  AddToDatabase(
+      "name: \"bar.proto\" "
+      "package: \"corge\" "
+      "dependency: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Bar\" "
+      "  extension_range { start: 1 end: 1000 } "
+      "} "
+      "extension { name:\"grault\" extendee: \".Foo\"       number:32 } "
+      "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
+      "extension { name:\"waldo\"  extendee: \"Bar\"        number:56 } ");
+
+  {
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 5, &file));
+    EXPECT_EQ("foo.proto", file.name());
+  }
+
+  {
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 32, &file));
+    EXPECT_EQ("bar.proto", file.name());
+  }
+
+  {
+    // Can find extensions for qualified type names.
+    FileDescriptorProto file;
+    EXPECT_TRUE(database_->FindFileContainingExtension("corge.Bar", 70, &file));
+    EXPECT_EQ("bar.proto", file.name());
+  }
+
+  {
+    // Can't find extensions whose extendee was not fully-qualified in the
+    // FileDescriptorProto.
+    FileDescriptorProto file;
+    EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 56, &file));
+    EXPECT_FALSE(
+        database_->FindFileContainingExtension("corge.Bar", 56, &file));
+  }
+
+  {
+    // Can't find non-existent extension numbers.
+    FileDescriptorProto file;
+    EXPECT_FALSE(database_->FindFileContainingExtension("Foo", 12, &file));
+  }
+
+  {
+    // Can't find extensions for non-existent types.
+    FileDescriptorProto file;
+    EXPECT_FALSE(
+        database_->FindFileContainingExtension("NoSuchType", 5, &file));
+  }
+
+  {
+    // Can't find extensions for unqualified type names.
+    FileDescriptorProto file;
+    EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 70, &file));
+  }
+}
+
+TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "  extension_range { start: 1 end: 1000 } "
+      "  extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "number:5 "
+      "              extendee: \".Foo\" }"
+      "}");
+  AddToDatabase(
+      "name: \"bar.proto\" "
+      "package: \"corge\" "
+      "dependency: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Bar\" "
+      "  extension_range { start: 1 end: 1000 } "
+      "} "
+      "extension { name:\"grault\" extendee: \".Foo\"       number:32 } "
+      "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
+      "extension { name:\"waldo\"  extendee: \"Bar\"        number:56 } ");
+
+  {
+    std::vector<int> numbers;
+    EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
+    ASSERT_EQ(2, numbers.size());
+    std::sort(numbers.begin(), numbers.end());
+    EXPECT_EQ(5, numbers[0]);
+    EXPECT_EQ(32, numbers[1]);
+  }
+
+  {
+    std::vector<int> numbers;
+    EXPECT_TRUE(database_->FindAllExtensionNumbers("corge.Bar", &numbers));
+    // Note: won't find extension 56 due to the name not being fully qualified.
+    ASSERT_EQ(1, numbers.size());
+    EXPECT_EQ(70, numbers[0]);
+  }
+
+  {
+    // Can't find extensions for non-existent types.
+    std::vector<int> numbers;
+    EXPECT_FALSE(database_->FindAllExtensionNumbers("NoSuchType", &numbers));
+  }
+
+  {
+    // Can't find extensions for unqualified types.
+    std::vector<int> numbers;
+    EXPECT_FALSE(database_->FindAllExtensionNumbers("Bar", &numbers));
+  }
+}
+
+TEST_P(DescriptorDatabaseTest, ConflictingFileError) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "}");
+  AddToDatabaseWithError(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Bar\" "
+      "}");
+}
+
+TEST_P(DescriptorDatabaseTest, ConflictingTypeError) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "}");
+  AddToDatabaseWithError(
+      "name: \"bar.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "}");
+}
+
+TEST_P(DescriptorDatabaseTest, ConflictingExtensionError) {
+  AddToDatabase(
+      "name: \"foo.proto\" "
+      "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
+      "            extendee: \".Foo\" }");
+  AddToDatabaseWithError(
+      "name: \"bar.proto\" "
+      "extension { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
+      "            extendee: \".Foo\" }");
+}
+
+INSTANTIATE_TEST_CASE_P(
+    Simple, DescriptorDatabaseTest,
+    testing::Values(&SimpleDescriptorDatabaseTestCase::New));
+INSTANTIATE_TEST_CASE_P(
+    MemoryConserving, DescriptorDatabaseTest,
+    testing::Values(&EncodedDescriptorDatabaseTestCase::New));
+INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest,
+                        testing::Values(&DescriptorPoolDatabaseTestCase::New));
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) {
+  // Create two files, one of which is in two parts.
+  FileDescriptorProto file1, file2a, file2b;
+  file1.set_name("foo.proto");
+  file1.set_package("foo");
+  file1.add_message_type()->set_name("Foo");
+  file2a.set_name("bar.proto");
+  file2b.set_package("bar");
+  file2b.add_message_type()->set_name("Bar");
+
+  // Normal serialization allows our optimization to kick in.
+  std::string data1 = file1.SerializeAsString();
+
+  // Force out-of-order serialization to test slow path.
+  std::string data2 = file2b.SerializeAsString() + file2a.SerializeAsString();
+
+  // Create EncodedDescriptorDatabase containing both files.
+  EncodedDescriptorDatabase db;
+  db.Add(data1.data(), data1.size());
+  db.Add(data2.data(), data2.size());
+
+  // Test!
+  std::string filename;
+  EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename));
+  EXPECT_EQ("foo.proto", filename);
+  EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename));
+  EXPECT_EQ("foo.proto", filename);
+  EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename));
+  EXPECT_EQ("bar.proto", filename);
+  EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename));
+  EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename));
+  EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename));
+}
+
+TEST(SimpleDescriptorDatabaseExtraTest, FindAllFileNames) {
+  FileDescriptorProto f;
+  f.set_name("foo.proto");
+  f.set_package("foo");
+  f.add_message_type()->set_name("Foo");
+
+  SimpleDescriptorDatabase db;
+  db.Add(f);
+
+  // Test!
+  std::vector<std::string> all_files;
+  db.FindAllFileNames(&all_files);
+  EXPECT_THAT(all_files, testing::ElementsAre("foo.proto"));
+}
+
+TEST(SimpleDescriptorDatabaseExtraTest, FindAllPackageNames) {
+  FileDescriptorProto f;
+  f.set_name("foo.proto");
+  f.set_package("foo");
+  f.add_message_type()->set_name("Foo");
+
+  FileDescriptorProto b;
+  b.set_name("bar.proto");
+  b.set_package("");
+  b.add_message_type()->set_name("Bar");
+
+  SimpleDescriptorDatabase db;
+  db.Add(f);
+  db.Add(b);
+
+  std::vector<std::string> packages;
+  EXPECT_TRUE(db.FindAllPackageNames(&packages));
+  EXPECT_THAT(packages, ::testing::UnorderedElementsAre("foo", ""));
+}
+
+TEST(SimpleDescriptorDatabaseExtraTest, FindAllMessageNames) {
+  FileDescriptorProto f;
+  f.set_name("foo.proto");
+  f.set_package("foo");
+  f.add_message_type()->set_name("Foo");
+
+  FileDescriptorProto b;
+  b.set_name("bar.proto");
+  b.set_package("");
+  b.add_message_type()->set_name("Bar");
+
+  SimpleDescriptorDatabase db;
+  db.Add(f);
+  db.Add(b);
+
+  std::vector<std::string> messages;
+  EXPECT_TRUE(db.FindAllMessageNames(&messages));
+  EXPECT_THAT(messages, ::testing::UnorderedElementsAre("foo.Foo", "Bar"));
+}
+
+// ===================================================================
+
+class MergedDescriptorDatabaseTest : public testing::Test {
+ protected:
+  MergedDescriptorDatabaseTest()
+      : forward_merged_(&database1_, &database2_),
+        reverse_merged_(&database2_, &database1_) {}
+
+  void SetUp() override {
+    AddToDatabase(
+        &database1_,
+        "name: \"foo.proto\" "
+        "message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
+        "extension { name:\"foo_ext\" extendee: \".Foo\" number:3 "
+        "            label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+    AddToDatabase(
+        &database2_,
+        "name: \"bar.proto\" "
+        "message_type { name:\"Bar\" extension_range { start: 1 end: 100 } } "
+        "extension { name:\"bar_ext\" extendee: \".Bar\" number:5 "
+        "            label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+
+    // baz.proto exists in both pools, with different definitions.
+    AddToDatabase(
+        &database1_,
+        "name: \"baz.proto\" "
+        "message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
+        "message_type { name:\"FromPool1\" } "
+        "extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
+        "            label:LABEL_OPTIONAL type:TYPE_INT32 } "
+        "extension { name:\"database1_only_ext\" extendee: \".Baz\" number:13 "
+        "            label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+    AddToDatabase(
+        &database2_,
+        "name: \"baz.proto\" "
+        "message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
+        "message_type { name:\"FromPool2\" } "
+        "extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
+        "            label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+  }
+
+  SimpleDescriptorDatabase database1_;
+  SimpleDescriptorDatabase database2_;
+
+  MergedDescriptorDatabase forward_merged_;
+  MergedDescriptorDatabase reverse_merged_;
+};
+
+TEST_F(MergedDescriptorDatabaseTest, FindFileByName) {
+  {
+    // Can find file that is only in database1_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileByName("foo.proto", &file));
+    EXPECT_EQ("foo.proto", file.name());
+    ExpectContainsType(file, "Foo");
+  }
+
+  {
+    // Can find file that is only in database2_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileByName("bar.proto", &file));
+    EXPECT_EQ("bar.proto", file.name());
+    ExpectContainsType(file, "Bar");
+  }
+
+  {
+    // In forward_merged_, database1_'s baz.proto takes precedence.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileByName("baz.proto", &file));
+    EXPECT_EQ("baz.proto", file.name());
+    ExpectContainsType(file, "FromPool1");
+  }
+
+  {
+    // In reverse_merged_, database2_'s baz.proto takes precedence.
+    FileDescriptorProto file;
+    EXPECT_TRUE(reverse_merged_.FindFileByName("baz.proto", &file));
+    EXPECT_EQ("baz.proto", file.name());
+    ExpectContainsType(file, "FromPool2");
+  }
+
+  {
+    // Can't find non-existent file.
+    FileDescriptorProto file;
+    EXPECT_FALSE(forward_merged_.FindFileByName("no_such.proto", &file));
+  }
+}
+
+TEST_F(MergedDescriptorDatabaseTest, FindFileContainingSymbol) {
+  {
+    // Can find file that is only in database1_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Foo", &file));
+    EXPECT_EQ("foo.proto", file.name());
+    ExpectContainsType(file, "Foo");
+  }
+
+  {
+    // Can find file that is only in database2_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Bar", &file));
+    EXPECT_EQ("bar.proto", file.name());
+    ExpectContainsType(file, "Bar");
+  }
+
+  {
+    // In forward_merged_, database1_'s baz.proto takes precedence.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Baz", &file));
+    EXPECT_EQ("baz.proto", file.name());
+    ExpectContainsType(file, "FromPool1");
+  }
+
+  {
+    // In reverse_merged_, database2_'s baz.proto takes precedence.
+    FileDescriptorProto file;
+    EXPECT_TRUE(reverse_merged_.FindFileContainingSymbol("Baz", &file));
+    EXPECT_EQ("baz.proto", file.name());
+    ExpectContainsType(file, "FromPool2");
+  }
+
+  {
+    // FromPool1 only shows up in forward_merged_ because it is masked by
+    // database2_'s baz.proto in reverse_merged_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("FromPool1", &file));
+    EXPECT_FALSE(reverse_merged_.FindFileContainingSymbol("FromPool1", &file));
+  }
+
+  {
+    // Can't find non-existent symbol.
+    FileDescriptorProto file;
+    EXPECT_FALSE(forward_merged_.FindFileContainingSymbol("NoSuchType", &file));
+  }
+}
+
+TEST_F(MergedDescriptorDatabaseTest, FindFileContainingExtension) {
+  {
+    // Can find file that is only in database1_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Foo", 3, &file));
+    EXPECT_EQ("foo.proto", file.name());
+    ExpectContainsType(file, "Foo");
+  }
+
+  {
+    // Can find file that is only in database2_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Bar", 5, &file));
+    EXPECT_EQ("bar.proto", file.name());
+    ExpectContainsType(file, "Bar");
+  }
+
+  {
+    // In forward_merged_, database1_'s baz.proto takes precedence.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Baz", 12, &file));
+    EXPECT_EQ("baz.proto", file.name());
+    ExpectContainsType(file, "FromPool1");
+  }
+
+  {
+    // In reverse_merged_, database2_'s baz.proto takes precedence.
+    FileDescriptorProto file;
+    EXPECT_TRUE(reverse_merged_.FindFileContainingExtension("Baz", 12, &file));
+    EXPECT_EQ("baz.proto", file.name());
+    ExpectContainsType(file, "FromPool2");
+  }
+
+  {
+    // Baz's extension 13 only shows up in forward_merged_ because it is
+    // masked by database2_'s baz.proto in reverse_merged_.
+    FileDescriptorProto file;
+    EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Baz", 13, &file));
+    EXPECT_FALSE(reverse_merged_.FindFileContainingExtension("Baz", 13, &file));
+  }
+
+  {
+    // Can't find non-existent extension.
+    FileDescriptorProto file;
+    EXPECT_FALSE(forward_merged_.FindFileContainingExtension("Foo", 6, &file));
+  }
+}
+
+TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
+  {
+    // Message only has extension in database1_
+    std::vector<int> numbers;
+    EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Foo", &numbers));
+    ASSERT_EQ(1, numbers.size());
+    EXPECT_EQ(3, numbers[0]);
+  }
+
+  {
+    // Message only has extension in database2_
+    std::vector<int> numbers;
+    EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Bar", &numbers));
+    ASSERT_EQ(1, numbers.size());
+    EXPECT_EQ(5, numbers[0]);
+  }
+
+  {
+    // Merge results from the two databases.
+    std::vector<int> numbers;
+    EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
+    ASSERT_EQ(2, numbers.size());
+    std::sort(numbers.begin(), numbers.end());
+    EXPECT_EQ(12, numbers[0]);
+    EXPECT_EQ(13, numbers[1]);
+  }
+
+  {
+    std::vector<int> numbers;
+    EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
+    ASSERT_EQ(2, numbers.size());
+    std::sort(numbers.begin(), numbers.end());
+    EXPECT_EQ(12, numbers[0]);
+    EXPECT_EQ(13, numbers[1]);
+  }
+
+  {
+    // Can't find extensions for a non-existent message.
+    std::vector<int> numbers;
+    EXPECT_FALSE(reverse_merged_.FindAllExtensionNumbers("Blah", &numbers));
+  }
+}
+
+TEST_F(MergedDescriptorDatabaseTest, FindAllFileNames) {
+  std::vector<std::string> files;
+  EXPECT_TRUE(forward_merged_.FindAllFileNames(&files));
+  EXPECT_THAT(files, ::testing::UnorderedElementsAre("foo.proto", "bar.proto",
+                                                     "baz.proto", "baz.proto"));
+}
+
+
+}  // anonymous namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
new file mode 100644
index 0000000..dc47531
--- /dev/null
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -0,0 +1,8430 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 makes extensive use of RFC 3092.  :)
+
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/compiler/parser.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/unittest_lazy_dependencies.pb.h>
+#include <google/protobuf/unittest_proto3_arena.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/substitute.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+using ::testing::AnyOf;
+
+namespace google {
+namespace protobuf {
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace descriptor_unittest {
+
+// Some helpers to make assembling descriptors faster.
+DescriptorProto* AddMessage(FileDescriptorProto* file,
+                            const std::string& name) {
+  DescriptorProto* result = file->add_message_type();
+  result->set_name(name);
+  return result;
+}
+
+DescriptorProto* AddNestedMessage(DescriptorProto* parent,
+                                  const std::string& name) {
+  DescriptorProto* result = parent->add_nested_type();
+  result->set_name(name);
+  return result;
+}
+
+EnumDescriptorProto* AddEnum(FileDescriptorProto* file,
+                             const std::string& name) {
+  EnumDescriptorProto* result = file->add_enum_type();
+  result->set_name(name);
+  return result;
+}
+
+EnumDescriptorProto* AddNestedEnum(DescriptorProto* parent,
+                                   const std::string& name) {
+  EnumDescriptorProto* result = parent->add_enum_type();
+  result->set_name(name);
+  return result;
+}
+
+ServiceDescriptorProto* AddService(FileDescriptorProto* file,
+                                   const std::string& name) {
+  ServiceDescriptorProto* result = file->add_service();
+  result->set_name(name);
+  return result;
+}
+
+FieldDescriptorProto* AddField(DescriptorProto* parent, const std::string& name,
+                               int number, FieldDescriptorProto::Label label,
+                               FieldDescriptorProto::Type type) {
+  FieldDescriptorProto* result = parent->add_field();
+  result->set_name(name);
+  result->set_number(number);
+  result->set_label(label);
+  result->set_type(type);
+  return result;
+}
+
+FieldDescriptorProto* AddExtension(FileDescriptorProto* file,
+                                   const std::string& extendee,
+                                   const std::string& name, int number,
+                                   FieldDescriptorProto::Label label,
+                                   FieldDescriptorProto::Type type) {
+  FieldDescriptorProto* result = file->add_extension();
+  result->set_name(name);
+  result->set_number(number);
+  result->set_label(label);
+  result->set_type(type);
+  result->set_extendee(extendee);
+  return result;
+}
+
+FieldDescriptorProto* AddNestedExtension(DescriptorProto* parent,
+                                         const std::string& extendee,
+                                         const std::string& name, int number,
+                                         FieldDescriptorProto::Label label,
+                                         FieldDescriptorProto::Type type) {
+  FieldDescriptorProto* result = parent->add_extension();
+  result->set_name(name);
+  result->set_number(number);
+  result->set_label(label);
+  result->set_type(type);
+  result->set_extendee(extendee);
+  return result;
+}
+
+DescriptorProto::ExtensionRange* AddExtensionRange(DescriptorProto* parent,
+                                                   int start, int end) {
+  DescriptorProto::ExtensionRange* result = parent->add_extension_range();
+  result->set_start(start);
+  result->set_end(end);
+  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;
+}
+
+EnumDescriptorProto::EnumReservedRange* AddReservedRange(
+    EnumDescriptorProto* parent, int start, int end) {
+  EnumDescriptorProto::EnumReservedRange* result = parent->add_reserved_range();
+  result->set_start(start);
+  result->set_end(end);
+  return result;
+}
+
+EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
+                                       const std::string& name, int number) {
+  EnumValueDescriptorProto* result = enum_proto->add_value();
+  result->set_name(name);
+  result->set_number(number);
+  return result;
+}
+
+MethodDescriptorProto* AddMethod(ServiceDescriptorProto* service,
+                                 const std::string& name,
+                                 const std::string& input_type,
+                                 const std::string& output_type) {
+  MethodDescriptorProto* result = service->add_method();
+  result->set_name(name);
+  result->set_input_type(input_type);
+  result->set_output_type(output_type);
+  return result;
+}
+
+// Empty enums technically aren't allowed.  We need to insert a dummy value
+// into them.
+void AddEmptyEnum(FileDescriptorProto* file, const std::string& name) {
+  AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
+}
+
+class MockErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() override {}
+
+  std::string text_;
+  std::string warning_text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const std::string& filename, const std::string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const std::string& message) override {
+    const char* location_name = nullptr;
+    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 IMPORT:
+        location_name = "IMPORT";
+        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 std::string& filename, const std::string& element_name,
+                  const Message* descriptor, ErrorLocation location,
+                  const std::string& message) override {
+    const char* location_name = nullptr;
+    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 IMPORT:
+        location_name = "IMPORT";
+        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.
+class FileDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   // in "foo.proto"
+    //   message FooMessage { extensions 1; }
+    //   enum FooEnum {FOO_ENUM_VALUE = 1;}
+    //   service FooService {}
+    //   extend FooMessage { optional int32 foo_extension = 1; }
+    //
+    //   // in "bar.proto"
+    //   package bar_package;
+    //   message BarMessage { extensions 1; }
+    //   enum BarEnum {BAR_ENUM_VALUE = 1;}
+    //   service BarService {}
+    //   extend BarMessage { optional int32 bar_extension = 1; }
+    //
+    // Also, we have an empty file "baz.proto".  This file's purpose is to
+    // make sure that even though it has the same package as foo.proto,
+    // searching it for members of foo.proto won't work.
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+    AddExtensionRange(AddMessage(&foo_file, "FooMessage"), 1, 2);
+    AddEnumValue(AddEnum(&foo_file, "FooEnum"), "FOO_ENUM_VALUE", 1);
+    AddService(&foo_file, "FooService");
+    AddExtension(&foo_file, "FooMessage", "foo_extension", 1,
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+
+    FileDescriptorProto bar_file;
+    bar_file.set_name("bar.proto");
+    bar_file.set_package("bar_package");
+    bar_file.add_dependency("foo.proto");
+    AddExtensionRange(AddMessage(&bar_file, "BarMessage"), 1, 2);
+    AddEnumValue(AddEnum(&bar_file, "BarEnum"), "BAR_ENUM_VALUE", 1);
+    AddService(&bar_file, "BarService");
+    AddExtension(&bar_file, "bar_package.BarMessage", "bar_extension", 1,
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+
+    FileDescriptorProto baz_file;
+    baz_file.set_name("baz.proto");
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    bar_file_ = pool_.BuildFile(bar_file);
+    ASSERT_TRUE(bar_file_ != nullptr);
+
+    baz_file_ = pool_.BuildFile(baz_file);
+    ASSERT_TRUE(baz_file_ != nullptr);
+
+    ASSERT_EQ(1, foo_file_->message_type_count());
+    foo_message_ = foo_file_->message_type(0);
+    ASSERT_EQ(1, foo_file_->enum_type_count());
+    foo_enum_ = foo_file_->enum_type(0);
+    ASSERT_EQ(1, foo_enum_->value_count());
+    foo_enum_value_ = foo_enum_->value(0);
+    ASSERT_EQ(1, foo_file_->service_count());
+    foo_service_ = foo_file_->service(0);
+    ASSERT_EQ(1, foo_file_->extension_count());
+    foo_extension_ = foo_file_->extension(0);
+
+    ASSERT_EQ(1, bar_file_->message_type_count());
+    bar_message_ = bar_file_->message_type(0);
+    ASSERT_EQ(1, bar_file_->enum_type_count());
+    bar_enum_ = bar_file_->enum_type(0);
+    ASSERT_EQ(1, bar_enum_->value_count());
+    bar_enum_value_ = bar_enum_->value(0);
+    ASSERT_EQ(1, bar_file_->service_count());
+    bar_service_ = bar_file_->service(0);
+    ASSERT_EQ(1, bar_file_->extension_count());
+    bar_extension_ = bar_file_->extension(0);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* foo_file_;
+  const FileDescriptor* bar_file_;
+  const FileDescriptor* baz_file_;
+
+  const Descriptor* foo_message_;
+  const EnumDescriptor* foo_enum_;
+  const EnumValueDescriptor* foo_enum_value_;
+  const ServiceDescriptor* foo_service_;
+  const FieldDescriptor* foo_extension_;
+
+  const Descriptor* bar_message_;
+  const EnumDescriptor* bar_enum_;
+  const EnumValueDescriptor* bar_enum_value_;
+  const ServiceDescriptor* bar_service_;
+  const FieldDescriptor* bar_extension_;
+};
+
+TEST_F(FileDescriptorTest, Name) {
+  EXPECT_EQ("foo.proto", foo_file_->name());
+  EXPECT_EQ("bar.proto", bar_file_->name());
+  EXPECT_EQ("baz.proto", baz_file_->name());
+}
+
+TEST_F(FileDescriptorTest, Package) {
+  EXPECT_EQ("", foo_file_->package());
+  EXPECT_EQ("bar_package", bar_file_->package());
+}
+
+TEST_F(FileDescriptorTest, Dependencies) {
+  EXPECT_EQ(0, foo_file_->dependency_count());
+  EXPECT_EQ(1, bar_file_->dependency_count());
+  EXPECT_EQ(foo_file_, bar_file_->dependency(0));
+}
+
+TEST_F(FileDescriptorTest, FindMessageTypeByName) {
+  EXPECT_EQ(foo_message_, foo_file_->FindMessageTypeByName("FooMessage"));
+  EXPECT_EQ(bar_message_, bar_file_->FindMessageTypeByName("BarMessage"));
+
+  EXPECT_TRUE(foo_file_->FindMessageTypeByName("BarMessage") == nullptr);
+  EXPECT_TRUE(bar_file_->FindMessageTypeByName("FooMessage") == nullptr);
+  EXPECT_TRUE(baz_file_->FindMessageTypeByName("FooMessage") == nullptr);
+
+  EXPECT_TRUE(foo_file_->FindMessageTypeByName("NoSuchMessage") == nullptr);
+  EXPECT_TRUE(foo_file_->FindMessageTypeByName("FooEnum") == nullptr);
+}
+
+TEST_F(FileDescriptorTest, FindEnumTypeByName) {
+  EXPECT_EQ(foo_enum_, foo_file_->FindEnumTypeByName("FooEnum"));
+  EXPECT_EQ(bar_enum_, bar_file_->FindEnumTypeByName("BarEnum"));
+
+  EXPECT_TRUE(foo_file_->FindEnumTypeByName("BarEnum") == nullptr);
+  EXPECT_TRUE(bar_file_->FindEnumTypeByName("FooEnum") == nullptr);
+  EXPECT_TRUE(baz_file_->FindEnumTypeByName("FooEnum") == nullptr);
+
+  EXPECT_TRUE(foo_file_->FindEnumTypeByName("NoSuchEnum") == nullptr);
+  EXPECT_TRUE(foo_file_->FindEnumTypeByName("FooMessage") == nullptr);
+}
+
+TEST_F(FileDescriptorTest, FindEnumValueByName) {
+  EXPECT_EQ(foo_enum_value_, foo_file_->FindEnumValueByName("FOO_ENUM_VALUE"));
+  EXPECT_EQ(bar_enum_value_, bar_file_->FindEnumValueByName("BAR_ENUM_VALUE"));
+
+  EXPECT_TRUE(foo_file_->FindEnumValueByName("BAR_ENUM_VALUE") == nullptr);
+  EXPECT_TRUE(bar_file_->FindEnumValueByName("FOO_ENUM_VALUE") == nullptr);
+  EXPECT_TRUE(baz_file_->FindEnumValueByName("FOO_ENUM_VALUE") == nullptr);
+
+  EXPECT_TRUE(foo_file_->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(foo_file_->FindEnumValueByName("FooMessage") == nullptr);
+}
+
+TEST_F(FileDescriptorTest, FindServiceByName) {
+  EXPECT_EQ(foo_service_, foo_file_->FindServiceByName("FooService"));
+  EXPECT_EQ(bar_service_, bar_file_->FindServiceByName("BarService"));
+
+  EXPECT_TRUE(foo_file_->FindServiceByName("BarService") == nullptr);
+  EXPECT_TRUE(bar_file_->FindServiceByName("FooService") == nullptr);
+  EXPECT_TRUE(baz_file_->FindServiceByName("FooService") == nullptr);
+
+  EXPECT_TRUE(foo_file_->FindServiceByName("NoSuchService") == nullptr);
+  EXPECT_TRUE(foo_file_->FindServiceByName("FooMessage") == nullptr);
+}
+
+TEST_F(FileDescriptorTest, FindExtensionByName) {
+  EXPECT_EQ(foo_extension_, foo_file_->FindExtensionByName("foo_extension"));
+  EXPECT_EQ(bar_extension_, bar_file_->FindExtensionByName("bar_extension"));
+
+  EXPECT_TRUE(foo_file_->FindExtensionByName("bar_extension") == nullptr);
+  EXPECT_TRUE(bar_file_->FindExtensionByName("foo_extension") == nullptr);
+  EXPECT_TRUE(baz_file_->FindExtensionByName("foo_extension") == nullptr);
+
+  EXPECT_TRUE(foo_file_->FindExtensionByName("no_such_extension") == nullptr);
+  EXPECT_TRUE(foo_file_->FindExtensionByName("FooMessage") == nullptr);
+}
+
+TEST_F(FileDescriptorTest, FindExtensionByNumber) {
+  EXPECT_EQ(foo_extension_, pool_.FindExtensionByNumber(foo_message_, 1));
+  EXPECT_EQ(bar_extension_, pool_.FindExtensionByNumber(bar_message_, 1));
+
+  EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == nullptr);
+}
+
+
+TEST_F(FileDescriptorTest, BuildAgain) {
+  // Test that if we call BuildFile again on the same input we get the same
+  // FileDescriptor back.
+  FileDescriptorProto file;
+  foo_file_->CopyTo(&file);
+  EXPECT_EQ(foo_file_, pool_.BuildFile(file));
+
+  // But if we change the file then it won't work.
+  file.set_package("some.other.package");
+  EXPECT_TRUE(pool_.BuildFile(file) == nullptr);
+}
+
+TEST_F(FileDescriptorTest, BuildAgainWithSyntax) {
+  // Test that if we 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 != nullptr);
+  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 != nullptr);
+  // 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 != nullptr);
+  EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3));
+}
+
+TEST_F(FileDescriptorTest, Syntax) {
+  FileDescriptorProto proto;
+  proto.set_name("foo");
+  // Enable the test when we also populate the syntax for proto2.
+#if 0
+  {
+    proto.set_syntax("proto2");
+    DescriptorPool pool;
+    const FileDescriptor* file = pool.BuildFile(proto);
+    EXPECT_TRUE(file != nullptr);
+    EXPECT_EQ(FileDescriptor::SYNTAX_PROTO2, file->syntax());
+    FileDescriptorProto other;
+    file->CopyTo(&other);
+    EXPECT_EQ("proto2", other.syntax());
+  }
+#endif
+  {
+    proto.set_syntax("proto3");
+    DescriptorPool pool;
+    const FileDescriptor* file = pool.BuildFile(proto);
+    EXPECT_TRUE(file != nullptr);
+    EXPECT_EQ(FileDescriptor::SYNTAX_PROTO3, file->syntax());
+    FileDescriptorProto other;
+    file->CopyTo(&other);
+    EXPECT_EQ("proto3", other.syntax());
+  }
+}
+
+void ExtractDebugString(
+    const FileDescriptor* file, std::set<std::string>* visited,
+    std::vector<std::pair<std::string, std::string>>* debug_strings) {
+  if (!visited->insert(file->name()).second) {
+    return;
+  }
+  for (int i = 0; i < file->dependency_count(); ++i) {
+    ExtractDebugString(file->dependency(i), visited, debug_strings);
+  }
+  debug_strings->push_back(std::make_pair(file->name(), file->DebugString()));
+}
+
+class SimpleErrorCollector : public io::ErrorCollector {
+ public:
+  // implements ErrorCollector ---------------------------------------
+  void AddError(int line, int column, const std::string& message) override {
+    last_error_ = StringPrintf("%d:%d:", line, column) + message;
+  }
+
+  const std::string& last_error() { return last_error_; }
+
+ private:
+  std::string last_error_;
+};
+// Test that the result of FileDescriptor::DebugString() can be used to create
+// the original descriptors.
+TEST_F(FileDescriptorTest, DebugStringRoundTrip) {
+  std::set<std::string> visited;
+  std::vector<std::pair<std::string, std::string>> debug_strings;
+  ExtractDebugString(protobuf_unittest::TestAllTypes::descriptor()->file(),
+                     &visited, &debug_strings);
+  ExtractDebugString(
+      protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file(),
+      &visited, &debug_strings);
+  ExtractDebugString(proto3_arena_unittest::TestAllTypes::descriptor()->file(),
+                     &visited, &debug_strings);
+  ASSERT_GE(debug_strings.size(), 3);
+
+  DescriptorPool pool;
+  for (int i = 0; i < debug_strings.size(); ++i) {
+    const std::string& name = debug_strings[i].first;
+    const std::string& content = debug_strings[i].second;
+    io::ArrayInputStream input_stream(content.data(), content.size());
+    SimpleErrorCollector error_collector;
+    io::Tokenizer tokenizer(&input_stream, &error_collector);
+    compiler::Parser parser;
+    parser.RecordErrorsTo(&error_collector);
+    FileDescriptorProto proto;
+    ASSERT_TRUE(parser.Parse(&tokenizer, &proto))
+        << error_collector.last_error() << "\n"
+        << content;
+    ASSERT_EQ("", error_collector.last_error());
+    proto.set_name(name);
+    const FileDescriptor* descriptor = pool.BuildFile(proto);
+    ASSERT_TRUE(descriptor != nullptr) << proto.DebugString();
+    EXPECT_EQ(content, descriptor->DebugString());
+  }
+}
+
+// ===================================================================
+
+// Test simple flat messages and fields.
+class DescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   // in "foo.proto"
+    //   message TestForeign {}
+    //   enum TestEnum {}
+    //
+    //   message TestMessage {
+    //     required string      foo = 1;
+    //     optional TestEnum    bar = 6;
+    //     repeated TestForeign baz = 500000000;
+    //     optional group       moo = 15 {}
+    //   }
+    //
+    //   // in "bar.proto"
+    //   package corge.grault;
+    //   message TestMessage2 {
+    //     required string foo = 1;
+    //     required string bar = 2;
+    //     required string mooo = 6;
+    //   }
+    //
+    //   // in "map.proto"
+    //   message TestMessage3 {
+    //     map<int32, int32> map_int32_int32 = 1;
+    //   }
+    //
+    //   // in "json.proto"
+    //   message TestMessage4 {
+    //     optional int32 field_name1 = 1;
+    //     optional int32 fieldName2 = 2;
+    //     optional int32 FieldName3 = 3;
+    //     optional int32 _field_name4 = 4;
+    //     optional int32 FIELD_NAME5 = 5;
+    //     optional int32 field_name6 = 6 [json_name = "@type"];
+    //   }
+    //
+    // We cheat and use TestForeign as the type for moo rather than create
+    // an actual nested type.
+    //
+    // Since all primitive types (including string) use the same building
+    // code, there's no need to test each one individually.
+    //
+    // TestMessage2 is primarily here to test FindFieldByName and friends.
+    // All messages created from the same DescriptorPool share the same lookup
+    // table, so we need to insure that they don't interfere.
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+    AddMessage(&foo_file, "TestForeign");
+    AddEmptyEnum(&foo_file, "TestEnum");
+
+    DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
+    AddField(message, "foo", 1, FieldDescriptorProto::LABEL_REQUIRED,
+             FieldDescriptorProto::TYPE_STRING);
+    AddField(message, "bar", 6, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_ENUM)
+        ->set_type_name("TestEnum");
+    AddField(message, "baz", 500000000, FieldDescriptorProto::LABEL_REPEATED,
+             FieldDescriptorProto::TYPE_MESSAGE)
+        ->set_type_name("TestForeign");
+    AddField(message, "moo", 15, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_GROUP)
+        ->set_type_name("TestForeign");
+
+    FileDescriptorProto bar_file;
+    bar_file.set_name("bar.proto");
+    bar_file.set_package("corge.grault");
+
+    DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
+    AddField(message2, "foo", 1, FieldDescriptorProto::LABEL_REQUIRED,
+             FieldDescriptorProto::TYPE_STRING);
+    AddField(message2, "bar", 2, FieldDescriptorProto::LABEL_REQUIRED,
+             FieldDescriptorProto::TYPE_STRING);
+    AddField(message2, "mooo", 6, FieldDescriptorProto::LABEL_REQUIRED,
+             FieldDescriptorProto::TYPE_STRING);
+
+    FileDescriptorProto map_file;
+    map_file.set_name("map.proto");
+    DescriptorProto* message3 = AddMessage(&map_file, "TestMessage3");
+
+    DescriptorProto* entry = AddNestedMessage(message3, "MapInt32Int32Entry");
+    AddField(entry, "key", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(entry, "value", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    entry->mutable_options()->set_map_entry(true);
+
+    AddField(message3, "map_int32_int32", 1,
+             FieldDescriptorProto::LABEL_REPEATED,
+             FieldDescriptorProto::TYPE_MESSAGE)
+        ->set_type_name("MapInt32Int32Entry");
+
+    FileDescriptorProto json_file;
+    json_file.set_name("json.proto");
+    json_file.set_syntax("proto3");
+    DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4");
+    AddField(message4, "field_name1", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "fieldName2", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "FieldName3", 3, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "_field_name4", 4, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "FIELD_NAME5", 5, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "field_name6", 6, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32)
+        ->set_json_name("@type");
+    AddField(message4, "fieldname7", 7, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    bar_file_ = pool_.BuildFile(bar_file);
+    ASSERT_TRUE(bar_file_ != nullptr);
+
+    map_file_ = pool_.BuildFile(map_file);
+    ASSERT_TRUE(map_file_ != nullptr);
+
+    json_file_ = pool_.BuildFile(json_file);
+    ASSERT_TRUE(json_file_ != nullptr);
+
+    ASSERT_EQ(1, foo_file_->enum_type_count());
+    enum_ = foo_file_->enum_type(0);
+
+    ASSERT_EQ(2, foo_file_->message_type_count());
+    foreign_ = foo_file_->message_type(0);
+    message_ = foo_file_->message_type(1);
+
+    ASSERT_EQ(4, message_->field_count());
+    foo_ = message_->field(0);
+    bar_ = message_->field(1);
+    baz_ = message_->field(2);
+    moo_ = message_->field(3);
+
+    ASSERT_EQ(1, bar_file_->message_type_count());
+    message2_ = bar_file_->message_type(0);
+
+    ASSERT_EQ(3, message2_->field_count());
+    foo2_ = message2_->field(0);
+    bar2_ = message2_->field(1);
+    mooo2_ = message2_->field(2);
+
+    ASSERT_EQ(1, map_file_->message_type_count());
+    message3_ = map_file_->message_type(0);
+
+    ASSERT_EQ(1, message3_->field_count());
+    map_ = message3_->field(0);
+
+    ASSERT_EQ(1, json_file_->message_type_count());
+    message4_ = json_file_->message_type(0);
+  }
+
+  void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) {
+    message->CopyTo(proto);
+    message->CopyJsonNameTo(proto);
+  }
+
+  const EnumValueDescriptor* FindValueByNumberCreatingIfUnknown(
+      const EnumDescriptor* desc, int number) {
+    return desc->FindValueByNumberCreatingIfUnknown(number);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* foo_file_;
+  const FileDescriptor* bar_file_;
+  const FileDescriptor* map_file_;
+  const FileDescriptor* json_file_;
+
+  const Descriptor* message_;
+  const Descriptor* message2_;
+  const Descriptor* message3_;
+  const Descriptor* message4_;
+  const Descriptor* foreign_;
+  const EnumDescriptor* enum_;
+
+  const FieldDescriptor* foo_;
+  const FieldDescriptor* bar_;
+  const FieldDescriptor* baz_;
+  const FieldDescriptor* moo_;
+
+  const FieldDescriptor* foo2_;
+  const FieldDescriptor* bar2_;
+  const FieldDescriptor* mooo2_;
+
+  const FieldDescriptor* map_;
+};
+
+TEST_F(DescriptorTest, Name) {
+  EXPECT_EQ("TestMessage", message_->name());
+  EXPECT_EQ("TestMessage", message_->full_name());
+  EXPECT_EQ(foo_file_, message_->file());
+
+  EXPECT_EQ("TestMessage2", message2_->name());
+  EXPECT_EQ("corge.grault.TestMessage2", message2_->full_name());
+  EXPECT_EQ(bar_file_, message2_->file());
+}
+
+TEST_F(DescriptorTest, ContainingType) {
+  EXPECT_TRUE(message_->containing_type() == nullptr);
+  EXPECT_TRUE(message2_->containing_type() == nullptr);
+}
+
+TEST_F(DescriptorTest, FieldNamesDedup) {
+  const auto collect_unique_names = [](const FieldDescriptor* field) {
+    std::set<std::string> names{field->name(), field->lowercase_name(),
+                                field->camelcase_name(), field->json_name()};
+    // Verify that we have the same number of string objects as we have string
+    // values. That is, duplicate names use the same std::string object.
+    // This is for memory efficiency.
+    EXPECT_EQ(names.size(), (std::set<const std::string*>{
+                                &field->name(), &field->lowercase_name(),
+                                &field->camelcase_name(), &field->json_name()}
+                                 .size()))
+        << testing::PrintToString(names);
+    return names;
+  };
+
+  using testing::ElementsAre;
+  // field_name1
+  EXPECT_THAT(collect_unique_names(message4_->field(0)),
+              ElementsAre("fieldName1", "field_name1"));
+  // fieldName2
+  EXPECT_THAT(collect_unique_names(message4_->field(1)),
+              ElementsAre("fieldName2", "fieldname2"));
+  // FieldName3
+  EXPECT_THAT(collect_unique_names(message4_->field(2)),
+              ElementsAre("FieldName3", "fieldName3", "fieldname3"));
+  // _field_name4
+  EXPECT_THAT(collect_unique_names(message4_->field(3)),
+              ElementsAre("FieldName4", "_field_name4", "fieldName4"));
+  // FIELD_NAME5
+  EXPECT_THAT(
+      collect_unique_names(message4_->field(4)),
+      ElementsAre("FIELDNAME5", "FIELD_NAME5", "fIELDNAME5", "field_name5"));
+  // field_name6, with json name @type
+  EXPECT_THAT(collect_unique_names(message4_->field(5)),
+              ElementsAre("@type", "fieldName6", "field_name6"));
+  // fieldname7
+  EXPECT_THAT(collect_unique_names(message4_->field(6)),
+              ElementsAre("fieldname7"));
+}
+
+TEST_F(DescriptorTest, FieldNameDedupJsonEqFull) {
+  // Test a regression where json_name == full_name
+  FileDescriptorProto proto;
+  proto.set_name("file");
+  auto* message = AddMessage(&proto, "Name1");
+  auto* field =
+      AddField(message, "Name2", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_INT32);
+  field->set_json_name("Name1.Name2");
+  auto* file = pool_.BuildFile(proto);
+  EXPECT_EQ(file->message_type(0)->name(), "Name1");
+  EXPECT_EQ(file->message_type(0)->field(0)->name(), "Name2");
+  EXPECT_EQ(file->message_type(0)->field(0)->full_name(), "Name1.Name2");
+  EXPECT_EQ(file->message_type(0)->field(0)->json_name(), "Name1.Name2");
+}
+
+TEST_F(DescriptorTest, FieldsByIndex) {
+  ASSERT_EQ(4, message_->field_count());
+  EXPECT_EQ(foo_, message_->field(0));
+  EXPECT_EQ(bar_, message_->field(1));
+  EXPECT_EQ(baz_, message_->field(2));
+  EXPECT_EQ(moo_, message_->field(3));
+}
+
+TEST_F(DescriptorTest, FindFieldByName) {
+  // All messages in the same DescriptorPool share a single lookup table for
+  // fields.  So, in addition to testing that FindFieldByName finds the fields
+  // of the message, we need to test that it does *not* find the fields of
+  // *other* messages.
+
+  EXPECT_EQ(foo_, message_->FindFieldByName("foo"));
+  EXPECT_EQ(bar_, message_->FindFieldByName("bar"));
+  EXPECT_EQ(baz_, message_->FindFieldByName("baz"));
+  EXPECT_EQ(moo_, message_->FindFieldByName("moo"));
+  EXPECT_TRUE(message_->FindFieldByName("no_such_field") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByName("mooo") == nullptr);
+
+  EXPECT_EQ(foo2_, message2_->FindFieldByName("foo"));
+  EXPECT_EQ(bar2_, message2_->FindFieldByName("bar"));
+  EXPECT_EQ(mooo2_, message2_->FindFieldByName("mooo"));
+  EXPECT_TRUE(message2_->FindFieldByName("baz") == nullptr);
+  EXPECT_TRUE(message2_->FindFieldByName("moo") == nullptr);
+}
+
+TEST_F(DescriptorTest, FindFieldByNumber) {
+  EXPECT_EQ(foo_, message_->FindFieldByNumber(1));
+  EXPECT_EQ(bar_, message_->FindFieldByNumber(6));
+  EXPECT_EQ(baz_, message_->FindFieldByNumber(500000000));
+  EXPECT_EQ(moo_, message_->FindFieldByNumber(15));
+  EXPECT_TRUE(message_->FindFieldByNumber(837592) == nullptr);
+  EXPECT_TRUE(message_->FindFieldByNumber(2) == nullptr);
+
+  EXPECT_EQ(foo2_, message2_->FindFieldByNumber(1));
+  EXPECT_EQ(bar2_, message2_->FindFieldByNumber(2));
+  EXPECT_EQ(mooo2_, message2_->FindFieldByNumber(6));
+  EXPECT_TRUE(message2_->FindFieldByNumber(15) == nullptr);
+  EXPECT_TRUE(message2_->FindFieldByNumber(500000000) == nullptr);
+}
+
+TEST_F(DescriptorTest, FieldName) {
+  EXPECT_EQ("foo", foo_->name());
+  EXPECT_EQ("bar", bar_->name());
+  EXPECT_EQ("baz", baz_->name());
+  EXPECT_EQ("moo", moo_->name());
+}
+
+TEST_F(DescriptorTest, FieldFullName) {
+  EXPECT_EQ("TestMessage.foo", foo_->full_name());
+  EXPECT_EQ("TestMessage.bar", bar_->full_name());
+  EXPECT_EQ("TestMessage.baz", baz_->full_name());
+  EXPECT_EQ("TestMessage.moo", moo_->full_name());
+
+  EXPECT_EQ("corge.grault.TestMessage2.foo", foo2_->full_name());
+  EXPECT_EQ("corge.grault.TestMessage2.bar", bar2_->full_name());
+  EXPECT_EQ("corge.grault.TestMessage2.mooo", mooo2_->full_name());
+}
+
+TEST_F(DescriptorTest, PrintableNameIsFullNameForNonExtensionFields) {
+  EXPECT_EQ("TestMessage.foo", foo_->PrintableNameForExtension());
+  EXPECT_EQ("TestMessage.bar", bar_->PrintableNameForExtension());
+  EXPECT_EQ("TestMessage.baz", baz_->PrintableNameForExtension());
+  EXPECT_EQ("TestMessage.moo", moo_->PrintableNameForExtension());
+
+  EXPECT_EQ("corge.grault.TestMessage2.foo",
+            foo2_->PrintableNameForExtension());
+  EXPECT_EQ("corge.grault.TestMessage2.bar",
+            bar2_->PrintableNameForExtension());
+  EXPECT_EQ("corge.grault.TestMessage2.mooo",
+            mooo2_->PrintableNameForExtension());
+}
+
+TEST_F(DescriptorTest, PrintableNameIsFullNameForNonMessageSetExtension) {
+  EXPECT_EQ("protobuf_unittest.Aggregate.nested",
+            protobuf_unittest::Aggregate::descriptor()
+                ->FindExtensionByName("nested")
+                ->PrintableNameForExtension());
+}
+
+TEST_F(DescriptorTest, PrintableNameIsExtendingTypeForMessageSetExtension) {
+  EXPECT_EQ("protobuf_unittest.AggregateMessageSetElement",
+            protobuf_unittest::AggregateMessageSetElement::descriptor()
+                ->FindExtensionByName("message_set_extension")
+                ->PrintableNameForExtension());
+}
+
+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(7, 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());
+  EXPECT_FALSE(proto.field(6).has_json_name());
+
+  proto.Clear();
+  CopyWithJsonName(message4_, &proto);
+  ASSERT_EQ(7, 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());
+  EXPECT_EQ("fieldname7", proto.field(6).json_name());
+
+  // Test generated descriptor.
+  const Descriptor* generated = protobuf_unittest::TestJsonName::descriptor();
+  ASSERT_EQ(7, generated->field_count());
+  EXPECT_EQ("fieldName1", generated->field(0)->json_name());
+  EXPECT_EQ("fieldName2", generated->field(1)->json_name());
+  EXPECT_EQ("FieldName3", generated->field(2)->json_name());
+  EXPECT_EQ("FieldName4", generated->field(3)->json_name());
+  EXPECT_EQ("FIELDNAME5", generated->field(4)->json_name());
+  EXPECT_EQ("@type", generated->field(5)->json_name());
+  EXPECT_EQ("fieldname7", generated->field(6)->json_name());
+}
+
+TEST_F(DescriptorTest, FieldFile) {
+  EXPECT_EQ(foo_file_, foo_->file());
+  EXPECT_EQ(foo_file_, bar_->file());
+  EXPECT_EQ(foo_file_, baz_->file());
+  EXPECT_EQ(foo_file_, moo_->file());
+
+  EXPECT_EQ(bar_file_, foo2_->file());
+  EXPECT_EQ(bar_file_, bar2_->file());
+  EXPECT_EQ(bar_file_, mooo2_->file());
+}
+
+TEST_F(DescriptorTest, FieldIndex) {
+  EXPECT_EQ(0, foo_->index());
+  EXPECT_EQ(1, bar_->index());
+  EXPECT_EQ(2, baz_->index());
+  EXPECT_EQ(3, moo_->index());
+}
+
+TEST_F(DescriptorTest, FieldNumber) {
+  EXPECT_EQ(1, foo_->number());
+  EXPECT_EQ(6, bar_->number());
+  EXPECT_EQ(500000000, baz_->number());
+  EXPECT_EQ(15, moo_->number());
+}
+
+TEST_F(DescriptorTest, FieldType) {
+  EXPECT_EQ(FieldDescriptor::TYPE_STRING, foo_->type());
+  EXPECT_EQ(FieldDescriptor::TYPE_ENUM, bar_->type());
+  EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_->type());
+  EXPECT_EQ(FieldDescriptor::TYPE_GROUP, moo_->type());
+}
+
+TEST_F(DescriptorTest, FieldLabel) {
+  EXPECT_EQ(FieldDescriptor::LABEL_REQUIRED, foo_->label());
+  EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->label());
+  EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, baz_->label());
+  EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, moo_->label());
+
+  EXPECT_TRUE(foo_->is_required());
+  EXPECT_FALSE(foo_->is_optional());
+  EXPECT_FALSE(foo_->is_repeated());
+
+  EXPECT_FALSE(bar_->is_required());
+  EXPECT_TRUE(bar_->is_optional());
+  EXPECT_FALSE(bar_->is_repeated());
+
+  EXPECT_FALSE(baz_->is_required());
+  EXPECT_FALSE(baz_->is_optional());
+  EXPECT_TRUE(baz_->is_repeated());
+}
+
+TEST_F(DescriptorTest, IsMap) {
+  EXPECT_TRUE(map_->is_map());
+  EXPECT_FALSE(baz_->is_map());
+  EXPECT_TRUE(map_->message_type()->options().map_entry());
+}
+
+TEST_F(DescriptorTest, GetMap) {
+  const Descriptor* map_desc = map_->message_type();
+  const FieldDescriptor* map_key = map_desc->map_key();
+  ASSERT_TRUE(map_key != nullptr);
+  EXPECT_EQ(map_key->name(), "key");
+  EXPECT_EQ(map_key->number(), 1);
+
+  const FieldDescriptor* map_value = map_desc->map_value();
+  ASSERT_TRUE(map_value != nullptr);
+  EXPECT_EQ(map_value->name(), "value");
+  EXPECT_EQ(map_value->number(), 2);
+
+  EXPECT_EQ(message_->map_key(), nullptr);
+  EXPECT_EQ(message_->map_value(), nullptr);
+}
+
+TEST_F(DescriptorTest, FieldHasDefault) {
+  EXPECT_FALSE(foo_->has_default_value());
+  EXPECT_FALSE(bar_->has_default_value());
+  EXPECT_FALSE(baz_->has_default_value());
+  EXPECT_FALSE(moo_->has_default_value());
+}
+
+TEST_F(DescriptorTest, FieldContainingType) {
+  EXPECT_EQ(message_, foo_->containing_type());
+  EXPECT_EQ(message_, bar_->containing_type());
+  EXPECT_EQ(message_, baz_->containing_type());
+  EXPECT_EQ(message_, moo_->containing_type());
+
+  EXPECT_EQ(message2_, foo2_->containing_type());
+  EXPECT_EQ(message2_, bar2_->containing_type());
+  EXPECT_EQ(message2_, mooo2_->containing_type());
+}
+
+TEST_F(DescriptorTest, FieldMessageType) {
+  EXPECT_TRUE(foo_->message_type() == nullptr);
+  EXPECT_TRUE(bar_->message_type() == nullptr);
+
+  EXPECT_EQ(foreign_, baz_->message_type());
+  EXPECT_EQ(foreign_, moo_->message_type());
+}
+
+TEST_F(DescriptorTest, FieldEnumType) {
+  EXPECT_TRUE(foo_->enum_type() == nullptr);
+  EXPECT_TRUE(baz_->enum_type() == nullptr);
+  EXPECT_TRUE(moo_->enum_type() == nullptr);
+
+  EXPECT_EQ(enum_, bar_->enum_type());
+}
+
+
+// ===================================================================
+
+// Test simple flat messages and fields.
+class OneofDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   package garply;
+    //   message TestOneof {
+    //     optional int32 a = 1;
+    //     oneof foo {
+    //       string b = 2;
+    //       TestOneof c = 3;
+    //     }
+    //     oneof bar {
+    //       float d = 4;
+    //     }
+    //   }
+
+    FileDescriptorProto baz_file;
+    baz_file.set_name("baz.proto");
+    baz_file.set_package("garply");
+
+    DescriptorProto* oneof_message = AddMessage(&baz_file, "TestOneof");
+    oneof_message->add_oneof_decl()->set_name("foo");
+    oneof_message->add_oneof_decl()->set_name("bar");
+
+    AddField(oneof_message, "a", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(oneof_message, "b", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_STRING);
+    oneof_message->mutable_field(1)->set_oneof_index(0);
+    AddField(oneof_message, "c", 3, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_MESSAGE);
+    oneof_message->mutable_field(2)->set_oneof_index(0);
+    oneof_message->mutable_field(2)->set_type_name("TestOneof");
+
+    AddField(oneof_message, "d", 4, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_FLOAT);
+    oneof_message->mutable_field(3)->set_oneof_index(1);
+
+    // Build the descriptors and get the pointers.
+    baz_file_ = pool_.BuildFile(baz_file);
+    ASSERT_TRUE(baz_file_ != nullptr);
+
+    ASSERT_EQ(1, baz_file_->message_type_count());
+    oneof_message_ = baz_file_->message_type(0);
+
+    ASSERT_EQ(2, oneof_message_->oneof_decl_count());
+    oneof_ = oneof_message_->oneof_decl(0);
+    oneof2_ = oneof_message_->oneof_decl(1);
+
+    ASSERT_EQ(4, oneof_message_->field_count());
+    a_ = oneof_message_->field(0);
+    b_ = oneof_message_->field(1);
+    c_ = oneof_message_->field(2);
+    d_ = oneof_message_->field(3);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* baz_file_;
+
+  const Descriptor* oneof_message_;
+
+  const OneofDescriptor* oneof_;
+  const OneofDescriptor* oneof2_;
+  const FieldDescriptor* a_;
+  const FieldDescriptor* b_;
+  const FieldDescriptor* c_;
+  const FieldDescriptor* d_;
+};
+
+TEST_F(OneofDescriptorTest, Normal) {
+  EXPECT_EQ("foo", oneof_->name());
+  EXPECT_EQ("garply.TestOneof.foo", oneof_->full_name());
+  EXPECT_EQ(0, oneof_->index());
+  ASSERT_EQ(2, oneof_->field_count());
+  EXPECT_EQ(b_, oneof_->field(0));
+  EXPECT_EQ(c_, oneof_->field(1));
+  EXPECT_TRUE(a_->containing_oneof() == nullptr);
+  EXPECT_EQ(oneof_, b_->containing_oneof());
+  EXPECT_EQ(oneof_, c_->containing_oneof());
+}
+
+TEST_F(OneofDescriptorTest, FindByName) {
+  EXPECT_EQ(oneof_, oneof_message_->FindOneofByName("foo"));
+  EXPECT_EQ(oneof2_, oneof_message_->FindOneofByName("bar"));
+  EXPECT_TRUE(oneof_message_->FindOneofByName("no_such_oneof") == nullptr);
+}
+
+// ===================================================================
+
+class StylizedFieldNamesTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    FileDescriptorProto file;
+    file.set_name("foo.proto");
+
+    AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000);
+
+    DescriptorProto* message = AddMessage(&file, "TestMessage");
+    AddField(message, "foo_foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message, "FooBar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message, "fooBaz", 3, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message, "fooFoo", 4,  // Camel-case conflict with foo_foo.
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message, "foobar", 5,  // Lower-case conflict with FooBar.
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+
+    AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1,
+                       FieldDescriptorProto::LABEL_OPTIONAL,
+                       FieldDescriptorProto::TYPE_INT32);
+    AddNestedExtension(message, "ExtendableMessage", "BarBar", 2,
+                       FieldDescriptorProto::LABEL_OPTIONAL,
+                       FieldDescriptorProto::TYPE_INT32);
+    AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3,
+                       FieldDescriptorProto::LABEL_OPTIONAL,
+                       FieldDescriptorProto::TYPE_INT32);
+    AddNestedExtension(message, "ExtendableMessage", "barFoo", 4,  // Conflict
+                       FieldDescriptorProto::LABEL_OPTIONAL,
+                       FieldDescriptorProto::TYPE_INT32);
+    AddNestedExtension(message, "ExtendableMessage", "barbar", 5,  // Conflict
+                       FieldDescriptorProto::LABEL_OPTIONAL,
+                       FieldDescriptorProto::TYPE_INT32);
+
+    AddExtension(&file, "ExtendableMessage", "baz_foo", 11,
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+    AddExtension(&file, "ExtendableMessage", "BazBar", 12,
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+    AddExtension(&file, "ExtendableMessage", "BazBaz", 13,
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+    AddExtension(&file, "ExtendableMessage", "bazFoo", 14,  // Conflict
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+    AddExtension(&file, "ExtendableMessage", "bazbar", 15,  // Conflict
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+
+    file_ = pool_.BuildFile(file);
+    ASSERT_TRUE(file_ != nullptr);
+    ASSERT_EQ(2, file_->message_type_count());
+    message_ = file_->message_type(1);
+    ASSERT_EQ("TestMessage", message_->name());
+    ASSERT_EQ(5, message_->field_count());
+    ASSERT_EQ(5, message_->extension_count());
+    ASSERT_EQ(5, file_->extension_count());
+  }
+
+  DescriptorPool pool_;
+  const FileDescriptor* file_;
+  const Descriptor* message_;
+};
+
+TEST_F(StylizedFieldNamesTest, LowercaseName) {
+  EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name());
+  EXPECT_EQ("foobar", message_->field(1)->lowercase_name());
+  EXPECT_EQ("foobaz", message_->field(2)->lowercase_name());
+  EXPECT_EQ("foofoo", message_->field(3)->lowercase_name());
+  EXPECT_EQ("foobar", message_->field(4)->lowercase_name());
+
+  EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name());
+  EXPECT_EQ("barbar", message_->extension(1)->lowercase_name());
+  EXPECT_EQ("barbaz", message_->extension(2)->lowercase_name());
+  EXPECT_EQ("barfoo", message_->extension(3)->lowercase_name());
+  EXPECT_EQ("barbar", message_->extension(4)->lowercase_name());
+
+  EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name());
+  EXPECT_EQ("bazbar", file_->extension(1)->lowercase_name());
+  EXPECT_EQ("bazbaz", file_->extension(2)->lowercase_name());
+  EXPECT_EQ("bazfoo", file_->extension(3)->lowercase_name());
+  EXPECT_EQ("bazbar", file_->extension(4)->lowercase_name());
+}
+
+TEST_F(StylizedFieldNamesTest, CamelcaseName) {
+  EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name());
+  EXPECT_EQ("fooBar", message_->field(1)->camelcase_name());
+  EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name());
+  EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name());
+  EXPECT_EQ("foobar", message_->field(4)->camelcase_name());
+
+  EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name());
+  EXPECT_EQ("barBar", message_->extension(1)->camelcase_name());
+  EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name());
+  EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name());
+  EXPECT_EQ("barbar", message_->extension(4)->camelcase_name());
+
+  EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name());
+  EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name());
+  EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name());
+  EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name());
+  EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name());
+}
+
+TEST_F(StylizedFieldNamesTest, FindByLowercaseName) {
+  EXPECT_EQ(message_->field(0), message_->FindFieldByLowercaseName("foo_foo"));
+  EXPECT_THAT(message_->FindFieldByLowercaseName("foobar"),
+              AnyOf(message_->field(1), message_->field(4)));
+  EXPECT_EQ(message_->field(2), message_->FindFieldByLowercaseName("foobaz"));
+  EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == nullptr);
+
+  EXPECT_EQ(message_->extension(0),
+            message_->FindExtensionByLowercaseName("bar_foo"));
+  EXPECT_THAT(message_->FindExtensionByLowercaseName("barbar"),
+              AnyOf(message_->extension(1), message_->extension(4)));
+  EXPECT_EQ(message_->extension(2),
+            message_->FindExtensionByLowercaseName("barbaz"));
+  EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == nullptr);
+
+  EXPECT_EQ(file_->extension(0),
+            file_->FindExtensionByLowercaseName("baz_foo"));
+  EXPECT_THAT(file_->FindExtensionByLowercaseName("bazbar"),
+              AnyOf(file_->extension(1), file_->extension(4)));
+  EXPECT_EQ(file_->extension(2), file_->FindExtensionByLowercaseName("bazbaz"));
+  EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == nullptr);
+  EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == nullptr);
+  EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == nullptr);
+}
+
+TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) {
+  EXPECT_THAT(message_->FindFieldByCamelcaseName("fooFoo"),
+              AnyOf(message_->field(0), message_->field(3)));
+  EXPECT_EQ(message_->field(1), message_->FindFieldByCamelcaseName("fooBar"));
+  EXPECT_EQ(message_->field(2), message_->FindFieldByCamelcaseName("fooBaz"));
+  EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == nullptr);
+
+  EXPECT_THAT(message_->FindExtensionByCamelcaseName("barFoo"),
+              AnyOf(message_->extension(0), message_->extension(3)));
+  EXPECT_EQ(message_->extension(1),
+            message_->FindExtensionByCamelcaseName("barBar"));
+  EXPECT_EQ(message_->extension(2),
+            message_->FindExtensionByCamelcaseName("barBaz"));
+  EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == nullptr);
+
+  EXPECT_THAT(file_->FindExtensionByCamelcaseName("bazFoo"),
+              AnyOf(file_->extension(0), file_->extension(3)));
+  EXPECT_EQ(file_->extension(1), file_->FindExtensionByCamelcaseName("bazBar"));
+  EXPECT_EQ(file_->extension(2), file_->FindExtensionByCamelcaseName("bazBaz"));
+  EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == nullptr);
+  EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == nullptr);
+  EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == nullptr);
+}
+
+// ===================================================================
+
+// Test enum descriptors.
+class EnumDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   // in "foo.proto"
+    //   enum TestEnum {
+    //     FOO = 1;
+    //     BAR = 2;
+    //   }
+    //
+    //   // in "bar.proto"
+    //   package corge.grault;
+    //   enum TestEnum2 {
+    //     FOO = 1;
+    //     BAZ = 3;
+    //   }
+    //
+    // TestEnum2 is primarily here to test FindValueByName and friends.
+    // All enums created from the same DescriptorPool share the same lookup
+    // table, so we need to insure that they don't interfere.
+
+    // TestEnum
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    EnumDescriptorProto* enum_proto = AddEnum(&foo_file, "TestEnum");
+    AddEnumValue(enum_proto, "FOO", 1);
+    AddEnumValue(enum_proto, "BAR", 2);
+
+    // TestEnum2
+    FileDescriptorProto bar_file;
+    bar_file.set_name("bar.proto");
+    bar_file.set_package("corge.grault");
+
+    EnumDescriptorProto* enum2_proto = AddEnum(&bar_file, "TestEnum2");
+    AddEnumValue(enum2_proto, "FOO", 1);
+    AddEnumValue(enum2_proto, "BAZ", 3);
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    bar_file_ = pool_.BuildFile(bar_file);
+    ASSERT_TRUE(bar_file_ != nullptr);
+
+    ASSERT_EQ(1, foo_file_->enum_type_count());
+    enum_ = foo_file_->enum_type(0);
+
+    ASSERT_EQ(2, enum_->value_count());
+    foo_ = enum_->value(0);
+    bar_ = enum_->value(1);
+
+    ASSERT_EQ(1, bar_file_->enum_type_count());
+    enum2_ = bar_file_->enum_type(0);
+
+    ASSERT_EQ(2, enum2_->value_count());
+    foo2_ = enum2_->value(0);
+    baz2_ = enum2_->value(1);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* foo_file_;
+  const FileDescriptor* bar_file_;
+
+  const EnumDescriptor* enum_;
+  const EnumDescriptor* enum2_;
+
+  const EnumValueDescriptor* foo_;
+  const EnumValueDescriptor* bar_;
+
+  const EnumValueDescriptor* foo2_;
+  const EnumValueDescriptor* baz2_;
+};
+
+TEST_F(EnumDescriptorTest, Name) {
+  EXPECT_EQ("TestEnum", enum_->name());
+  EXPECT_EQ("TestEnum", enum_->full_name());
+  EXPECT_EQ(foo_file_, enum_->file());
+
+  EXPECT_EQ("TestEnum2", enum2_->name());
+  EXPECT_EQ("corge.grault.TestEnum2", enum2_->full_name());
+  EXPECT_EQ(bar_file_, enum2_->file());
+}
+
+TEST_F(EnumDescriptorTest, ContainingType) {
+  EXPECT_TRUE(enum_->containing_type() == nullptr);
+  EXPECT_TRUE(enum2_->containing_type() == nullptr);
+}
+
+TEST_F(EnumDescriptorTest, ValuesByIndex) {
+  ASSERT_EQ(2, enum_->value_count());
+  EXPECT_EQ(foo_, enum_->value(0));
+  EXPECT_EQ(bar_, enum_->value(1));
+}
+
+TEST_F(EnumDescriptorTest, FindValueByName) {
+  EXPECT_EQ(foo_, enum_->FindValueByName("FOO"));
+  EXPECT_EQ(bar_, enum_->FindValueByName("BAR"));
+  EXPECT_EQ(foo2_, enum2_->FindValueByName("FOO"));
+  EXPECT_EQ(baz2_, enum2_->FindValueByName("BAZ"));
+
+  EXPECT_TRUE(enum_->FindValueByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(enum_->FindValueByName("BAZ") == nullptr);
+  EXPECT_TRUE(enum2_->FindValueByName("BAR") == nullptr);
+}
+
+TEST_F(EnumDescriptorTest, FindValueByNumber) {
+  EXPECT_EQ(foo_, enum_->FindValueByNumber(1));
+  EXPECT_EQ(bar_, enum_->FindValueByNumber(2));
+  EXPECT_EQ(foo2_, enum2_->FindValueByNumber(1));
+  EXPECT_EQ(baz2_, enum2_->FindValueByNumber(3));
+
+  EXPECT_TRUE(enum_->FindValueByNumber(416) == nullptr);
+  EXPECT_TRUE(enum_->FindValueByNumber(3) == nullptr);
+  EXPECT_TRUE(enum2_->FindValueByNumber(2) == nullptr);
+}
+
+TEST_F(EnumDescriptorTest, ValueName) {
+  EXPECT_EQ("FOO", foo_->name());
+  EXPECT_EQ("BAR", bar_->name());
+}
+
+TEST_F(EnumDescriptorTest, ValueFullName) {
+  EXPECT_EQ("FOO", foo_->full_name());
+  EXPECT_EQ("BAR", bar_->full_name());
+  EXPECT_EQ("corge.grault.FOO", foo2_->full_name());
+  EXPECT_EQ("corge.grault.BAZ", baz2_->full_name());
+}
+
+TEST_F(EnumDescriptorTest, ValueIndex) {
+  EXPECT_EQ(0, foo_->index());
+  EXPECT_EQ(1, bar_->index());
+}
+
+TEST_F(EnumDescriptorTest, ValueNumber) {
+  EXPECT_EQ(1, foo_->number());
+  EXPECT_EQ(2, bar_->number());
+}
+
+TEST_F(EnumDescriptorTest, ValueType) {
+  EXPECT_EQ(enum_, foo_->type());
+  EXPECT_EQ(enum_, bar_->type());
+  EXPECT_EQ(enum2_, foo2_->type());
+  EXPECT_EQ(enum2_, baz2_->type());
+}
+
+// ===================================================================
+
+// Test service descriptors.
+class ServiceDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following messages and service:
+    //    // in "foo.proto"
+    //    message FooRequest  {}
+    //    message FooResponse {}
+    //    message BarRequest  {}
+    //    message BarResponse {}
+    //    message BazRequest  {}
+    //    message BazResponse {}
+    //
+    //    service TestService {
+    //      rpc Foo(FooRequest) returns (FooResponse);
+    //      rpc Bar(BarRequest) returns (BarResponse);
+    //    }
+    //
+    //    // in "bar.proto"
+    //    package corge.grault
+    //    service TestService2 {
+    //      rpc Foo(FooRequest) returns (FooResponse);
+    //      rpc Baz(BazRequest) returns (BazResponse);
+    //    }
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    AddMessage(&foo_file, "FooRequest");
+    AddMessage(&foo_file, "FooResponse");
+    AddMessage(&foo_file, "BarRequest");
+    AddMessage(&foo_file, "BarResponse");
+    AddMessage(&foo_file, "BazRequest");
+    AddMessage(&foo_file, "BazResponse");
+
+    ServiceDescriptorProto* service = AddService(&foo_file, "TestService");
+    AddMethod(service, "Foo", "FooRequest", "FooResponse");
+    AddMethod(service, "Bar", "BarRequest", "BarResponse");
+
+    FileDescriptorProto bar_file;
+    bar_file.set_name("bar.proto");
+    bar_file.set_package("corge.grault");
+    bar_file.add_dependency("foo.proto");
+
+    ServiceDescriptorProto* service2 = AddService(&bar_file, "TestService2");
+    AddMethod(service2, "Foo", "FooRequest", "FooResponse");
+    AddMethod(service2, "Baz", "BazRequest", "BazResponse");
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    bar_file_ = pool_.BuildFile(bar_file);
+    ASSERT_TRUE(bar_file_ != nullptr);
+
+    ASSERT_EQ(6, foo_file_->message_type_count());
+    foo_request_ = foo_file_->message_type(0);
+    foo_response_ = foo_file_->message_type(1);
+    bar_request_ = foo_file_->message_type(2);
+    bar_response_ = foo_file_->message_type(3);
+    baz_request_ = foo_file_->message_type(4);
+    baz_response_ = foo_file_->message_type(5);
+
+    ASSERT_EQ(1, foo_file_->service_count());
+    service_ = foo_file_->service(0);
+
+    ASSERT_EQ(2, service_->method_count());
+    foo_ = service_->method(0);
+    bar_ = service_->method(1);
+
+    ASSERT_EQ(1, bar_file_->service_count());
+    service2_ = bar_file_->service(0);
+
+    ASSERT_EQ(2, service2_->method_count());
+    foo2_ = service2_->method(0);
+    baz2_ = service2_->method(1);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* foo_file_;
+  const FileDescriptor* bar_file_;
+
+  const Descriptor* foo_request_;
+  const Descriptor* foo_response_;
+  const Descriptor* bar_request_;
+  const Descriptor* bar_response_;
+  const Descriptor* baz_request_;
+  const Descriptor* baz_response_;
+
+  const ServiceDescriptor* service_;
+  const ServiceDescriptor* service2_;
+
+  const MethodDescriptor* foo_;
+  const MethodDescriptor* bar_;
+
+  const MethodDescriptor* foo2_;
+  const MethodDescriptor* baz2_;
+};
+
+TEST_F(ServiceDescriptorTest, Name) {
+  EXPECT_EQ("TestService", service_->name());
+  EXPECT_EQ("TestService", service_->full_name());
+  EXPECT_EQ(foo_file_, service_->file());
+
+  EXPECT_EQ("TestService2", service2_->name());
+  EXPECT_EQ("corge.grault.TestService2", service2_->full_name());
+  EXPECT_EQ(bar_file_, service2_->file());
+}
+
+TEST_F(ServiceDescriptorTest, MethodsByIndex) {
+  ASSERT_EQ(2, service_->method_count());
+  EXPECT_EQ(foo_, service_->method(0));
+  EXPECT_EQ(bar_, service_->method(1));
+}
+
+TEST_F(ServiceDescriptorTest, FindMethodByName) {
+  EXPECT_EQ(foo_, service_->FindMethodByName("Foo"));
+  EXPECT_EQ(bar_, service_->FindMethodByName("Bar"));
+  EXPECT_EQ(foo2_, service2_->FindMethodByName("Foo"));
+  EXPECT_EQ(baz2_, service2_->FindMethodByName("Baz"));
+
+  EXPECT_TRUE(service_->FindMethodByName("NoSuchMethod") == nullptr);
+  EXPECT_TRUE(service_->FindMethodByName("Baz") == nullptr);
+  EXPECT_TRUE(service2_->FindMethodByName("Bar") == nullptr);
+}
+
+TEST_F(ServiceDescriptorTest, MethodName) {
+  EXPECT_EQ("Foo", foo_->name());
+  EXPECT_EQ("Bar", bar_->name());
+}
+TEST_F(ServiceDescriptorTest, MethodFullName) {
+  EXPECT_EQ("TestService.Foo", foo_->full_name());
+  EXPECT_EQ("TestService.Bar", bar_->full_name());
+  EXPECT_EQ("corge.grault.TestService2.Foo", foo2_->full_name());
+  EXPECT_EQ("corge.grault.TestService2.Baz", baz2_->full_name());
+}
+
+TEST_F(ServiceDescriptorTest, MethodIndex) {
+  EXPECT_EQ(0, foo_->index());
+  EXPECT_EQ(1, bar_->index());
+}
+
+TEST_F(ServiceDescriptorTest, MethodParent) {
+  EXPECT_EQ(service_, foo_->service());
+  EXPECT_EQ(service_, bar_->service());
+}
+
+TEST_F(ServiceDescriptorTest, MethodInputType) {
+  EXPECT_EQ(foo_request_, foo_->input_type());
+  EXPECT_EQ(bar_request_, bar_->input_type());
+}
+
+TEST_F(ServiceDescriptorTest, MethodOutputType) {
+  EXPECT_EQ(foo_response_, foo_->output_type());
+  EXPECT_EQ(bar_response_, bar_->output_type());
+}
+
+// ===================================================================
+
+// Test nested types.
+class NestedDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   // in "foo.proto"
+    //   message TestMessage {
+    //     message Foo {}
+    //     message Bar {}
+    //     enum Baz { A = 1; }
+    //     enum Moo { B = 1; }
+    //   }
+    //
+    //   // in "bar.proto"
+    //   package corge.grault;
+    //   message TestMessage2 {
+    //     message Foo {}
+    //     message Baz {}
+    //     enum Moo  { A = 1; }
+    //     enum Mooo { C = 1; }
+    //   }
+    //
+    // TestMessage2 is primarily here to test FindNestedTypeByName and friends.
+    // All messages created from the same DescriptorPool share the same lookup
+    // table, so we need to insure that they don't interfere.
+    //
+    // We add enum values to the enums in order to test searching for enum
+    // values across a message's scope.
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
+    AddNestedMessage(message, "Foo");
+    AddNestedMessage(message, "Bar");
+    EnumDescriptorProto* baz = AddNestedEnum(message, "Baz");
+    AddEnumValue(baz, "A", 1);
+    EnumDescriptorProto* moo = AddNestedEnum(message, "Moo");
+    AddEnumValue(moo, "B", 1);
+
+    FileDescriptorProto bar_file;
+    bar_file.set_name("bar.proto");
+    bar_file.set_package("corge.grault");
+
+    DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
+    AddNestedMessage(message2, "Foo");
+    AddNestedMessage(message2, "Baz");
+    EnumDescriptorProto* moo2 = AddNestedEnum(message2, "Moo");
+    AddEnumValue(moo2, "A", 1);
+    EnumDescriptorProto* mooo2 = AddNestedEnum(message2, "Mooo");
+    AddEnumValue(mooo2, "C", 1);
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    bar_file_ = pool_.BuildFile(bar_file);
+    ASSERT_TRUE(bar_file_ != nullptr);
+
+    ASSERT_EQ(1, foo_file_->message_type_count());
+    message_ = foo_file_->message_type(0);
+
+    ASSERT_EQ(2, message_->nested_type_count());
+    foo_ = message_->nested_type(0);
+    bar_ = message_->nested_type(1);
+
+    ASSERT_EQ(2, message_->enum_type_count());
+    baz_ = message_->enum_type(0);
+    moo_ = message_->enum_type(1);
+
+    ASSERT_EQ(1, baz_->value_count());
+    a_ = baz_->value(0);
+    ASSERT_EQ(1, moo_->value_count());
+    b_ = moo_->value(0);
+
+    ASSERT_EQ(1, bar_file_->message_type_count());
+    message2_ = bar_file_->message_type(0);
+
+    ASSERT_EQ(2, message2_->nested_type_count());
+    foo2_ = message2_->nested_type(0);
+    baz2_ = message2_->nested_type(1);
+
+    ASSERT_EQ(2, message2_->enum_type_count());
+    moo2_ = message2_->enum_type(0);
+    mooo2_ = message2_->enum_type(1);
+
+    ASSERT_EQ(1, moo2_->value_count());
+    a2_ = moo2_->value(0);
+    ASSERT_EQ(1, mooo2_->value_count());
+    c2_ = mooo2_->value(0);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* foo_file_;
+  const FileDescriptor* bar_file_;
+
+  const Descriptor* message_;
+  const Descriptor* message2_;
+
+  const Descriptor* foo_;
+  const Descriptor* bar_;
+  const EnumDescriptor* baz_;
+  const EnumDescriptor* moo_;
+  const EnumValueDescriptor* a_;
+  const EnumValueDescriptor* b_;
+
+  const Descriptor* foo2_;
+  const Descriptor* baz2_;
+  const EnumDescriptor* moo2_;
+  const EnumDescriptor* mooo2_;
+  const EnumValueDescriptor* a2_;
+  const EnumValueDescriptor* c2_;
+};
+
+TEST_F(NestedDescriptorTest, MessageName) {
+  EXPECT_EQ("Foo", foo_->name());
+  EXPECT_EQ("Bar", bar_->name());
+  EXPECT_EQ("Foo", foo2_->name());
+  EXPECT_EQ("Baz", baz2_->name());
+
+  EXPECT_EQ("TestMessage.Foo", foo_->full_name());
+  EXPECT_EQ("TestMessage.Bar", bar_->full_name());
+  EXPECT_EQ("corge.grault.TestMessage2.Foo", foo2_->full_name());
+  EXPECT_EQ("corge.grault.TestMessage2.Baz", baz2_->full_name());
+}
+
+TEST_F(NestedDescriptorTest, MessageContainingType) {
+  EXPECT_EQ(message_, foo_->containing_type());
+  EXPECT_EQ(message_, bar_->containing_type());
+  EXPECT_EQ(message2_, foo2_->containing_type());
+  EXPECT_EQ(message2_, baz2_->containing_type());
+}
+
+TEST_F(NestedDescriptorTest, NestedMessagesByIndex) {
+  ASSERT_EQ(2, message_->nested_type_count());
+  EXPECT_EQ(foo_, message_->nested_type(0));
+  EXPECT_EQ(bar_, message_->nested_type(1));
+}
+
+TEST_F(NestedDescriptorTest, FindFieldByNameDoesntFindNestedTypes) {
+  EXPECT_TRUE(message_->FindFieldByName("Foo") == nullptr);
+  EXPECT_TRUE(message_->FindFieldByName("Moo") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByName("Foo") == nullptr);
+  EXPECT_TRUE(message_->FindExtensionByName("Moo") == nullptr);
+}
+
+TEST_F(NestedDescriptorTest, FindNestedTypeByName) {
+  EXPECT_EQ(foo_, message_->FindNestedTypeByName("Foo"));
+  EXPECT_EQ(bar_, message_->FindNestedTypeByName("Bar"));
+  EXPECT_EQ(foo2_, message2_->FindNestedTypeByName("Foo"));
+  EXPECT_EQ(baz2_, message2_->FindNestedTypeByName("Baz"));
+
+  EXPECT_TRUE(message_->FindNestedTypeByName("NoSuchType") == nullptr);
+  EXPECT_TRUE(message_->FindNestedTypeByName("Baz") == nullptr);
+  EXPECT_TRUE(message2_->FindNestedTypeByName("Bar") == nullptr);
+
+  EXPECT_TRUE(message_->FindNestedTypeByName("Moo") == nullptr);
+}
+
+TEST_F(NestedDescriptorTest, EnumName) {
+  EXPECT_EQ("Baz", baz_->name());
+  EXPECT_EQ("Moo", moo_->name());
+  EXPECT_EQ("Moo", moo2_->name());
+  EXPECT_EQ("Mooo", mooo2_->name());
+
+  EXPECT_EQ("TestMessage.Baz", baz_->full_name());
+  EXPECT_EQ("TestMessage.Moo", moo_->full_name());
+  EXPECT_EQ("corge.grault.TestMessage2.Moo", moo2_->full_name());
+  EXPECT_EQ("corge.grault.TestMessage2.Mooo", mooo2_->full_name());
+}
+
+TEST_F(NestedDescriptorTest, EnumContainingType) {
+  EXPECT_EQ(message_, baz_->containing_type());
+  EXPECT_EQ(message_, moo_->containing_type());
+  EXPECT_EQ(message2_, moo2_->containing_type());
+  EXPECT_EQ(message2_, mooo2_->containing_type());
+}
+
+TEST_F(NestedDescriptorTest, NestedEnumsByIndex) {
+  ASSERT_EQ(2, message_->nested_type_count());
+  EXPECT_EQ(foo_, message_->nested_type(0));
+  EXPECT_EQ(bar_, message_->nested_type(1));
+}
+
+TEST_F(NestedDescriptorTest, FindEnumTypeByName) {
+  EXPECT_EQ(baz_, message_->FindEnumTypeByName("Baz"));
+  EXPECT_EQ(moo_, message_->FindEnumTypeByName("Moo"));
+  EXPECT_EQ(moo2_, message2_->FindEnumTypeByName("Moo"));
+  EXPECT_EQ(mooo2_, message2_->FindEnumTypeByName("Mooo"));
+
+  EXPECT_TRUE(message_->FindEnumTypeByName("NoSuchType") == nullptr);
+  EXPECT_TRUE(message_->FindEnumTypeByName("Mooo") == nullptr);
+  EXPECT_TRUE(message2_->FindEnumTypeByName("Baz") == nullptr);
+
+  EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == nullptr);
+}
+
+TEST_F(NestedDescriptorTest, FindEnumValueByName) {
+  EXPECT_EQ(a_, message_->FindEnumValueByName("A"));
+  EXPECT_EQ(b_, message_->FindEnumValueByName("B"));
+  EXPECT_EQ(a2_, message2_->FindEnumValueByName("A"));
+  EXPECT_EQ(c2_, message2_->FindEnumValueByName("C"));
+
+  EXPECT_TRUE(message_->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(message_->FindEnumValueByName("C") == nullptr);
+  EXPECT_TRUE(message2_->FindEnumValueByName("B") == nullptr);
+
+  EXPECT_TRUE(message_->FindEnumValueByName("Foo") == nullptr);
+}
+
+// ===================================================================
+
+// Test extensions.
+class ExtensionDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   enum Baz {}
+    //   message Moo {}
+    //
+    //   message Foo {
+    //     extensions 10 to 19;
+    //     extensions 30 to 39;
+    //   }
+    //   extend Foo {
+    //     optional int32 foo_int32 = 10;
+    //   }
+    //   extend Foo {
+    //     repeated TestEnum foo_enum = 19;
+    //   }
+    //   message Bar {
+    //     optional int32 non_ext_int32 = 1;
+    //     extend Foo {
+    //       optional Moo foo_message = 30;
+    //       repeated Moo foo_group = 39;  // (but internally set to TYPE_GROUP)
+    //     }
+    //   }
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    AddEmptyEnum(&foo_file, "Baz");
+    AddMessage(&foo_file, "Moo");
+
+    DescriptorProto* foo = AddMessage(&foo_file, "Foo");
+    AddExtensionRange(foo, 10, 20);
+    AddExtensionRange(foo, 30, 40);
+
+    AddExtension(&foo_file, "Foo", "foo_int32", 10,
+                 FieldDescriptorProto::LABEL_OPTIONAL,
+                 FieldDescriptorProto::TYPE_INT32);
+    AddExtension(&foo_file, "Foo", "foo_enum", 19,
+                 FieldDescriptorProto::LABEL_REPEATED,
+                 FieldDescriptorProto::TYPE_ENUM)
+        ->set_type_name("Baz");
+
+    DescriptorProto* bar = AddMessage(&foo_file, "Bar");
+    AddField(bar, "non_ext_int32", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddNestedExtension(bar, "Foo", "foo_message", 30,
+                       FieldDescriptorProto::LABEL_OPTIONAL,
+                       FieldDescriptorProto::TYPE_MESSAGE)
+        ->set_type_name("Moo");
+    AddNestedExtension(bar, "Foo", "foo_group", 39,
+                       FieldDescriptorProto::LABEL_REPEATED,
+                       FieldDescriptorProto::TYPE_GROUP)
+        ->set_type_name("Moo");
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    ASSERT_EQ(1, foo_file_->enum_type_count());
+    baz_ = foo_file_->enum_type(0);
+
+    ASSERT_EQ(3, foo_file_->message_type_count());
+    moo_ = foo_file_->message_type(0);
+    foo_ = foo_file_->message_type(1);
+    bar_ = foo_file_->message_type(2);
+  }
+
+  DescriptorPool pool_;
+
+  const FileDescriptor* foo_file_;
+
+  const Descriptor* foo_;
+  const Descriptor* bar_;
+  const EnumDescriptor* baz_;
+  const Descriptor* moo_;
+};
+
+TEST_F(ExtensionDescriptorTest, ExtensionRanges) {
+  EXPECT_EQ(0, bar_->extension_range_count());
+  ASSERT_EQ(2, foo_->extension_range_count());
+
+  EXPECT_EQ(10, foo_->extension_range(0)->start);
+  EXPECT_EQ(30, foo_->extension_range(1)->start);
+
+  EXPECT_EQ(20, foo_->extension_range(0)->end);
+  EXPECT_EQ(40, foo_->extension_range(1)->end);
+}
+
+TEST_F(ExtensionDescriptorTest, Extensions) {
+  EXPECT_EQ(0, foo_->extension_count());
+  ASSERT_EQ(2, foo_file_->extension_count());
+  ASSERT_EQ(2, bar_->extension_count());
+
+  EXPECT_TRUE(foo_file_->extension(0)->is_extension());
+  EXPECT_TRUE(foo_file_->extension(1)->is_extension());
+  EXPECT_TRUE(bar_->extension(0)->is_extension());
+  EXPECT_TRUE(bar_->extension(1)->is_extension());
+
+  EXPECT_EQ("foo_int32", foo_file_->extension(0)->name());
+  EXPECT_EQ("foo_enum", foo_file_->extension(1)->name());
+  EXPECT_EQ("foo_message", bar_->extension(0)->name());
+  EXPECT_EQ("foo_group", bar_->extension(1)->name());
+
+  EXPECT_EQ(10, foo_file_->extension(0)->number());
+  EXPECT_EQ(19, foo_file_->extension(1)->number());
+  EXPECT_EQ(30, bar_->extension(0)->number());
+  EXPECT_EQ(39, bar_->extension(1)->number());
+
+  EXPECT_EQ(FieldDescriptor::TYPE_INT32, foo_file_->extension(0)->type());
+  EXPECT_EQ(FieldDescriptor::TYPE_ENUM, foo_file_->extension(1)->type());
+  EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_->extension(0)->type());
+  EXPECT_EQ(FieldDescriptor::TYPE_GROUP, bar_->extension(1)->type());
+
+  EXPECT_EQ(baz_, foo_file_->extension(1)->enum_type());
+  EXPECT_EQ(moo_, bar_->extension(0)->message_type());
+  EXPECT_EQ(moo_, bar_->extension(1)->message_type());
+
+  EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, foo_file_->extension(0)->label());
+  EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, foo_file_->extension(1)->label());
+  EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->extension(0)->label());
+  EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, bar_->extension(1)->label());
+
+  EXPECT_EQ(foo_, foo_file_->extension(0)->containing_type());
+  EXPECT_EQ(foo_, foo_file_->extension(1)->containing_type());
+  EXPECT_EQ(foo_, bar_->extension(0)->containing_type());
+  EXPECT_EQ(foo_, bar_->extension(1)->containing_type());
+
+  EXPECT_TRUE(foo_file_->extension(0)->extension_scope() == nullptr);
+  EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == nullptr);
+  EXPECT_EQ(bar_, bar_->extension(0)->extension_scope());
+  EXPECT_EQ(bar_, bar_->extension(1)->extension_scope());
+}
+
+TEST_F(ExtensionDescriptorTest, IsExtensionNumber) {
+  EXPECT_FALSE(foo_->IsExtensionNumber(9));
+  EXPECT_TRUE(foo_->IsExtensionNumber(10));
+  EXPECT_TRUE(foo_->IsExtensionNumber(19));
+  EXPECT_FALSE(foo_->IsExtensionNumber(20));
+  EXPECT_FALSE(foo_->IsExtensionNumber(29));
+  EXPECT_TRUE(foo_->IsExtensionNumber(30));
+  EXPECT_TRUE(foo_->IsExtensionNumber(39));
+  EXPECT_FALSE(foo_->IsExtensionNumber(40));
+}
+
+TEST_F(ExtensionDescriptorTest, FindExtensionByName) {
+  // Note that FileDescriptor::FindExtensionByName() is tested by
+  // FileDescriptorTest.
+  ASSERT_EQ(2, bar_->extension_count());
+
+  EXPECT_EQ(bar_->extension(0), bar_->FindExtensionByName("foo_message"));
+  EXPECT_EQ(bar_->extension(1), bar_->FindExtensionByName("foo_group"));
+
+  EXPECT_TRUE(bar_->FindExtensionByName("no_such_extension") == nullptr);
+  EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == nullptr);
+  EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == nullptr);
+}
+
+TEST_F(ExtensionDescriptorTest, FieldVsExtension) {
+  EXPECT_EQ(foo_->FindFieldByName("foo_message"), nullptr);
+  EXPECT_EQ(bar_->FindFieldByName("foo_message"), nullptr);
+  EXPECT_NE(bar_->FindFieldByName("non_ext_int32"), nullptr);
+  EXPECT_EQ(foo_->FindExtensionByName("foo_message"), nullptr);
+  EXPECT_NE(bar_->FindExtensionByName("foo_message"), nullptr);
+  EXPECT_EQ(bar_->FindExtensionByName("non_ext_int32"), nullptr);
+}
+
+TEST_F(ExtensionDescriptorTest, FindExtensionByPrintableName) {
+  EXPECT_TRUE(pool_.FindExtensionByPrintableName(foo_, "no_such_extension") ==
+              nullptr);
+  EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "no_such_extension") ==
+              nullptr);
+
+  ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "Bar.foo_message") ==
+               nullptr);
+  ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "Bar.foo_group") ==
+               nullptr);
+  EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_message") ==
+              nullptr);
+  EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_group") == nullptr);
+  EXPECT_EQ(bar_->FindExtensionByName("foo_message"),
+            pool_.FindExtensionByPrintableName(foo_, "Bar.foo_message"));
+  EXPECT_EQ(bar_->FindExtensionByName("foo_group"),
+            pool_.FindExtensionByPrintableName(foo_, "Bar.foo_group"));
+
+  ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "foo_int32") ==
+               nullptr);
+  ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "foo_enum") == nullptr);
+  EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_int32") == nullptr);
+  EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_enum") == nullptr);
+  EXPECT_EQ(foo_file_->FindExtensionByName("foo_int32"),
+            pool_.FindExtensionByPrintableName(foo_, "foo_int32"));
+  EXPECT_EQ(foo_file_->FindExtensionByName("foo_enum"),
+            pool_.FindExtensionByPrintableName(foo_, "foo_enum"));
+}
+
+TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
+  std::vector<const FieldDescriptor*> extensions;
+  pool_.FindAllExtensions(foo_, &extensions);
+  ASSERT_EQ(4, extensions.size());
+  EXPECT_EQ(10, extensions[0]->number());
+  EXPECT_EQ(19, extensions[1]->number());
+  EXPECT_EQ(30, extensions[2]->number());
+  EXPECT_EQ(39, extensions[3]->number());
+}
+
+
+TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) {
+  DescriptorPool pool;
+  FileDescriptorProto file_proto;
+  // Add "google/protobuf/descriptor.proto".
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+  // Add "foo.proto":
+  //   import "google/protobuf/descriptor.proto";
+  //   extend google.protobuf.FieldOptions {
+  //     optional int32 option1 = 1000;
+  //   }
+  file_proto.Clear();
+  file_proto.set_name("foo.proto");
+  file_proto.add_dependency("google/protobuf/descriptor.proto");
+  AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_INT32);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+  // Add "bar.proto":
+  //   import "google/protobuf/descriptor.proto";
+  //   extend google.protobuf.FieldOptions {
+  //     optional int32 option2 = 1000;
+  //   }
+  file_proto.Clear();
+  file_proto.set_name("bar.proto");
+  file_proto.add_dependency("google/protobuf/descriptor.proto");
+  AddExtension(&file_proto, "google.protobuf.FieldOptions", "option2", 1000,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_INT32);
+  // Currently we only generate a warning for conflicting extension numbers.
+  // TODO(xiaofeng): Change it to an error.
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+}
+
+// ===================================================================
+
+// Ensure that overlapping extension ranges are not allowed.
+TEST(OverlappingExtensionRangeTest, ExtensionRangeInternal) {
+  // Build descriptors for the following definitions:
+  //
+  //   message Foo {
+  //     extensions 10 to 19;
+  //     extensions 15;
+  //   }
+  FileDescriptorProto foo_file;
+  foo_file.set_name("foo.proto");
+
+  DescriptorProto* foo = AddMessage(&foo_file, "Foo");
+  AddExtensionRange(foo, 10, 20);
+  AddExtensionRange(foo, 15, 16);
+
+  DescriptorPool pool;
+  MockErrorCollector error_collector;
+  // The extensions ranges are invalid, so the proto shouldn't build.
+  ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
+              nullptr);
+  ASSERT_EQ(
+      "foo.proto: Foo: NUMBER: Extension range 15 to 15 overlaps with "
+      "already-defined range 10 to 19.\n",
+      error_collector.text_);
+}
+
+TEST(OverlappingExtensionRangeTest, ExtensionRangeAfter) {
+  // Build descriptors for the following definitions:
+  //
+  //   message Foo {
+  //     extensions 10 to 19;
+  //     extensions 15 to 24;
+  //   }
+  FileDescriptorProto foo_file;
+  foo_file.set_name("foo.proto");
+
+  DescriptorProto* foo = AddMessage(&foo_file, "Foo");
+  AddExtensionRange(foo, 10, 20);
+  AddExtensionRange(foo, 15, 25);
+
+  DescriptorPool pool;
+  MockErrorCollector error_collector;
+  // The extensions ranges are invalid, so the proto shouldn't build.
+  ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
+              nullptr);
+  ASSERT_EQ(
+      "foo.proto: Foo: NUMBER: Extension range 15 to 24 overlaps with "
+      "already-defined range 10 to 19.\n",
+      error_collector.text_);
+}
+
+TEST(OverlappingExtensionRangeTest, ExtensionRangeBefore) {
+  // Build descriptors for the following definitions:
+  //
+  //   message Foo {
+  //     extensions 10 to 19;
+  //     extensions 5 to 14;
+  //   }
+  FileDescriptorProto foo_file;
+  foo_file.set_name("foo.proto");
+
+  DescriptorProto* foo = AddMessage(&foo_file, "Foo");
+  AddExtensionRange(foo, 10, 20);
+  AddExtensionRange(foo, 5, 15);
+
+  DescriptorPool pool;
+  MockErrorCollector error_collector;
+  // The extensions ranges are invalid, so the proto shouldn't build.
+  ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
+              nullptr);
+  ASSERT_EQ(
+      "foo.proto: Foo: NUMBER: Extension range 5 to 14 overlaps with "
+      "already-defined range 10 to 19.\n",
+      error_collector.text_);
+}
+
+// ===================================================================
+
+// Test reserved fields.
+class ReservedDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // 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_ != nullptr);
+
+    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"));
+}
+
+// ===================================================================
+
+// Test reserved enum fields.
+class ReservedEnumDescriptorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Build descriptors for the following definitions:
+    //
+    //   enum Foo {
+    //     BAR = 1;
+    //     reserved 2, 9 to 11, 15;
+    //     reserved "foo", "bar";
+    //   }
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    EnumDescriptorProto* foo = AddEnum(&foo_file, "Foo");
+    EnumDescriptorProto* edge1 = AddEnum(&foo_file, "Edge1");
+    EnumDescriptorProto* edge2 = AddEnum(&foo_file, "Edge2");
+
+    AddEnumValue(foo, "BAR", 4);
+    AddReservedRange(foo, -5, -3);
+    AddReservedRange(foo, -2, 1);
+    AddReservedRange(foo, 2, 3);
+    AddReservedRange(foo, 9, 12);
+    AddReservedRange(foo, 15, 16);
+
+    foo->add_reserved_name("foo");
+    foo->add_reserved_name("bar");
+
+    // Some additional edge cases that cover most or all of the range of enum
+    // values
+
+    // Note: We use INT_MAX as the maximum reserved range upper bound,
+    // inclusive.
+    AddEnumValue(edge1, "EDGE1", 1);
+    AddReservedRange(edge1, 10, INT_MAX);
+    AddEnumValue(edge2, "EDGE2", 15);
+    AddReservedRange(edge2, INT_MIN, 10);
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    ASSERT_EQ(3, foo_file_->enum_type_count());
+    foo_ = foo_file_->enum_type(0);
+    edge1_ = foo_file_->enum_type(1);
+    edge2_ = foo_file_->enum_type(2);
+  }
+
+  DescriptorPool pool_;
+  const FileDescriptor* foo_file_;
+  const EnumDescriptor* foo_;
+  const EnumDescriptor* edge1_;
+  const EnumDescriptor* edge2_;
+};
+
+TEST_F(ReservedEnumDescriptorTest, ReservedRanges) {
+  ASSERT_EQ(5, foo_->reserved_range_count());
+
+  EXPECT_EQ(-5, foo_->reserved_range(0)->start);
+  EXPECT_EQ(-3, foo_->reserved_range(0)->end);
+
+  EXPECT_EQ(-2, foo_->reserved_range(1)->start);
+  EXPECT_EQ(1, foo_->reserved_range(1)->end);
+
+  EXPECT_EQ(2, foo_->reserved_range(2)->start);
+  EXPECT_EQ(3, foo_->reserved_range(2)->end);
+
+  EXPECT_EQ(9, foo_->reserved_range(3)->start);
+  EXPECT_EQ(12, foo_->reserved_range(3)->end);
+
+  EXPECT_EQ(15, foo_->reserved_range(4)->start);
+  EXPECT_EQ(16, foo_->reserved_range(4)->end);
+
+  ASSERT_EQ(1, edge1_->reserved_range_count());
+  EXPECT_EQ(10, edge1_->reserved_range(0)->start);
+  EXPECT_EQ(INT_MAX, edge1_->reserved_range(0)->end);
+
+  ASSERT_EQ(1, edge2_->reserved_range_count());
+  EXPECT_EQ(INT_MIN, edge2_->reserved_range(0)->start);
+  EXPECT_EQ(10, edge2_->reserved_range(0)->end);
+}
+
+TEST_F(ReservedEnumDescriptorTest, IsReservedNumber) {
+  EXPECT_TRUE(foo_->IsReservedNumber(-5));
+  EXPECT_TRUE(foo_->IsReservedNumber(-4));
+  EXPECT_TRUE(foo_->IsReservedNumber(-3));
+  EXPECT_TRUE(foo_->IsReservedNumber(-2));
+  EXPECT_TRUE(foo_->IsReservedNumber(-1));
+  EXPECT_TRUE(foo_->IsReservedNumber(0));
+  EXPECT_TRUE(foo_->IsReservedNumber(1));
+  EXPECT_TRUE(foo_->IsReservedNumber(2));
+  EXPECT_TRUE(foo_->IsReservedNumber(3));
+  EXPECT_FALSE(foo_->IsReservedNumber(8));
+  EXPECT_TRUE(foo_->IsReservedNumber(9));
+  EXPECT_TRUE(foo_->IsReservedNumber(10));
+  EXPECT_TRUE(foo_->IsReservedNumber(11));
+  EXPECT_TRUE(foo_->IsReservedNumber(12));
+  EXPECT_FALSE(foo_->IsReservedNumber(13));
+  EXPECT_FALSE(foo_->IsReservedNumber(13));
+  EXPECT_FALSE(foo_->IsReservedNumber(14));
+  EXPECT_TRUE(foo_->IsReservedNumber(15));
+  EXPECT_TRUE(foo_->IsReservedNumber(16));
+  EXPECT_FALSE(foo_->IsReservedNumber(17));
+
+  EXPECT_FALSE(edge1_->IsReservedNumber(9));
+  EXPECT_TRUE(edge1_->IsReservedNumber(10));
+  EXPECT_TRUE(edge1_->IsReservedNumber(INT_MAX - 1));
+  EXPECT_TRUE(edge1_->IsReservedNumber(INT_MAX));
+
+  EXPECT_TRUE(edge2_->IsReservedNumber(INT_MIN));
+  EXPECT_TRUE(edge2_->IsReservedNumber(9));
+  EXPECT_TRUE(edge2_->IsReservedNumber(10));
+  EXPECT_FALSE(edge2_->IsReservedNumber(11));
+}
+
+TEST_F(ReservedEnumDescriptorTest, ReservedNames) {
+  ASSERT_EQ(2, foo_->reserved_name_count());
+
+  EXPECT_EQ("foo", foo_->reserved_name(0));
+  EXPECT_EQ("bar", foo_->reserved_name(1));
+}
+
+TEST_F(ReservedEnumDescriptorTest, 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.
+  const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) {
+    FileDescriptorProto file_proto;
+    file_proto.set_name("foo.proto");
+    AddEmptyEnum(&file_proto, "DummyEnum");
+
+    DescriptorProto* message = AddMessage(&file_proto, "TestMessage");
+    FieldDescriptorProto* field = AddField(
+        message, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+        static_cast<FieldDescriptorProto::Type>(static_cast<int>(type)));
+
+    if (type == FieldDescriptor::TYPE_MESSAGE ||
+        type == FieldDescriptor::TYPE_GROUP) {
+      field->set_type_name("TestMessage");
+    } else if (type == FieldDescriptor::TYPE_ENUM) {
+      field->set_type_name("DummyEnum");
+    }
+
+    // Build the descriptors and get the pointers.
+    pool_.reset(new DescriptorPool());
+    const FileDescriptor* file = pool_->BuildFile(file_proto);
+
+    if (file != nullptr && file->message_type_count() == 1 &&
+        file->message_type(0)->field_count() == 1) {
+      return file->message_type(0)->field(0);
+    } else {
+      return nullptr;
+    }
+  }
+
+  const char* GetTypeNameForFieldType(FieldDescriptor::Type type) {
+    const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+    return field != nullptr ? field->type_name() : "";
+  }
+
+  FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
+    const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+    return field != nullptr ? field->cpp_type()
+                            : static_cast<FieldDescriptor::CppType>(0);
+  }
+
+  const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) {
+    const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+    return field != nullptr ? field->cpp_type_name() : "";
+  }
+
+  const Descriptor* GetMessageDescriptorForFieldType(
+      FieldDescriptor::Type type) {
+    const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+    return field != nullptr ? field->message_type() : nullptr;
+  }
+
+  const EnumDescriptor* GetEnumDescriptorForFieldType(
+      FieldDescriptor::Type type) {
+    const FieldDescriptor* field = GetFieldDescriptorOfType(type);
+    return field != nullptr ? field->enum_type() : nullptr;
+  }
+
+  std::unique_ptr<DescriptorPool> pool_;
+};
+
+TEST_F(MiscTest, TypeNames) {
+  // Test that correct type names are returned.
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_STREQ("double", GetTypeNameForFieldType(FD::TYPE_DOUBLE));
+  EXPECT_STREQ("float", GetTypeNameForFieldType(FD::TYPE_FLOAT));
+  EXPECT_STREQ("int64", GetTypeNameForFieldType(FD::TYPE_INT64));
+  EXPECT_STREQ("uint64", GetTypeNameForFieldType(FD::TYPE_UINT64));
+  EXPECT_STREQ("int32", GetTypeNameForFieldType(FD::TYPE_INT32));
+  EXPECT_STREQ("fixed64", GetTypeNameForFieldType(FD::TYPE_FIXED64));
+  EXPECT_STREQ("fixed32", GetTypeNameForFieldType(FD::TYPE_FIXED32));
+  EXPECT_STREQ("bool", GetTypeNameForFieldType(FD::TYPE_BOOL));
+  EXPECT_STREQ("string", GetTypeNameForFieldType(FD::TYPE_STRING));
+  EXPECT_STREQ("group", GetTypeNameForFieldType(FD::TYPE_GROUP));
+  EXPECT_STREQ("message", GetTypeNameForFieldType(FD::TYPE_MESSAGE));
+  EXPECT_STREQ("bytes", GetTypeNameForFieldType(FD::TYPE_BYTES));
+  EXPECT_STREQ("uint32", GetTypeNameForFieldType(FD::TYPE_UINT32));
+  EXPECT_STREQ("enum", GetTypeNameForFieldType(FD::TYPE_ENUM));
+  EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32));
+  EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64));
+  EXPECT_STREQ("sint32", GetTypeNameForFieldType(FD::TYPE_SINT32));
+  EXPECT_STREQ("sint64", GetTypeNameForFieldType(FD::TYPE_SINT64));
+}
+
+TEST_F(MiscTest, StaticTypeNames) {
+  // Test that correct type names are returned.
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_STREQ("double", FD::TypeName(FD::TYPE_DOUBLE));
+  EXPECT_STREQ("float", FD::TypeName(FD::TYPE_FLOAT));
+  EXPECT_STREQ("int64", FD::TypeName(FD::TYPE_INT64));
+  EXPECT_STREQ("uint64", FD::TypeName(FD::TYPE_UINT64));
+  EXPECT_STREQ("int32", FD::TypeName(FD::TYPE_INT32));
+  EXPECT_STREQ("fixed64", FD::TypeName(FD::TYPE_FIXED64));
+  EXPECT_STREQ("fixed32", FD::TypeName(FD::TYPE_FIXED32));
+  EXPECT_STREQ("bool", FD::TypeName(FD::TYPE_BOOL));
+  EXPECT_STREQ("string", FD::TypeName(FD::TYPE_STRING));
+  EXPECT_STREQ("group", FD::TypeName(FD::TYPE_GROUP));
+  EXPECT_STREQ("message", FD::TypeName(FD::TYPE_MESSAGE));
+  EXPECT_STREQ("bytes", FD::TypeName(FD::TYPE_BYTES));
+  EXPECT_STREQ("uint32", FD::TypeName(FD::TYPE_UINT32));
+  EXPECT_STREQ("enum", FD::TypeName(FD::TYPE_ENUM));
+  EXPECT_STREQ("sfixed32", FD::TypeName(FD::TYPE_SFIXED32));
+  EXPECT_STREQ("sfixed64", FD::TypeName(FD::TYPE_SFIXED64));
+  EXPECT_STREQ("sint32", FD::TypeName(FD::TYPE_SINT32));
+  EXPECT_STREQ("sint64", FD::TypeName(FD::TYPE_SINT64));
+}
+
+TEST_F(MiscTest, CppTypes) {
+  // Test that CPP types are assigned correctly.
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_EQ(FD::CPPTYPE_DOUBLE, GetCppTypeForFieldType(FD::TYPE_DOUBLE));
+  EXPECT_EQ(FD::CPPTYPE_FLOAT, GetCppTypeForFieldType(FD::TYPE_FLOAT));
+  EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_INT64));
+  EXPECT_EQ(FD::CPPTYPE_UINT64, GetCppTypeForFieldType(FD::TYPE_UINT64));
+  EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_INT32));
+  EXPECT_EQ(FD::CPPTYPE_UINT64, GetCppTypeForFieldType(FD::TYPE_FIXED64));
+  EXPECT_EQ(FD::CPPTYPE_UINT32, GetCppTypeForFieldType(FD::TYPE_FIXED32));
+  EXPECT_EQ(FD::CPPTYPE_BOOL, GetCppTypeForFieldType(FD::TYPE_BOOL));
+  EXPECT_EQ(FD::CPPTYPE_STRING, GetCppTypeForFieldType(FD::TYPE_STRING));
+  EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_GROUP));
+  EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_MESSAGE));
+  EXPECT_EQ(FD::CPPTYPE_STRING, GetCppTypeForFieldType(FD::TYPE_BYTES));
+  EXPECT_EQ(FD::CPPTYPE_UINT32, GetCppTypeForFieldType(FD::TYPE_UINT32));
+  EXPECT_EQ(FD::CPPTYPE_ENUM, GetCppTypeForFieldType(FD::TYPE_ENUM));
+  EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_SFIXED32));
+  EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_SFIXED64));
+  EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_SINT32));
+  EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_SINT64));
+}
+
+TEST_F(MiscTest, CppTypeNames) {
+  // Test that correct CPP type names are returned.
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_STREQ("double", GetCppTypeNameForFieldType(FD::TYPE_DOUBLE));
+  EXPECT_STREQ("float", GetCppTypeNameForFieldType(FD::TYPE_FLOAT));
+  EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_INT64));
+  EXPECT_STREQ("uint64", GetCppTypeNameForFieldType(FD::TYPE_UINT64));
+  EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_INT32));
+  EXPECT_STREQ("uint64", GetCppTypeNameForFieldType(FD::TYPE_FIXED64));
+  EXPECT_STREQ("uint32", GetCppTypeNameForFieldType(FD::TYPE_FIXED32));
+  EXPECT_STREQ("bool", GetCppTypeNameForFieldType(FD::TYPE_BOOL));
+  EXPECT_STREQ("string", GetCppTypeNameForFieldType(FD::TYPE_STRING));
+  EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP));
+  EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE));
+  EXPECT_STREQ("string", GetCppTypeNameForFieldType(FD::TYPE_BYTES));
+  EXPECT_STREQ("uint32", GetCppTypeNameForFieldType(FD::TYPE_UINT32));
+  EXPECT_STREQ("enum", GetCppTypeNameForFieldType(FD::TYPE_ENUM));
+  EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_SFIXED32));
+  EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_SFIXED64));
+  EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_SINT32));
+  EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_SINT64));
+}
+
+TEST_F(MiscTest, StaticCppTypeNames) {
+  // Test that correct CPP type names are returned.
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_STREQ("int32", FD::CppTypeName(FD::CPPTYPE_INT32));
+  EXPECT_STREQ("int64", FD::CppTypeName(FD::CPPTYPE_INT64));
+  EXPECT_STREQ("uint32", FD::CppTypeName(FD::CPPTYPE_UINT32));
+  EXPECT_STREQ("uint64", FD::CppTypeName(FD::CPPTYPE_UINT64));
+  EXPECT_STREQ("double", FD::CppTypeName(FD::CPPTYPE_DOUBLE));
+  EXPECT_STREQ("float", FD::CppTypeName(FD::CPPTYPE_FLOAT));
+  EXPECT_STREQ("bool", FD::CppTypeName(FD::CPPTYPE_BOOL));
+  EXPECT_STREQ("enum", FD::CppTypeName(FD::CPPTYPE_ENUM));
+  EXPECT_STREQ("string", FD::CppTypeName(FD::CPPTYPE_STRING));
+  EXPECT_STREQ("message", FD::CppTypeName(FD::CPPTYPE_MESSAGE));
+}
+
+TEST_F(MiscTest, MessageType) {
+  // Test that message_type() is nullptr for non-aggregate fields
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_DOUBLE));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FLOAT));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_INT64));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_UINT64));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_INT32));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FIXED64));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FIXED32));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_BOOL));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_STRING));
+  EXPECT_TRUE(nullptr != GetMessageDescriptorForFieldType(FD::TYPE_GROUP));
+  EXPECT_TRUE(nullptr != GetMessageDescriptorForFieldType(FD::TYPE_MESSAGE));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_BYTES));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_UINT32));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_ENUM));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED32));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED64));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SINT32));
+  EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SINT64));
+}
+
+TEST_F(MiscTest, EnumType) {
+  // Test that enum_type() is nullptr for non-enum fields
+
+  typedef FieldDescriptor FD;  // avoid ugly line wrapping
+
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_DOUBLE));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FLOAT));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_INT64));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_UINT64));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_INT32));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FIXED64));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FIXED32));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_BOOL));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_STRING));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_GROUP));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_MESSAGE));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_BYTES));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_UINT32));
+  EXPECT_TRUE(nullptr != GetEnumDescriptorForFieldType(FD::TYPE_ENUM));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED32));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED64));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SINT32));
+  EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SINT64));
+}
+
+TEST_F(MiscTest, DefaultValues) {
+  // Test that setting default values works.
+  FileDescriptorProto file_proto;
+  file_proto.set_name("foo.proto");
+
+  EnumDescriptorProto* enum_type_proto = AddEnum(&file_proto, "DummyEnum");
+  AddEnumValue(enum_type_proto, "A", 1);
+  AddEnumValue(enum_type_proto, "B", 2);
+
+  DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
+
+  typedef FieldDescriptorProto FD;  // avoid ugly line wrapping
+  const FD::Label label = FD::LABEL_OPTIONAL;
+
+  // Create fields of every CPP type with default values.
+  AddField(message_proto, "int32", 1, label, FD::TYPE_INT32)
+      ->set_default_value("-1");
+  AddField(message_proto, "int64", 2, label, FD::TYPE_INT64)
+      ->set_default_value("-1000000000000");
+  AddField(message_proto, "uint32", 3, label, FD::TYPE_UINT32)
+      ->set_default_value("42");
+  AddField(message_proto, "uint64", 4, label, FD::TYPE_UINT64)
+      ->set_default_value("2000000000000");
+  AddField(message_proto, "float", 5, label, FD::TYPE_FLOAT)
+      ->set_default_value("4.5");
+  AddField(message_proto, "double", 6, label, FD::TYPE_DOUBLE)
+      ->set_default_value("10e100");
+  AddField(message_proto, "bool", 7, label, FD::TYPE_BOOL)
+      ->set_default_value("true");
+  AddField(message_proto, "string", 8, label, FD::TYPE_STRING)
+      ->set_default_value("hello");
+  AddField(message_proto, "data", 9, label, FD::TYPE_BYTES)
+      ->set_default_value("\\001\\002\\003");
+
+  FieldDescriptorProto* enum_field =
+      AddField(message_proto, "enum", 10, label, FD::TYPE_ENUM);
+  enum_field->set_type_name("DummyEnum");
+  enum_field->set_default_value("B");
+
+  // Strings are allowed to have empty defaults.  (At one point, due to
+  // a bug, empty defaults for strings were rejected.  Oops.)
+  AddField(message_proto, "empty_string", 11, label, FD::TYPE_STRING)
+      ->set_default_value("");
+
+  // Add a second set of fields with implicit default values.
+  AddField(message_proto, "implicit_int32", 21, label, FD::TYPE_INT32);
+  AddField(message_proto, "implicit_int64", 22, label, FD::TYPE_INT64);
+  AddField(message_proto, "implicit_uint32", 23, label, FD::TYPE_UINT32);
+  AddField(message_proto, "implicit_uint64", 24, label, FD::TYPE_UINT64);
+  AddField(message_proto, "implicit_float", 25, label, FD::TYPE_FLOAT);
+  AddField(message_proto, "implicit_double", 26, label, FD::TYPE_DOUBLE);
+  AddField(message_proto, "implicit_bool", 27, label, FD::TYPE_BOOL);
+  AddField(message_proto, "implicit_string", 28, label, FD::TYPE_STRING);
+  AddField(message_proto, "implicit_data", 29, label, FD::TYPE_BYTES);
+  AddField(message_proto, "implicit_enum", 30, label, FD::TYPE_ENUM)
+      ->set_type_name("DummyEnum");
+
+  // Build it.
+  DescriptorPool pool;
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != nullptr);
+
+  ASSERT_EQ(1, file->enum_type_count());
+  const EnumDescriptor* enum_type = file->enum_type(0);
+  ASSERT_EQ(2, enum_type->value_count());
+  const EnumValueDescriptor* enum_value_a = enum_type->value(0);
+  const EnumValueDescriptor* enum_value_b = enum_type->value(1);
+
+  ASSERT_EQ(1, file->message_type_count());
+  const Descriptor* message = file->message_type(0);
+
+  ASSERT_EQ(21, message->field_count());
+
+  // Check the default values.
+  ASSERT_TRUE(message->field(0)->has_default_value());
+  ASSERT_TRUE(message->field(1)->has_default_value());
+  ASSERT_TRUE(message->field(2)->has_default_value());
+  ASSERT_TRUE(message->field(3)->has_default_value());
+  ASSERT_TRUE(message->field(4)->has_default_value());
+  ASSERT_TRUE(message->field(5)->has_default_value());
+  ASSERT_TRUE(message->field(6)->has_default_value());
+  ASSERT_TRUE(message->field(7)->has_default_value());
+  ASSERT_TRUE(message->field(8)->has_default_value());
+  ASSERT_TRUE(message->field(9)->has_default_value());
+  ASSERT_TRUE(message->field(10)->has_default_value());
+
+  EXPECT_EQ(-1, message->field(0)->default_value_int32());
+  EXPECT_EQ(int64_t{-1000000000000}, message->field(1)->default_value_int64());
+  EXPECT_EQ(42, message->field(2)->default_value_uint32());
+  EXPECT_EQ(uint64_t{2000000000000}, message->field(3)->default_value_uint64());
+  EXPECT_EQ(4.5, message->field(4)->default_value_float());
+  EXPECT_EQ(10e100, message->field(5)->default_value_double());
+  EXPECT_TRUE(message->field(6)->default_value_bool());
+  EXPECT_EQ("hello", message->field(7)->default_value_string());
+  EXPECT_EQ("\001\002\003", message->field(8)->default_value_string());
+  EXPECT_EQ(enum_value_b, message->field(9)->default_value_enum());
+  EXPECT_EQ("", message->field(10)->default_value_string());
+
+  ASSERT_FALSE(message->field(11)->has_default_value());
+  ASSERT_FALSE(message->field(12)->has_default_value());
+  ASSERT_FALSE(message->field(13)->has_default_value());
+  ASSERT_FALSE(message->field(14)->has_default_value());
+  ASSERT_FALSE(message->field(15)->has_default_value());
+  ASSERT_FALSE(message->field(16)->has_default_value());
+  ASSERT_FALSE(message->field(17)->has_default_value());
+  ASSERT_FALSE(message->field(18)->has_default_value());
+  ASSERT_FALSE(message->field(19)->has_default_value());
+  ASSERT_FALSE(message->field(20)->has_default_value());
+
+  EXPECT_EQ(0, message->field(11)->default_value_int32());
+  EXPECT_EQ(0, message->field(12)->default_value_int64());
+  EXPECT_EQ(0, message->field(13)->default_value_uint32());
+  EXPECT_EQ(0, message->field(14)->default_value_uint64());
+  EXPECT_EQ(0.0f, message->field(15)->default_value_float());
+  EXPECT_EQ(0.0, message->field(16)->default_value_double());
+  EXPECT_FALSE(message->field(17)->default_value_bool());
+  EXPECT_EQ("", message->field(18)->default_value_string());
+  EXPECT_EQ("", message->field(19)->default_value_string());
+  EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum());
+}
+
+TEST_F(MiscTest, FieldOptions) {
+  // Try setting field options.
+
+  FileDescriptorProto file_proto;
+  file_proto.set_name("foo.proto");
+
+  DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
+  AddField(message_proto, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+           FieldDescriptorProto::TYPE_INT32);
+  FieldDescriptorProto* bar_proto =
+      AddField(message_proto, "bar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_INT32);
+
+  FieldOptions* options = bar_proto->mutable_options();
+  options->set_ctype(FieldOptions::CORD);
+
+  // Build the descriptors and get the pointers.
+  DescriptorPool pool;
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != nullptr);
+
+  ASSERT_EQ(1, file->message_type_count());
+  const Descriptor* message = file->message_type(0);
+
+  ASSERT_EQ(2, message->field_count());
+  const FieldDescriptor* foo = message->field(0);
+  const FieldDescriptor* bar = message->field(1);
+
+  // "foo" had no options set, so it should return the default options.
+  EXPECT_EQ(&FieldOptions::default_instance(), &foo->options());
+
+  // "bar" had options set.
+  EXPECT_NE(&FieldOptions::default_instance(), options);
+  EXPECT_TRUE(bar->options().has_ctype());
+  EXPECT_EQ(FieldOptions::CORD, bar->options().ctype());
+}
+
+// ===================================================================
+enum DescriptorPoolMode { NO_DATABASE, FALLBACK_DATABASE };
+
+class AllowUnknownDependenciesTest
+    : public testing::TestWithParam<
+          std::tuple<DescriptorPoolMode, const char*>> {
+ protected:
+  DescriptorPoolMode mode() { return std::get<0>(GetParam()); }
+  const char* syntax() { return std::get<1>(GetParam()); }
+
+  void SetUp() override {
+    FileDescriptorProto foo_proto, bar_proto;
+
+    switch (mode()) {
+      case NO_DATABASE:
+        pool_.reset(new DescriptorPool);
+        break;
+      case FALLBACK_DATABASE:
+        pool_.reset(new DescriptorPool(&db_));
+        break;
+    }
+
+    pool_->AllowUnknownDependencies();
+
+    ASSERT_TRUE(TextFormat::ParseFromString(
+        "name: 'foo.proto'"
+        "dependency: 'bar.proto'"
+        "dependency: 'baz.proto'"
+        "message_type {"
+        "  name: 'Foo'"
+        "  field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }"
+        "  field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }"
+        "  field { name:'moo' number:3 label:LABEL_OPTIONAL"
+        "    type_name: '.corge.Moo'"
+        "    type: TYPE_ENUM"
+        "    options {"
+        "      uninterpreted_option {"
+        "        name {"
+        "          name_part: 'grault'"
+        "          is_extension: true"
+        "        }"
+        "        positive_int_value: 1234"
+        "      }"
+        "    }"
+        "  }"
+        "}",
+        &foo_proto));
+    foo_proto.set_syntax(syntax());
+
+    ASSERT_TRUE(
+        TextFormat::ParseFromString("name: 'bar.proto'"
+                                    "message_type { name: 'Bar' }",
+                                    &bar_proto));
+    bar_proto.set_syntax(syntax());
+
+    // Collect pointers to stuff.
+    bar_file_ = BuildFile(bar_proto);
+    ASSERT_TRUE(bar_file_ != nullptr);
+
+    ASSERT_EQ(1, bar_file_->message_type_count());
+    bar_type_ = bar_file_->message_type(0);
+
+    foo_file_ = BuildFile(foo_proto);
+    ASSERT_TRUE(foo_file_ != nullptr);
+
+    ASSERT_EQ(1, foo_file_->message_type_count());
+    foo_type_ = foo_file_->message_type(0);
+
+    ASSERT_EQ(3, foo_type_->field_count());
+    bar_field_ = foo_type_->field(0);
+    baz_field_ = foo_type_->field(1);
+    moo_field_ = foo_type_->field(2);
+  }
+
+  const FileDescriptor* BuildFile(const FileDescriptorProto& proto) {
+    switch (mode()) {
+      case NO_DATABASE:
+        return pool_->BuildFile(proto);
+        break;
+      case FALLBACK_DATABASE: {
+        EXPECT_TRUE(db_.Add(proto));
+        return pool_->FindFileByName(proto.name());
+      }
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return nullptr;
+  }
+
+  const FileDescriptor* bar_file_;
+  const Descriptor* bar_type_;
+  const FileDescriptor* foo_file_;
+  const Descriptor* foo_type_;
+  const FieldDescriptor* bar_field_;
+  const FieldDescriptor* baz_field_;
+  const FieldDescriptor* moo_field_;
+
+  SimpleDescriptorDatabase db_;  // used if in FALLBACK_DATABASE mode.
+  std::unique_ptr<DescriptorPool> pool_;
+};
+
+TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
+  ASSERT_EQ(2, foo_file_->dependency_count());
+  EXPECT_EQ(bar_file_, foo_file_->dependency(0));
+  EXPECT_FALSE(bar_file_->is_placeholder());
+
+  const FileDescriptor* baz_file = foo_file_->dependency(1);
+  EXPECT_EQ("baz.proto", baz_file->name());
+  EXPECT_EQ(0, baz_file->message_type_count());
+  EXPECT_TRUE(baz_file->is_placeholder());
+
+  // Placeholder files should not be findable.
+  EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name()));
+  EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == nullptr);
+
+  // Copy*To should not crash for placeholder files.
+  FileDescriptorProto baz_file_proto;
+  baz_file->CopyTo(&baz_file_proto);
+  baz_file->CopySourceCodeInfoTo(&baz_file_proto);
+  EXPECT_FALSE(baz_file_proto.has_source_code_info());
+}
+
+TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
+  ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
+  EXPECT_EQ(bar_type_, bar_field_->message_type());
+  EXPECT_FALSE(bar_type_->is_placeholder());
+
+  ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type());
+  const Descriptor* baz_type = baz_field_->message_type();
+  EXPECT_EQ("Baz", baz_type->name());
+  EXPECT_EQ("Baz", baz_type->full_name());
+  EXPECT_EQ(0, baz_type->extension_range_count());
+  EXPECT_TRUE(baz_type->is_placeholder());
+
+  ASSERT_EQ(FieldDescriptor::TYPE_ENUM, moo_field_->type());
+  const EnumDescriptor* moo_type = moo_field_->enum_type();
+  EXPECT_EQ("Moo", moo_type->name());
+  EXPECT_EQ("corge.Moo", moo_type->full_name());
+  EXPECT_TRUE(moo_type->is_placeholder());
+  // Placeholder enum values should not be findable.
+  EXPECT_EQ(moo_type->FindValueByNumber(0), nullptr);
+
+  // Placeholder types should not be findable.
+  EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name()));
+  EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == nullptr);
+  EXPECT_TRUE(pool_->FindEnumTypeByName(moo_type->full_name()) == nullptr);
+}
+
+TEST_P(AllowUnknownDependenciesTest, CopyTo) {
+  // FieldDescriptor::CopyTo() should write non-fully-qualified type names
+  // for placeholder types which were not originally fully-qualified.
+  FieldDescriptorProto proto;
+
+  // Bar is not a placeholder, so it is fully-qualified.
+  bar_field_->CopyTo(&proto);
+  EXPECT_EQ(".Bar", proto.type_name());
+  EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type());
+
+  // Baz is an unqualified placeholder.
+  proto.Clear();
+  baz_field_->CopyTo(&proto);
+  EXPECT_EQ("Baz", proto.type_name());
+  EXPECT_FALSE(proto.has_type());
+
+  // Moo is a fully-qualified placeholder.
+  proto.Clear();
+  moo_field_->CopyTo(&proto);
+  EXPECT_EQ(".corge.Moo", proto.type_name());
+  EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
+}
+
+TEST_P(AllowUnknownDependenciesTest, CustomOptions) {
+  // Moo should still have the uninterpreted option attached.
+  ASSERT_EQ(1, moo_field_->options().uninterpreted_option_size());
+  const UninterpretedOption& option =
+      moo_field_->options().uninterpreted_option(0);
+  ASSERT_EQ(1, option.name_size());
+  EXPECT_EQ("grault", option.name(0).name_part());
+}
+
+TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) {
+  // Test that we can extend an unknown type.  This is slightly tricky because
+  // it means that the placeholder type must have an extension range.
+
+  FileDescriptorProto extension_proto;
+
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: 'extension.proto'"
+      "extension { extendee: 'UnknownType' name:'some_extension' number:123"
+      "            label:LABEL_OPTIONAL type:TYPE_INT32 }",
+      &extension_proto));
+  const FileDescriptor* file = BuildFile(extension_proto);
+
+  ASSERT_TRUE(file != nullptr);
+
+  ASSERT_EQ(1, file->extension_count());
+  const Descriptor* extendee = file->extension(0)->containing_type();
+  EXPECT_EQ("UnknownType", extendee->name());
+  EXPECT_TRUE(extendee->is_placeholder());
+  ASSERT_EQ(1, extendee->extension_range_count());
+  EXPECT_EQ(1, extendee->extension_range(0)->start);
+  EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end);
+}
+
+TEST_P(AllowUnknownDependenciesTest, CustomOption) {
+  // Test that we can use a custom option without having parsed
+  // descriptor.proto.
+
+  FileDescriptorProto option_proto;
+
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"unknown_custom_options.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { "
+      "  extendee: \"google.protobuf.FileOptions\" "
+      "  name: \"some_option\" "
+      "  number: 123456 "
+      "  label: LABEL_OPTIONAL "
+      "  type: TYPE_INT32 "
+      "} "
+      "options { "
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"some_option\" "
+      "      is_extension: true "
+      "    } "
+      "    positive_int_value: 1234 "
+      "  } "
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"unknown_option\" "
+      "      is_extension: true "
+      "    } "
+      "    positive_int_value: 1234 "
+      "  } "
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"optimize_for\" "
+      "      is_extension: false "
+      "    } "
+      "    identifier_value: \"SPEED\" "
+      "  } "
+      "}",
+      &option_proto));
+
+  const FileDescriptor* file = BuildFile(option_proto);
+  ASSERT_TRUE(file != nullptr);
+
+  // Verify that no extension options were set, but they were left as
+  // uninterpreted_options.
+  std::vector<const FieldDescriptor*> fields;
+  file->options().GetReflection()->ListFields(file->options(), &fields);
+  ASSERT_EQ(2, fields.size());
+  EXPECT_TRUE(file->options().has_optimize_for());
+  EXPECT_EQ(2, file->options().uninterpreted_option_size());
+}
+
+TEST_P(AllowUnknownDependenciesTest,
+       UndeclaredDependencyTriggersBuildOfDependency) {
+  // Crazy case: suppose foo.proto refers to a symbol without declaring the
+  // dependency that finds it. In the event that the pool is backed by a
+  // DescriptorDatabase, the pool will attempt to find the symbol in the
+  // database. If successful, it will build the undeclared dependency to verify
+  // that the file does indeed contain the symbol. If that file fails to build,
+  // then its descriptors must be rolled back. However, we still want foo.proto
+  // to build successfully, since we are allowing unknown dependencies.
+
+  FileDescriptorProto undeclared_dep_proto;
+  // We make this file fail to build by giving it two fields with tag 1.
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"invalid_file_as_undeclared_dep.proto\" "
+      "package: \"undeclared\" "
+      "message_type: {  "
+      "  name: \"Mooo\"  "
+      "  field { "
+      "    name:'moo' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 "
+      "  }"
+      "  field { "
+      "    name:'mooo' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 "
+      "  }"
+      "}",
+      &undeclared_dep_proto));
+  // We can't use the BuildFile() helper because we don't actually want to build
+  // it into the descriptor pool in the fallback database case: it just needs to
+  // be sitting in the database so that it gets built during the building of
+  // test.proto below.
+  switch (mode()) {
+    case NO_DATABASE: {
+      ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == nullptr);
+      break;
+    }
+    case FALLBACK_DATABASE: {
+      ASSERT_TRUE(db_.Add(undeclared_dep_proto));
+    }
+  }
+
+  FileDescriptorProto test_proto;
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"test.proto\" "
+      "message_type: { "
+      "  name: \"Corge\" "
+      "  field { "
+      "    name:'mooo' number:1 label: LABEL_OPTIONAL "
+      "    type_name:'undeclared.Mooo' type: TYPE_MESSAGE "
+      "  }"
+      "}",
+      &test_proto));
+
+  const FileDescriptor* file = BuildFile(test_proto);
+  ASSERT_TRUE(file != nullptr);
+  GOOGLE_LOG(INFO) << file->DebugString();
+
+  EXPECT_EQ(0, file->dependency_count());
+  ASSERT_EQ(1, file->message_type_count());
+  const Descriptor* corge_desc = file->message_type(0);
+  ASSERT_EQ("Corge", corge_desc->name());
+  ASSERT_EQ(1, corge_desc->field_count());
+  EXPECT_FALSE(corge_desc->is_placeholder());
+
+  const FieldDescriptor* mooo_field = corge_desc->field(0);
+  ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, mooo_field->type());
+  ASSERT_EQ("Mooo", mooo_field->message_type()->name());
+  ASSERT_EQ("undeclared.Mooo", mooo_field->message_type()->full_name());
+  EXPECT_TRUE(mooo_field->message_type()->is_placeholder());
+  // The place holder type should not be findable.
+  ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Mooo") == nullptr);
+}
+
+INSTANTIATE_TEST_SUITE_P(DatabaseSource, AllowUnknownDependenciesTest,
+                         testing::Combine(testing::Values(NO_DATABASE,
+                                                          FALLBACK_DATABASE),
+                                          testing::Values("proto2", "proto3")));
+
+// ===================================================================
+
+TEST(CustomOptions, OptionLocations) {
+  const Descriptor* message =
+      protobuf_unittest::TestMessageWithCustomOptions::descriptor();
+  const FileDescriptor* file = message->file();
+  const FieldDescriptor* field = message->FindFieldByName("field1");
+  const OneofDescriptor* oneof = message->FindOneofByName("AnOneof");
+  const FieldDescriptor* map_field = message->FindFieldByName("map_field");
+  const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
+  // TODO(benjy): Support EnumValue options, once the compiler does.
+  const ServiceDescriptor* service =
+      file->FindServiceByName("TestServiceWithCustomOptions");
+  const MethodDescriptor* method = service->FindMethodByName("Foo");
+
+  EXPECT_EQ(int64_t{9876543210},
+            file->options().GetExtension(protobuf_unittest::file_opt1));
+  EXPECT_EQ(-56,
+            message->options().GetExtension(protobuf_unittest::message_opt1));
+  EXPECT_EQ(int64_t{8765432109},
+            field->options().GetExtension(protobuf_unittest::field_opt1));
+  EXPECT_EQ(42,  // Check that we get the default for an option we don't set.
+            field->options().GetExtension(protobuf_unittest::field_opt2));
+  EXPECT_EQ(-99, oneof->options().GetExtension(protobuf_unittest::oneof_opt1));
+  EXPECT_EQ(int64_t{12345},
+            map_field->options().GetExtension(protobuf_unittest::field_opt1));
+  EXPECT_EQ(-789, enm->options().GetExtension(protobuf_unittest::enum_opt1));
+  EXPECT_EQ(123, enm->value(1)->options().GetExtension(
+                     protobuf_unittest::enum_value_opt1));
+  EXPECT_EQ(int64_t{-9876543210},
+            service->options().GetExtension(protobuf_unittest::service_opt1));
+  EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2,
+            method->options().GetExtension(protobuf_unittest::method_opt1));
+
+  // See that the regular options went through unscathed.
+  EXPECT_TRUE(message->options().has_message_set_wire_format());
+  EXPECT_EQ(FieldOptions::CORD, field->options().ctype());
+}
+
+TEST(CustomOptions, OptionTypes) {
+  const MessageOptions* options = nullptr;
+
+  constexpr int32_t kint32min = std::numeric_limits<int32_t>::min();
+  constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
+  constexpr uint32_t kuint32max = std::numeric_limits<uint32_t>::max();
+  constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+  constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+  constexpr uint64_t kuint64max = std::numeric_limits<uint64_t>::max();
+
+  options =
+      &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options();
+  EXPECT_EQ(false, options->GetExtension(protobuf_unittest::bool_opt));
+  EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt));
+  EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt));
+  EXPECT_EQ(0, options->GetExtension(protobuf_unittest::uint32_opt));
+  EXPECT_EQ(0, options->GetExtension(protobuf_unittest::uint64_opt));
+  EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sint32_opt));
+  EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sint64_opt));
+  EXPECT_EQ(0, options->GetExtension(protobuf_unittest::fixed32_opt));
+  EXPECT_EQ(0, options->GetExtension(protobuf_unittest::fixed64_opt));
+  EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sfixed32_opt));
+  EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sfixed64_opt));
+
+  options =
+      &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options();
+  EXPECT_EQ(true, options->GetExtension(protobuf_unittest::bool_opt));
+  EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::int32_opt));
+  EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::int64_opt));
+  EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt));
+  EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::uint64_opt));
+  EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::sint32_opt));
+  EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::sint64_opt));
+  EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::fixed32_opt));
+  EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::fixed64_opt));
+  EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::sfixed32_opt));
+  EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::sfixed64_opt));
+
+  options = &protobuf_unittest::CustomOptionOtherValues::descriptor()->options();
+  EXPECT_EQ(-100, options->GetExtension(protobuf_unittest::int32_opt));
+  EXPECT_FLOAT_EQ(12.3456789,
+                  options->GetExtension(protobuf_unittest::float_opt));
+  EXPECT_DOUBLE_EQ(1.234567890123456789,
+                   options->GetExtension(protobuf_unittest::double_opt));
+  EXPECT_EQ("Hello, \"World\"",
+            options->GetExtension(protobuf_unittest::string_opt));
+
+  EXPECT_EQ(std::string("Hello\0World", 11),
+            options->GetExtension(protobuf_unittest::bytes_opt));
+
+  EXPECT_EQ(protobuf_unittest::DummyMessageContainingEnum::TEST_OPTION_ENUM_TYPE2,
+            options->GetExtension(protobuf_unittest::enum_opt));
+
+  options =
+      &protobuf_unittest::SettingRealsFromPositiveInts::descriptor()->options();
+  EXPECT_FLOAT_EQ(12, options->GetExtension(protobuf_unittest::float_opt));
+  EXPECT_DOUBLE_EQ(154, options->GetExtension(protobuf_unittest::double_opt));
+
+  options =
+      &protobuf_unittest::SettingRealsFromNegativeInts::descriptor()->options();
+  EXPECT_FLOAT_EQ(-12, options->GetExtension(protobuf_unittest::float_opt));
+  EXPECT_DOUBLE_EQ(-154, options->GetExtension(protobuf_unittest::double_opt));
+}
+
+TEST(CustomOptions, ComplexExtensionOptions) {
+  const MessageOptions* options =
+      &protobuf_unittest::VariousComplexOptions::descriptor()->options();
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).foo(), 42);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1)
+                .GetExtension(protobuf_unittest::mooo),
+            324);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1)
+                .GetExtension(protobuf_unittest::corge)
+                .moo(),
+            876);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).baz(), 987);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
+                .GetExtension(protobuf_unittest::grault),
+            654);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().foo(),
+            743);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
+                .bar()
+                .GetExtension(protobuf_unittest::mooo),
+            1999);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
+                .bar()
+                .GetExtension(protobuf_unittest::corge)
+                .moo(),
+            2008);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
+                .GetExtension(protobuf_unittest::garply)
+                .foo(),
+            741);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
+                .GetExtension(protobuf_unittest::garply)
+                .GetExtension(protobuf_unittest::mooo),
+            1998);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
+                .GetExtension(protobuf_unittest::garply)
+                .GetExtension(protobuf_unittest::corge)
+                .moo(),
+            2121);
+  EXPECT_EQ(options
+                ->GetExtension(protobuf_unittest::ComplexOptionType2::
+                                   ComplexOptionType4::complex_opt4)
+                .waldo(),
+            1971);
+  EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).fred().waldo(),
+            321);
+  EXPECT_EQ(9, options->GetExtension(protobuf_unittest::complex_opt3).moo());
+  EXPECT_EQ(22, options->GetExtension(protobuf_unittest::complex_opt3)
+                    .complexoptiontype5()
+                    .plugh());
+  EXPECT_EQ(24, options->GetExtension(protobuf_unittest::complexopt6).xyzzy());
+}
+
+TEST(CustomOptions, OptionsFromOtherFile) {
+  // Test that to use a custom option, we only need to import the file
+  // defining the option; we do not also have to import descriptor.proto.
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // We have to import the Any dependency.
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
+  protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
+      &file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"custom_options_import.proto\" "
+      "package: \"protobuf_unittest\" "
+      "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+      "options { "
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"file_opt1\" "
+      "      is_extension: true "
+      "    } "
+      "    positive_int_value: 1234 "
+      "  } "
+      // Test a non-extension option too.  (At one point this failed due to a
+      // bug.)
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"java_package\" "
+      "      is_extension: false "
+      "    } "
+      "    string_value: \"foo\" "
+      "  } "
+      // Test that enum-typed options still work too.  (At one point this also
+      // failed due to a bug.)
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"optimize_for\" "
+      "      is_extension: false "
+      "    } "
+      "    identifier_value: \"SPEED\" "
+      "  } "
+      "}",
+      &file_proto));
+
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != nullptr);
+  EXPECT_EQ(1234, file->options().GetExtension(protobuf_unittest::file_opt1));
+  EXPECT_TRUE(file->options().has_java_package());
+  EXPECT_EQ("foo", file->options().java_package());
+  EXPECT_TRUE(file->options().has_optimize_for());
+  EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
+}
+
+TEST(CustomOptions, MessageOptionThreeFieldsSet) {
+  // This tests a bug which previously existed in custom options parsing.  The
+  // bug occurred when you defined a custom option with message type and then
+  // set three fields of that option on a single definition (see the example
+  // below).  The bug is a bit hard to explain, so check the change history if
+  // you want to know more.
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
+  protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
+      &file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // The following represents the definition:
+  //
+  //   import "google/protobuf/unittest_custom_options.proto"
+  //   package protobuf_unittest;
+  //   message Foo {
+  //     option (complex_opt1).foo  = 1234;
+  //     option (complex_opt1).foo2 = 1234;
+  //     option (complex_opt1).foo3 = 1234;
+  //   }
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"custom_options_import.proto\" "
+      "package: \"protobuf_unittest\" "
+      "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "  options { "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt1\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"foo\" "
+      "        is_extension: false "
+      "      } "
+      "      positive_int_value: 1234 "
+      "    } "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt1\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"foo2\" "
+      "        is_extension: false "
+      "      } "
+      "      positive_int_value: 1234 "
+      "    } "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt1\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"foo3\" "
+      "        is_extension: false "
+      "      } "
+      "      positive_int_value: 1234 "
+      "    } "
+      "  } "
+      "}",
+      &file_proto));
+
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != nullptr);
+  ASSERT_EQ(1, file->message_type_count());
+
+  const MessageOptions& options = file->message_type(0)->options();
+  EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
+}
+
+TEST(CustomOptions, MessageOptionRepeatedLeafFieldSet) {
+  // This test verifies that repeated fields in custom options can be
+  // given multiple values by repeating the option with a different value.
+  // This test checks repeated leaf values. Each repeated custom value
+  // appears in a different uninterpreted_option, which will be concatenated
+  // when they are merged into the final option value.
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
+  protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
+      &file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // The following represents the definition:
+  //
+  //   import "google/protobuf/unittest_custom_options.proto"
+  //   package protobuf_unittest;
+  //   message Foo {
+  //     option (complex_opt1).foo4 = 12;
+  //     option (complex_opt1).foo4 = 34;
+  //     option (complex_opt1).foo4 = 56;
+  //   }
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"custom_options_import.proto\" "
+      "package: \"protobuf_unittest\" "
+      "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "  options { "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt1\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"foo4\" "
+      "        is_extension: false "
+      "      } "
+      "      positive_int_value: 12 "
+      "    } "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt1\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"foo4\" "
+      "        is_extension: false "
+      "      } "
+      "      positive_int_value: 34 "
+      "    } "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt1\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"foo4\" "
+      "        is_extension: false "
+      "      } "
+      "      positive_int_value: 56 "
+      "    } "
+      "  } "
+      "}",
+      &file_proto));
+
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != nullptr);
+  ASSERT_EQ(1, file->message_type_count());
+
+  const MessageOptions& options = file->message_type(0)->options();
+  EXPECT_EQ(3, options.GetExtension(protobuf_unittest::complex_opt1).foo4_size());
+  EXPECT_EQ(12, options.GetExtension(protobuf_unittest::complex_opt1).foo4(0));
+  EXPECT_EQ(34, options.GetExtension(protobuf_unittest::complex_opt1).foo4(1));
+  EXPECT_EQ(56, options.GetExtension(protobuf_unittest::complex_opt1).foo4(2));
+}
+
+TEST(CustomOptions, MessageOptionRepeatedMsgFieldSet) {
+  // This test verifies that repeated fields in custom options can be
+  // given multiple values by repeating the option with a different value.
+  // This test checks repeated message values. Each repeated custom value
+  // appears in a different uninterpreted_option, which will be concatenated
+  // when they are merged into the final option value.
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
+  protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
+      &file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // The following represents the definition:
+  //
+  //   import "google/protobuf/unittest_custom_options.proto"
+  //   package protobuf_unittest;
+  //   message Foo {
+  //     option (complex_opt2).barney = {waldo: 1};
+  //     option (complex_opt2).barney = {waldo: 10};
+  //     option (complex_opt2).barney = {waldo: 100};
+  //   }
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"custom_options_import.proto\" "
+      "package: \"protobuf_unittest\" "
+      "dependency: \"google/protobuf/unittest_custom_options.proto\" "
+      "message_type { "
+      "  name: \"Foo\" "
+      "  options { "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt2\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"barney\" "
+      "        is_extension: false "
+      "      } "
+      "      aggregate_value: \"waldo: 1\" "
+      "    } "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt2\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"barney\" "
+      "        is_extension: false "
+      "      } "
+      "      aggregate_value: \"waldo: 10\" "
+      "    } "
+      "    uninterpreted_option { "
+      "      name { "
+      "        name_part: \"complex_opt2\" "
+      "        is_extension: true "
+      "      } "
+      "      name { "
+      "        name_part: \"barney\" "
+      "        is_extension: false "
+      "      } "
+      "      aggregate_value: \"waldo: 100\" "
+      "    } "
+      "  } "
+      "}",
+      &file_proto));
+
+  const FileDescriptor* file = pool.BuildFile(file_proto);
+  ASSERT_TRUE(file != nullptr);
+  ASSERT_EQ(1, file->message_type_count());
+
+  const MessageOptions& options = file->message_type(0)->options();
+  EXPECT_EQ(3,
+            options.GetExtension(protobuf_unittest::complex_opt2).barney_size());
+  EXPECT_EQ(
+      1, options.GetExtension(protobuf_unittest::complex_opt2).barney(0).waldo());
+  EXPECT_EQ(
+      10,
+      options.GetExtension(protobuf_unittest::complex_opt2).barney(1).waldo());
+  EXPECT_EQ(
+      100,
+      options.GetExtension(protobuf_unittest::complex_opt2).barney(2).waldo());
+}
+
+// Check that aggregate options were parsed and saved correctly in
+// the appropriate descriptors.
+TEST(CustomOptions, AggregateOptions) {
+  const Descriptor* msg = protobuf_unittest::AggregateMessage::descriptor();
+  const FileDescriptor* file = msg->file();
+  const FieldDescriptor* field = msg->FindFieldByName("fieldname");
+  const EnumDescriptor* enumd = file->FindEnumTypeByName("AggregateEnum");
+  const EnumValueDescriptor* enumv = enumd->FindValueByName("VALUE");
+  const ServiceDescriptor* service =
+      file->FindServiceByName("AggregateService");
+  const MethodDescriptor* method = service->FindMethodByName("Method");
+
+  // Tests for the different types of data embedded in fileopt
+  const protobuf_unittest::Aggregate& file_options =
+      file->options().GetExtension(protobuf_unittest::fileopt);
+  EXPECT_EQ(100, file_options.i());
+  EXPECT_EQ("FileAnnotation", file_options.s());
+  EXPECT_EQ("NestedFileAnnotation", file_options.sub().s());
+  EXPECT_EQ("FileExtensionAnnotation",
+            file_options.file().GetExtension(protobuf_unittest::fileopt).s());
+  EXPECT_EQ("EmbeddedMessageSetElement",
+            file_options.mset()
+                .GetExtension(protobuf_unittest::AggregateMessageSetElement ::
+                                  message_set_extension)
+                .s());
+
+  protobuf_unittest::AggregateMessageSetElement any_payload;
+  ASSERT_TRUE(file_options.any().UnpackTo(&any_payload));
+  EXPECT_EQ("EmbeddedMessageSetElement", any_payload.s());
+
+  // Simple tests for all the other types of annotations
+  EXPECT_EQ("MessageAnnotation",
+            msg->options().GetExtension(protobuf_unittest::msgopt).s());
+  EXPECT_EQ("FieldAnnotation",
+            field->options().GetExtension(protobuf_unittest::fieldopt).s());
+  EXPECT_EQ("EnumAnnotation",
+            enumd->options().GetExtension(protobuf_unittest::enumopt).s());
+  EXPECT_EQ("EnumValueAnnotation",
+            enumv->options().GetExtension(protobuf_unittest::enumvalopt).s());
+  EXPECT_EQ("ServiceAnnotation",
+            service->options().GetExtension(protobuf_unittest::serviceopt).s());
+  EXPECT_EQ("MethodAnnotation",
+            method->options().GetExtension(protobuf_unittest::methodopt).s());
+}
+
+TEST(CustomOptions, UnusedImportError) {
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
+  protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
+      &file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  pool.AddUnusedImportTrackFile("custom_options_import.proto", true);
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"custom_options_import.proto\" "
+      "package: \"protobuf_unittest\" "
+      "dependency: \"google/protobuf/unittest_custom_options.proto\" ",
+      &file_proto));
+
+  MockErrorCollector error_collector;
+  EXPECT_FALSE(pool.BuildFileCollectingErrors(file_proto, &error_collector));
+  EXPECT_EQ(
+      "custom_options_import.proto: "
+      "google/protobuf/unittest_custom_options.proto: IMPORT: Import "
+      "google/protobuf/unittest_custom_options.proto is unused.\n",
+      error_collector.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, OptionsWithIncompatibleDescriptors) {
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  MessageOptions::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // 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()));
+
+  // Adding the file descriptor to the pool should fail.
+  EXPECT_TRUE(pool.BuildFile(file_proto) == nullptr);
+}
+
+// Test that FileDescriptor::DebugString() formats custom options correctly.
+TEST(CustomOptions, DebugString) {
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  MessageOptions::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // Add "foo.proto":
+  //   import "google/protobuf/descriptor.proto";
+  //   package "protobuf_unittest";
+  //   option (protobuf_unittest.cc_option1) = 1;
+  //   option (protobuf_unittest.cc_option2) = 2;
+  //   extend google.protobuf.FieldOptions {
+  //     optional int32 cc_option1 = 7736974;
+  //     optional int32 cc_option2 = 7736975;
+  //   }
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: \"foo.proto\" "
+      "package: \"protobuf_unittest\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "options { "
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"protobuf_unittest.cc_option1\" "
+      "      is_extension: true "
+      "    } "
+      "    positive_int_value: 1 "
+      "  } "
+      "  uninterpreted_option { "
+      "    name { "
+      "      name_part: \"protobuf_unittest.cc_option2\" "
+      "      is_extension: true "
+      "    } "
+      "    positive_int_value: 2 "
+      "  } "
+      "} "
+      "extension { "
+      "  name: \"cc_option1\" "
+      "  extendee: \".google.protobuf.FileOptions\" "
+      // This field number is intentionally chosen to be the same as
+      // (.fileopt1) defined in unittest_custom_options.proto (linked
+      // in this test binary). This is to test whether we are messing
+      // generated pool with custom descriptor pools when dealing with
+      // custom options.
+      "  number: 7736974 "
+      "  label: LABEL_OPTIONAL "
+      "  type: TYPE_INT32 "
+      "}"
+      "extension { "
+      "  name: \"cc_option2\" "
+      "  extendee: \".google.protobuf.FileOptions\" "
+      "  number: 7736975 "
+      "  label: LABEL_OPTIONAL "
+      "  type: TYPE_INT32 "
+      "}",
+      &file_proto));
+  const FileDescriptor* descriptor = pool.BuildFile(file_proto);
+  ASSERT_TRUE(descriptor != nullptr);
+
+  EXPECT_EQ(2, descriptor->extension_count());
+
+  ASSERT_EQ(
+      "syntax = \"proto2\";\n"
+      "\n"
+      "import \"google/protobuf/descriptor.proto\";\n"
+      "package protobuf_unittest;\n"
+      "\n"
+      "option (.protobuf_unittest.cc_option1) = 1;\n"
+      "option (.protobuf_unittest.cc_option2) = 2;\n"
+      "\n"
+      "extend .google.protobuf.FileOptions {\n"
+      "  optional int32 cc_option1 = 7736974;\n"
+      "  optional int32 cc_option2 = 7736975;\n"
+      "}\n"
+      "\n",
+      descriptor->DebugString());
+}
+
+// ===================================================================
+
+class ValidationErrorTest : public testing::Test {
+ protected:
+  // Parse file_text as a FileDescriptorProto in text format and add it
+  // to the DescriptorPool.  Expect no errors.
+  const FileDescriptor* BuildFile(const std::string& file_text) {
+    FileDescriptorProto file_proto;
+    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
+  // to the DescriptorPool.  Expect errors to be produced which match the
+  // given error text.
+  void BuildFileWithErrors(const std::string& file_text,
+                           const std::string& expected_errors) {
+    FileDescriptorProto file_proto;
+    ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+
+    MockErrorCollector error_collector;
+    EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
+                nullptr);
+    EXPECT_EQ(expected_errors, error_collector.text_);
+  }
+
+  // Parse file_text as a FileDescriptorProto in text format and add it
+  // to the DescriptorPool.  Expect errors to be produced which match the
+  // given warning text.
+  void BuildFileWithWarnings(const std::string& file_text,
+                             const std::string& expected_warnings) {
+    FileDescriptorProto file_proto;
+    ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+
+    MockErrorCollector error_collector;
+    EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector));
+    EXPECT_EQ(expected_warnings, error_collector.warning_text_);
+  }
+
+  // Builds some already-parsed file in our test pool.
+  void BuildFileInTestPool(const FileDescriptor* file) {
+    FileDescriptorProto file_proto;
+    file->CopyTo(&file_proto);
+    ASSERT_TRUE(pool_.BuildFile(file_proto) != nullptr);
+  }
+
+  // Build descriptor.proto in our test pool. This allows us to extend it in
+  // the test pool, so we can test custom options.
+  void BuildDescriptorMessagesInTestPool() {
+    BuildFileInTestPool(DescriptorProto::descriptor()->file());
+  }
+
+  DescriptorPool pool_;
+};
+
+TEST_F(ValidationErrorTest, AlreadyDefined) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" }"
+      "message_type { name: \"Foo\" }",
+
+      "foo.proto: Foo: NAME: \"Foo\" is already defined.\n");
+}
+
+TEST_F(ValidationErrorTest, AlreadyDefinedInPackage) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "package: \"foo.bar\" "
+      "message_type { name: \"Foo\" }"
+      "message_type { name: \"Foo\" }",
+
+      "foo.proto: foo.bar.Foo: NAME: \"Foo\" is already defined in "
+      "\"foo.bar\".\n");
+}
+
+TEST_F(ValidationErrorTest, AlreadyDefinedInOtherFile) {
+  BuildFile(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" }");
+
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Foo\" }",
+
+      "bar.proto: Foo: NAME: \"Foo\" is already defined in file "
+      "\"foo.proto\".\n");
+}
+
+TEST_F(ValidationErrorTest, PackageAlreadyDefined) {
+  BuildFile(
+      "name: \"foo.proto\" "
+      "message_type { name: \"foo\" }");
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "package: \"foo.bar\"",
+
+      "bar.proto: foo: NAME: \"foo\" is already defined (as something other "
+      "than a package) in file \"foo.proto\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
+      "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
+
+      "foo.proto: FOO: NAME: \"FOO\" is already defined.\n"
+      "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, "
+      "meaning that enum values are siblings of their type, not children of "
+      "it.  Therefore, \"FOO\" must be unique within the global scope, not "
+      "just within \"Bar\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "package: \"pkg\" "
+      "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
+      "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
+
+      "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n"
+      "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, "
+      "meaning that enum values are siblings of their type, not children of "
+      "it.  Therefore, \"FOO\" must be unique within \"pkg\", not just within "
+      "\"Bar\".\n");
+}
+
+TEST_F(ValidationErrorTest, MissingName) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { }",
+
+      "foo.proto: : NAME: Missing name.\n");
+}
+
+TEST_F(ValidationErrorTest, InvalidName) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"$\" }",
+
+      "foo.proto: $: NAME: \"$\" is not a valid identifier.\n");
+}
+
+TEST_F(ValidationErrorTest, InvalidPackageName) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "package: \"foo.$\"",
+
+      "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n");
+}
+
+// 'str' is a static C-style string that may contain '\0'
+#define STATIC_STR(str) std::string((str), sizeof(str) - 1)
+
+TEST_F(ValidationErrorTest, NullCharSymbolName) {
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "package: \"foo\""
+      "message_type { "
+      "  name: '\\000\\001\\013.Bar' "
+      "  field { name: \"foo\" number:  9 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "} "
+      "}",
+      STATIC_STR("bar.proto: foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a "
+                 "valid identifier.\nbar.proto: foo.\0\x1\v.Bar.foo: NAME: "
+                 "\"foo.\0\x1\v.Bar.foo\" contains null character.\nbar.proto: "
+                 "foo.\0\x1\v.Bar: NAME: \"foo.\0\x1\v.Bar\" contains null "
+                 "character.\n"));
+}
+
+TEST_F(ValidationErrorTest, NullCharFileName) {
+  BuildFileWithErrors(
+      "name: \"bar\\000\\001\\013.proto\" "
+      "package: \"outer.foo\"",
+      STATIC_STR("bar\0\x1\v.proto: bar\0\x1\v.proto: NAME: "
+                 "\"bar\0\x1\v.proto\" contains null character.\n"));
+}
+
+TEST_F(ValidationErrorTest, NullCharPackageName) {
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "package: \"\\000\\001\\013.\"",
+      STATIC_STR("bar.proto: \0\x1\v.: NAME: \"\0\x1\v.\" contains null "
+                 "character.\n"));
+}
+
+TEST_F(ValidationErrorTest, MissingFileName) {
+  BuildFileWithErrors("",
+
+                      ": : OTHER: Missing field: FileDescriptorProto.name.\n");
+}
+
+TEST_F(ValidationErrorTest, DupeDependency) {
+  BuildFile("name: \"foo.proto\"");
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "dependency: \"foo.proto\" "
+      "dependency: \"foo.proto\" ",
+
+      "bar.proto: foo.proto: IMPORT: Import \"foo.proto\" was listed twice.\n");
+}
+
+TEST_F(ValidationErrorTest, UnknownDependency) {
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "dependency: \"foo.proto\" ",
+
+      "bar.proto: foo.proto: IMPORT: Import \"foo.proto\" has not been "
+      "loaded.\n");
+}
+
+TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) {
+  BuildFile("name: \"foo.proto\"");
+  BuildFileWithErrors(
+      "name: \"bar.proto\" "
+      "dependency: \"foo.proto\" "
+      "public_dependency: 1",
+      "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n");
+}
+
+TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
+  // Used to crash:  If we depend on a non-existent file and then refer to a
+  // package defined in a file that we didn't import, and that package is
+  // nested within a parent package which this file is also in, and we don't
+  // include that parent package in the name (i.e. we do a relative lookup)...
+  // Yes, really.
+  BuildFile(
+      "name: 'foo.proto' "
+      "package: 'outer.foo' ");
+  BuildFileWithErrors(
+      "name: 'bar.proto' "
+      "dependency: 'baz.proto' "
+      "package: 'outer.bar' "
+      "message_type { "
+      "  name: 'Bar' "
+      "  field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
+      "}",
+
+      "bar.proto: baz.proto: IMPORT: Import \"baz.proto\" has not been "
+      "loaded.\n"
+      "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined "
+      "in "
+      "\"foo.proto\", which is not imported by \"bar.proto\".  To use it here, "
+      "please add the necessary import.\n");
+}
+
+TEST_F(ValidationErrorTest, DupeFile) {
+  BuildFile(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" }");
+  // Note:  We should *not* get redundant errors about "Foo" already being
+  //   defined.
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" } "
+      // Add another type so that the files aren't identical (in which case
+      // there would be no error).
+      "enum_type { name: \"Bar\" }",
+
+      "foo.proto: foo.proto: OTHER: A file with this name is already in the "
+      "pool.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldInExtensionRange) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name: \"foo\" number:  9 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "}"
+      "  field { name: \"bar\" number: 10 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "}"
+      "  field { name: \"baz\" number: 19 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "}"
+      "  field { name: \"moo\" number: 20 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "}"
+      "  extension_range { start: 10 end: 20 }"
+      "}",
+
+      "foo.proto: Foo.bar: NUMBER: Extension range 10 to 19 includes field "
+      "\"bar\" (10).\n"
+      "foo.proto: Foo.baz: NUMBER: Extension range 10 to 19 includes field "
+      "\"baz\" (19).\n"
+      "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1, 2\n");
+}
+
+TEST_F(ValidationErrorTest, OverlappingExtensionRanges) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension_range { start: 10 end: 20 }"
+      "  extension_range { start: 20 end: 30 }"
+      "  extension_range { start: 19 end: 21 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
+      "already-defined range 10 to 19.\n"
+      "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
+      "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"
+      "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1\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, DebugStringReservedRangeMax) {
+  const FileDescriptor* file = BuildFile(strings::Substitute(
+      "name: \"foo.proto\" "
+      "enum_type { "
+      "  name: \"Bar\""
+      "  value { name:\"BAR\" number:1 }"
+      "  reserved_range { start: 5 end: $0 }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  reserved_range { start: 5 end: $1 }"
+      "}",
+      std::numeric_limits<int>::max(), FieldDescriptor::kMaxNumber + 1));
+
+  ASSERT_EQ(
+      "syntax = \"proto2\";\n\n"
+      "enum Bar {\n"
+      "  BAR = 1;\n"
+      "  reserved 5 to max;\n"
+      "}\n\n"
+      "message Foo {\n"
+      "  reserved 5 to max;\n"
+      "}\n\n",
+      file->DebugString());
+}
+
+TEST_F(ValidationErrorTest, EnumReservedFieldError) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:15 }"
+      "  reserved_range { start: 10 end: 20 }"
+      "}",
+
+      "foo.proto: BAR: NUMBER: Enum value \"BAR\" uses reserved number 15.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumNegativeReservedFieldError) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:-15 }"
+      "  reserved_range { start: -20 end: -10 }"
+      "}",
+
+      "foo.proto: BAR: NUMBER: Enum value \"BAR\" uses reserved number -15.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumReservedRangeOverlap) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:0 }"
+      "  reserved_range { start: 10 end: 20 }"
+      "  reserved_range { start: 5 end: 15 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Reserved range 5 to 15"
+      " overlaps with already-defined range 10 to 20.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumReservedRangeOverlapByOne) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:0 }"
+      "  reserved_range { start: 10 end: 20 }"
+      "  reserved_range { start: 5 end: 10 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Reserved range 5 to 10"
+      " overlaps with already-defined range 10 to 20.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumNegativeReservedRangeOverlap) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:0 }"
+      "  reserved_range { start: -20 end: -10 }"
+      "  reserved_range { start: -15 end: -5 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Reserved range -15 to -5"
+      " overlaps with already-defined range -20 to -10.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumMixedReservedRangeOverlap) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:20 }"
+      "  reserved_range { start: -20 end: 10 }"
+      "  reserved_range { start: -15 end: 5 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Reserved range -15 to 5"
+      " overlaps with already-defined range -20 to 10.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumMixedReservedRangeOverlap2) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:20 }"
+      "  reserved_range { start: -20 end: 10 }"
+      "  reserved_range { start: 10 end: 10 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Reserved range 10 to 10"
+      " overlaps with already-defined range -20 to 10.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumReservedRangeStartGreaterThanEnd) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"BAR\" number:20 }"
+      "  reserved_range { start: 11 end: 10 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Reserved range end number must be greater"
+      " than start number.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumReservedNameError) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"FOO\" number:15 }"
+      "  value { name:\"BAR\" number:15 }"
+      "  reserved_name: \"FOO\""
+      "  reserved_name: \"BAR\""
+      "}",
+
+      "foo.proto: FOO: NAME: Enum value \"FOO\" is reserved.\n"
+      "foo.proto: BAR: NAME: Enum value \"BAR\" is reserved.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumReservedNameRedundant) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"FOO\" number:15 }"
+      "  reserved_name: \"foo\""
+      "  reserved_name: \"foo\""
+      "}",
+
+      "foo.proto: foo: NAME: Enum value \"foo\" is reserved multiple times.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumReservedFieldsDebugString) {
+  const FileDescriptor* file = BuildFile(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Foo\""
+      "  value { name:\"FOO\" number:3 }"
+      "  reserved_name: \"foo\""
+      "  reserved_name: \"bar\""
+      "  reserved_range { start: -6 end: -6 }"
+      "  reserved_range { start: -5 end: -4 }"
+      "  reserved_range { start: -1 end: 1 }"
+      "  reserved_range { start: 5 end: 5 }"
+      "  reserved_range { start: 10 end: 19 }"
+      "}");
+
+  ASSERT_EQ(
+      "syntax = \"proto2\";\n\n"
+      "enum Foo {\n"
+      "  FOO = 3;\n"
+      "  reserved -6, -5 to -4, -1 to 1, 5, 10 to 19;\n"
+      "  reserved \"foo\", \"bar\";\n"
+      "}\n\n",
+      file->DebugString());
+}
+
+TEST_F(ValidationErrorTest, InvalidDefaults) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+
+      // Invalid number.
+      "  field { name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32"
+      "          default_value: \"abc\" }"
+
+      // Empty default value.
+      "  field { name: \"bar\" number: 2 label: LABEL_OPTIONAL type: TYPE_INT32"
+      "          default_value: \"\" }"
+
+      // Invalid boolean.
+      "  field { name: \"baz\" number: 3 label: LABEL_OPTIONAL type: TYPE_BOOL"
+      "          default_value: \"abc\" }"
+
+      // Messages can't have defaults.
+      "  field { name: \"moo\" number: 4 label: LABEL_OPTIONAL type: "
+      "TYPE_MESSAGE"
+      "          default_value: \"abc\" type_name: \"Foo\" }"
+
+      // Same thing, but we don't know that this field has message type until
+      // we look up the type name.
+      "  field { name: \"mooo\" number: 5 label: LABEL_OPTIONAL"
+      "          default_value: \"abc\" type_name: \"Foo\" }"
+
+      // Repeateds can't have defaults.
+      "  field { name: \"corge\" number: 6 label: LABEL_REPEATED type: "
+      "TYPE_INT32"
+      "          default_value: \"1\" }"
+      "}",
+
+      "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value "
+      "\"abc\".\n"
+      "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value \"\".\n"
+      "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or "
+      "false.\n"
+      "foo.proto: Foo.moo: DEFAULT_VALUE: Messages can't have default values.\n"
+      "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default "
+      "values.\n"
+      // This ends up being reported later because the error is detected at
+      // cross-linking time.
+      "foo.proto: Foo.mooo: DEFAULT_VALUE: Messages can't have default "
+      "values.\n");
+}
+
+TEST_F(ValidationErrorTest, NegativeFieldNumber) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name: \"foo\" number: -1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "}"
+      "}",
+
+      "foo.proto: Foo.foo: NUMBER: Field numbers must be positive integers.\n"
+      "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1\n");
+}
+
+TEST_F(ValidationErrorTest, HugeFieldNumber) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name: \"foo\" number: 0x70000000 "
+      "          label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+
+      "foo.proto: Foo.foo: NUMBER: Field numbers cannot be greater than "
+      "536870911.\n"
+      "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedFieldNumber) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field {name:\"foo\" number: 18999 label:LABEL_OPTIONAL "
+      "type:TYPE_INT32 }"
+      "  field {name:\"bar\" number: 19000 label:LABEL_OPTIONAL "
+      "type:TYPE_INT32 }"
+      "  field {name:\"baz\" number: 19999 label:LABEL_OPTIONAL "
+      "type:TYPE_INT32 }"
+      "  field {name:\"moo\" number: 20000 label:LABEL_OPTIONAL "
+      "type:TYPE_INT32 }"
+      "}",
+
+      "foo.proto: Foo.bar: NUMBER: Field numbers 19000 through 19999 are "
+      "reserved for the protocol buffer library implementation.\n"
+      "foo.proto: Foo.baz: NUMBER: Field numbers 19000 through 19999 are "
+      "reserved for the protocol buffer library implementation.\n"
+      "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1, 2\n");
+}
+
+TEST_F(ValidationErrorTest, ExtensionMissingExtendee) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
+      "              type_name: \"Foo\" }"
+      "}",
+
+      "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee not set for "
+      "extension field.\n");
+}
+
+TEST_F(ValidationErrorTest, NonExtensionWithExtendee) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Bar\""
+      "  extension_range { start: 1 end: 2 }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
+      "          type_name: \"Foo\" extendee: \"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee set for "
+      "non-extension field.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldOneofIndexTooLarge) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 1 }"
+      "  field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  oneof_decl { name:\"bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: FieldDescriptorProto.oneof_index 1 is out of "
+      "range for type \"Foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, FieldOneofIndexNegative) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: -1 }"
+      "  field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  oneof_decl { name:\"bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: FieldDescriptorProto.oneof_index -1 is out "
+      "of "
+      "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: TYPE: 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: TYPE: 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: TYPE: 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: TYPE: 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\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name: \"bar\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+
+      "foo.proto: Foo.bar: NUMBER: Field number 1 has already been used in "
+      "\"Foo\" by field \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, BadMessageSetExtensionType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"MessageSet\""
+      "  options { message_set_wire_format: true }"
+      "  extension_range { start: 4 end: 5 }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension { name:\"foo\" number:4 label:LABEL_OPTIONAL type:TYPE_INT32"
+      "              extendee: \"MessageSet\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
+      "messages.\n");
+}
+
+TEST_F(ValidationErrorTest, BadMessageSetExtensionLabel) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"MessageSet\""
+      "  options { message_set_wire_format: true }"
+      "  extension_range { start: 4 end: 5 }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension { name:\"foo\" number:4 label:LABEL_REPEATED "
+      "type:TYPE_MESSAGE"
+      "              type_name: \"Foo\" extendee: \"MessageSet\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
+      "messages.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldInMessageSet) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  options { message_set_wire_format: true }"
+      "  field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+
+      "foo.proto: Foo.foo: NAME: MessageSets cannot have fields, only "
+      "extensions.\n");
+}
+
+TEST_F(ValidationErrorTest, NegativeExtensionRangeNumber) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension_range { start: -10 end: -1 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Extension numbers must be positive integers.\n");
+}
+
+TEST_F(ValidationErrorTest, HugeExtensionRangeNumber) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension_range { start: 1 end: 0x70000000 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Extension numbers cannot be greater than "
+      "536870911.\n");
+}
+
+TEST_F(ValidationErrorTest, ExtensionRangeEndBeforeStart) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension_range { start: 10 end: 10 }"
+      "  extension_range { start: 10 end: 5 }"
+      "}",
+
+      "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
+      "start number.\n"
+      "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
+      "start number.\n");
+}
+
+TEST_F(ValidationErrorTest, EmptyEnum) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type { name: \"Foo\" }"
+      // Also use the empty enum in a message to make sure there are no crashes
+      // during validation (possible if the code attempts to derive a default
+      // value for the field).
+      "message_type {"
+      "  name: \"Bar\""
+      "  field { name: \"foo\" number: 1 label:LABEL_OPTIONAL "
+      "type_name:\"Foo\" }"
+      "  field { name: \"bar\" number: 2 label:LABEL_OPTIONAL "
+      "type_name:\"Foo\" "
+      "          default_value: \"NO_SUCH_VALUE\" }"
+      "}",
+
+      "foo.proto: Foo: NAME: Enums must contain at least one value.\n"
+      "foo.proto: Bar.bar: DEFAULT_VALUE: Enum type \"Foo\" has no value named "
+      "\"NO_SUCH_VALUE\".\n");
+}
+
+TEST_F(ValidationErrorTest, UndefinedExtendee) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
+      "              extendee: \"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not defined.\n");
+}
+
+TEST_F(ValidationErrorTest, NonMessageExtendee) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } }"
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
+      "              extendee: \"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not a message type.\n");
+}
+
+TEST_F(ValidationErrorTest, NotAnExtensionNumber) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Bar\""
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
+      "              extendee: \"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: NUMBER: \"Bar\" does not declare 1 as an extension "
+      "number.\n");
+}
+
+TEST_F(ValidationErrorTest, RequiredExtension) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Bar\""
+      "  extension_range { start: 1000 end: 10000 }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension {"
+      "    name:\"foo\""
+      "    number:1000"
+      "    label:LABEL_REQUIRED"
+      "    type:TYPE_INT32"
+      "    extendee: \"Bar\""
+      "  }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: The extension Foo.foo cannot be required.\n");
+}
+
+TEST_F(ValidationErrorTest, UndefinedFieldType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n");
+}
+
+TEST_F(ValidationErrorTest, UndefinedFieldTypeWithDefault) {
+  // See b/12533582. Previously this failed because the default value was not
+  // accepted by the parser, which assumed an enum type, leading to an unclear
+  // error message. We want this input to yield a validation error instead,
+  // since the unknown type is the primary problem.
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"int\" "
+      "          default_value:\"1\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: \"int\" is not defined.\n");
+}
+
+TEST_F(ValidationErrorTest, UndefinedNestedFieldType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  nested_type { name:\"Baz\" }"
+      "  field { name:\"foo\" number:1"
+      "          label:LABEL_OPTIONAL"
+      "          type_name:\"Foo.Baz.Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: \"Foo.Baz.Bar\" is not defined.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Bar\" } ");
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}",
+      "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+      "which is not imported by \"foo.proto\".  To use it here, please add the "
+      "necessary import.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) {
+  // Test for hidden dependencies.
+  //
+  // // bar.proto
+  // message Bar{}
+  //
+  // // forward.proto
+  // import "bar.proto"
+  //
+  // // foo.proto
+  // import "forward.proto"
+  // message Foo {
+  //   optional Bar foo = 1;  // Error, needs to import bar.proto explicitly.
+  // }
+  //
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Bar\" }");
+
+  BuildFile(
+      "name: \"forward.proto\""
+      "dependency: \"bar.proto\"");
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"forward.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}",
+      "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+      "which is not imported by \"foo.proto\".  To use it here, please add the "
+      "necessary import.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) {
+  // Test for public dependencies.
+  //
+  // // bar.proto
+  // message Bar{}
+  //
+  // // forward.proto
+  // import public "bar.proto"
+  //
+  // // foo.proto
+  // import "forward.proto"
+  // message Foo {
+  //   optional Bar foo = 1;  // Correct. "bar.proto" is public imported into
+  //                          // forward.proto, so when "foo.proto" imports
+  //                          // "forward.proto", it imports "bar.proto" too.
+  // }
+  //
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Bar\" }");
+
+  BuildFile(
+      "name: \"forward.proto\""
+      "dependency: \"bar.proto\" "
+      "public_dependency: 0");
+
+  BuildFile(
+      "name: \"foo.proto\" "
+      "dependency: \"forward.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) {
+  // Test for public dependencies.
+  //
+  // // bar.proto
+  // message Bar{}
+  //
+  // // forward.proto
+  // import public "bar.proto"
+  //
+  // // forward2.proto
+  // import public "forward.proto"
+  //
+  // // foo.proto
+  // import "forward2.proto"
+  // message Foo {
+  //   optional Bar foo = 1;  // Correct, public imports are transitive.
+  // }
+  //
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Bar\" }");
+
+  BuildFile(
+      "name: \"forward.proto\""
+      "dependency: \"bar.proto\" "
+      "public_dependency: 0");
+
+  BuildFile(
+      "name: \"forward2.proto\""
+      "dependency: \"forward.proto\" "
+      "public_dependency: 0");
+
+  BuildFile(
+      "name: \"foo.proto\" "
+      "dependency: \"forward2.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest,
+       FieldTypeDefinedInPrivateDependencyOfPublicDependency) {
+  // Test for public dependencies.
+  //
+  // // bar.proto
+  // message Bar{}
+  //
+  // // forward.proto
+  // import "bar.proto"
+  //
+  // // forward2.proto
+  // import public "forward.proto"
+  //
+  // // foo.proto
+  // import "forward2.proto"
+  // message Foo {
+  //   optional Bar foo = 1;  // Error, the "bar.proto" is not public imported
+  //                          // into "forward.proto", so will not be imported
+  //                          // into either "forward2.proto" or "foo.proto".
+  // }
+  //
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Bar\" }");
+
+  BuildFile(
+      "name: \"forward.proto\""
+      "dependency: \"bar.proto\"");
+
+  BuildFile(
+      "name: \"forward2.proto\""
+      "dependency: \"forward.proto\" "
+      "public_dependency: 0");
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"forward2.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}",
+      "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
+      "which is not imported by \"foo.proto\".  To use it here, please add the "
+      "necessary import.\n");
+}
+
+
+TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
+  // The following should produce an error that Bar.Baz is resolved but
+  // not defined:
+  //   message Bar { message Baz {} }
+  //   message Foo {
+  //     message Bar {
+  //       // Placing "message Baz{}" here, or removing Foo.Bar altogether,
+  //       // would fix the error.
+  //     }
+  //     optional Bar.Baz baz = 1;
+  //   }
+  // An one point the lookup code incorrectly did not produce an error in this
+  // case, because when looking for Bar.Baz, it would try "Foo.Bar.Baz" first,
+  // fail, and ten try "Bar.Baz" and succeed, even though "Bar" should actually
+  // refer to the inner Bar, not the outer one.
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Bar\""
+      "  nested_type { name: \"Baz\" }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  nested_type { name: \"Bar\" }"
+      "  field { name:\"baz\" number:1 label:LABEL_OPTIONAL"
+      "          type_name:\"Bar.Baz\" }"
+      "}",
+
+      "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is resolved to \"Foo.Bar.Baz\","
+      " which is not defined. The innermost scope is searched first in name "
+      "resolution. Consider using a leading '.'(i.e., \".Bar.Baz\") to start "
+      "from the outermost scope.\n");
+}
+
+TEST_F(ValidationErrorTest, SearchMostLocalFirst2) {
+  // This test would find the most local "Bar" first, and does, but
+  // proceeds to find the outer one because the inner one's not an
+  // aggregate.
+  BuildFile(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Bar\""
+      "  nested_type { name: \"Baz\" }"
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name: \"Bar\" number:1 type:TYPE_BYTES } "
+      "  field { name:\"baz\" number:2 label:LABEL_OPTIONAL"
+      "          type_name:\"Bar.Baz\" }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) {
+  // Imagine we have the following:
+  //
+  // foo.proto:
+  //   package foo.bar;
+  // bar.proto:
+  //   package foo.bar;
+  //   import "foo.proto";
+  //   message Bar {}
+  // baz.proto:
+  //   package foo;
+  //   import "bar.proto"
+  //   message Baz { optional bar.Bar moo = 1; }
+  //
+  // When validating baz.proto, we will look up "bar.Bar".  As part of this
+  // lookup, we first lookup "bar" then try to find "Bar" within it.  "bar"
+  // should resolve to "foo.bar".  Note, though, that "foo.bar" was originally
+  // defined in foo.proto, which is not a direct dependency of baz.proto.  The
+  // implementation of FindSymbol() normally only returns symbols in direct
+  // dependencies, not indirect ones.  This test insures that this does not
+  // prevent it from finding "foo.bar".
+
+  BuildFile(
+      "name: \"foo.proto\" "
+      "package: \"foo.bar\" ");
+  BuildFile(
+      "name: \"bar.proto\" "
+      "package: \"foo.bar\" "
+      "dependency: \"foo.proto\" "
+      "message_type { name: \"Bar\" }");
+  BuildFile(
+      "name: \"baz.proto\" "
+      "package: \"foo\" "
+      "dependency: \"bar.proto\" "
+      "message_type { "
+      "  name: \"Baz\" "
+      "  field { name:\"moo\" number:1 label:LABEL_OPTIONAL "
+      "          type_name:\"bar.Bar\" }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeNotAType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
+      "          type_name:\".Foo.bar\" }"
+      "  field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n");
+}
+
+TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  nested_type {"
+      "    name: \"Bar\""
+      "    field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  }"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
+      "          type_name:\"Bar.Baz\" }"
+      "}",
+      "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n");
+}
+
+TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) {
+  BuildFile(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Bar\""
+      "}"
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Bar\" } "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM"
+      "          type_name:\"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: \"Bar\" is not an enum type.\n");
+}
+
+TEST_F(ValidationErrorTest, MessageFieldTypeIsEnum) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE"
+      "          type_name:\"Bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: \"Bar\" is not a message type.\n");
+}
+
+TEST_F(ValidationErrorTest, BadEnumDefaultValue) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
+      "          default_value:\"NO_SUCH_VALUE\" }"
+      "}",
+
+      "foo.proto: Foo.foo: DEFAULT_VALUE: Enum type \"Bar\" has no value named "
+      "\"NO_SUCH_VALUE\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumDefaultValueIsInteger) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
+      "          default_value:\"0\" }"
+      "}",
+
+      "foo.proto: Foo.foo: DEFAULT_VALUE: Default value for an enum field must "
+      "be an identifier.\n");
+}
+
+TEST_F(ValidationErrorTest, PrimitiveWithTypeName) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
+      "          type_name:\"Foo\" }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: Field with primitive type has type_name.\n");
+}
+
+TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE }"
+      "}",
+
+      "foo.proto: Foo.foo: TYPE: Field with message or enum type missing "
+      "type_name.\n");
+}
+
+TEST_F(ValidationErrorTest, OneofWithNoFields) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  oneof_decl { name:\"bar\" }"
+      "}",
+
+      "foo.proto: Foo.bar: NAME: Oneof must have at least one field.\n");
+}
+
+TEST_F(ValidationErrorTest, OneofLabelMismatch) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo\" number:1 label:LABEL_REPEATED type:TYPE_INT32 "
+      "          oneof_index:0 }"
+      "  oneof_decl { name:\"bar\" }"
+      "}",
+
+      "foo.proto: Foo.foo: NAME: Fields of oneofs must themselves have label "
+      "LABEL_OPTIONAL.\n");
+}
+
+TEST_F(ValidationErrorTest, InputTypeNotDefined) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" } "
+      "service {"
+      "  name: \"TestService\""
+      "  method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
+      "}",
+
+      "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"
+  );
+}
+
+TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" } "
+      "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
+      "service {"
+      "  name: \"TestService\""
+      "  method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
+      "}",
+
+      "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"
+  );
+}
+
+TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" } "
+      "service {"
+      "  name: \"TestService\""
+      "  method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
+      "}",
+
+      "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"
+  );
+}
+
+TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { name: \"Foo\" } "
+      "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
+      "service {"
+      "  name: \"TestService\""
+      "  method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
+      "}",
+
+      "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"
+  );
+}
+
+
+TEST_F(ValidationErrorTest, IllegalPackedField) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {\n"
+      "  name: \"Foo\""
+      "  field { name:\"packed_string\" number:1 label:LABEL_REPEATED "
+      "          type:TYPE_STRING "
+      "          options { uninterpreted_option {"
+      "            name { name_part: \"packed\" is_extension: false }"
+      "            identifier_value: \"true\" }}}\n"
+      "  field { name:\"packed_message\" number:3 label:LABEL_REPEATED "
+      "          type_name: \"Foo\""
+      "          options { uninterpreted_option {"
+      "            name { name_part: \"packed\" is_extension: false }"
+      "            identifier_value: \"true\" }}}\n"
+      "  field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL "
+      "          type:TYPE_INT32 "
+      "          options { uninterpreted_option {"
+      "            name { name_part: \"packed\" is_extension: false }"
+      "            identifier_value: \"true\" }}}\n"
+      "}",
+
+      "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be "
+      "specified for repeated primitive fields.\n"
+      "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be "
+      "specified for repeated primitive fields.\n"
+      "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be "
+      "specified for repeated primitive fields.\n");
+}
+
+TEST_F(ValidationErrorTest, OptionWrongType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"TestMessage\" "
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
+      "          options { uninterpreted_option { name { name_part: \"ctype\" "
+      "                                                  is_extension: false }"
+      "                                           positive_int_value: 1 }"
+      "          }"
+      "  }"
+      "}\n",
+
+      "foo.proto: TestMessage.foo: OPTION_VALUE: Value must be identifier for "
+      "enum-valued option \"google.protobuf.FieldOptions.ctype\".\n");
+}
+
+TEST_F(ValidationErrorTest, OptionExtendsAtomicType) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"TestMessage\" "
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
+      "          options { uninterpreted_option { name { name_part: \"ctype\" "
+      "                                                  is_extension: false }"
+      "                                           name { name_part: \"foo\" "
+      "                                                  is_extension: true }"
+      "                                           positive_int_value: 1 }"
+      "          }"
+      "  }"
+      "}\n",
+
+      "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" is an "
+      "atomic type, not a message.\n");
+}
+
+TEST_F(ValidationErrorTest, DupOption) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"TestMessage\" "
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32 "
+      "          options { uninterpreted_option { name { name_part: \"ctype\" "
+      "                                                  is_extension: false }"
+      "                                           identifier_value: \"CORD\" }"
+      "                    uninterpreted_option { name { name_part: \"ctype\" "
+      "                                                  is_extension: false }"
+      "                                           identifier_value: \"CORD\" }"
+      "          }"
+      "  }"
+      "}\n",
+
+      "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" was "
+      "already set.\n");
+}
+
+TEST_F(ValidationErrorTest, InvalidOptionName) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type { "
+      "  name: \"TestMessage\" "
+      "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL "
+      "          options { uninterpreted_option { "
+      "                      name { name_part: \"uninterpreted_option\" "
+      "                             is_extension: false }"
+      "                      positive_int_value: 1 "
+      "                    }"
+      "          }"
+      "  }"
+      "}\n",
+
+      "foo.proto: TestMessage.foo: OPTION_NAME: Option must not use "
+      "reserved name \"uninterpreted_option\".\n");
+}
+
+TEST_F(ValidationErrorTest, RepeatedMessageOption) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "message_type: { name: \"Bar\" field: { "
+      "  name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
+      "} "
+      "extension { name: \"bar\" number: 7672757 label: LABEL_REPEATED "
+      "            type: TYPE_MESSAGE type_name: \"Bar\" "
+      "            extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"bar\" "
+      "                                        is_extension: true } "
+      "                                 name { name_part: \"foo\" "
+      "                                        is_extension: false } "
+      "                                 positive_int_value: 1 } }",
+
+      "foo.proto: foo.proto: OPTION_NAME: Option field \"(bar)\" is a "
+      "repeated message. Repeated message options must be initialized "
+      "using an aggregate value.\n");
+}
+
+TEST_F(ValidationErrorTest, ResolveUndefinedOption) {
+  // The following should produce an error that baz.bar is resolved but not
+  // defined.
+  // foo.proto:
+  //   package baz
+  //   import google/protobuf/descriptor.proto
+  //   message Bar { optional int32 foo = 1; }
+  //   extend FileOptions { optional Bar bar = 7672757; }
+  //
+  // moo.proto:
+  //   package moo.baz
+  //   option (baz.bar).foo = 1;
+  //
+  // Although "baz.bar" is already defined, the lookup code will try
+  // "moo.baz.bar", since it's the match from the innermost scope, which will
+  // cause a symbol not defined error.
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFile(
+      "name: \"foo.proto\" "
+      "package: \"baz\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "message_type: { name: \"Bar\" field: { "
+      "  name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
+      "} "
+      "extension { name: \"bar\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_MESSAGE type_name: \"Bar\" "
+      "            extendee: \"google.protobuf.FileOptions\" }");
+
+  BuildFileWithErrors(
+      "name: \"moo.proto\" "
+      "package: \"moo.baz\" "
+      "options { uninterpreted_option { name { name_part: \"baz.bar\" "
+      "                                        is_extension: true } "
+      "                                 name { name_part: \"foo\" "
+      "                                        is_extension: false } "
+      "                                 positive_int_value: 1 } }",
+
+      "moo.proto: moo.proto: OPTION_NAME: Option \"(baz.bar)\" is resolved to "
+      "\"(moo.baz.bar)\","
+      " which is not defined. The innermost scope is searched first in name "
+      "resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\") to start "
+      "from the outermost scope.\n");
+}
+
+TEST_F(ValidationErrorTest, UnknownOption) {
+  BuildFileWithErrors(
+      "name: \"moo.proto\" "
+      "package: \"moo.baz\" "
+      "options { uninterpreted_option { name { name_part: \"baaz.bar\" "
+      "                                        is_extension: true } "
+      "                                 name { name_part: \"foo\" "
+      "                                        is_extension: false } "
+      "                                 positive_int_value: 1 } }",
+
+      "moo.proto: moo.proto: OPTION_NAME: Option \"(baaz.bar)\" unknown. "
+      "Ensure "
+      "that your proto definition file imports the proto which defines the "
+      "option.\n");
+}
+
+TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo1\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }"
+      "extension { name: \"foo2\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }",
+
+      "foo.proto: foo2: NUMBER: Extension number 7672757 has already been used "
+      "in \"google.protobuf.FieldOptions\" by extension \"foo1\".\n");
+}
+
+TEST_F(ValidationErrorTest, Int32OptionValueOutOfPositiveRange) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 positive_int_value: 0x80000000 } "
+      "}",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
+      "for int32 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, Int32OptionValueOutOfNegativeRange) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 negative_int_value: -0x80000001 } "
+      "}",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
+      "for int32 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, Int32OptionValueIsNotPositiveInt) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 string_value: \"5\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
+      "for int32 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, Int64OptionValueOutOfRange) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 positive_int_value: 0x8000000000000000 "
+      "} "
+      "}",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
+      "for int64 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, Int64OptionValueIsNotPositiveInt) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 identifier_value: \"5\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
+      "for int64 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, UInt32OptionValueOutOfRange) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 positive_int_value: 0x100000000 } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
+      "for uint32 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, UInt32OptionValueIsNotPositiveInt) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 double_value: -5.6 } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
+      "for uint32 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, UInt64OptionValueIsNotPositiveInt) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_UINT64 extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 negative_int_value: -5 } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
+      "for uint64 option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, FloatOptionValueIsNotNumber) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 string_value: \"bar\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
+      "for float option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, DoubleOptionValueIsNotNumber) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_DOUBLE extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 string_value: \"bar\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
+      "for double option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, BoolOptionValueIsNotTrueOrFalse) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_BOOL extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 identifier_value: \"bar\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be \"true\" or \"false\" "
+      "for boolean option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumOptionValueIsNotIdentifier) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
+      "                              value { name: \"BAZ\" number: 2 } }"
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_ENUM type_name: \"FooEnum\" "
+      "            extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 string_value: \"MOOO\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be identifier for "
+      "enum-valued option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumOptionValueIsNotEnumValueName) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
+      "                              value { name: \"BAZ\" number: 2 } }"
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_ENUM type_name: \"FooEnum\" "
+      "            extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 identifier_value: \"MOOO\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum\" has no value "
+      "named \"MOOO\" for option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumOptionValueIsSiblingEnumValueName) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "enum_type { name: \"FooEnum1\" value { name: \"BAR\" number: 1 } "
+      "                               value { name: \"BAZ\" number: 2 } }"
+      "enum_type { name: \"FooEnum2\" value { name: \"MOO\" number: 1 } "
+      "                               value { name: \"MOOO\" number: 2 } }"
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_ENUM type_name: \"FooEnum1\" "
+      "            extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 identifier_value: \"MOOO\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum1\" has no value "
+      "named \"MOOO\" for option \"foo\". This appears to be a value from a "
+      "sibling type.\n");
+}
+
+TEST_F(ValidationErrorTest, StringOptionValueIsNotString) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_STRING extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 identifier_value: \"MOOO\" } }",
+
+      "foo.proto: foo.proto: OPTION_VALUE: Value must be quoted string "
+      "for "
+      "string option \"foo\".\n");
+}
+
+TEST_F(ValidationErrorTest, JsonNameOptionOnExtensions) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "package: \"foo\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  extension_range { start: 10 end: 20 }"
+      "}"
+      "extension {"
+      "  name: \"value\""
+      "  number: 10"
+      "  label: LABEL_OPTIONAL"
+      "  type: TYPE_INT32"
+      "  extendee: \"foo.Foo\""
+      "  json_name: \"myName\""
+      "}",
+      "foo.proto: foo.value: OPTION_NAME: option json_name is not allowed on "
+      "extension fields.\n");
+}
+
+TEST_F(ValidationErrorTest, DuplicateExtensionFieldNumber) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFile(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"option1\" number: 1000 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }");
+
+  BuildFileWithWarnings(
+      "name: \"bar.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "extension { name: \"option2\" number: 1000 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }",
+      "bar.proto: option2: NUMBER: Extension number 1000 has already been used "
+      "in \"google.protobuf.FileOptions\" by extension \"option1\" defined in "
+      "foo.proto.\n");
+}
+
+// Helper function for tests that check for aggregate value parsing
+// errors.  The "value" argument is embedded inside the
+// "uninterpreted_option" portion of the result.
+static std::string EmbedAggregateValue(const char* value) {
+  return strings::Substitute(
+      "name: \"foo.proto\" "
+      "dependency: \"google/protobuf/descriptor.proto\" "
+      "message_type { name: \"Foo\" } "
+      "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
+      "            type: TYPE_MESSAGE type_name: \"Foo\" "
+      "            extendee: \"google.protobuf.FileOptions\" }"
+      "options { uninterpreted_option { name { name_part: \"foo\" "
+      "                                        is_extension: true } "
+      "                                 $0 } }",
+      value);
+}
+
+TEST_F(ValidationErrorTest, AggregateValueNotFound) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      EmbedAggregateValue("string_value: \"\""),
+      "foo.proto: foo.proto: OPTION_VALUE: Option \"foo\" is a message. "
+      "To set the entire message, use syntax like "
+      "\"foo = { <proto text format> }\". To set fields within it, use "
+      "syntax like \"foo.foo = value\".\n");
+}
+
+TEST_F(ValidationErrorTest, AggregateValueParseError) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      EmbedAggregateValue("aggregate_value: \"1+2\""),
+      "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
+      "value for \"foo\": Expected identifier, got: 1\n");
+}
+
+TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
+  BuildDescriptorMessagesInTestPool();
+
+  BuildFileWithErrors(
+      EmbedAggregateValue("aggregate_value: \"x:100\""),
+      "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
+      "value for \"foo\": Message type \"Foo\" has no field named \"x\".\n");
+}
+
+TEST_F(ValidationErrorTest, NotLiteImportsLite) {
+  BuildFile(
+      "name: \"bar.proto\" "
+      "options { optimize_for: LITE_RUNTIME } ");
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"bar.proto\" ",
+
+      "foo.proto: bar.proto: IMPORT: Files that do not use optimize_for = "
+      "LITE_RUNTIME cannot import files which do use this option.  This file "
+      "is not lite, but it imports \"bar.proto\" which is.\n");
+}
+
+TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type: {"
+      "  name: \"Bar\""
+      "  extension_range { start: 1 end: 1000 }"
+      "}");
+
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "dependency: \"bar.proto\" "
+      "options { optimize_for: LITE_RUNTIME } "
+      "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
+      "            type: TYPE_INT32 extendee: \"Bar\" }",
+
+      "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
+      "declared in non-lite files.  Note that you cannot extend a non-lite "
+      "type to contain a lite type, but the reverse is allowed.\n");
+}
+
+TEST_F(ValidationErrorTest, NoLiteServices) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "options {"
+      "  optimize_for: LITE_RUNTIME"
+      "  cc_generic_services: true"
+      "  java_generic_services: true"
+      "} "
+      "service { name: \"Foo\" }",
+
+      "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
+      "define services unless you set both options cc_generic_services and "
+      "java_generic_services to false.\n");
+
+  BuildFile(
+      "name: \"bar.proto\" "
+      "options {"
+      "  optimize_for: LITE_RUNTIME"
+      "  cc_generic_services: false"
+      "  java_generic_services: false"
+      "} "
+      "service { name: \"Bar\" }");
+}
+
+TEST_F(ValidationErrorTest, RollbackAfterError) {
+  // Build a file which contains every kind of construct but references an
+  // undefined type.  All these constructs will be added to the symbol table
+  // before the undefined type error is noticed.  The DescriptorPool will then
+  // have to roll everything back.
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
+      "} "
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name:\"BAR\" number:1 }"
+      "} "
+      "service {"
+      "  name: \"TestService\""
+      "  method {"
+      "    name: \"Baz\""
+      "    input_type: \"NoSuchType\""  // error
+      "    output_type: \"TestMessage\""
+      "  }"
+      "}",
+
+      "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n"
+  );
+
+  // Make sure that if we build the same file again with the error fixed,
+  // it works.  If the above rollback was incomplete, then some symbols will
+  // be left defined, and this second attempt will fail since it tries to
+  // re-define the same symbols.
+  BuildFile(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"TestMessage\""
+      "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
+      "} "
+      "enum_type {"
+      "  name: \"TestEnum\""
+      "  value { name:\"BAR\" number:1 }"
+      "} "
+      "service {"
+      "  name: \"TestService\""
+      "  method { name:\"Baz\""
+      "           input_type:\"TestMessage\""
+      "           output_type:\"TestMessage\" }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
+  // Test that errors are reported to GOOGLE_LOG(ERROR) if no error collector is
+  // provided.
+
+  FileDescriptorProto file_proto;
+  ASSERT_TRUE(
+      TextFormat::ParseFromString("name: \"foo.proto\" "
+                                  "message_type { name: \"Foo\" } "
+                                  "message_type { name: \"Foo\" } ",
+                                  &file_proto));
+
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog log;
+    EXPECT_TRUE(pool_.BuildFile(file_proto) == nullptr);
+    errors = log.GetMessages(ERROR);
+  }
+
+  ASSERT_EQ(2, errors.size());
+
+  EXPECT_EQ("Invalid proto descriptor for file \"foo.proto\":", errors[0]);
+  EXPECT_EQ("  Foo: \"Foo\" is already defined.", errors[1]);
+}
+
+TEST_F(ValidationErrorTest, DisallowEnumAlias) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Bar\""
+      "  value { name:\"ENUM_A\" number:0 }"
+      "  value { name:\"ENUM_B\" number:0 }"
+      "}",
+      "foo.proto: Bar: NUMBER: "
+      "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
+      "If this is intended, set 'option allow_alias = true;' to the enum "
+      "definition.\n");
+}
+
+TEST_F(ValidationErrorTest, AllowEnumAlias) {
+  BuildFile(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Bar\""
+      "  value { name:\"ENUM_A\" number:0 }"
+      "  value { name:\"ENUM_B\" number:0 }"
+      "  options { allow_alias: true }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, UnusedImportWarning) {
+  pool_.AddUnusedImportTrackFile("bar.proto");
+  BuildFile(
+      "name: \"bar.proto\" "
+      "message_type { name: \"Bar\" }");
+
+  pool_.AddUnusedImportTrackFile("base.proto");
+  BuildFile(
+      "name: \"base.proto\" "
+      "message_type { name: \"Base\" }");
+
+  pool_.AddUnusedImportTrackFile("baz.proto");
+  BuildFile(
+      "name: \"baz.proto\" "
+      "message_type { name: \"Baz\" }");
+
+  pool_.AddUnusedImportTrackFile("public.proto");
+  BuildFile(
+      "name: \"public.proto\" "
+      "dependency: \"bar.proto\""
+      "public_dependency: 0");
+
+  // // forward.proto
+  // import "base.proto"       // No warning: Base message is used.
+  // import "bar.proto"        // Will log a warning.
+  // import public "baz.proto" // No warning: Do not track import public.
+  // import "public.proto"     // No warning: public.proto has import public.
+  // message Forward {
+  //   optional Base base = 1;
+  // }
+  //
+  pool_.AddUnusedImportTrackFile("forward.proto");
+  BuildFileWithWarnings(
+      "name: \"forward.proto\""
+      "dependency: \"base.proto\""
+      "dependency: \"bar.proto\""
+      "dependency: \"baz.proto\""
+      "dependency: \"public.proto\""
+      "public_dependency: 2 "
+      "message_type {"
+      "  name: \"Forward\""
+      "  field { name:\"base\" number:1 label:LABEL_OPTIONAL "
+      "type_name:\"Base\" }"
+      "}",
+      "forward.proto: bar.proto: IMPORT: Import bar.proto is unused.\n");
+}
+
+namespace {
+void FillValidMapEntry(FileDescriptorProto* file_proto) {
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: 'foo.proto' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { "
+      "    name: 'foo_map' number: 1 label:LABEL_REPEATED "
+      "    type_name: 'FooMapEntry' "
+      "  } "
+      "  nested_type { "
+      "    name: 'FooMapEntry' "
+      "    options {  map_entry: true } "
+      "    field { "
+      "      name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
+      "    } "
+      "    field { "
+      "      name: 'value' number: 2 type:TYPE_INT32 label:LABEL_OPTIONAL "
+      "    } "
+      "  } "
+      "} "
+      "message_type { "
+      "  name: 'Bar' "
+      "  extension_range { start: 1 end: 10 }"
+      "} ",
+      file_proto));
+}
+static const char* kMapEntryErrorMessage =
+    "foo.proto: Foo.foo_map: TYPE: map_entry should not be set explicitly. "
+    "Use map<KeyType, ValueType> instead.\n";
+static const char* kMapEntryKeyTypeErrorMessage =
+    "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot be float/double, "
+    "bytes or message types.\n";
+
+}  // namespace
+
+TEST_F(ValidationErrorTest, MapEntryBase) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  BuildFile(file_proto.DebugString());
+}
+
+TEST_F(ValidationErrorTest, MapEntryExtensionRange) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "extension_range { "
+      "  start: 10 end: 20 "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryExtension) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "extension { "
+      "  name: 'foo_ext' extendee: '.Bar' number: 5"
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryNestedType) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "nested_type { "
+      "  name: 'Bar' "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryEnumTypes) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "enum_type { "
+      "  name: 'BarEnum' "
+      "  value { name: 'BAR_BAR' number:0 } "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryExtraField) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "field { "
+      "  name: 'other_field' "
+      "  label: LABEL_OPTIONAL "
+      "  type: TYPE_INT32 "
+      "  number: 3 "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryMessageName) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  file_proto.mutable_message_type(0)->mutable_nested_type(0)->set_name(
+      "OtherMapEntry");
+  file_proto.mutable_message_type(0)->mutable_field(0)->set_type_name(
+      "OtherMapEntry");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryNoneRepeatedMapEntry) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  file_proto.mutable_message_type(0)->mutable_field(0)->set_label(
+      FieldDescriptorProto::LABEL_OPTIONAL);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryDifferentContainingType) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  // Move the nested MapEntry message into the top level, which should not pass
+  // the validation.
+  file_proto.mutable_message_type()->AddAllocated(
+      file_proto.mutable_message_type(0)->mutable_nested_type()->ReleaseLast());
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyName) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->set_name("Key");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyLabel) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->set_label(FieldDescriptorProto::LABEL_REQUIRED);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyNumber) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->set_number(3);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryValueName) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* value =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          1);
+  value->set_name("Value");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryValueLabel) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* value =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          1);
+  value->set_label(FieldDescriptorProto::LABEL_REQUIRED);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryValueNumber) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* value =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          1);
+  value->set_number(3);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeFloat) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->set_type(FieldDescriptorProto::TYPE_FLOAT);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeDouble) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->set_type(FieldDescriptorProto::TYPE_DOUBLE);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeBytes) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->set_type(FieldDescriptorProto::TYPE_BYTES);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeEnum) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->clear_type();
+  key->set_type_name("BarEnum");
+  EnumDescriptorProto* enum_proto = file_proto.add_enum_type();
+  enum_proto->set_name("BarEnum");
+  EnumValueDescriptorProto* enum_value_proto = enum_proto->add_value();
+  enum_value_proto->set_name("BAR_VALUE0");
+  enum_value_proto->set_number(0);
+  BuildFileWithErrors(file_proto.DebugString(),
+                      "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
+                      "be enum types.\n");
+  // Enum keys are not allowed in proto3 as well.
+  // Get rid of extensions for proto3 to make it proto3 compatible.
+  file_proto.mutable_message_type()->RemoveLast();
+  file_proto.set_syntax("proto3");
+  BuildFileWithErrors(file_proto.DebugString(),
+                      "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
+                      "be enum types.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeMessage) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key =
+      file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
+          0);
+  key->clear_type();
+  key->set_type_name(".Bar");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithField) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "field { "
+      "  name: 'FooMapEntry' "
+      "  type: TYPE_INT32 "
+      "  label: LABEL_OPTIONAL "
+      "  number: 100 "
+      "}",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing field.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithMessage) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "nested_type { "
+      "  name: 'FooMapEntry' "
+      "}",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing nested message type.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithEnum) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "enum_type { "
+      "  name: 'FooMapEntry' "
+      "  value { name: 'ENTRY_FOO' number: 0 }"
+      "}",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing enum type.\n");
+}
+
+TEST_F(ValidationErrorTest, EnumValuesConflictWithDifferentCasing) {
+  BuildFileWithErrors(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  value { name: 'BAR' number: 0 }"
+      "  value { name: 'bar' number: 1 }"
+      "}",
+      "foo.proto: bar: NAME: Enum name bar has the same name as BAR "
+      "if you ignore case and strip out the enum name prefix (if any). "
+      "This is error-prone and can lead to undefined behavior. "
+      "Please avoid doing this. If you are using allow_alias, please assign "
+      "the same numeric value to both enums.\n");
+
+  // Not an error because both enums are mapped to the same value.
+  BuildFile(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  options { allow_alias: true }"
+      "  value { name: 'UNKNOWN' number: 0 }"
+      "  value { name: 'BAR' number: 1 }"
+      "  value { name: 'bar' number: 1 }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, EnumValuesConflictWhenPrefixesStripped) {
+  BuildFileWithErrors(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_ENUM_BAZ' number: 0 }"
+      "  value { name: 'BAZ' number: 1 }"
+      "}",
+      "foo.proto: BAZ: NAME: Enum name BAZ has the same name as FOO_ENUM_BAZ "
+      "if you ignore case and strip out the enum name prefix (if any). "
+      "This is error-prone and can lead to undefined behavior. "
+      "Please avoid doing this. If you are using allow_alias, please assign "
+      "the same numeric value to both enums.\n");
+
+  BuildFileWithErrors(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  value { name: 'FOOENUM_BAZ' number: 0 }"
+      "  value { name: 'BAZ' number: 1 }"
+      "}",
+      "foo.proto: BAZ: NAME: Enum name BAZ has the same name as FOOENUM_BAZ "
+      "if you ignore case and strip out the enum name prefix (if any). "
+      "This is error-prone and can lead to undefined behavior. "
+      "Please avoid doing this. If you are using allow_alias, please assign "
+      "the same numeric value to both enums.\n");
+
+  BuildFileWithErrors(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_ENUM_BAR_BAZ' number: 0 }"
+      "  value { name: 'BAR__BAZ' number: 1 }"
+      "}",
+      "foo.proto: BAR__BAZ: NAME: Enum name BAR__BAZ has the same name as "
+      "FOO_ENUM_BAR_BAZ if you ignore case and strip out the enum name prefix "
+      "(if any). This is error-prone and can lead to undefined behavior. "
+      "Please avoid doing this. If you are using allow_alias, please assign "
+      "the same numeric value to both enums.\n");
+
+  BuildFileWithErrors(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_ENUM__BAR_BAZ' number: 0 }"
+      "  value { name: 'BAR_BAZ' number: 1 }"
+      "}",
+      "foo.proto: BAR_BAZ: NAME: Enum name BAR_BAZ has the same name as "
+      "FOO_ENUM__BAR_BAZ if you ignore case and strip out the enum name prefix "
+      "(if any). This is error-prone and can lead to undefined behavior. "
+      "Please avoid doing this. If you are using allow_alias, please assign "
+      "the same numeric value to both enums.\n");
+
+  // This isn't an error because the underscore will cause the PascalCase to
+  // differ by case (BarBaz vs. Barbaz).
+  BuildFile(
+      "syntax: 'proto3'"
+      "name: 'foo.proto' "
+      "enum_type {"
+      "  name: 'FooEnum' "
+      "  value { name: 'BAR_BAZ' number: 0 }"
+      "  value { name: 'BARBAZ' number: 1 }"
+      "}");
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "oneof_decl { "
+      "  name: 'FooMapEntry' "
+      "}"
+      "field { "
+      "  name: 'int_field' "
+      "  type: TYPE_INT32 "
+      "  label: LABEL_OPTIONAL "
+      "  oneof_index: 0 "
+      "  number: 100 "
+      "} ",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing oneof type.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "enum_type {"
+      "  name: \"Bar\""
+      "  value { name:\"ENUM_A\" number:1 }"
+      "  value { name:\"ENUM_B\" number:2 }"
+      "}"
+      "message_type {"
+      "  name: 'Foo' "
+      "  field { "
+      "    name: 'foo_map' number: 1 label:LABEL_REPEATED "
+      "    type_name: 'FooMapEntry' "
+      "  } "
+      "  nested_type { "
+      "    name: 'FooMapEntry' "
+      "    options {  map_entry: true } "
+      "    field { "
+      "      name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
+      "    } "
+      "    field { "
+      "      name: 'value' number: 2 type_name:\"Bar\" label:LABEL_OPTIONAL "
+      "    } "
+      "  } "
+      "}",
+      "foo.proto: Foo.foo_map: "
+      "TYPE: Enum value in map must define 0 as the first value.\n");
+}
+
+TEST_F(ValidationErrorTest, Proto3RequiredFields) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
+      "}",
+      "foo.proto: Foo.foo: TYPE: Required fields are not allowed in "
+      "proto3.\n");
+
+  // applied to nested types as well.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name : 'Bar' "
+      "    field { name:'bar' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
+      "  } "
+      "}",
+      "foo.proto: Foo.Bar.bar: TYPE: Required fields are not allowed in "
+      "proto3.\n");
+
+  // optional and repeated fields are OK.
+  BuildFile(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
+      "  field { name:'bar' number:2 label:LABEL_REPEATED type:TYPE_INT32 } "
+      "}");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3DefaultValue) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          default_value: '1' }"
+      "}",
+      "foo.proto: Foo.foo: DEFAULT_VALUE: Explicit default values are not "
+      "allowed in proto3.\n");
+
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name : 'Bar' "
+      "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "            default_value: '1' }"
+      "  } "
+      "}",
+      "foo.proto: Foo.Bar.bar: DEFAULT_VALUE: Explicit default values are not "
+      "allowed in proto3.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3ExtensionRange) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
+      "  extension_range { start:10 end:100 } "
+      "}",
+      "foo.proto: Foo: NUMBER: Extension ranges are not allowed in "
+      "proto3.\n");
+
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name : 'Bar' "
+      "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
+      "    extension_range { start:10 end:100 } "
+      "  } "
+      "}",
+      "foo.proto: Foo.Bar: NUMBER: Extension ranges are not allowed in "
+      "proto3.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3MessageSetWireFormat) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  options { message_set_wire_format: true } "
+      "}",
+      "foo.proto: Foo: NAME: MessageSet is not supported "
+      "in proto3.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3Enum) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "enum_type { "
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_FOO' number:1 } "
+      "}",
+      "foo.proto: FooEnum: NUMBER: The first enum value must be "
+      "zero in proto3.\n");
+
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  enum_type { "
+      "    name: 'FooEnum' "
+      "    value { name: 'FOO_FOO' number:1 } "
+      "  } "
+      "}",
+      "foo.proto: Foo.FooEnum: NUMBER: The first enum value must be "
+      "zero in proto3.\n");
+
+  // valid case.
+  BuildFile(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "enum_type { "
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_FOO' number:0 } "
+      "}");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3Group) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name: 'FooGroup' "
+      "  } "
+      "  field { name:'foo_group' number: 1 label:LABEL_OPTIONAL "
+      "          type: TYPE_GROUP type_name:'FooGroup' } "
+      "}",
+      "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 "
+      "syntax.\n");
+}
+
+
+TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) {
+  // Define an enum in a proto2 file.
+  BuildFile(
+      "name: 'foo.proto' "
+      "package: 'foo' "
+      "syntax: 'proto2' "
+      "enum_type { "
+      "  name: 'FooEnum' "
+      "  value { name: 'DEFAULT_OPTION' number:0 } "
+      "}");
+
+  // Now try to refer to it. (All tests in the fixture use the same pool, so we
+  // can refer to the enum above in this definition.)
+  BuildFileWithErrors(
+      "name: 'bar.proto' "
+      "dependency: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_ENUM "
+      "            type_name: 'foo.FooEnum' }"
+      "}",
+      "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not a proto3 "
+      "enum, but is used in \"Foo\" which is a proto3 message type.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3Extension) {
+  // Valid for options.
+  DescriptorPool pool;
+  FileDescriptorProto file_proto;
+  // Add "google/protobuf/descriptor.proto".
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+  // Add "foo.proto":
+  //   import "google/protobuf/descriptor.proto";
+  //   extend google.protobuf.FileOptions {
+  //     optional string test_file_opt = 1001;
+  //   }
+  //   extend google.protobuf.MessageOptions {
+  //     optional string test_msg_opt = 1002;
+  //   }
+  //   extend google.protobuf.FieldOptions {
+  //     optional string test_field_opt = 1003;
+  //   }
+  //   extend google.protobuf.EnumOptions {
+  //     repeated int32 test_enum_opt = 1004;
+  //   }
+  //   extend google.protobuf.EnumValueOptions {
+  //     optional int32 test_enumval_opt = 1005;
+  //   }
+  //   extend google.protobuf.ServiceOptions {
+  //     repeated int32 test_svc_opt = 1006;
+  //   }
+  //   extend google.protobuf.MethodOptions {
+  //     optional string test_method_opt = 1007;
+  //   }
+  //   extend google.protobuf.OneofOptions {
+  //     optional string test_oneof_opt = 1008;
+  //   }
+  //   extend google.protobuf.ExtensionRangeOptions {
+  //     optional string test_ext_opt = 1009;
+  //   }
+  file_proto.Clear();
+  file_proto.set_name("foo.proto");
+  file_proto.set_syntax("proto3");
+  file_proto.add_dependency("google/protobuf/descriptor.proto");
+  AddExtension(&file_proto, "google.protobuf.FileOptions", "test_file_opt", 1001,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_STRING);
+  AddExtension(&file_proto, "google.protobuf.MessageOptions", "test_msg_opt", 1001,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_STRING);
+  AddExtension(&file_proto, "google.protobuf.FieldOptions", "test_field_opt", 1003,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_STRING);
+  AddExtension(&file_proto, "google.protobuf.EnumOptions", "test_enum_opt", 1004,
+               FieldDescriptorProto::LABEL_REPEATED,
+               FieldDescriptorProto::TYPE_INT32);
+  AddExtension(&file_proto, "google.protobuf.EnumValueOptions", "test_enumval_opt", 1005,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_INT32);
+  AddExtension(&file_proto, "google.protobuf.ServiceOptions", "test_svc_opt", 1006,
+               FieldDescriptorProto::LABEL_REPEATED,
+               FieldDescriptorProto::TYPE_INT32);
+  AddExtension(&file_proto, "google.protobuf.MethodOptions", "test_method_opt", 1007,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_STRING);
+  AddExtension(&file_proto, "google.protobuf.OneofOptions", "test_oneof_opt", 1008,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_STRING);
+  AddExtension(&file_proto, "google.protobuf.ExtensionRangeOptions", "test_ext_opt",
+               1009, FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_STRING);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
+
+  // Copy and change the package of the descriptor.proto
+  BuildFile(
+      "name: 'google.protobuf.proto' "
+      "syntax: 'proto2' "
+      "message_type { "
+      "  name: 'Container' extension_range { start: 1 end: 1000 } "
+      "}");
+  BuildFileWithErrors(
+      "name: 'bar.proto' "
+      "syntax: 'proto3' "
+      "dependency: 'google.protobuf.proto' "
+      "extension { "
+      "  name: 'bar' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 "
+      "  extendee: 'Container' "
+      "}",
+      "bar.proto: bar: EXTENDEE: Extensions in proto3 are only allowed for "
+      "defining options.\n");
+}
+
+// Test that field names that may conflict in JSON is not allowed by protoc.
+TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
+  // The comparison is case-insensitive.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type {"
+      "  name: 'Foo'"
+      "  field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+      "foo.proto: Foo: NAME: The JSON camel-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: NAME: The JSON camel-case name of field \"_a__b_\" "
+      "conflicts with field \"ab\". This is not allowed in proto3.\n");
+}
+
+
+TEST_F(ValidationErrorTest, UnusedImportWithOtherError) {
+  BuildFile(
+      "name: 'bar.proto' "
+      "message_type {"
+      "  name: 'Bar'"
+      "}");
+
+  pool_.AddUnusedImportTrackFile("foo.proto", true);
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "dependency: 'bar.proto' "
+      "message_type {"
+      "  name: 'Foo'"
+      "  extension { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
+      "              extendee: 'Baz' }"
+      "}",
+
+      // Should not also contain unused import error.
+      "foo.proto: Foo.foo: EXTENDEE: \"Baz\" is not defined.\n");
+}
+
+
+TEST_F(ValidationErrorTest, PackageTooLong) {
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "syntax: \"proto3\" "
+      "package: "
+      "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaa\"",
+      "foo.proto: "
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+      "aaaaaaaa: NAME: Package name is too long\n");
+}
+
+// ===================================================================
+// DescriptorDatabase
+
+static void AddToDatabase(SimpleDescriptorDatabase* database,
+                          const char* file_text) {
+  FileDescriptorProto file_proto;
+  EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+  database->Add(file_proto);
+}
+
+class DatabaseBackedPoolTest : public testing::Test {
+ protected:
+  DatabaseBackedPoolTest() {}
+
+  SimpleDescriptorDatabase database_;
+
+  void SetUp() override {
+    AddToDatabase(
+        &database_,
+        "name: 'foo.proto' "
+        "message_type { name:'Foo' extension_range { start: 1 end: 100 } } "
+        "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } "
+        "service { name:'TestService' } ");
+    AddToDatabase(&database_,
+                  "name: 'bar.proto' "
+                  "dependency: 'foo.proto' "
+                  "message_type { name:'Bar' } "
+                  "extension { name:'foo_ext' extendee: '.Foo' number:5 "
+                  "            label:LABEL_OPTIONAL type:TYPE_INT32 } ");
+    // Baz has an undeclared dependency on Foo.
+    AddToDatabase(
+        &database_,
+        "name: 'baz.proto' "
+        "message_type { "
+        "  name:'Baz' "
+        "  field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } "
+        "}");
+  }
+
+  // We can't inject a file containing errors into a DescriptorPool, so we
+  // need an actual mock DescriptorDatabase to test errors.
+  class ErrorDescriptorDatabase : public DescriptorDatabase {
+   public:
+    ErrorDescriptorDatabase() {}
+    ~ErrorDescriptorDatabase() override {}
+
+    // implements DescriptorDatabase ---------------------------------
+    bool FindFileByName(const std::string& filename,
+                        FileDescriptorProto* output) override {
+      // error.proto and error2.proto cyclically import each other.
+      if (filename == "error.proto") {
+        output->Clear();
+        output->set_name("error.proto");
+        output->add_dependency("error2.proto");
+        return true;
+      } else if (filename == "error2.proto") {
+        output->Clear();
+        output->set_name("error2.proto");
+        output->add_dependency("error.proto");
+        return true;
+      } else {
+        return false;
+      }
+    }
+    bool FindFileContainingSymbol(const std::string& symbol_name,
+                                  FileDescriptorProto* output) override {
+      return false;
+    }
+    bool FindFileContainingExtension(const std::string& containing_type,
+                                     int field_number,
+                                     FileDescriptorProto* output) override {
+      return false;
+    }
+  };
+
+  // A DescriptorDatabase that counts how many times each method has been
+  // called and forwards to some other DescriptorDatabase.
+  class CallCountingDatabase : public DescriptorDatabase {
+   public:
+    CallCountingDatabase(DescriptorDatabase* wrapped_db)
+        : wrapped_db_(wrapped_db) {
+      Clear();
+    }
+    ~CallCountingDatabase() override {}
+
+    DescriptorDatabase* wrapped_db_;
+
+    int call_count_;
+
+    void Clear() { call_count_ = 0; }
+
+    // implements DescriptorDatabase ---------------------------------
+    bool FindFileByName(const std::string& filename,
+                        FileDescriptorProto* output) override {
+      ++call_count_;
+      return wrapped_db_->FindFileByName(filename, output);
+    }
+    bool FindFileContainingSymbol(const std::string& symbol_name,
+                                  FileDescriptorProto* output) override {
+      ++call_count_;
+      return wrapped_db_->FindFileContainingSymbol(symbol_name, output);
+    }
+    bool FindFileContainingExtension(const std::string& containing_type,
+                                     int field_number,
+                                     FileDescriptorProto* output) override {
+      ++call_count_;
+      return wrapped_db_->FindFileContainingExtension(containing_type,
+                                                      field_number, output);
+    }
+  };
+
+  // A DescriptorDatabase which falsely always returns foo.proto when searching
+  // for any symbol or extension number.  This shouldn't cause the
+  // DescriptorPool to reload foo.proto if it is already loaded.
+  class FalsePositiveDatabase : public DescriptorDatabase {
+   public:
+    FalsePositiveDatabase(DescriptorDatabase* wrapped_db)
+        : wrapped_db_(wrapped_db) {}
+    ~FalsePositiveDatabase() override {}
+
+    DescriptorDatabase* wrapped_db_;
+
+    // implements DescriptorDatabase ---------------------------------
+    bool FindFileByName(const std::string& filename,
+                        FileDescriptorProto* output) override {
+      return wrapped_db_->FindFileByName(filename, output);
+    }
+    bool FindFileContainingSymbol(const std::string& symbol_name,
+                                  FileDescriptorProto* output) override {
+      return FindFileByName("foo.proto", output);
+    }
+    bool FindFileContainingExtension(const std::string& containing_type,
+                                     int field_number,
+                                     FileDescriptorProto* output) override {
+      return FindFileByName("foo.proto", output);
+    }
+  };
+};
+
+TEST_F(DatabaseBackedPoolTest, FindFileByName) {
+  DescriptorPool pool(&database_);
+
+  const FileDescriptor* foo = pool.FindFileByName("foo.proto");
+  ASSERT_TRUE(foo != nullptr);
+  EXPECT_EQ("foo.proto", foo->name());
+  ASSERT_EQ(1, foo->message_type_count());
+  EXPECT_EQ("Foo", foo->message_type(0)->name());
+
+  EXPECT_EQ(foo, pool.FindFileByName("foo.proto"));
+
+  EXPECT_TRUE(pool.FindFileByName("no_such_file.proto") == nullptr);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) {
+  DescriptorPool pool(&database_);
+
+  const FileDescriptor* foo = pool.FindFileByName("foo.proto");
+  ASSERT_TRUE(foo != nullptr);
+  EXPECT_EQ("foo.proto", foo->name());
+  ASSERT_EQ(1, foo->message_type_count());
+  EXPECT_EQ("Foo", foo->message_type(0)->name());
+
+  const FileDescriptor* bar = pool.FindFileByName("bar.proto");
+  ASSERT_TRUE(bar != nullptr);
+  EXPECT_EQ("bar.proto", bar->name());
+  ASSERT_EQ(1, bar->message_type_count());
+  EXPECT_EQ("Bar", bar->message_type(0)->name());
+
+  ASSERT_EQ(1, bar->dependency_count());
+  EXPECT_EQ(foo, bar->dependency(0));
+}
+
+TEST_F(DatabaseBackedPoolTest, FindDependentBeforeDependency) {
+  DescriptorPool pool(&database_);
+
+  const FileDescriptor* bar = pool.FindFileByName("bar.proto");
+  ASSERT_TRUE(bar != nullptr);
+  EXPECT_EQ("bar.proto", bar->name());
+  ASSERT_EQ(1, bar->message_type_count());
+  ASSERT_EQ("Bar", bar->message_type(0)->name());
+
+  const FileDescriptor* foo = pool.FindFileByName("foo.proto");
+  ASSERT_TRUE(foo != nullptr);
+  EXPECT_EQ("foo.proto", foo->name());
+  ASSERT_EQ(1, foo->message_type_count());
+  ASSERT_EQ("Foo", foo->message_type(0)->name());
+
+  ASSERT_EQ(1, bar->dependency_count());
+  EXPECT_EQ(foo, bar->dependency(0));
+}
+
+TEST_F(DatabaseBackedPoolTest, FindFileContainingSymbol) {
+  DescriptorPool pool(&database_);
+
+  const FileDescriptor* file = pool.FindFileContainingSymbol("Foo");
+  ASSERT_TRUE(file != nullptr);
+  EXPECT_EQ("foo.proto", file->name());
+  EXPECT_EQ(file, pool.FindFileByName("foo.proto"));
+
+  EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == nullptr);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) {
+  DescriptorPool pool(&database_);
+
+  const Descriptor* type = pool.FindMessageTypeByName("Foo");
+  ASSERT_TRUE(type != nullptr);
+  EXPECT_EQ("Foo", type->name());
+  EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto"));
+
+  EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == nullptr);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) {
+  DescriptorPool pool(&database_);
+
+  const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+  ASSERT_TRUE(foo != nullptr);
+
+  const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5);
+  ASSERT_TRUE(extension != nullptr);
+  EXPECT_EQ("foo_ext", extension->name());
+  EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto"));
+
+  EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == nullptr);
+}
+
+TEST_F(DatabaseBackedPoolTest, FindAllExtensions) {
+  DescriptorPool pool(&database_);
+
+  const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+
+  for (int i = 0; i < 2; ++i) {
+    // Repeat the lookup twice, to check that we get consistent
+    // results despite the fallback database lookup mutating the pool.
+    std::vector<const FieldDescriptor*> extensions;
+    pool.FindAllExtensions(foo, &extensions);
+    ASSERT_EQ(1, extensions.size());
+    EXPECT_EQ(5, extensions[0]->number());
+  }
+}
+
+TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) {
+  ErrorDescriptorDatabase error_database;
+  DescriptorPool pool(&error_database);
+
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog log;
+    EXPECT_TRUE(pool.FindFileByName("error.proto") == nullptr);
+    errors = log.GetMessages(ERROR);
+  }
+
+  EXPECT_FALSE(errors.empty());
+}
+
+TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
+  ErrorDescriptorDatabase error_database;
+  MockErrorCollector error_collector;
+  DescriptorPool pool(&error_database, &error_collector);
+
+  EXPECT_TRUE(pool.FindFileByName("error.proto") == nullptr);
+  EXPECT_EQ(
+      "error.proto: error2.proto: IMPORT: File recursively imports itself: "
+      "error.proto -> error2.proto -> error.proto\n"
+      "error2.proto: error.proto: IMPORT: Import \"error.proto\" was not "
+      "found or had errors.\n"
+      "error.proto: error2.proto: IMPORT: Import \"error2.proto\" was not "
+      "found or had errors.\n",
+      error_collector.text_);
+}
+
+TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) {
+  // Check that we find and report undeclared dependencies on types that exist
+  // in the descriptor database but that have not not been built yet.
+  MockErrorCollector error_collector;
+  DescriptorPool pool(&database_, &error_collector);
+  EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
+  EXPECT_EQ(
+      "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", "
+      "which is not imported by \"baz.proto\".  To use it here, please add "
+      "the necessary import.\n",
+      error_collector.text_);
+}
+
+TEST_F(DatabaseBackedPoolTest, RollbackAfterError) {
+  // Make sure that all traces of bad types are removed from the pool. This used
+  // to be b/4529436, due to the fact that a symbol resolution failure could
+  // potentially cause another file to be recursively built, which would trigger
+  // a checkpoint _past_ possibly invalid symbols.
+  // Baz is defined in the database, but the file is invalid because it is
+  // missing a necessary import.
+  DescriptorPool pool(&database_);
+  EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
+  // Make sure that searching again for the file or the type fails.
+  EXPECT_TRUE(pool.FindFileByName("baz.proto") == nullptr);
+  EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
+}
+
+TEST_F(DatabaseBackedPoolTest, UnittestProto) {
+  // Try to load all of unittest.proto from a DescriptorDatabase.  This should
+  // thoroughly test all paths through DescriptorBuilder to insure that there
+  // are no deadlocking problems when pool_->mutex_ is non-null.
+  const FileDescriptor* original_file =
+      protobuf_unittest::TestAllTypes::descriptor()->file();
+
+  DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
+  DescriptorPool pool(&database);
+  const FileDescriptor* file_from_database =
+      pool.FindFileByName(original_file->name());
+
+  ASSERT_TRUE(file_from_database != nullptr);
+
+  FileDescriptorProto original_file_proto;
+  original_file->CopyTo(&original_file_proto);
+
+  FileDescriptorProto file_from_database_proto;
+  file_from_database->CopyTo(&file_from_database_proto);
+
+  EXPECT_EQ(original_file_proto.DebugString(),
+            file_from_database_proto.DebugString());
+
+  // Also verify that CopyTo() did not omit any information.
+  EXPECT_EQ(original_file->DebugString(), file_from_database->DebugString());
+}
+
+TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
+  // Searching for a child of an existing descriptor should never fall back
+  // to the DescriptorDatabase even if it isn't found, because we know all
+  // children are already loaded.
+  CallCountingDatabase call_counter(&database_);
+  DescriptorPool pool(&call_counter);
+
+  const FileDescriptor* file = pool.FindFileByName("foo.proto");
+  ASSERT_TRUE(file != nullptr);
+  const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+  ASSERT_TRUE(foo != nullptr);
+  const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
+  ASSERT_TRUE(test_enum != nullptr);
+  const ServiceDescriptor* test_service = pool.FindServiceByName("TestService");
+  ASSERT_TRUE(test_service != nullptr);
+
+  EXPECT_NE(0, call_counter.call_count_);
+  call_counter.Clear();
+
+  EXPECT_TRUE(foo->FindFieldByName("no_such_field") == nullptr);
+  EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == nullptr);
+  EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == nullptr);
+  EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == nullptr);
+  EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == nullptr);
+
+  EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == nullptr);
+  EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == nullptr);
+  EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == nullptr);
+
+  EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == nullptr);
+  EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == nullptr);
+  EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == nullptr);
+  EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == nullptr);
+  EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == nullptr);
+  EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == nullptr);
+  EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == nullptr);
+  EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == nullptr);
+
+  EXPECT_EQ(0, call_counter.call_count_);
+}
+
+TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) {
+  // If FindFileContainingSymbol() or FindFileContainingExtension() return a
+  // file that is already in the DescriptorPool, it should not attempt to
+  // reload the file.
+  FalsePositiveDatabase false_positive_database(&database_);
+  MockErrorCollector error_collector;
+  DescriptorPool pool(&false_positive_database, &error_collector);
+
+  // First make sure foo.proto is loaded.
+  const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+  ASSERT_TRUE(foo != nullptr);
+
+  // Try inducing false positives.
+  EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == nullptr);
+  EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == nullptr);
+
+  // No errors should have been reported.  (If foo.proto was incorrectly
+  // loaded multiple times, errors would have been reported.)
+  EXPECT_EQ("", error_collector.text_);
+}
+
+// DescriptorDatabase that attempts to induce exponentially-bad performance
+// in DescriptorPool. For every positive N, the database contains a file
+// fileN.proto, which defines a message MessageN, which contains fields of
+// type MessageK for all K in [0,N). Message0 is not defined anywhere
+// (file0.proto exists, but is empty), so every other file and message type
+// will fail to build.
+//
+// If the DescriptorPool is not careful to memoize errors, an attempt to
+// build a descriptor for MessageN can require O(2^N) time.
+class ExponentialErrorDatabase : public DescriptorDatabase {
+ public:
+  ExponentialErrorDatabase() {}
+  ~ExponentialErrorDatabase() override {}
+
+  // implements DescriptorDatabase ---------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override {
+    int file_num = -1;
+    FullMatch(filename, "file", ".proto", &file_num);
+    if (file_num > -1) {
+      return PopulateFile(file_num, output);
+    } else {
+      return false;
+    }
+  }
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override {
+    int file_num = -1;
+    FullMatch(symbol_name, "Message", "", &file_num);
+    if (file_num > 0) {
+      return PopulateFile(file_num, output);
+    } else {
+      return false;
+    }
+  }
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override {
+    return false;
+  }
+
+ private:
+  void FullMatch(const std::string& name, const std::string& begin_with,
+                 const std::string& end_with, int* file_num) {
+    int begin_size = begin_with.size();
+    int end_size = end_with.size();
+    if (name.substr(0, begin_size) != begin_with ||
+        name.substr(name.size() - end_size, end_size) != end_with) {
+      return;
+    }
+    safe_strto32(
+        name.substr(begin_size, name.size() - end_size - begin_size), file_num);
+  }
+
+  bool PopulateFile(int file_num, FileDescriptorProto* output) {
+    GOOGLE_CHECK_GE(file_num, 0);
+    output->Clear();
+    output->set_name(strings::Substitute("file$0.proto", file_num));
+    // file0.proto doesn't define Message0
+    if (file_num > 0) {
+      DescriptorProto* message = output->add_message_type();
+      message->set_name(strings::Substitute("Message$0", file_num));
+      for (int i = 0; i < file_num; ++i) {
+        output->add_dependency(strings::Substitute("file$0.proto", i));
+        FieldDescriptorProto* field = message->add_field();
+        field->set_name(strings::Substitute("field$0", i));
+        field->set_number(i);
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+        field->set_type(FieldDescriptorProto::TYPE_MESSAGE);
+        field->set_type_name(strings::Substitute("Message$0", i));
+      }
+    }
+    return true;
+  }
+};
+
+TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
+  ExponentialErrorDatabase error_database;
+  DescriptorPool pool(&error_database);
+
+  GOOGLE_LOG(INFO) << "A timeout in this test probably indicates a real bug.";
+
+  EXPECT_TRUE(pool.FindFileByName("file40.proto") == nullptr);
+  EXPECT_TRUE(pool.FindMessageTypeByName("Message40") == nullptr);
+}
+
+TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
+  // If a lookup finds a symbol of the wrong type (e.g. we pass a type name
+  // to FindFieldByName()), we should fail fast, without checking the fallback
+  // database.
+  CallCountingDatabase call_counter(&database_);
+  DescriptorPool pool(&call_counter);
+
+  const FileDescriptor* file = pool.FindFileByName("foo.proto");
+  ASSERT_TRUE(file != nullptr);
+  const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+  ASSERT_TRUE(foo != nullptr);
+  const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
+  ASSERT_TRUE(test_enum != nullptr);
+
+  EXPECT_NE(0, call_counter.call_count_);
+  call_counter.Clear();
+
+  EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == nullptr);
+  EXPECT_TRUE(pool.FindFieldByName("Foo") == nullptr);
+  EXPECT_TRUE(pool.FindExtensionByName("Foo") == nullptr);
+  EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == nullptr);
+  EXPECT_TRUE(pool.FindEnumValueByName("Foo") == nullptr);
+  EXPECT_TRUE(pool.FindServiceByName("Foo") == nullptr);
+  EXPECT_TRUE(pool.FindMethodByName("Foo") == nullptr);
+
+  EXPECT_EQ(0, call_counter.call_count_);
+}
+
+// ===================================================================
+
+class AbortingErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  AbortingErrorCollector() {}
+
+  void AddError(const std::string& filename, const std::string& element_name,
+                const Message* message, ErrorLocation location,
+                const std::string& error_message) override {
+    GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << " ["
+               << element_name << "]: " << error_message;
+  }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector);
+};
+
+// A source tree containing only one file.
+class SingletonSourceTree : public compiler::SourceTree {
+ public:
+  SingletonSourceTree(const std::string& filename, const std::string& contents)
+      : filename_(filename), contents_(contents) {}
+
+  io::ZeroCopyInputStream* Open(const std::string& filename) override {
+    return filename == filename_
+               ? new io::ArrayInputStream(contents_.data(), contents_.size())
+               : nullptr;
+  }
+
+ private:
+  const std::string filename_;
+  const std::string contents_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingletonSourceTree);
+};
+
+const char* const kSourceLocationTestInput =
+    "syntax = \"proto2\";\n"
+    "option java_package = \"com.foo.bar\";\n"
+    "option (test_file_opt) = \"foobar\";\n"
+    "message A {\n"
+    "  option (test_msg_opt) = \"foobar\";\n"
+    "  optional int32 a = 1 [deprecated = true];\n"
+    "  message B {\n"
+    "    required double b = 1 [(test_field_opt) = \"foobar\"];\n"
+    "  }\n"
+    "  oneof c {\n"
+    "    option (test_oneof_opt) = \"foobar\";\n"
+    "    string d = 2;\n"
+    "    string e = 3;\n"
+    "    string f = 4;\n"
+    "  }\n"
+    "}\n"
+    "enum Indecision {\n"
+    "  option (test_enum_opt) = 21;\n"
+    "  option (test_enum_opt) = 42;\n"
+    "  option (test_enum_opt) = 63;\n"
+    "  YES   = 1 [(test_enumval_opt).a = 100];\n"
+    "  NO    = 2 [(test_enumval_opt) = {a:200}];\n"
+    "  MAYBE = 3;\n"
+    "}\n"
+    "service S {\n"
+    "  option (test_svc_opt) = {a:100};\n"
+    "  option (test_svc_opt) = {a:200};\n"
+    "  option (test_svc_opt) = {a:300};\n"
+    "  rpc Method(A) returns (A.B);\n"
+    // Put an empty line here to make the source location range match.
+    "\n"
+    "  rpc OtherMethod(A) returns (A) {\n"
+    "    option deprecated = true;\n"
+    "    option (test_method_opt) = \"foobar\";\n"
+    "  }\n"
+    "}\n"
+    "message MessageWithExtensions {\n"
+    "  extensions 1000 to 2000, 2001 to max [(test_ext_opt) = \"foobar\"];\n"
+    "}\n"
+    "extend MessageWithExtensions {\n"
+    "  repeated int32 int32_extension = 1001 [packed=true];\n"
+    "}\n"
+    "message C {\n"
+    "  extend MessageWithExtensions {\n"
+    "    optional C message_extension = 1002;\n"
+    "  }\n"
+    "}\n"
+    "import \"google/protobuf/descriptor.proto\";\n"
+    "extend google.protobuf.FileOptions {\n"
+    "  optional string test_file_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.MessageOptions {\n"
+    "  optional string test_msg_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.FieldOptions {\n"
+    "  optional string test_field_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.EnumOptions {\n"
+    "  repeated int32 test_enum_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.EnumValueOptions {\n"
+    "  optional A test_enumval_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.ServiceOptions {\n"
+    "  repeated A test_svc_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.MethodOptions {\n"
+    "  optional string test_method_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.OneofOptions {\n"
+    "  optional string test_oneof_opt = 10101;\n"
+    "}\n"
+    "extend google.protobuf.ExtensionRangeOptions {\n"
+    "  optional string test_ext_opt = 10101;\n"
+    "}\n";
+
+class SourceLocationTest : public testing::Test {
+ public:
+  SourceLocationTest()
+      : source_tree_("/test/test.proto", kSourceLocationTestInput),
+        simple_db_(),
+        source_tree_db_(&source_tree_),
+        merged_db_(&simple_db_, &source_tree_db_),
+        pool_(&merged_db_, &collector_) {
+    // we need descriptor.proto to be accessible by the pool
+    // since our test file imports it
+    FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto_);
+    simple_db_.Add(file_proto_);
+  }
+
+  static std::string PrintSourceLocation(const SourceLocation& loc) {
+    return strings::Substitute("$0:$1-$2:$3", 1 + loc.start_line,
+                            1 + loc.start_column, 1 + loc.end_line,
+                            1 + loc.end_column);
+  }
+
+ private:
+  FileDescriptorProto file_proto_;
+  AbortingErrorCollector collector_;
+  SingletonSourceTree source_tree_;
+  SimpleDescriptorDatabase simple_db_;  // contains descriptor.proto
+  compiler::SourceTreeDescriptorDatabase source_tree_db_;  // loads test.proto
+  MergedDescriptorDatabase merged_db_;  // combines above two dbs
+
+ protected:
+  DescriptorPool pool_;
+
+  // tag number of all custom options in above test file
+  static constexpr int kCustomOptionFieldNumber = 10101;
+  // tag number of field "a" in message type "A" in above test file
+  static constexpr int kAFieldNumber = 1;
+};
+
+// TODO(adonovan): implement support for option fields and for
+// subparts of declarations.
+
+TEST_F(SourceLocationTest, GetSourceLocation) {
+  SourceLocation loc;
+
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+  const Descriptor* a_desc = file_desc->FindMessageTypeByName("A");
+  EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("4:1-16:2", PrintSourceLocation(loc));
+
+  const Descriptor* a_b_desc = a_desc->FindNestedTypeByName("B");
+  EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("7:3-9:4", PrintSourceLocation(loc));
+
+  const EnumDescriptor* e_desc = file_desc->FindEnumTypeByName("Indecision");
+  EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("17:1-24:2", PrintSourceLocation(loc));
+
+  const EnumValueDescriptor* yes_desc = e_desc->FindValueByName("YES");
+  EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("21:3-21:42", PrintSourceLocation(loc));
+
+  const ServiceDescriptor* s_desc = file_desc->FindServiceByName("S");
+  EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("25:1-35:2", PrintSourceLocation(loc));
+
+  const MethodDescriptor* m_desc = s_desc->FindMethodByName("Method");
+  EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("29:3-29:31", PrintSourceLocation(loc));
+}
+
+TEST_F(SourceLocationTest, ExtensionSourceLocation) {
+  SourceLocation loc;
+
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+  const FieldDescriptor* int32_extension_desc =
+      file_desc->FindExtensionByName("int32_extension");
+  EXPECT_TRUE(int32_extension_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("40:3-40:55", PrintSourceLocation(loc));
+
+  const Descriptor* c_desc = file_desc->FindMessageTypeByName("C");
+  EXPECT_TRUE(c_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("42:1-46:2", PrintSourceLocation(loc));
+
+  const FieldDescriptor* message_extension_desc =
+      c_desc->FindExtensionByName("message_extension");
+  EXPECT_TRUE(message_extension_desc->GetSourceLocation(&loc));
+  EXPECT_EQ("44:5-44:41", PrintSourceLocation(loc));
+}
+TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
+  // This one's a doozy. It checks every kind of option, including
+  // extension range options.
+
+  // We are verifying that the file's source info contains correct
+  // info for interpreted options and that it does *not* contain
+  // any info for corresponding uninterpreted option path.
+
+  SourceLocation loc;
+
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+  // File options
+  {
+    int path[] = {FileDescriptorProto::kOptionsFieldNumber,
+                  FileOptions::kJavaPackageFieldNumber};
+    int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
+                   FileOptions::kUninterpretedOptionFieldNumber, 0};
+
+    std::vector<int> vpath(path, path + 2);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("2:1-2:37", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 3);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
+                   FileOptions::kUninterpretedOptionFieldNumber, 1};
+    std::vector<int> vpath(path, path + 2);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("3:1-3:35", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 3);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Message option
+  {
+    int path[] = {FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                  DescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber, 0,
+                   DescriptorProto::kOptionsFieldNumber,
+                   MessageOptions::kUninterpretedOptionFieldNumber, 0};
+    std::vector<int> vpath(path, path + 4);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("5:3-5:36", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Field option
+  {
+    int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                  0,
+                  DescriptorProto::kFieldFieldNumber,
+                  0,
+                  FieldDescriptorProto::kOptionsFieldNumber,
+                  FieldOptions::kDeprecatedFieldNumber};
+    int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                   0,
+                   DescriptorProto::kFieldFieldNumber,
+                   0,
+                   FieldDescriptorProto::kOptionsFieldNumber,
+                   FieldOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("6:25-6:42", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Nested message option
+  {
+    int path[] = {
+        FileDescriptorProto::kMessageTypeFieldNumber, 0,
+        DescriptorProto::kNestedTypeFieldNumber,      0,
+        DescriptorProto::kFieldFieldNumber,           0,
+        FieldDescriptorProto::kOptionsFieldNumber,    kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                   0,
+                   DescriptorProto::kNestedTypeFieldNumber,
+                   0,
+                   DescriptorProto::kFieldFieldNumber,
+                   0,
+                   FieldDescriptorProto::kOptionsFieldNumber,
+                   FieldOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 8);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("8:28-8:55", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 9);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // One-of option
+  {
+    int path[] = {
+        FileDescriptorProto::kMessageTypeFieldNumber, 0,
+        DescriptorProto::kOneofDeclFieldNumber,       0,
+        OneofDescriptorProto::kOptionsFieldNumber,    kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                   0,
+                   DescriptorProto::kOneofDeclFieldNumber,
+                   0,
+                   OneofDescriptorProto::kOptionsFieldNumber,
+                   OneofOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("11:5-11:40", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Enum option, repeated options
+  {
+    int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
+                  EnumDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber, 0};
+    int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
+                   EnumDescriptorProto::kOptionsFieldNumber,
+                   EnumOptions::kUninterpretedOptionFieldNumber, 0};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("18:3-18:31", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
+                  EnumDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber, 1};
+    int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
+                   EnumDescriptorProto::kOptionsFieldNumber,
+                   EnumOptions::kUninterpretedOptionFieldNumber, 1};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("19:3-19:31", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
+                  EnumDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber, 2};
+    int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
+                   EnumDescriptorProto::kOptionsFieldNumber,
+                   OneofOptions::kUninterpretedOptionFieldNumber, 2};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("20:3-20:31", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Enum value options
+  {
+    // option w/ message type that directly sets field
+    int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
+                  0,
+                  EnumDescriptorProto::kValueFieldNumber,
+                  0,
+                  EnumValueDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber,
+                  kAFieldNumber};
+    int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
+                   0,
+                   EnumDescriptorProto::kValueFieldNumber,
+                   0,
+                   EnumValueDescriptorProto::kOptionsFieldNumber,
+                   EnumValueOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 7);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("21:14-21:40", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
+                  0,
+                  EnumDescriptorProto::kValueFieldNumber,
+                  1,
+                  EnumValueDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
+                   0,
+                   EnumDescriptorProto::kValueFieldNumber,
+                   1,
+                   EnumValueDescriptorProto::kOptionsFieldNumber,
+                   EnumValueOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("22:14-22:42", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Service option, repeated options
+  {
+    int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
+                  ServiceDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber, 0};
+    int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
+                   ServiceDescriptorProto::kOptionsFieldNumber,
+                   ServiceOptions::kUninterpretedOptionFieldNumber, 0};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("26:3-26:35", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
+                  ServiceDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber, 1};
+    int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
+                   ServiceDescriptorProto::kOptionsFieldNumber,
+                   ServiceOptions::kUninterpretedOptionFieldNumber, 1};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("27:3-27:35", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
+                  ServiceDescriptorProto::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber, 2};
+    int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
+                   ServiceDescriptorProto::kOptionsFieldNumber,
+                   ServiceOptions::kUninterpretedOptionFieldNumber, 2};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("28:3-28:35", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Method options
+  {
+    int path[] = {FileDescriptorProto::kServiceFieldNumber,
+                  0,
+                  ServiceDescriptorProto::kMethodFieldNumber,
+                  1,
+                  MethodDescriptorProto::kOptionsFieldNumber,
+                  MethodOptions::kDeprecatedFieldNumber};
+    int unint[] = {FileDescriptorProto::kServiceFieldNumber,
+                   0,
+                   ServiceDescriptorProto::kMethodFieldNumber,
+                   1,
+                   MethodDescriptorProto::kOptionsFieldNumber,
+                   MethodOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("32:5-32:30", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {
+        FileDescriptorProto::kServiceFieldNumber,   0,
+        ServiceDescriptorProto::kMethodFieldNumber, 1,
+        MethodDescriptorProto::kOptionsFieldNumber, kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kServiceFieldNumber,
+                   0,
+                   ServiceDescriptorProto::kMethodFieldNumber,
+                   1,
+                   MethodDescriptorProto::kOptionsFieldNumber,
+                   MethodOptions::kUninterpretedOptionFieldNumber,
+                   1};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("33:5-33:41", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Extension range options
+  {
+    int path[] = {FileDescriptorProto::kMessageTypeFieldNumber, 1,
+                  DescriptorProto::kExtensionRangeFieldNumber, 0,
+                  DescriptorProto_ExtensionRange::kOptionsFieldNumber};
+    std::vector<int> vpath(path, path + 5);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("37:40-37:67", PrintSourceLocation(loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                  1,
+                  DescriptorProto::kExtensionRangeFieldNumber,
+                  0,
+                  DescriptorProto_ExtensionRange::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                   1,
+                   DescriptorProto::kExtensionRangeFieldNumber,
+                   0,
+                   DescriptorProto_ExtensionRange::kOptionsFieldNumber,
+                   ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+  {
+    int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                  1,
+                  DescriptorProto::kExtensionRangeFieldNumber,
+                  1,
+                  DescriptorProto_ExtensionRange::kOptionsFieldNumber,
+                  kCustomOptionFieldNumber};
+    int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
+                   1,
+                   DescriptorProto::kExtensionRangeFieldNumber,
+                   1,
+                   DescriptorProto_ExtensionRange::kOptionsFieldNumber,
+                   ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
+                   0};
+    std::vector<int> vpath(path, path + 6);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 7);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+
+  // Field option on extension
+  {
+    int path[] = {FileDescriptorProto::kExtensionFieldNumber, 0,
+                  FieldDescriptorProto::kOptionsFieldNumber,
+                  FieldOptions::kPackedFieldNumber};
+    int unint[] = {FileDescriptorProto::kExtensionFieldNumber, 0,
+                   FieldDescriptorProto::kOptionsFieldNumber,
+                   FieldOptions::kUninterpretedOptionFieldNumber, 0};
+    std::vector<int> vpath(path, path + 4);
+    EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
+    EXPECT_EQ("40:42-40:53", PrintSourceLocation(loc));
+
+    std::vector<int> vunint(unint, unint + 5);
+    EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
+  }
+}
+
+// Missing SourceCodeInfo doesn't cause crash:
+TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) {
+  SourceLocation loc;
+
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+  FileDescriptorProto proto;
+  file_desc->CopyTo(&proto);  // Note, this discards the SourceCodeInfo.
+  EXPECT_FALSE(proto.has_source_code_info());
+
+  DescriptorPool bad1_pool(&pool_);
+  const FileDescriptor* bad1_file_desc =
+      GOOGLE_CHECK_NOTNULL(bad1_pool.BuildFile(proto));
+  const Descriptor* bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A");
+  EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc));
+}
+
+// Corrupt SourceCodeInfo doesn't cause crash:
+TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) {
+  SourceLocation loc;
+
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+
+  FileDescriptorProto proto;
+  file_desc->CopyTo(&proto);  // Note, this discards the SourceCodeInfo.
+  EXPECT_FALSE(proto.has_source_code_info());
+  SourceCodeInfo_Location* loc_msg =
+      proto.mutable_source_code_info()->add_location();
+  loc_msg->add_path(1);
+  loc_msg->add_path(2);
+  loc_msg->add_path(3);
+  loc_msg->add_span(4);
+  loc_msg->add_span(5);
+  loc_msg->add_span(6);
+
+  DescriptorPool bad2_pool(&pool_);
+  const FileDescriptor* bad2_file_desc =
+      GOOGLE_CHECK_NOTNULL(bad2_pool.BuildFile(proto));
+  const Descriptor* bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A");
+  EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc));
+}
+
+// ===================================================================
+
+const char* const kCopySourceCodeInfoToTestInput =
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n";
+
+// Required since source code information is not preserved by
+// FileDescriptorTest.
+class CopySourceCodeInfoToTest : public testing::Test {
+ public:
+  CopySourceCodeInfoToTest()
+      : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput),
+        db_(&source_tree_),
+        pool_(&db_, &collector_) {}
+
+ private:
+  AbortingErrorCollector collector_;
+  SingletonSourceTree source_tree_;
+  compiler::SourceTreeDescriptorDatabase db_;
+
+ protected:
+  DescriptorPool pool_;
+};
+
+TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) {
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+  FileDescriptorProto file_desc_proto;
+  ASSERT_FALSE(file_desc_proto.has_source_code_info());
+
+  file_desc->CopyTo(&file_desc_proto);
+  EXPECT_FALSE(file_desc_proto.has_source_code_info());
+}
+
+TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
+  const FileDescriptor* file_desc =
+      GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
+  FileDescriptorProto file_desc_proto;
+  ASSERT_FALSE(file_desc_proto.has_source_code_info());
+
+  file_desc->CopySourceCodeInfoTo(&file_desc_proto);
+  const SourceCodeInfo& info = file_desc_proto.source_code_info();
+  ASSERT_EQ(4, info.location_size());
+  // Get the Foo message location
+  const SourceCodeInfo_Location& foo_location = info.location(2);
+  ASSERT_EQ(2, foo_location.path_size());
+  EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
+  EXPECT_EQ(0, foo_location.path(1));      // Foo is the first message defined
+  ASSERT_EQ(3, foo_location.span_size());  // Foo spans one line
+  EXPECT_EQ(1, foo_location.span(0));      // Foo is declared on line 1
+  EXPECT_EQ(0, foo_location.span(1));      // Foo starts at column 0
+  EXPECT_EQ(14, foo_location.span(2));     // Foo ends on column 14
+}
+
+// ===================================================================
+
+class LazilyBuildDependenciesTest : public testing::Test {
+ public:
+  LazilyBuildDependenciesTest() : pool_(&db_, nullptr) {
+    pool_.InternalSetLazilyBuildDependencies();
+  }
+
+  void ParseProtoAndAddToDb(const char* proto) {
+    FileDescriptorProto tmp;
+    ASSERT_TRUE(TextFormat::ParseFromString(proto, &tmp));
+    db_.Add(tmp);
+  }
+
+  void ParseProtoAndAddToDb(const std::string& proto) {
+    FileDescriptorProto tmp;
+    ASSERT_TRUE(TextFormat::ParseFromString(proto, &tmp));
+    db_.Add(tmp);
+  }
+
+  void AddSimpleMessageProtoFileToDb(const char* file_name,
+                                     const char* message_name) {
+    ParseProtoAndAddToDb("name: '" + std::string(file_name) +
+                         ".proto' "
+                         "package: \"protobuf_unittest\" "
+                         "message_type { "
+                         "  name:'" +
+                         std::string(message_name) +
+                         "' "
+                         "  field { name:'a' number:1 "
+                         "  label:LABEL_OPTIONAL "
+                         "  type_name:'int32' } "
+                         "}");
+  }
+
+  void AddSimpleEnumProtoFileToDb(const char* file_name, const char* enum_name,
+                                  const char* enum_value_name) {
+    ParseProtoAndAddToDb("name: '" + std::string(file_name) +
+                         ".proto' "
+                         "package: 'protobuf_unittest' "
+                         "enum_type { "
+                         "  name:'" +
+                         std::string(enum_name) +
+                         "' "
+                         "  value { name:'" +
+                         std::string(enum_value_name) +
+                         "' number:1 } "
+                         "}");
+  }
+
+ protected:
+  SimpleDescriptorDatabase db_;
+  DescriptorPool pool_;
+};
+
+TEST_F(LazilyBuildDependenciesTest, Message) {
+  ParseProtoAndAddToDb(
+      "name: 'foo.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'bar.proto' "
+      "message_type { "
+      "  name:'Foo' "
+      "  field { name:'bar' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Bar' } "
+      "}");
+  AddSimpleMessageProtoFileToDb("bar", "Bar");
+
+  // Verify neither has been built yet.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("foo.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
+
+  const FileDescriptor* file = pool_.FindFileByName("foo.proto");
+
+  // Verify only foo gets built when asking for foo.proto
+  EXPECT_TRUE(file != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
+
+  // Verify calling FindFieldBy* works when the type of the field was
+  // not built at cross link time. Verify this doesn't build the file
+  // the field's type is defined in, as well.
+  const Descriptor* desc = file->FindMessageTypeByName("Foo");
+  const FieldDescriptor* field = desc->FindFieldByName("bar");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_EQ(field, desc->FindFieldByNumber(1));
+  EXPECT_EQ(field, desc->FindFieldByLowercaseName("bar"));
+  EXPECT_EQ(field, desc->FindFieldByCamelcaseName("bar"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
+
+  // Finally, verify that if we call message_type() on the field, we will
+  // build the file where the message is defined, and get a valid descriptor
+  EXPECT_TRUE(field->message_type() != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
+}
+
+TEST_F(LazilyBuildDependenciesTest, Enum) {
+  ParseProtoAndAddToDb(
+      "name: 'foo.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'enum1.proto' "
+      "dependency: 'enum2.proto' "
+      "message_type { "
+      "  name:'Lazy' "
+      "  field { name:'enum1' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Enum1' } "
+      "  field { name:'enum2' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Enum2' } "
+      "}");
+  AddSimpleEnumProtoFileToDb("enum1", "Enum1", "ENUM1");
+  AddSimpleEnumProtoFileToDb("enum2", "Enum2", "ENUM2");
+
+  const FileDescriptor* file = pool_.FindFileByName("foo.proto");
+
+  // Verify calling enum_type() on a field whose definition is not
+  // yet built will build the file and return a descriptor.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
+  const Descriptor* desc = file->FindMessageTypeByName("Lazy");
+  EXPECT_TRUE(desc != nullptr);
+  const FieldDescriptor* field = desc->FindFieldByName("enum1");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_TRUE(field->enum_type() != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("enum1.proto"));
+
+  // Verify calling default_value_enum() on a field whose definition is not
+  // yet built will build the file and return a descriptor to the value.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
+  field = desc->FindFieldByName("enum2");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_TRUE(field->default_value_enum() != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("enum2.proto"));
+}
+
+TEST_F(LazilyBuildDependenciesTest, Type) {
+  ParseProtoAndAddToDb(
+      "name: 'foo.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'message1.proto' "
+      "dependency: 'message2.proto' "
+      "dependency: 'enum1.proto' "
+      "dependency: 'enum2.proto' "
+      "message_type { "
+      "  name:'Lazy' "
+      "  field { name:'message1' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Message1' } "
+      "  field { name:'message2' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Message2' } "
+      "  field { name:'enum1' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Enum1' } "
+      "  field { name:'enum2' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Enum2' } "
+      "}");
+  AddSimpleMessageProtoFileToDb("message1", "Message1");
+  AddSimpleMessageProtoFileToDb("message2", "Message2");
+  AddSimpleEnumProtoFileToDb("enum1", "Enum1", "ENUM1");
+  AddSimpleEnumProtoFileToDb("enum2", "Enum2", "ENUM2");
+
+  const FileDescriptor* file = pool_.FindFileByName("foo.proto");
+
+  // Verify calling type() on a field that is a message type will
+  // build the type defined in another file.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
+  const Descriptor* desc = file->FindMessageTypeByName("Lazy");
+  EXPECT_TRUE(desc != nullptr);
+  const FieldDescriptor* field = desc->FindFieldByName("message1");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("message1.proto"));
+
+  // Verify calling cpp_type() on a field that is a message type will
+  // build the type defined in another file.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
+  field = desc->FindFieldByName("message2");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_EQ(field->cpp_type(), FieldDescriptor::CPPTYPE_MESSAGE);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("message2.proto"));
+
+  // Verify calling type() on a field that is an enum type will
+  // build the type defined in another file.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
+  field = desc->FindFieldByName("enum1");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_EQ(field->type(), FieldDescriptor::TYPE_ENUM);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("enum1.proto"));
+
+  // Verify calling cpp_type() on a field that is an enum type will
+  // build the type defined in another file.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
+  field = desc->FindFieldByName("enum2");
+  EXPECT_TRUE(field != nullptr);
+  EXPECT_EQ(field->cpp_type(), FieldDescriptor::CPPTYPE_ENUM);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("enum2.proto"));
+}
+
+TEST_F(LazilyBuildDependenciesTest, Extension) {
+  ParseProtoAndAddToDb(
+      "name: 'foo.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'bar.proto' "
+      "dependency: 'baz.proto' "
+      "extension { extendee: '.protobuf_unittest.Bar' name:'bar' number:11"
+      "            label:LABEL_OPTIONAL type_name:'.protobuf_unittest.Baz' }");
+  ParseProtoAndAddToDb(
+      "name: 'bar.proto' "
+      "package: 'protobuf_unittest' "
+      "message_type { "
+      "  name:'Bar' "
+      "  extension_range { start: 10 end: 20 }"
+      "}");
+  AddSimpleMessageProtoFileToDb("baz", "Baz");
+
+  // Verify none have been built yet.
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("foo.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
+
+  const FileDescriptor* file = pool_.FindFileByName("foo.proto");
+
+  // Verify foo.bar gets loaded, and bar.proto gets loaded
+  // to register the extension. baz.proto should not get loaded.
+  EXPECT_TRUE(file != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
+}
+
+TEST_F(LazilyBuildDependenciesTest, Service) {
+  ParseProtoAndAddToDb(
+      "name: 'foo.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'message1.proto' "
+      "dependency: 'message2.proto' "
+      "dependency: 'message3.proto' "
+      "dependency: 'message4.proto' "
+      "service {"
+      "  name: 'LazyService'"
+      "  method { name: 'A' input_type:  '.protobuf_unittest.Message1' "
+      "                     output_type: '.protobuf_unittest.Message2' }"
+      "}");
+  AddSimpleMessageProtoFileToDb("message1", "Message1");
+  AddSimpleMessageProtoFileToDb("message2", "Message2");
+  AddSimpleMessageProtoFileToDb("message3", "Message3");
+  AddSimpleMessageProtoFileToDb("message4", "Message4");
+
+  const FileDescriptor* file = pool_.FindFileByName("foo.proto");
+
+  // Verify calling FindServiceByName or FindMethodByName doesn't build the
+  // files defining the input and output type, and input_type() and
+  // output_type() does indeed build the appropriate files.
+  const ServiceDescriptor* service = file->FindServiceByName("LazyService");
+  EXPECT_TRUE(service != nullptr);
+  const MethodDescriptor* method = service->FindMethodByName("A");
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
+  EXPECT_TRUE(method != nullptr);
+  EXPECT_TRUE(method->input_type() != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("message1.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
+  EXPECT_TRUE(method->output_type() != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("message2.proto"));
+}
+
+
+TEST_F(LazilyBuildDependenciesTest, GeneratedFile) {
+  // Most testing is done with custom pools with lazy dependencies forced on,
+  // do some sanity checking that lazy imports is on by default for the
+  // generated pool, and do custom options testing with generated to
+  // be able to use the GetExtension ids for the custom options.
+
+  // Verify none of the files are loaded yet.
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies.proto"));
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_enum.proto"));
+
+  // Verify calling autogenerated function to get a descriptor in the base
+  // file will build that file but none of it's imports. This verifies that
+  // lazily_build_dependencies_ is set on the generated pool, and also that
+  // the generated function "descriptor()" doesn't somehow subvert the laziness
+  // by manually loading the dependencies or something.
+  EXPECT_TRUE(protobuf_unittest::lazy_imports::ImportedMessage::descriptor() !=
+              nullptr);
+  EXPECT_TRUE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies.proto"));
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_enum.proto"));
+
+  // Verify custom options work when defined in an import that isn't loaded,
+  // and that a non-default value of a custom option doesn't load the file
+  // where that enum is defined.
+  const MessageOptions& options =
+      protobuf_unittest::lazy_imports::MessageCustomOption::descriptor()
+          ->options();
+  protobuf_unittest::lazy_imports::LazyEnum custom_option_value =
+      options.GetExtension(protobuf_unittest::lazy_imports::lazy_enum_option);
+
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_enum.proto"));
+  EXPECT_EQ(custom_option_value, protobuf_unittest::lazy_imports::LAZY_ENUM_1);
+
+  const MessageOptions& options2 =
+      protobuf_unittest::lazy_imports::MessageCustomOption2::descriptor()
+          ->options();
+  custom_option_value =
+      options2.GetExtension(protobuf_unittest::lazy_imports::lazy_enum_option);
+
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
+  EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
+      "google/protobuf/unittest_lazy_dependencies_enum.proto"));
+  EXPECT_EQ(custom_option_value, protobuf_unittest::lazy_imports::LAZY_ENUM_0);
+}
+
+TEST_F(LazilyBuildDependenciesTest, Dependency) {
+  ParseProtoAndAddToDb(
+      "name: 'foo.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'bar.proto' "
+      "message_type { "
+      "  name:'Foo' "
+      "  field { name:'bar' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Bar' } "
+      "}");
+  ParseProtoAndAddToDb(
+      "name: 'bar.proto' "
+      "package: 'protobuf_unittest' "
+      "dependency: 'baz.proto' "
+      "message_type { "
+      "  name:'Bar' "
+      "  field { name:'baz' number:1 label:LABEL_OPTIONAL "
+      "type_name:'.protobuf_unittest.Baz' } "
+      "}");
+  AddSimpleMessageProtoFileToDb("baz", "Baz");
+
+  const FileDescriptor* foo_file = pool_.FindFileByName("foo.proto");
+  EXPECT_TRUE(foo_file != nullptr);
+  // As expected, requesting foo.proto shouldn't build it's dependencies
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
+
+  // Verify calling dependency(N) will build the dependency, but
+  // not that file's dependencies.
+  const FileDescriptor* bar_file = foo_file->dependency(0);
+  EXPECT_TRUE(bar_file != nullptr);
+  EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
+  EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
+}
+
+// ===================================================================
+
+
+}  // namespace descriptor_unittest
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/drop_unknown_fields_test.cc b/src/google/protobuf/drop_unknown_fields_test.cc
new file mode 100644
index 0000000..55c6b67
--- /dev/null
+++ b/src/google/protobuf/drop_unknown_fields_test.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 <memory>
+
+#include <google/protobuf/unittest_drop_unknown_fields.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message_lite.h>
+#include <gtest/gtest.h>
+
+using unittest_drop_unknown_fields::Foo;
+using unittest_drop_unknown_fields::FooWithExtraFields;
+
+namespace google {
+namespace protobuf {
+
+TEST(DropUnknownFieldsTest, GeneratedMessage) {
+  FooWithExtraFields foo_with_extra_fields;
+  foo_with_extra_fields.set_int32_value(1);
+  foo_with_extra_fields.set_enum_value(FooWithExtraFields::MOO);
+  foo_with_extra_fields.set_extra_int32_value(2);
+
+  Foo foo;
+  ASSERT_TRUE(foo.ParseFromString(foo_with_extra_fields.SerializeAsString()));
+  EXPECT_EQ(1, foo.int32_value());
+  EXPECT_EQ(static_cast<int>(FooWithExtraFields::MOO),
+            static_cast<int>(foo.enum_value()));
+  EXPECT_FALSE(foo.GetReflection()->GetUnknownFields(foo).empty());
+
+  ASSERT_TRUE(foo_with_extra_fields.ParseFromString(foo.SerializeAsString()));
+  EXPECT_EQ(1, foo_with_extra_fields.int32_value());
+  EXPECT_EQ(FooWithExtraFields::MOO, foo_with_extra_fields.enum_value());
+  // The "extra_int32_value" field should not be lost.
+  EXPECT_EQ(2, foo_with_extra_fields.extra_int32_value());
+}
+
+TEST(DropUnknownFieldsTest, DynamicMessage) {
+  FooWithExtraFields foo_with_extra_fields;
+  foo_with_extra_fields.set_int32_value(1);
+  foo_with_extra_fields.set_enum_value(FooWithExtraFields::MOO);
+  foo_with_extra_fields.set_extra_int32_value(2);
+
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> foo(factory.GetPrototype(Foo::descriptor())->New());
+  ASSERT_TRUE(foo->ParseFromString(foo_with_extra_fields.SerializeAsString()));
+  EXPECT_FALSE(foo->GetReflection()->GetUnknownFields(*foo).empty());
+
+  ASSERT_TRUE(foo_with_extra_fields.ParseFromString(foo->SerializeAsString()));
+  EXPECT_EQ(1, foo_with_extra_fields.int32_value());
+  EXPECT_EQ(FooWithExtraFields::MOO, foo_with_extra_fields.enum_value());
+  // The "extra_int32_value" field should not be lost.
+  EXPECT_EQ(2, foo_with_extra_fields.extra_int32_value());
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
new file mode 100644
index 0000000..72766bd
--- /dev/null
+++ b/src/google/protobuf/duration.pb.cc
@@ -0,0 +1,307 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#include <google/protobuf/duration.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Duration::Duration(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.seconds_)*/int64_t{0}
+  , /*decltype(_impl_.nanos_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct DurationDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DurationDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DurationDefaultTypeInternal() {}
+  union {
+    Duration _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DurationDefaultTypeInternal _Duration_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fduration_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, _impl_.seconds_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, _impl_.nanos_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Duration)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Duration_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\036google/protobuf/duration.proto\022\017google"
+  ".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r"
+  "\n\005nanos\030\002 \001(\005B\203\001\n\023com.google.protobufB\rD"
+  "urationProtoP\001Z1google.golang.org/protob"
+  "uf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Goo"
+  "gle.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fduration_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
+    false, false, 235, descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto,
+    "google/protobuf/duration.proto",
+    &descriptor_table_google_2fprotobuf_2fduration_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fduration_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fduration_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fduration_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fduration_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fduration_2eproto(&descriptor_table_google_2fprotobuf_2fduration_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Duration::_Internal {
+ public:
+};
+
+Duration::Duration(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Duration)
+}
+Duration::Duration(const Duration& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Duration* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){}
+    , decltype(_impl_.nanos_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.seconds_, &from._impl_.seconds_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.nanos_) -
+    reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Duration)
+}
+
+inline void Duration::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){int64_t{0}}
+    , decltype(_impl_.nanos_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Duration::~Duration() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Duration)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Duration::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Duration::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Duration::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Duration)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  ::memset(&_impl_.seconds_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.nanos_) -
+      reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Duration::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int64 seconds = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.seconds_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 nanos = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _impl_.nanos_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Duration::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Duration)
+  return target;
+}
+
+size_t Duration::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Duration::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Duration::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Duration::GetClassData() const { return &_class_data_; }
+
+
+void Duration::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Duration*>(&to_msg);
+  auto& from = static_cast<const Duration&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_seconds() != 0) {
+    _this->_internal_set_seconds(from._internal_seconds());
+  }
+  if (from._internal_nanos() != 0) {
+    _this->_internal_set_nanos(from._internal_nanos());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Duration::CopyFrom(const Duration& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Duration)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Duration::IsInitialized() const {
+  return true;
+}
+
+void Duration::InternalSwap(Duration* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Duration, _impl_.nanos_)
+      + sizeof(Duration::_impl_.nanos_)
+      - PROTOBUF_FIELD_OFFSET(Duration, _impl_.seconds_)>(
+          reinterpret_cast<char*>(&_impl_.seconds_),
+          reinterpret_cast<char*>(&other->_impl_.seconds_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Duration::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fduration_2eproto_getter, &descriptor_table_google_2fprotobuf_2fduration_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fduration_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Duration*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Duration >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Duration >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
new file mode 100644
index 0000000..c913020
--- /dev/null
+++ b/src/google/protobuf/duration.pb.h
@@ -0,0 +1,278 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fduration_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fduration_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fduration_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fduration_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Duration;
+struct DurationDefaultTypeInternal;
+PROTOBUF_EXPORT extern DurationDefaultTypeInternal _Duration_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Duration* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Duration>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Duration final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Duration) */ {
+ public:
+  inline Duration() : Duration(nullptr) {}
+  ~Duration() override;
+  explicit PROTOBUF_CONSTEXPR Duration(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Duration(const Duration& from);
+  Duration(Duration&& from) noexcept
+    : Duration() {
+    *this = ::std::move(from);
+  }
+
+  inline Duration& operator=(const Duration& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Duration& operator=(Duration&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Duration& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Duration* internal_default_instance() {
+    return reinterpret_cast<const Duration*>(
+               &_Duration_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Duration& a, Duration& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Duration* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Duration* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Duration* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Duration>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Duration& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Duration& from) {
+    Duration::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Duration* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Duration";
+  }
+  protected:
+  explicit Duration(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kSecondsFieldNumber = 1,
+    kNanosFieldNumber = 2,
+  };
+  // int64 seconds = 1;
+  void clear_seconds();
+  int64_t seconds() const;
+  void set_seconds(int64_t value);
+  private:
+  int64_t _internal_seconds() const;
+  void _internal_set_seconds(int64_t value);
+  public:
+
+  // int32 nanos = 2;
+  void clear_nanos();
+  int32_t nanos() const;
+  void set_nanos(int32_t value);
+  private:
+  int32_t _internal_nanos() const;
+  void _internal_set_nanos(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Duration)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int64_t seconds_;
+    int32_t nanos_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fduration_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Duration
+
+// int64 seconds = 1;
+inline void Duration::clear_seconds() {
+  _impl_.seconds_ = int64_t{0};
+}
+inline int64_t Duration::_internal_seconds() const {
+  return _impl_.seconds_;
+}
+inline int64_t Duration::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.seconds)
+  return _internal_seconds();
+}
+inline void Duration::_internal_set_seconds(int64_t value) {
+  
+  _impl_.seconds_ = value;
+}
+inline void Duration::set_seconds(int64_t value) {
+  _internal_set_seconds(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.seconds)
+}
+
+// int32 nanos = 2;
+inline void Duration::clear_nanos() {
+  _impl_.nanos_ = 0;
+}
+inline int32_t Duration::_internal_nanos() const {
+  return _impl_.nanos_;
+}
+inline int32_t Duration::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.nanos)
+  return _internal_nanos();
+}
+inline void Duration::_internal_set_nanos(int32_t value) {
+  
+  _impl_.nanos_ = value;
+}
+inline void Duration::set_nanos(int32_t value) {
+  _internal_set_nanos(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.nanos)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fduration_2eproto
diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto
new file mode 100644
index 0000000..81c3e36
--- /dev/null
+++ b/src/google/protobuf/duration.proto
@@ -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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/durationpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DurationProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// A Duration represents a signed, fixed-length span of time represented
+// as a count of seconds and fractions of seconds at nanosecond
+// resolution. It is independent of any calendar and concepts like "day"
+// or "month". It is related to Timestamp in that the difference between
+// two Timestamp values is a Duration and it can be added or subtracted
+// from a Timestamp. Range is approximately +-10,000 years.
+//
+// # Examples
+//
+// 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 (duration.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;
+//     }
+//
+// Example 3: Compute Duration from datetime.timedelta in Python.
+//
+//     td = datetime.timedelta(days=3, minutes=10)
+//     duration = Duration()
+//     duration.FromTimedelta(td)
+//
+// # JSON Mapping
+//
+// In JSON format, the Duration type is encoded as a string rather than an
+// object, where the string ends in the suffix "s" (indicating seconds) and
+// is preceded by the number of seconds, with nanoseconds expressed as
+// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
+// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
+// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
+// microsecond should be expressed in JSON format as "3.000001s".
+//
+//
+message Duration {
+  // Signed seconds of the span of time. Must be from -315,576,000,000
+  // to +315,576,000,000 inclusive. Note: these bounds are computed from:
+  // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
+  int64 seconds = 1;
+
+  // Signed fractions of a second at nanosecond resolution of the span
+  // of time. Durations less than one second are represented with a 0
+  // `seconds` field and a positive or negative `nanos` field. For durations
+  // of one second or more, a non-zero value for the `nanos` field must be
+  // of the same sign as the `seconds` field. Must be from -999,999,999
+  // to +999,999,999 inclusive.
+  int32 nanos = 2;
+}
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
new file mode 100644
index 0000000..1c96ca2
--- /dev/null
+++ b/src/google/protobuf/dynamic_message.cc
@@ -0,0 +1,826 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// DynamicMessage is implemented by constructing a data structure which
+// has roughly the same memory layout as a generated message would have.
+// Then, we use Reflection to implement our reflection interface.  All
+// the other operations we need to implement (e.g.  parsing, copying,
+// etc.) are already implemented in terms of Reflection, so the rest is
+// easy.
+//
+// The up side of this strategy is that it's very efficient.  We don't
+// need to use hash_maps or generic representations of fields.  The
+// down side is that this is a low-level memory management hack which
+// can be tricky to get right.
+//
+// As mentioned in the header, we only expose a DynamicMessageFactory
+// publicly, not the DynamicMessage class itself.  This is because
+// GenericMessageReflection wants to have a pointer to a "default"
+// copy of the class, with all fields initialized to their default
+// values.  We only want to construct one of these per message type,
+// so DynamicMessageFactory stores a cache of default messages for
+// each type it sees (each unique Descriptor pointer).  The code
+// refers to the "default" copy of the class as the "prototype".
+//
+// Note on memory allocation:  This module often calls "operator new()"
+// to allocate untyped memory, rather than calling something like
+// "new uint8_t[]".  This is because "operator new()" means "Give me some
+// space which I can use as I please." while "new uint8_t[]" means "Give
+// me an array of 8-bit integers.".  In practice, the later may return
+// a pointer that is not aligned correctly for general use.  I believe
+// Item 8 of "More Effective C++" discusses this in more detail, though
+// I don't have the book on me right now so I'm not sure.
+
+#include <google/protobuf/dynamic_message.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <new>
+#include <unordered_map>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+using internal::DynamicMapField;
+using internal::ExtensionSet;
+using internal::MapField;
+
+
+using internal::ArenaStringPtr;
+
+// ===================================================================
+// Some helper tables and functions...
+
+namespace {
+
+bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); }
+
+// Sync with helpers.h.
+inline bool HasHasbit(const FieldDescriptor* field) {
+  // This predicate includes proto3 message fields only if they have "optional".
+  //   Foo submsg1 = 1;           // HasHasbit() == false
+  //   optional Foo submsg2 = 2;  // HasHasbit() == true
+  // This is slightly odd, as adding "optional" to a singular proto3 field does
+  // not change the semantics or API. However whenever any field in a message
+  // has a hasbit, it forces reflection to include hasbit offsets for *all*
+  // fields, even if almost all of them are set to -1 (no hasbit). So to avoid
+  // causing a sudden size regression for ~all proto3 messages, we give proto3
+  // message fields a hasbit only if "optional" is present. If the user is
+  // explicitly writing "optional", it is likely they are writing it on
+  // primitive fields also.
+  return (field->has_optional_keyword() || field->is_required()) &&
+         !field->options().weak();
+}
+
+inline bool InRealOneof(const FieldDescriptor* field) {
+  return field->containing_oneof() &&
+         !field->containing_oneof()->is_synthetic();
+}
+
+// Compute the byte size of the in-memory representation of the field.
+int FieldSpaceUsed(const FieldDescriptor* field) {
+  typedef FieldDescriptor FD;  // avoid line wrapping
+  if (field->label() == FD::LABEL_REPEATED) {
+    switch (field->cpp_type()) {
+      case FD::CPPTYPE_INT32:
+        return sizeof(RepeatedField<int32_t>);
+      case FD::CPPTYPE_INT64:
+        return sizeof(RepeatedField<int64_t>);
+      case FD::CPPTYPE_UINT32:
+        return sizeof(RepeatedField<uint32_t>);
+      case FD::CPPTYPE_UINT64:
+        return sizeof(RepeatedField<uint64_t>);
+      case FD::CPPTYPE_DOUBLE:
+        return sizeof(RepeatedField<double>);
+      case FD::CPPTYPE_FLOAT:
+        return sizeof(RepeatedField<float>);
+      case FD::CPPTYPE_BOOL:
+        return sizeof(RepeatedField<bool>);
+      case FD::CPPTYPE_ENUM:
+        return sizeof(RepeatedField<int>);
+      case FD::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          return sizeof(DynamicMapField);
+        } else {
+          return sizeof(RepeatedPtrField<Message>);
+        }
+
+      case FD::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            return sizeof(RepeatedPtrField<std::string>);
+        }
+        break;
+    }
+  } else {
+    switch (field->cpp_type()) {
+      case FD::CPPTYPE_INT32:
+        return sizeof(int32_t);
+      case FD::CPPTYPE_INT64:
+        return sizeof(int64_t);
+      case FD::CPPTYPE_UINT32:
+        return sizeof(uint32_t);
+      case FD::CPPTYPE_UINT64:
+        return sizeof(uint64_t);
+      case FD::CPPTYPE_DOUBLE:
+        return sizeof(double);
+      case FD::CPPTYPE_FLOAT:
+        return sizeof(float);
+      case FD::CPPTYPE_BOOL:
+        return sizeof(bool);
+      case FD::CPPTYPE_ENUM:
+        return sizeof(int);
+
+      case FD::CPPTYPE_MESSAGE:
+        return sizeof(Message*);
+
+      case FD::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            return sizeof(ArenaStringPtr);
+        }
+        break;
+    }
+  }
+
+  GOOGLE_LOG(DFATAL) << "Can't get here.";
+  return 0;
+}
+
+inline int DivideRoundingUp(int i, int j) { return (i + (j - 1)) / j; }
+
+static const int kSafeAlignment = sizeof(uint64_t);
+static const int kMaxOneofUnionSize = sizeof(uint64_t);
+
+inline int AlignTo(int offset, int alignment) {
+  return DivideRoundingUp(offset, alignment) * alignment;
+}
+
+// Rounds the given byte offset up to the next offset aligned such that any
+// type may be stored at it.
+inline int AlignOffset(int offset) { return AlignTo(offset, kSafeAlignment); }
+
+#define bitsizeof(T) (sizeof(T) * 8)
+
+}  // namespace
+
+// ===================================================================
+
+class DynamicMessage : public Message {
+ public:
+  explicit DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info);
+
+  // This should only be used by GetPrototypeNoLock() to avoid dead lock.
+  DynamicMessage(DynamicMessageFactory::TypeInfo* type_info, bool lock_factory);
+
+  ~DynamicMessage() override;
+
+  // Called on the prototype after construction to initialize message fields.
+  // Cross linking the default instances allows for fast reflection access of
+  // unset message fields. Without it we would have to go to the MessageFactory
+  // to get the prototype, which is a much more expensive operation.
+  //
+  // Generated messages do not cross-link to avoid dynamic initialization of the
+  // global instances.
+  // Instead, they keep the default instances in the FieldDescriptor objects.
+  void CrossLinkPrototypes();
+
+  // implements Message ----------------------------------------------
+
+  Message* New(Arena* arena) const override;
+
+  int GetCachedSize() const override;
+  void SetCachedSize(int size) const override;
+
+  Metadata GetMetadata() const override;
+
+#if defined(__cpp_lib_destroying_delete) && defined(__cpp_sized_deallocation)
+  static void operator delete(DynamicMessage* msg, std::destroying_delete_t);
+#else
+  // We actually allocate more memory than sizeof(*this) when this
+  // class's memory is allocated via the global operator new. Thus, we need to
+  // manually call the global operator delete. Calling the destructor is taken
+  // care of for us. This makes DynamicMessage compatible with -fsized-delete.
+  // It doesn't work for MSVC though.
+#ifndef _MSC_VER
+  static void operator delete(void* ptr) { ::operator delete(ptr); }
+#endif  // !_MSC_VER
+#endif
+
+ private:
+  DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info,
+                 Arena* arena);
+
+  void SharedCtor(bool lock_factory);
+
+  // Needed to get the offset of the internal metadata member.
+  friend class DynamicMessageFactory;
+
+  bool is_prototype() const;
+
+  inline void* OffsetToPointer(int offset) {
+    return reinterpret_cast<uint8_t*>(this) + offset;
+  }
+  inline const void* OffsetToPointer(int offset) const {
+    return reinterpret_cast<const uint8_t*>(this) + offset;
+  }
+
+  void* MutableRaw(int i);
+  void* MutableExtensionsRaw();
+  void* MutableWeakFieldMapRaw();
+  void* MutableOneofCaseRaw(int i);
+  void* MutableOneofFieldRaw(const FieldDescriptor* f);
+
+  const DynamicMessageFactory::TypeInfo* type_info_;
+  mutable std::atomic<int> cached_byte_size_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
+};
+
+struct DynamicMessageFactory::TypeInfo {
+  int size;
+  int has_bits_offset;
+  int oneof_case_offset;
+  int extensions_offset;
+
+  // Not owned by the TypeInfo.
+  DynamicMessageFactory* factory;  // The factory that created this object.
+  const DescriptorPool* pool;      // The factory's DescriptorPool.
+  const Descriptor* type;          // Type of this DynamicMessage.
+
+  // Warning:  The order in which the following pointers are defined is
+  //   important (the prototype must be deleted *before* the offsets).
+  std::unique_ptr<uint32_t[]> offsets;
+  std::unique_ptr<uint32_t[]> has_bits_indices;
+  std::unique_ptr<const Reflection> reflection;
+  // Don't use a unique_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
+  // implementation of unique_ptr.
+  const DynamicMessage* prototype;
+  int weak_field_map_offset;  // The offset for the weak_field_map;
+
+  TypeInfo() : prototype(nullptr) {}
+
+  ~TypeInfo() { delete prototype; }
+};
+
+DynamicMessage::DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info)
+    : type_info_(type_info), cached_byte_size_(0) {
+  SharedCtor(true);
+}
+
+DynamicMessage::DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info,
+                               Arena* arena)
+    : Message(arena), type_info_(type_info), cached_byte_size_(0) {
+  SharedCtor(true);
+}
+
+DynamicMessage::DynamicMessage(DynamicMessageFactory::TypeInfo* type_info,
+                               bool lock_factory)
+    : type_info_(type_info), cached_byte_size_(0) {
+  // The prototype in type_info has to be set before creating the prototype
+  // instance on memory. e.g., message Foo { map<int32_t, 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 assign the address of
+  // prototype into type_info first.
+  type_info->prototype = this;
+  SharedCtor(lock_factory);
+}
+
+inline void* DynamicMessage::MutableRaw(int i) {
+  return OffsetToPointer(type_info_->offsets[i]);
+}
+inline void* DynamicMessage::MutableExtensionsRaw() {
+  return OffsetToPointer(type_info_->extensions_offset);
+}
+inline void* DynamicMessage::MutableWeakFieldMapRaw() {
+  return OffsetToPointer(type_info_->weak_field_map_offset);
+}
+inline void* DynamicMessage::MutableOneofCaseRaw(int i) {
+  return OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32_t) * i);
+}
+inline void* DynamicMessage::MutableOneofFieldRaw(const FieldDescriptor* f) {
+  return OffsetToPointer(type_info_->offsets[type_info_->type->field_count() +
+                                             f->containing_oneof()->index()]);
+}
+
+void DynamicMessage::SharedCtor(bool lock_factory) {
+  // We need to call constructors for various fields manually and set
+  // default values where appropriate.  We use placement new to call
+  // constructors.  If you haven't heard of placement new, I suggest Googling
+  // it now.  We use placement new even for primitive types that don't have
+  // constructors for consistency.  (In theory, placement new should be used
+  // any time you are trying to convert untyped memory to typed memory, though
+  // in practice that's not strictly necessary for types that don't have a
+  // constructor.)
+
+  const Descriptor* descriptor = type_info_->type;
+  // Initialize oneof cases.
+  int oneof_count = 0;
+  for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
+    if (descriptor->oneof_decl(i)->is_synthetic()) continue;
+    new (MutableOneofCaseRaw(oneof_count++)) uint32_t{0};
+  }
+
+  if (type_info_->extensions_offset != -1) {
+    new (MutableExtensionsRaw()) ExtensionSet(GetArenaForAllocation());
+  }
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    void* field_ptr = MutableRaw(i);
+    if (InRealOneof(field)) {
+      continue;
+    }
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                                  \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                          \
+    if (!field->is_repeated()) {                                    \
+      new (field_ptr) TYPE(field->default_value_##TYPE());          \
+    } else {                                                        \
+      new (field_ptr) RepeatedField<TYPE>(GetArenaForAllocation()); \
+    }                                                               \
+    break;
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_ENUM:
+        if (!field->is_repeated()) {
+          new (field_ptr) int{field->default_value_enum()->number()};
+        } else {
+          new (field_ptr) RepeatedField<int>(GetArenaForAllocation());
+        }
+        break;
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            if (!field->is_repeated()) {
+              ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
+              asp->InitDefault();
+            } else {
+              new (field_ptr)
+                  RepeatedPtrField<std::string>(GetArenaForAllocation());
+            }
+            break;
+        }
+        break;
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        if (!field->is_repeated()) {
+          new (field_ptr) Message*(nullptr);
+        } else {
+          if (IsMapFieldInApi(field)) {
+            // We need to lock in most cases to avoid data racing. Only not lock
+            // when the constructor is called inside GetPrototype(), in which
+            // case we have already locked the factory.
+            if (lock_factory) {
+              if (GetArenaForAllocation() != nullptr) {
+                new (field_ptr) DynamicMapField(
+                    type_info_->factory->GetPrototype(field->message_type()),
+                    GetArenaForAllocation());
+                if (GetOwningArena() != nullptr) {
+                  // Needs to destroy the mutex member.
+                  GetOwningArena()->OwnDestructor(
+                      static_cast<DynamicMapField*>(field_ptr));
+                }
+              } else {
+                new (field_ptr) DynamicMapField(
+                    type_info_->factory->GetPrototype(field->message_type()));
+              }
+            } else {
+              if (GetArenaForAllocation() != nullptr) {
+                new (field_ptr)
+                    DynamicMapField(type_info_->factory->GetPrototypeNoLock(
+                                        field->message_type()),
+                                    GetArenaForAllocation());
+                if (GetOwningArena() != nullptr) {
+                  // Needs to destroy the mutex member.
+                  GetOwningArena()->OwnDestructor(
+                      static_cast<DynamicMapField*>(field_ptr));
+                }
+              } else {
+                new (field_ptr)
+                    DynamicMapField(type_info_->factory->GetPrototypeNoLock(
+                        field->message_type()));
+              }
+            }
+          } else {
+            new (field_ptr) RepeatedPtrField<Message>(GetArenaForAllocation());
+          }
+        }
+        break;
+      }
+    }
+  }
+}
+
+bool DynamicMessage::is_prototype() const {
+  return type_info_->prototype == this ||
+         // If type_info_->prototype is nullptr, then we must be constructing
+         // the prototype now, which means we must be the prototype.
+         type_info_->prototype == nullptr;
+}
+
+#if defined(__cpp_lib_destroying_delete) && defined(__cpp_sized_deallocation)
+void DynamicMessage::operator delete(DynamicMessage* msg,
+                                     std::destroying_delete_t) {
+  const size_t size = msg->type_info_->size;
+  msg->~DynamicMessage();
+  ::operator delete(msg, size);
+}
+#endif
+
+DynamicMessage::~DynamicMessage() {
+  const Descriptor* descriptor = type_info_->type;
+
+  _internal_metadata_.Delete<UnknownFieldSet>();
+
+  if (type_info_->extensions_offset != -1) {
+    reinterpret_cast<ExtensionSet*>(MutableExtensionsRaw())->~ExtensionSet();
+  }
+
+  // We need to manually run the destructors for repeated fields and strings,
+  // 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
+  // need to delete them, UNLESS we are the prototype message of this type,
+  // in which case any embedded messages are other prototypes and shouldn't
+  // be touched.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (InRealOneof(field)) {
+      void* field_ptr = MutableOneofCaseRaw(field->containing_oneof()->index());
+      if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) {
+        field_ptr = MutableOneofFieldRaw(field);
+        if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+          switch (field->options().ctype()) {
+            default:
+            case FieldOptions::STRING: {
+              reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
+              break;
+            }
+          }
+        } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+            delete *reinterpret_cast<Message**>(field_ptr);
+        }
+      }
+      continue;
+    }
+    void* field_ptr = MutableRaw(i);
+
+    if (field->is_repeated()) {
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                  \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:               \
+    reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
+        ->~RepeatedField<LOWERCASE>();                     \
+    break
+
+        HANDLE_TYPE(INT32, int32_t);
+        HANDLE_TYPE(INT64, int64_t);
+        HANDLE_TYPE(UINT32, uint32_t);
+        HANDLE_TYPE(UINT64, uint64_t);
+        HANDLE_TYPE(DOUBLE, double);
+        HANDLE_TYPE(FLOAT, float);
+        HANDLE_TYPE(BOOL, bool);
+        HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_STRING:
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              reinterpret_cast<RepeatedPtrField<std::string>*>(field_ptr)
+                  ->~RepeatedPtrField<std::string>();
+              break;
+          }
+          break;
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (IsMapFieldInApi(field)) {
+            reinterpret_cast<DynamicMapField*>(field_ptr)->~DynamicMapField();
+          } else {
+            reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
+                ->~RepeatedPtrField<Message>();
+          }
+          break;
+      }
+
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      switch (field->options().ctype()) {
+        default:  // TODO(kenton):  Support other string reps.
+        case FieldOptions::STRING: {
+          reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
+          break;
+        }
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          if (!is_prototype()) {
+        Message* message = *reinterpret_cast<Message**>(field_ptr);
+        if (message != nullptr) {
+          delete message;
+        }
+      }
+    }
+  }
+}
+
+void DynamicMessage::CrossLinkPrototypes() {
+  // This should only be called on the prototype message.
+  GOOGLE_CHECK(is_prototype());
+
+  DynamicMessageFactory* factory = type_info_->factory;
+  const Descriptor* descriptor = type_info_->type;
+
+  // Cross-link default messages.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !field->options().weak() && !InRealOneof(field) &&
+        !field->is_repeated()) {
+      void* field_ptr = MutableRaw(i);
+      // For fields with message types, we need to cross-link with the
+      // prototype for the field's type.
+      // For singular fields, the field is just a pointer which should
+      // point to the prototype.
+      *reinterpret_cast<const Message**>(field_ptr) =
+          factory->GetPrototypeNoLock(field->message_type());
+    }
+  }
+}
+
+Message* DynamicMessage::New(Arena* arena) const {
+  if (arena != nullptr) {
+    void* new_base = Arena::CreateArray<char>(arena, type_info_->size);
+    memset(new_base, 0, type_info_->size);
+    return new (new_base) DynamicMessage(type_info_, arena);
+  } else {
+    void* new_base = operator new(type_info_->size);
+    memset(new_base, 0, type_info_->size);
+    return new (new_base) DynamicMessage(type_info_);
+  }
+}
+
+int DynamicMessage::GetCachedSize() const {
+  return cached_byte_size_.load(std::memory_order_relaxed);
+}
+
+void DynamicMessage::SetCachedSize(int size) const {
+  cached_byte_size_.store(size, std::memory_order_relaxed);
+}
+
+Metadata DynamicMessage::GetMetadata() const {
+  Metadata metadata;
+  metadata.descriptor = type_info_->type;
+  metadata.reflection = type_info_->reflection.get();
+  return metadata;
+}
+
+// ===================================================================
+
+DynamicMessageFactory::DynamicMessageFactory()
+    : pool_(nullptr), delegate_to_generated_factory_(false) {}
+
+DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
+    : pool_(pool), delegate_to_generated_factory_(false) {}
+
+DynamicMessageFactory::~DynamicMessageFactory() {
+  for (auto iter = prototypes_.begin(); iter != prototypes_.end(); ++iter) {
+    delete iter->second;
+  }
+}
+
+const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
+  MutexLock lock(&prototypes_mutex_);
+  return GetPrototypeNoLock(type);
+}
+
+const Message* DynamicMessageFactory::GetPrototypeNoLock(
+    const Descriptor* type) {
+  if (delegate_to_generated_factory_ &&
+      type->file()->pool() == DescriptorPool::generated_pool()) {
+    return MessageFactory::generated_factory()->GetPrototype(type);
+  }
+
+  const TypeInfo** target = &prototypes_[type];
+  if (*target != nullptr) {
+    // Already exists.
+    return (*target)->prototype;
+  }
+
+  TypeInfo* type_info = new TypeInfo;
+  *target = type_info;
+
+  type_info->type = type;
+  type_info->pool = (pool_ == nullptr) ? type->file()->pool() : pool_;
+  type_info->factory = this;
+
+  // We need to construct all the structures passed to Reflection's constructor.
+  // This includes:
+  // - A block of memory that contains space for all the message's fields.
+  // - An array of integers indicating the byte offset of each field within
+  //   this block.
+  // - A big bitfield containing a bit for each field indicating whether
+  //   or not that field is set.
+  int real_oneof_count = 0;
+  for (int i = 0; i < type->oneof_decl_count(); i++) {
+    if (!type->oneof_decl(i)->is_synthetic()) {
+      real_oneof_count++;
+    }
+  }
+
+  // Compute size and offsets.
+  uint32_t* offsets = new uint32_t[type->field_count() + real_oneof_count];
+  type_info->offsets.reset(offsets);
+
+  // Decide all field offsets by packing in order.
+  // We place the DynamicMessage object itself at the beginning of the allocated
+  // space.
+  int size = sizeof(DynamicMessage);
+  size = AlignOffset(size);
+
+  // Next the has_bits, which is an array of uint32s.
+  type_info->has_bits_offset = -1;
+  int max_hasbit = 0;
+  for (int i = 0; i < type->field_count(); i++) {
+    if (HasHasbit(type->field(i))) {
+      if (type_info->has_bits_offset == -1) {
+        // At least one field in the message requires a hasbit, so allocate
+        // hasbits.
+        type_info->has_bits_offset = size;
+        uint32_t* has_bits_indices = new uint32_t[type->field_count()];
+        for (int j = 0; j < type->field_count(); j++) {
+          // Initialize to -1, fields that need a hasbit will overwrite.
+          has_bits_indices[j] = static_cast<uint32_t>(-1);
+        }
+        type_info->has_bits_indices.reset(has_bits_indices);
+      }
+      type_info->has_bits_indices[i] = max_hasbit++;
+    }
+  }
+
+  if (max_hasbit > 0) {
+    int has_bits_array_size = DivideRoundingUp(max_hasbit, bitsizeof(uint32_t));
+    size += has_bits_array_size * sizeof(uint32_t);
+    size = AlignOffset(size);
+  }
+
+  // The oneof_case, if any. It is an array of uint32s.
+  if (real_oneof_count > 0) {
+    type_info->oneof_case_offset = size;
+    size += real_oneof_count * sizeof(uint32_t);
+    size = AlignOffset(size);
+  }
+
+  // The ExtensionSet, if any.
+  if (type->extension_range_count() > 0) {
+    type_info->extensions_offset = size;
+    size += sizeof(ExtensionSet);
+    size = AlignOffset(size);
+  } else {
+    // No extensions.
+    type_info->extensions_offset = -1;
+  }
+
+  // All the fields.
+  //
+  // TODO(b/31226269):  Optimize the order of fields to minimize padding.
+  for (int i = 0; i < type->field_count(); i++) {
+    // Make sure field is aligned to avoid bus errors.
+    // Oneof fields do not use any space.
+    if (!InRealOneof(type->field(i))) {
+      int field_size = FieldSpaceUsed(type->field(i));
+      size = AlignTo(size, std::min(kSafeAlignment, field_size));
+      offsets[i] = size;
+      size += field_size;
+    }
+  }
+
+  // The oneofs.
+  for (int i = 0; i < type->oneof_decl_count(); i++) {
+    if (!type->oneof_decl(i)->is_synthetic()) {
+      size = AlignTo(size, kSafeAlignment);
+      offsets[type->field_count() + i] = size;
+      size += kMaxOneofUnionSize;
+    }
+  }
+
+  type_info->weak_field_map_offset = -1;
+
+  // Align the final size to make sure no clever allocators think that
+  // alignment is not necessary.
+  type_info->size = size;
+
+  // Construct the reflection object.
+
+  // Compute the size of default oneof instance and offsets of default
+  // oneof fields.
+  for (int i = 0; i < type->oneof_decl_count(); i++) {
+    if (type->oneof_decl(i)->is_synthetic()) continue;
+    for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = type->oneof_decl(i)->field(j);
+      // oneof fields are not accessed through offsets, but we still have the
+      // entry from a legacy implementation. This should be removed at some
+      // point.
+      // Mark the field to prevent unintentional access through reflection.
+      // Don't use the top bit because that is for unused fields.
+      offsets[field->index()] = internal::kInvalidFieldOffsetTag;
+    }
+  }
+
+  // Allocate the prototype fields.
+  void* base = operator new(size);
+  memset(base, 0, size);
+
+  // We have already locked the factory so we should not lock in the constructor
+  // of dynamic message to avoid dead lock.
+  DynamicMessage* prototype = new (base) DynamicMessage(type_info, false);
+
+  internal::ReflectionSchema schema = {
+      type_info->prototype,
+      type_info->offsets.get(),
+      type_info->has_bits_indices.get(),
+      type_info->has_bits_offset,
+      PROTOBUF_FIELD_OFFSET(DynamicMessage, _internal_metadata_),
+      type_info->extensions_offset,
+      type_info->oneof_case_offset,
+      type_info->size,
+      type_info->weak_field_map_offset,
+      nullptr /* inlined_string_indices_ */,
+      0 /* inlined_string_donated_offset_ */};
+
+  type_info->reflection.reset(
+      new Reflection(type_info->type, schema, type_info->pool, this));
+
+  // Cross link prototypes.
+  prototype->CrossLinkPrototypes();
+
+  return prototype;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>  // NOLINT
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
new file mode 100644
index 0000000..6fa6425
--- /dev/null
+++ b/src/google/protobuf/dynamic_message.h
@@ -0,0 +1,227 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Defines an implementation of Message which can emulate types which are not
+// known at compile-time.
+
+#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
+#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
+
+
+#include <algorithm>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/repeated_field.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Defined in other files.
+class Descriptor;      // descriptor.h
+class DescriptorPool;  // descriptor.h
+
+// Constructs implementations of Message which can emulate types which are not
+// known at compile-time.
+//
+// Sometimes you want to be able to manipulate protocol types that you don't
+// know about at compile time.  It would be nice to be able to construct
+// a Message object which implements the message type given by any arbitrary
+// Descriptor.  DynamicMessage provides this.
+//
+// As it turns out, a DynamicMessage needs to construct extra
+// information about its type in order to operate.  Most of this information
+// can be shared between all DynamicMessages of the same type.  But, caching
+// this information in some sort of global map would be a bad idea, since
+// the cached information for a particular descriptor could outlive the
+// descriptor itself.  To avoid this problem, DynamicMessageFactory
+// encapsulates this "cache".  All DynamicMessages of the same type created
+// from the same factory will share the same support data.  Any Descriptors
+// used with a particular factory must outlive the factory.
+class PROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
+ public:
+  // Construct a DynamicMessageFactory that will search for extensions in
+  // the DescriptorPool in which the extendee is defined.
+  DynamicMessageFactory();
+
+  // Construct a DynamicMessageFactory that will search for extensions in
+  // the given DescriptorPool.
+  //
+  // DEPRECATED:  Use CodedInputStream::SetExtensionRegistry() to tell the
+  //   parser to look for extensions in an alternate pool.  However, note that
+  //   this is almost never what you want to do.  Almost all users should use
+  //   the zero-arg constructor.
+  DynamicMessageFactory(const DescriptorPool* pool);
+
+  ~DynamicMessageFactory() override;
+
+  // Call this to tell the DynamicMessageFactory that if it is given a
+  // Descriptor d for which:
+  //   d->file()->pool() == DescriptorPool::generated_pool(),
+  // then it should delegate to MessageFactory::generated_factory() instead
+  // of constructing a dynamic implementation of the message.  In theory there
+  // is no down side to doing this, so it may become the default in the future.
+  void SetDelegateToGeneratedFactory(bool enable) {
+    delegate_to_generated_factory_ = enable;
+  }
+
+  // implements MessageFactory ---------------------------------------
+
+  // Given a Descriptor, constructs the default (prototype) Message of that
+  // type.  You can then call that message's New() method to construct a
+  // mutable message of that type.
+  //
+  // Calling this method twice with the same Descriptor returns the same
+  // object.  The returned object remains property of the factory and will
+  // be destroyed when the factory is destroyed.  Also, any objects created
+  // by calling the prototype's New() method share some data with the
+  // prototype, so these must be destroyed before the DynamicMessageFactory
+  // is destroyed.
+  //
+  // The given descriptor must outlive the returned message, and hence must
+  // outlive the DynamicMessageFactory.
+  //
+  // The method is thread-safe.
+  const Message* GetPrototype(const Descriptor* type) override;
+
+ private:
+  const DescriptorPool* pool_;
+  bool delegate_to_generated_factory_;
+
+  struct TypeInfo;
+  std::unordered_map<const Descriptor*, const TypeInfo*> prototypes_;
+  mutable internal::WrappedMutex prototypes_mutex_;
+
+  friend class DynamicMessage;
+  const Message* GetPrototypeNoLock(const Descriptor* type);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
+};
+
+// Helper for computing a sorted list of map entries via reflection.
+class PROTOBUF_EXPORT DynamicMapSorter {
+ public:
+  static std::vector<const Message*> Sort(const Message& message, int map_size,
+                                          const Reflection* reflection,
+                                          const FieldDescriptor* field) {
+    std::vector<const Message*> result;
+    result.reserve(map_size);
+    RepeatedFieldRef<Message> map_field =
+        reflection->GetRepeatedFieldRef<Message>(message, field);
+    for (auto it = map_field.begin(); it != map_field.end(); ++it) {
+      result.push_back(&*it);
+    }
+    MapEntryMessageComparator comparator(field->message_type());
+    std::stable_sort(result.begin(), result.end(), comparator);
+    // Complain if the keys aren't in ascending order.
+#ifndef NDEBUG
+    for (size_t j = 1; j < static_cast<size_t>(map_size); j++) {
+      if (!comparator(result[j - 1], result[j])) {
+        GOOGLE_LOG(ERROR) << (comparator(result[j], result[j - 1])
+                           ? "internal error in map key sorting"
+                           : "map keys are not unique");
+      }
+    }
+#endif
+    return result;
+  }
+
+ private:
+  class PROTOBUF_EXPORT 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_t first = reflection->GetInt32(*a, field_);
+          int32_t second = reflection->GetInt32(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_INT64: {
+          int64_t first = reflection->GetInt64(*a, field_);
+          int64_t second = reflection->GetInt64(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_UINT32: {
+          uint32_t first = reflection->GetUInt32(*a, field_);
+          uint32_t second = reflection->GetUInt32(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_UINT64: {
+          uint64_t first = reflection->GetUInt64(*a, field_);
+          uint64_t second = reflection->GetUInt64(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_STRING: {
+          std::string first = reflection->GetString(*a, field_);
+          std::string second = reflection->GetString(*b, field_);
+          return first < second;
+        }
+        default:
+          GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+          return true;
+      }
+    }
+
+   private:
+    const FieldDescriptor* field_;
+  };
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
new file mode 100644
index 0000000..7ac2029
--- /dev/null
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Since the reflection interface for DynamicMessage is implemented by
+// GenericMessageReflection, the only thing we really have to test is
+// that DynamicMessage correctly sets up the information that
+// GenericMessageReflection needs to use.  So, we focus on that in this
+// test.  Other tests, such as generic_message_reflection_unittest and
+// reflection_ops_unittest, cover the rest of the functionality used by
+// DynamicMessage.
+
+#include <google/protobuf/dynamic_message.h>
+
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_no_field_presence.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/test_util.h>
+
+namespace google {
+namespace protobuf {
+
+class DynamicMessageTest : public ::testing::TestWithParam<bool> {
+ protected:
+  DescriptorPool pool_;
+  DynamicMessageFactory factory_;
+  const Descriptor* descriptor_;
+  const Message* prototype_;
+  const Descriptor* extensions_descriptor_;
+  const Message* extensions_prototype_;
+  const Descriptor* packed_descriptor_;
+  const Message* packed_prototype_;
+  const Descriptor* oneof_descriptor_;
+  const Message* oneof_prototype_;
+  const Descriptor* proto3_descriptor_;
+  const Message* proto3_prototype_;
+
+  DynamicMessageTest() : factory_(&pool_) {}
+
+  void SetUp() override {
+    // We want to make sure that DynamicMessage works (particularly with
+    // extensions) even if we use descriptors that are *not* from compiled-in
+    // types, so we make copies of the descriptors for unittest.proto and
+    // unittest_import.proto.
+    FileDescriptorProto unittest_file;
+    FileDescriptorProto unittest_import_file;
+    FileDescriptorProto unittest_import_public_file;
+    FileDescriptorProto unittest_no_field_presence_file;
+
+    unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
+    unittest_import::ImportMessage::descriptor()->file()->CopyTo(
+        &unittest_import_file);
+    unittest_import::PublicImportMessage::descriptor()->file()->CopyTo(
+        &unittest_import_public_file);
+    proto2_nofieldpresence_unittest::TestAllTypes::descriptor()->file()->CopyTo(
+        &unittest_no_field_presence_file);
+
+    ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != nullptr);
+    ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != nullptr);
+    ASSERT_TRUE(pool_.BuildFile(unittest_file) != nullptr);
+    ASSERT_TRUE(pool_.BuildFile(unittest_no_field_presence_file) != nullptr);
+
+    descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes");
+    ASSERT_TRUE(descriptor_ != nullptr);
+    prototype_ = factory_.GetPrototype(descriptor_);
+
+    extensions_descriptor_ =
+        pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions");
+    ASSERT_TRUE(extensions_descriptor_ != nullptr);
+    extensions_prototype_ = factory_.GetPrototype(extensions_descriptor_);
+
+    packed_descriptor_ =
+        pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes");
+    ASSERT_TRUE(packed_descriptor_ != nullptr);
+    packed_prototype_ = factory_.GetPrototype(packed_descriptor_);
+
+    oneof_descriptor_ =
+        pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2");
+    ASSERT_TRUE(oneof_descriptor_ != nullptr);
+    oneof_prototype_ = factory_.GetPrototype(oneof_descriptor_);
+
+    proto3_descriptor_ = pool_.FindMessageTypeByName(
+        "proto2_nofieldpresence_unittest.TestAllTypes");
+    ASSERT_TRUE(proto3_descriptor_ != nullptr);
+    proto3_prototype_ = factory_.GetPrototype(proto3_descriptor_);
+  }
+};
+
+TEST_F(DynamicMessageTest, Descriptor) {
+  // Check that the descriptor on the DynamicMessage matches the descriptor
+  // passed to GetPrototype().
+  EXPECT_EQ(prototype_->GetDescriptor(), descriptor_);
+}
+
+TEST_F(DynamicMessageTest, OnePrototype) {
+  // Check that requesting the same prototype twice produces the same object.
+  EXPECT_EQ(prototype_, factory_.GetPrototype(descriptor_));
+}
+
+TEST_F(DynamicMessageTest, Defaults) {
+  // Check that all default values are set correctly in the initial message.
+  TestUtil::ReflectionTester reflection_tester(descriptor_);
+  reflection_tester.ExpectClearViaReflection(*prototype_);
+}
+
+TEST_P(DynamicMessageTest, IndependentOffsets) {
+  // 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).
+  Arena arena;
+  Message* message = prototype_->New(GetParam() ? &arena : nullptr);
+  TestUtil::ReflectionTester reflection_tester(descriptor_);
+
+  reflection_tester.SetAllFieldsViaReflection(message);
+  reflection_tester.ExpectAllFieldsSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
+}
+
+TEST_P(DynamicMessageTest, Extensions) {
+  // Check that extensions work.
+  Arena arena;
+  Message* message = extensions_prototype_->New(GetParam() ? &arena : nullptr);
+  TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
+
+  reflection_tester.SetAllFieldsViaReflection(message);
+  reflection_tester.ExpectAllFieldsSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
+}
+
+TEST_P(DynamicMessageTest, PackedFields) {
+  // Check that packed fields work properly.
+  Arena arena;
+  Message* message = packed_prototype_->New(GetParam() ? &arena : nullptr);
+  TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
+
+  reflection_tester.SetPackedFieldsViaReflection(message);
+  reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
+}
+
+TEST_P(DynamicMessageTest, Oneof) {
+  // Check that oneof fields work properly.
+  Arena arena;
+  Message* message = oneof_prototype_->New(GetParam() ? &arena : nullptr);
+
+  // Check default values.
+  const Descriptor* descriptor = message->GetDescriptor();
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_EQ(0, reflection->GetInt32(*message,
+                                    descriptor->FindFieldByName("foo_int")));
+  EXPECT_EQ("", reflection->GetString(
+                    *message, descriptor->FindFieldByName("foo_string")));
+  EXPECT_EQ("", reflection->GetString(*message,
+                                      descriptor->FindFieldByName("foo_cord")));
+  EXPECT_EQ("", reflection->GetString(
+                    *message, descriptor->FindFieldByName("foo_string_piece")));
+  EXPECT_EQ("", reflection->GetString(
+                    *message, descriptor->FindFieldByName("foo_bytes")));
+  EXPECT_EQ(
+      unittest::TestOneof2::FOO,
+      reflection->GetEnum(*message, descriptor->FindFieldByName("foo_enum"))
+          ->number());
+  const Descriptor* nested_descriptor;
+  const Message* nested_prototype;
+  nested_descriptor =
+      pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2.NestedMessage");
+  nested_prototype = factory_.GetPrototype(nested_descriptor);
+  EXPECT_EQ(nested_prototype,
+            &reflection->GetMessage(
+                *message, descriptor->FindFieldByName("foo_message")));
+  const Descriptor* foogroup_descriptor;
+  const Message* foogroup_prototype;
+  foogroup_descriptor =
+      pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2.FooGroup");
+  foogroup_prototype = factory_.GetPrototype(foogroup_descriptor);
+  EXPECT_EQ(foogroup_prototype,
+            &reflection->GetMessage(*message,
+                                    descriptor->FindFieldByName("foogroup")));
+  EXPECT_NE(foogroup_prototype,
+            &reflection->GetMessage(
+                *message, descriptor->FindFieldByName("foo_lazy_message")));
+  EXPECT_EQ(5, reflection->GetInt32(*message,
+                                    descriptor->FindFieldByName("bar_int")));
+  EXPECT_EQ("STRING", reflection->GetString(
+                          *message, descriptor->FindFieldByName("bar_string")));
+  EXPECT_EQ("CORD", reflection->GetString(
+                        *message, descriptor->FindFieldByName("bar_cord")));
+  EXPECT_EQ("SPIECE",
+            reflection->GetString(
+                *message, descriptor->FindFieldByName("bar_string_piece")));
+  EXPECT_EQ("BYTES", reflection->GetString(
+                         *message, descriptor->FindFieldByName("bar_bytes")));
+  EXPECT_EQ(
+      unittest::TestOneof2::BAR,
+      reflection->GetEnum(*message, descriptor->FindFieldByName("bar_enum"))
+          ->number());
+
+  // Check set functions.
+  TestUtil::ReflectionTester reflection_tester(oneof_descriptor_);
+  reflection_tester.SetOneofViaReflection(message);
+  reflection_tester.ExpectOneofSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
+}
+
+TEST_P(DynamicMessageTest, SpaceUsed) {
+  // Test that SpaceUsedLong() works properly
+
+  // Since we share the implementation with generated messages, we don't need
+  // to test very much here.  Just make sure it appears to be working.
+
+  Arena arena;
+  Message* message = prototype_->New(GetParam() ? &arena : nullptr);
+  TestUtil::ReflectionTester reflection_tester(descriptor_);
+
+  size_t initial_space_used = message->SpaceUsedLong();
+
+  reflection_tester.SetAllFieldsViaReflection(message);
+  EXPECT_LT(initial_space_used, message->SpaceUsedLong());
+
+  if (!GetParam()) {
+    delete message;
+  }
+}
+
+TEST_F(DynamicMessageTest, Arena) {
+  Arena arena;
+  Message* message = prototype_->New(&arena);
+  Message* extension_message = extensions_prototype_->New(&arena);
+  Message* packed_message = packed_prototype_->New(&arena);
+  Message* oneof_message = oneof_prototype_->New(&arena);
+
+  // avoid unused-variable error.
+  (void)message;
+  (void)extension_message;
+  (void)packed_message;
+  (void)oneof_message;
+  // Return without freeing: should not leak.
+}
+
+
+TEST_F(DynamicMessageTest, Proto3) {
+  Message* message = proto3_prototype_->New();
+  const Reflection* refl = message->GetReflection();
+  const Descriptor* desc = message->GetDescriptor();
+
+  // Just test a single primitive and single message field here to make sure we
+  // are getting the no-field-presence semantics elsewhere. DynamicMessage uses
+  // GeneratedMessageReflection under the hood, so the rest should be fine as
+  // long as GMR recognizes that we're using a proto3 message.
+  const FieldDescriptor* optional_int32 =
+      desc->FindFieldByName("optional_int32");
+  const FieldDescriptor* optional_msg =
+      desc->FindFieldByName("optional_nested_message");
+  EXPECT_TRUE(optional_int32 != nullptr);
+  EXPECT_TRUE(optional_msg != nullptr);
+
+  EXPECT_EQ(false, refl->HasField(*message, optional_int32));
+  refl->SetInt32(message, optional_int32, 42);
+  EXPECT_EQ(true, refl->HasField(*message, optional_int32));
+  refl->SetInt32(message, optional_int32, 0);
+  EXPECT_EQ(false, refl->HasField(*message, optional_int32));
+
+  EXPECT_EQ(false, refl->HasField(*message, optional_msg));
+  refl->MutableMessage(message, optional_msg);
+  EXPECT_EQ(true, refl->HasField(*message, optional_msg));
+  delete refl->ReleaseMessage(message, optional_msg);
+  EXPECT_EQ(false, refl->HasField(*message, optional_msg));
+
+  // Also ensure that the default instance handles field presence properly.
+  EXPECT_EQ(false, refl->HasField(*proto3_prototype_, optional_msg));
+
+  delete message;
+}
+
+INSTANTIATE_TEST_SUITE_P(UseArena, DynamicMessageTest, ::testing::Bool());
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
new file mode 100644
index 0000000..3a30776
--- /dev/null
+++ b/src/google/protobuf/empty.pb.cc
@@ -0,0 +1,130 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#include <google/protobuf/empty.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Empty::Empty(
+    ::_pbi::ConstantInitialized) {}
+struct EmptyDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EmptyDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EmptyDefaultTypeInternal() {}
+  union {
+    Empty _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EmptyDefaultTypeInternal _Empty_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fempty_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Empty, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Empty)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Empty_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\033google/protobuf/empty.proto\022\017google.pr"
+  "otobuf\"\007\n\005EmptyB}\n\023com.google.protobufB\n"
+  "EmptyProtoP\001Z.google.golang.org/protobuf"
+  "/types/known/emptypb\370\001\001\242\002\003GPB\252\002\036Google.P"
+  "rotobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fempty_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
+    false, false, 190, descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto,
+    "google/protobuf/empty.proto",
+    &descriptor_table_google_2fprotobuf_2fempty_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fempty_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fempty_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fempty_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fempty_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fempty_2eproto(&descriptor_table_google_2fprotobuf_2fempty_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Empty::_Internal {
+ public:
+};
+
+Empty::Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase(arena, is_message_owned) {
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
+}
+Empty::Empty(const Empty& from)
+  : ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase() {
+  Empty* const _this = this; (void)_this;
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Empty)
+}
+
+
+
+
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Empty::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyImpl,
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeImpl,
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Empty::GetClassData() const { return &_class_data_; }
+
+
+
+
+
+
+
+::PROTOBUF_NAMESPACE_ID::Metadata Empty::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fempty_2eproto_getter, &descriptor_table_google_2fprotobuf_2fempty_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fempty_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Empty*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Empty >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Empty >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
new file mode 100644
index 0000000..329e819
--- /dev/null
+++ b/src/google/protobuf/empty.pb.h
@@ -0,0 +1,198 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fempty_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fempty_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_bases.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fempty_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fempty_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Empty;
+struct EmptyDefaultTypeInternal;
+PROTOBUF_EXPORT extern EmptyDefaultTypeInternal _Empty_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Empty* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Empty>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Empty final :
+    public ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
+ public:
+  inline Empty() : Empty(nullptr) {}
+  explicit PROTOBUF_CONSTEXPR Empty(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Empty(const Empty& from);
+  Empty(Empty&& from) noexcept
+    : Empty() {
+    *this = ::std::move(from);
+  }
+
+  inline Empty& operator=(const Empty& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Empty& operator=(Empty&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Empty& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Empty* internal_default_instance() {
+    return reinterpret_cast<const Empty*>(
+               &_Empty_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Empty& a, Empty& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Empty* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Empty* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Empty* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Empty>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyFrom;
+  inline void CopyFrom(const Empty& from) {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyImpl(*this, from);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeFrom;
+  void MergeFrom(const Empty& from) {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeImpl(*this, from);
+  }
+  public:
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Empty";
+  }
+  protected:
+  explicit Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Empty)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+  };
+  friend struct ::TableStruct_google_2fprotobuf_2fempty_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Empty
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fempty_2eproto
diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto
new file mode 100644
index 0000000..2227462
--- /dev/null
+++ b/src/google/protobuf/empty.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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "google.golang.org/protobuf/types/known/emptypb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = 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);
+//     }
+//
+message Empty {}
diff --git a/src/google/protobuf/endian.h b/src/google/protobuf/endian.h
new file mode 100644
index 0000000..e0ee6cd
--- /dev/null
+++ b/src/google/protobuf/endian.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_ENDIAN_H__
+#define GOOGLE_PROTOBUF_ENDIAN_H__
+
+#if defined(_MSC_VER)
+#include <stdlib.h>
+#endif
+
+#include <cstdint>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline uint64_t BSwap64(uint64_t host_int) {
+#if defined(PROTOBUF_BUILTIN_BSWAP64)
+  return PROTOBUF_BUILTIN_BSWAP64(host_int);
+#elif defined(_MSC_VER)
+  return _byteswap_uint64(host_int);
+#else
+  return (((host_int & uint64_t{0xFF}) << 56) |
+          ((host_int & uint64_t{0xFF00}) << 40) |
+          ((host_int & uint64_t{0xFF0000}) << 24) |
+          ((host_int & uint64_t{0xFF000000}) << 8) |
+          ((host_int & uint64_t{0xFF00000000}) >> 8) |
+          ((host_int & uint64_t{0xFF0000000000}) >> 24) |
+          ((host_int & uint64_t{0xFF000000000000}) >> 40) |
+          ((host_int & uint64_t{0xFF00000000000000}) >> 56));
+#endif
+}
+
+inline uint32_t BSwap32(uint32_t host_int) {
+#if defined(PROTOBUF_BUILTIN_BSWAP32)
+  return PROTOBUF_BUILTIN_BSWAP32(host_int);
+#elif defined(_MSC_VER)
+  return _byteswap_ulong(host_int);
+#else
+  return (((host_int & uint32_t{0xFF}) << 24) |
+          ((host_int & uint32_t{0xFF00}) << 8) |
+          ((host_int & uint32_t{0xFF0000}) >> 8) |
+          ((host_int & uint32_t{0xFF000000}) >> 24));
+#endif
+}
+
+inline uint16_t BSwap16(uint16_t host_int) {
+#if defined(PROTOBUF_BUILTIN_BSWAP16)
+  return PROTOBUF_BUILTIN_BSWAP16(host_int);
+#elif defined(_MSC_VER)
+  return _byteswap_ushort(host_int);
+#else
+  return (((host_int & uint16_t{0xFF}) << 8) |
+          ((host_int & uint16_t{0xFF00}) >> 8));
+#endif
+}
+
+namespace little_endian {
+
+inline uint16_t FromHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap16(value);
+#else
+  return value;
+#endif
+}
+
+inline uint32_t FromHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap32(value);
+#else
+  return value;
+#endif
+}
+
+inline uint64_t FromHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap64(value);
+#else
+  return value;
+#endif
+}
+
+inline uint16_t ToHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap16(value);
+#else
+  return value;
+#endif
+}
+
+inline uint32_t ToHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap32(value);
+#else
+  return value;
+#endif
+}
+
+inline uint64_t ToHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap64(value);
+#else
+  return value;
+#endif
+}
+
+}  // namespace little_endian
+
+namespace big_endian {
+
+inline uint16_t FromHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap16(value);
+#endif
+}
+
+inline uint32_t FromHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap32(value);
+#endif
+}
+
+inline uint64_t FromHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap64(value);
+#endif
+}
+
+inline uint16_t ToHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap16(value);
+#endif
+}
+
+inline uint32_t ToHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap32(value);
+#endif
+}
+
+inline uint64_t ToHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap64(value);
+#endif
+}
+
+}  // namespace big_endian
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ENDIAN_H__
diff --git a/src/google/protobuf/explicitly_constructed.h b/src/google/protobuf/explicitly_constructed.h
new file mode 100644
index 0000000..174c59a
--- /dev/null
+++ b/src/google/protobuf/explicitly_constructed.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_EXPLICITLY_CONSTRUCTED_H__
+#define GOOGLE_PROTOBUF_EXPLICITLY_CONSTRUCTED_H__
+
+#include <stdint.h>
+
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Wraps a variable whose constructor and destructor are explicitly
+// called. It is particularly useful for a global variable, without its
+// constructor and destructor run on start and end of the program lifetime.
+// This circumvents the initial construction order fiasco, while keeping
+// the address of the empty string a compile time constant.
+//
+// Pay special attention to the initialization state of the object.
+// 1. The object is "uninitialized" to begin with.
+// 2. Call Construct() or DefaultConstruct() only if the object is
+//    uninitialized. After the call, the object becomes "initialized".
+// 3. Call get() and get_mutable() only if the object is initialized.
+// 4. Call Destruct() only if the object is initialized.
+//    After the call, the object becomes uninitialized.
+template <typename T, size_t min_align = 1>
+class ExplicitlyConstructed {
+ public:
+  void DefaultConstruct() { new (&union_) T(); }
+
+  template <typename... Args>
+  void Construct(Args&&... args) {
+    new (&union_) T(std::forward<Args>(args)...);
+  }
+
+  void Destruct() { get_mutable()->~T(); }
+
+  constexpr const T& get() const { return reinterpret_cast<const T&>(union_); }
+  T* get_mutable() { return reinterpret_cast<T*>(&union_); }
+
+ private:
+  union AlignedUnion {
+    alignas(min_align > alignof(T) ? min_align
+                                   : alignof(T)) char space[sizeof(T)];
+    int64_t align_to_int64;
+    void* align_to_ptr;
+  } union_;
+};
+
+// ArenaStringPtr compatible explicitly constructed string type.
+// This empty string type is aligned with a minimum alignment of 8 bytes
+// which is the minimum requirement of ArenaStringPtr
+using ExplicitlyConstructedArenaString = ExplicitlyConstructed<std::string, 8>;
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_EXPLICITLY_CONSTRUCTED_H__
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
new file mode 100644
index 0000000..fada4f5
--- /dev/null
+++ b/src/google/protobuf/extension_set.cc
@@ -0,0 +1,1967 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/extension_set.h>
+
+#include <tuple>
+#include <unordered_set>
+#include <utility>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>  // must be last.
+// clang-format on
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+inline WireFormatLite::FieldType real_type(FieldType type) {
+  GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
+  return static_cast<WireFormatLite::FieldType>(type);
+}
+
+inline WireFormatLite::CppType cpp_type(FieldType type) {
+  return WireFormatLite::FieldTypeToCppType(real_type(type));
+}
+
+// Registry stuff.
+
+// Note that we cannot use hetererogeneous lookup for std containers since we
+// need to support C++11.
+struct ExtensionEq {
+  bool operator()(const ExtensionInfo& lhs, const ExtensionInfo& rhs) const {
+    return lhs.message == rhs.message && lhs.number == rhs.number;
+  }
+};
+
+struct ExtensionHasher {
+  std::size_t operator()(const ExtensionInfo& info) const {
+    return std::hash<const MessageLite*>{}(info.message) ^
+           std::hash<int>{}(info.number);
+  }
+};
+
+using ExtensionRegistry =
+    std::unordered_set<ExtensionInfo, ExtensionHasher, ExtensionEq>;
+
+static const ExtensionRegistry* global_registry = nullptr;
+
+// This function is only called at startup, so there is no need for thread-
+// safety.
+void Register(const ExtensionInfo& info) {
+  static auto local_static_registry = OnShutdownDelete(new ExtensionRegistry);
+  global_registry = local_static_registry;
+  if (!InsertIfNotPresent(local_static_registry, info)) {
+    GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
+               << info.message->GetTypeName() << "\", field number "
+               << info.number << ".";
+  }
+}
+
+const ExtensionInfo* FindRegisteredExtension(const MessageLite* extendee,
+                                             int number) {
+  if (!global_registry) return nullptr;
+
+  ExtensionInfo info;
+  info.message = extendee;
+  info.number = number;
+
+  auto it = global_registry->find(info);
+  if (it == global_registry->end()) {
+    return nullptr;
+  } else {
+    return &*it;
+  }
+}
+
+}  // namespace
+
+bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) {
+  const ExtensionInfo* extension = FindRegisteredExtension(extendee_, number);
+  if (extension == nullptr) {
+    return false;
+  } else {
+    *output = *extension;
+    return true;
+  }
+}
+
+void ExtensionSet::RegisterExtension(const MessageLite* extendee, int number,
+                                     FieldType type, bool is_repeated,
+                                     bool is_packed,
+                                     LazyEagerVerifyFnType verify_func) {
+  GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_ENUM);
+  GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_MESSAGE);
+  GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_GROUP);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed,
+                     verify_func);
+  Register(info);
+}
+
+static bool CallNoArgValidityFunc(const void* arg, int number) {
+  // Note:  Must use C-style cast here rather than reinterpret_cast because
+  //   the C++ standard at one point did not allow casts between function and
+  //   data pointers and some compilers enforce this for C++-style casts.  No
+  //   compiler enforces it for C-style casts since lots of C-style code has
+  //   relied on these kinds of casts for a long time, despite being
+  //   technically undefined.  See:
+  //     http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195
+  // Also note:  Some compilers do not allow function pointers to be "const".
+  //   Which makes sense, I suppose, because it's meaningless.
+  return ((EnumValidityFunc*)arg)(number);
+}
+
+void ExtensionSet::RegisterEnumExtension(const MessageLite* extendee,
+                                         int number, FieldType type,
+                                         bool is_repeated, bool is_packed,
+                                         EnumValidityFunc* is_valid) {
+  GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed, nullptr);
+  info.enum_validity_check.func = CallNoArgValidityFunc;
+  // See comment in CallNoArgValidityFunc() about why we use a c-style cast.
+  info.enum_validity_check.arg = (void*)is_valid;
+  Register(info);
+}
+
+void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
+                                            int number, FieldType type,
+                                            bool is_repeated, bool is_packed,
+                                            const MessageLite* prototype,
+                                            LazyEagerVerifyFnType verify_func) {
+  GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
+        type == WireFormatLite::TYPE_GROUP);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed,
+                     verify_func);
+  info.message_info = {prototype};
+  Register(info);
+}
+
+// ===================================================================
+// Constructors and basic methods.
+
+ExtensionSet::ExtensionSet(Arena* arena)
+    : arena_(arena),
+      flat_capacity_(0),
+      flat_size_(0),
+      map_{flat_capacity_ == 0
+               ? nullptr
+               : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {}
+
+ExtensionSet::~ExtensionSet() {
+  // Deletes all allocated extensions.
+  if (arena_ == nullptr) {
+    ForEach([](int /* number */, Extension& ext) { ext.Free(); });
+    if (PROTOBUF_PREDICT_FALSE(is_large())) {
+      delete map_.large;
+    } else {
+      DeleteFlatMap(map_.flat, flat_capacity_);
+    }
+  }
+}
+
+void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat,
+                                 uint16_t flat_capacity) {
+  // Arena::CreateArray already requires a trivially destructible type, but
+  // ensure this constraint is not violated in the future.
+  static_assert(std::is_trivially_destructible<KeyValue>::value,
+                "CreateArray requires a trivially destructible type");
+  // A const-cast is needed, but this is safe as we are about to deallocate the
+  // array.
+  internal::SizedArrayDelete(const_cast<KeyValue*>(flat),
+                             sizeof(*flat) * flat_capacity);
+}
+
+// Defined in extension_set_heavy.cc.
+// void ExtensionSet::AppendToList(const Descriptor* extendee,
+//                                 const DescriptorPool* pool,
+//                                 vector<const FieldDescriptor*>* output) const
+
+bool ExtensionSet::Has(int number) const {
+  const Extension* ext = FindOrNull(number);
+  if (ext == nullptr) return false;
+  GOOGLE_DCHECK(!ext->is_repeated);
+  return !ext->is_cleared;
+}
+
+bool ExtensionSet::HasLazy(int number) const {
+  return Has(number) && FindOrNull(number)->is_lazy;
+}
+
+int ExtensionSet::NumExtensions() const {
+  int result = 0;
+  ForEach([&result](int /* number */, const Extension& ext) {
+    if (!ext.is_cleared) {
+      ++result;
+    }
+  });
+  return result;
+}
+
+int ExtensionSet::ExtensionSize(int number) const {
+  const Extension* ext = FindOrNull(number);
+  return ext == nullptr ? 0 : ext->GetSize();
+}
+
+FieldType ExtensionSet::ExtensionType(int number) const {
+  const Extension* ext = FindOrNull(number);
+  if (ext == nullptr) {
+    GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (1). ";
+    return 0;
+  }
+  if (ext->is_cleared) {
+    GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (2). ";
+  }
+  return ext->type;
+}
+
+void ExtensionSet::ClearExtension(int number) {
+  Extension* ext = FindOrNull(number);
+  if (ext == nullptr) return;
+  ext->Clear();
+}
+
+// ===================================================================
+// Field accessors
+
+namespace {
+
+enum { REPEATED_FIELD, OPTIONAL_FIELD };
+
+}  // namespace
+
+#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                                 \
+  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? REPEATED_FIELD : OPTIONAL_FIELD, LABEL); \
+  GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), WireFormatLite::CPPTYPE_##CPPTYPE)
+
+// -------------------------------------------------------------------
+// Primitives
+
+#define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE)                  \
+                                                                              \
+  LOWERCASE ExtensionSet::Get##CAMELCASE(int number, LOWERCASE default_value) \
+      const {                                                                 \
+    const Extension* extension = FindOrNull(number);                          \
+    if (extension == nullptr || extension->is_cleared) {                      \
+      return default_value;                                                   \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+      return extension->LOWERCASE##_value;                                    \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
+  const LOWERCASE& ExtensionSet::GetRef##CAMELCASE(                           \
+      int number, const LOWERCASE& default_value) const {                     \
+    const Extension* extension = FindOrNull(number);                          \
+    if (extension == nullptr || extension->is_cleared) {                      \
+      return default_value;                                                   \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+      return extension->LOWERCASE##_value;                                    \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
+  void ExtensionSet::Set##CAMELCASE(int number, FieldType type,               \
+                                    LOWERCASE value,                          \
+                                    const FieldDescriptor* descriptor) {      \
+    Extension* extension;                                                     \
+    if (MaybeNewExtension(number, descriptor, &extension)) {                  \
+      extension->type = type;                                                 \
+      GOOGLE_DCHECK_EQ(cpp_type(extension->type),                                    \
+                WireFormatLite::CPPTYPE_##UPPERCASE);                         \
+      extension->is_repeated = false;                                         \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+    }                                                                         \
+    extension->is_cleared = false;                                            \
+    extension->LOWERCASE##_value = value;                                     \
+  }                                                                           \
+                                                                              \
+  LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index)       \
+      const {                                                                 \
+    const Extension* extension = FindOrNull(number);                          \
+    GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";   \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    return extension->repeated_##LOWERCASE##_value->Get(index);               \
+  }                                                                           \
+                                                                              \
+  const LOWERCASE& ExtensionSet::GetRefRepeated##CAMELCASE(int number,        \
+                                                           int index) const { \
+    const Extension* extension = FindOrNull(number);                          \
+    GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";   \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    return extension->repeated_##LOWERCASE##_value->Get(index);               \
+  }                                                                           \
+                                                                              \
+  void ExtensionSet::SetRepeated##CAMELCASE(int number, int index,            \
+                                            LOWERCASE value) {                \
+    Extension* extension = FindOrNull(number);                                \
+    GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";   \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    extension->repeated_##LOWERCASE##_value->Set(index, value);               \
+  }                                                                           \
+                                                                              \
+  void ExtensionSet::Add##CAMELCASE(int number, FieldType type, bool packed,  \
+                                    LOWERCASE value,                          \
+                                    const FieldDescriptor* descriptor) {      \
+    Extension* extension;                                                     \
+    if (MaybeNewExtension(number, descriptor, &extension)) {                  \
+      extension->type = type;                                                 \
+      GOOGLE_DCHECK_EQ(cpp_type(extension->type),                                    \
+                WireFormatLite::CPPTYPE_##UPPERCASE);                         \
+      extension->is_repeated = true;                                          \
+      extension->is_packed = packed;                                          \
+      extension->repeated_##LOWERCASE##_value =                               \
+          Arena::CreateMessage<RepeatedField<LOWERCASE>>(arena_);             \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                     \
+      GOOGLE_DCHECK_EQ(extension->is_packed, packed);                                \
+    }                                                                         \
+    extension->repeated_##LOWERCASE##_value->Add(value);                      \
+  }
+
+PRIMITIVE_ACCESSORS(INT32, int32_t, Int32)
+PRIMITIVE_ACCESSORS(INT64, int64_t, Int64)
+PRIMITIVE_ACCESSORS(UINT32, uint32_t, UInt32)
+PRIMITIVE_ACCESSORS(UINT64, uint64_t, UInt64)
+PRIMITIVE_ACCESSORS(FLOAT, float, Float)
+PRIMITIVE_ACCESSORS(DOUBLE, double, Double)
+PRIMITIVE_ACCESSORS(BOOL, bool, Bool)
+
+#undef PRIMITIVE_ACCESSORS
+
+const void* ExtensionSet::GetRawRepeatedField(int number,
+                                              const void* default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    return default_value;
+  }
+  // We assume that all the RepeatedField<>* pointers have the same
+  // size and alignment within the anonymous union in Extension.
+  return extension->repeated_int32_t_value;
+}
+
+void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
+                                            bool packed,
+                                            const FieldDescriptor* desc) {
+  Extension* extension;
+
+  // We instantiate an empty Repeated{,Ptr}Field if one doesn't exist for this
+  // extension.
+  if (MaybeNewExtension(number, desc, &extension)) {
+    extension->is_repeated = true;
+    extension->type = field_type;
+    extension->is_packed = packed;
+
+    switch (WireFormatLite::FieldTypeToCppType(
+        static_cast<WireFormatLite::FieldType>(field_type))) {
+      case WireFormatLite::CPPTYPE_INT32:
+        extension->repeated_int32_t_value =
+            Arena::CreateMessage<RepeatedField<int32_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_INT64:
+        extension->repeated_int64_t_value =
+            Arena::CreateMessage<RepeatedField<int64_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_UINT32:
+        extension->repeated_uint32_t_value =
+            Arena::CreateMessage<RepeatedField<uint32_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_UINT64:
+        extension->repeated_uint64_t_value =
+            Arena::CreateMessage<RepeatedField<uint64_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_DOUBLE:
+        extension->repeated_double_value =
+            Arena::CreateMessage<RepeatedField<double>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_FLOAT:
+        extension->repeated_float_value =
+            Arena::CreateMessage<RepeatedField<float>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_BOOL:
+        extension->repeated_bool_value =
+            Arena::CreateMessage<RepeatedField<bool>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_ENUM:
+        extension->repeated_enum_value =
+            Arena::CreateMessage<RepeatedField<int>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_STRING:
+        extension->repeated_string_value =
+            Arena::CreateMessage<RepeatedPtrField<std::string>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        extension->repeated_message_value =
+            Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_);
+        break;
+    }
+  }
+
+  // We assume that all the RepeatedField<>* pointers have the same
+  // size and alignment within the anonymous union in Extension.
+  return extension->repeated_int32_t_value;
+}
+
+// Compatible version using old call signature. Does not create extensions when
+// the don't already exist; instead, just GOOGLE_CHECK-fails.
+void* ExtensionSet::MutableRawRepeatedField(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Extension not found.";
+  // We assume that all the RepeatedField<>* pointers have the same
+  // size and alignment within the anonymous union in Extension.
+  return extension->repeated_int32_t_value;
+}
+
+// -------------------------------------------------------------------
+// Enums
+
+int ExtensionSet::GetEnum(int number, int default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+    return extension->enum_value;
+  }
+}
+
+const int& ExtensionSet::GetRefEnum(int number,
+                                    const int& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+    return extension->enum_value;
+  }
+}
+
+void ExtensionSet::SetEnum(int number, FieldType type, int value,
+                           const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
+    extension->is_repeated = false;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+  }
+  extension->is_cleared = false;
+  extension->enum_value = value;
+}
+
+int ExtensionSet::GetRepeatedEnum(int number, int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  return extension->repeated_enum_value->Get(index);
+}
+
+const int& ExtensionSet::GetRefRepeatedEnum(int number, int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  return extension->repeated_enum_value->Get(index);
+}
+
+void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  extension->repeated_enum_value->Set(index, value);
+}
+
+void ExtensionSet::AddEnum(int number, FieldType type, bool packed, int value,
+                           const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
+    extension->is_repeated = true;
+    extension->is_packed = packed;
+    extension->repeated_enum_value =
+        Arena::CreateMessage<RepeatedField<int>>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+    GOOGLE_DCHECK_EQ(extension->is_packed, packed);
+  }
+  extension->repeated_enum_value->Add(value);
+}
+
+// -------------------------------------------------------------------
+// Strings
+
+const std::string& ExtensionSet::GetString(
+    int number, const std::string& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
+    return *extension->string_value;
+  }
+}
+
+std::string* ExtensionSet::MutableString(int number, FieldType type,
+                                         const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
+    extension->is_repeated = false;
+    extension->string_value = Arena::Create<std::string>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
+  }
+  extension->is_cleared = false;
+  return extension->string_value;
+}
+
+const std::string& ExtensionSet::GetRepeatedString(int number,
+                                                   int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
+  return extension->repeated_string_value->Get(index);
+}
+
+std::string* ExtensionSet::MutableRepeatedString(int number, int index) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
+  return extension->repeated_string_value->Mutable(index);
+}
+
+std::string* ExtensionSet::AddString(int number, FieldType type,
+                                     const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
+    extension->is_repeated = true;
+    extension->is_packed = false;
+    extension->repeated_string_value =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
+  }
+  return extension->repeated_string_value->Add();
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+const MessageLite& ExtensionSet::GetMessage(
+    int number, const MessageLite& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->GetMessage(default_value, arena_);
+    } else {
+      return *extension->message_value;
+    }
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// const MessageLite& ExtensionSet::GetMessage(int number,
+//                                             const Descriptor* message_type,
+//                                             MessageFactory* factory) const
+
+MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
+                                          const MessageLite& prototype,
+                                          const FieldDescriptor* descriptor) {
+  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 = prototype.New(arena_);
+    extension->is_cleared = false;
+    return extension->message_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    extension->is_cleared = false;
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->MutableMessage(prototype, arena_);
+    } else {
+      return extension->message_value;
+    }
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
+//                                           const Descriptor* message_type,
+//                                           MessageFactory* factory)
+
+void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
+                                       const FieldDescriptor* descriptor,
+                                       MessageLite* message) {
+  if (message == nullptr) {
+    ClearExtension(number);
+    return;
+  }
+  GOOGLE_DCHECK(message->GetOwningArena() == nullptr ||
+         message->GetOwningArena() == arena_);
+  Arena* message_arena = message->GetOwningArena();
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    if (message_arena == arena_) {
+      extension->message_value = message;
+    } else if (message_arena == nullptr) {
+      extension->message_value = message;
+      arena_->Own(message);  // not nullptr because not equal to message_arena
+    } else {
+      extension->message_value = message->New(arena_);
+      extension->message_value->CheckTypeAndMergeFrom(*message);
+    }
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->SetAllocatedMessage(message, arena_);
+    } else {
+      if (arena_ == nullptr) {
+        delete extension->message_value;
+      }
+      if (message_arena == arena_) {
+        extension->message_value = message;
+      } else if (message_arena == nullptr) {
+        extension->message_value = message;
+        arena_->Own(message);  // not nullptr because not equal to message_arena
+      } else {
+        extension->message_value = message->New(arena_);
+        extension->message_value->CheckTypeAndMergeFrom(*message);
+      }
+    }
+  }
+  extension->is_cleared = false;
+}
+
+void ExtensionSet::UnsafeArenaSetAllocatedMessage(
+    int number, FieldType type, const FieldDescriptor* descriptor,
+    MessageLite* message) {
+  if (message == nullptr) {
+    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_FIELD, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message,
+                                                                   arena_);
+    } else {
+      if (arena_ == nullptr) {
+        delete extension->message_value;
+      }
+      extension->message_value = message;
+    }
+  }
+  extension->is_cleared = false;
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(int number,
+                                          const MessageLite& prototype) {
+  Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->ReleaseMessage(prototype, arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      if (arena_ == nullptr) {
+        ret = extension->message_value;
+      } else {
+        // ReleaseMessage() always returns a heap-allocated message, and we are
+        // on an arena, so we need to make a copy of this message to return.
+        ret = extension->message_value->New();
+        ret->CheckTypeAndMergeFrom(*extension->message_value);
+      }
+    }
+    Erase(number);
+    return ret;
+  }
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+    int number, const MessageLite& prototype) {
+  Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(prototype,
+                                                                    arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      ret = extension->message_value;
+    }
+    Erase(number);
+    return ret;
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+//                                           MessageFactory* factory);
+
+const MessageLite& ExtensionSet::GetRepeatedMessage(int number,
+                                                    int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
+  return extension->repeated_message_value->Get(index);
+}
+
+MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
+  return extension->repeated_message_value->Mutable(index);
+}
+
+MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
+                                      const MessageLite& prototype,
+                                      const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = true;
+    extension->repeated_message_value =
+        Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
+  }
+
+  // RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
+  // allocate an abstract object, so we have to be tricky.
+  MessageLite* result = reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+                            extension->repeated_message_value)
+                            ->AddFromCleared<GenericTypeHandler<MessageLite>>();
+  if (result == nullptr) {
+    result = prototype.New(arena_);
+    extension->repeated_message_value->AddAllocated(result);
+  }
+  return result;
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
+//                                       const Descriptor* message_type,
+//                                       MessageFactory* factory)
+
+#undef GOOGLE_DCHECK_TYPE
+
+void ExtensionSet::RemoveLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+
+  switch (cpp_type(extension->type)) {
+    case WireFormatLite::CPPTYPE_INT32:
+      extension->repeated_int32_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_INT64:
+      extension->repeated_int64_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_UINT32:
+      extension->repeated_uint32_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_UINT64:
+      extension->repeated_uint64_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_FLOAT:
+      extension->repeated_float_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_DOUBLE:
+      extension->repeated_double_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_BOOL:
+      extension->repeated_bool_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_ENUM:
+      extension->repeated_enum_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_STRING:
+      extension->repeated_string_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_MESSAGE:
+      extension->repeated_message_value->RemoveLast();
+      break;
+  }
+}
+
+MessageLite* ExtensionSet::ReleaseLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+  GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+  return extension->repeated_message_value->ReleaseLast();
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+  GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+  return extension->repeated_message_value->UnsafeArenaReleaseLast();
+}
+
+void ExtensionSet::SwapElements(int number, int index1, int index2) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+
+  switch (cpp_type(extension->type)) {
+    case WireFormatLite::CPPTYPE_INT32:
+      extension->repeated_int32_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_INT64:
+      extension->repeated_int64_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_UINT32:
+      extension->repeated_uint32_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_UINT64:
+      extension->repeated_uint64_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_FLOAT:
+      extension->repeated_float_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_DOUBLE:
+      extension->repeated_double_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_BOOL:
+      extension->repeated_bool_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_ENUM:
+      extension->repeated_enum_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_STRING:
+      extension->repeated_string_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_MESSAGE:
+      extension->repeated_message_value->SwapElements(index1, index2);
+      break;
+  }
+}
+
+// ===================================================================
+
+void ExtensionSet::Clear() {
+  ForEach([](int /* number */, Extension& ext) { ext.Clear(); });
+}
+
+namespace {
+// Computes the size of an ExtensionSet union without actually constructing the
+// union. Note that we do not count cleared extensions from the source to be
+// part of the total, because there is no need to allocate space for those. We
+// do include cleared extensions in the destination, though, because those are
+// already allocated and will not be going away.
+template <typename ItX, typename ItY>
+size_t SizeOfUnion(ItX it_dest, ItX end_dest, ItY it_source, ItY end_source) {
+  size_t result = 0;
+  while (it_dest != end_dest && it_source != end_source) {
+    if (it_dest->first < it_source->first) {
+      ++result;
+      ++it_dest;
+    } else if (it_dest->first == it_source->first) {
+      ++result;
+      ++it_dest;
+      ++it_source;
+    } else {
+      if (!it_source->second.is_cleared) {
+        ++result;
+      }
+      ++it_source;
+    }
+  }
+  result += std::distance(it_dest, end_dest);
+  for (; it_source != end_source; ++it_source) {
+    if (!it_source->second.is_cleared) {
+      ++result;
+    }
+  }
+  return result;
+}
+}  // namespace
+
+void ExtensionSet::MergeFrom(const MessageLite* extendee,
+                             const ExtensionSet& other) {
+  if (PROTOBUF_PREDICT_TRUE(!is_large())) {
+    if (PROTOBUF_PREDICT_TRUE(!other.is_large())) {
+      GrowCapacity(SizeOfUnion(flat_begin(), flat_end(), other.flat_begin(),
+                               other.flat_end()));
+    } else {
+      GrowCapacity(SizeOfUnion(flat_begin(), flat_end(),
+                               other.map_.large->begin(),
+                               other.map_.large->end()));
+    }
+  }
+  other.ForEach([extendee, this, &other](int number, const Extension& ext) {
+    this->InternalExtensionMergeFrom(extendee, number, ext, other.arena_);
+  });
+}
+
+void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee,
+                                              int number,
+                                              const Extension& other_extension,
+                                              Arena* other_arena) {
+  if (other_extension.is_repeated) {
+    Extension* extension;
+    bool is_new =
+        MaybeNewExtension(number, other_extension.descriptor, &extension);
+    if (is_new) {
+      // Extension did not already exist in set.
+      extension->type = other_extension.type;
+      extension->is_packed = other_extension.is_packed;
+      extension->is_repeated = true;
+    } else {
+      GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+      GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
+      GOOGLE_DCHECK(extension->is_repeated);
+    }
+
+    switch (cpp_type(other_extension.type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \
+  case WireFormatLite::CPPTYPE_##UPPERCASE:              \
+    if (is_new) {                                        \
+      extension->repeated_##LOWERCASE##_value =          \
+          Arena::CreateMessage<REPEATED_TYPE>(arena_);   \
+    }                                                    \
+    extension->repeated_##LOWERCASE##_value->MergeFrom(  \
+        *other_extension.repeated_##LOWERCASE##_value);  \
+    break;
+
+      HANDLE_TYPE(INT32, int32_t, RepeatedField<int32_t>);
+      HANDLE_TYPE(INT64, int64_t, RepeatedField<int64_t>);
+      HANDLE_TYPE(UINT32, uint32_t, RepeatedField<uint32_t>);
+      HANDLE_TYPE(UINT64, uint64_t, RepeatedField<uint64_t>);
+      HANDLE_TYPE(FLOAT, float, RepeatedField<float>);
+      HANDLE_TYPE(DOUBLE, double, RepeatedField<double>);
+      HANDLE_TYPE(BOOL, bool, RepeatedField<bool>);
+      HANDLE_TYPE(ENUM, enum, RepeatedField<int>);
+      HANDLE_TYPE(STRING, string, RepeatedPtrField<std::string>);
+#undef HANDLE_TYPE
+
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        if (is_new) {
+          extension->repeated_message_value =
+              Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_);
+        }
+        // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
+        // it would attempt to allocate new objects.
+        RepeatedPtrField<MessageLite>* other_repeated_message =
+            other_extension.repeated_message_value;
+        for (int i = 0; i < other_repeated_message->size(); i++) {
+          const MessageLite& other_message = other_repeated_message->Get(i);
+          MessageLite* target =
+              reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+                  extension->repeated_message_value)
+                  ->AddFromCleared<GenericTypeHandler<MessageLite>>();
+          if (target == nullptr) {
+            target = other_message.New(arena_);
+            extension->repeated_message_value->AddAllocated(target);
+          }
+          target->CheckTypeAndMergeFrom(other_message);
+        }
+        break;
+    }
+  } else {
+    if (!other_extension.is_cleared) {
+      switch (cpp_type(other_extension.type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE)  \
+  case WireFormatLite::CPPTYPE_##UPPERCASE:           \
+    Set##CAMELCASE(number, other_extension.type,      \
+                   other_extension.LOWERCASE##_value, \
+                   other_extension.descriptor);       \
+    break;
+
+        HANDLE_TYPE(INT32, int32_t, Int32);
+        HANDLE_TYPE(INT64, int64_t, Int64);
+        HANDLE_TYPE(UINT32, uint32_t, UInt32);
+        HANDLE_TYPE(UINT64, uint64_t, UInt64);
+        HANDLE_TYPE(FLOAT, float, Float);
+        HANDLE_TYPE(DOUBLE, double, Double);
+        HANDLE_TYPE(BOOL, bool, Bool);
+        HANDLE_TYPE(ENUM, enum, Enum);
+#undef HANDLE_TYPE
+        case WireFormatLite::CPPTYPE_STRING:
+          SetString(number, other_extension.type, *other_extension.string_value,
+                    other_extension.descriptor);
+          break;
+        case WireFormatLite::CPPTYPE_MESSAGE: {
+          Extension* extension;
+          bool is_new =
+              MaybeNewExtension(number, other_extension.descriptor, &extension);
+          if (is_new) {
+            extension->type = other_extension.type;
+            extension->is_packed = other_extension.is_packed;
+            extension->is_repeated = false;
+            if (other_extension.is_lazy) {
+              extension->is_lazy = true;
+              extension->lazymessage_value =
+                  other_extension.lazymessage_value->New(arena_);
+              extension->lazymessage_value->MergeFrom(
+                  GetPrototypeForLazyMessage(extendee, number),
+                  *other_extension.lazymessage_value, arena_);
+            } else {
+              extension->is_lazy = false;
+              extension->message_value =
+                  other_extension.message_value->New(arena_);
+              extension->message_value->CheckTypeAndMergeFrom(
+                  *other_extension.message_value);
+            }
+          } else {
+            GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+            GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
+            GOOGLE_DCHECK(!extension->is_repeated);
+            if (other_extension.is_lazy) {
+              if (extension->is_lazy) {
+                extension->lazymessage_value->MergeFrom(
+                    GetPrototypeForLazyMessage(extendee, number),
+                    *other_extension.lazymessage_value, arena_);
+              } else {
+                extension->message_value->CheckTypeAndMergeFrom(
+                    other_extension.lazymessage_value->GetMessage(
+                        *extension->message_value, other_arena));
+              }
+            } else {
+              if (extension->is_lazy) {
+                extension->lazymessage_value
+                    ->MutableMessage(*other_extension.message_value, arena_)
+                    ->CheckTypeAndMergeFrom(*other_extension.message_value);
+              } else {
+                extension->message_value->CheckTypeAndMergeFrom(
+                    *other_extension.message_value);
+              }
+            }
+          }
+          extension->is_cleared = false;
+          break;
+        }
+      }
+    }
+  }
+}
+
+void ExtensionSet::Swap(const MessageLite* extendee, ExtensionSet* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetArena() != nullptr && GetArena() == other->GetArena()) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetArena() == other->GetArena()) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    InternalSwap(other);
+  } else {
+    // TODO(cfallin, rohananil): We maybe able to optimize a case where we are
+    // swapping from heap to arena-allocated extension set, by just Own()'ing
+    // the extensions.
+    ExtensionSet extension_set;
+    extension_set.MergeFrom(extendee, *other);
+    other->Clear();
+    other->MergeFrom(extendee, *this);
+    Clear();
+    MergeFrom(extendee, extension_set);
+  }
+}
+
+void ExtensionSet::InternalSwap(ExtensionSet* other) {
+  using std::swap;
+  swap(arena_, other->arena_);
+  swap(flat_capacity_, other->flat_capacity_);
+  swap(flat_size_, other->flat_size_);
+  swap(map_, other->map_);
+}
+
+void ExtensionSet::SwapExtension(const MessageLite* extendee,
+                                 ExtensionSet* other, int number) {
+  if (this == other) return;
+
+  if (GetArena() == other->GetArena()) {
+    UnsafeShallowSwapExtension(other, number);
+    return;
+  }
+
+  Extension* this_ext = FindOrNull(number);
+  Extension* other_ext = other->FindOrNull(number);
+
+  if (this_ext == other_ext) return;
+
+  if (this_ext != nullptr && other_ext != nullptr) {
+    // TODO(cfallin, rohananil): We could further optimize these cases,
+    // especially avoid creation of ExtensionSet, and move MergeFrom logic
+    // into Extensions itself (which takes arena as an argument).
+    // We do it this way to reuse the copy-across-arenas logic already
+    // implemented in ExtensionSet's MergeFrom.
+    ExtensionSet temp;
+    temp.InternalExtensionMergeFrom(extendee, number, *other_ext,
+                                    other->GetArena());
+    Extension* temp_ext = temp.FindOrNull(number);
+
+    other_ext->Clear();
+    other->InternalExtensionMergeFrom(extendee, number, *this_ext,
+                                      this->GetArena());
+    this_ext->Clear();
+    InternalExtensionMergeFrom(extendee, number, *temp_ext, temp.GetArena());
+  } else if (this_ext == nullptr) {
+    InternalExtensionMergeFrom(extendee, number, *other_ext, other->GetArena());
+    if (other->GetArena() == nullptr) other_ext->Free();
+    other->Erase(number);
+  } else {
+    other->InternalExtensionMergeFrom(extendee, number, *this_ext,
+                                      this->GetArena());
+    if (GetArena() == nullptr) this_ext->Free();
+    Erase(number);
+  }
+}
+
+void ExtensionSet::UnsafeShallowSwapExtension(ExtensionSet* other, int number) {
+  if (this == other) return;
+
+  Extension* this_ext = FindOrNull(number);
+  Extension* other_ext = other->FindOrNull(number);
+
+  if (this_ext == other_ext) return;
+
+  GOOGLE_DCHECK_EQ(GetArena(), other->GetArena());
+
+  if (this_ext != nullptr && other_ext != nullptr) {
+    std::swap(*this_ext, *other_ext);
+  } else if (this_ext == nullptr) {
+    *Insert(number).first = *other_ext;
+    other->Erase(number);
+  } else {
+    *other->Insert(number).first = *this_ext;
+    Erase(number);
+  }
+}
+
+bool ExtensionSet::IsInitialized() const {
+  // Extensions are never required.  However, we need to check that all
+  // embedded messages are initialized.
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    for (const auto& kv : *map_.large) {
+      if (!kv.second.IsInitialized()) return false;
+    }
+    return true;
+  }
+  for (const KeyValue* it = flat_begin(); it != flat_end(); ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
+                                     const MessageLite* extendee,
+                                     internal::InternalMetadata* metadata,
+                                     internal::ParseContext* ctx) {
+  GeneratedExtensionFinder finder(extendee);
+  int number = tag >> 3;
+  bool was_packed_on_wire;
+  ExtensionInfo extension;
+  if (!FindExtensionInfoFromFieldNumber(tag & 7, number, &finder, &extension,
+                                        &was_packed_on_wire)) {
+    return UnknownFieldParse(
+        tag, metadata->mutable_unknown_fields<std::string>(), ptr, ctx);
+  }
+  return ParseFieldWithExtensionInfo<std::string>(
+      number, was_packed_on_wire, extension, metadata, ptr, ctx);
+}
+
+const char* ExtensionSet::ParseMessageSetItem(
+    const char* ptr, const MessageLite* extendee,
+    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+  return ParseMessageSetItemTmpl<MessageLite, std::string>(ptr, extendee,
+                                                           metadata, ctx);
+}
+
+uint8_t* ExtensionSet::_InternalSerializeImpl(
+    const MessageLite* extendee, int start_field_number, int end_field_number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    const auto& end = map_.large->end();
+    for (auto it = map_.large->lower_bound(start_field_number);
+         it != end && it->first < end_field_number; ++it) {
+      target = it->second.InternalSerializeFieldWithCachedSizesToArray(
+          extendee, this, it->first, target, stream);
+    }
+    return target;
+  }
+  const KeyValue* end = flat_end();
+  for (const KeyValue* it = std::lower_bound(
+           flat_begin(), end, start_field_number, KeyValue::FirstComparator());
+       it != end && it->first < end_field_number; ++it) {
+    target = it->second.InternalSerializeFieldWithCachedSizesToArray(
+        extendee, this, it->first, target, stream);
+  }
+  return target;
+}
+
+uint8_t* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
+    const MessageLite* extendee, uint8_t* target,
+    io::EpsCopyOutputStream* stream) const {
+  const ExtensionSet* extension_set = this;
+  ForEach([&target, extendee, stream, extension_set](int number,
+                                                     const Extension& ext) {
+    target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(
+        extendee, extension_set, number, target, stream);
+  });
+  return target;
+}
+
+size_t ExtensionSet::ByteSize() const {
+  size_t total_size = 0;
+  ForEach([&total_size](int number, const Extension& ext) {
+    total_size += ext.ByteSize(number);
+  });
+  return total_size;
+}
+
+// Defined in extension_set_heavy.cc.
+// int ExtensionSet::SpaceUsedExcludingSelf() const
+
+bool ExtensionSet::MaybeNewExtension(int number,
+                                     const FieldDescriptor* descriptor,
+                                     Extension** result) {
+  bool extension_is_new = false;
+  std::tie(*result, extension_is_new) = Insert(number);
+  (*result)->descriptor = descriptor;
+  return extension_is_new;
+}
+
+// ===================================================================
+// Methods of ExtensionSet::Extension
+
+void ExtensionSet::Extension::Clear() {
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
+  case WireFormatLite::CPPTYPE_##UPPERCASE: \
+    repeated_##LOWERCASE##_value->Clear();  \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, enum);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+    }
+  } else {
+    if (!is_cleared) {
+      switch (cpp_type(type)) {
+        case WireFormatLite::CPPTYPE_STRING:
+          string_value->clear();
+          break;
+        case WireFormatLite::CPPTYPE_MESSAGE:
+          if (is_lazy) {
+            lazymessage_value->Clear();
+          } else {
+            message_value->Clear();
+          }
+          break;
+        default:
+          // No need to do anything.  Get*() will return the default value
+          // as long as is_cleared is true and Set*() will overwrite the
+          // previous value.
+          break;
+      }
+
+      is_cleared = true;
+    }
+  }
+}
+
+size_t ExtensionSet::Extension::ByteSize(int number) const {
+  size_t result = 0;
+
+  if (is_repeated) {
+    if (is_packed) {
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      result += WireFormatLite::CAMELCASE##Size(                     \
+          repeated_##LOWERCASE##_value->Get(i));                     \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+
+        // Stuff with fixed size.
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)             \
+  case WireFormatLite::TYPE_##UPPERCASE:                         \
+    result += WireFormatLite::k##CAMELCASE##Size *               \
+              FromIntSize(repeated_##LOWERCASE##_value->size()); \
+    break
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+#undef HANDLE_TYPE
+
+        case WireFormatLite::TYPE_STRING:
+        case WireFormatLite::TYPE_BYTES:
+        case WireFormatLite::TYPE_GROUP:
+        case WireFormatLite::TYPE_MESSAGE:
+          GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+          break;
+      }
+
+      cached_size = ToCachedSize(result);
+      if (result > 0) {
+        result += io::CodedOutputStream::VarintSize32(result);
+        result += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+      }
+    } else {
+      size_t tag_size = WireFormatLite::TagSize(number, real_type(type));
+
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                        \
+  case WireFormatLite::TYPE_##UPPERCASE:                                    \
+    result += tag_size * FromIntSize(repeated_##LOWERCASE##_value->size()); \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) {        \
+      result += WireFormatLite::CAMELCASE##Size(                            \
+          repeated_##LOWERCASE##_value->Get(i));                            \
+    }                                                                       \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(STRING, String, string);
+        HANDLE_TYPE(BYTES, Bytes, string);
+        HANDLE_TYPE(ENUM, Enum, enum);
+        HANDLE_TYPE(GROUP, Group, message);
+        HANDLE_TYPE(MESSAGE, Message, message);
+#undef HANDLE_TYPE
+
+        // Stuff with fixed size.
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)             \
+  case WireFormatLite::TYPE_##UPPERCASE:                         \
+    result += (tag_size + WireFormatLite::k##CAMELCASE##Size) *  \
+              FromIntSize(repeated_##LOWERCASE##_value->size()); \
+    break
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+#undef HANDLE_TYPE
+      }
+    }
+  } else if (!is_cleared) {
+    result += WireFormatLite::TagSize(number, real_type(type));
+    switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)      \
+  case WireFormatLite::TYPE_##UPPERCASE:                  \
+    result += WireFormatLite::CAMELCASE##Size(LOWERCASE); \
+    break
+
+      HANDLE_TYPE(INT32, Int32, int32_t_value);
+      HANDLE_TYPE(INT64, Int64, int64_t_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
+      HANDLE_TYPE(STRING, String, *string_value);
+      HANDLE_TYPE(BYTES, Bytes, *string_value);
+      HANDLE_TYPE(ENUM, Enum, enum_value);
+      HANDLE_TYPE(GROUP, Group, *message_value);
+#undef HANDLE_TYPE
+      case WireFormatLite::TYPE_MESSAGE: {
+        if (is_lazy) {
+          size_t size = lazymessage_value->ByteSizeLong();
+          result += io::CodedOutputStream::VarintSize32(size) + size;
+        } else {
+          result += WireFormatLite::MessageSize(*message_value);
+        }
+        break;
+      }
+
+      // Stuff with fixed size.
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE)         \
+  case WireFormatLite::TYPE_##UPPERCASE:          \
+    result += WireFormatLite::k##CAMELCASE##Size; \
+    break
+        HANDLE_TYPE(FIXED32, Fixed32);
+        HANDLE_TYPE(FIXED64, Fixed64);
+        HANDLE_TYPE(SFIXED32, SFixed32);
+        HANDLE_TYPE(SFIXED64, SFixed64);
+        HANDLE_TYPE(FLOAT, Float);
+        HANDLE_TYPE(DOUBLE, Double);
+        HANDLE_TYPE(BOOL, Bool);
+#undef HANDLE_TYPE
+    }
+  }
+
+  return result;
+}
+
+int ExtensionSet::Extension::GetSize() const {
+  GOOGLE_DCHECK(is_repeated);
+  switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
+  case WireFormatLite::CPPTYPE_##UPPERCASE: \
+    return repeated_##LOWERCASE##_value->size()
+
+    HANDLE_TYPE(INT32, int32_t);
+    HANDLE_TYPE(INT64, int64_t);
+    HANDLE_TYPE(UINT32, uint32_t);
+    HANDLE_TYPE(UINT64, uint64_t);
+    HANDLE_TYPE(FLOAT, float);
+    HANDLE_TYPE(DOUBLE, double);
+    HANDLE_TYPE(BOOL, bool);
+    HANDLE_TYPE(ENUM, enum);
+    HANDLE_TYPE(STRING, string);
+    HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return 0;
+}
+
+// This function deletes all allocated objects. This function should be only
+// called if the Extension was created without an arena.
+void ExtensionSet::Extension::Free() {
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
+  case WireFormatLite::CPPTYPE_##UPPERCASE: \
+    delete repeated_##LOWERCASE##_value;    \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, enum);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+    }
+  } else {
+    switch (cpp_type(type)) {
+      case WireFormatLite::CPPTYPE_STRING:
+        delete string_value;
+        break;
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        if (is_lazy) {
+          delete lazymessage_value;
+        } else {
+          delete message_value;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// int ExtensionSet::Extension::SpaceUsedExcludingSelf() const
+
+bool ExtensionSet::Extension::IsInitialized() const {
+  if (cpp_type(type) == WireFormatLite::CPPTYPE_MESSAGE) {
+    if (is_repeated) {
+      for (int i = 0; i < repeated_message_value->size(); i++) {
+        if (!repeated_message_value->Get(i).IsInitialized()) {
+          return false;
+        }
+      }
+    } else {
+      if (!is_cleared) {
+        if (is_lazy) {
+          if (!lazymessage_value->IsInitialized()) return false;
+        } else {
+          if (!message_value->IsInitialized()) return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+// Dummy key method to avoid weak vtable.
+void ExtensionSet::LazyMessageExtension::UnusedKeyMethod() {}
+
+const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
+  if (flat_size_ == 0) {
+    return nullptr;
+  } else if (PROTOBUF_PREDICT_TRUE(!is_large())) {
+    auto it = std::lower_bound(flat_begin(), flat_end() - 1, key,
+                               KeyValue::FirstComparator());
+    return it->first == key ? &it->second : nullptr;
+  } else {
+    return FindOrNullInLargeMap(key);
+  }
+}
+
+const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(
+    int key) const {
+  assert(is_large());
+  LargeMap::const_iterator it = map_.large->find(key);
+  if (it != map_.large->end()) {
+    return &it->second;
+  }
+  return nullptr;
+}
+
+ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) {
+  const auto* const_this = this;
+  return const_cast<ExtensionSet::Extension*>(const_this->FindOrNull(key));
+}
+
+ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(int key) {
+  const auto* const_this = this;
+  return const_cast<ExtensionSet::Extension*>(
+      const_this->FindOrNullInLargeMap(key));
+}
+
+std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(int key) {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    auto maybe = map_.large->insert({key, Extension()});
+    return {&maybe.first->second, maybe.second};
+  }
+  KeyValue* end = flat_end();
+  KeyValue* it =
+      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
+  if (it != end && it->first == key) {
+    return {&it->second, false};
+  }
+  if (flat_size_ < flat_capacity_) {
+    std::copy_backward(it, end, end + 1);
+    ++flat_size_;
+    it->first = key;
+    it->second = Extension();
+    return {&it->second, true};
+  }
+  GrowCapacity(flat_size_ + 1);
+  return Insert(key);
+}
+
+void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    return;  // LargeMap does not have a "reserve" method.
+  }
+  if (flat_capacity_ >= minimum_new_capacity) {
+    return;
+  }
+
+  auto new_flat_capacity = flat_capacity_;
+  do {
+    new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 4;
+  } while (new_flat_capacity < minimum_new_capacity);
+
+  const KeyValue* begin = flat_begin();
+  const KeyValue* end = flat_end();
+  AllocatedData new_map;
+  if (new_flat_capacity > kMaximumFlatCapacity) {
+    new_map.large = Arena::Create<LargeMap>(arena_);
+    LargeMap::iterator hint = new_map.large->begin();
+    for (const KeyValue* it = begin; it != end; ++it) {
+      hint = new_map.large->insert(hint, {it->first, it->second});
+    }
+    flat_size_ = static_cast<uint16_t>(-1);
+    GOOGLE_DCHECK(is_large());
+  } else {
+    new_map.flat = Arena::CreateArray<KeyValue>(arena_, new_flat_capacity);
+    std::copy(begin, end, new_map.flat);
+  }
+
+  if (arena_ == nullptr) {
+    DeleteFlatMap(begin, flat_capacity_);
+  }
+  flat_capacity_ = new_flat_capacity;
+  map_ = new_map;
+}
+
+#if (__cplusplus < 201703) && \
+    (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+// static
+constexpr uint16_t ExtensionSet::kMaximumFlatCapacity;
+#endif  //  (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900
+        //  && _MSC_VER < 1912))
+
+void ExtensionSet::Erase(int key) {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    map_.large->erase(key);
+    return;
+  }
+  KeyValue* end = flat_end();
+  KeyValue* it =
+      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
+  if (it != end && it->first == key) {
+    std::copy(it + 1, end, it);
+    --flat_size_;
+  }
+}
+
+// ==================================================================
+// Default repeated field instances for iterator-compatible accessors
+
+const RepeatedPrimitiveDefaults* RepeatedPrimitiveDefaults::default_instance() {
+  static auto instance = OnShutdownDelete(new RepeatedPrimitiveDefaults);
+  return instance;
+}
+
+const RepeatedStringTypeTraits::RepeatedFieldType*
+RepeatedStringTypeTraits::GetDefaultRepeatedField() {
+  static auto instance = OnShutdownDelete(new RepeatedFieldType);
+  return instance;
+}
+
+uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
+    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (is_repeated) {
+    if (is_packed) {
+      if (cached_size == 0) return target;
+
+      target = stream->EnsureSpace(target);
+      target = WireFormatLite::WriteTagToArray(
+          number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
+      target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
+
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      target = stream->EnsureSpace(target);                          \
+      target = WireFormatLite::Write##CAMELCASE##NoTagToArray(       \
+          repeated_##LOWERCASE##_value->Get(i), target);             \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+
+        case WireFormatLite::TYPE_STRING:
+        case WireFormatLite::TYPE_BYTES:
+        case WireFormatLite::TYPE_GROUP:
+        case WireFormatLite::TYPE_MESSAGE:
+          GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+          break;
+      }
+    } else {
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      target = stream->EnsureSpace(target);                          \
+      target = WireFormatLite::Write##CAMELCASE##ToArray(            \
+          number, repeated_##LOWERCASE##_value->Get(i), target);     \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      target = stream->EnsureSpace(target);                          \
+      target = stream->WriteString(                                  \
+          number, repeated_##LOWERCASE##_value->Get(i), target);     \
+    }                                                                \
+    break
+        HANDLE_TYPE(STRING, String, string);
+        HANDLE_TYPE(BYTES, Bytes, string);
+#undef HANDLE_TYPE
+        case WireFormatLite::TYPE_GROUP:
+          for (int i = 0; i < repeated_message_value->size(); i++) {
+            target = stream->EnsureSpace(target);
+            target = WireFormatLite::InternalWriteGroup(
+                number, repeated_message_value->Get(i), target, stream);
+          }
+          break;
+        case WireFormatLite::TYPE_MESSAGE:
+          for (int i = 0; i < repeated_message_value->size(); i++) {
+            auto& msg = repeated_message_value->Get(i);
+            target = WireFormatLite::InternalWriteMessage(
+                number, msg, msg.GetCachedSize(), target, stream);
+          }
+          break;
+      }
+    }
+  } else if (!is_cleared) {
+    switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)                               \
+  case WireFormatLite::TYPE_##UPPERCASE:                                       \
+    target = stream->EnsureSpace(target);                                      \
+    target = WireFormatLite::Write##CAMELCASE##ToArray(number, VALUE, target); \
+    break
+
+      HANDLE_TYPE(INT32, Int32, int32_t_value);
+      HANDLE_TYPE(INT64, Int64, int64_t_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
+      HANDLE_TYPE(FIXED32, Fixed32, uint32_t_value);
+      HANDLE_TYPE(FIXED64, Fixed64, uint64_t_value);
+      HANDLE_TYPE(SFIXED32, SFixed32, int32_t_value);
+      HANDLE_TYPE(SFIXED64, SFixed64, int64_t_value);
+      HANDLE_TYPE(FLOAT, Float, float_value);
+      HANDLE_TYPE(DOUBLE, Double, double_value);
+      HANDLE_TYPE(BOOL, Bool, bool_value);
+      HANDLE_TYPE(ENUM, Enum, enum_value);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)         \
+  case WireFormatLite::TYPE_##UPPERCASE:                 \
+    target = stream->EnsureSpace(target);                \
+    target = stream->WriteString(number, VALUE, target); \
+    break
+      HANDLE_TYPE(STRING, String, *string_value);
+      HANDLE_TYPE(BYTES, Bytes, *string_value);
+#undef HANDLE_TYPE
+      case WireFormatLite::TYPE_GROUP:
+        target = stream->EnsureSpace(target);
+        target = WireFormatLite::InternalWriteGroup(number, *message_value,
+                                                    target, stream);
+        break;
+      case WireFormatLite::TYPE_MESSAGE:
+        if (is_lazy) {
+          const auto* prototype =
+              extension_set->GetPrototypeForLazyMessage(extendee, number);
+          target = lazymessage_value->WriteMessageToArray(prototype, number,
+                                                          target, stream);
+        } else {
+          target = WireFormatLite::InternalWriteMessage(
+              number, *message_value, message_value->GetCachedSize(), target,
+              stream);
+        }
+        break;
+    }
+  }
+  return target;
+}
+
+const MessageLite* ExtensionSet::GetPrototypeForLazyMessage(
+    const MessageLite* extendee, int number) const {
+  GeneratedExtensionFinder finder(extendee);
+  bool was_packed_on_wire = false;
+  ExtensionInfo extension_info;
+  if (!FindExtensionInfoFromFieldNumber(
+          WireFormatLite::WireType::WIRETYPE_LENGTH_DELIMITED, number, &finder,
+          &extension_info, &was_packed_on_wire)) {
+    return nullptr;
+  }
+  return extension_info.message_info.prototype;
+}
+
+uint8_t*
+ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
+    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+    // Not a valid MessageSet extension, but serialize it the normal way.
+    GOOGLE_LOG(WARNING) << "Invalid message set extension.";
+    return InternalSerializeFieldWithCachedSizesToArray(extendee, extension_set,
+                                                        number, target, stream);
+  }
+
+  if (is_cleared) return target;
+
+  target = stream->EnsureSpace(target);
+  // Start group.
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemStartTag, target);
+  // Write type ID.
+  target = WireFormatLite::WriteUInt32ToArray(
+      WireFormatLite::kMessageSetTypeIdNumber, number, target);
+  // Write message.
+  if (is_lazy) {
+    const auto* prototype =
+        extension_set->GetPrototypeForLazyMessage(extendee, number);
+    target = lazymessage_value->WriteMessageToArray(
+        prototype, WireFormatLite::kMessageSetMessageNumber, target, stream);
+  } else {
+    target = WireFormatLite::InternalWriteMessage(
+        WireFormatLite::kMessageSetMessageNumber, *message_value,
+        message_value->GetCachedSize(), target, stream);
+  }
+  // End group.
+  target = stream->EnsureSpace(target);
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemEndTag, target);
+  return target;
+}
+
+size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
+  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+    // Not a valid MessageSet extension, but compute the byte size for it the
+    // normal way.
+    return ByteSize(number);
+  }
+
+  if (is_cleared) return 0;
+
+  size_t our_size = WireFormatLite::kMessageSetItemTagsSize;
+
+  // type_id
+  our_size += io::CodedOutputStream::VarintSize32(number);
+
+  // message
+  size_t message_size = 0;
+  if (is_lazy) {
+    message_size = lazymessage_value->ByteSizeLong();
+  } else {
+    message_size = message_value->ByteSizeLong();
+  }
+
+  our_size += io::CodedOutputStream::VarintSize32(message_size);
+  our_size += message_size;
+
+  return our_size;
+}
+
+size_t ExtensionSet::MessageSetByteSize() const {
+  size_t total_size = 0;
+  ForEach([&total_size](int number, const Extension& ext) {
+    total_size += ext.MessageSetItemByteSize(number);
+  });
+  return total_size;
+}
+
+LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
+    const MessageLite* extendee, int number) {
+  const ExtensionInfo* registered = FindRegisteredExtension(extendee, number);
+  if (registered != nullptr) {
+    return registered->lazy_eager_verify_func;
+  }
+  return nullptr;
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
new file mode 100644
index 0000000..0e6d052
--- /dev/null
+++ b/src/google/protobuf/extension_set.h
@@ -0,0 +1,1561 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// 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_EXTENSION_SET_H__
+#define GOOGLE_PROTOBUF_EXTENSION_SET_H__
+
+
+#include <algorithm>
+#include <cassert>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>  // Must be last
+// clang-format on
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class Arena;
+class Descriptor;       // descriptor.h
+class FieldDescriptor;  // descriptor.h
+class DescriptorPool;   // descriptor.h
+class MessageLite;      // message_lite.h
+class Message;          // message.h
+class MessageFactory;   // message.h
+class Reflection;       // message.h
+class UnknownFieldSet;  // unknown_field_set.h
+namespace internal {
+class FieldSkipper;  // wire_format_lite.h
+enum class LazyVerifyOption;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class InternalMetadata;
+
+// Used to store values of type WireFormatLite::FieldType without having to
+// #include wire_format_lite.h.  Also, ensures that we use only one byte to
+// store these values, which is important to keep the layout of
+// ExtensionSet::Extension small.
+typedef uint8_t FieldType;
+
+// A function which, given an integer value, returns true if the number
+// matches one of the defined values for the corresponding enum type.  This
+// is used with RegisterEnumExtension, below.
+typedef bool EnumValidityFunc(int number);
+
+// Version of the above which takes an argument.  This is needed to deal with
+// extensions that are not compiled in.
+typedef bool EnumValidityFuncWithArg(const void* arg, int number);
+
+// Information about a registered extension.
+struct ExtensionInfo {
+  constexpr ExtensionInfo() : enum_validity_check() {}
+  constexpr ExtensionInfo(const MessageLite* extendee, int param_number,
+                          FieldType type_param, bool isrepeated, bool ispacked,
+                          LazyEagerVerifyFnType verify_func)
+      : message(extendee),
+        number(param_number),
+        type(type_param),
+        is_repeated(isrepeated),
+        is_packed(ispacked),
+        enum_validity_check(),
+        lazy_eager_verify_func(verify_func) {}
+
+  const MessageLite* message = nullptr;
+  int number = 0;
+
+  FieldType type = 0;
+  bool is_repeated = false;
+  bool is_packed = false;
+
+  struct EnumValidityCheck {
+    EnumValidityFuncWithArg* func;
+    const void* arg;
+  };
+
+  struct MessageInfo {
+    const MessageLite* prototype;
+  };
+
+  union {
+    EnumValidityCheck enum_validity_check;
+    MessageInfo message_info;
+  };
+
+  // The descriptor for this extension, if one exists and is known.  May be
+  // nullptr.  Must not be nullptr if the descriptor for the extension does not
+  // live in the same pool as the descriptor for the containing type.
+  const FieldDescriptor* descriptor = nullptr;
+
+  // If this field is potentially lazy this function can be used as a cheap
+  // verification of the raw bytes.
+  // If nullptr then no verification is performed.
+  LazyEagerVerifyFnType lazy_eager_verify_func = nullptr;
+};
+
+// An ExtensionFinder is an object which looks up extension definitions.  It
+// must implement this method:
+//
+// bool Find(int number, ExtensionInfo* output);
+
+// GeneratedExtensionFinder is an ExtensionFinder which finds extensions
+// defined in .proto files which have been compiled into the binary.
+class PROTOBUF_EXPORT GeneratedExtensionFinder {
+ public:
+  explicit GeneratedExtensionFinder(const MessageLite* extendee)
+      : extendee_(extendee) {}
+
+  // Returns true and fills in *output if found, otherwise returns false.
+  bool Find(int number, ExtensionInfo* output);
+
+ private:
+  const MessageLite* extendee_;
+};
+
+// Note:  extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
+// finding extensions from a DescriptorPool.
+
+// This is an internal helper class intended for use within the protocol buffer
+// library and generated classes.  Clients should not use it directly.  Instead,
+// use the generated accessors such as GetExtension() of the class being
+// extended.
+//
+// This class manages extensions for a protocol message object.  The
+// message's HasExtension(), GetExtension(), MutableExtension(), and
+// ClearExtension() methods are just thin wrappers around the embedded
+// ExtensionSet.  When parsing, if a tag number is encountered which is
+// inside one of the message type's extension ranges, the tag is passed
+// off to the ExtensionSet for parsing.  Etc.
+class PROTOBUF_EXPORT ExtensionSet {
+ public:
+  constexpr ExtensionSet();
+  explicit ExtensionSet(Arena* arena);
+  ExtensionSet(ArenaInitialized, Arena* arena) : ExtensionSet(arena) {}
+  ~ExtensionSet();
+
+  // These are called at startup by protocol-compiler-generated code to
+  // register known extensions.  The registrations are used by ParseField()
+  // to look up extensions for parsed field numbers.  Note that dynamic parsing
+  // does not use ParseField(); only protocol-compiler-generated parsing
+  // methods do.
+  static void RegisterExtension(const MessageLite* extendee, int number,
+                                FieldType type, bool is_repeated,
+                                bool is_packed,
+                                LazyEagerVerifyFnType verify_func);
+  static void RegisterEnumExtension(const MessageLite* extendee, int number,
+                                    FieldType type, bool is_repeated,
+                                    bool is_packed, EnumValidityFunc* is_valid);
+  static void RegisterMessageExtension(const MessageLite* extendee, int number,
+                                       FieldType type, bool is_repeated,
+                                       bool is_packed,
+                                       const MessageLite* prototype,
+                                       LazyEagerVerifyFnType verify_func);
+
+  // =================================================================
+
+  // Add all fields which are currently present to the given vector.  This
+  // is useful to implement Reflection::ListFields().
+  void AppendToList(const Descriptor* extendee, const DescriptorPool* pool,
+                    std::vector<const FieldDescriptor*>* output) const;
+
+  // =================================================================
+  // Accessors
+  //
+  // Generated message classes include type-safe templated wrappers around
+  // these methods.  Generally you should use those rather than call these
+  // 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.  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
+  // of the reflection interface.  In both cases, it is impossible to
+  // trigger this assert failure:  the generated accessors only accept
+  // linked-in extension types as parameters, while the Reflection interface
+  // requires you to provide the FieldDescriptor describing the extension.
+  //
+  // When calling any of these accessors, a protocol-compiler-generated
+  // implementation of the extension corresponding to the number MUST
+  // be linked in, and the FieldDescriptor used to refer to it MUST be
+  // the one generated by that linked-in code.  Otherwise, the method will
+  // die on an assert failure.  The message objects returned by the message
+  // accessors are guaranteed to be of the correct linked-in type.
+  //
+  // These methods pretty much match Reflection except that:
+  // - They're not virtual.
+  // - They identify fields by number rather than FieldDescriptors.
+  // - They identify enum values using integers rather than descriptors.
+  // - Strings provide Mutable() in addition to Set() accessors.
+
+  bool Has(int number) const;
+  int ExtensionSize(int number) const;  // Size of a repeated extension.
+  int NumExtensions() const;            // The number of extensions
+  FieldType ExtensionType(int number) const;
+  void ClearExtension(int number);
+
+  // singular fields -------------------------------------------------
+
+  int32_t GetInt32(int number, int32_t default_value) const;
+  int64_t GetInt64(int number, int64_t default_value) const;
+  uint32_t GetUInt32(int number, uint32_t default_value) const;
+  uint64_t GetUInt64(int number, uint64_t default_value) const;
+  float GetFloat(int number, float default_value) const;
+  double GetDouble(int number, double default_value) const;
+  bool GetBool(int number, bool default_value) const;
+  int GetEnum(int number, int default_value) const;
+  const std::string& GetString(int number,
+                               const std::string& default_value) const;
+  const MessageLite& GetMessage(int number,
+                                const MessageLite& default_value) const;
+  const MessageLite& GetMessage(int number, const Descriptor* message_type,
+                                MessageFactory* factory) const;
+
+  // |descriptor| may be nullptr so long as it is known that the descriptor for
+  // the extension lives in the same pool as the descriptor for the containing
+  // type.
+#define desc const FieldDescriptor* descriptor  // avoid line wrapping
+  void SetInt32(int number, FieldType type, int32_t value, desc);
+  void SetInt64(int number, FieldType type, int64_t value, desc);
+  void SetUInt32(int number, FieldType type, uint32_t value, desc);
+  void SetUInt64(int number, FieldType type, uint64_t value, desc);
+  void SetFloat(int number, FieldType type, float value, desc);
+  void SetDouble(int number, FieldType type, double value, desc);
+  void SetBool(int number, FieldType type, bool value, desc);
+  void SetEnum(int number, FieldType type, int value, desc);
+  void SetString(int number, FieldType type, std::string value, desc);
+  std::string* MutableString(int number, FieldType type, desc);
+  MessageLite* MutableMessage(int number, FieldType type,
+                              const MessageLite& prototype, desc);
+  MessageLite* MutableMessage(const FieldDescriptor* descriptor,
+                              MessageFactory* factory);
+  // Adds the given message to the ExtensionSet, taking ownership of the
+  // message object. Existing message with the same number will be deleted.
+  // If "message" is nullptr, this is equivalent to "ClearExtension(number)".
+  void SetAllocatedMessage(int number, FieldType type,
+                           const FieldDescriptor* descriptor,
+                           MessageLite* message);
+  void UnsafeArenaSetAllocatedMessage(int number, FieldType type,
+                                      const FieldDescriptor* descriptor,
+                                      MessageLite* message);
+  PROTOBUF_NODISCARD MessageLite* ReleaseMessage(int number,
+                                                 const MessageLite& prototype);
+  MessageLite* UnsafeArenaReleaseMessage(int number,
+                                         const MessageLite& prototype);
+
+  PROTOBUF_NODISCARD MessageLite* ReleaseMessage(
+      const FieldDescriptor* descriptor, MessageFactory* factory);
+  MessageLite* UnsafeArenaReleaseMessage(const FieldDescriptor* descriptor,
+                                         MessageFactory* factory);
+#undef desc
+  Arena* GetArena() const { return arena_; }
+
+  // repeated fields -------------------------------------------------
+
+  // Fetches a RepeatedField extension by number; returns |default_value|
+  // if no such extension exists. User should not touch this directly; it is
+  // used by the GetRepeatedExtension() method.
+  const void* GetRawRepeatedField(int number, const void* default_value) const;
+  // Fetches a mutable version of a RepeatedField extension by number,
+  // instantiating one if none exists. Similar to above, user should not use
+  // this directly; it underlies MutableRepeatedExtension().
+  void* MutableRawRepeatedField(int number, FieldType field_type, bool packed,
+                                const FieldDescriptor* desc);
+
+  // This is an overload of MutableRawRepeatedField to maintain compatibility
+  // with old code using a previous API. This version of
+  // MutableRawRepeatedField() will GOOGLE_CHECK-fail on a missing extension.
+  // (E.g.: borg/clients/internal/proto1/proto2_reflection.cc.)
+  void* MutableRawRepeatedField(int number);
+
+  int32_t GetRepeatedInt32(int number, int index) const;
+  int64_t GetRepeatedInt64(int number, int index) const;
+  uint32_t GetRepeatedUInt32(int number, int index) const;
+  uint64_t GetRepeatedUInt64(int number, int index) const;
+  float GetRepeatedFloat(int number, int index) const;
+  double GetRepeatedDouble(int number, int index) const;
+  bool GetRepeatedBool(int number, int index) const;
+  int GetRepeatedEnum(int number, int index) const;
+  const std::string& GetRepeatedString(int number, int index) const;
+  const MessageLite& GetRepeatedMessage(int number, int index) const;
+
+  void SetRepeatedInt32(int number, int index, int32_t value);
+  void SetRepeatedInt64(int number, int index, int64_t value);
+  void SetRepeatedUInt32(int number, int index, uint32_t value);
+  void SetRepeatedUInt64(int number, int index, uint64_t value);
+  void SetRepeatedFloat(int number, int index, float value);
+  void SetRepeatedDouble(int number, int index, double value);
+  void SetRepeatedBool(int number, int index, bool value);
+  void SetRepeatedEnum(int number, int index, int value);
+  void SetRepeatedString(int number, int index, std::string value);
+  std::string* MutableRepeatedString(int number, int index);
+  MessageLite* MutableRepeatedMessage(int number, int index);
+
+#define desc const FieldDescriptor* descriptor  // avoid line wrapping
+  void AddInt32(int number, FieldType type, bool packed, int32_t value, desc);
+  void AddInt64(int number, FieldType type, bool packed, int64_t value, desc);
+  void AddUInt32(int number, FieldType type, bool packed, uint32_t value, desc);
+  void AddUInt64(int number, FieldType type, bool packed, uint64_t value, desc);
+  void AddFloat(int number, FieldType type, bool packed, float value, desc);
+  void AddDouble(int number, FieldType type, bool packed, double value, desc);
+  void AddBool(int number, FieldType type, bool packed, bool value, desc);
+  void AddEnum(int number, FieldType type, bool packed, int value, desc);
+  void AddString(int number, FieldType type, std::string value, desc);
+  std::string* AddString(int number, FieldType type, desc);
+  MessageLite* AddMessage(int number, FieldType type,
+                          const MessageLite& prototype, desc);
+  MessageLite* AddMessage(const FieldDescriptor* descriptor,
+                          MessageFactory* factory);
+  void AddAllocatedMessage(const FieldDescriptor* descriptor,
+                           MessageLite* new_entry);
+  void UnsafeArenaAddAllocatedMessage(const FieldDescriptor* descriptor,
+                                      MessageLite* new_entry);
+#undef desc
+
+  void RemoveLast(int number);
+  PROTOBUF_NODISCARD MessageLite* ReleaseLast(int number);
+  MessageLite* UnsafeArenaReleaseLast(int number);
+  void SwapElements(int number, int index1, int index2);
+
+  // =================================================================
+  // convenience methods for implementing methods of Message
+  //
+  // These could all be implemented in terms of the other methods of this
+  // class, but providing them here helps keep the generated code size down.
+
+  void Clear();
+  void MergeFrom(const MessageLite* extendee, const ExtensionSet& other);
+  void Swap(const MessageLite* extendee, ExtensionSet* other);
+  void InternalSwap(ExtensionSet* other);
+  void SwapExtension(const MessageLite* extendee, ExtensionSet* other,
+                     int number);
+  void UnsafeShallowSwapExtension(ExtensionSet* other, int number);
+  bool IsInitialized() const;
+
+  // Lite parser
+  const char* ParseField(uint64_t tag, const char* ptr,
+                         const MessageLite* extendee,
+                         internal::InternalMetadata* metadata,
+                         internal::ParseContext* ctx);
+  // Full parser
+  const char* ParseField(uint64_t tag, const char* ptr, const Message* extendee,
+                         internal::InternalMetadata* metadata,
+                         internal::ParseContext* ctx);
+  template <typename Msg>
+  const char* ParseMessageSet(const char* ptr, const Msg* extendee,
+                              InternalMetadata* metadata,
+                              internal::ParseContext* ctx) {
+    struct MessageSetItem {
+      const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+        return me->ParseMessageSetItem(ptr, extendee, metadata, ctx);
+      }
+      ExtensionSet* me;
+      const Msg* extendee;
+      InternalMetadata* metadata;
+    } item{this, extendee, metadata};
+    while (!ctx->Done(&ptr)) {
+      uint32_t tag;
+      ptr = ReadTag(ptr, &tag);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (tag == WireFormatLite::kMessageSetItemStartTag) {
+        ptr = ctx->ParseGroup(&item, ptr, tag);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      } else {
+        if (tag == 0 || (tag & 7) == 4) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        ptr = ParseField(tag, ptr, extendee, metadata, ctx);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      }
+    }
+    return ptr;
+  }
+
+  // Write all extension fields with field numbers in the range
+  //   [start_field_number, end_field_number)
+  // to the output stream, using the cached sizes computed when ByteSize() was
+  // last called.  Note that the range bounds are inclusive-exclusive.
+  void SerializeWithCachedSizes(const MessageLite* extendee,
+                                int start_field_number, int end_field_number,
+                                io::CodedOutputStream* output) const {
+    output->SetCur(_InternalSerialize(extendee, start_field_number,
+                                      end_field_number, output->Cur(),
+                                      output->EpsCopy()));
+  }
+
+  // Same as SerializeWithCachedSizes, but without any bounds checking.
+  // The caller must ensure that target has sufficient capacity for the
+  // serialized extensions.
+  //
+  // Returns a pointer past the last written byte.
+
+  uint8_t* _InternalSerialize(const MessageLite* extendee,
+                              int start_field_number, int end_field_number,
+                              uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const {
+    if (flat_size_ == 0) {
+      assert(!is_large());
+      return target;
+    }
+    return _InternalSerializeImpl(extendee, start_field_number,
+                                  end_field_number, target, stream);
+  }
+
+  // Like above but serializes in MessageSet format.
+  void SerializeMessageSetWithCachedSizes(const MessageLite* extendee,
+                                          io::CodedOutputStream* output) const {
+    output->SetCur(InternalSerializeMessageSetWithCachedSizesToArray(
+        extendee, output->Cur(), output->EpsCopy()));
+  }
+  uint8_t* InternalSerializeMessageSetWithCachedSizesToArray(
+      const MessageLite* extendee, uint8_t* target,
+      io::EpsCopyOutputStream* stream) const;
+
+  // For backward-compatibility, versions of two of the above methods that
+  // serialize deterministically iff SetDefaultSerializationDeterministic()
+  // has been called.
+  uint8_t* SerializeWithCachedSizesToArray(int start_field_number,
+                                           int end_field_number,
+                                           uint8_t* target) const;
+  uint8_t* SerializeMessageSetWithCachedSizesToArray(
+      const MessageLite* extendee, uint8_t* target) const;
+
+  // Returns the total serialized size of all the extensions.
+  size_t ByteSize() const;
+
+  // Like ByteSize() but uses MessageSet format.
+  size_t MessageSetByteSize() const;
+
+  // Returns (an estimate of) the total number of bytes used for storing the
+  // extensions in memory, excluding sizeof(*this).  If the ExtensionSet is
+  // for a lite message (and thus possibly contains lite messages), the results
+  // are undefined (might work, might crash, might corrupt data, might not even
+  // be linked in).  It's up to the protocol compiler to avoid calling this on
+  // such ExtensionSets (easy enough since lite messages don't implement
+  // SpaceUsed()).
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  // This method just calls SpaceUsedExcludingSelfLong() but it can not be
+  // inlined because the definition of SpaceUsedExcludingSelfLong() is not
+  // included in lite runtime and when an inline method refers to it MSVC
+  // will complain about unresolved symbols when building the lite runtime
+  // as .dll.
+  int SpaceUsedExcludingSelf() const;
+
+ private:
+  template <typename Type>
+  friend class PrimitiveTypeTraits;
+
+  template <typename Type>
+  friend class RepeatedPrimitiveTypeTraits;
+
+  template <typename Type, bool IsValid(int)>
+  friend class EnumTypeTraits;
+
+  template <typename Type, bool IsValid(int)>
+  friend class RepeatedEnumTypeTraits;
+
+  friend class google::protobuf::Reflection;
+
+  const int32_t& GetRefInt32(int number, const int32_t& default_value) const;
+  const int64_t& GetRefInt64(int number, const int64_t& default_value) const;
+  const uint32_t& GetRefUInt32(int number, const uint32_t& default_value) const;
+  const uint64_t& GetRefUInt64(int number, const uint64_t& default_value) const;
+  const float& GetRefFloat(int number, const float& default_value) const;
+  const double& GetRefDouble(int number, const double& default_value) const;
+  const bool& GetRefBool(int number, const bool& default_value) const;
+  const int& GetRefEnum(int number, const int& default_value) const;
+  const int32_t& GetRefRepeatedInt32(int number, int index) const;
+  const int64_t& GetRefRepeatedInt64(int number, int index) const;
+  const uint32_t& GetRefRepeatedUInt32(int number, int index) const;
+  const uint64_t& GetRefRepeatedUInt64(int number, int index) const;
+  const float& GetRefRepeatedFloat(int number, int index) const;
+  const double& GetRefRepeatedDouble(int number, int index) const;
+  const bool& GetRefRepeatedBool(int number, int index) const;
+  const int& GetRefRepeatedEnum(int number, int index) const;
+
+  // Implementation of _InternalSerialize for non-empty map_.
+  uint8_t* _InternalSerializeImpl(const MessageLite* extendee,
+                                  int start_field_number, int end_field_number,
+                                  uint8_t* target,
+                                  io::EpsCopyOutputStream* stream) const;
+  // Interface of a lazily parsed singular message extension.
+  class PROTOBUF_EXPORT LazyMessageExtension {
+   public:
+    LazyMessageExtension() {}
+    virtual ~LazyMessageExtension() {}
+
+    virtual LazyMessageExtension* New(Arena* arena) const = 0;
+    virtual const MessageLite& GetMessage(const MessageLite& prototype,
+                                          Arena* arena) const = 0;
+    virtual MessageLite* MutableMessage(const MessageLite& prototype,
+                                        Arena* arena) = 0;
+    virtual void SetAllocatedMessage(MessageLite* message, Arena* arena) = 0;
+    virtual void UnsafeArenaSetAllocatedMessage(MessageLite* message,
+                                                Arena* arena) = 0;
+    PROTOBUF_NODISCARD virtual MessageLite* ReleaseMessage(
+        const MessageLite& prototype, Arena* arena) = 0;
+    virtual MessageLite* UnsafeArenaReleaseMessage(const MessageLite& prototype,
+                                                   Arena* arena) = 0;
+
+    virtual bool IsInitialized() const = 0;
+
+    PROTOBUF_DEPRECATED_MSG("Please use ByteSizeLong() instead")
+    virtual int ByteSize() const { return internal::ToIntSize(ByteSizeLong()); }
+    virtual size_t ByteSizeLong() const = 0;
+    virtual size_t SpaceUsedLong() const = 0;
+
+    virtual void MergeFrom(const MessageLite* prototype,
+                           const LazyMessageExtension& other, Arena* arena) = 0;
+    virtual void MergeFromMessage(const MessageLite& msg, Arena* arena) = 0;
+    virtual void Clear() = 0;
+
+    virtual const char* _InternalParse(const Message& prototype, Arena* arena,
+                                       LazyVerifyOption option, const char* ptr,
+                                       ParseContext* ctx) = 0;
+    virtual uint8_t* WriteMessageToArray(
+        const MessageLite* prototype, int number, uint8_t* target,
+        io::EpsCopyOutputStream* stream) const = 0;
+
+   private:
+    virtual void UnusedKeyMethod();  // Dummy key method to avoid weak vtable.
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
+  };
+  // Give access to function defined below to see LazyMessageExtension.
+  friend LazyMessageExtension* MaybeCreateLazyExtension(Arena* arena);
+  struct Extension {
+    // The order of these fields packs Extension into 24 bytes when using 8
+    // byte alignment. Consider this when adding or removing fields here.
+    union {
+      int32_t int32_t_value;
+      int64_t int64_t_value;
+      uint32_t uint32_t_value;
+      uint64_t uint64_t_value;
+      float float_value;
+      double double_value;
+      bool bool_value;
+      int enum_value;
+      std::string* string_value;
+      MessageLite* message_value;
+      LazyMessageExtension* lazymessage_value;
+
+      RepeatedField<int32_t>* repeated_int32_t_value;
+      RepeatedField<int64_t>* repeated_int64_t_value;
+      RepeatedField<uint32_t>* repeated_uint32_t_value;
+      RepeatedField<uint64_t>* repeated_uint64_t_value;
+      RepeatedField<float>* repeated_float_value;
+      RepeatedField<double>* repeated_double_value;
+      RepeatedField<bool>* repeated_bool_value;
+      RepeatedField<int>* repeated_enum_value;
+      RepeatedPtrField<std::string>* repeated_string_value;
+      RepeatedPtrField<MessageLite>* repeated_message_value;
+    };
+
+    FieldType type;
+    bool is_repeated;
+
+    // For singular types, indicates if the extension is "cleared".  This
+    // happens when an extension is set and then later cleared by the caller.
+    // We want to keep the Extension object around for reuse, so instead of
+    // removing it from the map, we just set is_cleared = true.  This has no
+    // meaning for repeated types; for those, the size of the RepeatedField
+    // simply becomes zero when cleared.
+    bool is_cleared : 4;
+
+    // For singular message types, indicates whether lazy parsing is enabled
+    // for this extension. This field is only valid when type == TYPE_MESSAGE
+    // and !is_repeated because we only support lazy parsing for singular
+    // message types currently. If is_lazy = true, the extension is stored in
+    // lazymessage_value. Otherwise, the extension will be message_value.
+    bool is_lazy : 4;
+
+    // For repeated types, this indicates if the [packed=true] option is set.
+    bool is_packed;
+
+    // For packed fields, the size of the packed data is recorded here when
+    // ByteSize() is called then used during serialization.
+    // TODO(kenton):  Use atomic<int> when C++ supports it.
+    mutable int cached_size;
+
+    // The descriptor for this extension, if one exists and is known.  May be
+    // nullptr.  Must not be nullptr if the descriptor for the extension does
+    // not live in the same pool as the descriptor for the containing type.
+    const FieldDescriptor* descriptor;
+
+    // Some helper methods for operations on a single Extension.
+    uint8_t* InternalSerializeFieldWithCachedSizesToArray(
+        const MessageLite* extendee, const ExtensionSet* extension_set,
+        int number, uint8_t* target, io::EpsCopyOutputStream* stream) const;
+    uint8_t* InternalSerializeMessageSetItemWithCachedSizesToArray(
+        const MessageLite* extendee, const ExtensionSet* extension_set,
+        int number, uint8_t* target, io::EpsCopyOutputStream* stream) const;
+    size_t ByteSize(int number) const;
+    size_t MessageSetItemByteSize(int number) const;
+    void Clear();
+    int GetSize() const;
+    void Free();
+    size_t SpaceUsedExcludingSelfLong() const;
+    bool IsInitialized() const;
+  };
+
+  // The Extension struct is small enough to be passed by value, so we use it
+  // directly as the value type in mappings rather than use pointers.  We use
+  // sorted maps rather than hash-maps because we expect most ExtensionSets will
+  // only contain a small number of extension.  Also, we want AppendToList and
+  // deterministic serialization to order fields by field number.
+
+  struct KeyValue {
+    int first;
+    Extension second;
+
+    struct FirstComparator {
+      bool operator()(const KeyValue& lhs, const KeyValue& rhs) const {
+        return lhs.first < rhs.first;
+      }
+      bool operator()(const KeyValue& lhs, int key) const {
+        return lhs.first < key;
+      }
+      bool operator()(int key, const KeyValue& rhs) const {
+        return key < rhs.first;
+      }
+    };
+  };
+
+  typedef std::map<int, Extension> LargeMap;
+
+  // Wrapper API that switches between flat-map and LargeMap.
+
+  // Finds a key (if present) in the ExtensionSet.
+  const Extension* FindOrNull(int key) const;
+  Extension* FindOrNull(int key);
+
+  // Helper-functions that only inspect the LargeMap.
+  const Extension* FindOrNullInLargeMap(int key) const;
+  Extension* FindOrNullInLargeMap(int key);
+
+  // Inserts a new (key, Extension) into the ExtensionSet (and returns true), or
+  // finds the already-existing Extension for that key (returns false).
+  // The Extension* will point to the new-or-found Extension.
+  std::pair<Extension*, bool> Insert(int key);
+
+  // Grows the flat_capacity_.
+  // If flat_capacity_ > kMaximumFlatCapacity, converts to LargeMap.
+  void GrowCapacity(size_t minimum_new_capacity);
+  static constexpr uint16_t kMaximumFlatCapacity = 256;
+  bool is_large() const { return static_cast<int16_t>(flat_size_) < 0; }
+
+  // Removes a key from the ExtensionSet.
+  void Erase(int key);
+
+  size_t Size() const {
+    return PROTOBUF_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_;
+  }
+
+  // Similar to std::for_each.
+  // Each Iterator is decomposed into ->first and ->second fields, so
+  // that the KeyValueFunctor can be agnostic vis-a-vis KeyValue-vs-std::pair.
+  template <typename Iterator, typename KeyValueFunctor>
+  static KeyValueFunctor ForEach(Iterator begin, Iterator end,
+                                 KeyValueFunctor func) {
+    for (Iterator it = begin; it != end; ++it) func(it->first, it->second);
+    return std::move(func);
+  }
+
+  // Applies a functor to the <int, Extension&> pairs in sorted order.
+  template <typename KeyValueFunctor>
+  KeyValueFunctor ForEach(KeyValueFunctor func) {
+    if (PROTOBUF_PREDICT_FALSE(is_large())) {
+      return ForEach(map_.large->begin(), map_.large->end(), std::move(func));
+    }
+    return ForEach(flat_begin(), flat_end(), std::move(func));
+  }
+
+  // Applies a functor to the <int, const Extension&> pairs in sorted order.
+  template <typename KeyValueFunctor>
+  KeyValueFunctor ForEach(KeyValueFunctor func) const {
+    if (PROTOBUF_PREDICT_FALSE(is_large())) {
+      return ForEach(map_.large->begin(), map_.large->end(), std::move(func));
+    }
+    return ForEach(flat_begin(), flat_end(), std::move(func));
+  }
+
+  // Merges existing Extension from other_extension
+  void InternalExtensionMergeFrom(const MessageLite* extendee, int number,
+                                  const Extension& other_extension,
+                                  Arena* other_arena);
+
+  inline static bool is_packable(WireFormatLite::WireType type) {
+    switch (type) {
+      case WireFormatLite::WIRETYPE_VARINT:
+      case WireFormatLite::WIRETYPE_FIXED64:
+      case WireFormatLite::WIRETYPE_FIXED32:
+        return true;
+      case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
+      case WireFormatLite::WIRETYPE_START_GROUP:
+      case WireFormatLite::WIRETYPE_END_GROUP:
+        return false;
+
+        // Do not add a default statement. Let the compiler complain when
+        // someone
+        // adds a new wire type.
+    }
+    PROTOBUF_ASSUME(false);  // switch handles all possible enum values
+    return false;
+  }
+
+  // Returns true and fills field_number and extension if extension is found.
+  // Note to support packed repeated field compatibility, it also fills whether
+  // the tag on wire is packed, which can be different from
+  // extension->is_packed (whether packed=true is specified).
+  template <typename ExtensionFinder>
+  bool FindExtensionInfoFromTag(uint32_t tag, ExtensionFinder* extension_finder,
+                                int* field_number, ExtensionInfo* extension,
+                                bool* was_packed_on_wire) {
+    *field_number = WireFormatLite::GetTagFieldNumber(tag);
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+    return FindExtensionInfoFromFieldNumber(wire_type, *field_number,
+                                            extension_finder, extension,
+                                            was_packed_on_wire);
+  }
+
+  // Returns true and fills extension if extension is found.
+  // Note to support packed repeated field compatibility, it also fills whether
+  // the tag on wire is packed, which can be different from
+  // extension->is_packed (whether packed=true is specified).
+  template <typename ExtensionFinder>
+  bool FindExtensionInfoFromFieldNumber(int wire_type, int field_number,
+                                        ExtensionFinder* extension_finder,
+                                        ExtensionInfo* extension,
+                                        bool* was_packed_on_wire) const {
+    if (!extension_finder->Find(field_number, extension)) {
+      return false;
+    }
+
+    GOOGLE_DCHECK(extension->type > 0 &&
+           extension->type <= WireFormatLite::MAX_FIELD_TYPE);
+    auto real_type = static_cast<WireFormatLite::FieldType>(extension->type);
+
+    WireFormatLite::WireType expected_wire_type =
+        WireFormatLite::WireTypeForFieldType(real_type);
+
+    // Check if this is a packed field.
+    *was_packed_on_wire = false;
+    if (extension->is_repeated &&
+        wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED &&
+        is_packable(expected_wire_type)) {
+      *was_packed_on_wire = true;
+      return true;
+    }
+    // Otherwise the wire type must match.
+    return expected_wire_type == wire_type;
+  }
+
+  // Find the prototype for a LazyMessage from the extension registry. Returns
+  // null if the extension is not found.
+  const MessageLite* GetPrototypeForLazyMessage(const MessageLite* extendee,
+                                                int number) const;
+
+  // Returns true if extension is present and lazy.
+  bool HasLazy(int number) const;
+
+  // Gets the extension with the given number, creating it if it does not
+  // already exist.  Returns true if the extension did not already exist.
+  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);
+
+  bool FindExtension(int wire_type, uint32_t field, const MessageLite* extendee,
+                     const internal::ParseContext* /*ctx*/,
+                     ExtensionInfo* extension, bool* was_packed_on_wire) {
+    GeneratedExtensionFinder finder(extendee);
+    return FindExtensionInfoFromFieldNumber(wire_type, field, &finder,
+                                            extension, was_packed_on_wire);
+  }
+  inline bool FindExtension(int wire_type, uint32_t field,
+                            const Message* extendee,
+                            const internal::ParseContext* ctx,
+                            ExtensionInfo* extension, bool* was_packed_on_wire);
+  // Used for MessageSet only
+  const char* ParseFieldMaybeLazily(uint64_t tag, const char* ptr,
+                                    const MessageLite* extendee,
+                                    internal::InternalMetadata* metadata,
+                                    internal::ParseContext* ctx) {
+    // Lite MessageSet doesn't implement lazy.
+    return ParseField(tag, ptr, extendee, metadata, ctx);
+  }
+  const char* ParseFieldMaybeLazily(uint64_t tag, const char* ptr,
+                                    const Message* extendee,
+                                    internal::InternalMetadata* metadata,
+                                    internal::ParseContext* ctx);
+  const char* ParseMessageSetItem(const char* ptr, const MessageLite* extendee,
+                                  internal::InternalMetadata* metadata,
+                                  internal::ParseContext* ctx);
+  const char* ParseMessageSetItem(const char* ptr, const Message* extendee,
+                                  internal::InternalMetadata* metadata,
+                                  internal::ParseContext* ctx);
+
+  // Implemented in extension_set_inl.h to keep code out of the header file.
+  template <typename T>
+  const char* ParseFieldWithExtensionInfo(int number, bool was_packed_on_wire,
+                                          const ExtensionInfo& info,
+                                          internal::InternalMetadata* metadata,
+                                          const char* ptr,
+                                          internal::ParseContext* ctx);
+  template <typename Msg, typename T>
+  const char* ParseMessageSetItemTmpl(const char* ptr, const Msg* extendee,
+                                      internal::InternalMetadata* metadata,
+                                      internal::ParseContext* ctx);
+
+  // Hack:  RepeatedPtrFieldBase declares ExtensionSet as a friend.  This
+  //   friendship should automatically extend to ExtensionSet::Extension, but
+  //   unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this
+  //   correctly.  So, we must provide helpers for calling methods of that
+  //   class.
+
+  // Defined in extension_set_heavy.cc.
+  static inline size_t RepeatedMessage_SpaceUsedExcludingSelfLong(
+      RepeatedPtrFieldBase* field);
+
+  KeyValue* flat_begin() {
+    assert(!is_large());
+    return map_.flat;
+  }
+  const KeyValue* flat_begin() const {
+    assert(!is_large());
+    return map_.flat;
+  }
+  KeyValue* flat_end() {
+    assert(!is_large());
+    return map_.flat + flat_size_;
+  }
+  const KeyValue* flat_end() const {
+    assert(!is_large());
+    return map_.flat + flat_size_;
+  }
+
+  Arena* arena_;
+
+  // Manual memory-management:
+  // map_.flat is an allocated array of flat_capacity_ elements.
+  // [map_.flat, map_.flat + flat_size_) is the currently-in-use prefix.
+  uint16_t flat_capacity_;
+  uint16_t flat_size_;  // negative int16_t(flat_size_) indicates is_large()
+  union AllocatedData {
+    KeyValue* flat;
+
+    // If flat_capacity_ > kMaximumFlatCapacity, switch to LargeMap,
+    // which guarantees O(n lg n) CPU but larger constant factors.
+    LargeMap* large;
+  } map_;
+
+  static void DeleteFlatMap(const KeyValue* flat, uint16_t flat_capacity);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
+};
+
+constexpr ExtensionSet::ExtensionSet()
+    : arena_(nullptr), flat_capacity_(0), flat_size_(0), map_{nullptr} {}
+
+// These are just for convenience...
+inline void ExtensionSet::SetString(int number, FieldType type,
+                                    std::string value,
+                                    const FieldDescriptor* descriptor) {
+  MutableString(number, type, descriptor)->assign(std::move(value));
+}
+inline void ExtensionSet::SetRepeatedString(int number, int index,
+                                            std::string value) {
+  MutableRepeatedString(number, index)->assign(std::move(value));
+}
+inline void ExtensionSet::AddString(int number, FieldType type,
+                                    std::string value,
+                                    const FieldDescriptor* descriptor) {
+  AddString(number, type, descriptor)->assign(std::move(value));
+}
+// ===================================================================
+// Glue for generated extension accessors
+
+// -------------------------------------------------------------------
+// Template magic
+
+// First we have a set of classes representing "type traits" for different
+// field types.  A type traits class knows how to implement basic accessors
+// for extensions of a particular type given an ExtensionSet.  The signature
+// for a type traits class looks like this:
+//
+//   class TypeTraits {
+//    public:
+//     typedef ? ConstType;
+//     typedef ? MutableType;
+//     // TypeTraits for singular fields and repeated fields will define the
+//     // symbol "Singular" or "Repeated" respectively. These two symbols will
+//     // be used in extension accessors to distinguish between singular
+//     // extensions and repeated extensions. If the TypeTraits for the passed
+//     // in extension doesn't have the expected symbol defined, it means the
+//     // user is passing a repeated extension to a singular accessor, or the
+//     // opposite. In that case the C++ compiler will generate an error
+//     // message "no matching member function" to inform the user.
+//     typedef ? Singular
+//     typedef ? Repeated
+//
+//     static inline ConstType Get(int number, const ExtensionSet& set);
+//     static inline void Set(int number, ConstType value, ExtensionSet* set);
+//     static inline MutableType Mutable(int number, ExtensionSet* set);
+//
+//     // Variants for repeated fields.
+//     static inline ConstType Get(int number, const ExtensionSet& set,
+//                                 int index);
+//     static inline void Set(int number, int index,
+//                            ConstType value, ExtensionSet* set);
+//     static inline MutableType Mutable(int number, int index,
+//                                       ExtensionSet* set);
+//     static inline void Add(int number, ConstType value, ExtensionSet* set);
+//     static inline MutableType Add(int number, ExtensionSet* set);
+//     This is used by the ExtensionIdentifier constructor to register
+//     the extension at dynamic initialization.
+//     template <typename ExtendeeT>
+//     static void Register(int number, FieldType type, bool is_packed);
+//   };
+//
+// Not all of these methods make sense for all field types.  For example, the
+// "Mutable" methods only make sense for strings and messages, and the
+// repeated methods only make sense for repeated types.  So, each type
+// traits class implements only the set of methods from this signature that it
+// actually supports.  This will cause a compiler error if the user tries to
+// access an extension using a method that doesn't make sense for its type.
+// For example, if "foo" is an extension of type "optional int32", then if you
+// try to write code like:
+//   my_message.MutableExtension(foo)
+// you will get a compile error because PrimitiveTypeTraits<int32_t> does not
+// have a "Mutable()" method.
+
+// -------------------------------------------------------------------
+// PrimitiveTypeTraits
+
+// Since the ExtensionSet has different methods for each primitive type,
+// we must explicitly define the methods of the type traits class for each
+// known type.
+template <typename Type>
+class PrimitiveTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef PrimitiveTypeTraits<Type> Singular;
+
+  static inline ConstType Get(int number, const ExtensionSet& set,
+                              ConstType default_value);
+
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        const ConstType& default_value);
+  static inline void Set(int number, FieldType field_type, ConstType value,
+                         ExtensionSet* set);
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, false, is_packed, verify_func);
+  }
+};
+
+template <typename Type>
+class RepeatedPrimitiveTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef RepeatedPrimitiveTypeTraits<Type> Repeated;
+
+  typedef RepeatedField<Type> RepeatedFieldType;
+
+  static inline Type Get(int number, const ExtensionSet& set, int index);
+  static inline const Type* GetPtr(int number, const ExtensionSet& set,
+                                   int index);
+  static inline const RepeatedField<ConstType>* GetRepeatedPtr(
+      int number, const ExtensionSet& set);
+  static inline void Set(int number, int index, Type value, ExtensionSet* set);
+  static inline void Add(int number, FieldType field_type, bool is_packed,
+                         Type value, ExtensionSet* set);
+
+  static inline const RepeatedField<ConstType>& GetRepeated(
+      int number, const ExtensionSet& set);
+  static inline RepeatedField<Type>* MutableRepeated(int number,
+                                                     FieldType field_type,
+                                                     bool is_packed,
+                                                     ExtensionSet* set);
+
+  static const RepeatedFieldType* GetDefaultRepeatedField();
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, true, is_packed, verify_func);
+  }
+};
+
+class PROTOBUF_EXPORT RepeatedPrimitiveDefaults {
+ private:
+  template <typename Type>
+  friend class RepeatedPrimitiveTypeTraits;
+  static const RepeatedPrimitiveDefaults* default_instance();
+  RepeatedField<int32_t> default_repeated_field_int32_t_;
+  RepeatedField<int64_t> default_repeated_field_int64_t_;
+  RepeatedField<uint32_t> default_repeated_field_uint32_t_;
+  RepeatedField<uint64_t> default_repeated_field_uint64_t_;
+  RepeatedField<double> default_repeated_field_double_;
+  RepeatedField<float> default_repeated_field_float_;
+  RepeatedField<bool> default_repeated_field_bool_;
+};
+
+#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD)                           \
+  template <>                                                                  \
+  inline TYPE PrimitiveTypeTraits<TYPE>::Get(                                  \
+      int number, const ExtensionSet& set, TYPE default_value) {               \
+    return set.Get##METHOD(number, default_value);                             \
+  }                                                                            \
+  template <>                                                                  \
+  inline const TYPE* PrimitiveTypeTraits<TYPE>::GetPtr(                        \
+      int number, const ExtensionSet& set, const TYPE& default_value) {        \
+    return &set.GetRef##METHOD(number, default_value);                         \
+  }                                                                            \
+  template <>                                                                  \
+  inline void PrimitiveTypeTraits<TYPE>::Set(int number, FieldType field_type, \
+                                             TYPE value, ExtensionSet* set) {  \
+    set->Set##METHOD(number, field_type, value, nullptr);                      \
+  }                                                                            \
+                                                                               \
+  template <>                                                                  \
+  inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get(                          \
+      int number, const ExtensionSet& set, int index) {                        \
+    return set.GetRepeated##METHOD(number, index);                             \
+  }                                                                            \
+  template <>                                                                  \
+  inline const TYPE* RepeatedPrimitiveTypeTraits<TYPE>::GetPtr(                \
+      int number, const ExtensionSet& set, int index) {                        \
+    return &set.GetRefRepeated##METHOD(number, index);                         \
+  }                                                                            \
+  template <>                                                                  \
+  inline void RepeatedPrimitiveTypeTraits<TYPE>::Set(                          \
+      int number, int index, TYPE value, ExtensionSet* set) {                  \
+    set->SetRepeated##METHOD(number, index, value);                            \
+  }                                                                            \
+  template <>                                                                  \
+  inline void RepeatedPrimitiveTypeTraits<TYPE>::Add(                          \
+      int number, FieldType field_type, bool is_packed, TYPE value,            \
+      ExtensionSet* set) {                                                     \
+    set->Add##METHOD(number, field_type, is_packed, value, nullptr);           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const RepeatedField<TYPE>*                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() {               \
+    return &RepeatedPrimitiveDefaults::default_instance()                      \
+                ->default_repeated_field_##TYPE##_;                            \
+  }                                                                            \
+  template <>                                                                  \
+  inline const RepeatedField<TYPE>&                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetRepeated(int number,                   \
+                                                 const ExtensionSet& set) {    \
+    return *reinterpret_cast<const RepeatedField<TYPE>*>(                      \
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const RepeatedField<TYPE>*                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetRepeatedPtr(int number,                \
+                                                    const ExtensionSet& set) { \
+    return &GetRepeated(number, set);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline RepeatedField<TYPE>*                                                  \
+  RepeatedPrimitiveTypeTraits<TYPE>::MutableRepeated(                          \
+      int number, FieldType field_type, bool is_packed, ExtensionSet* set) {   \
+    return reinterpret_cast<RepeatedField<TYPE>*>(                             \
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr)); \
+  }
+
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(int32_t, Int32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(int64_t, Int64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32_t, UInt32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64_t, UInt64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(float, Float)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(bool, Bool)
+
+#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE
+
+// -------------------------------------------------------------------
+// StringTypeTraits
+
+// Strings support both Set() and Mutable().
+class PROTOBUF_EXPORT StringTypeTraits {
+ public:
+  typedef const std::string& ConstType;
+  typedef std::string* MutableType;
+  typedef StringTypeTraits Singular;
+
+  static inline const std::string& Get(int number, const ExtensionSet& set,
+                                       ConstType default_value) {
+    return set.GetString(number, default_value);
+  }
+  static inline const std::string* GetPtr(int number, const ExtensionSet& set,
+                                          ConstType default_value) {
+    return &Get(number, set, default_value);
+  }
+  static inline void Set(int number, FieldType field_type,
+                         const std::string& value, ExtensionSet* set) {
+    set->SetString(number, field_type, value, nullptr);
+  }
+  static inline std::string* Mutable(int number, FieldType field_type,
+                                     ExtensionSet* set) {
+    return set->MutableString(number, field_type, nullptr);
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, false, is_packed, verify_func);
+  }
+};
+
+class PROTOBUF_EXPORT RepeatedStringTypeTraits {
+ public:
+  typedef const std::string& ConstType;
+  typedef std::string* MutableType;
+  typedef RepeatedStringTypeTraits Repeated;
+
+  typedef RepeatedPtrField<std::string> RepeatedFieldType;
+
+  static inline const std::string& Get(int number, const ExtensionSet& set,
+                                       int index) {
+    return set.GetRepeatedString(number, index);
+  }
+  static inline const std::string* GetPtr(int number, const ExtensionSet& set,
+                                          int index) {
+    return &Get(number, set, index);
+  }
+  static inline const RepeatedPtrField<std::string>* GetRepeatedPtr(
+      int number, const ExtensionSet& set) {
+    return &GetRepeated(number, set);
+  }
+  static inline void Set(int number, int index, const std::string& value,
+                         ExtensionSet* set) {
+    set->SetRepeatedString(number, index, value);
+  }
+  static inline std::string* Mutable(int number, int index, ExtensionSet* set) {
+    return set->MutableRepeatedString(number, index);
+  }
+  static inline void Add(int number, FieldType field_type, bool /*is_packed*/,
+                         const std::string& value, ExtensionSet* set) {
+    set->AddString(number, field_type, value, nullptr);
+  }
+  static inline std::string* Add(int number, FieldType field_type,
+                                 ExtensionSet* set) {
+    return set->AddString(number, field_type, nullptr);
+  }
+  static inline const RepeatedPtrField<std::string>& GetRepeated(
+      int number, const ExtensionSet& set) {
+    return *reinterpret_cast<const RepeatedPtrField<std::string>*>(
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+  }
+
+  static inline RepeatedPtrField<std::string>* MutableRepeated(
+      int number, FieldType field_type, bool is_packed, ExtensionSet* set) {
+    return reinterpret_cast<RepeatedPtrField<std::string>*>(
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr));
+  }
+
+  static const RepeatedFieldType* GetDefaultRepeatedField();
+
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, true, is_packed, fn);
+  }
+
+ private:
+  static void InitializeDefaultRepeatedFields();
+  static void DestroyDefaultRepeatedFields();
+};
+
+// -------------------------------------------------------------------
+// EnumTypeTraits
+
+// ExtensionSet represents enums using integers internally, so we have to
+// static_cast around.
+template <typename Type, bool IsValid(int)>
+class EnumTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef EnumTypeTraits<Type, IsValid> Singular;
+
+  static inline ConstType Get(int number, const ExtensionSet& set,
+                              ConstType default_value) {
+    return static_cast<Type>(set.GetEnum(number, default_value));
+  }
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        const ConstType& default_value) {
+    return reinterpret_cast<const Type*>(
+        &set.GetRefEnum(number, default_value));
+  }
+  static inline void Set(int number, FieldType field_type, ConstType value,
+                         ExtensionSet* set) {
+    GOOGLE_DCHECK(IsValid(value));
+    set->SetEnum(number, field_type, value, nullptr);
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number,
+                                        type, false, is_packed, IsValid);
+  }
+};
+
+template <typename Type, bool IsValid(int)>
+class RepeatedEnumTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef RepeatedEnumTypeTraits<Type, IsValid> Repeated;
+
+  typedef RepeatedField<Type> RepeatedFieldType;
+
+  static inline ConstType Get(int number, const ExtensionSet& set, int index) {
+    return static_cast<Type>(set.GetRepeatedEnum(number, index));
+  }
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        int index) {
+    return reinterpret_cast<const Type*>(
+        &set.GetRefRepeatedEnum(number, index));
+  }
+  static inline void Set(int number, int index, ConstType value,
+                         ExtensionSet* set) {
+    GOOGLE_DCHECK(IsValid(value));
+    set->SetRepeatedEnum(number, index, value);
+  }
+  static inline void Add(int number, FieldType field_type, bool is_packed,
+                         ConstType value, ExtensionSet* set) {
+    GOOGLE_DCHECK(IsValid(value));
+    set->AddEnum(number, field_type, is_packed, value, nullptr);
+  }
+  static inline const RepeatedField<Type>& GetRepeated(
+      int number, const ExtensionSet& set) {
+    // Hack: the `Extension` struct stores a RepeatedField<int> for enums.
+    // RepeatedField<int> cannot implicitly convert to RepeatedField<EnumType>
+    // so we need to do some casting magic. See message.h for similar
+    // contortions for non-extension fields.
+    return *reinterpret_cast<const RepeatedField<Type>*>(
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+  }
+  static inline const RepeatedField<Type>* GetRepeatedPtr(
+      int number, const ExtensionSet& set) {
+    return &GetRepeated(number, set);
+  }
+  static inline RepeatedField<Type>* MutableRepeated(int number,
+                                                     FieldType field_type,
+                                                     bool is_packed,
+                                                     ExtensionSet* set) {
+    return reinterpret_cast<RepeatedField<Type>*>(
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr));
+  }
+
+  static const RepeatedFieldType* GetDefaultRepeatedField() {
+    // Hack: as noted above, repeated enum fields are internally stored as a
+    // RepeatedField<int>. We need to be able to instantiate global static
+    // objects to return as default (empty) repeated fields on non-existent
+    // extensions. We would not be able to know a-priori all of the enum types
+    // (values of |Type|) to instantiate all of these, so we just re-use
+    // int32_t's default repeated field object.
+    return reinterpret_cast<const RepeatedField<Type>*>(
+        RepeatedPrimitiveTypeTraits<int32_t>::GetDefaultRepeatedField());
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number,
+                                        type, true, is_packed, IsValid);
+  }
+};
+
+// -------------------------------------------------------------------
+// MessageTypeTraits
+
+// ExtensionSet guarantees that when manipulating extensions with message
+// types, the implementation used will be the compiled-in class representing
+// that type.  So, we can static_cast down to the exact type we expect.
+template <typename Type>
+class MessageTypeTraits {
+ public:
+  typedef const Type& ConstType;
+  typedef Type* MutableType;
+  typedef MessageTypeTraits<Type> Singular;
+
+  static inline ConstType Get(int number, const ExtensionSet& set,
+                              ConstType default_value) {
+    return static_cast<const Type&>(set.GetMessage(number, default_value));
+  }
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
+                                      ConstType /* default_value */) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline MutableType Mutable(int number, FieldType field_type,
+                                    ExtensionSet* set) {
+    return static_cast<Type*>(set->MutableMessage(
+        number, field_type, Type::default_instance(), nullptr));
+  }
+  static inline void SetAllocated(int number, FieldType field_type,
+                                  MutableType message, ExtensionSet* set) {
+    set->SetAllocatedMessage(number, field_type, nullptr, message);
+  }
+  static inline void UnsafeArenaSetAllocated(int number, FieldType field_type,
+                                             MutableType message,
+                                             ExtensionSet* set) {
+    set->UnsafeArenaSetAllocatedMessage(number, field_type, nullptr, message);
+  }
+  PROTOBUF_NODISCARD static inline MutableType Release(
+      int number, FieldType /* field_type */, ExtensionSet* set) {
+    return static_cast<Type*>(
+        set->ReleaseMessage(number, Type::default_instance()));
+  }
+  static inline MutableType UnsafeArenaRelease(int number,
+                                               FieldType /* field_type */,
+                                               ExtensionSet* set) {
+    return static_cast<Type*>(
+        set->UnsafeArenaReleaseMessage(number, Type::default_instance()));
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(),
+                                           number, type, false, is_packed,
+                                           &Type::default_instance(), fn);
+  }
+};
+
+// Used by WireFormatVerify to extract the verify function from the registry.
+LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
+    const MessageLite* extendee, int number);
+
+// forward declaration.
+class RepeatedMessageGenericTypeTraits;
+
+template <typename Type>
+class RepeatedMessageTypeTraits {
+ public:
+  typedef const Type& ConstType;
+  typedef Type* MutableType;
+  typedef RepeatedMessageTypeTraits<Type> Repeated;
+
+  typedef RepeatedPtrField<Type> RepeatedFieldType;
+
+  static inline ConstType Get(int number, const ExtensionSet& set, int index) {
+    return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
+  }
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
+                                      int /* index */) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline std::nullptr_t GetRepeatedPtr(int /* number */,
+                                              const ExtensionSet& /* set */) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
+    return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
+  }
+  static inline MutableType Add(int number, FieldType field_type,
+                                ExtensionSet* set) {
+    return static_cast<Type*>(
+        set->AddMessage(number, field_type, Type::default_instance(), nullptr));
+  }
+  static inline const RepeatedPtrField<Type>& GetRepeated(
+      int number, const ExtensionSet& set) {
+    // See notes above in RepeatedEnumTypeTraits::GetRepeated(): same
+    // casting hack applies here, because a RepeatedPtrField<MessageLite>
+    // cannot naturally become a RepeatedPtrType<Type> even though Type is
+    // presumably a message. google::protobuf::Message goes through similar contortions
+    // with a reinterpret_cast<>.
+    return *reinterpret_cast<const RepeatedPtrField<Type>*>(
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+  }
+  static inline RepeatedPtrField<Type>* MutableRepeated(int number,
+                                                        FieldType field_type,
+                                                        bool is_packed,
+                                                        ExtensionSet* set) {
+    return reinterpret_cast<RepeatedPtrField<Type>*>(
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr));
+  }
+
+  static const RepeatedFieldType* GetDefaultRepeatedField();
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(),
+                                           number, type, true, is_packed,
+                                           &Type::default_instance(), fn);
+  }
+};
+
+template <typename Type>
+inline const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
+RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
+  static auto instance = OnShutdownDelete(new RepeatedFieldType);
+  return instance;
+}
+
+// -------------------------------------------------------------------
+// ExtensionIdentifier
+
+// This is the type of actual extension objects.  E.g. if you have:
+//   extend Foo {
+//     optional int32 bar = 1234;
+//   }
+// then "bar" will be defined in C++ as:
+//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32_t>, 5, false> bar(1234);
+//
+// Note that we could, in theory, supply the field number as a template
+// parameter, and thus make an instance of ExtensionIdentifier have no
+// actual contents.  However, if we did that, then using an extension
+// identifier would not necessarily cause the compiler to output any sort
+// of reference to any symbol defined in the extension's .pb.o file.  Some
+// linkers will actually drop object files that are not explicitly referenced,
+// but that would be bad because it would cause this extension to not be
+// registered at static initialization, and therefore using it would crash.
+
+template <typename ExtendeeType, typename TypeTraitsType, FieldType field_type,
+          bool is_packed>
+class ExtensionIdentifier {
+ public:
+  typedef TypeTraitsType TypeTraits;
+  typedef ExtendeeType Extendee;
+
+  ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value,
+                      LazyEagerVerifyFnType verify_func = nullptr)
+      : number_(number), default_value_(default_value) {
+    Register(number, verify_func);
+  }
+  inline int number() const { return number_; }
+  typename TypeTraits::ConstType default_value() const {
+    return default_value_;
+  }
+
+  static void Register(int number, LazyEagerVerifyFnType verify_func) {
+    TypeTraits::template Register<ExtendeeType>(number, field_type, is_packed,
+                                                verify_func);
+  }
+
+  typename TypeTraits::ConstType const& default_value_ref() const {
+    return default_value_;
+  }
+
+ private:
+  const int number_;
+  typename TypeTraits::ConstType default_value_;
+};
+
+// -------------------------------------------------------------------
+// Generated accessors
+
+
+// Used to retrieve a lazy extension, may return nullptr in some environments.
+extern PROTOBUF_ATTRIBUTE_WEAK ExtensionSet::LazyMessageExtension*
+MaybeCreateLazyExtension(Arena* arena);
+
+}  // namespace internal
+
+// Call this function to ensure that this extensions's reflection is linked into
+// the binary:
+//
+//   google::protobuf::LinkExtensionReflection(Foo::my_extension);
+//
+// This will ensure that the following lookup will succeed:
+//
+//   DescriptorPool::generated_pool()->FindExtensionByName("Foo.my_extension");
+//
+// This is often relevant for parsing extensions in text mode.
+//
+// As a side-effect, it will also guarantee that anything else from the same
+// .proto file will also be available for lookup in the generated pool.
+//
+// This function does not actually register the extension, so it does not need
+// to be called before the lookup.  However it does need to occur in a function
+// that cannot be stripped from the binary (ie. it must be reachable from main).
+//
+// Best practice is to call this function as close as possible to where the
+// reflection is actually needed.  This function is very cheap to call, so you
+// should not need to worry about its runtime overhead except in tight loops (on
+// x86-64 it compiles into two "mov" instructions).
+template <typename ExtendeeType, typename TypeTraitsType,
+          internal::FieldType field_type, bool is_packed>
+void LinkExtensionReflection(
+    const google::protobuf::internal::ExtensionIdentifier<
+        ExtendeeType, TypeTraitsType, field_type, is_packed>& extension) {
+  internal::StrongReference(extension);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_EXTENSION_SET_H__
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
new file mode 100644
index 0000000..a4bb948
--- /dev/null
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -0,0 +1,440 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Contains methods defined in extension_set.h which cannot be part of the
+// lite library because they use descriptors or reflection.
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Implementation of ExtensionFinder which finds extensions in a given
+// DescriptorPool, using the given MessageFactory to construct sub-objects.
+// This class is implemented in extension_set_heavy.cc.
+class DescriptorPoolExtensionFinder {
+ public:
+  DescriptorPoolExtensionFinder(const DescriptorPool* pool,
+                                MessageFactory* factory,
+                                const Descriptor* containing_type)
+      : pool_(pool), factory_(factory), containing_type_(containing_type) {}
+
+  bool Find(int number, ExtensionInfo* output);
+
+ private:
+  const DescriptorPool* pool_;
+  MessageFactory* factory_;
+  const Descriptor* containing_type_;
+};
+
+void ExtensionSet::AppendToList(
+    const Descriptor* containing_type, const DescriptorPool* pool,
+    std::vector<const FieldDescriptor*>* output) const {
+  ForEach([containing_type, pool, &output](int number, const Extension& ext) {
+    bool has = false;
+    if (ext.is_repeated) {
+      has = ext.GetSize() > 0;
+    } else {
+      has = !ext.is_cleared;
+    }
+
+    if (has) {
+      // TODO(kenton): Looking up each field by number is somewhat unfortunate.
+      //   Is there a better way?  The problem is that descriptors are lazily-
+      //   initialized, so they might not even be constructed until
+      //   AppendToList() is called.
+
+      if (ext.descriptor == nullptr) {
+        output->push_back(pool->FindExtensionByNumber(containing_type, number));
+      } else {
+        output->push_back(ext.descriptor);
+      }
+    }
+  });
+}
+
+inline FieldDescriptor::Type real_type(FieldType type) {
+  GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE);
+  return static_cast<FieldDescriptor::Type>(type);
+}
+
+inline FieldDescriptor::CppType cpp_type(FieldType type) {
+  return FieldDescriptor::TypeToCppType(
+      static_cast<FieldDescriptor::Type>(type));
+}
+
+inline WireFormatLite::FieldType field_type(FieldType type) {
+  GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
+  return static_cast<WireFormatLite::FieldType>(type);
+}
+
+#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                         \
+  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED  \
+                                    : FieldDescriptor::LABEL_OPTIONAL, \
+            FieldDescriptor::LABEL_##LABEL);                           \
+  GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+const MessageLite& ExtensionSet::GetMessage(int number,
+                                            const Descriptor* message_type,
+                                            MessageFactory* factory) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return *factory->GetPrototype(message_type);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->GetMessage(
+          *factory->GetPrototype(message_type), arena_);
+    } else {
+      return *extension->message_value;
+    }
+  }
+}
+
+MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
+                                          MessageFactory* factory) {
+  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 = false;
+    extension->is_packed = false;
+    const MessageLite* prototype =
+        factory->GetPrototype(descriptor->message_type());
+    extension->is_lazy = false;
+    extension->message_value = prototype->New(arena_);
+    extension->is_cleared = false;
+    return extension->message_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    extension->is_cleared = false;
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->MutableMessage(
+          *factory->GetPrototype(descriptor->message_type()), arena_);
+    } else {
+      return extension->message_value;
+    }
+  }
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+                                          MessageFactory* factory) {
+  Extension* extension = FindOrNull(descriptor->number());
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->ReleaseMessage(
+          *factory->GetPrototype(descriptor->message_type()), arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      if (arena_ != nullptr) {
+        ret = extension->message_value->New();
+        ret->CheckTypeAndMergeFrom(*extension->message_value);
+      } else {
+        ret = extension->message_value;
+      }
+    }
+    Erase(descriptor->number());
+    return ret;
+  }
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+    const FieldDescriptor* descriptor, MessageFactory* factory) {
+  Extension* extension = FindOrNull(descriptor->number());
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(
+          *factory->GetPrototype(descriptor->message_type()), arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      ret = extension->message_value;
+    }
+    Erase(descriptor->number());
+    return ret;
+  }
+}
+
+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 =
+        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.
+  MessageLite* result =
+      reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+          extension->repeated_message_value)
+          ->AddFromCleared<GenericTypeHandler<MessageLite> >();
+  if (result == nullptr) {
+    const MessageLite* prototype;
+    if (extension->repeated_message_value->empty()) {
+      prototype = factory->GetPrototype(descriptor->message_type());
+      GOOGLE_CHECK(prototype != nullptr);
+    } else {
+      prototype = &extension->repeated_message_value->Get(0);
+    }
+    result = prototype->New(arena_);
+    extension->repeated_message_value->AddAllocated(result);
+  }
+  return result;
+}
+
+void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor,
+                                       MessageLite* new_entry) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  extension->repeated_message_value->AddAllocated(new_entry);
+}
+
+void ExtensionSet::UnsafeArenaAddAllocatedMessage(
+    const FieldDescriptor* descriptor, MessageLite* new_entry) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  extension->repeated_message_value->UnsafeArenaAddAllocated(new_entry);
+}
+
+static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
+  return reinterpret_cast<const EnumDescriptor*>(arg)->FindValueByNumber(
+             number) != nullptr;
+}
+
+bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
+  const FieldDescriptor* extension =
+      pool_->FindExtensionByNumber(containing_type_, number);
+  if (extension == nullptr) {
+    return false;
+  } else {
+    output->type = extension->type();
+    output->is_repeated = extension->is_repeated();
+    output->is_packed = extension->options().packed();
+    output->descriptor = extension;
+    if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      output->message_info.prototype =
+          factory_->GetPrototype(extension->message_type());
+      GOOGLE_CHECK(output->message_info.prototype != nullptr)
+          << "Extension factory's GetPrototype() returned nullptr; extension: "
+          << extension->full_name();
+    } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      output->enum_validity_check.func = ValidateEnumUsingDescriptor;
+      output->enum_validity_check.arg = extension->enum_type();
+    }
+
+    return true;
+  }
+}
+
+
+bool ExtensionSet::FindExtension(int wire_type, uint32_t field,
+                                 const Message* containing_type,
+                                 const internal::ParseContext* ctx,
+                                 ExtensionInfo* extension,
+                                 bool* was_packed_on_wire) {
+  if (ctx->data().pool == nullptr) {
+    GeneratedExtensionFinder finder(containing_type);
+    if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
+                                          was_packed_on_wire)) {
+      return false;
+    }
+  } else {
+    DescriptorPoolExtensionFinder finder(ctx->data().pool, ctx->data().factory,
+                                         containing_type->GetDescriptor());
+    if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
+                                          was_packed_on_wire)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
+                                     const Message* containing_type,
+                                     internal::InternalMetadata* metadata,
+                                     internal::ParseContext* ctx) {
+  int number = tag >> 3;
+  bool was_packed_on_wire;
+  ExtensionInfo extension;
+  if (!FindExtension(tag & 7, number, containing_type, ctx, &extension,
+                     &was_packed_on_wire)) {
+    return UnknownFieldParse(
+        tag, metadata->mutable_unknown_fields<UnknownFieldSet>(), ptr, ctx);
+  }
+  return ParseFieldWithExtensionInfo<UnknownFieldSet>(
+      number, was_packed_on_wire, extension, metadata, ptr, ctx);
+}
+
+const char* ExtensionSet::ParseFieldMaybeLazily(
+    uint64_t tag, const char* ptr, const Message* containing_type,
+    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+  return ParseField(tag, ptr, containing_type, metadata, ctx);
+}
+
+const char* ExtensionSet::ParseMessageSetItem(
+    const char* ptr, const Message* containing_type,
+    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+  return ParseMessageSetItemTmpl<Message, UnknownFieldSet>(ptr, containing_type,
+                                                           metadata, ctx);
+}
+
+int ExtensionSet::SpaceUsedExcludingSelf() const {
+  return internal::FromIntSize(SpaceUsedExcludingSelfLong());
+}
+
+size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
+  size_t total_size =
+      (is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue);
+  ForEach([&total_size](int /* number */, const Extension& ext) {
+    total_size += ext.SpaceUsedExcludingSelfLong();
+  });
+  return total_size;
+}
+
+inline size_t ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelfLong(
+    RepeatedPtrFieldBase* field) {
+  return field->SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >();
+}
+
+size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
+  size_t total_size = 0;
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                                  \
+    total_size += sizeof(*repeated_##LOWERCASE##_value) +                     \
+                  repeated_##LOWERCASE##_value->SpaceUsedExcludingSelfLong(); \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, enum);
+      HANDLE_TYPE(STRING, string);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        // repeated_message_value is actually a RepeatedPtrField<MessageLite>,
+        // but MessageLite has no SpaceUsedLong(), so we must directly call
+        // RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() with a different
+        // type handler.
+        total_size += sizeof(*repeated_message_value) +
+                      RepeatedMessage_SpaceUsedExcludingSelfLong(
+                          reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+                              repeated_message_value));
+        break;
+    }
+  } else {
+    switch (cpp_type(type)) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        total_size += sizeof(*string_value) +
+                      StringSpaceUsedExcludingSelfLong(*string_value);
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (is_lazy) {
+          total_size += lazymessage_value->SpaceUsedLong();
+        } else {
+          total_size += down_cast<Message*>(message_value)->SpaceUsedLong();
+        }
+        break;
+      default:
+        // No extra storage costs for primitive types.
+        break;
+    }
+  }
+  return total_size;
+}
+
+uint8_t* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
+    const MessageLite* extendee, uint8_t* target) const {
+  io::EpsCopyOutputStream stream(
+      target, MessageSetByteSize(),
+      io::CodedOutputStream::IsDefaultSerializationDeterministic());
+  return InternalSerializeMessageSetWithCachedSizesToArray(extendee, target,
+                                                           &stream);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
new file mode 100644
index 0000000..e4e7117
--- /dev/null
+++ b/src/google/protobuf/extension_set_inl.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+#define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template <typename T>
+const char* ExtensionSet::ParseFieldWithExtensionInfo(
+    int number, bool was_packed_on_wire, const ExtensionInfo& extension,
+    InternalMetadata* metadata, const char* ptr, internal::ParseContext* ctx) {
+  if (was_packed_on_wire) {
+    switch (extension.type) {
+#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
+  case WireFormatLite::TYPE_##UPPERCASE:                                     \
+    return internal::Packed##CPP_CAMELCASE##Parser(                          \
+        MutableRawRepeatedField(number, extension.type, extension.is_packed, \
+                                extension.descriptor),                       \
+        ptr, ctx);
+      HANDLE_TYPE(INT32, Int32);
+      HANDLE_TYPE(INT64, Int64);
+      HANDLE_TYPE(UINT32, UInt32);
+      HANDLE_TYPE(UINT64, UInt64);
+      HANDLE_TYPE(SINT32, SInt32);
+      HANDLE_TYPE(SINT64, SInt64);
+      HANDLE_TYPE(FIXED32, Fixed32);
+      HANDLE_TYPE(FIXED64, Fixed64);
+      HANDLE_TYPE(SFIXED32, SFixed32);
+      HANDLE_TYPE(SFIXED64, SFixed64);
+      HANDLE_TYPE(FLOAT, Float);
+      HANDLE_TYPE(DOUBLE, Double);
+      HANDLE_TYPE(BOOL, Bool);
+#undef HANDLE_TYPE
+
+      case WireFormatLite::TYPE_ENUM:
+        return internal::PackedEnumParserArg<T>(
+            MutableRawRepeatedField(number, extension.type, extension.is_packed,
+                                    extension.descriptor),
+            ptr, ctx, extension.enum_validity_check.func,
+            extension.enum_validity_check.arg, metadata, number);
+      case WireFormatLite::TYPE_STRING:
+      case WireFormatLite::TYPE_BYTES:
+      case WireFormatLite::TYPE_GROUP:
+      case WireFormatLite::TYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+        break;
+    }
+  } else {
+    switch (extension.type) {
+#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    uint64_t value;                                                         \
+    ptr = VarintParse(ptr, &value);                                         \
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_VARINT_TYPE(INT32, Int32);
+      HANDLE_VARINT_TYPE(INT64, Int64);
+      HANDLE_VARINT_TYPE(UINT32, UInt32);
+      HANDLE_VARINT_TYPE(UINT64, UInt64);
+      HANDLE_VARINT_TYPE(BOOL, Bool);
+#undef HANDLE_VARINT_TYPE
+#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    uint64_t val;                                                           \
+    ptr = VarintParse(ptr, &val);                                           \
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
+    auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
+      HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
+#undef HANDLE_SVARINT_TYPE
+#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    auto value = UnalignedLoad<CPPTYPE>(ptr);                               \
+    ptr += sizeof(CPPTYPE);                                                 \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32_t);
+      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64_t);
+      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32_t);
+      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64_t);
+      HANDLE_FIXED_TYPE(FLOAT, Float, float);
+      HANDLE_FIXED_TYPE(DOUBLE, Double, double);
+#undef HANDLE_FIXED_TYPE
+
+      case WireFormatLite::TYPE_ENUM: {
+        uint64_t val;
+        ptr = VarintParse(ptr, &val);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        int value = val;
+
+        if (!extension.enum_validity_check.func(
+                extension.enum_validity_check.arg, value)) {
+          WriteVarint(number, val, metadata->mutable_unknown_fields<T>());
+        } else if (extension.is_repeated) {
+          AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
+                  extension.descriptor);
+        } else {
+          SetEnum(number, WireFormatLite::TYPE_ENUM, value,
+                  extension.descriptor);
+        }
+        break;
+      }
+
+      case WireFormatLite::TYPE_BYTES:
+      case WireFormatLite::TYPE_STRING: {
+        std::string* value =
+            extension.is_repeated
+                ? AddString(number, WireFormatLite::TYPE_STRING,
+                            extension.descriptor)
+                : MutableString(number, WireFormatLite::TYPE_STRING,
+                                extension.descriptor);
+        int size = ReadSize(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        return ctx->ReadString(ptr, size, value);
+      }
+
+      case WireFormatLite::TYPE_GROUP: {
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
+        uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
+        return ctx->ParseGroup(value, ptr, tag);
+      }
+
+      case WireFormatLite::TYPE_MESSAGE: {
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
+        return ctx->ParseMessage(value, ptr);
+      }
+    }
+  }
+  return ptr;
+}
+
+template <typename Msg, typename T>
+const char* ExtensionSet::ParseMessageSetItemTmpl(
+    const char* ptr, const Msg* extendee, internal::InternalMetadata* metadata,
+    internal::ParseContext* ctx) {
+  std::string payload;
+  uint32_t type_id;
+  enum class State { kNoTag, kHasType, kHasPayload, kDone };
+  State state = State::kNoTag;
+
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag = static_cast<uint8_t>(*ptr++);
+    if (tag == WireFormatLite::kMessageSetTypeIdTag) {
+      uint64_t tmp;
+      ptr = ParseBigVarint(ptr, &tmp);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (state == State::kNoTag) {
+        type_id = tmp;
+        state = State::kHasType;
+      } else if (state == State::kHasPayload) {
+        type_id = tmp;
+        ExtensionInfo extension;
+        bool was_packed_on_wire;
+        if (!FindExtension(2, type_id, extendee, ctx, &extension,
+                           &was_packed_on_wire)) {
+          WriteLengthDelimited(type_id, payload,
+                               metadata->mutable_unknown_fields<T>());
+        } else {
+          MessageLite* value =
+              extension.is_repeated
+                  ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
+                               *extension.message_info.prototype,
+                               extension.descriptor)
+                  : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
+                                   *extension.message_info.prototype,
+                                   extension.descriptor);
+
+          const char* p;
+          // We can't use regular parse from string as we have to track
+          // proper recursion depth and descriptor pools.
+          ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
+          tmp_ctx.data().pool = ctx->data().pool;
+          tmp_ctx.data().factory = ctx->data().factory;
+          GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
+                                         tmp_ctx.EndedAtLimit());
+        }
+        state = State::kDone;
+      }
+    } else if (tag == WireFormatLite::kMessageSetMessageTag) {
+      if (state == State::kHasType) {
+        ptr = ParseFieldMaybeLazily(static_cast<uint64_t>(type_id) * 8 + 2, ptr,
+                                    extendee, metadata, ctx);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+        state = State::kDone;
+      } else {
+        std::string tmp;
+        int32_t size = ReadSize(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        ptr = ctx->ReadString(ptr, size, &tmp);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        if (state == State::kNoTag) {
+          payload = std::move(tmp);
+          state = State::kHasPayload;
+        }
+      }
+    } else {
+      ptr = ReadTag(ptr - 1, &tag);
+      if (tag == 0 || (tag & 7) == 4) {
+        ctx->SetLastTag(tag);
+        return ptr;
+      }
+      ptr = ParseField(tag, ptr, extendee, metadata, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+  }
+  return ptr;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
new file mode 100644
index 0000000..207e10c
--- /dev/null
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -0,0 +1,1385 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_mset.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/arena.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+using TestUtil::EqualsToSerialized;
+
+// This test closely mirrors third_party/protobuf/compiler/cpp/unittest.cc
+// except that it uses extensions rather than regular fields.
+
+TEST(ExtensionSetTest, Defaults) {
+  // Check that all default values are set correctly in the initial message.
+  unittest::TestAllExtensions message;
+
+  TestUtil::ExpectExtensionsClear(message);
+
+  // Messages should return pointers to default instances until first use.
+  // (This is not checked by ExpectClear() since it is not actually true after
+  // the fields have been set and then cleared.)
+  EXPECT_EQ(&unittest::OptionalGroup_extension::default_instance(),
+            &message.GetExtension(unittest::optionalgroup_extension));
+  EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
+            &message.GetExtension(unittest::optional_nested_message_extension));
+  EXPECT_EQ(
+      &unittest::ForeignMessage::default_instance(),
+      &message.GetExtension(unittest::optional_foreign_message_extension));
+  EXPECT_EQ(&unittest_import::ImportMessage::default_instance(),
+            &message.GetExtension(unittest::optional_import_message_extension));
+}
+
+TEST(ExtensionSetTest, Accessors) {
+  // Set every field to a unique value then go back and check all those
+  // values.
+  unittest::TestAllExtensions message;
+
+  TestUtil::SetAllExtensions(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+
+  TestUtil::ModifyRepeatedExtensions(&message);
+  TestUtil::ExpectRepeatedExtensionsModified(message);
+}
+
+TEST(ExtensionSetTest, Clear) {
+  // Set every field to a unique value, clear the message, then check that
+  // it is cleared.
+  unittest::TestAllExtensions message;
+
+  TestUtil::SetAllExtensions(&message);
+  message.Clear();
+  TestUtil::ExpectExtensionsClear(message);
+
+  // Make sure setting stuff again after clearing works.  (This takes slightly
+  // different code paths since the objects are reused.)
+  TestUtil::SetAllExtensions(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(ExtensionSetTest, ClearOneField) {
+  // Set every field to a unique value, then clear one value and insure that
+  // only that one value is cleared.
+  unittest::TestAllExtensions message;
+
+  TestUtil::SetAllExtensions(&message);
+  int64_t original_value =
+      message.GetExtension(unittest::optional_int64_extension);
+
+  // Clear the field and make sure it shows up as cleared.
+  message.ClearExtension(unittest::optional_int64_extension);
+  EXPECT_FALSE(message.HasExtension(unittest::optional_int64_extension));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_int64_extension));
+
+  // Other adjacent fields should not be cleared.
+  EXPECT_TRUE(message.HasExtension(unittest::optional_int32_extension));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_uint32_extension));
+
+  // Make sure if we set it again, then all fields are set.
+  message.SetExtension(unittest::optional_int64_extension, original_value);
+  TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(ExtensionSetTest, SetAllocatedExtension) {
+  unittest::TestAllExtensions message;
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_foreign_message_extension));
+  // Add a extension using SetAllocatedExtension
+  unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
+  message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+                                foreign_message);
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_foreign_message_extension));
+  EXPECT_EQ(foreign_message, message.MutableExtension(
+                                 unittest::optional_foreign_message_extension));
+  EXPECT_EQ(foreign_message, &message.GetExtension(
+                                 unittest::optional_foreign_message_extension));
+
+  // SetAllocatedExtension should delete the previously existing extension.
+  // (We reply on unittest to check memory leaks for this case)
+  message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+                                new unittest::ForeignMessage());
+
+  // SetAllocatedExtension with nullptr is equivalent to ClearExtenion.
+  message.SetAllocatedExtension(unittest::optional_foreign_message_extension,
+                                nullptr);
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_foreign_message_extension));
+}
+
+TEST(ExtensionSetTest, ReleaseExtension) {
+  proto2_wireformat_unittest::TestMessageSet message;
+  EXPECT_FALSE(message.HasExtension(
+      unittest::TestMessageSetExtension1::message_set_extension));
+  // Add a extension using SetAllocatedExtension
+  unittest::TestMessageSetExtension1* extension =
+      new unittest::TestMessageSetExtension1();
+  message.SetAllocatedExtension(
+      unittest::TestMessageSetExtension1::message_set_extension, extension);
+  EXPECT_TRUE(message.HasExtension(
+      unittest::TestMessageSetExtension1::message_set_extension));
+  // Release the extension using ReleaseExtension
+  unittest::TestMessageSetExtension1* released_extension =
+      message.ReleaseExtension(
+          unittest::TestMessageSetExtension1::message_set_extension);
+  EXPECT_EQ(extension, released_extension);
+  EXPECT_FALSE(message.HasExtension(
+      unittest::TestMessageSetExtension1::message_set_extension));
+  // ReleaseExtension will return the underlying object even after
+  // ClearExtension is called.
+  message.SetAllocatedExtension(
+      unittest::TestMessageSetExtension1::message_set_extension,
+      released_extension);
+  message.ClearExtension(
+      unittest::TestMessageSetExtension1::message_set_extension);
+  released_extension = message.ReleaseExtension(
+      unittest::TestMessageSetExtension1::message_set_extension);
+  EXPECT_TRUE(released_extension != nullptr);
+  delete released_extension;
+}
+
+TEST(ExtensionSetTest, ArenaUnsafeArenaSetAllocatedAndRelease) {
+  Arena arena;
+  unittest::TestAllExtensions* message =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  unittest::ForeignMessage extension;
+  message->UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension, &extension);
+  // No copy when set.
+  unittest::ForeignMessage* mutable_extension =
+      message->MutableExtension(unittest::optional_foreign_message_extension);
+  EXPECT_EQ(&extension, mutable_extension);
+  // No copy when unsafe released.
+  unittest::ForeignMessage* released_extension =
+      message->UnsafeArenaReleaseExtension(
+          unittest::optional_foreign_message_extension);
+  EXPECT_EQ(&extension, released_extension);
+  EXPECT_FALSE(
+      message->HasExtension(unittest::optional_foreign_message_extension));
+  // Set the ownership back and let the destructors run.  It should not take
+  // ownership, so this should not crash.
+  message->UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension, &extension);
+}
+
+TEST(ExtensionSetTest, UnsafeArenaSetAllocatedAndRelease) {
+  unittest::TestAllExtensions message;
+  unittest::ForeignMessage* extension = new unittest::ForeignMessage();
+  message.UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension, extension);
+  // No copy when set.
+  unittest::ForeignMessage* mutable_extension =
+      message.MutableExtension(unittest::optional_foreign_message_extension);
+  EXPECT_EQ(extension, mutable_extension);
+  // No copy when unsafe released.
+  unittest::ForeignMessage* released_extension =
+      message.UnsafeArenaReleaseExtension(
+          unittest::optional_foreign_message_extension);
+  EXPECT_EQ(extension, released_extension);
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_foreign_message_extension));
+  // Set the ownership back and let the destructors run.  It should take
+  // ownership, so this should not leak.
+  message.UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension, extension);
+}
+
+TEST(ExtensionSetTest, ArenaUnsafeArenaReleaseOfHeapAlloc) {
+  Arena arena;
+  unittest::TestAllExtensions* message =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  unittest::ForeignMessage* extension = new unittest::ForeignMessage;
+  message->SetAllocatedExtension(unittest::optional_foreign_message_extension,
+                                 extension);
+  // The arena should maintain ownership of the heap allocated proto because we
+  // used UnsafeArenaReleaseExtension.  The leak checker will ensure this.
+  unittest::ForeignMessage* released_extension =
+      message->UnsafeArenaReleaseExtension(
+          unittest::optional_foreign_message_extension);
+  EXPECT_EQ(extension, released_extension);
+  EXPECT_FALSE(
+      message->HasExtension(unittest::optional_foreign_message_extension));
+}
+
+
+TEST(ExtensionSetTest, CopyFrom) {
+  unittest::TestAllExtensions message1, message2;
+
+  TestUtil::SetAllExtensions(&message1);
+  message2.CopyFrom(message1);
+  TestUtil::ExpectAllExtensionsSet(message2);
+  message2.CopyFrom(message1);  // exercise copy when fields already exist
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, CopyFromPacked) {
+  unittest::TestPackedExtensions message1, message2;
+
+  TestUtil::SetPackedExtensions(&message1);
+  message2.CopyFrom(message1);
+  TestUtil::ExpectPackedExtensionsSet(message2);
+  message2.CopyFrom(message1);  // exercise copy when fields already exist
+  TestUtil::ExpectPackedExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, CopyFromUpcasted) {
+  unittest::TestAllExtensions message1, message2;
+  const Message& upcasted_message = message1;
+
+  TestUtil::SetAllExtensions(&message1);
+  message2.CopyFrom(upcasted_message);
+  TestUtil::ExpectAllExtensionsSet(message2);
+  // exercise copy when fields already exist
+  message2.CopyFrom(upcasted_message);
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, SwapWithEmpty) {
+  unittest::TestAllExtensions message1, message2;
+  TestUtil::SetAllExtensions(&message1);
+
+  TestUtil::ExpectAllExtensionsSet(message1);
+  TestUtil::ExpectExtensionsClear(message2);
+  message1.Swap(&message2);
+  TestUtil::ExpectAllExtensionsSet(message2);
+  TestUtil::ExpectExtensionsClear(message1);
+}
+
+TEST(ExtensionSetTest, SwapWithSelf) {
+  unittest::TestAllExtensions message;
+  TestUtil::SetAllExtensions(&message);
+
+  TestUtil::ExpectAllExtensionsSet(message);
+  message.Swap(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(ExtensionSetTest, SwapExtension) {
+  unittest::TestAllExtensions message1;
+  unittest::TestAllExtensions message2;
+
+  TestUtil::SetAllExtensions(&message1);
+  std::vector<const FieldDescriptor*> fields;
+
+  // Swap empty fields.
+  const Reflection* reflection = message1.GetReflection();
+  reflection->SwapFields(&message1, &message2, fields);
+  TestUtil::ExpectAllExtensionsSet(message1);
+  TestUtil::ExpectExtensionsClear(message2);
+
+  // Swap two extensions.
+  fields.push_back(reflection->FindKnownExtensionByNumber(12));
+  fields.push_back(reflection->FindKnownExtensionByNumber(25));
+  reflection->SwapFields(&message1, &message2, fields);
+
+  EXPECT_TRUE(message1.HasExtension(unittest::optional_int32_extension));
+  EXPECT_FALSE(message1.HasExtension(unittest::optional_double_extension));
+  EXPECT_FALSE(message1.HasExtension(unittest::optional_cord_extension));
+
+  EXPECT_FALSE(message2.HasExtension(unittest::optional_int32_extension));
+  EXPECT_TRUE(message2.HasExtension(unittest::optional_double_extension));
+  EXPECT_TRUE(message2.HasExtension(unittest::optional_cord_extension));
+}
+
+TEST(ExtensionSetTest, SwapExtensionWithEmpty) {
+  unittest::TestAllExtensions message1;
+  unittest::TestAllExtensions message2;
+  unittest::TestAllExtensions message3;
+
+  TestUtil::SetAllExtensions(&message3);
+
+  const Reflection* reflection = message3.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(message3, &fields);
+
+  reflection->SwapFields(&message1, &message2, fields);
+
+  TestUtil::ExpectExtensionsClear(message1);
+  TestUtil::ExpectExtensionsClear(message2);
+}
+
+TEST(ExtensionSetTest, SwapExtensionBothFull) {
+  unittest::TestAllExtensions message1;
+  unittest::TestAllExtensions message2;
+
+  TestUtil::SetAllExtensions(&message1);
+  TestUtil::SetAllExtensions(&message2);
+
+  const Reflection* reflection = message1.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(message1, &fields);
+
+  reflection->SwapFields(&message1, &message2, fields);
+
+  TestUtil::ExpectAllExtensionsSet(message1);
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, ArenaSetAllExtension) {
+  Arena arena1;
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  TestUtil::SetAllExtensions(message1);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+}
+
+TEST(ExtensionSetTest, ArenaCopyConstructor) {
+  Arena arena1;
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  TestUtil::SetAllExtensions(message1);
+  unittest::TestAllExtensions message2(*message1);
+  arena1.Reset();
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, ArenaMergeFrom) {
+  Arena arena1;
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  TestUtil::SetAllExtensions(message1);
+  unittest::TestAllExtensions message2;
+  message2.MergeFrom(*message1);
+  arena1.Reset();
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, ArenaMergeFromWithClearedExtensions) {
+  Arena arena;
+  {
+    auto* message1 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+    auto* message2 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+
+    // Set an extension and then clear it
+    message1->SetExtension(unittest::optional_int32_extension, 1);
+    message1->ClearExtension(unittest::optional_int32_extension);
+
+    // Since all extensions in message1 have been cleared, we should be able to
+    // merge it into message2 without allocating any additional memory.
+    uint64_t space_used_before_merge = arena.SpaceUsed();
+    message2->MergeFrom(*message1);
+    EXPECT_EQ(space_used_before_merge, arena.SpaceUsed());
+  }
+  {
+    // As more complicated case, let's have message1 and message2 share some
+    // uncleared extensions in common.
+    auto* message1 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+    auto* message2 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+
+    // Set int32 and uint32 on both messages.
+    message1->SetExtension(unittest::optional_int32_extension, 1);
+    message2->SetExtension(unittest::optional_int32_extension, 2);
+    message1->SetExtension(unittest::optional_uint32_extension, 1);
+    message2->SetExtension(unittest::optional_uint32_extension, 2);
+
+    // Set and clear int64 and uint64 on message1.
+    message1->SetExtension(unittest::optional_int64_extension, 0);
+    message1->ClearExtension(unittest::optional_int64_extension);
+    message1->SetExtension(unittest::optional_uint64_extension, 0);
+    message1->ClearExtension(unittest::optional_uint64_extension);
+
+    uint64_t space_used_before_merge = arena.SpaceUsed();
+    message2->MergeFrom(*message1);
+    EXPECT_EQ(space_used_before_merge, arena.SpaceUsed());
+  }
+}
+
+TEST(ExtensionSetTest, ArenaSetAllocatedMessageAndRelease) {
+  Arena arena;
+  unittest::TestAllExtensions* message =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  EXPECT_FALSE(
+      message->HasExtension(unittest::optional_foreign_message_extension));
+  // Add a extension using SetAllocatedExtension
+  unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
+  message->SetAllocatedExtension(unittest::optional_foreign_message_extension,
+                                 foreign_message);
+  // foreign_message is now owned by the arena.
+  EXPECT_EQ(foreign_message, message->MutableExtension(
+                                 unittest::optional_foreign_message_extension));
+
+  // Underlying message is copied, and returned.
+  unittest::ForeignMessage* released_message =
+      message->ReleaseExtension(unittest::optional_foreign_message_extension);
+  delete released_message;
+  EXPECT_FALSE(
+      message->HasExtension(unittest::optional_foreign_message_extension));
+}
+
+TEST(ExtensionSetTest, SwapExtensionBothFullWithArena) {
+  Arena arena1;
+  std::unique_ptr<Arena> arena2(new Arena());
+
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  unittest::TestAllExtensions* message2 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(arena2.get());
+
+  TestUtil::SetAllExtensions(message1);
+  TestUtil::SetAllExtensions(message2);
+  message1->SetExtension(unittest::optional_int32_extension, 1);
+  message2->SetExtension(unittest::optional_int32_extension, 2);
+  message1->Swap(message2);
+  EXPECT_EQ(2, message1->GetExtension(unittest::optional_int32_extension));
+  EXPECT_EQ(1, message2->GetExtension(unittest::optional_int32_extension));
+  // Re-set the original values so ExpectAllExtensionsSet is happy.
+  message1->SetExtension(unittest::optional_int32_extension, 101);
+  message2->SetExtension(unittest::optional_int32_extension, 101);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+  TestUtil::ExpectAllExtensionsSet(*message2);
+  arena2.reset(nullptr);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+  // Test corner cases, when one is empty and other is not.
+  Arena arena3, arena4;
+
+  unittest::TestAllExtensions* message3 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena3);
+  unittest::TestAllExtensions* message4 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena4);
+  TestUtil::SetAllExtensions(message3);
+  message3->Swap(message4);
+  arena3.Reset();
+  TestUtil::ExpectAllExtensionsSet(*message4);
+}
+
+TEST(ExtensionSetTest, SwapFieldsOfExtensionBothFullWithArena) {
+  Arena arena1;
+  Arena* arena2 = new Arena();
+
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  unittest::TestAllExtensions* message2 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(arena2);
+
+  TestUtil::SetAllExtensions(message1);
+  TestUtil::SetAllExtensions(message2);
+
+  const Reflection* reflection = message1->GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*message1, &fields);
+  reflection->SwapFields(message1, message2, fields);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+  TestUtil::ExpectAllExtensionsSet(*message2);
+  delete arena2;
+  TestUtil::ExpectAllExtensionsSet(*message1);
+}
+
+TEST(ExtensionSetTest, SwapExtensionWithSelf) {
+  unittest::TestAllExtensions message1;
+
+  TestUtil::SetAllExtensions(&message1);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1.GetReflection();
+  reflection->ListFields(message1, &fields);
+  reflection->SwapFields(&message1, &message1, fields);
+
+  TestUtil::ExpectAllExtensionsSet(message1);
+}
+
+TEST(ExtensionSetTest, SerializationToArray) {
+  // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
+  // compatibility of extensions.
+  //
+  // This checks serialization to a flat array by explicitly reserving space in
+  // the string and calling the generated message's
+  // SerializeWithCachedSizesToArray.
+  unittest::TestAllExtensions source;
+  unittest::TestAllTypes destination;
+  TestUtil::SetAllExtensions(&source);
+  size_t size = source.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  uint8_t* target = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = source.SerializeWithCachedSizesToArray(target);
+  EXPECT_EQ(size, end - target);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectAllFieldsSet(destination);
+}
+
+TEST(ExtensionSetTest, SerializationToStream) {
+  // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
+  // compatibility of extensions.
+  //
+  // This checks serialization to an output stream by creating an array output
+  // stream that can only buffer 1 byte at a time - this prevents the message
+  // from ever jumping to the fast path, ensuring that serialization happens via
+  // the CodedOutputStream.
+  unittest::TestAllExtensions source;
+  unittest::TestAllTypes destination;
+  TestUtil::SetAllExtensions(&source);
+  size_t size = source.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  {
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    source.SerializeWithCachedSizes(&output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectAllFieldsSet(destination);
+}
+
+TEST(ExtensionSetTest, PackedSerializationToArray) {
+  // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
+  // wire compatibility of extensions.
+  //
+  // This checks serialization to a flat array by explicitly reserving space in
+  // the string and calling the generated message's
+  // SerializeWithCachedSizesToArray.
+  unittest::TestPackedExtensions source;
+  unittest::TestPackedTypes destination;
+  TestUtil::SetPackedExtensions(&source);
+  size_t size = source.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  uint8_t* target = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = source.SerializeWithCachedSizesToArray(target);
+  EXPECT_EQ(size, end - target);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectPackedFieldsSet(destination);
+}
+
+TEST(ExtensionSetTest, PackedSerializationToStream) {
+  // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
+  // wire compatibility of extensions.
+  //
+  // This checks serialization to an output stream by creating an array output
+  // stream that can only buffer 1 byte at a time - this prevents the message
+  // from ever jumping to the fast path, ensuring that serialization happens via
+  // the CodedOutputStream.
+  unittest::TestPackedExtensions source;
+  unittest::TestPackedTypes destination;
+  TestUtil::SetPackedExtensions(&source);
+  size_t size = source.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  {
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    source.SerializeWithCachedSizes(&output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectPackedFieldsSet(destination);
+}
+
+TEST(ExtensionSetTest, NestedExtensionGroup) {
+  // Serialize as TestGroup and parse as TestGroupExtension.
+  unittest::TestGroup source;
+  unittest::TestGroupExtension destination;
+  std::string data;
+
+  source.mutable_optionalgroup()->set_a(117);
+  source.set_optional_foreign_enum(unittest::FOREIGN_BAZ);
+  source.SerializeToString(&data);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  EXPECT_TRUE(
+      destination
+          .GetExtension(unittest::TestNestedExtension::optionalgroup_extension)
+          .has_a());
+  EXPECT_EQ(117, destination
+                     .GetExtension(
+                         unittest::TestNestedExtension::optionalgroup_extension)
+                     .a());
+  EXPECT_TRUE(destination.HasExtension(
+      unittest::TestNestedExtension::optional_foreign_enum_extension));
+  EXPECT_EQ(
+      unittest::FOREIGN_BAZ,
+      destination.GetExtension(
+          unittest::TestNestedExtension::optional_foreign_enum_extension));
+}
+
+TEST(ExtensionSetTest, Parsing) {
+  // Serialize as TestAllTypes and parse as TestAllExtensions.
+  unittest::TestAllTypes source;
+  unittest::TestAllExtensions destination;
+  std::string data;
+
+  TestUtil::SetAllFields(&source);
+  source.SerializeToString(&data);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::SetOneofFields(&destination);
+  TestUtil::ExpectAllExtensionsSet(destination);
+}
+
+TEST(ExtensionSetTest, PackedParsing) {
+  // Serialize as TestPackedTypes and parse as TestPackedExtensions.
+  unittest::TestPackedTypes source;
+  unittest::TestPackedExtensions destination;
+  std::string data;
+
+  TestUtil::SetPackedFields(&source);
+  source.SerializeToString(&data);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectPackedExtensionsSet(destination);
+}
+
+TEST(ExtensionSetTest, PackedToUnpackedParsing) {
+  unittest::TestPackedTypes source;
+  unittest::TestUnpackedExtensions destination;
+  std::string data;
+
+  TestUtil::SetPackedFields(&source);
+  source.SerializeToString(&data);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectUnpackedExtensionsSet(destination);
+
+  // Reserialize
+  unittest::TestUnpackedTypes unpacked;
+  TestUtil::SetUnpackedFields(&unpacked);
+  // Serialized proto has to be the same size and parsed to the same message.
+  EXPECT_EQ(unpacked.SerializeAsString().size(),
+            destination.SerializeAsString().size());
+  EXPECT_TRUE(EqualsToSerialized(unpacked, destination.SerializeAsString()));
+
+  // Make sure we can add extensions.
+  destination.AddExtension(unittest::unpacked_int32_extension, 1);
+  destination.AddExtension(unittest::unpacked_enum_extension,
+                           protobuf_unittest::FOREIGN_BAR);
+}
+
+TEST(ExtensionSetTest, UnpackedToPackedParsing) {
+  unittest::TestUnpackedTypes source;
+  unittest::TestPackedExtensions destination;
+  std::string data;
+
+  TestUtil::SetUnpackedFields(&source);
+  source.SerializeToString(&data);
+  EXPECT_TRUE(destination.ParseFromString(data));
+  TestUtil::ExpectPackedExtensionsSet(destination);
+
+  // Reserialize
+  unittest::TestPackedTypes packed;
+  TestUtil::SetPackedFields(&packed);
+  // Serialized proto has to be the same size and parsed to the same message.
+  EXPECT_EQ(packed.SerializeAsString().size(),
+            destination.SerializeAsString().size());
+  EXPECT_TRUE(EqualsToSerialized(packed, destination.SerializeAsString()));
+
+  // Make sure we can add extensions.
+  destination.AddExtension(unittest::packed_int32_extension, 1);
+  destination.AddExtension(unittest::packed_enum_extension,
+                           protobuf_unittest::FOREIGN_BAR);
+}
+
+TEST(ExtensionSetTest, IsInitialized) {
+  // Test that IsInitialized() returns false if required fields in nested
+  // extensions are missing.
+  unittest::TestAllExtensions message;
+
+  EXPECT_TRUE(message.IsInitialized());
+
+  message.MutableExtension(unittest::TestRequired::single);
+  EXPECT_FALSE(message.IsInitialized());
+
+  message.MutableExtension(unittest::TestRequired::single)->set_a(1);
+  EXPECT_FALSE(message.IsInitialized());
+  message.MutableExtension(unittest::TestRequired::single)->set_b(2);
+  EXPECT_FALSE(message.IsInitialized());
+  message.MutableExtension(unittest::TestRequired::single)->set_c(3);
+  EXPECT_TRUE(message.IsInitialized());
+
+  message.AddExtension(unittest::TestRequired::multi);
+  EXPECT_FALSE(message.IsInitialized());
+
+  message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1);
+  EXPECT_FALSE(message.IsInitialized());
+  message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2);
+  EXPECT_FALSE(message.IsInitialized());
+  message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3);
+  EXPECT_TRUE(message.IsInitialized());
+}
+
+TEST(ExtensionSetTest, MutableString) {
+  // Test the mutable string accessors.
+  unittest::TestAllExtensions message;
+
+  message.MutableExtension(unittest::optional_string_extension)->assign("foo");
+  EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension));
+  EXPECT_EQ("foo", message.GetExtension(unittest::optional_string_extension));
+
+  message.AddExtension(unittest::repeated_string_extension)->assign("bar");
+  ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_extension));
+  EXPECT_EQ("bar",
+            message.GetExtension(unittest::repeated_string_extension, 0));
+}
+
+TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
+  // Scalar primitive extensions should increase the extension set size by a
+  // minimum of the size of the primitive type.
+#define TEST_SCALAR_EXTENSIONS_SPACE_USED(type, value)                       \
+  do {                                                                       \
+    unittest::TestAllExtensions message;                                     \
+    const int base_size = message.SpaceUsedLong();                           \
+    message.SetExtension(unittest::optional_##type##_extension, value);      \
+    int min_expected_size =                                                  \
+        base_size +                                                          \
+        sizeof(message.GetExtension(unittest::optional_##type##_extension)); \
+    EXPECT_LE(min_expected_size, message.SpaceUsedLong());                   \
+  } while (0)
+
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(int32, 101);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(int64, 102);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(uint32, 103);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(uint64, 104);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(sint32, 105);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(sint64, 106);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed32, 107);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed64, 108);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed32, 109);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed64, 110);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(float, 111);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(double, 112);
+  TEST_SCALAR_EXTENSIONS_SPACE_USED(bool, true);
+#undef TEST_SCALAR_EXTENSIONS_SPACE_USED
+  {
+    unittest::TestAllExtensions message;
+    const int base_size = message.SpaceUsedLong();
+    message.SetExtension(unittest::optional_nested_enum_extension,
+                         unittest::TestAllTypes::FOO);
+    int min_expected_size =
+        base_size +
+        sizeof(message.GetExtension(unittest::optional_nested_enum_extension));
+    EXPECT_LE(min_expected_size, message.SpaceUsedLong());
+  }
+  {
+    // Strings may cause extra allocations depending on their length; ensure
+    // that gets included as well.
+    unittest::TestAllExtensions message;
+    const int base_size = message.SpaceUsedLong();
+    const std::string s(
+        "this is a fairly large string that will cause some "
+        "allocation in order to store it in the extension");
+    message.SetExtension(unittest::optional_string_extension, s);
+    int min_expected_size = base_size + s.length();
+    EXPECT_LE(min_expected_size, message.SpaceUsedLong());
+  }
+  {
+    // Messages also have additional allocation that need to be counted.
+    unittest::TestAllExtensions message;
+    const int base_size = message.SpaceUsedLong();
+    unittest::ForeignMessage foreign;
+    foreign.set_c(42);
+    message.MutableExtension(unittest::optional_foreign_message_extension)
+        ->CopyFrom(foreign);
+    int min_expected_size = base_size + foreign.SpaceUsedLong();
+    EXPECT_LE(min_expected_size, message.SpaceUsedLong());
+  }
+
+  // Repeated primitive extensions will increase space used by at least a
+  // RepeatedField<T>, and will cause additional allocations when the array
+  // gets too big for the initial space.  Note, we explicitly allocate on the
+  // heap to avoid message-owned arenas.
+  // This macro:
+  //   - Adds a value to the repeated extension, then clears it, establishing
+  //     the base size.
+  //   - Adds a small number of values, testing that it doesn't increase the
+  //     SpaceUsedLong()
+  //   - Adds a large number of values (requiring allocation in the repeated
+  //     field), and ensures that that allocation is included in SpaceUsedLong()
+#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value)              \
+  do {                                                                         \
+    std::unique_ptr<unittest::TestAllExtensions> message(                      \
+        Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));           \
+    const size_t base_size = message->SpaceUsedLong();                         \
+    size_t min_expected_size = sizeof(RepeatedField<cpptype>) + base_size;     \
+    message->AddExtension(unittest::repeated_##type##_extension, value);       \
+    message->ClearExtension(unittest::repeated_##type##_extension);            \
+    const size_t empty_repeated_field_size = message->SpaceUsedLong();         \
+    EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type;          \
+    message->AddExtension(unittest::repeated_##type##_extension, value);       \
+    EXPECT_EQ(empty_repeated_field_size, message->SpaceUsedLong()) << #type;   \
+    message->ClearExtension(unittest::repeated_##type##_extension);            \
+    const size_t old_capacity =                                                \
+        message->GetRepeatedExtension(unittest::repeated_##type##_extension)   \
+            .Capacity();                                                       \
+    EXPECT_GE(old_capacity,                                                    \
+              (RepeatedFieldLowerClampLimit<cpptype, sizeof(void*)>()));       \
+    for (int i = 0; i < 16; ++i) {                                             \
+      message->AddExtension(unittest::repeated_##type##_extension, value);     \
+    }                                                                          \
+    int expected_size =                                                        \
+        sizeof(cpptype) *                                                      \
+            (message                                                           \
+                 ->GetRepeatedExtension(unittest::repeated_##type##_extension) \
+                 .Capacity() -                                                 \
+             old_capacity) +                                                   \
+        empty_repeated_field_size;                                             \
+    EXPECT_LE(expected_size, message->SpaceUsedLong()) << #type;               \
+  } while (0)
+
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(int32, int32_t, 101);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(int64, int64_t, 102);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32, uint32_t, 103);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64, uint64_t, 104);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32, int32_t, 105);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64, int64_t, 106);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32, uint32_t, 107);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64, uint64_t, 108);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32_t, 109);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64_t, 110);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(float, float, 111);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(double, double, 112);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(bool, bool, true);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(nested_enum, int,
+                                      unittest::TestAllTypes::FOO);
+#undef TEST_REPEATED_EXTENSIONS_SPACE_USED
+  // Repeated strings
+  {
+    std::unique_ptr<unittest::TestAllExtensions> message(
+        Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));
+    const size_t base_size = message->SpaceUsedLong();
+    size_t min_expected_size =
+        sizeof(RepeatedPtrField<std::string>) + base_size;
+    const std::string value(256, 'x');
+    // Once items are allocated, they may stick around even when cleared so
+    // without the hardcore memory management accessors there isn't a notion of
+    // the empty repeated field memory usage as there is with primitive types.
+    for (int i = 0; i < 16; ++i) {
+      message->AddExtension(unittest::repeated_string_extension, value);
+    }
+    min_expected_size +=
+        (sizeof(value) + value.size()) *
+        (16 - RepeatedFieldLowerClampLimit<void*, sizeof(void*)>());
+    EXPECT_LE(min_expected_size, message->SpaceUsedLong());
+  }
+  // Repeated messages
+  {
+    std::unique_ptr<unittest::TestAllExtensions> message(
+        Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));
+    const size_t base_size = message->SpaceUsedLong();
+    size_t min_expected_size =
+        sizeof(RepeatedPtrField<unittest::ForeignMessage>) + base_size;
+    unittest::ForeignMessage prototype;
+    prototype.set_c(2);
+    for (int i = 0; i < 16; ++i) {
+      *message->AddExtension(unittest::repeated_foreign_message_extension) =
+          prototype;
+    }
+    min_expected_size +=
+        (16 - RepeatedFieldLowerClampLimit<void*, sizeof(void*)>()) *
+        prototype.SpaceUsedLong();
+    EXPECT_LE(min_expected_size, message->SpaceUsedLong());
+  }
+}
+
+// N.B.: We do not test range-based for here because we remain C++03 compatible.
+template <typename T, typename M, typename ID>
+inline T SumAllExtensions(const M& message, ID extension, T zero) {
+  T sum = zero;
+  typename RepeatedField<T>::const_iterator iter =
+      message.GetRepeatedExtension(extension).begin();
+  typename RepeatedField<T>::const_iterator end =
+      message.GetRepeatedExtension(extension).end();
+  for (; iter != end; ++iter) {
+    sum += *iter;
+  }
+  return sum;
+}
+
+template <typename T, typename M, typename ID>
+inline void IncAllExtensions(M* message, ID extension, T val) {
+  typename RepeatedField<T>::iterator iter =
+      message->MutableRepeatedExtension(extension)->begin();
+  typename RepeatedField<T>::iterator end =
+      message->MutableRepeatedExtension(extension)->end();
+  for (; iter != end; ++iter) {
+    *iter += val;
+  }
+}
+
+TEST(ExtensionSetTest, RepeatedFields) {
+  unittest::TestAllExtensions message;
+
+  // Test empty repeated-field case (b/12926163)
+  ASSERT_EQ(
+      0,
+      message.GetRepeatedExtension(unittest::repeated_int32_extension).size());
+  ASSERT_EQ(
+      0, message.GetRepeatedExtension(unittest::repeated_nested_enum_extension)
+             .size());
+  ASSERT_EQ(
+      0,
+      message.GetRepeatedExtension(unittest::repeated_string_extension).size());
+  ASSERT_EQ(
+      0,
+      message.GetRepeatedExtension(unittest::repeated_nested_message_extension)
+          .size());
+
+  unittest::TestAllTypes::NestedMessage nested_message;
+  nested_message.set_bb(42);
+  unittest::TestAllTypes::NestedEnum nested_enum =
+      unittest::TestAllTypes::NestedEnum_MIN;
+
+  for (int i = 0; i < 10; ++i) {
+    message.AddExtension(unittest::repeated_int32_extension, 1);
+    message.AddExtension(unittest::repeated_int64_extension, 2);
+    message.AddExtension(unittest::repeated_uint32_extension, 3);
+    message.AddExtension(unittest::repeated_uint64_extension, 4);
+    message.AddExtension(unittest::repeated_sint32_extension, 5);
+    message.AddExtension(unittest::repeated_sint64_extension, 6);
+    message.AddExtension(unittest::repeated_fixed32_extension, 7);
+    message.AddExtension(unittest::repeated_fixed64_extension, 8);
+    message.AddExtension(unittest::repeated_sfixed32_extension, 7);
+    message.AddExtension(unittest::repeated_sfixed64_extension, 8);
+    message.AddExtension(unittest::repeated_float_extension, 9.0);
+    message.AddExtension(unittest::repeated_double_extension, 10.0);
+    message.AddExtension(unittest::repeated_bool_extension, true);
+    message.AddExtension(unittest::repeated_nested_enum_extension, nested_enum);
+    message.AddExtension(unittest::repeated_string_extension,
+                         std::string("test"));
+    message.AddExtension(unittest::repeated_bytes_extension,
+                         std::string("test\xFF"));
+    message.AddExtension(unittest::repeated_nested_message_extension)
+        ->CopyFrom(nested_message);
+    message.AddExtension(unittest::repeated_nested_enum_extension, nested_enum);
+  }
+
+  ASSERT_EQ(10, SumAllExtensions<int32_t>(
+                    message, unittest::repeated_int32_extension, 0));
+  IncAllExtensions<int32_t>(&message, unittest::repeated_int32_extension, 1);
+  ASSERT_EQ(20, SumAllExtensions<int32_t>(
+                    message, unittest::repeated_int32_extension, 0));
+
+  ASSERT_EQ(20, SumAllExtensions<int64_t>(
+                    message, unittest::repeated_int64_extension, 0));
+  IncAllExtensions<int64_t>(&message, unittest::repeated_int64_extension, 1);
+  ASSERT_EQ(30, SumAllExtensions<int64_t>(
+                    message, unittest::repeated_int64_extension, 0));
+
+  ASSERT_EQ(30, SumAllExtensions<uint32_t>(
+                    message, unittest::repeated_uint32_extension, 0));
+  IncAllExtensions<uint32_t>(&message, unittest::repeated_uint32_extension, 1);
+  ASSERT_EQ(40, SumAllExtensions<uint32_t>(
+                    message, unittest::repeated_uint32_extension, 0));
+
+  ASSERT_EQ(40, SumAllExtensions<uint64_t>(
+                    message, unittest::repeated_uint64_extension, 0));
+  IncAllExtensions<uint64_t>(&message, unittest::repeated_uint64_extension, 1);
+  ASSERT_EQ(50, SumAllExtensions<uint64_t>(
+                    message, unittest::repeated_uint64_extension, 0));
+
+  ASSERT_EQ(50, SumAllExtensions<int32_t>(
+                    message, unittest::repeated_sint32_extension, 0));
+  IncAllExtensions<int32_t>(&message, unittest::repeated_sint32_extension, 1);
+  ASSERT_EQ(60, SumAllExtensions<int32_t>(
+                    message, unittest::repeated_sint32_extension, 0));
+
+  ASSERT_EQ(60, SumAllExtensions<int64_t>(
+                    message, unittest::repeated_sint64_extension, 0));
+  IncAllExtensions<int64_t>(&message, unittest::repeated_sint64_extension, 1);
+  ASSERT_EQ(70, SumAllExtensions<int64_t>(
+                    message, unittest::repeated_sint64_extension, 0));
+
+  ASSERT_EQ(70, SumAllExtensions<uint32_t>(
+                    message, unittest::repeated_fixed32_extension, 0));
+  IncAllExtensions<uint32_t>(&message, unittest::repeated_fixed32_extension, 1);
+  ASSERT_EQ(80, SumAllExtensions<uint32_t>(
+                    message, unittest::repeated_fixed32_extension, 0));
+
+  ASSERT_EQ(80, SumAllExtensions<uint64_t>(
+                    message, unittest::repeated_fixed64_extension, 0));
+  IncAllExtensions<uint64_t>(&message, unittest::repeated_fixed64_extension, 1);
+  ASSERT_EQ(90, SumAllExtensions<uint64_t>(
+                    message, unittest::repeated_fixed64_extension, 0));
+
+  // Usually, floating-point arithmetic cannot be trusted to be exact, so it is
+  // a Bad Idea to assert equality in a test like this. However, we're dealing
+  // with integers with a small number of significant mantissa bits, so we
+  // should actually have exact precision here.
+  ASSERT_EQ(90, SumAllExtensions<float>(message,
+                                        unittest::repeated_float_extension, 0));
+  IncAllExtensions<float>(&message, unittest::repeated_float_extension, 1);
+  ASSERT_EQ(100, SumAllExtensions<float>(
+                     message, unittest::repeated_float_extension, 0));
+
+  ASSERT_EQ(100, SumAllExtensions<double>(
+                     message, unittest::repeated_double_extension, 0));
+  IncAllExtensions<double>(&message, unittest::repeated_double_extension, 1);
+  ASSERT_EQ(110, SumAllExtensions<double>(
+                     message, unittest::repeated_double_extension, 0));
+
+  RepeatedPtrField<std::string>::iterator string_iter;
+  RepeatedPtrField<std::string>::iterator string_end;
+  for (string_iter =
+           message
+               .MutableRepeatedExtension(unittest::repeated_string_extension)
+               ->begin(),
+      string_end =
+           message
+               .MutableRepeatedExtension(unittest::repeated_string_extension)
+               ->end();
+       string_iter != string_end; ++string_iter) {
+    *string_iter += "test";
+  }
+  RepeatedPtrField<std::string>::const_iterator string_const_iter;
+  RepeatedPtrField<std::string>::const_iterator string_const_end;
+  for (string_const_iter =
+           message.GetRepeatedExtension(unittest::repeated_string_extension)
+               .begin(),
+      string_const_end =
+           message.GetRepeatedExtension(unittest::repeated_string_extension)
+               .end();
+       string_iter != string_end; ++string_iter) {
+    ASSERT_TRUE(*string_iter == "testtest");
+  }
+
+  RepeatedField<unittest::TestAllTypes_NestedEnum>::iterator enum_iter;
+  RepeatedField<unittest::TestAllTypes_NestedEnum>::iterator enum_end;
+  for (enum_iter = message
+                       .MutableRepeatedExtension(
+                           unittest::repeated_nested_enum_extension)
+                       ->begin(),
+      enum_end = message
+                     .MutableRepeatedExtension(
+                         unittest::repeated_nested_enum_extension)
+                     ->end();
+       enum_iter != enum_end; ++enum_iter) {
+    *enum_iter = unittest::TestAllTypes::NestedEnum_MAX;
+  }
+  RepeatedField<unittest::TestAllTypes_NestedEnum>::const_iterator
+      enum_const_iter;
+  RepeatedField<unittest::TestAllTypes_NestedEnum>::const_iterator
+      enum_const_end;
+  for (enum_const_iter =
+           message
+               .GetRepeatedExtension(unittest::repeated_nested_enum_extension)
+               .begin(),
+      enum_const_end =
+           message
+               .GetRepeatedExtension(unittest::repeated_nested_enum_extension)
+               .end();
+       enum_const_iter != enum_const_end; ++enum_const_iter) {
+    ASSERT_EQ(*enum_const_iter, unittest::TestAllTypes::NestedEnum_MAX);
+  }
+
+  RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::iterator msg_iter;
+  RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::iterator msg_end;
+  for (msg_iter = message
+                      .MutableRepeatedExtension(
+                          unittest::repeated_nested_message_extension)
+                      ->begin(),
+      msg_end = message
+                    .MutableRepeatedExtension(
+                        unittest::repeated_nested_message_extension)
+                    ->end();
+       msg_iter != msg_end; ++msg_iter) {
+    msg_iter->set_bb(1234);
+  }
+  RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::const_iterator
+      msg_const_iter;
+  RepeatedPtrField<unittest::TestAllTypes_NestedMessage>::const_iterator
+      msg_const_end;
+  for (msg_const_iter = message
+                            .GetRepeatedExtension(
+                                unittest::repeated_nested_message_extension)
+                            .begin(),
+      msg_const_end = message
+                          .GetRepeatedExtension(
+                              unittest::repeated_nested_message_extension)
+                          .end();
+       msg_const_iter != msg_const_end; ++msg_const_iter) {
+    ASSERT_EQ(msg_const_iter->bb(), 1234);
+  }
+
+  // Test one primitive field.
+  for (auto& x :
+       *message.MutableRepeatedExtension(unittest::repeated_int32_extension)) {
+    x = 4321;
+  }
+  for (const auto& x :
+       message.GetRepeatedExtension(unittest::repeated_int32_extension)) {
+    ASSERT_EQ(x, 4321);
+  }
+  // Test one string field.
+  for (auto& x :
+       *message.MutableRepeatedExtension(unittest::repeated_string_extension)) {
+    x = "test_range_based_for";
+  }
+  for (const auto& x :
+       message.GetRepeatedExtension(unittest::repeated_string_extension)) {
+    ASSERT_TRUE(x == "test_range_based_for");
+  }
+  // Test one message field.
+  for (auto& x : *message.MutableRepeatedExtension(
+           unittest::repeated_nested_message_extension)) {
+    x.set_bb(4321);
+  }
+  for (const auto& x : *message.MutableRepeatedExtension(
+           unittest::repeated_nested_message_extension)) {
+    ASSERT_EQ(x.bb(), 4321);
+  }
+}
+
+// From b/12926163
+TEST(ExtensionSetTest, AbsentExtension) {
+  unittest::TestAllExtensions message;
+  message.MutableRepeatedExtension(unittest::repeated_nested_message_extension)
+      ->Add()
+      ->set_bb(123);
+  ASSERT_EQ(1,
+            message.ExtensionSize(unittest::repeated_nested_message_extension));
+  EXPECT_EQ(123,
+            message.GetExtension(unittest::repeated_nested_message_extension, 0)
+                .bb());
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST(ExtensionSetTest, InvalidEnumDeath) {
+  unittest::TestAllExtensions message;
+  EXPECT_DEBUG_DEATH(
+      message.SetExtension(unittest::optional_foreign_enum_extension,
+                           static_cast<unittest::ForeignEnum>(53)),
+      "IsValid");
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST(ExtensionSetTest, DynamicExtensions) {
+  // Test adding a dynamic extension to a compiled-in message object.
+
+  FileDescriptorProto dynamic_proto;
+  dynamic_proto.set_name("dynamic_extensions_test.proto");
+  dynamic_proto.add_dependency(
+      unittest::TestAllExtensions::descriptor()->file()->name());
+  dynamic_proto.set_package("dynamic_extensions");
+
+  // Copy the fields and nested types from TestDynamicExtensions into our new
+  // proto, converting the fields into extensions.
+  const Descriptor* template_descriptor =
+      unittest::TestDynamicExtensions::descriptor();
+  DescriptorProto template_descriptor_proto;
+  template_descriptor->CopyTo(&template_descriptor_proto);
+  dynamic_proto.mutable_message_type()->MergeFrom(
+      template_descriptor_proto.nested_type());
+  dynamic_proto.mutable_enum_type()->MergeFrom(
+      template_descriptor_proto.enum_type());
+  dynamic_proto.mutable_extension()->MergeFrom(
+      template_descriptor_proto.field());
+
+  // For each extension that we added...
+  for (int i = 0; i < dynamic_proto.extension_size(); i++) {
+    // Set its extendee to TestAllExtensions.
+    FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i);
+    extension->set_extendee(
+        unittest::TestAllExtensions::descriptor()->full_name());
+
+    // If the field refers to one of the types nested in TestDynamicExtensions,
+    // make it refer to the type in our dynamic proto instead.
+    std::string prefix = "." + template_descriptor->full_name() + ".";
+    if (extension->has_type_name()) {
+      std::string* type_name = extension->mutable_type_name();
+      if (HasPrefixString(*type_name, prefix)) {
+        type_name->replace(0, prefix.size(), ".dynamic_extensions.");
+      }
+    }
+  }
+
+  // Now build the file, using the generated pool as an underlay.
+  DescriptorPool dynamic_pool(DescriptorPool::generated_pool());
+  const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto);
+  ASSERT_TRUE(file != nullptr);
+  DynamicMessageFactory dynamic_factory(&dynamic_pool);
+  dynamic_factory.SetDelegateToGeneratedFactory(true);
+
+  // Construct a message that we can parse with the extensions we defined.
+  // Since the extensions were based off of the fields of TestDynamicExtensions,
+  // we can use that message to create this test message.
+  std::string data;
+  unittest::TestDynamicExtensions dynamic_extension;
+  {
+    unittest::TestDynamicExtensions message;
+    message.set_scalar_extension(123);
+    message.set_enum_extension(unittest::FOREIGN_BAR);
+    message.set_dynamic_enum_extension(
+        unittest::TestDynamicExtensions::DYNAMIC_BAZ);
+    message.mutable_message_extension()->set_c(456);
+    message.mutable_dynamic_message_extension()->set_dynamic_field(789);
+    message.add_repeated_extension("foo");
+    message.add_repeated_extension("bar");
+    message.add_packed_extension(12);
+    message.add_packed_extension(-34);
+    message.add_packed_extension(56);
+    message.add_packed_extension(-78);
+
+    // Also add some unknown fields.
+
+    // An unknown enum value (for a known field).
+    message.mutable_unknown_fields()->AddVarint(
+        unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber,
+        12345);
+    // A regular unknown field.
+    message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown");
+
+    message.SerializeToString(&data);
+    dynamic_extension = message;
+  }
+
+  // Now we can parse this using our dynamic extension definitions...
+  unittest::TestAllExtensions message;
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
+    ASSERT_TRUE(message.ParseFromCodedStream(&input));
+    ASSERT_TRUE(input.ConsumedEntireMessage());
+  }
+
+  // Can we print it?
+  std::string message_text;
+  TextFormat::PrintToString(message, &message_text);
+  EXPECT_EQ(
+      "[dynamic_extensions.scalar_extension]: 123\n"
+      "[dynamic_extensions.enum_extension]: FOREIGN_BAR\n"
+      "[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n"
+      "[dynamic_extensions.message_extension] {\n"
+      "  c: 456\n"
+      "}\n"
+      "[dynamic_extensions.dynamic_message_extension] {\n"
+      "  dynamic_field: 789\n"
+      "}\n"
+      "[dynamic_extensions.repeated_extension]: \"foo\"\n"
+      "[dynamic_extensions.repeated_extension]: \"bar\"\n"
+      "[dynamic_extensions.packed_extension]: 12\n"
+      "[dynamic_extensions.packed_extension]: -34\n"
+      "[dynamic_extensions.packed_extension]: 56\n"
+      "[dynamic_extensions.packed_extension]: -78\n"
+      "2002: 12345\n"
+      "54321: \"unknown\"\n",
+      message_text);
+
+  // Can we serialize it?
+  EXPECT_TRUE(
+      EqualsToSerialized(dynamic_extension, message.SerializeAsString()));
+
+  // What if we parse using the reflection-based parser?
+  {
+    unittest::TestAllExtensions message2;
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
+    ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2));
+    ASSERT_TRUE(input.ConsumedEntireMessage());
+    EXPECT_EQ(message.DebugString(), message2.DebugString());
+  }
+
+  // Are the embedded generated types actually using the generated objects?
+  {
+    const FieldDescriptor* message_extension =
+        file->FindExtensionByName("message_extension");
+    ASSERT_TRUE(message_extension != nullptr);
+    const Message& sub_message =
+        message.GetReflection()->GetMessage(message, message_extension);
+    const unittest::ForeignMessage* typed_sub_message =
+#if PROTOBUF_RTTI
+        dynamic_cast<const unittest::ForeignMessage*>(&sub_message);
+#else
+        static_cast<const unittest::ForeignMessage*>(&sub_message);
+#endif
+    ASSERT_TRUE(typed_sub_message != nullptr);
+    EXPECT_EQ(456, typed_sub_message->c());
+  }
+
+  // What does GetMessage() return for the embedded dynamic type if it isn't
+  // present?
+  {
+    const FieldDescriptor* dynamic_message_extension =
+        file->FindExtensionByName("dynamic_message_extension");
+    ASSERT_TRUE(dynamic_message_extension != nullptr);
+    const Message& parent = unittest::TestAllExtensions::default_instance();
+    const Message& sub_message = parent.GetReflection()->GetMessage(
+        parent, dynamic_message_extension, &dynamic_factory);
+    const Message* prototype =
+        dynamic_factory.GetPrototype(dynamic_message_extension->message_type());
+    EXPECT_EQ(prototype, &sub_message);
+  }
+}
+
+TEST(ExtensionSetTest, BoolExtension) {
+  unittest::TestAllExtensions msg;
+  uint8_t wire_bytes[2] = {13 * 8, 42 /* out of bounds payload for bool */};
+  EXPECT_TRUE(msg.ParseFromArray(wire_bytes, 2));
+  EXPECT_TRUE(msg.GetExtension(protobuf_unittest::optional_bool_extension));
+}
+
+TEST(ExtensionSetTest, ConstInit) {
+  PROTOBUF_CONSTINIT static ExtensionSet set{};
+  EXPECT_EQ(set.NumExtensions(), 0);
+}
+
+TEST(ExtensionSetTest, ExtensionSetSpaceUsed) {
+  unittest::TestAllExtensions msg;
+  size_t l = msg.SpaceUsedLong();
+  msg.SetExtension(unittest::optional_int32_extension, 100);
+  unittest::TestAllExtensions msg2(msg);
+  size_t l2 = msg2.SpaceUsedLong();
+  msg.ClearExtension(unittest::optional_int32_extension);
+  unittest::TestAllExtensions msg3(msg);
+  size_t l3 = msg3.SpaceUsedLong();
+  EXPECT_TRUE((l2 - l) > (l3 - l));
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/field_access_listener.h b/src/google/protobuf/field_access_listener.h
new file mode 100644
index 0000000..47422e6
--- /dev/null
+++ b/src/google/protobuf/field_access_listener.h
@@ -0,0 +1,172 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_FIELD_ACCESS_LISTENER_H__
+#define GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
+
+#include <cstddef>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message_lite.h>
+
+
+namespace google {
+namespace protobuf {
+
+// A default/no-op implementation of message hooks.
+//
+// See go/statically-dispatched-message-hooks for details.
+template <typename Proto>
+struct NoOpAccessListener {
+  // Number of fields are provided at compile time for the trackers to be able
+  // to have stack allocated bitmaps for the fields. This is useful for
+  // performance critical trackers. This is also to avoid cyclic dependencies
+  // if the number of fields is needed.
+  static constexpr int kFields = Proto::_kInternalFieldNumber;
+  // Default constructor is called during the static global initialization of
+  // the program.
+  // We provide a pointer to extract the name of the proto not to get cyclic
+  // dependencies on GetDescriptor() and OnGetMetadata() calls. If you want
+  // to differentiate the protos during the runtime before the start of the
+  // program, use this functor to get its name. We either way need it for
+  // LITE_RUNTIME protos as they don't have descriptors at all.
+  explicit NoOpAccessListener(StringPiece (*name_extractor)()) {}
+  // called repeatedly during serialization/deserialization/ByteSize of
+  // Reflection as:
+  //   AccessListener<MessageT>::OnSerialize(this);
+  static void OnSerialize(const MessageLite* msg) {}
+  static void OnDeserialize(const MessageLite* msg) {}
+  static void OnByteSize(const MessageLite* msg) {}
+  static void OnMergeFrom(const MessageLite* to, const MessageLite* from) {}
+
+  // NOTE: This function can be called pre-main. Make sure it does not make
+  // the state of the listener invalid.
+  static void OnGetMetadata() {}
+
+  // called from accessors as:
+  //   AccessListener<MessageT>::On$operation(this, &field_storage_);
+  // If you need to override this with type, in your hook implementation
+  // introduce
+  // template <int kFieldNum, typename T>
+  // static void On$operation(const MessageLite* msg,
+  //                          const T* field) {}
+  // And overloads for std::nullptr_t for incomplete types such as Messages,
+  // Maps. Extract them using reflection if you need. Consequently, second
+  // argument can be null pointer.
+  // For an example, see proto_hooks/testing/memory_test_field_listener.h
+  // And argument template deduction will deduce the type itself without
+  // changing the generated code.
+
+  // add_<field>(f)
+  template <int kFieldNum>
+  static void OnAdd(const MessageLite* msg, const void* field) {}
+
+  // add_<field>()
+  template <int kFieldNum>
+  static void OnAddMutable(const MessageLite* msg, const void* field) {}
+
+  // <field>() and <repeated_field>(i)
+  template <int kFieldNum>
+  static void OnGet(const MessageLite* msg, const void* field) {}
+
+  // clear_<field>()
+  template <int kFieldNum>
+  static void OnClear(const MessageLite* msg, const void* field) {}
+
+  // has_<field>()
+  template <int kFieldNum>
+  static void OnHas(const MessageLite* msg, const void* field) {}
+
+  // <repeated_field>()
+  template <int kFieldNum>
+  static void OnList(const MessageLite* msg, const void* field) {}
+
+  // mutable_<field>()
+  template <int kFieldNum>
+  static void OnMutable(const MessageLite* msg, const void* field) {}
+
+  // mutable_<repeated_field>()
+  template <int kFieldNum>
+  static void OnMutableList(const MessageLite* msg, const void* field) {}
+
+  // release_<field>()
+  template <int kFieldNum>
+  static void OnRelease(const MessageLite* msg, const void* field) {}
+
+  // set_<field>() and set_<repeated_field>(i)
+  template <int kFieldNum>
+  static void OnSet(const MessageLite* msg, const void* field) {}
+
+  // <repeated_field>_size()
+  template <int kFieldNum>
+  static void OnSize(const MessageLite* msg, const void* field) {}
+
+  static void OnHasExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  // TODO(b/190614678): Support clear in the proto compiler.
+  static void OnClearExtension(const MessageLite* msg, int extension_tag,
+                               const void* field) {}
+  static void OnExtensionSize(const MessageLite* msg, int extension_tag,
+                              const void* field) {}
+  static void OnGetExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnMutableExtension(const MessageLite* msg, int extension_tag,
+                                 const void* field) {}
+  static void OnSetExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnReleaseExtension(const MessageLite* msg, int extension_tag,
+                                 const void* field) {}
+  static void OnAddExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnAddMutableExtension(const MessageLite* msg, int extension_tag,
+                                    const void* field) {}
+  static void OnListExtension(const MessageLite* msg, int extension_tag,
+                              const void* field) {}
+  static void OnMutableListExtension(const MessageLite* msg, int extension_tag,
+                                     const void* field) {}
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#ifndef REPLACE_PROTO_LISTENER_IMPL
+namespace google {
+namespace protobuf {
+template <class T>
+using AccessListener = NoOpAccessListener<T>;
+}  // namespace protobuf
+}  // namespace google
+#else
+// You can put your implementations of hooks/listeners here.
+// All hooks are subject to approval by protobuf-team@.
+
+#endif  // !REPLACE_PROTO_LISTENER_IMPL
+
+#endif  // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
new file mode 100644
index 0000000..7860bfb
--- /dev/null
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -0,0 +1,284 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#include <google/protobuf/field_mask.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR FieldMask::FieldMask(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.paths_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FieldMaskDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldMaskDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldMaskDefaultTypeInternal() {}
+  union {
+    FieldMask _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldMask, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldMask, _impl_.paths_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldMask)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_FieldMask_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n google/protobuf/field_mask.proto\022\017goog"
+  "le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB"
+  "\205\001\n\023com.google.protobufB\016FieldMaskProtoP"
+  "\001Z2google.golang.org/protobuf/types/know"
+  "n/fieldmaskpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
+  ".WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+    false, false, 223, descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto,
+    "google/protobuf/field_mask.proto",
+    &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ffield_5fmask_2eproto(&descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class FieldMask::_Internal {
+ public:
+};
+
+FieldMask::FieldMask(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldMask)
+}
+FieldMask::FieldMask(const FieldMask& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FieldMask* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.paths_){from._impl_.paths_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldMask)
+}
+
+inline void FieldMask::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.paths_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+FieldMask::~FieldMask() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldMask)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FieldMask::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.paths_.~RepeatedPtrField();
+}
+
+void FieldMask::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FieldMask::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.paths_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FieldMask::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated string paths = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_paths();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.FieldMask.paths"));
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FieldMask::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated string paths = 1;
+  for (int i = 0, n = this->_internal_paths_size(); i < n; i++) {
+    const auto& s = this->_internal_paths(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.FieldMask.paths");
+    target = stream->WriteString(1, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldMask)
+  return target;
+}
+
+size_t FieldMask::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated string paths = 1;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.paths_.size());
+  for (int i = 0, n = _impl_.paths_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.paths_.Get(i));
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldMask::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FieldMask::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldMask::GetClassData() const { return &_class_data_; }
+
+
+void FieldMask::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FieldMask*>(&to_msg);
+  auto& from = static_cast<const FieldMask&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.paths_.MergeFrom(from._impl_.paths_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FieldMask::CopyFrom(const FieldMask& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldMask)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldMask::IsInitialized() const {
+  return true;
+}
+
+void FieldMask::InternalSwap(FieldMask* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.paths_.InternalSwap(&other->_impl_.paths_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FieldMask::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter, &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldMask*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldMask >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldMask >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
new file mode 100644
index 0000000..20a3d4c
--- /dev/null
+++ b/src/google/protobuf/field_mask.pb.h
@@ -0,0 +1,317 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ffield_5fmask_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class FieldMask;
+struct FieldMaskDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldMask* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldMask>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT FieldMask final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldMask) */ {
+ public:
+  inline FieldMask() : FieldMask(nullptr) {}
+  ~FieldMask() override;
+  explicit PROTOBUF_CONSTEXPR FieldMask(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FieldMask(const FieldMask& from);
+  FieldMask(FieldMask&& from) noexcept
+    : FieldMask() {
+    *this = ::std::move(from);
+  }
+
+  inline FieldMask& operator=(const FieldMask& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FieldMask& operator=(FieldMask&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FieldMask& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FieldMask* internal_default_instance() {
+    return reinterpret_cast<const FieldMask*>(
+               &_FieldMask_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(FieldMask& a, FieldMask& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FieldMask* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldMask* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FieldMask* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FieldMask>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FieldMask& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FieldMask& from) {
+    FieldMask::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FieldMask* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FieldMask";
+  }
+  protected:
+  explicit FieldMask(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPathsFieldNumber = 1,
+  };
+  // repeated string paths = 1;
+  int paths_size() const;
+  private:
+  int _internal_paths_size() const;
+  public:
+  void clear_paths();
+  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, 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(std::string&& value);
+  void add_paths(const char* value);
+  void add_paths(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& paths() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_paths();
+  private:
+  const std::string& _internal_paths(int index) const;
+  std::string* _internal_add_paths();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldMask)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> paths_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// FieldMask
+
+// repeated string paths = 1;
+inline int FieldMask::_internal_paths_size() const {
+  return _impl_.paths_.size();
+}
+inline int FieldMask::paths_size() const {
+  return _internal_paths_size();
+}
+inline void FieldMask::clear_paths() {
+  _impl_.paths_.Clear();
+}
+inline std::string* FieldMask::add_paths() {
+  std::string* _s = _internal_add_paths();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths)
+  return _s;
+}
+inline const std::string& FieldMask::_internal_paths(int index) const {
+  return _impl_.paths_.Get(index);
+}
+inline const std::string& FieldMask::paths(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldMask.paths)
+  return _internal_paths(index);
+}
+inline std::string* FieldMask::mutable_paths(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldMask.paths)
+  return _impl_.paths_.Mutable(index);
+}
+inline void FieldMask::set_paths(int index, const std::string& value) {
+  _impl_.paths_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::set_paths(int index, std::string&& value) {
+  _impl_.paths_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::set_paths(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.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) {
+  _impl_.paths_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths)
+}
+inline std::string* FieldMask::_internal_add_paths() {
+  return _impl_.paths_.Add();
+}
+inline void FieldMask::add_paths(const std::string& value) {
+  _impl_.paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(std::string&& value) {
+  _impl_.paths_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.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) {
+  _impl_.paths_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FieldMask.paths)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+FieldMask::paths() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldMask.paths)
+  return _impl_.paths_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+FieldMask::mutable_paths() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldMask.paths)
+  return &_impl_.paths_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
new file mode 100644
index 0000000..6b5104f
--- /dev/null
+++ b/src/google/protobuf/field_mask.proto
@@ -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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldMaskProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb";
+option cc_enable_arenas = true;
+
+// `FieldMask` represents a set of symbolic field paths, for example:
+//
+//     paths: "f.a"
+//     paths: "f.b.d"
+//
+// Here `f` represents a field in some root message, `a` and `b`
+// fields in the message found in `f`, and `d` a field found in the
+// message in `f.b`.
+//
+// Field masks are used to specify a subset of fields that should be
+// returned by a get operation or modified by an update operation.
+// Field masks also have a custom JSON encoding (see below).
+//
+// # Field Masks in Projections
+//
+// When used in the context of a projection, a response message or
+// sub-message is filtered by the API to only contain those fields as
+// specified in the mask. For example, if the mask in the previous
+// example is applied to a response message as follows:
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//         x : 2
+//       }
+//       y : 13
+//     }
+//     z: 8
+//
+// The result will not contain specific values for fields x,y and z
+// (their value will be set to the default, and omitted in proto text
+// output):
+//
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//       }
+//     }
+//
+// A repeated field is not allowed except at the last position of a
+// paths string.
+//
+// If a FieldMask object is not present in a get operation, the
+// operation applies to all fields (as if a FieldMask of all fields
+// had been specified).
+//
+// Note that a field mask does not necessarily apply to the
+// top-level response message. In case of a REST get operation, the
+// field mask applies directly to the response, but in case of a REST
+// list operation, the mask instead applies to each individual message
+// in the returned resource list. In case of a REST custom method,
+// other definitions may be used. Where the mask applies will be
+// clearly documented together with its declaration in the API.  In
+// any case, the effect on the returned resource/resources is required
+// behavior for APIs.
+//
+// # Field Masks in Update Operations
+//
+// A field mask in update operations specifies which fields of the
+// targeted resource are going to be updated. The API is required
+// to only change the values of the fields as specified in the mask
+// and leave the others untouched. If a resource is passed in to
+// describe the updated values, the API ignores the values of all
+// fields not covered by the mask.
+//
+// If a repeated field is specified for an update operation, new values will
+// be appended to the existing repeated field in the target resource. Note that
+// a repeated field is only allowed in the last position of a `paths` string.
+//
+// If a sub-message is specified in the last position of the field mask for an
+// update operation, then new value will be merged into the existing sub-message
+// in the target resource.
+//
+// For example, given the target message:
+//
+//     f {
+//       b {
+//         d: 1
+//         x: 2
+//       }
+//       c: [1]
+//     }
+//
+// And an update message:
+//
+//     f {
+//       b {
+//         d: 10
+//       }
+//       c: [2]
+//     }
+//
+// then if the field mask is:
+//
+//  paths: ["f.b", "f.c"]
+//
+// then the result will be:
+//
+//     f {
+//       b {
+//         d: 10
+//         x: 2
+//       }
+//       c: [1, 2]
+//     }
+//
+// An implementation may provide options to override this default behavior for
+// repeated and message fields.
+//
+// In order to reset a field's value to the default, the field must
+// be in the mask and set to the default value in the provided resource.
+// Hence, in order to reset all fields of a resource, provide a default
+// instance of the resource and set all fields in the mask, or do
+// not provide a mask as described below.
+//
+// If a field mask is not present on update, the operation applies to
+// all fields (as if a field mask of all fields has been specified).
+// Note that in the presence of schema evolution, this may mean that
+// fields the client does not know and has therefore not filled into
+// the request will be reset to their default. If this is unwanted
+// behavior, a specific service may require a client to always specify
+// a field mask, producing an error if not.
+//
+// As with get operations, the location of the resource which
+// describes the updated values in the request message depends on the
+// operation kind. In any case, the effect of the field mask is
+// required to be honored by the API.
+//
+// ## Considerations for HTTP REST
+//
+// The HTTP kind of an update operation which uses a field mask must
+// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+// (PUT must only be used for full updates).
+//
+// # JSON Encoding of Field Masks
+//
+// In JSON, a field mask is encoded as a single string where paths are
+// separated by a comma. Fields name in each path are converted
+// to/from lower-camel naming conventions.
+//
+// As an example, consider the following message declarations:
+//
+//     message Profile {
+//       User user = 1;
+//       Photo photo = 2;
+//     }
+//     message User {
+//       string display_name = 1;
+//       string address = 2;
+//     }
+//
+// In proto a field mask for `Profile` may look as such:
+//
+//     mask {
+//       paths: "user.display_name"
+//       paths: "photo"
+//     }
+//
+// In JSON, the same mask is represented as below:
+//
+//     {
+//       mask: "user.displayName,photo"
+//     }
+//
+// # Field Masks and Oneof Fields
+//
+// Field masks treat fields in oneofs just as regular fields. Consider the
+// following message:
+//
+//     message SampleMessage {
+//       oneof test_oneof {
+//         string name = 4;
+//         SubMessage sub_message = 9;
+//       }
+//     }
+//
+// The field mask can be:
+//
+//     mask {
+//       paths: "name"
+//     }
+//
+// Or:
+//
+//     mask {
+//       paths: "sub_message"
+//     }
+//
+// Note that oneof type names ("test_oneof" in this case) cannot be used in
+// paths.
+//
+// ## Field Mask Verification
+//
+// The implementation of any API method which has a FieldMask type field in the
+// request should verify the included field paths, and return an
+// `INVALID_ARGUMENT` error if any path is unmappable.
+message FieldMask {
+  // The set of field mask paths.
+  repeated string paths = 1;
+}
diff --git a/src/google/protobuf/generated_enum_reflection.h b/src/google/protobuf/generated_enum_reflection.h
new file mode 100644
index 0000000..b96a9c6
--- /dev/null
+++ b/src/google/protobuf/generated_enum_reflection.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.
+
+// Author: jasonh@google.com (Jason Hsueh)
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+// It provides reflection support for generated enums, and is included in
+// generated .pb.h files and should have minimal dependencies. The methods are
+// implemented in generated_message_reflection.cc.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+
+
+#include <string>
+
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/generated_enum_util.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class EnumDescriptor;
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+
+// Returns the EnumDescriptor for enum type E, which must be a
+// proto-declared enum type.  Code generated by the protocol compiler
+// will include specializations of this template for each enum type declared.
+template <typename E>
+const EnumDescriptor* GetEnumDescriptor();
+
+namespace internal {
+
+// Helper for EnumType_Parse functions: try to parse the string 'name' as
+// an enum name of the given type, returning true and filling in value on
+// success, or returning false and leaving value unchanged on failure.
+PROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
+                                    ConstStringParam name, int* value);
+
+template <typename EnumType>
+bool ParseNamedEnum(const EnumDescriptor* descriptor, ConstStringParam name,
+                    EnumType* value) {
+  int tmp;
+  if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
+  *value = static_cast<EnumType>(tmp);
+  return true;
+}
+
+// Just a wrapper around printing the name of a value. The main point of this
+// function is not to be inlined, so that you can do this without including
+// descriptor.h.
+PROTOBUF_EXPORT const std::string& NameOfEnum(const EnumDescriptor* descriptor,
+                                              int value);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
diff --git a/src/google/protobuf/generated_enum_util.cc b/src/google/protobuf/generated_enum_util.cc
new file mode 100644
index 0000000..df7583e
--- /dev/null
+++ b/src/google/protobuf/generated_enum_util.cc
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/generated_enum_util.h>
+
+#include <algorithm>
+
+#include <google/protobuf/generated_message_util.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+bool EnumCompareByName(const EnumEntry& a, const EnumEntry& b) {
+  return StringPiece(a.name) < StringPiece(b.name);
+}
+
+// Gets the numeric value of the EnumEntry at the given index, but returns a
+// special value for the index -1. This gives a way to use std::lower_bound on a
+// sorted array of indices while searching for value that we associate with -1.
+int GetValue(const EnumEntry* enums, int i, int target) {
+  if (i == -1) {
+    return target;
+  } else {
+    return enums[i].value;
+  }
+}
+
+}  // namespace
+
+bool LookUpEnumValue(const EnumEntry* enums, size_t size,
+                     StringPiece name, int* value) {
+  EnumEntry target{name, 0};
+  auto it = std::lower_bound(enums, enums + size, target, EnumCompareByName);
+  if (it != enums + size && it->name == name) {
+    *value = it->value;
+    return true;
+  }
+  return false;
+}
+
+int LookUpEnumName(const EnumEntry* enums, const int* sorted_indices,
+                   size_t size, int value) {
+  auto comparator = [enums, value](int a, int b) {
+    return GetValue(enums, a, value) < GetValue(enums, b, value);
+  };
+  auto it =
+      std::lower_bound(sorted_indices, sorted_indices + size, -1, comparator);
+  if (it != sorted_indices + size && enums[*it].value == value) {
+    return it - sorted_indices;
+  }
+  return -1;
+}
+
+bool InitializeEnumStrings(
+    const EnumEntry* enums, const int* sorted_indices, size_t size,
+    internal::ExplicitlyConstructed<std::string>* enum_strings) {
+  for (size_t i = 0; i < size; ++i) {
+    enum_strings[i].Construct(enums[sorted_indices[i]].name);
+    internal::OnShutdownDestroyString(enum_strings[i].get_mutable());
+  }
+  return true;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/generated_enum_util.h b/src/google/protobuf/generated_enum_util.h
new file mode 100644
index 0000000..5d10ac0
--- /dev/null
+++ b/src/google/protobuf/generated_enum_util.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_GENERATED_ENUM_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+
+
+#include <type_traits>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// This type trait can be used to cause templates to only match proto2 enum
+// types.
+template <typename T>
+struct is_proto_enum : ::std::false_type {};
+
+namespace internal {
+
+// The table entry format for storing enum name-to-value mapping used with lite
+// protos. This struct and the following related functions should only be used
+// by protobuf generated code.
+struct EnumEntry {
+  StringPiece name;
+  int value;
+};
+
+// Looks up a numeric enum value given the string name.
+PROTOBUF_EXPORT bool LookUpEnumValue(const EnumEntry* enums, size_t size,
+                                     StringPiece name, int* value);
+
+// Looks up an enum name given the numeric value.
+PROTOBUF_EXPORT int LookUpEnumName(const EnumEntry* enums,
+                                   const int* sorted_indices, size_t size,
+                                   int value);
+
+// Initializes the list of enum names in std::string form.
+PROTOBUF_EXPORT bool InitializeEnumStrings(
+    const EnumEntry* enums, const int* sorted_indices, size_t size,
+    internal::ExplicitlyConstructed<std::string>* enum_strings);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
diff --git a/src/google/protobuf/generated_message_bases.cc b/src/google/protobuf/generated_message_bases.cc
new file mode 100644
index 0000000..306a38e
--- /dev/null
+++ b/src/google/protobuf/generated_message_bases.cc
@@ -0,0 +1,124 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/generated_message_bases.h>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// =============================================================================
+// ZeroFieldsBase
+
+void ZeroFieldsBase::Clear() {
+  _internal_metadata_.Clear<UnknownFieldSet>();  //
+}
+
+ZeroFieldsBase::~ZeroFieldsBase() {
+  (void)_internal_metadata_.DeleteReturnArena<UnknownFieldSet>();
+}
+
+size_t ZeroFieldsBase::ByteSizeLong() const {
+  return MaybeComputeUnknownFieldsSize(0, &_cached_size_);
+}
+
+const char* ZeroFieldsBase::_InternalParse(const char* ptr,
+                                           internal::ParseContext* ctx) {
+#define CHK_(x)                       \
+  if (PROTOBUF_PREDICT_FALSE(!(x))) { \
+    goto failure;                     \
+  }
+
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = internal::ReadTag(ptr, &tag);
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag, _internal_metadata_.mutable_unknown_fields<UnknownFieldSet>(), ptr,
+        ctx);
+    CHK_(ptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+::uint8_t* ZeroFieldsBase::_InternalSerialize(
+    ::uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<UnknownFieldSet>(
+            UnknownFieldSet::default_instance),
+        target, stream);
+  }
+  return target;
+}
+
+void ZeroFieldsBase::MergeImpl(Message& to_param, const Message& from_param) {
+  auto* to = static_cast<ZeroFieldsBase*>(&to_param);
+  const auto* from = static_cast<const ZeroFieldsBase*>(&from_param);
+  GOOGLE_DCHECK_NE(from, to);
+  to->_internal_metadata_.MergeFrom<UnknownFieldSet>(from->_internal_metadata_);
+}
+
+void ZeroFieldsBase::CopyImpl(Message& to_param, const Message& from_param) {
+  auto* to = static_cast<ZeroFieldsBase*>(&to_param);
+  const auto* from = static_cast<const ZeroFieldsBase*>(&from_param);
+  if (from == to) return;
+  to->_internal_metadata_.Clear<UnknownFieldSet>();
+  to->_internal_metadata_.MergeFrom<UnknownFieldSet>(from->_internal_metadata_);
+}
+
+void ZeroFieldsBase::InternalSwap(ZeroFieldsBase* other) {
+  _internal_metadata_.Swap<UnknownFieldSet>(&other->_internal_metadata_);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/generated_message_bases.h b/src/google/protobuf/generated_message_bases.h
new file mode 100644
index 0000000..b295218
--- /dev/null
+++ b/src/google/protobuf/generated_message_bases.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.
+
+// This file contains helpers for generated code.
+//
+//  Nothing in this file should be directly referenced by users of protobufs.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
+
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/parse_context.h>
+
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// To save code size, protos without any fields are derived from ZeroFieldsBase
+// rather than Message.
+class PROTOBUF_EXPORT ZeroFieldsBase : public Message {
+ public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final { return true; }
+  size_t ByteSizeLong() const final;
+  int GetCachedSize() const final { return _cached_size_.Get(); }
+  const char* _InternalParse(const char* ptr,
+                             internal::ParseContext* ctx) final;
+  ::uint8_t* _InternalSerialize(::uint8_t* target,
+                                io::EpsCopyOutputStream* stream) const final;
+
+ protected:
+  constexpr ZeroFieldsBase() {}
+  explicit ZeroFieldsBase(Arena* arena, bool is_message_owned)
+      : Message(arena, is_message_owned) {}
+  ZeroFieldsBase(const ZeroFieldsBase&) = delete;
+  ZeroFieldsBase& operator=(const ZeroFieldsBase&) = delete;
+  ~ZeroFieldsBase() override;
+
+  void SetCachedSize(int size) const final { _cached_size_.Set(size); }
+
+  static void MergeImpl(Message& to, const Message& from);
+  static void CopyImpl(Message& to, const Message& from);
+  void InternalSwap(ZeroFieldsBase* other);
+
+  mutable internal::CachedSize _cached_size_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
new file mode 100644
index 0000000..2a807e0
--- /dev/null
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -0,0 +1,3168 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/generated_message_reflection.h>
+
+#include <algorithm>
+#include <set>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/inlined_string_field.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+#define GOOGLE_PROTOBUF_HAS_ONEOF
+
+using google::protobuf::internal::ArenaStringPtr;
+using google::protobuf::internal::DescriptorTable;
+using google::protobuf::internal::ExtensionSet;
+using google::protobuf::internal::GenericTypeHandler;
+using google::protobuf::internal::GetEmptyString;
+using google::protobuf::internal::InlinedStringField;
+using google::protobuf::internal::InternalMetadata;
+using google::protobuf::internal::LazyField;
+using google::protobuf::internal::MapFieldBase;
+using google::protobuf::internal::MigrationSchema;
+using google::protobuf::internal::OnShutdownDelete;
+using google::protobuf::internal::ReflectionSchema;
+using google::protobuf::internal::RepeatedPtrFieldBase;
+using google::protobuf::internal::StringSpaceUsedExcludingSelfLong;
+using google::protobuf::internal::WrappedMutex;
+
+namespace google {
+namespace protobuf {
+
+namespace {
+bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); }
+
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+Message* MaybeForceCopy(Arena* arena, Message* msg) {
+  if (arena != nullptr || msg == nullptr) return msg;
+
+  Message* copy = msg->New();
+  copy->MergeFrom(*msg);
+  delete msg;
+  return copy;
+}
+#endif  // PROTOBUF_FORCE_COPY_IN_RELEASE
+}  // anonymous namespace
+
+namespace internal {
+
+bool ParseNamedEnum(const EnumDescriptor* descriptor, ConstStringParam name,
+                    int* value) {
+  const EnumValueDescriptor* d = descriptor->FindValueByName(name);
+  if (d == nullptr) return false;
+  *value = d->number();
+  return true;
+}
+
+const std::string& NameOfEnum(const EnumDescriptor* descriptor, int value) {
+  const EnumValueDescriptor* d = descriptor->FindValueByNumber(value);
+  return (d == nullptr ? GetEmptyString() : d->name());
+}
+
+}  // namespace internal
+
+// ===================================================================
+// Helpers for reporting usage errors (e.g. trying to use GetInt32() on
+// a string field).
+
+namespace {
+
+using internal::GetConstPointerAtOffset;
+using internal::GetConstRefAtOffset;
+using internal::GetPointerAtOffset;
+
+void ReportReflectionUsageError(const Descriptor* descriptor,
+                                const FieldDescriptor* field,
+                                const char* method, const char* description) {
+  GOOGLE_LOG(FATAL) << "Protocol Buffer reflection usage error:\n"
+                "  Method      : google::protobuf::Reflection::"
+             << method
+             << "\n"
+                "  Message type: "
+             << descriptor->full_name()
+             << "\n"
+                "  Field       : "
+             << field->full_name()
+             << "\n"
+                "  Problem     : "
+             << description;
+}
+
+const char* cpptype_names_[FieldDescriptor::MAX_CPPTYPE + 1] = {
+    "INVALID_CPPTYPE", "CPPTYPE_INT32",  "CPPTYPE_INT64",  "CPPTYPE_UINT32",
+    "CPPTYPE_UINT64",  "CPPTYPE_DOUBLE", "CPPTYPE_FLOAT",  "CPPTYPE_BOOL",
+    "CPPTYPE_ENUM",    "CPPTYPE_STRING", "CPPTYPE_MESSAGE"};
+
+static void ReportReflectionUsageTypeError(
+    const Descriptor* descriptor, const FieldDescriptor* field,
+    const char* method, FieldDescriptor::CppType expected_type) {
+  GOOGLE_LOG(FATAL)
+      << "Protocol Buffer reflection usage error:\n"
+         "  Method      : google::protobuf::Reflection::"
+      << method
+      << "\n"
+         "  Message type: "
+      << descriptor->full_name()
+      << "\n"
+         "  Field       : "
+      << field->full_name()
+      << "\n"
+         "  Problem     : Field is not the right type for this message:\n"
+         "    Expected  : "
+      << cpptype_names_[expected_type]
+      << "\n"
+         "    Field type: "
+      << cpptype_names_[field->cpp_type()];
+}
+
+static void ReportReflectionUsageEnumTypeError(
+    const Descriptor* descriptor, const FieldDescriptor* field,
+    const char* method, const EnumValueDescriptor* value) {
+  GOOGLE_LOG(FATAL) << "Protocol Buffer reflection usage error:\n"
+                "  Method      : google::protobuf::Reflection::"
+             << method
+             << "\n"
+                "  Message type: "
+             << descriptor->full_name()
+             << "\n"
+                "  Field       : "
+             << field->full_name()
+             << "\n"
+                "  Problem     : Enum value did not match field type:\n"
+                "    Expected  : "
+             << field->enum_type()->full_name()
+             << "\n"
+                "    Actual    : "
+             << value->full_name();
+}
+
+inline void CheckInvalidAccess(const internal::ReflectionSchema& schema,
+                               const FieldDescriptor* field) {
+  GOOGLE_CHECK(!schema.IsFieldStripped(field))
+      << "invalid access to a stripped field " << field->full_name();
+}
+
+#define USAGE_CHECK(CONDITION, METHOD, ERROR_DESCRIPTION) \
+  if (!(CONDITION))                                       \
+  ReportReflectionUsageError(descriptor_, field, #METHOD, ERROR_DESCRIPTION)
+#define USAGE_CHECK_EQ(A, B, METHOD, ERROR_DESCRIPTION) \
+  USAGE_CHECK((A) == (B), METHOD, ERROR_DESCRIPTION)
+#define USAGE_CHECK_NE(A, B, METHOD, ERROR_DESCRIPTION) \
+  USAGE_CHECK((A) != (B), METHOD, ERROR_DESCRIPTION)
+
+#define USAGE_CHECK_TYPE(METHOD, CPPTYPE)                      \
+  if (field->cpp_type() != FieldDescriptor::CPPTYPE_##CPPTYPE) \
+  ReportReflectionUsageTypeError(descriptor_, field, #METHOD,  \
+                                 FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+#define USAGE_CHECK_ENUM_VALUE(METHOD)     \
+  if (value->type() != field->enum_type()) \
+  ReportReflectionUsageEnumTypeError(descriptor_, field, #METHOD, value)
+
+#define USAGE_CHECK_MESSAGE_TYPE(METHOD)                        \
+  USAGE_CHECK_EQ(field->containing_type(), descriptor_, METHOD, \
+                 "Field does not match message type.");
+#define USAGE_CHECK_SINGULAR(METHOD)                                      \
+  USAGE_CHECK_NE(field->label(), FieldDescriptor::LABEL_REPEATED, METHOD, \
+                 "Field is repeated; the method requires a singular field.")
+#define USAGE_CHECK_REPEATED(METHOD)                                      \
+  USAGE_CHECK_EQ(field->label(), FieldDescriptor::LABEL_REPEATED, METHOD, \
+                 "Field is singular; the method requires a repeated field.")
+
+#define USAGE_CHECK_ALL(METHOD, LABEL, CPPTYPE) \
+  USAGE_CHECK_MESSAGE_TYPE(METHOD);             \
+  USAGE_CHECK_##LABEL(METHOD);                  \
+  USAGE_CHECK_TYPE(METHOD, CPPTYPE)
+
+}  // namespace
+
+// ===================================================================
+
+Reflection::Reflection(const Descriptor* descriptor,
+                       const internal::ReflectionSchema& schema,
+                       const DescriptorPool* pool, MessageFactory* factory)
+    : descriptor_(descriptor),
+      schema_(schema),
+      descriptor_pool_(
+          (pool == nullptr) ? DescriptorPool::internal_generated_pool() : pool),
+      message_factory_(factory),
+      last_non_weak_field_index_(-1) {
+  last_non_weak_field_index_ = descriptor_->field_count() - 1;
+}
+
+const UnknownFieldSet& Reflection::GetUnknownFields(
+    const Message& message) const {
+  return GetInternalMetadata(message).unknown_fields<UnknownFieldSet>(
+      UnknownFieldSet::default_instance);
+}
+
+UnknownFieldSet* Reflection::MutableUnknownFields(Message* message) const {
+  return MutableInternalMetadata(message)
+      ->mutable_unknown_fields<UnknownFieldSet>();
+}
+
+bool Reflection::IsLazyExtension(const Message& message,
+                                 const FieldDescriptor* field) const {
+  return field->is_extension() &&
+         GetExtensionSet(message).HasLazy(field->number());
+}
+
+bool Reflection::IsLazilyVerifiedLazyField(const FieldDescriptor* field) const {
+  if (field->options().unverified_lazy()) return true;
+
+  // Message fields with [lazy=true] will be eagerly verified
+  // (go/verified-lazy).
+  return field->options().lazy() && !IsEagerlyVerifiedLazyField(field);
+}
+
+bool Reflection::IsEagerlyVerifiedLazyField(
+    const FieldDescriptor* field) const {
+  return (field->type() == FieldDescriptor::TYPE_MESSAGE &&
+          schema_.IsEagerlyVerifiedLazyField(field));
+}
+
+bool Reflection::IsInlined(const FieldDescriptor* field) const {
+  return schema_.IsFieldInlined(field);
+}
+
+size_t Reflection::SpaceUsedLong(const Message& message) const {
+  // object_size_ already includes the in-memory representation of each field
+  // in the message, so we only need to account for additional memory used by
+  // the fields.
+  size_t total_size = schema_.GetObjectSize();
+
+  total_size += GetUnknownFields(message).SpaceUsedExcludingSelfLong();
+
+  // If this message owns an arena, add any unused space that's been allocated.
+  auto* arena = Arena::InternalGetArenaForAllocation(&message);
+  if (arena != nullptr && Arena::InternalGetOwningArena(&message) == nullptr &&
+      arena->InternalIsMessageOwnedArena()) {
+    total_size += arena->SpaceAllocated() - arena->SpaceUsed();
+  }
+
+  if (schema_.HasExtensionSet()) {
+    total_size += GetExtensionSet(message).SpaceUsedExcludingSelfLong();
+  }
+  for (int i = 0; i <= last_non_weak_field_index_; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->is_repeated()) {
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                           \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                        \
+    total_size += GetRaw<RepeatedField<LOWERCASE> >(message, field) \
+                      .SpaceUsedExcludingSelfLong();                \
+    break
+
+        HANDLE_TYPE(INT32, int32_t);
+        HANDLE_TYPE(INT64, int64_t);
+        HANDLE_TYPE(UINT32, uint32_t);
+        HANDLE_TYPE(UINT64, uint64_t);
+        HANDLE_TYPE(DOUBLE, double);
+        HANDLE_TYPE(FLOAT, float);
+        HANDLE_TYPE(BOOL, bool);
+        HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_STRING:
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              total_size +=
+                  GetRaw<RepeatedPtrField<std::string> >(message, field)
+                      .SpaceUsedExcludingSelfLong();
+              break;
+          }
+          break;
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (IsMapFieldInApi(field)) {
+            total_size += GetRaw<internal::MapFieldBase>(message, field)
+                              .SpaceUsedExcludingSelfLong();
+          } else {
+            // We don't know which subclass of RepeatedPtrFieldBase the type is,
+            // so we use RepeatedPtrFieldBase directly.
+            total_size +=
+                GetRaw<RepeatedPtrFieldBase>(message, field)
+                    .SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >();
+          }
+
+          break;
+      }
+    } else {
+      if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+        continue;
+      }
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+        case FieldDescriptor::CPPTYPE_INT64:
+        case FieldDescriptor::CPPTYPE_UINT32:
+        case FieldDescriptor::CPPTYPE_UINT64:
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+        case FieldDescriptor::CPPTYPE_FLOAT:
+        case FieldDescriptor::CPPTYPE_BOOL:
+        case FieldDescriptor::CPPTYPE_ENUM:
+          // Field is inline, so we've already counted it.
+          break;
+
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              if (IsInlined(field)) {
+                const std::string* ptr =
+                    &GetField<InlinedStringField>(message, field).GetNoArena();
+                total_size += StringSpaceUsedExcludingSelfLong(*ptr);
+              } else {
+                // Initially, the string points to the default value stored
+                // in the prototype. Only count the string if it has been
+                // changed from the default value.
+                // Except oneof fields, those never point to a default instance,
+                // and there is no default instance to point to.
+                const auto& str = GetField<ArenaStringPtr>(message, field);
+                if (!str.IsDefault() || schema_.InRealOneof(field)) {
+                  // string fields are represented by just a pointer, so also
+                  // include sizeof(string) as well.
+                  total_size += sizeof(std::string) +
+                                StringSpaceUsedExcludingSelfLong(str.Get());
+                }
+              }
+              break;
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (schema_.IsDefaultInstance(message)) {
+            // For singular fields, the prototype just stores a pointer to the
+            // external type's prototype, so there is no extra memory usage.
+          } else {
+            const Message* sub_message = GetRaw<const Message*>(message, field);
+            if (sub_message != nullptr) {
+              total_size += sub_message->SpaceUsedLong();
+            }
+          }
+          break;
+      }
+    }
+  }
+  return total_size;
+}
+
+namespace {
+
+template <bool unsafe_shallow_swap>
+struct OneofFieldMover {
+  template <typename FromType, typename ToType>
+  void operator()(const FieldDescriptor* field, FromType* from, ToType* to) {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        to->SetInt32(from->GetInt32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        to->SetInt64(from->GetInt64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        to->SetUint32(from->GetUint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        to->SetUint64(from->GetUint64());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        to->SetFloat(from->GetFloat());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        to->SetDouble(from->GetDouble());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        to->SetBool(from->GetBool());
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        to->SetEnum(from->GetEnum());
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (!unsafe_shallow_swap) {
+          to->SetMessage(from->GetMessage());
+        } else {
+          to->UnsafeSetMessage(from->UnsafeGetMessage());
+        }
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        if (!unsafe_shallow_swap) {
+          to->SetString(from->GetString());
+          break;
+        }
+        switch (field->options().ctype()) {
+          default:
+          case FieldOptions::STRING: {
+            to->SetArenaStringPtr(from->GetArenaStringPtr());
+            break;
+          }
+        }
+        break;
+      default:
+        GOOGLE_LOG(FATAL) << "unimplemented type: " << field->cpp_type();
+    }
+    if (unsafe_shallow_swap) {
+      // Not clearing oneof case after move may cause unwanted "ClearOneof"
+      // where the residual message or string value is deleted and causes
+      // use-after-free (only for unsafe swap).
+      from->ClearOneofCase();
+    }
+  }
+};
+
+}  // namespace
+
+namespace internal {
+
+class SwapFieldHelper {
+ public:
+  template <bool unsafe_shallow_swap>
+  static void SwapRepeatedStringField(const Reflection* r, Message* lhs,
+                                      Message* rhs,
+                                      const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapInlinedStrings(const Reflection* r, Message* lhs,
+                                 Message* rhs, const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapNonInlinedStrings(const Reflection* r, Message* lhs,
+                                    Message* rhs, const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapStringField(const Reflection* r, Message* lhs, Message* rhs,
+                              const FieldDescriptor* field);
+
+  static void SwapArenaStringPtr(ArenaStringPtr* lhs, Arena* lhs_arena,
+                                 ArenaStringPtr* rhs, Arena* rhs_arena);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapRepeatedMessageField(const Reflection* r, Message* lhs,
+                                       Message* rhs,
+                                       const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapMessageField(const Reflection* r, Message* lhs, Message* rhs,
+                               const FieldDescriptor* field);
+
+  static void SwapMessage(const Reflection* r, Message* lhs, Arena* lhs_arena,
+                          Message* rhs, Arena* rhs_arena,
+                          const FieldDescriptor* field);
+
+  static void SwapNonMessageNonStringField(const Reflection* r, Message* lhs,
+                                           Message* rhs,
+                                           const FieldDescriptor* field);
+};
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs,
+                                              Message* rhs,
+                                              const FieldDescriptor* field) {
+  switch (field->options().ctype()) {
+    default:
+    case FieldOptions::STRING: {
+      auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field);
+      auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field);
+      if (unsafe_shallow_swap) {
+        lhs_string->InternalSwap(rhs_string);
+      } else {
+        lhs_string->Swap<GenericTypeHandler<std::string>>(rhs_string);
+      }
+      break;
+    }
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapInlinedStrings(const Reflection* r, Message* lhs,
+                                         Message* rhs,
+                                         const FieldDescriptor* field) {
+  // Inlined string field.
+  Arena* lhs_arena = lhs->GetArenaForAllocation();
+  Arena* rhs_arena = rhs->GetArenaForAllocation();
+  auto* lhs_string = r->MutableRaw<InlinedStringField>(lhs, field);
+  auto* rhs_string = r->MutableRaw<InlinedStringField>(rhs, field);
+  uint32_t index = r->schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  uint32_t* lhs_array = r->MutableInlinedStringDonatedArray(lhs);
+  uint32_t* rhs_array = r->MutableInlinedStringDonatedArray(rhs);
+  uint32_t* lhs_state = &lhs_array[index / 32];
+  uint32_t* rhs_state = &rhs_array[index / 32];
+  bool lhs_arena_dtor_registered = (lhs_array[0] & 0x1u) == 0;
+  bool rhs_arena_dtor_registered = (rhs_array[0] & 0x1u) == 0;
+  const uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
+  if (unsafe_shallow_swap || lhs_arena == rhs_arena) {
+    InlinedStringField::InternalSwap(lhs_string, lhs_arena,
+                                     lhs_arena_dtor_registered, lhs, rhs_string,
+                                     rhs_arena, rhs_arena_dtor_registered, rhs);
+  } else {
+    const std::string temp = lhs_string->Get();
+    lhs_string->Set(rhs_string->Get(), lhs_arena,
+                    r->IsInlinedStringDonated(*lhs, field), lhs_state, mask,
+                    lhs);
+    rhs_string->Set(temp, rhs_arena, r->IsInlinedStringDonated(*rhs, field),
+                    rhs_state, mask, rhs);
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapNonInlinedStrings(const Reflection* r, Message* lhs,
+                                            Message* rhs,
+                                            const FieldDescriptor* field) {
+  ArenaStringPtr* lhs_string = r->MutableRaw<ArenaStringPtr>(lhs, field);
+  ArenaStringPtr* rhs_string = r->MutableRaw<ArenaStringPtr>(rhs, field);
+  if (unsafe_shallow_swap) {
+    ArenaStringPtr::UnsafeShallowSwap(lhs_string, rhs_string);
+  } else {
+    SwapFieldHelper::SwapArenaStringPtr(
+        lhs_string, lhs->GetArenaForAllocation(),  //
+        rhs_string, rhs->GetArenaForAllocation());
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
+                                      Message* rhs,
+                                      const FieldDescriptor* field) {
+  switch (field->options().ctype()) {
+    default:
+    case FieldOptions::STRING: {
+      if (r->IsInlined(field)) {
+        SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
+                                                                 field);
+      } else {
+        SwapFieldHelper::SwapNonInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
+                                                                    field);
+      }
+      break;
+    }
+  }
+}
+
+void SwapFieldHelper::SwapArenaStringPtr(ArenaStringPtr* lhs, Arena* lhs_arena,
+                                         ArenaStringPtr* rhs,
+                                         Arena* rhs_arena) {
+  if (lhs_arena == rhs_arena) {
+    ArenaStringPtr::InternalSwap(lhs, lhs_arena, rhs, rhs_arena);
+  } else if (lhs->IsDefault() && rhs->IsDefault()) {
+    // Nothing to do.
+  } else if (lhs->IsDefault()) {
+    lhs->Set(rhs->Get(), lhs_arena);
+    // rhs needs to be destroyed before overwritten.
+    rhs->Destroy();
+    rhs->InitDefault();
+  } else if (rhs->IsDefault()) {
+    rhs->Set(lhs->Get(), rhs_arena);
+    // lhs needs to be destroyed before overwritten.
+    lhs->Destroy();
+    lhs->InitDefault();
+  } else {
+    std::string temp = lhs->Get();
+    lhs->Set(rhs->Get(), lhs_arena);
+    rhs->Set(std::move(temp), rhs_arena);
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapRepeatedMessageField(const Reflection* r,
+                                               Message* lhs, Message* rhs,
+                                               const FieldDescriptor* field) {
+  if (IsMapFieldInApi(field)) {
+    auto* lhs_map = r->MutableRaw<MapFieldBase>(lhs, field);
+    auto* rhs_map = r->MutableRaw<MapFieldBase>(rhs, field);
+    if (unsafe_shallow_swap) {
+      lhs_map->UnsafeShallowSwap(rhs_map);
+    } else {
+      lhs_map->Swap(rhs_map);
+    }
+  } else {
+    auto* lhs_rm = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field);
+    auto* rhs_rm = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field);
+    if (unsafe_shallow_swap) {
+      lhs_rm->InternalSwap(rhs_rm);
+    } else {
+      lhs_rm->Swap<GenericTypeHandler<Message>>(rhs_rm);
+    }
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapMessageField(const Reflection* r, Message* lhs,
+                                       Message* rhs,
+                                       const FieldDescriptor* field) {
+  if (unsafe_shallow_swap) {
+    std::swap(*r->MutableRaw<Message*>(lhs, field),
+              *r->MutableRaw<Message*>(rhs, field));
+  } else {
+    SwapMessage(r, lhs, lhs->GetArenaForAllocation(), rhs,
+                rhs->GetArenaForAllocation(), field);
+  }
+}
+
+void SwapFieldHelper::SwapMessage(const Reflection* r, Message* lhs,
+                                  Arena* lhs_arena, Message* rhs,
+                                  Arena* rhs_arena,
+                                  const FieldDescriptor* field) {
+  Message** lhs_sub = r->MutableRaw<Message*>(lhs, field);
+  Message** rhs_sub = r->MutableRaw<Message*>(rhs, field);
+
+  if (*lhs_sub == *rhs_sub) return;
+
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (lhs_arena != nullptr && lhs_arena == rhs_arena) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (lhs_arena == rhs_arena) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    std::swap(*lhs_sub, *rhs_sub);
+    return;
+  }
+
+  if (*lhs_sub != nullptr && *rhs_sub != nullptr) {
+    (*lhs_sub)->GetReflection()->Swap(*lhs_sub, *rhs_sub);
+  } else if (*lhs_sub == nullptr && r->HasBit(*rhs, field)) {
+    *lhs_sub = (*rhs_sub)->New(lhs_arena);
+    (*lhs_sub)->CopyFrom(**rhs_sub);
+    r->ClearField(rhs, field);
+    // Ensures has bit is unchanged after ClearField.
+    r->SetBit(rhs, field);
+  } else if (*rhs_sub == nullptr && r->HasBit(*lhs, field)) {
+    *rhs_sub = (*lhs_sub)->New(rhs_arena);
+    (*rhs_sub)->CopyFrom(**lhs_sub);
+    r->ClearField(lhs, field);
+    // Ensures has bit is unchanged after ClearField.
+    r->SetBit(lhs, field);
+  }
+}
+
+void SwapFieldHelper::SwapNonMessageNonStringField(
+    const Reflection* r, Message* lhs, Message* rhs,
+    const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+#define SWAP_VALUES(CPPTYPE, TYPE)               \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:       \
+    std::swap(*r->MutableRaw<TYPE>(lhs, field),  \
+              *r->MutableRaw<TYPE>(rhs, field)); \
+    break;
+
+    SWAP_VALUES(INT32, int32_t);
+    SWAP_VALUES(INT64, int64_t);
+    SWAP_VALUES(UINT32, uint32_t);
+    SWAP_VALUES(UINT64, uint64_t);
+    SWAP_VALUES(FLOAT, float);
+    SWAP_VALUES(DOUBLE, double);
+    SWAP_VALUES(BOOL, bool);
+    SWAP_VALUES(ENUM, int);
+#undef SWAP_VALUES
+    default:
+      GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+  }
+}
+
+}  // namespace internal
+
+void Reflection::SwapField(Message* message1, Message* message2,
+                           const FieldDescriptor* field) const {
+  if (field->is_repeated()) {
+    switch (field->cpp_type()) {
+#define SWAP_ARRAYS(CPPTYPE, TYPE)                                 \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                         \
+    MutableRaw<RepeatedField<TYPE> >(message1, field)              \
+        ->Swap(MutableRaw<RepeatedField<TYPE> >(message2, field)); \
+    break;
+
+      SWAP_ARRAYS(INT32, int32_t);
+      SWAP_ARRAYS(INT64, int64_t);
+      SWAP_ARRAYS(UINT32, uint32_t);
+      SWAP_ARRAYS(UINT64, uint64_t);
+      SWAP_ARRAYS(FLOAT, float);
+      SWAP_ARRAYS(DOUBLE, double);
+      SWAP_ARRAYS(BOOL, bool);
+      SWAP_ARRAYS(ENUM, int);
+#undef SWAP_ARRAYS
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        internal::SwapFieldHelper::SwapRepeatedStringField<false>(
+            this, message1, message2, field);
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        internal::SwapFieldHelper::SwapRepeatedMessageField<false>(
+            this, message1, message2, field);
+        break;
+
+      default:
+        GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+    }
+  } else {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        internal::SwapFieldHelper::SwapMessageField<false>(this, message1,
+                                                           message2, field);
+        break;
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        internal::SwapFieldHelper::SwapStringField<false>(this, message1,
+                                                          message2, field);
+        break;
+      default:
+        internal::SwapFieldHelper::SwapNonMessageNonStringField(
+            this, message1, message2, field);
+    }
+  }
+}
+
+void Reflection::UnsafeShallowSwapField(Message* message1, Message* message2,
+                                        const FieldDescriptor* field) const {
+  if (!field->is_repeated()) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      internal::SwapFieldHelper::SwapMessageField<true>(this, message1,
+                                                        message2, field);
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      internal::SwapFieldHelper::SwapStringField<true>(this, message1, message2,
+                                                       field);
+    } else {
+      internal::SwapFieldHelper::SwapNonMessageNonStringField(this, message1,
+                                                              message2, field);
+    }
+    return;
+  }
+
+  switch (field->cpp_type()) {
+#define SHALLOW_SWAP_ARRAYS(CPPTYPE, TYPE)                                \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                                \
+    MutableRaw<RepeatedField<TYPE>>(message1, field)                      \
+        ->InternalSwap(MutableRaw<RepeatedField<TYPE>>(message2, field)); \
+    break;
+
+    SHALLOW_SWAP_ARRAYS(INT32, int32_t);
+    SHALLOW_SWAP_ARRAYS(INT64, int64_t);
+    SHALLOW_SWAP_ARRAYS(UINT32, uint32_t);
+    SHALLOW_SWAP_ARRAYS(UINT64, uint64_t);
+    SHALLOW_SWAP_ARRAYS(FLOAT, float);
+    SHALLOW_SWAP_ARRAYS(DOUBLE, double);
+    SHALLOW_SWAP_ARRAYS(BOOL, bool);
+    SHALLOW_SWAP_ARRAYS(ENUM, int);
+#undef SHALLOW_SWAP_ARRAYS
+
+    case FieldDescriptor::CPPTYPE_STRING:
+      internal::SwapFieldHelper::SwapRepeatedStringField<true>(this, message1,
+                                                               message2, field);
+      break;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      internal::SwapFieldHelper::SwapRepeatedMessageField<true>(
+          this, message1, message2, field);
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+  }
+}
+
+// Swaps oneof field between lhs and rhs. If unsafe_shallow_swap is true, it
+// directly swaps oneof values; otherwise, it may involve copy/delete. Note that
+// two messages may have different oneof cases. So, it has to be done in three
+// steps (i.e. lhs -> temp, rhs -> lhs, temp -> rhs).
+template <bool unsafe_shallow_swap>
+void Reflection::SwapOneofField(Message* lhs, Message* rhs,
+                                const OneofDescriptor* oneof_descriptor) const {
+  // Wraps a local variable to temporarily store oneof value.
+  struct LocalVarWrapper {
+#define LOCAL_VAR_ACCESSOR(type, var, name)               \
+  type Get##name() const { return oneof_val.type_##var; } \
+  void Set##name(type v) { oneof_val.type_##var = v; }
+
+    LOCAL_VAR_ACCESSOR(int32_t, int32, Int32);
+    LOCAL_VAR_ACCESSOR(int64_t, int64, Int64);
+    LOCAL_VAR_ACCESSOR(uint32_t, uint32, Uint32);
+    LOCAL_VAR_ACCESSOR(uint64_t, uint64, Uint64);
+    LOCAL_VAR_ACCESSOR(float, float, Float);
+    LOCAL_VAR_ACCESSOR(double, double, Double);
+    LOCAL_VAR_ACCESSOR(bool, bool, Bool);
+    LOCAL_VAR_ACCESSOR(int, enum, Enum);
+    LOCAL_VAR_ACCESSOR(Message*, message, Message);
+    LOCAL_VAR_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
+    const std::string& GetString() const { return string_val; }
+    void SetString(const std::string& v) { string_val = v; }
+    Message* UnsafeGetMessage() const { return GetMessage(); }
+    void UnsafeSetMessage(Message* v) { SetMessage(v); }
+    void ClearOneofCase() {}
+
+    union {
+      int32_t type_int32;
+      int64_t type_int64;
+      uint32_t type_uint32;
+      uint64_t type_uint64;
+      float type_float;
+      double type_double;
+      bool type_bool;
+      int type_enum;
+      Message* type_message;
+      internal::ArenaStringPtr type_arena_string_ptr;
+    } oneof_val;
+
+    // std::string cannot be in union.
+    std::string string_val;
+  };
+
+  // Wraps a message pointer to read and write a field.
+  struct MessageWrapper {
+#define MESSAGE_FIELD_ACCESSOR(type, var, name)         \
+  type Get##name() const {                              \
+    return reflection->GetField<type>(*message, field); \
+  }                                                     \
+  void Set##name(type v) { reflection->SetField<type>(message, field, v); }
+
+    MESSAGE_FIELD_ACCESSOR(int32_t, int32, Int32);
+    MESSAGE_FIELD_ACCESSOR(int64_t, int64, Int64);
+    MESSAGE_FIELD_ACCESSOR(uint32_t, uint32, Uint32);
+    MESSAGE_FIELD_ACCESSOR(uint64_t, uint64, Uint64);
+    MESSAGE_FIELD_ACCESSOR(float, float, Float);
+    MESSAGE_FIELD_ACCESSOR(double, double, Double);
+    MESSAGE_FIELD_ACCESSOR(bool, bool, Bool);
+    MESSAGE_FIELD_ACCESSOR(int, enum, Enum);
+    MESSAGE_FIELD_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
+    std::string GetString() const {
+      return reflection->GetString(*message, field);
+    }
+    void SetString(const std::string& v) {
+      reflection->SetString(message, field, v);
+    }
+    Message* GetMessage() const {
+      return reflection->ReleaseMessage(message, field);
+    }
+    void SetMessage(Message* v) {
+      reflection->SetAllocatedMessage(message, v, field);
+    }
+    Message* UnsafeGetMessage() const {
+      return reflection->UnsafeArenaReleaseMessage(message, field);
+    }
+    void UnsafeSetMessage(Message* v) {
+      reflection->UnsafeArenaSetAllocatedMessage(message, v, field);
+    }
+    void ClearOneofCase() {
+      *reflection->MutableOneofCase(message, field->containing_oneof()) = 0;
+    }
+
+    const Reflection* reflection;
+    Message* message;
+    const FieldDescriptor* field;
+  };
+
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  uint32_t oneof_case_lhs = GetOneofCase(*lhs, oneof_descriptor);
+  uint32_t oneof_case_rhs = GetOneofCase(*rhs, oneof_descriptor);
+
+  LocalVarWrapper temp;
+  MessageWrapper lhs_wrapper, rhs_wrapper;
+  const FieldDescriptor* field_lhs = nullptr;
+  OneofFieldMover<unsafe_shallow_swap> mover;
+  // lhs --> temp
+  if (oneof_case_lhs > 0) {
+    field_lhs = descriptor_->FindFieldByNumber(oneof_case_lhs);
+    lhs_wrapper = {this, lhs, field_lhs};
+    mover(field_lhs, &lhs_wrapper, &temp);
+  }
+  // rhs --> lhs
+  if (oneof_case_rhs > 0) {
+    const FieldDescriptor* f = descriptor_->FindFieldByNumber(oneof_case_rhs);
+    lhs_wrapper = {this, lhs, f};
+    rhs_wrapper = {this, rhs, f};
+    mover(f, &rhs_wrapper, &lhs_wrapper);
+  } else if (!unsafe_shallow_swap) {
+    ClearOneof(lhs, oneof_descriptor);
+  }
+  // temp --> rhs
+  if (oneof_case_lhs > 0) {
+    rhs_wrapper = {this, rhs, field_lhs};
+    mover(field_lhs, &temp, &rhs_wrapper);
+  } else if (!unsafe_shallow_swap) {
+    ClearOneof(rhs, oneof_descriptor);
+  }
+
+  if (unsafe_shallow_swap) {
+    *MutableOneofCase(lhs, oneof_descriptor) = oneof_case_rhs;
+    *MutableOneofCase(rhs, oneof_descriptor) = oneof_case_lhs;
+  }
+}
+
+void Reflection::Swap(Message* message1, Message* message2) const {
+  if (message1 == message2) return;
+
+  // TODO(kenton):  Other Reflection methods should probably check this too.
+  GOOGLE_CHECK_EQ(message1->GetReflection(), this)
+      << "First argument to Swap() (of type \""
+      << message1->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+  GOOGLE_CHECK_EQ(message2->GetReflection(), this)
+      << "Second argument to Swap() (of type \""
+      << message2->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+
+  // Check that both messages are in the same arena (or both on the heap). We
+  // need to copy all data if not, due to ownership semantics.
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (message1->GetOwningArena() == nullptr ||
+      message1->GetOwningArena() != message2->GetOwningArena()) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (message1->GetOwningArena() != message2->GetOwningArena()) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    // One of the two is guaranteed to have an arena.  Switch things around
+    // to guarantee that message1 has an arena.
+    Arena* arena = message1->GetOwningArena();
+    if (arena == nullptr) {
+      arena = message2->GetOwningArena();
+      std::swap(message1, message2);  // Swapping names for pointers!
+    }
+
+    Message* temp = message1->New(arena);
+    temp->MergeFrom(*message2);
+    message2->CopyFrom(*message1);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    message1->CopyFrom(*temp);
+    if (arena == nullptr) delete temp;
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    Swap(message1, temp);
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    return;
+  }
+
+  GOOGLE_DCHECK_EQ(message1->GetOwningArena(), message2->GetOwningArena());
+
+  UnsafeArenaSwap(message1, message2);
+}
+
+template <bool unsafe_shallow_swap>
+void Reflection::SwapFieldsImpl(
+    Message* message1, Message* message2,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  if (message1 == message2) return;
+
+  // TODO(kenton):  Other Reflection methods should probably check this too.
+  GOOGLE_CHECK_EQ(message1->GetReflection(), this)
+      << "First argument to SwapFields() (of type \""
+      << message1->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+  GOOGLE_CHECK_EQ(message2->GetReflection(), this)
+      << "Second argument to SwapFields() (of type \""
+      << message2->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+
+  std::set<int> swapped_oneof;
+
+  GOOGLE_DCHECK(!unsafe_shallow_swap || message1->GetArenaForAllocation() ==
+                                     message2->GetArenaForAllocation());
+
+  const Message* prototype =
+      message_factory_->GetPrototype(message1->GetDescriptor());
+  for (const auto* field : fields) {
+    CheckInvalidAccess(schema_, field);
+    if (field->is_extension()) {
+      if (unsafe_shallow_swap) {
+        MutableExtensionSet(message1)->UnsafeShallowSwapExtension(
+            MutableExtensionSet(message2), field->number());
+      } else {
+        MutableExtensionSet(message1)->SwapExtension(
+            prototype, MutableExtensionSet(message2), field->number());
+      }
+    } else {
+      if (schema_.InRealOneof(field)) {
+        int oneof_index = field->containing_oneof()->index();
+        // Only swap the oneof field once.
+        if (swapped_oneof.find(oneof_index) != swapped_oneof.end()) {
+          continue;
+        }
+        swapped_oneof.insert(oneof_index);
+        SwapOneofField<unsafe_shallow_swap>(message1, message2,
+                                            field->containing_oneof());
+      } else {
+        // Swap field.
+        if (unsafe_shallow_swap) {
+          UnsafeShallowSwapField(message1, message2, field);
+        } else {
+          SwapField(message1, message2, field);
+        }
+        // Swap has bit for non-repeated fields.  We have already checked for
+        // oneof already. This has to be done after SwapField, because SwapField
+        // may depend on the information in has bits.
+        if (!field->is_repeated()) {
+          SwapBit(message1, message2, field);
+          if (field->options().ctype() == FieldOptions::STRING &&
+              IsInlined(field)) {
+            GOOGLE_DCHECK(!unsafe_shallow_swap ||
+                   message1->GetArenaForAllocation() ==
+                       message2->GetArenaForAllocation());
+            SwapInlinedStringDonated(message1, message2, field);
+          }
+        }
+      }
+    }
+  }
+}
+
+void Reflection::SwapFields(
+    Message* message1, Message* message2,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  SwapFieldsImpl<false>(message1, message2, fields);
+}
+
+void Reflection::UnsafeShallowSwapFields(
+    Message* message1, Message* message2,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  SwapFieldsImpl<true>(message1, message2, fields);
+}
+
+void Reflection::UnsafeArenaSwapFields(
+    Message* lhs, Message* rhs,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  GOOGLE_DCHECK_EQ(lhs->GetArenaForAllocation(), rhs->GetArenaForAllocation());
+  UnsafeShallowSwapFields(lhs, rhs, fields);
+}
+
+// -------------------------------------------------------------------
+
+bool Reflection::HasField(const Message& message,
+                          const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(HasField);
+  USAGE_CHECK_SINGULAR(HasField);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return GetExtensionSet(message).Has(field->number());
+  } else {
+    if (schema_.InRealOneof(field)) {
+      return HasOneofField(message, field);
+    } else {
+      return HasBit(message, field);
+    }
+  }
+}
+
+void Reflection::UnsafeArenaSwap(Message* lhs, Message* rhs) const {
+  if (lhs == rhs) return;
+
+  MutableInternalMetadata(lhs)->InternalSwap(MutableInternalMetadata(rhs));
+
+  for (int i = 0; i <= last_non_weak_field_index_; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (schema_.InRealOneof(field)) continue;
+    if (schema_.IsFieldStripped(field)) continue;
+    UnsafeShallowSwapField(lhs, rhs, field);
+  }
+  const int oneof_decl_count = descriptor_->oneof_decl_count();
+  for (int i = 0; i < oneof_decl_count; i++) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    if (!oneof->is_synthetic()) {
+      SwapOneofField<true>(lhs, rhs, oneof);
+    }
+  }
+
+  // Swapping bits need to happen after swapping fields, because the latter may
+  // depend on the has bit information.
+  if (schema_.HasHasbits()) {
+    uint32_t* lhs_has_bits = MutableHasBits(lhs);
+    uint32_t* rhs_has_bits = MutableHasBits(rhs);
+
+    int fields_with_has_bits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_repeated() || schema_.InRealOneof(field)) {
+        continue;
+      }
+      fields_with_has_bits++;
+    }
+
+    int has_bits_size = (fields_with_has_bits + 31) / 32;
+
+    for (int i = 0; i < has_bits_size; i++) {
+      std::swap(lhs_has_bits[i], rhs_has_bits[i]);
+    }
+  }
+
+  if (schema_.HasInlinedString()) {
+    uint32_t* lhs_donated_array = MutableInlinedStringDonatedArray(lhs);
+    uint32_t* rhs_donated_array = MutableInlinedStringDonatedArray(rhs);
+    int inlined_string_count = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_extension() || field->is_repeated() ||
+          schema_.InRealOneof(field) ||
+          field->options().ctype() != FieldOptions::STRING ||
+          !IsInlined(field)) {
+        continue;
+      }
+      inlined_string_count++;
+    }
+
+    int donated_array_size = inlined_string_count == 0
+                                 ? 0
+                                 // One extra bit for the arena dtor tracking.
+                                 : (inlined_string_count + 1 + 31) / 32;
+    GOOGLE_CHECK_EQ((lhs_donated_array[0] & 0x1u) == 0,
+             (rhs_donated_array[0] & 0x1u) == 0);
+    for (int i = 0; i < donated_array_size; i++) {
+      std::swap(lhs_donated_array[i], rhs_donated_array[i]);
+    }
+  }
+
+  if (schema_.HasExtensionSet()) {
+    MutableExtensionSet(lhs)->InternalSwap(MutableExtensionSet(rhs));
+  }
+}
+
+int Reflection::FieldSize(const Message& message,
+                          const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(FieldSize);
+  USAGE_CHECK_REPEATED(FieldSize);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return GetExtensionSet(message).ExtensionSize(field->number());
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)    \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+    return GetRaw<RepeatedField<LOWERCASE> >(message, field).size()
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          const internal::MapFieldBase& map =
+              GetRaw<MapFieldBase>(message, field);
+          if (map.IsRepeatedFieldValid()) {
+            return map.GetRepeatedField().size();
+          } else {
+            // No need to materialize the repeated field if it is out of sync:
+            // its size will be the same as the map's size.
+            return map.size();
+          }
+        } else {
+          return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+        }
+    }
+
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
+  }
+}
+
+void Reflection::ClearField(Message* message,
+                            const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(ClearField);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->ClearExtension(field->number());
+  } else if (!field->is_repeated()) {
+    if (schema_.InRealOneof(field)) {
+      ClearOneofField(message, field);
+      return;
+    }
+    if (HasBit(*message, field)) {
+      ClearBit(message, field);
+
+      // We need to set the field back to its default value.
+      switch (field->cpp_type()) {
+#define CLEAR_TYPE(CPPTYPE, TYPE)                                      \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                             \
+    *MutableRaw<TYPE>(message, field) = field->default_value_##TYPE(); \
+    break;
+
+        CLEAR_TYPE(INT32, int32_t);
+        CLEAR_TYPE(INT64, int64_t);
+        CLEAR_TYPE(UINT32, uint32_t);
+        CLEAR_TYPE(UINT64, uint64_t);
+        CLEAR_TYPE(FLOAT, float);
+        CLEAR_TYPE(DOUBLE, double);
+        CLEAR_TYPE(BOOL, bool);
+#undef CLEAR_TYPE
+
+        case FieldDescriptor::CPPTYPE_ENUM:
+          *MutableRaw<int>(message, field) =
+              field->default_value_enum()->number();
+          break;
+
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              if (IsInlined(field)) {
+                // Currently, string with default value can't be inlined. So we
+                // don't have to handle default value here.
+                MutableRaw<InlinedStringField>(message, field)->ClearToEmpty();
+              } else {
+                auto* str = MutableRaw<ArenaStringPtr>(message, field);
+                str->Destroy();
+                str->InitDefault();
+              }
+              break;
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (schema_.HasBitIndex(field) == static_cast<uint32_t>(-1)) {
+            // Proto3 does not have has-bits and we need to set a message field
+            // to nullptr in order to indicate its un-presence.
+            if (message->GetArenaForAllocation() == nullptr) {
+              delete *MutableRaw<Message*>(message, field);
+            }
+            *MutableRaw<Message*>(message, field) = nullptr;
+          } else {
+            (*MutableRaw<Message*>(message, field))->Clear();
+          }
+          break;
+      }
+    }
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                           \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                        \
+    MutableRaw<RepeatedField<LOWERCASE> >(message, field)->Clear(); \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING: {
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            MutableRaw<RepeatedPtrField<std::string> >(message, field)->Clear();
+            break;
+        }
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)->Clear();
+        } else {
+          // We don't know which subclass of RepeatedPtrFieldBase the type is,
+          // so we use RepeatedPtrFieldBase directly.
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->Clear<GenericTypeHandler<Message> >();
+        }
+        break;
+      }
+    }
+  }
+}
+
+void Reflection::RemoveLast(Message* message,
+                            const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(RemoveLast);
+  USAGE_CHECK_REPEATED(RemoveLast);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->RemoveLast(field->number());
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                             \
+    MutableRaw<RepeatedField<LOWERCASE> >(message, field)->RemoveLast(); \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            MutableRaw<RepeatedPtrField<std::string> >(message, field)
+                ->RemoveLast();
+            break;
+        }
+        break;
+
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->RemoveLast<GenericTypeHandler<Message> >();
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->RemoveLast<GenericTypeHandler<Message> >();
+        }
+        break;
+    }
+  }
+}
+
+Message* Reflection::ReleaseLast(Message* message,
+                                 const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(ReleaseLast, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  Message* released;
+  if (field->is_extension()) {
+    released = static_cast<Message*>(
+        MutableExtensionSet(message)->ReleaseLast(field->number()));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      released = MutableRaw<MapFieldBase>(message, field)
+                     ->MutableRepeatedField()
+                     ->ReleaseLast<GenericTypeHandler<Message>>();
+    } else {
+      released = MutableRaw<RepeatedPtrFieldBase>(message, field)
+                     ->ReleaseLast<GenericTypeHandler<Message>>();
+    }
+  }
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  return MaybeForceCopy(message->GetArenaForAllocation(), released);
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+  return released;
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+}
+
+Message* Reflection::UnsafeArenaReleaseLast(
+    Message* message, const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(UnsafeArenaReleaseLast, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->UnsafeArenaReleaseLast(field->number()));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>();
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
+          ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>();
+    }
+  }
+}
+
+void Reflection::SwapElements(Message* message, const FieldDescriptor* field,
+                              int index1, int index2) const {
+  USAGE_CHECK_MESSAGE_TYPE(Swap);
+  USAGE_CHECK_REPEATED(Swap);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SwapElements(field->number(), index1, index2);
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                 \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:              \
+    MutableRaw<RepeatedField<LOWERCASE> >(message, field) \
+        ->SwapElements(index1, index2);                   \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->SwapElements(index1, index2);
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->SwapElements(index1, index2);
+        }
+        break;
+    }
+  }
+}
+
+namespace {
+// Comparison functor for sorting FieldDescriptors by field number.
+struct FieldNumberSorter {
+  bool operator()(const FieldDescriptor* left,
+                  const FieldDescriptor* right) const {
+    return left->number() < right->number();
+  }
+};
+
+bool IsIndexInHasBitSet(const uint32_t* has_bit_set, uint32_t has_bit_index) {
+  GOOGLE_DCHECK_NE(has_bit_index, ~0u);
+  return ((has_bit_set[has_bit_index / 32] >> (has_bit_index % 32)) &
+          static_cast<uint32_t>(1)) != 0;
+}
+
+bool CreateUnknownEnumValues(const FileDescriptor* file) {
+  return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+}  // namespace
+
+namespace internal {
+bool CreateUnknownEnumValues(const FieldDescriptor* field) {
+  bool open_enum = false;
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 || open_enum;
+}
+}  // namespace internal
+using internal::CreateUnknownEnumValues;
+
+void Reflection::ListFieldsMayFailOnStripped(
+    const Message& message, bool should_fail,
+    std::vector<const FieldDescriptor*>* output) const {
+  output->clear();
+
+  // Optimization:  The default instance never has any fields set.
+  if (schema_.IsDefaultInstance(message)) return;
+
+  // Optimization: Avoid calling GetHasBits() and HasOneofField() many times
+  // within the field loop.  We allow this violation of ReflectionSchema
+  // encapsulation because this function takes a noticeable about of CPU
+  // fleetwide and properly allowing this optimization through public interfaces
+  // seems more trouble than it is worth.
+  const uint32_t* const has_bits =
+      schema_.HasHasbits() ? GetHasBits(message) : nullptr;
+  const uint32_t* const has_bits_indices = schema_.has_bit_indices_;
+  output->reserve(descriptor_->field_count());
+  const int last_non_weak_field_index = last_non_weak_field_index_;
+  for (int i = 0; i <= last_non_weak_field_index; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!should_fail && schema_.IsFieldStripped(field)) {
+      continue;
+    }
+    if (field->is_repeated()) {
+      if (FieldSize(message, field) > 0) {
+        output->push_back(field);
+      }
+    } else {
+      const OneofDescriptor* containing_oneof = field->containing_oneof();
+      if (schema_.InRealOneof(field)) {
+        const uint32_t* const oneof_case_array =
+            GetConstPointerAtOffset<uint32_t>(&message,
+                                              schema_.oneof_case_offset_);
+        // Equivalent to: HasOneofField(message, field)
+        if (static_cast<int64_t>(oneof_case_array[containing_oneof->index()]) ==
+            field->number()) {
+          output->push_back(field);
+        }
+      } else if (has_bits && has_bits_indices[i] != static_cast<uint32_t>(-1)) {
+        CheckInvalidAccess(schema_, field);
+        // Equivalent to: HasBit(message, field)
+        if (IsIndexInHasBitSet(has_bits, has_bits_indices[i])) {
+          output->push_back(field);
+        }
+      } else if (HasBit(message, field)) {  // Fall back on proto3-style HasBit.
+        output->push_back(field);
+      }
+    }
+  }
+  if (schema_.HasExtensionSet()) {
+    GetExtensionSet(message).AppendToList(descriptor_, descriptor_pool_,
+                                          output);
+  }
+
+  // ListFields() must sort output by field number.
+  std::sort(output->begin(), output->end(), FieldNumberSorter());
+}
+
+void Reflection::ListFields(const Message& message,
+                            std::vector<const FieldDescriptor*>* output) const {
+  ListFieldsMayFailOnStripped(message, true, output);
+}
+
+void Reflection::ListFieldsOmitStripped(
+    const Message& message, std::vector<const FieldDescriptor*>* output) const {
+  ListFieldsMayFailOnStripped(message, false, output);
+}
+
+// -------------------------------------------------------------------
+
+#undef DEFINE_PRIMITIVE_ACCESSORS
+#define DEFINE_PRIMITIVE_ACCESSORS(TYPENAME, TYPE, PASSTYPE, CPPTYPE)          \
+  PASSTYPE Reflection::Get##TYPENAME(const Message& message,                   \
+                                     const FieldDescriptor* field) const {     \
+    USAGE_CHECK_ALL(Get##TYPENAME, SINGULAR, CPPTYPE);                         \
+    if (field->is_extension()) {                                               \
+      return GetExtensionSet(message).Get##TYPENAME(                           \
+          field->number(), field->default_value_##PASSTYPE());                 \
+    } else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { \
+      return field->default_value_##PASSTYPE();                                \
+    } else {                                                                   \
+      return GetField<TYPE>(message, field);                                   \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  void Reflection::Set##TYPENAME(                                              \
+      Message* message, const FieldDescriptor* field, PASSTYPE value) const {  \
+    USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE);                         \
+    if (field->is_extension()) {                                               \
+      return MutableExtensionSet(message)->Set##TYPENAME(                      \
+          field->number(), field->type(), value, field);                       \
+    } else {                                                                   \
+      SetField<TYPE>(message, field, value);                                   \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  PASSTYPE Reflection::GetRepeated##TYPENAME(                                  \
+      const Message& message, const FieldDescriptor* field, int index) const { \
+    USAGE_CHECK_ALL(GetRepeated##TYPENAME, REPEATED, CPPTYPE);                 \
+    if (field->is_extension()) {                                               \
+      return GetExtensionSet(message).GetRepeated##TYPENAME(field->number(),   \
+                                                            index);            \
+    } else {                                                                   \
+      return GetRepeatedField<TYPE>(message, field, index);                    \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  void Reflection::SetRepeated##TYPENAME(Message* message,                     \
+                                         const FieldDescriptor* field,         \
+                                         int index, PASSTYPE value) const {    \
+    USAGE_CHECK_ALL(SetRepeated##TYPENAME, REPEATED, CPPTYPE);                 \
+    if (field->is_extension()) {                                               \
+      MutableExtensionSet(message)->SetRepeated##TYPENAME(field->number(),     \
+                                                          index, value);       \
+    } else {                                                                   \
+      SetRepeatedField<TYPE>(message, field, index, value);                    \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  void Reflection::Add##TYPENAME(                                              \
+      Message* message, const FieldDescriptor* field, PASSTYPE value) const {  \
+    USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE);                         \
+    if (field->is_extension()) {                                               \
+      MutableExtensionSet(message)->Add##TYPENAME(                             \
+          field->number(), field->type(), field->options().packed(), value,    \
+          field);                                                              \
+    } else {                                                                   \
+      AddField<TYPE>(message, field, value);                                   \
+    }                                                                          \
+  }
+
+DEFINE_PRIMITIVE_ACCESSORS(Int32, int32_t, int32_t, INT32)
+DEFINE_PRIMITIVE_ACCESSORS(Int64, int64_t, int64_t, INT64)
+DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32_t, uint32_t, UINT32)
+DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64_t, uint64_t, UINT64)
+DEFINE_PRIMITIVE_ACCESSORS(Float, float, float, FLOAT)
+DEFINE_PRIMITIVE_ACCESSORS(Double, double, double, DOUBLE)
+DEFINE_PRIMITIVE_ACCESSORS(Bool, bool, bool, BOOL)
+#undef DEFINE_PRIMITIVE_ACCESSORS
+
+// -------------------------------------------------------------------
+
+std::string Reflection::GetString(const Message& message,
+                                  const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(GetString, SINGULAR, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetString(field->number(),
+                                              field->default_value_string());
+  } else {
+    if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+      return field->default_value_string();
+    }
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        if (IsInlined(field)) {
+          return GetField<InlinedStringField>(message, field).GetNoArena();
+        } else {
+          const auto& str = GetField<ArenaStringPtr>(message, field);
+          return str.IsDefault() ? field->default_value_string() : str.Get();
+        }
+    }
+  }
+}
+
+const std::string& Reflection::GetStringReference(const Message& message,
+                                                  const FieldDescriptor* field,
+                                                  std::string* scratch) const {
+  (void)scratch;  // Parameter is used by Google-internal code.
+  USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetString(field->number(),
+                                              field->default_value_string());
+  } else {
+    if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+      return field->default_value_string();
+    }
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        if (IsInlined(field)) {
+          return GetField<InlinedStringField>(message, field).GetNoArena();
+        } else {
+          const auto& str = GetField<ArenaStringPtr>(message, field);
+          return str.IsDefault() ? field->default_value_string() : str.Get();
+        }
+    }
+  }
+}
+
+
+void Reflection::SetString(Message* message, const FieldDescriptor* field,
+                           std::string value) const {
+  USAGE_CHECK_ALL(SetString, SINGULAR, STRING);
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->SetString(
+        field->number(), field->type(), std::move(value), field);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING: {
+        if (IsInlined(field)) {
+          const uint32_t index = schema_.InlinedStringIndex(field);
+          GOOGLE_DCHECK_GT(index, 0);
+          uint32_t* states =
+              &MutableInlinedStringDonatedArray(message)[index / 32];
+          uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
+          MutableField<InlinedStringField>(message, field)
+              ->Set(value, message->GetArenaForAllocation(),
+                    IsInlinedStringDonated(*message, field), states, mask,
+                    message);
+          break;
+        }
+
+        // Oneof string fields are never set as a default instance.
+        // We just need to pass some arbitrary default string to make it work.
+        // This allows us to not have the real default accessible from
+        // reflection.
+        if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) {
+          ClearOneof(message, field->containing_oneof());
+          MutableField<ArenaStringPtr>(message, field)->InitDefault();
+        }
+        MutableField<ArenaStringPtr>(message, field)
+            ->Set(std::move(value), message->GetArenaForAllocation());
+        break;
+      }
+    }
+  }
+}
+
+
+std::string Reflection::GetRepeatedString(const Message& message,
+                                          const FieldDescriptor* field,
+                                          int index) const {
+  USAGE_CHECK_ALL(GetRepeatedString, REPEATED, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetRepeatedString(field->number(), index);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        return GetRepeatedPtrField<std::string>(message, field, index);
+    }
+  }
+}
+
+const std::string& Reflection::GetRepeatedStringReference(
+    const Message& message, const FieldDescriptor* field, int index,
+    std::string* scratch) const {
+  (void)scratch;  // Parameter is used by Google-internal code.
+  USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetRepeatedString(field->number(), index);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        return GetRepeatedPtrField<std::string>(message, field, index);
+    }
+  }
+}
+
+
+void Reflection::SetRepeatedString(Message* message,
+                                   const FieldDescriptor* field, int index,
+                                   std::string value) const {
+  USAGE_CHECK_ALL(SetRepeatedString, REPEATED, STRING);
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SetRepeatedString(field->number(), index,
+                                                    std::move(value));
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        MutableRepeatedField<std::string>(message, field, index)
+            ->assign(std::move(value));
+        break;
+    }
+  }
+}
+
+
+void Reflection::AddString(Message* message, const FieldDescriptor* field,
+                           std::string value) const {
+  USAGE_CHECK_ALL(AddString, REPEATED, STRING);
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddString(field->number(), field->type(),
+                                            std::move(value), field);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        AddField<std::string>(message, field)->assign(std::move(value));
+        break;
+    }
+  }
+}
+
+
+// -------------------------------------------------------------------
+
+const EnumValueDescriptor* Reflection::GetEnum(
+    const Message& message, const FieldDescriptor* field) const {
+  // Usage checked by GetEnumValue.
+  int value = GetEnumValue(message, field);
+  return field->enum_type()->FindValueByNumberCreatingIfUnknown(value);
+}
+
+int Reflection::GetEnumValue(const Message& message,
+                             const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM);
+
+  int32_t value;
+  if (field->is_extension()) {
+    value = GetExtensionSet(message).GetEnum(
+        field->number(), field->default_value_enum()->number());
+  } else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+    value = field->default_value_enum()->number();
+  } else {
+    value = GetField<int>(message, field);
+  }
+  return value;
+}
+
+void Reflection::SetEnum(Message* message, const FieldDescriptor* field,
+                         const EnumValueDescriptor* value) const {
+  // Usage checked by SetEnumValue.
+  USAGE_CHECK_ENUM_VALUE(SetEnum);
+  SetEnumValueInternal(message, field, value->number());
+}
+
+void Reflection::SetEnumValue(Message* message, const FieldDescriptor* field,
+                              int value) const {
+  USAGE_CHECK_ALL(SetEnumValue, SINGULAR, ENUM);
+  if (!CreateUnknownEnumValues(field)) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == nullptr) {
+      MutableUnknownFields(message)->AddVarint(field->number(), value);
+      return;
+    }
+  }
+  SetEnumValueInternal(message, field, value);
+}
+
+void Reflection::SetEnumValueInternal(Message* message,
+                                      const FieldDescriptor* field,
+                                      int value) const {
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SetEnum(field->number(), field->type(), value,
+                                          field);
+  } else {
+    SetField<int>(message, field, value);
+  }
+}
+
+const EnumValueDescriptor* Reflection::GetRepeatedEnum(
+    const Message& message, const FieldDescriptor* field, int index) const {
+  // Usage checked by GetRepeatedEnumValue.
+  int value = GetRepeatedEnumValue(message, field, index);
+  return field->enum_type()->FindValueByNumberCreatingIfUnknown(value);
+}
+
+int Reflection::GetRepeatedEnumValue(const Message& message,
+                                     const FieldDescriptor* field,
+                                     int index) const {
+  USAGE_CHECK_ALL(GetRepeatedEnumValue, REPEATED, ENUM);
+
+  int value;
+  if (field->is_extension()) {
+    value = GetExtensionSet(message).GetRepeatedEnum(field->number(), index);
+  } else {
+    value = GetRepeatedField<int>(message, field, index);
+  }
+  return value;
+}
+
+void Reflection::SetRepeatedEnum(Message* message, const FieldDescriptor* field,
+                                 int index,
+                                 const EnumValueDescriptor* value) const {
+  // Usage checked by SetRepeatedEnumValue.
+  USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum);
+  SetRepeatedEnumValueInternal(message, field, index, value->number());
+}
+
+void Reflection::SetRepeatedEnumValue(Message* message,
+                                      const FieldDescriptor* field, int index,
+                                      int value) const {
+  USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM);
+  if (!CreateUnknownEnumValues(field)) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == nullptr) {
+      MutableUnknownFields(message)->AddVarint(field->number(), value);
+      return;
+    }
+  }
+  SetRepeatedEnumValueInternal(message, field, index, value);
+}
+
+void Reflection::SetRepeatedEnumValueInternal(Message* message,
+                                              const FieldDescriptor* field,
+                                              int index, int value) const {
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SetRepeatedEnum(field->number(), index,
+                                                  value);
+  } else {
+    SetRepeatedField<int>(message, field, index, value);
+  }
+}
+
+void Reflection::AddEnum(Message* message, const FieldDescriptor* field,
+                         const EnumValueDescriptor* value) const {
+  // Usage checked by AddEnumValue.
+  USAGE_CHECK_ENUM_VALUE(AddEnum);
+  AddEnumValueInternal(message, field, value->number());
+}
+
+void Reflection::AddEnumValue(Message* message, const FieldDescriptor* field,
+                              int value) const {
+  USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM);
+  if (!CreateUnknownEnumValues(field)) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == nullptr) {
+      MutableUnknownFields(message)->AddVarint(field->number(), value);
+      return;
+    }
+  }
+  AddEnumValueInternal(message, field, value);
+}
+
+void Reflection::AddEnumValueInternal(Message* message,
+                                      const FieldDescriptor* field,
+                                      int value) const {
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddEnum(field->number(), field->type(),
+                                          field->options().packed(), value,
+                                          field);
+  } else {
+    AddField<int>(message, field, value);
+  }
+}
+
+// -------------------------------------------------------------------
+
+const Message* Reflection::GetDefaultMessageInstance(
+    const FieldDescriptor* field) const {
+  // If we are using the generated factory, we cache the prototype in the field
+  // descriptor for faster access.
+  // The default instances of generated messages are not cross-linked, which
+  // means they contain null pointers on their message fields and can't be used
+  // to get the default of submessages.
+  if (message_factory_ == MessageFactory::generated_factory()) {
+    auto& ptr = field->default_generated_instance_;
+    auto* res = ptr.load(std::memory_order_acquire);
+    if (res == nullptr) {
+      // First time asking for this field's default. Load it and cache it.
+      res = message_factory_->GetPrototype(field->message_type());
+      ptr.store(res, std::memory_order_release);
+    }
+    return res;
+  }
+
+  // For other factories, we try the default's object field.
+  // In particular, the DynamicMessageFactory will cross link the default
+  // instances to allow for this. But only do this for real fields.
+  // This is an optimization to avoid going to GetPrototype() below, as that
+  // requires a lock and a map lookup.
+  if (!field->is_extension() && !field->options().weak() &&
+      !IsLazyField(field) && !schema_.InRealOneof(field)) {
+    auto* res = DefaultRaw<const Message*>(field);
+    if (res != nullptr) {
+      return res;
+    }
+  }
+  // Otherwise, just go to the factory.
+  return message_factory_->GetPrototype(field->message_type());
+}
+
+const Message& Reflection::GetMessage(const Message& message,
+                                      const FieldDescriptor* field,
+                                      MessageFactory* factory) const {
+  USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<const Message&>(GetExtensionSet(message).GetMessage(
+        field->number(), field->message_type(), factory));
+  } else {
+    if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+      return *GetDefaultMessageInstance(field);
+    }
+    const Message* result = GetRaw<const Message*>(message, field);
+    if (result == nullptr) {
+      result = GetDefaultMessageInstance(field);
+    }
+    return *result;
+  }
+}
+
+Message* Reflection::MutableMessage(Message* message,
+                                    const FieldDescriptor* field,
+                                    MessageFactory* factory) const {
+  USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->MutableMessage(field, factory));
+  } else {
+    Message* result;
+
+    Message** result_holder = MutableRaw<Message*>(message, field);
+
+    if (schema_.InRealOneof(field)) {
+      if (!HasOneofField(*message, field)) {
+        ClearOneof(message, field->containing_oneof());
+        result_holder = MutableField<Message*>(message, field);
+        const Message* default_message = GetDefaultMessageInstance(field);
+        *result_holder = default_message->New(message->GetArenaForAllocation());
+      }
+    } else {
+      SetBit(message, field);
+    }
+
+    if (*result_holder == nullptr) {
+      const Message* default_message = GetDefaultMessageInstance(field);
+      *result_holder = default_message->New(message->GetArenaForAllocation());
+    }
+    result = *result_holder;
+    return result;
+  }
+}
+
+void Reflection::UnsafeArenaSetAllocatedMessage(
+    Message* message, Message* sub_message,
+    const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(SetAllocatedMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->UnsafeArenaSetAllocatedMessage(
+        field->number(), field->type(), field, sub_message);
+  } else {
+    if (schema_.InRealOneof(field)) {
+      if (sub_message == nullptr) {
+        ClearOneof(message, field->containing_oneof());
+        return;
+      }
+        ClearOneof(message, field->containing_oneof());
+        *MutableRaw<Message*>(message, field) = sub_message;
+      SetOneofCase(message, field);
+      return;
+    }
+
+    if (sub_message == nullptr) {
+      ClearBit(message, field);
+    } else {
+      SetBit(message, field);
+    }
+    Message** sub_message_holder = MutableRaw<Message*>(message, field);
+    if (message->GetArenaForAllocation() == nullptr) {
+      delete *sub_message_holder;
+    }
+    *sub_message_holder = sub_message;
+  }
+}
+
+void Reflection::SetAllocatedMessage(Message* message, Message* sub_message,
+                                     const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(sub_message == nullptr || sub_message->GetOwningArena() == nullptr ||
+         sub_message->GetOwningArena() == message->GetArenaForAllocation());
+  CheckInvalidAccess(schema_, field);
+
+  // If message and sub-message are in different memory ownership domains
+  // (different arenas, or one is on heap and one is not), then we may need to
+  // do a copy.
+  if (sub_message != nullptr &&
+      sub_message->GetOwningArena() != message->GetArenaForAllocation()) {
+    if (sub_message->GetOwningArena() == nullptr &&
+        message->GetArenaForAllocation() != nullptr) {
+      // Case 1: parent is on an arena and child is heap-allocated. We can add
+      // the child to the arena's Own() list to free on arena destruction, then
+      // set our pointer.
+      message->GetArenaForAllocation()->Own(sub_message);
+      UnsafeArenaSetAllocatedMessage(message, sub_message, field);
+    } else {
+      // Case 2: all other cases. We need to make a copy. MutableMessage() will
+      // either get the existing message object, or instantiate a new one as
+      // appropriate w.r.t. our arena.
+      Message* sub_message_copy = MutableMessage(message, field);
+      sub_message_copy->CopyFrom(*sub_message);
+    }
+  } else {
+    // Same memory ownership domains.
+    UnsafeArenaSetAllocatedMessage(message, sub_message, field);
+  }
+}
+
+Message* Reflection::UnsafeArenaReleaseMessage(Message* message,
+                                               const FieldDescriptor* field,
+                                               MessageFactory* factory) const {
+  USAGE_CHECK_ALL(ReleaseMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->UnsafeArenaReleaseMessage(field,
+                                                                factory));
+  } else {
+    if (!(field->is_repeated() || schema_.InRealOneof(field))) {
+      ClearBit(message, field);
+    }
+    if (schema_.InRealOneof(field)) {
+      if (HasOneofField(*message, field)) {
+        *MutableOneofCase(message, field->containing_oneof()) = 0;
+      } else {
+        return nullptr;
+      }
+    }
+    Message** result = MutableRaw<Message*>(message, field);
+    Message* ret = *result;
+    *result = nullptr;
+    return ret;
+  }
+}
+
+Message* Reflection::ReleaseMessage(Message* message,
+                                    const FieldDescriptor* field,
+                                    MessageFactory* factory) const {
+  CheckInvalidAccess(schema_, field);
+
+  Message* released = UnsafeArenaReleaseMessage(message, field, factory);
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  released = MaybeForceCopy(message->GetArenaForAllocation(), released);
+#endif  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (message->GetArenaForAllocation() != nullptr && released != nullptr) {
+    Message* copy_from_arena = released->New();
+    copy_from_arena->CopyFrom(*released);
+    released = copy_from_arena;
+  }
+  return released;
+}
+
+const Message& Reflection::GetRepeatedMessage(const Message& message,
+                                              const FieldDescriptor* field,
+                                              int index) const {
+  USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<const Message&>(
+        GetExtensionSet(message).GetRepeatedMessage(field->number(), index));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return GetRaw<MapFieldBase>(message, field)
+          .GetRepeatedField()
+          .Get<GenericTypeHandler<Message> >(index);
+    } else {
+      return GetRaw<RepeatedPtrFieldBase>(message, field)
+          .Get<GenericTypeHandler<Message> >(index);
+    }
+  }
+}
+
+Message* Reflection::MutableRepeatedMessage(Message* message,
+                                            const FieldDescriptor* field,
+                                            int index) const {
+  USAGE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->MutableRepeatedMessage(field->number(),
+                                                             index));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->Mutable<GenericTypeHandler<Message> >(index);
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
+          ->Mutable<GenericTypeHandler<Message> >(index);
+    }
+  }
+}
+
+Message* Reflection::AddMessage(Message* message, const FieldDescriptor* field,
+                                MessageFactory* factory) const {
+  USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->AddMessage(field, factory));
+  } else {
+    Message* result = nullptr;
+
+    // We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
+    // know how to allocate one.
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
+    if (result == nullptr) {
+      // We must allocate a new object.
+      const Message* prototype;
+      if (repeated->size() == 0) {
+        prototype = factory->GetPrototype(field->message_type());
+      } else {
+        prototype = &repeated->Get<GenericTypeHandler<Message> >(0);
+      }
+      result = prototype->New(message->GetArenaForAllocation());
+      // We can guarantee here that repeated and result are either both heap
+      // allocated or arena owned. So it is safe to call the unsafe version
+      // of AddAllocated.
+      repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message> >(result);
+    }
+
+    return result;
+  }
+}
+
+void Reflection::AddAllocatedMessage(Message* message,
+                                     const FieldDescriptor* field,
+                                     Message* new_entry) const {
+  USAGE_CHECK_ALL(AddAllocatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddAllocatedMessage(field, new_entry);
+  } else {
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    repeated->AddAllocated<GenericTypeHandler<Message> >(new_entry);
+  }
+}
+
+void Reflection::UnsafeArenaAddAllocatedMessage(Message* message,
+                                                const FieldDescriptor* field,
+                                                Message* new_entry) const {
+  USAGE_CHECK_ALL(UnsafeArenaAddAllocatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->UnsafeArenaAddAllocatedMessage(field,
+                                                                 new_entry);
+  } else {
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message>>(new_entry);
+  }
+}
+
+void* Reflection::MutableRawRepeatedField(Message* message,
+                                          const FieldDescriptor* field,
+                                          FieldDescriptor::CppType cpptype,
+                                          int ctype,
+                                          const Descriptor* desc) const {
+  (void)ctype;  // Parameter is used by Google-internal code.
+  USAGE_CHECK_REPEATED("MutableRawRepeatedField");
+  CheckInvalidAccess(schema_, field);
+
+  if (field->cpp_type() != cpptype &&
+      (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM ||
+       cpptype != FieldDescriptor::CPPTYPE_INT32))
+    ReportReflectionUsageTypeError(descriptor_, field,
+                                   "MutableRawRepeatedField", cpptype);
+  if (desc != nullptr)
+    GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->MutableRawRepeatedField(
+        field->number(), field->type(), field->is_packed(), field);
+  } else {
+    // Trigger transform for MapField
+    if (IsMapFieldInApi(field)) {
+      return MutableRawNonOneof<MapFieldBase>(message, field)
+          ->MutableRepeatedField();
+    }
+    return MutableRawNonOneof<void>(message, field);
+  }
+}
+
+const void* Reflection::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 != nullptr)
+    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 &(GetRawNonOneof<MapFieldBase>(message, field).GetRepeatedField());
+    }
+    return &GetRawNonOneof<char>(message, field);
+  }
+}
+
+const FieldDescriptor* Reflection::GetOneofFieldDescriptor(
+    const Message& message, const OneofDescriptor* oneof_descriptor) const {
+  if (oneof_descriptor->is_synthetic()) {
+    const FieldDescriptor* field = oneof_descriptor->field(0);
+    return HasField(message, field) ? field : nullptr;
+  }
+  uint32_t field_number = GetOneofCase(message, oneof_descriptor);
+  if (field_number == 0) {
+    return nullptr;
+  }
+  return descriptor_->FindFieldByNumber(field_number);
+}
+
+bool Reflection::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 Reflection::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()->map_value()->cpp_type());
+  return MutableRaw<MapFieldBase>(message, field)
+      ->InsertOrLookupMapValue(key, val);
+}
+
+bool Reflection::LookupMapValue(const Message& message,
+                                const FieldDescriptor* field, const MapKey& key,
+                                MapValueConstRef* val) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "LookupMapValue",
+              "Field is not a map field.");
+  val->SetType(field->message_type()->map_value()->cpp_type());
+  return GetRaw<MapFieldBase>(message, field).LookupMapValue(key, val);
+}
+
+bool Reflection::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 Reflection::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 Reflection::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 Reflection::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* Reflection::FindKnownExtensionByName(
+    const std::string& name) const {
+  if (!schema_.HasExtensionSet()) return nullptr;
+  return descriptor_pool_->FindExtensionByPrintableName(descriptor_, name);
+}
+
+const FieldDescriptor* Reflection::FindKnownExtensionByNumber(
+    int number) const {
+  if (!schema_.HasExtensionSet()) return nullptr;
+  return descriptor_pool_->FindExtensionByNumber(descriptor_, number);
+}
+
+bool Reflection::SupportsUnknownEnumValues() const {
+  return CreateUnknownEnumValues(descriptor_->file());
+}
+
+// ===================================================================
+// Some private helpers.
+
+// These simple template accessors obtain pointers (or references) to
+// the given field.
+
+template <class Type>
+const Type& Reflection::GetRawNonOneof(const Message& message,
+                                       const FieldDescriptor* field) const {
+  return GetConstRefAtOffset<Type>(message,
+                                   schema_.GetFieldOffsetNonOneof(field));
+}
+
+template <class Type>
+Type* Reflection::MutableRawNonOneof(Message* message,
+                                     const FieldDescriptor* field) const {
+  return GetPointerAtOffset<Type>(message,
+                                  schema_.GetFieldOffsetNonOneof(field));
+}
+
+template <typename Type>
+Type* Reflection::MutableRaw(Message* message,
+                             const FieldDescriptor* field) const {
+  return GetPointerAtOffset<Type>(message, schema_.GetFieldOffset(field));
+}
+
+const uint32_t* Reflection::GetHasBits(const Message& message) const {
+  GOOGLE_DCHECK(schema_.HasHasbits());
+  return &GetConstRefAtOffset<uint32_t>(message, schema_.HasBitsOffset());
+}
+
+uint32_t* Reflection::MutableHasBits(Message* message) const {
+  GOOGLE_DCHECK(schema_.HasHasbits());
+  return GetPointerAtOffset<uint32_t>(message, schema_.HasBitsOffset());
+}
+
+uint32_t* Reflection::MutableOneofCase(
+    Message* message, const OneofDescriptor* oneof_descriptor) const {
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  return GetPointerAtOffset<uint32_t>(
+      message, schema_.GetOneofCaseOffset(oneof_descriptor));
+}
+
+const ExtensionSet& Reflection::GetExtensionSet(const Message& message) const {
+  return GetConstRefAtOffset<ExtensionSet>(message,
+                                           schema_.GetExtensionSetOffset());
+}
+
+ExtensionSet* Reflection::MutableExtensionSet(Message* message) const {
+  return GetPointerAtOffset<ExtensionSet>(message,
+                                          schema_.GetExtensionSetOffset());
+}
+
+const InternalMetadata& Reflection::GetInternalMetadata(
+    const Message& message) const {
+  return GetConstRefAtOffset<InternalMetadata>(message,
+                                               schema_.GetMetadataOffset());
+}
+
+InternalMetadata* Reflection::MutableInternalMetadata(Message* message) const {
+  return GetPointerAtOffset<InternalMetadata>(message,
+                                              schema_.GetMetadataOffset());
+}
+
+const uint32_t* Reflection::GetInlinedStringDonatedArray(
+    const Message& message) const {
+  GOOGLE_DCHECK(schema_.HasInlinedString());
+  return &GetConstRefAtOffset<uint32_t>(message,
+                                        schema_.InlinedStringDonatedOffset());
+}
+
+uint32_t* Reflection::MutableInlinedStringDonatedArray(Message* message) const {
+  GOOGLE_DCHECK(schema_.HasInlinedString());
+  return GetPointerAtOffset<uint32_t>(message,
+                                      schema_.InlinedStringDonatedOffset());
+}
+
+// Simple accessors for manipulating _inlined_string_donated_;
+bool Reflection::IsInlinedStringDonated(const Message& message,
+                                        const FieldDescriptor* field) const {
+  uint32_t index = schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  return IsIndexInHasBitSet(GetInlinedStringDonatedArray(message), index);
+}
+
+inline void SetInlinedStringDonated(uint32_t index, uint32_t* array) {
+  array[index / 32] |= (static_cast<uint32_t>(1) << (index % 32));
+}
+
+inline void ClearInlinedStringDonated(uint32_t index, uint32_t* array) {
+  array[index / 32] &= ~(static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::SwapInlinedStringDonated(Message* lhs, Message* rhs,
+                                          const FieldDescriptor* field) const {
+  Arena* lhs_arena = lhs->GetArenaForAllocation();
+  Arena* rhs_arena = rhs->GetArenaForAllocation();
+  // If arenas differ, inined string fields are swapped by copying values.
+  // Donation status should not be swapped.
+  if (lhs_arena != rhs_arena) {
+    return;
+  }
+  bool lhs_donated = IsInlinedStringDonated(*lhs, field);
+  bool rhs_donated = IsInlinedStringDonated(*rhs, field);
+  if (lhs_donated == rhs_donated) {
+    return;
+  }
+  // If one is undonated, both must have already registered ArenaDtor.
+  uint32_t* lhs_array = MutableInlinedStringDonatedArray(lhs);
+  uint32_t* rhs_array = MutableInlinedStringDonatedArray(rhs);
+  GOOGLE_CHECK_EQ(lhs_array[0] & 0x1u, 0u);
+  GOOGLE_CHECK_EQ(rhs_array[0] & 0x1u, 0u);
+  // Swap donation status bit.
+  uint32_t index = schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  if (rhs_donated) {
+    SetInlinedStringDonated(index, lhs_array);
+    ClearInlinedStringDonated(index, rhs_array);
+  } else {  // lhs_donated
+    ClearInlinedStringDonated(index, lhs_array);
+    SetInlinedStringDonated(index, rhs_array);
+  }
+}
+
+// Simple accessors for manipulating has_bits_.
+bool Reflection::HasBit(const Message& message,
+                        const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  if (schema_.HasBitIndex(field) != static_cast<uint32_t>(-1)) {
+    return IsIndexInHasBitSet(GetHasBits(message), schema_.HasBitIndex(field));
+  }
+
+  // Intentionally check here because HasBitIndex(field) != -1 means valid.
+  CheckInvalidAccess(schema_, field);
+
+  // proto3: no has-bits. All fields present except messages, which are
+  // present only if their message-field pointer is non-null.
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    return !schema_.IsDefaultInstance(message) &&
+           GetRaw<const Message*>(message, field) != nullptr;
+  } else {
+    // Non-message field (and non-oneof, since that was handled in HasField()
+    // before calling us), and singular (again, checked in HasField). So, this
+    // field must be a scalar.
+
+    // Scalar primitive (numeric or string/bytes) fields are present if
+    // their value is non-zero (numeric) or non-empty (string/bytes). N.B.:
+    // we must use this definition here, rather than the "scalar fields
+    // always present" in the proto3 docs, because MergeFrom() semantics
+    // require presence as "present on wire", and reflection-based merge
+    // (which uses HasField()) needs to be consistent with this.
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default: {
+            if (IsInlined(field)) {
+              return !GetField<InlinedStringField>(message, field)
+                          .GetNoArena()
+                          .empty();
+            }
+
+            return GetField<ArenaStringPtr>(message, field).Get().size() > 0;
+          }
+        }
+        return false;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return GetRaw<bool>(message, field) != false;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return GetRaw<int32_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return GetRaw<int64_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return GetRaw<uint32_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return GetRaw<uint64_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        static_assert(sizeof(uint32_t) == sizeof(float),
+                      "Code assumes uint32_t and float are the same size.");
+        return GetRaw<uint32_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        static_assert(sizeof(uint64_t) == sizeof(double),
+                      "Code assumes uint64_t and double are the same size.");
+        return GetRaw<uint64_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return GetRaw<int>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        // handled above; avoid warning
+        break;
+    }
+    GOOGLE_LOG(FATAL) << "Reached impossible case in HasBit().";
+    return false;
+  }
+}
+
+void Reflection::SetBit(Message* message, const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  const uint32_t index = schema_.HasBitIndex(field);
+  if (index == static_cast<uint32_t>(-1)) return;
+  MutableHasBits(message)[index / 32] |=
+      (static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::ClearBit(Message* message,
+                          const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  const uint32_t index = schema_.HasBitIndex(field);
+  if (index == static_cast<uint32_t>(-1)) return;
+  MutableHasBits(message)[index / 32] &=
+      ~(static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::SwapBit(Message* message1, Message* message2,
+                         const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  if (!schema_.HasHasbits()) {
+    return;
+  }
+  bool temp_has_bit = HasBit(*message1, field);
+  if (HasBit(*message2, field)) {
+    SetBit(message1, field);
+  } else {
+    ClearBit(message1, field);
+  }
+  if (temp_has_bit) {
+    SetBit(message2, field);
+  } else {
+    ClearBit(message2, field);
+  }
+}
+
+bool Reflection::HasOneof(const Message& message,
+                          const OneofDescriptor* oneof_descriptor) const {
+  if (oneof_descriptor->is_synthetic()) {
+    return HasField(message, oneof_descriptor->field(0));
+  }
+  return (GetOneofCase(message, oneof_descriptor) > 0);
+}
+
+void Reflection::SetOneofCase(Message* message,
+                              const FieldDescriptor* field) const {
+  *MutableOneofCase(message, field->containing_oneof()) = field->number();
+}
+
+void Reflection::ClearOneofField(Message* message,
+                                 const FieldDescriptor* field) const {
+  if (HasOneofField(*message, field)) {
+    ClearOneof(message, field->containing_oneof());
+  }
+}
+
+void Reflection::ClearOneof(Message* message,
+                            const OneofDescriptor* oneof_descriptor) const {
+  if (oneof_descriptor->is_synthetic()) {
+    ClearField(message, oneof_descriptor->field(0));
+    return;
+  }
+  // TODO(jieluo): Consider to cache the unused object instead of deleting
+  // it. It will be much faster if an application switches a lot from
+  // a few oneof fields.  Time/space tradeoff
+  uint32_t oneof_case = GetOneofCase(*message, oneof_descriptor);
+  if (oneof_case > 0) {
+    const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
+    if (message->GetArenaForAllocation() == nullptr) {
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING: {
+              // Oneof string fields are never set as a default instance.
+              // We just need to pass some arbitrary default string to make it
+              // work. This allows us to not have the real default accessible
+              // from reflection.
+              MutableField<ArenaStringPtr>(message, field)->Destroy();
+              break;
+            }
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          delete *MutableRaw<Message*>(message, field);
+          break;
+        default:
+          break;
+      }
+    } else {
+    }
+
+    *MutableOneofCase(message, oneof_descriptor) = 0;
+  }
+}
+
+#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE)                                  \
+  template <>                                                              \
+  const RepeatedField<TYPE>& Reflection::GetRepeatedFieldInternal<TYPE>(   \
+      const Message& message, const FieldDescriptor* field) const {        \
+    return *static_cast<RepeatedField<TYPE>*>(MutableRawRepeatedField(     \
+        const_cast<Message*>(&message), field, CPPTYPE, CTYPE, nullptr));  \
+  }                                                                        \
+                                                                           \
+  template <>                                                              \
+  RepeatedField<TYPE>* Reflection::MutableRepeatedFieldInternal<TYPE>(     \
+      Message * message, const FieldDescriptor* field) const {             \
+    return static_cast<RepeatedField<TYPE>*>(                              \
+        MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, nullptr)); \
+  }
+
+HANDLE_TYPE(int32_t, FieldDescriptor::CPPTYPE_INT32, -1);
+HANDLE_TYPE(int64_t, FieldDescriptor::CPPTYPE_INT64, -1);
+HANDLE_TYPE(uint32_t, FieldDescriptor::CPPTYPE_UINT32, -1);
+HANDLE_TYPE(uint64_t, FieldDescriptor::CPPTYPE_UINT64, -1);
+HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1);
+HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1);
+HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
+
+
+#undef HANDLE_TYPE
+
+void* Reflection::MutableRawRepeatedString(Message* message,
+                                           const FieldDescriptor* field,
+                                           bool is_string) const {
+  (void)is_string;  // Parameter is used by Google-internal code.
+  return MutableRawRepeatedField(message, field,
+                                 FieldDescriptor::CPPTYPE_STRING,
+                                 FieldOptions::STRING, nullptr);
+}
+
+// Template implementations of basic accessors.  Inline because each
+// template instance is only called from one location.  These are
+// used for all types except messages.
+template <typename Type>
+const Type& Reflection::GetField(const Message& message,
+                                 const FieldDescriptor* field) const {
+  return GetRaw<Type>(message, field);
+}
+
+template <typename Type>
+void Reflection::SetField(Message* message, const FieldDescriptor* field,
+                          const Type& value) const {
+  bool real_oneof = schema_.InRealOneof(field);
+  if (real_oneof && !HasOneofField(*message, field)) {
+    ClearOneof(message, field->containing_oneof());
+  }
+  *MutableRaw<Type>(message, field) = value;
+  real_oneof ? SetOneofCase(message, field) : SetBit(message, field);
+}
+
+template <typename Type>
+Type* Reflection::MutableField(Message* message,
+                               const FieldDescriptor* field) const {
+  schema_.InRealOneof(field) ? SetOneofCase(message, field)
+                             : SetBit(message, field);
+  return MutableRaw<Type>(message, field);
+}
+
+template <typename Type>
+const Type& Reflection::GetRepeatedField(const Message& message,
+                                         const FieldDescriptor* field,
+                                         int index) const {
+  return GetRaw<RepeatedField<Type> >(message, field).Get(index);
+}
+
+template <typename Type>
+const Type& Reflection::GetRepeatedPtrField(const Message& message,
+                                            const FieldDescriptor* field,
+                                            int index) const {
+  return GetRaw<RepeatedPtrField<Type> >(message, field).Get(index);
+}
+
+template <typename Type>
+void Reflection::SetRepeatedField(Message* message,
+                                  const FieldDescriptor* field, int index,
+                                  Type value) const {
+  MutableRaw<RepeatedField<Type> >(message, field)->Set(index, value);
+}
+
+template <typename Type>
+Type* Reflection::MutableRepeatedField(Message* message,
+                                       const FieldDescriptor* field,
+                                       int index) const {
+  RepeatedPtrField<Type>* repeated =
+      MutableRaw<RepeatedPtrField<Type> >(message, field);
+  return repeated->Mutable(index);
+}
+
+template <typename Type>
+void Reflection::AddField(Message* message, const FieldDescriptor* field,
+                          const Type& value) const {
+  MutableRaw<RepeatedField<Type> >(message, field)->Add(value);
+}
+
+template <typename Type>
+Type* Reflection::AddField(Message* message,
+                           const FieldDescriptor* field) const {
+  RepeatedPtrField<Type>* repeated =
+      MutableRaw<RepeatedPtrField<Type> >(message, field);
+  return repeated->Add();
+}
+
+MessageFactory* Reflection::GetMessageFactory() const {
+  return message_factory_;
+}
+
+void* Reflection::RepeatedFieldData(Message* message,
+                                    const FieldDescriptor* field,
+                                    FieldDescriptor::CppType cpp_type,
+                                    const Descriptor* message_type) const {
+  GOOGLE_CHECK(field->is_repeated());
+  GOOGLE_CHECK(field->cpp_type() == cpp_type ||
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+         cpp_type == FieldDescriptor::CPPTYPE_INT32))
+      << "The type parameter T in RepeatedFieldRef<T> API doesn't match "
+      << "the actual field type (for enums T should be the generated enum "
+      << "type or int32_t).";
+  if (message_type != nullptr) {
+    GOOGLE_CHECK_EQ(message_type, field->message_type());
+  }
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->MutableRawRepeatedField(
+        field->number(), field->type(), field->is_packed(), field);
+  } else {
+    return MutableRawNonOneof<char>(message, field);
+  }
+}
+
+MapFieldBase* Reflection::MutableMapData(Message* message,
+                                         const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "GetMapData",
+              "Field is not a map field.");
+  return MutableRaw<MapFieldBase>(message, field);
+}
+
+const MapFieldBase* Reflection::GetMapData(const Message& message,
+                                           const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "GetMapData",
+              "Field is not a map field.");
+  return &(GetRaw<MapFieldBase>(message, field));
+}
+
+namespace {
+
+// Helper function to transform migration schema into reflection schema.
+ReflectionSchema MigrationToReflectionSchema(
+    const Message* const* default_instance, const uint32_t* offsets,
+    MigrationSchema migration_schema) {
+  ReflectionSchema result;
+  result.default_instance_ = *default_instance;
+  // First 7 offsets are offsets to the special fields. The following offsets
+  // are the proto fields.
+  result.offsets_ = offsets + migration_schema.offsets_index + 6;
+  result.has_bit_indices_ = offsets + migration_schema.has_bit_indices_index;
+  result.has_bits_offset_ = offsets[migration_schema.offsets_index + 0];
+  result.metadata_offset_ = offsets[migration_schema.offsets_index + 1];
+  result.extensions_offset_ = offsets[migration_schema.offsets_index + 2];
+  result.oneof_case_offset_ = offsets[migration_schema.offsets_index + 3];
+  result.object_size_ = migration_schema.object_size;
+  result.weak_field_map_offset_ = offsets[migration_schema.offsets_index + 4];
+  result.inlined_string_donated_offset_ =
+      offsets[migration_schema.offsets_index + 5];
+  result.inlined_string_indices_ =
+      offsets + migration_schema.inlined_string_indices_index;
+  return result;
+}
+
+}  // namespace
+
+class AssignDescriptorsHelper {
+ public:
+  AssignDescriptorsHelper(MessageFactory* factory,
+                          Metadata* file_level_metadata,
+                          const EnumDescriptor** file_level_enum_descriptors,
+                          const MigrationSchema* schemas,
+                          const Message* const* default_instance_data,
+                          const uint32_t* offsets)
+      : factory_(factory),
+        file_level_metadata_(file_level_metadata),
+        file_level_enum_descriptors_(file_level_enum_descriptors),
+        schemas_(schemas),
+        default_instance_data_(default_instance_data),
+        offsets_(offsets) {}
+
+  void AssignMessageDescriptor(const Descriptor* descriptor) {
+    for (int i = 0; i < descriptor->nested_type_count(); i++) {
+      AssignMessageDescriptor(descriptor->nested_type(i));
+    }
+
+    file_level_metadata_->descriptor = descriptor;
+
+    file_level_metadata_->reflection =
+        new Reflection(descriptor,
+                       MigrationToReflectionSchema(default_instance_data_,
+                                                   offsets_, *schemas_),
+                       DescriptorPool::internal_generated_pool(), factory_);
+    for (int i = 0; i < descriptor->enum_type_count(); i++) {
+      AssignEnumDescriptor(descriptor->enum_type(i));
+    }
+    schemas_++;
+    default_instance_data_++;
+    file_level_metadata_++;
+  }
+
+  void AssignEnumDescriptor(const EnumDescriptor* descriptor) {
+    *file_level_enum_descriptors_ = descriptor;
+    file_level_enum_descriptors_++;
+  }
+
+  const Metadata* GetCurrentMetadataPtr() const { return file_level_metadata_; }
+
+ private:
+  MessageFactory* factory_;
+  Metadata* file_level_metadata_;
+  const EnumDescriptor** file_level_enum_descriptors_;
+  const MigrationSchema* schemas_;
+  const Message* const* default_instance_data_;
+  const uint32_t* offsets_;
+};
+
+namespace {
+
+// We have the routines that assign descriptors and build reflection
+// automatically delete the allocated reflection. MetadataOwner owns
+// all the allocated reflection instances.
+struct MetadataOwner {
+  ~MetadataOwner() {
+    for (auto range : metadata_arrays_) {
+      for (const Metadata* m = range.first; m < range.second; m++) {
+        delete m->reflection;
+      }
+    }
+  }
+
+  void AddArray(const Metadata* begin, const Metadata* end) {
+    mu_.Lock();
+    metadata_arrays_.push_back(std::make_pair(begin, end));
+    mu_.Unlock();
+  }
+
+  static MetadataOwner* Instance() {
+    static MetadataOwner* res = OnShutdownDelete(new MetadataOwner);
+    return res;
+  }
+
+ private:
+  MetadataOwner() = default;  // private because singleton
+
+  WrappedMutex mu_;
+  std::vector<std::pair<const Metadata*, const Metadata*> > metadata_arrays_;
+};
+
+void AddDescriptors(const DescriptorTable* table);
+
+void AssignDescriptorsImpl(const DescriptorTable* table, bool eager) {
+  // Ensure the file descriptor is added to the pool.
+  {
+    // This only happens once per proto file. So a global mutex to serialize
+    // calls to AddDescriptors.
+    static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
+    mu.Lock();
+    AddDescriptors(table);
+    mu.Unlock();
+  }
+  if (eager) {
+    // Normally we do not want to eagerly build descriptors of our deps.
+    // However if this proto is optimized for code size (ie using reflection)
+    // and it has a message extending a custom option of a descriptor with that
+    // message being optimized for code size as well. Building the descriptors
+    // in this file requires parsing the serialized file descriptor, which now
+    // requires parsing the message extension, which potentially requires
+    // building the descriptor of the message extending one of the options.
+    // However we are already updating descriptor pool under a lock. To prevent
+    // this the compiler statically looks for this case and we just make sure we
+    // first build the descriptors of all our dependencies, preventing the
+    // deadlock.
+    int num_deps = table->num_deps;
+    for (int i = 0; i < num_deps; i++) {
+      // In case of weak fields deps[i] could be null.
+      if (table->deps[i]) AssignDescriptors(table->deps[i], true);
+    }
+  }
+
+  // Fill the arrays with pointers to descriptors and reflection classes.
+  const FileDescriptor* file =
+      DescriptorPool::internal_generated_pool()->FindFileByName(
+          table->filename);
+  GOOGLE_CHECK(file != nullptr);
+
+  MessageFactory* factory = MessageFactory::generated_factory();
+
+  AssignDescriptorsHelper helper(
+      factory, table->file_level_metadata, table->file_level_enum_descriptors,
+      table->schemas, table->default_instances, table->offsets);
+
+  for (int i = 0; i < file->message_type_count(); i++) {
+    helper.AssignMessageDescriptor(file->message_type(i));
+  }
+
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    helper.AssignEnumDescriptor(file->enum_type(i));
+  }
+  if (file->options().cc_generic_services()) {
+    for (int i = 0; i < file->service_count(); i++) {
+      table->file_level_service_descriptors[i] = file->service(i);
+    }
+  }
+  MetadataOwner::Instance()->AddArray(table->file_level_metadata,
+                                      helper.GetCurrentMetadataPtr());
+}
+
+void AddDescriptorsImpl(const DescriptorTable* table) {
+  // Reflection refers to the default fields so make sure they are initialized.
+  internal::InitProtobufDefaults();
+
+  // Ensure all dependent descriptors are registered to the generated descriptor
+  // pool and message factory.
+  int num_deps = table->num_deps;
+  for (int i = 0; i < num_deps; i++) {
+    // In case of weak fields deps[i] could be null.
+    if (table->deps[i]) AddDescriptors(table->deps[i]);
+  }
+
+  // Register the descriptor of this file.
+  DescriptorPool::InternalAddGeneratedFile(table->descriptor, table->size);
+  MessageFactory::InternalRegisterGeneratedFile(table);
+}
+
+void AddDescriptors(const DescriptorTable* table) {
+  // AddDescriptors is not thread safe. Callers need to ensure calls are
+  // properly serialized. This function is only called pre-main by global
+  // descriptors and we can assume single threaded access or it's called
+  // by AssignDescriptorImpl which uses a mutex to sequence calls.
+  if (table->is_initialized) return;
+  table->is_initialized = true;
+  AddDescriptorsImpl(table);
+}
+
+}  // namespace
+
+// Separate function because it needs to be a friend of
+// Reflection
+void RegisterAllTypesInternal(const Metadata* file_level_metadata, int size) {
+  for (int i = 0; i < size; i++) {
+    const Reflection* reflection = file_level_metadata[i].reflection;
+    MessageFactory::InternalRegisterGeneratedMessage(
+        file_level_metadata[i].descriptor,
+        reflection->schema_.default_instance_);
+  }
+}
+
+namespace internal {
+
+Metadata AssignDescriptors(const DescriptorTable* (*table)(),
+                           internal::once_flag* once,
+                           const Metadata& metadata) {
+  call_once(*once, [=] {
+    auto* t = table();
+    AssignDescriptorsImpl(t, t->is_eager);
+  });
+
+  return metadata;
+}
+
+void AssignDescriptors(const DescriptorTable* table, bool eager) {
+  if (!eager) eager = table->is_eager;
+  call_once(*table->once, AssignDescriptorsImpl, table, eager);
+}
+
+AddDescriptorsRunner::AddDescriptorsRunner(const DescriptorTable* table) {
+  AddDescriptors(table);
+}
+
+void RegisterFileLevelMetadata(const DescriptorTable* table) {
+  AssignDescriptors(table);
+  RegisterAllTypesInternal(table->file_level_metadata, table->num_messages);
+}
+
+void UnknownFieldSetSerializer(const uint8_t* base, uint32_t offset,
+                               uint32_t /*tag*/, uint32_t /*has_offset*/,
+                               io::CodedOutputStream* output) {
+  const void* ptr = base + offset;
+  const InternalMetadata* metadata = static_cast<const InternalMetadata*>(ptr);
+  if (metadata->have_unknown_fields()) {
+    metadata->unknown_fields<UnknownFieldSet>(UnknownFieldSet::default_instance)
+        .SerializeToCodedStream(output);
+  }
+}
+
+bool IsDescendant(Message& root, const Message& message) {
+  const Reflection* reflection = root.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFieldsOmitStripped(root, &fields);
+
+  for (const auto* field : fields) {
+    // Skip non-message fields.
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    // Optional messages.
+    if (!field->is_repeated()) {
+      Message* sub_message = reflection->MutableMessage(&root, field);
+      if (sub_message == &message || IsDescendant(*sub_message, message)) {
+        return true;
+      }
+      continue;
+    }
+
+    // Repeated messages.
+    if (!IsMapFieldInApi(field)) {
+      int count = reflection->FieldSize(root, field);
+      for (int i = 0; i < count; i++) {
+        Message* sub_message =
+            reflection->MutableRepeatedMessage(&root, field, i);
+        if (sub_message == &message || IsDescendant(*sub_message, message)) {
+          return true;
+        }
+      }
+      continue;
+    }
+
+    // Map field: if accessed as repeated fields, messages are *copied* and
+    // matching pointer won't work. Must directly access map.
+    constexpr int kValIdx = 1;
+    const FieldDescriptor* val_field = field->message_type()->field(kValIdx);
+    // Skip map fields whose value type is not message.
+    if (val_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    MapIterator end = reflection->MapEnd(&root, field);
+    for (auto iter = reflection->MapBegin(&root, field); iter != end; ++iter) {
+      Message* sub_message = iter.MutableValueRef()->MutableMessageValue();
+      if (sub_message == &message || IsDescendant(*sub_message, message)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
new file mode 100644
index 0000000..334b2cc
--- /dev/null
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -0,0 +1,354 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 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_GENERATED_MESSAGE_REFLECTION_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class MapKey;
+class MapValueRef;
+class MessageLayoutInspector;
+class Message;
+struct Metadata;
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+class DefaultEmptyOneof;
+// Defined in other files.
+class ExtensionSet;  // extension_set.h
+class WeakFieldMap;  // weak_field_map.h
+
+// This struct describes the internal layout of the message, hence this is
+// used to act on the message reflectively.
+//   default_instance:  The default instance of the message.  This is only
+//                  used to obtain pointers to default instances of embedded
+//                  messages, which GetMessage() will return if the particular
+//                  sub-message has not been initialized yet.  (Thus, all
+//                  embedded message fields *must* have non-null pointers
+//                  in the default instance.)
+//   offsets:       An array of ints giving the byte offsets.
+//                  For each oneof or weak field, the offset is relative to the
+//                  default_instance. These can be computed at compile time
+//                  using the
+//                  PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET()
+//                  macro. For each none oneof field, the offset is related to
+//                  the start of the message object.  These can be computed at
+//                  compile time using the
+//                  PROTO2_GENERATED_MESSAGE_FIELD_OFFSET() macro.
+//                  Besides offsets for all fields, this array also contains
+//                  offsets for oneof unions. The offset of the i-th oneof union
+//                  is offsets[descriptor->field_count() + i].
+//   has_bit_indices:  Mapping from field indexes to their index in the has
+//                  bit array.
+//   has_bits_offset:  Offset in the message of an array of uint32s of size
+//                  descriptor->field_count()/32, rounded up.  This is a
+//                  bitfield where each bit indicates whether or not the
+//                  corresponding field of the message has been initialized.
+//                  The bit for field index i is obtained by the expression:
+//                    has_bits[i / 32] & (1 << (i % 32))
+//   unknown_fields_offset:  Offset in the message of the UnknownFieldSet for
+//                  the message.
+//   extensions_offset:  Offset in the message of the ExtensionSet for the
+//                  message, or -1 if the message type has no extension
+//                  ranges.
+//   oneof_case_offset:  Offset in the message of an array of uint32s of
+//                  size descriptor->oneof_decl_count().  Each uint32_t
+//                  indicates what field is set for each oneof.
+//   object_size:   The size of a message object of this type, as measured
+//                  by sizeof().
+//   arena_offset:  If a message doesn't have a unknown_field_set that stores
+//                  the arena, it must have a direct pointer to the arena.
+//   weak_field_map_offset: If the message proto has weak fields, this is the
+//                  offset of _weak_field_map_ in the generated proto. Otherwise
+//                  -1.
+struct ReflectionSchema {
+ public:
+  // Size of a google::protobuf::Message object of this type.
+  uint32_t GetObjectSize() const { return static_cast<uint32_t>(object_size_); }
+
+  bool InRealOneof(const FieldDescriptor* field) const {
+    return field->containing_oneof() &&
+           !field->containing_oneof()->is_synthetic();
+  }
+
+  // Offset of a non-oneof field.  Getting a field offset is slightly more
+  // efficient when we know statically that it is not a oneof field.
+  uint32_t GetFieldOffsetNonOneof(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK(!InRealOneof(field));
+    return OffsetValue(offsets_[field->index()], field->type());
+  }
+
+  // Offset of any field.
+  uint32_t GetFieldOffset(const FieldDescriptor* field) const {
+    if (InRealOneof(field)) {
+      size_t offset =
+          static_cast<size_t>(field->containing_type()->field_count()) +
+          field->containing_oneof()->index();
+      return OffsetValue(offsets_[offset], field->type());
+    } else {
+      return GetFieldOffsetNonOneof(field);
+    }
+  }
+
+  bool IsFieldInlined(const FieldDescriptor* field) const {
+    return Inlined(offsets_[field->index()], field->type());
+  }
+
+  uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
+    return static_cast<uint32_t>(oneof_case_offset_) +
+           static_cast<uint32_t>(
+               static_cast<size_t>(oneof_descriptor->index()) *
+               sizeof(uint32_t));
+  }
+
+  bool HasHasbits() const { return has_bits_offset_ != -1; }
+
+  // Bit index within the bit array of hasbits.  Bit order is low-to-high.
+  uint32_t HasBitIndex(const FieldDescriptor* field) const {
+    if (has_bits_offset_ == -1) return static_cast<uint32_t>(-1);
+    GOOGLE_DCHECK(HasHasbits());
+    return has_bit_indices_[field->index()];
+  }
+
+  // Byte offset of the hasbits array.
+  uint32_t HasBitsOffset() const {
+    GOOGLE_DCHECK(HasHasbits());
+    return static_cast<uint32_t>(has_bits_offset_);
+  }
+
+  bool HasInlinedString() const { return inlined_string_donated_offset_ != -1; }
+
+  // Bit index within the bit array of _inlined_string_donated_.  Bit order is
+  // low-to-high.
+  uint32_t InlinedStringIndex(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK(HasInlinedString());
+    return inlined_string_indices_[field->index()];
+  }
+
+  // Byte offset of the _inlined_string_donated_ array.
+  uint32_t InlinedStringDonatedOffset() const {
+    GOOGLE_DCHECK(HasInlinedString());
+    return static_cast<uint32_t>(inlined_string_donated_offset_);
+  }
+
+  // The offset of the InternalMetadataWithArena member.
+  // For Lite this will actually be an InternalMetadataWithArenaLite.
+  // The schema doesn't contain enough information to distinguish between
+  // these two cases.
+  uint32_t GetMetadataOffset() const {
+    return static_cast<uint32_t>(metadata_offset_);
+  }
+
+  // Whether this message has an ExtensionSet.
+  bool HasExtensionSet() const { return extensions_offset_ != -1; }
+
+  // The offset of the ExtensionSet in this message.
+  uint32_t GetExtensionSetOffset() const {
+    GOOGLE_DCHECK(HasExtensionSet());
+    return static_cast<uint32_t>(extensions_offset_);
+  }
+
+  // The off set of WeakFieldMap when the message contains weak fields.
+  // The default is 0 for now.
+  int GetWeakFieldMapOffset() const { return weak_field_map_offset_; }
+
+  bool IsDefaultInstance(const Message& message) const {
+    return &message == default_instance_;
+  }
+
+  // Returns a pointer to the default value for this field.  The size and type
+  // of the underlying data depends on the field's type.
+  const void* GetFieldDefault(const FieldDescriptor* field) const {
+    return reinterpret_cast<const uint8_t*>(default_instance_) +
+           OffsetValue(offsets_[field->index()], field->type());
+  }
+
+  // Returns true if the field is implicitly backed by LazyField.
+  bool IsEagerlyVerifiedLazyField(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE);
+    (void)field;
+    return false;
+  }
+
+  bool IsFieldStripped(const FieldDescriptor* field) const {
+    (void)field;
+    return false;
+  }
+
+  bool IsMessageStripped(const Descriptor* descriptor) const {
+    (void)descriptor;
+    return false;
+  }
+
+
+  bool HasWeakFields() const { return weak_field_map_offset_ > 0; }
+
+  // These members are intended to be private, but we cannot actually make them
+  // private because this prevents us from using aggregate initialization of
+  // them, ie.
+  //
+  //   ReflectionSchema schema = {a, b, c, d, e, ...};
+  // private:
+  const Message* default_instance_;
+  const uint32_t* offsets_;
+  const uint32_t* has_bit_indices_;
+  int has_bits_offset_;
+  int metadata_offset_;
+  int extensions_offset_;
+  int oneof_case_offset_;
+  int object_size_;
+  int weak_field_map_offset_;
+  const uint32_t* inlined_string_indices_;
+  int inlined_string_donated_offset_;
+
+  // We tag offset values to provide additional data about fields (such as
+  // "unused" or "lazy" or "inlined").
+  static uint32_t OffsetValue(uint32_t v, FieldDescriptor::Type type) {
+    if (type == FieldDescriptor::TYPE_MESSAGE ||
+        type == FieldDescriptor::TYPE_STRING ||
+        type == FieldDescriptor::TYPE_BYTES) {
+      return v & 0xFFFFFFFEu;
+    }
+    return v;
+  }
+
+  static bool Inlined(uint32_t v, FieldDescriptor::Type type) {
+    if (type == FieldDescriptor::TYPE_STRING ||
+        type == FieldDescriptor::TYPE_BYTES) {
+      return (v & 1u) != 0u;
+    } else {
+      // Non string/byte fields are not inlined.
+      return false;
+    }
+  }
+};
+
+// Structs that the code generator emits directly to describe a message.
+// These should never used directly except to build a ReflectionSchema
+// object.
+//
+// EXPERIMENTAL: these are changing rapidly, and may completely disappear
+// or merge with ReflectionSchema.
+struct MigrationSchema {
+  int32_t offsets_index;
+  int32_t has_bit_indices_index;
+  int32_t inlined_string_indices_index;
+  int object_size;
+};
+
+// This struct tries to reduce unnecessary padding.
+// The num_xxx might not be close to their respective pointer, but this saves
+// padding.
+struct PROTOBUF_EXPORT DescriptorTable {
+  mutable bool is_initialized;
+  bool is_eager;
+  int size;  // of serialized descriptor
+  const char* descriptor;
+  const char* filename;
+  once_flag* once;
+  const DescriptorTable* const* deps;
+  int num_deps;
+  int num_messages;
+  const MigrationSchema* schemas;
+  const Message* const* default_instances;
+  const uint32_t* offsets;
+  // update the following descriptor arrays.
+  Metadata* file_level_metadata;
+  const EnumDescriptor** file_level_enum_descriptors;
+  const ServiceDescriptor** file_level_service_descriptors;
+};
+
+enum {
+  // Tag used on offsets for fields that don't have a real offset.
+  // For example, weak message fields go into the WeakFieldMap and not in an
+  // actual field.
+  kInvalidFieldOffsetTag = 0x40000000u,
+};
+
+// AssignDescriptors() pulls the compiled FileDescriptor from the DescriptorPool
+// and uses it to populate all of the global variables which store pointers to
+// the descriptor objects.  It also constructs the reflection objects.  It is
+// called the first time anyone calls descriptor() or GetReflection() on one of
+// the types defined in the file.  AssignDescriptors() is thread-safe.
+void PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* table,
+                                       bool eager = false);
+
+// Overload used to implement GetMetadataStatic in the generated code.
+// See comments in compiler/cpp/internal/file.cc as to why.
+// It takes a `Metadata` and returns it to allow for tail calls and reduce
+// binary size.
+Metadata PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* (*table)(),
+                                           internal::once_flag* once,
+                                           const Metadata& metadata);
+
+// These cannot be in lite so we put them in the reflection.
+PROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8_t* base,
+                                               uint32_t offset, uint32_t tag,
+                                               uint32_t has_offset,
+                                               io::CodedOutputStream* output);
+
+struct PROTOBUF_EXPORT AddDescriptorsRunner {
+  explicit AddDescriptorsRunner(const DescriptorTable* table);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
new file mode 100644
index 0000000..50ce399
--- /dev/null
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -0,0 +1,1373 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// To test GeneratedMessageReflection, we actually let the protocol compiler
+// generate a full protocol message implementation and then test its
+// reflection interface.  This is much easier and more maintainable than
+// trying to create our own Message class for GeneratedMessageReflection
+// to wrap.
+//
+// The tests here closely mirror some of the tests in
+// compiler/cpp/unittest, except using the reflection interface
+// rather than generated accessors.
+
+#include <google/protobuf/generated_message_reflection.h>
+
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/map_unittest.pb.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/arena.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/test_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class GeneratedMessageReflectionTestHelper {
+ public:
+  static void UnsafeShallowSwapFields(
+      Message* lhs, Message* rhs,
+      const std::vector<const FieldDescriptor*>& fields) {
+    lhs->GetReflection()->UnsafeShallowSwapFields(lhs, rhs, fields);
+  }
+  static bool IsLazyExtension(const Message& msg, const FieldDescriptor* ext) {
+    return msg.GetReflection()->IsLazyExtension(msg, ext);
+  }
+  static bool IsLazyField(const Message& msg, const FieldDescriptor* field) {
+    return msg.GetReflection()->IsLazyField(field);
+  }
+  static bool IsEagerlyVerifiedLazyField(const Message& msg,
+                                         const FieldDescriptor* field) {
+    return msg.GetReflection()->IsEagerlyVerifiedLazyField(field);
+  }
+  static bool IsLazilyVerifiedLazyField(const Message& msg,
+                                        const FieldDescriptor* field) {
+    return msg.GetReflection()->IsLazilyVerifiedLazyField(field);
+  }
+};
+
+namespace {
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+const FieldDescriptor* F(const std::string& name) {
+  const FieldDescriptor* result =
+      unittest::TestAllTypes::descriptor()->FindFieldByName(name);
+  GOOGLE_CHECK(result != nullptr);
+  return result;
+}
+
+TEST(GeneratedMessageReflectionTest, Defaults) {
+  // Check that all default values are set correctly in the initial message.
+  unittest::TestAllTypes message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  reflection_tester.ExpectClearViaReflection(message);
+
+  const Reflection* reflection = message.GetReflection();
+
+  // Messages should return pointers to default instances until first use.
+  // (This is not checked by ExpectClear() since it is not actually true after
+  // the fields have been set and then cleared.)
+  EXPECT_EQ(&unittest::TestAllTypes::OptionalGroup::default_instance(),
+            &reflection->GetMessage(message, F("optionalgroup")));
+  EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
+            &reflection->GetMessage(message, F("optional_nested_message")));
+  EXPECT_EQ(&unittest::ForeignMessage::default_instance(),
+            &reflection->GetMessage(message, F("optional_foreign_message")));
+  EXPECT_EQ(&unittest_import::ImportMessage::default_instance(),
+            &reflection->GetMessage(message, F("optional_import_message")));
+}
+
+TEST(GeneratedMessageReflectionTest, Accessors) {
+  // Set every field to a unique value then go back and check all those
+  // values.
+  unittest::TestAllTypes message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  reflection_tester.SetAllFieldsViaReflection(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+  reflection_tester.ExpectAllFieldsSetViaReflection(message);
+
+  reflection_tester.ModifyRepeatedFieldsViaReflection(&message);
+  TestUtil::ExpectRepeatedFieldsModified(message);
+}
+
+TEST(GeneratedMessageReflectionTest, GetStringReference) {
+  // Test that GetStringReference() returns the underlying string when it
+  // is a normal string field.
+  unittest::TestAllTypes message;
+  message.set_optional_string("foo");
+  message.add_repeated_string("foo");
+
+  const Reflection* reflection = message.GetReflection();
+  std::string scratch;
+
+  EXPECT_EQ(
+      &message.optional_string(),
+      &reflection->GetStringReference(message, F("optional_string"), &scratch))
+      << "For simple string fields, GetStringReference() should return a "
+         "reference to the underlying string.";
+  EXPECT_EQ(&message.repeated_string(0),
+            &reflection->GetRepeatedStringReference(
+                message, F("repeated_string"), 0, &scratch))
+      << "For simple string fields, GetRepeatedStringReference() should "
+         "return "
+         "a reference to the underlying string.";
+}
+
+
+class GeneratedMessageReflectionSwapTest : public testing::TestWithParam<bool> {
+ protected:
+  void Swap(const Reflection* reflection, Message* lhs, Message* rhs) {
+    if (GetParam()) {
+      reflection->UnsafeArenaSwap(lhs, rhs);
+    } else {
+      reflection->Swap(lhs, rhs);
+    }
+  }
+  void SwapFields(const Reflection* reflection, Message* lhs, Message* rhs,
+                  const std::vector<const FieldDescriptor*>& fields) {
+    if (GetParam()) {
+      reflection->UnsafeArenaSwapFields(lhs, rhs, fields);
+    } else {
+      reflection->SwapFields(lhs, rhs, fields);
+    }
+  }
+};
+
+// unsafe_shallow_swap: true -> UnsafeArena* API.
+INSTANTIATE_TEST_SUITE_P(ReflectionSwap, GeneratedMessageReflectionSwapTest,
+                         testing::Bool());
+
+TEST_P(GeneratedMessageReflectionSwapTest, LhsSet) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
+
+  TestUtil::SetAllFields(&lhs);
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectClear(lhs);
+  TestUtil::ExpectAllFieldsSet(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, BothSet) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
+
+  TestUtil::SetAllFields(&lhs);
+  TestUtil::SetAllFields(&rhs);
+  TestUtil::ModifyRepeatedFields(&rhs);
+
+  const Reflection* reflection = lhs.GetReflection();
+  Swap(reflection, &lhs, &rhs);
+
+  TestUtil::ExpectRepeatedFieldsModified(lhs);
+  TestUtil::ExpectAllFieldsSet(rhs);
+
+  lhs.set_optional_int32(532819);
+
+  Swap(reflection, &lhs, &rhs);
+
+  EXPECT_EQ(532819, rhs.optional_int32());
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, LhsCleared) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
+
+  TestUtil::SetAllFields(&lhs);
+
+  // For proto2 message, for message field, Clear only reset hasbits, but
+  // doesn't delete the underlying field.
+  lhs.Clear();
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectClear(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, RhsCleared) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
+
+  TestUtil::SetAllFields(&rhs);
+
+  // For proto2 message, for message field, Clear only reset hasbits, but
+  // doesn't delete the underlying field.
+  rhs.Clear();
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectClear(lhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, Extensions) {
+  unittest::TestAllExtensions lhs;
+  unittest::TestAllExtensions rhs;
+
+  TestUtil::SetAllExtensions(&lhs);
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectExtensionsClear(lhs);
+  TestUtil::ExpectAllExtensionsSet(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, Unknown) {
+  unittest::TestEmptyMessage lhs, rhs;
+
+  lhs.mutable_unknown_fields()->AddVarint(1234, 1);
+
+  EXPECT_EQ(1, lhs.unknown_fields().field_count());
+  EXPECT_EQ(0, rhs.unknown_fields().field_count());
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+  EXPECT_EQ(0, lhs.unknown_fields().field_count());
+  EXPECT_EQ(1, rhs.unknown_fields().field_count());
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, Oneof) {
+  unittest::TestOneof2 lhs, rhs;
+  TestUtil::SetOneof1(&lhs);
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectOneofClear(lhs);
+  TestUtil::ExpectOneofSet1(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, OneofBothSet) {
+  unittest::TestOneof2 lhs, rhs;
+  TestUtil::SetOneof1(&lhs);
+  TestUtil::SetOneof2(&rhs);
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectOneofSet2(lhs);
+  TestUtil::ExpectOneofSet1(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, SwapFields) {
+  std::unique_ptr<unittest::TestAllTypes> lhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+  std::unique_ptr<unittest::TestAllTypes> rhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+  lhs->set_optional_double(12.3);
+  lhs->mutable_repeated_int32()->Add(10);
+  lhs->mutable_repeated_int32()->Add(20);
+
+  rhs->set_optional_string("hello");
+  rhs->mutable_repeated_int64()->Add(30);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Descriptor* descriptor = lhs->GetDescriptor();
+  fields.push_back(descriptor->FindFieldByName("optional_double"));
+  fields.push_back(descriptor->FindFieldByName("repeated_int32"));
+  fields.push_back(descriptor->FindFieldByName("optional_string"));
+  fields.push_back(descriptor->FindFieldByName("optional_uint64"));
+
+  SwapFields(lhs->GetReflection(), lhs.get(), rhs.get(), fields);
+
+  EXPECT_FALSE(lhs->has_optional_double());
+  EXPECT_EQ(0, lhs->repeated_int32_size());
+  EXPECT_TRUE(lhs->has_optional_string());
+  EXPECT_EQ("hello", lhs->optional_string());
+  EXPECT_EQ(0, lhs->repeated_int64_size());
+  EXPECT_FALSE(lhs->has_optional_uint64());
+
+  EXPECT_TRUE(rhs->has_optional_double());
+  EXPECT_EQ(12.3, rhs->optional_double());
+  EXPECT_EQ(2, rhs->repeated_int32_size());
+  EXPECT_EQ(10, rhs->repeated_int32(0));
+  EXPECT_EQ(20, rhs->repeated_int32(1));
+  EXPECT_FALSE(rhs->has_optional_string());
+  EXPECT_EQ(1, rhs->repeated_int64_size());
+  EXPECT_FALSE(rhs->has_optional_uint64());
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, SwapFieldsAll) {
+  std::unique_ptr<unittest::TestAllTypes> lhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+  std::unique_ptr<unittest::TestAllTypes> rhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+
+  TestUtil::SetAllFields(rhs.get());
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = lhs->GetReflection();
+  reflection->ListFields(*rhs, &fields);
+  SwapFields(reflection, lhs.get(), rhs.get(), fields);
+
+  TestUtil::ExpectAllFieldsSet(*lhs);
+  TestUtil::ExpectClear(*rhs);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsAllOnDifferentArena) {
+  Arena arena1, arena2;
+  auto* message1 = Arena::CreateMessage<unittest::TestAllTypes>(&arena1);
+  auto* message2 = Arena::CreateMessage<unittest::TestAllTypes>(&arena2);
+
+  TestUtil::SetAllFields(message2);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1->GetReflection();
+  reflection->ListFields(*message2, &fields);
+  reflection->SwapFields(message1, message2, fields);
+
+  TestUtil::ExpectAllFieldsSet(*message1);
+  TestUtil::ExpectClear(*message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsAllOnArenaHeap) {
+  Arena arena;
+  auto* message1 = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+  std::unique_ptr<unittest::TestAllTypes> message2(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+
+  TestUtil::SetAllFields(message2.get());
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1->GetReflection();
+  reflection->ListFields(*message2, &fields);
+  reflection->SwapFields(message1, message2.get(), fields);
+
+  TestUtil::ExpectAllFieldsSet(*message1);
+  TestUtil::ExpectClear(*message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsAllExtension) {
+  unittest::TestAllExtensions message1;
+  unittest::TestAllExtensions message2;
+
+  TestUtil::SetAllExtensions(&message1);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1.GetReflection();
+  reflection->ListFields(message1, &fields);
+  reflection->SwapFields(&message1, &message2, fields);
+
+  TestUtil::ExpectExtensionsClear(message1);
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsAllExtensionArenaHeap) {
+  Arena arena;
+
+  std::unique_ptr<unittest::TestAllExtensions> message1(
+      Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));
+  auto* message2 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+
+  TestUtil::SetAllExtensions(message1.get());
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1->GetReflection();
+  reflection->ListFields(*message1, &fields);
+  reflection->SwapFields(message1.get(), message2, fields);
+
+  TestUtil::ExpectExtensionsClear(*message1);
+  TestUtil::ExpectAllExtensionsSet(*message2);
+}
+
+TEST(GeneratedMessageReflectionTest, UnsafeShallowSwapFieldsAll) {
+  Arena arena;
+  auto* message1 = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+  auto* message2 = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+
+  TestUtil::SetAllFields(message2);
+
+  auto* kept_nested_message_ptr = message2->mutable_optional_nested_message();
+  auto* kept_foreign_message_ptr = message2->mutable_optional_foreign_message();
+  auto* kept_repeated_nested_message_ptr =
+      message2->mutable_repeated_nested_message(0);
+  auto* kept_repeated_foreign_message_ptr =
+      message2->mutable_repeated_foreign_message(0);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1->GetReflection();
+  reflection->ListFields(*message2, &fields);
+  GeneratedMessageReflectionTestHelper::UnsafeShallowSwapFields(
+      message1, message2, fields);
+
+  TestUtil::ExpectAllFieldsSet(*message1);
+  TestUtil::ExpectClear(*message2);
+
+  // Expects the swap to be shallow. Expects pointer stability to the element of
+  // the repeated fields (not the container).
+  EXPECT_EQ(kept_nested_message_ptr,
+            message1->mutable_optional_nested_message());
+  EXPECT_EQ(kept_foreign_message_ptr,
+            message1->mutable_optional_foreign_message());
+  EXPECT_EQ(kept_repeated_nested_message_ptr,
+            message1->mutable_repeated_nested_message(0));
+  EXPECT_EQ(kept_repeated_foreign_message_ptr,
+            message1->mutable_repeated_foreign_message(0));
+}
+
+TEST(GeneratedMessageReflectionTest, UnsafeShallowSwapFieldsMap) {
+  Arena arena;
+  auto* message1 = Arena::CreateMessage<unittest::TestMap>(&arena);
+  auto* message2 = Arena::CreateMessage<unittest::TestMap>(&arena);
+
+  MapTestUtil::SetMapFields(message2);
+
+  auto* kept_map_int32_fm_ptr =
+      &(*message2->mutable_map_int32_foreign_message())[0];
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1->GetReflection();
+  reflection->ListFields(*message2, &fields);
+  GeneratedMessageReflectionTestHelper::UnsafeShallowSwapFields(
+      message1, message2, fields);
+
+  MapTestUtil::ExpectMapFieldsSet(*message1);
+  MapTestUtil::ExpectClear(*message2);
+
+  // Expects the swap to be shallow.
+  EXPECT_EQ(kept_map_int32_fm_ptr,
+            &(*message1->mutable_map_int32_foreign_message())[0]);
+}
+
+TEST(GeneratedMessageReflectionTest, UnsafeShallowSwapFieldsAllExtension) {
+  Arena arena;
+  auto* message1 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  auto* message2 = Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+
+  TestUtil::SetAllExtensions(message1);
+
+  auto* kept_nested_message_ext_ptr =
+      message1->MutableExtension(unittest::optional_nested_message_extension);
+  auto* kept_foreign_message_ext_ptr =
+      message1->MutableExtension(unittest::optional_foreign_message_extension);
+  auto* kept_repeated_nested_message_ext_ptr =
+      message1->MutableRepeatedExtension(
+          unittest::repeated_nested_message_extension);
+  auto* kept_repeated_foreign_message_ext_ptr =
+      message1->MutableRepeatedExtension(
+          unittest::repeated_foreign_message_extension);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1->GetReflection();
+  reflection->ListFields(*message1, &fields);
+  GeneratedMessageReflectionTestHelper::UnsafeShallowSwapFields(
+      message1, message2, fields);
+
+  TestUtil::ExpectExtensionsClear(*message1);
+  TestUtil::ExpectAllExtensionsSet(*message2);
+
+  // Expects the swap to be shallow.
+  EXPECT_EQ(
+      kept_nested_message_ext_ptr,
+      message2->MutableExtension(unittest::optional_nested_message_extension));
+  EXPECT_EQ(
+      kept_foreign_message_ext_ptr,
+      message2->MutableExtension(unittest::optional_foreign_message_extension));
+  EXPECT_EQ(kept_repeated_nested_message_ext_ptr,
+            message2->MutableRepeatedExtension(
+                unittest::repeated_nested_message_extension));
+  EXPECT_EQ(kept_repeated_foreign_message_ext_ptr,
+            message2->MutableRepeatedExtension(
+                unittest::repeated_foreign_message_extension));
+}
+
+TEST(GeneratedMessageReflectionTest, SwapFieldsOneof) {
+  unittest::TestOneof2 message1, message2;
+  TestUtil::SetOneof1(&message1);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Descriptor* descriptor = message1.GetDescriptor();
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields.push_back(descriptor->field(i));
+  }
+  const Reflection* reflection = message1.GetReflection();
+  reflection->SwapFields(&message1, &message2, fields);
+
+  TestUtil::ExpectOneofClear(message1);
+  TestUtil::ExpectOneofSet1(message2);
+}
+
+TEST(GeneratedMessageReflectionTest, UnsafeShallowSwapFieldsOneof) {
+  Arena arena;
+  auto* message1 = Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  auto* message2 = Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  TestUtil::SetOneof1(message1);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Descriptor* descriptor = message1->GetDescriptor();
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields.push_back(descriptor->field(i));
+  }
+  GeneratedMessageReflectionTestHelper::UnsafeShallowSwapFields(
+      message1, message2, fields);
+
+  TestUtil::ExpectOneofClear(*message1);
+  TestUtil::ExpectOneofSet1(*message2);
+}
+
+TEST(GeneratedMessageReflectionTest,
+     UnsafeShallowSwapFieldsOneofExpectShallow) {
+  Arena arena;
+  auto* message1 = Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  auto* message2 = Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  TestUtil::SetOneof1(message1);
+  message1->mutable_foo_message()->set_moo_int(1000);
+  auto* kept_foo_ptr = message1->mutable_foo_message();
+
+  std::vector<const FieldDescriptor*> fields;
+  const Descriptor* descriptor = message1->GetDescriptor();
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields.push_back(descriptor->field(i));
+  }
+  GeneratedMessageReflectionTestHelper::UnsafeShallowSwapFields(
+      message1, message2, fields);
+
+  EXPECT_TRUE(message2->has_foo_message());
+  EXPECT_EQ(message2->foo_message().moo_int(), 1000);
+  EXPECT_EQ(kept_foo_ptr, message2->mutable_foo_message());
+}
+
+TEST(GeneratedMessageReflectionTest, RemoveLast) {
+  unittest::TestAllTypes message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  TestUtil::SetAllFields(&message);
+
+  reflection_tester.RemoveLastRepeatedsViaReflection(&message);
+
+  TestUtil::ExpectLastRepeatedsRemoved(message);
+}
+
+TEST(GeneratedMessageReflectionTest, RemoveLastExtensions) {
+  unittest::TestAllExtensions message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+
+  TestUtil::SetAllExtensions(&message);
+
+  reflection_tester.RemoveLastRepeatedsViaReflection(&message);
+
+  TestUtil::ExpectLastRepeatedExtensionsRemoved(message);
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseLast) {
+  unittest::TestAllTypes message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  TestUtil::ReflectionTester reflection_tester(descriptor);
+
+  TestUtil::SetAllFields(&message);
+
+  reflection_tester.ReleaseLastRepeatedsViaReflection(&message, false);
+
+  TestUtil::ExpectLastRepeatedsReleased(message);
+
+  // Now test that we actually release the right message.
+  message.Clear();
+  TestUtil::SetAllFields(&message);
+  ASSERT_EQ(2, message.repeated_foreign_message_size());
+  const protobuf_unittest::ForeignMessage* expected =
+      message.mutable_repeated_foreign_message(1);
+  (void)expected;  // unused in somce configurations
+  std::unique_ptr<Message> released(message.GetReflection()->ReleaseLast(
+      &message, descriptor->FindFieldByName("repeated_foreign_message")));
+  EXPECT_EQ(expected, released.get());
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseLastExtensions) {
+  unittest::TestAllExtensions message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  TestUtil::ReflectionTester reflection_tester(descriptor);
+
+  TestUtil::SetAllExtensions(&message);
+
+  reflection_tester.ReleaseLastRepeatedsViaReflection(&message, true);
+
+  TestUtil::ExpectLastRepeatedExtensionsReleased(message);
+
+  // Now test that we actually release the right message.
+  message.Clear();
+  TestUtil::SetAllExtensions(&message);
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_foreign_message_extension));
+  const protobuf_unittest::ForeignMessage* expected =
+      message.MutableExtension(unittest::repeated_foreign_message_extension, 1);
+  std::unique_ptr<Message> released(message.GetReflection()->ReleaseLast(
+      &message, descriptor->file()->FindExtensionByName(
+                    "repeated_foreign_message_extension")));
+  EXPECT_EQ(expected, released.get());
+}
+
+TEST(GeneratedMessageReflectionTest, SwapRepeatedElements) {
+  unittest::TestAllTypes message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  TestUtil::SetAllFields(&message);
+
+  // Swap and test that fields are all swapped.
+  reflection_tester.SwapRepeatedsViaReflection(&message);
+  TestUtil::ExpectRepeatedsSwapped(message);
+
+  // Swap back and test that fields are all back to original values.
+  reflection_tester.SwapRepeatedsViaReflection(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, SwapRepeatedElementsExtension) {
+  unittest::TestAllExtensions message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+
+  TestUtil::SetAllExtensions(&message);
+
+  // Swap and test that fields are all swapped.
+  reflection_tester.SwapRepeatedsViaReflection(&message);
+  TestUtil::ExpectRepeatedExtensionsSwapped(message);
+
+  // Swap back and test that fields are all back to original values.
+  reflection_tester.SwapRepeatedsViaReflection(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, Extensions) {
+  // Set every extension to a unique value then go back and check all those
+  // values.
+  unittest::TestAllExtensions message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+
+  reflection_tester.SetAllFieldsViaReflection(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+  reflection_tester.ExpectAllFieldsSetViaReflection(message);
+
+  reflection_tester.ModifyRepeatedFieldsViaReflection(&message);
+  TestUtil::ExpectRepeatedExtensionsModified(message);
+}
+
+TEST(GeneratedMessageReflectionTest, FindExtensionTypeByNumber) {
+  const Reflection* reflection =
+      unittest::TestAllExtensions::default_instance().GetReflection();
+
+  const FieldDescriptor* extension1 =
+      unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
+          "optional_int32_extension");
+  const FieldDescriptor* extension2 =
+      unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
+          "repeated_string_extension");
+
+  EXPECT_EQ(extension1,
+            reflection->FindKnownExtensionByNumber(extension1->number()));
+  EXPECT_EQ(extension2,
+            reflection->FindKnownExtensionByNumber(extension2->number()));
+
+  // Non-existent extension.
+  EXPECT_TRUE(reflection->FindKnownExtensionByNumber(62341) == nullptr);
+
+  // Extensions of TestAllExtensions should not show up as extensions of
+  // other types.
+  EXPECT_TRUE(unittest::TestAllTypes::default_instance()
+                  .GetReflection()
+                  ->FindKnownExtensionByNumber(extension1->number()) ==
+              nullptr);
+}
+
+TEST(GeneratedMessageReflectionTest, FindKnownExtensionByName) {
+  const Reflection* reflection =
+      unittest::TestAllExtensions::default_instance().GetReflection();
+
+  const FieldDescriptor* extension1 =
+      unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
+          "optional_int32_extension");
+  const FieldDescriptor* extension2 =
+      unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
+          "repeated_string_extension");
+
+  EXPECT_EQ(extension1,
+            reflection->FindKnownExtensionByName(extension1->full_name()));
+  EXPECT_EQ(extension2,
+            reflection->FindKnownExtensionByName(extension2->full_name()));
+
+  // Non-existent extension.
+  EXPECT_TRUE(reflection->FindKnownExtensionByName("no_such_ext") == nullptr);
+
+  // Extensions of TestAllExtensions should not show up as extensions of
+  // other types.
+  EXPECT_TRUE(unittest::TestAllTypes::default_instance()
+                  .GetReflection()
+                  ->FindKnownExtensionByName(extension1->full_name()) ==
+              nullptr);
+}
+
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedMessageTest) {
+  unittest::TestAllTypes from_message1;
+  unittest::TestAllTypes from_message2;
+  unittest::TestAllTypes to_message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+  reflection_tester.SetAllFieldsViaReflection(&from_message1);
+  reflection_tester.SetAllFieldsViaReflection(&from_message2);
+
+  // Before moving fields, we expect the nested messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are moved we should get non-nullptr releases.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message1, &to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // Another move to make sure that we can SetAllocated several times.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message2, &to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After SetAllocatedOptionalMessageFieldsToNullViaReflection() we expect the
+  // releases to be nullptr again.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToNullViaReflection(
+      &to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::IS_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedMessageOnArenaTest) {
+  unittest::TestAllTypes from_message1;
+  unittest::TestAllTypes from_message2;
+  Arena arena;
+  unittest::TestAllTypes* to_message =
+      Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+  reflection_tester.SetAllFieldsViaReflection(&from_message1);
+  reflection_tester.SetAllFieldsViaReflection(&from_message2);
+
+  // Before moving fields, we expect the nested messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are moved we should get non-nullptr releases.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message1, to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // Another move to make sure that we can SetAllocated several times.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message2, to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After SetAllocatedOptionalMessageFieldsToNullViaReflection() we expect the
+  // releases to be nullptr again.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToNullViaReflection(
+      to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::IS_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedExtensionMessageTest) {
+  unittest::TestAllExtensions from_message1;
+  unittest::TestAllExtensions from_message2;
+  unittest::TestAllExtensions to_message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+  reflection_tester.SetAllFieldsViaReflection(&from_message1);
+  reflection_tester.SetAllFieldsViaReflection(&from_message2);
+
+  // Before moving fields, we expect the nested messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are moved we should get non-nullptr releases.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message1, &to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // Another move to make sure that we can SetAllocated several times.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message2, &to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After SetAllocatedOptionalMessageFieldsToNullViaReflection() we expect the
+  // releases to be nullptr again.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToNullViaReflection(
+      &to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &to_message, TestUtil::ReflectionTester::IS_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedExtensionMessageOnArenaTest) {
+  Arena arena;
+  unittest::TestAllExtensions* to_message =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  unittest::TestAllExtensions from_message1;
+  unittest::TestAllExtensions from_message2;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+  reflection_tester.SetAllFieldsViaReflection(&from_message1);
+  reflection_tester.SetAllFieldsViaReflection(&from_message2);
+
+  // Before moving fields, we expect the nested messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are moved we should get non-nullptr releases.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message1, to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // Another move to make sure that we can SetAllocated several times.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      &from_message2, to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      to_message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After SetAllocatedOptionalMessageFieldsToNullViaReflection() we expect the
+  // releases to be nullptr again.
+  reflection_tester.SetAllocatedOptionalMessageFieldsToNullViaReflection(
+      to_message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      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);
+
+  const Reflection* reflection = message.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(message, &fields);
+  EXPECT_EQ(4, fields.size());
+}
+
+TEST(GeneratedMessageReflectionTest, Oneof) {
+  unittest::TestOneof2 message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = message.GetReflection();
+
+  // Check default values.
+  EXPECT_EQ(
+      0, reflection->GetInt32(message, descriptor->FindFieldByName("foo_int")));
+  EXPECT_EQ("", reflection->GetString(
+                    message, descriptor->FindFieldByName("foo_string")));
+  EXPECT_EQ("", reflection->GetString(message,
+                                      descriptor->FindFieldByName("foo_cord")));
+  EXPECT_EQ("", reflection->GetString(
+                    message, descriptor->FindFieldByName("foo_string_piece")));
+  EXPECT_EQ("", reflection->GetString(
+                    message, descriptor->FindFieldByName("foo_bytes")));
+  EXPECT_EQ(
+      unittest::TestOneof2::FOO,
+      reflection->GetEnum(message, descriptor->FindFieldByName("foo_enum"))
+          ->number());
+  EXPECT_EQ(&unittest::TestOneof2::NestedMessage::default_instance(),
+            &reflection->GetMessage(
+                message, descriptor->FindFieldByName("foo_message")));
+  EXPECT_EQ(&unittest::TestOneof2::FooGroup::default_instance(),
+            &reflection->GetMessage(message,
+                                    descriptor->FindFieldByName("foogroup")));
+  EXPECT_NE(&unittest::TestOneof2::FooGroup::default_instance(),
+            &reflection->GetMessage(
+                message, descriptor->FindFieldByName("foo_lazy_message")));
+  EXPECT_EQ(
+      5, reflection->GetInt32(message, descriptor->FindFieldByName("bar_int")));
+  EXPECT_EQ("STRING", reflection->GetString(
+                          message, descriptor->FindFieldByName("bar_string")));
+  EXPECT_EQ("CORD", reflection->GetString(
+                        message, descriptor->FindFieldByName("bar_cord")));
+  EXPECT_EQ("SPIECE",
+            reflection->GetString(
+                message, descriptor->FindFieldByName("bar_string_piece")));
+  EXPECT_EQ("BYTES", reflection->GetString(
+                         message, descriptor->FindFieldByName("bar_bytes")));
+  EXPECT_EQ(
+      unittest::TestOneof2::BAR,
+      reflection->GetEnum(message, descriptor->FindFieldByName("bar_enum"))
+          ->number());
+
+  // Check Set functions.
+  reflection->SetInt32(&message, descriptor->FindFieldByName("foo_int"), 123);
+  EXPECT_EQ(123, reflection->GetInt32(message,
+                                      descriptor->FindFieldByName("foo_int")));
+  reflection->SetString(&message, descriptor->FindFieldByName("foo_string"),
+                        "abc");
+  EXPECT_EQ("abc", reflection->GetString(
+                       message, descriptor->FindFieldByName("foo_string")));
+  reflection->SetString(&message, descriptor->FindFieldByName("foo_bytes"),
+                        "bytes");
+  EXPECT_EQ("bytes", reflection->GetString(
+                         message, descriptor->FindFieldByName("foo_bytes")));
+  reflection->SetString(&message, descriptor->FindFieldByName("bar_cord"),
+                        "change_cord");
+  EXPECT_EQ(
+      "change_cord",
+      reflection->GetString(message, descriptor->FindFieldByName("bar_cord")));
+  reflection->SetString(&message,
+                        descriptor->FindFieldByName("bar_string_piece"),
+                        "change_spiece");
+  EXPECT_EQ("change_spiece",
+            reflection->GetString(
+                message, descriptor->FindFieldByName("bar_string_piece")));
+
+  message.clear_foo();
+  message.clear_bar();
+  TestUtil::ExpectOneofClear(message);
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedOneofMessageTest) {
+  unittest::TestOneof2 from_message1;
+  unittest::TestOneof2 from_message2;
+  unittest::TestOneof2 to_message;
+  const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+  const Reflection* reflection = to_message.GetReflection();
+
+  Message* released = reflection->ReleaseMessage(
+      &to_message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released == nullptr);
+  released = reflection->ReleaseMessage(
+      &to_message, descriptor->FindFieldByName("foo_message"));
+  EXPECT_TRUE(released == nullptr);
+
+  TestUtil::ReflectionTester::SetOneofViaReflection(&from_message1);
+  TestUtil::ReflectionTester::ExpectOneofSetViaReflection(from_message1);
+
+  TestUtil::ReflectionTester::
+      SetAllocatedOptionalMessageFieldsToMessageViaReflection(&from_message1,
+                                                              &to_message);
+  const Message& sub_message = reflection->GetMessage(
+      to_message, descriptor->FindFieldByName("foo_lazy_message"));
+  (void)sub_message;  // unused in somce configurations
+  released = reflection->ReleaseMessage(
+      &to_message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released != nullptr);
+  EXPECT_EQ(&sub_message, released);
+  delete released;
+
+  TestUtil::ReflectionTester::SetOneofViaReflection(&from_message2);
+
+  reflection->MutableMessage(&from_message2,
+                             descriptor->FindFieldByName("foo_message"));
+
+  TestUtil::ReflectionTester::
+      SetAllocatedOptionalMessageFieldsToMessageViaReflection(&from_message2,
+                                                              &to_message);
+
+  const Message& sub_message2 = reflection->GetMessage(
+      to_message, descriptor->FindFieldByName("foo_message"));
+  (void)sub_message2;  // unused in somce configurations
+  released = reflection->ReleaseMessage(
+      &to_message, descriptor->FindFieldByName("foo_message"));
+  EXPECT_TRUE(released != nullptr);
+  EXPECT_EQ(&sub_message2, released);
+  delete released;
+}
+
+TEST(GeneratedMessageReflectionTest, SetAllocatedOneofMessageOnArenaTest) {
+  unittest::TestOneof2 from_message1;
+  unittest::TestOneof2 from_message2;
+  Arena arena;
+  unittest::TestOneof2* to_message =
+      Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+  const Reflection* reflection = to_message->GetReflection();
+
+  Message* released = reflection->ReleaseMessage(
+      to_message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released == nullptr);
+  released = reflection->ReleaseMessage(
+      to_message, descriptor->FindFieldByName("foo_message"));
+  EXPECT_TRUE(released == nullptr);
+
+  TestUtil::ReflectionTester::SetOneofViaReflection(&from_message1);
+  TestUtil::ReflectionTester::ExpectOneofSetViaReflection(from_message1);
+
+  TestUtil::ReflectionTester::
+      SetAllocatedOptionalMessageFieldsToMessageViaReflection(&from_message1,
+                                                              to_message);
+  const Message& sub_message = reflection->GetMessage(
+      *to_message, descriptor->FindFieldByName("foo_lazy_message"));
+  released = reflection->ReleaseMessage(
+      to_message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released != nullptr);
+  // Since sub_message is arena allocated, releasing it results in copying it
+  // into new heap-allocated memory.
+  EXPECT_NE(&sub_message, released);
+  delete released;
+
+  TestUtil::ReflectionTester::SetOneofViaReflection(&from_message2);
+
+  reflection->MutableMessage(&from_message2,
+                             descriptor->FindFieldByName("foo_message"));
+
+  TestUtil::ReflectionTester::
+      SetAllocatedOptionalMessageFieldsToMessageViaReflection(&from_message2,
+                                                              to_message);
+
+  const Message& sub_message2 = reflection->GetMessage(
+      *to_message, descriptor->FindFieldByName("foo_message"));
+  released = reflection->ReleaseMessage(
+      to_message, descriptor->FindFieldByName("foo_message"));
+  EXPECT_TRUE(released != nullptr);
+  // Since sub_message2 is arena allocated, releasing it results in copying it
+  // into new heap-allocated memory.
+  EXPECT_NE(&sub_message2, released);
+  delete released;
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseMessageTest) {
+  unittest::TestAllTypes message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  // When nothing is set, we expect all released messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are set we should get non-nullptr releases.
+  reflection_tester.SetAllFieldsViaReflection(&message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After Clear() we may or may not get a message from ReleaseMessage().
+  // This is implementation specific.
+  reflection_tester.SetAllFieldsViaReflection(&message);
+  message.Clear();
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &message, TestUtil::ReflectionTester::CAN_BE_NULL);
+
+  // Test a different code path for setting after releasing.
+  TestUtil::SetAllFields(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseExtensionMessageTest) {
+  unittest::TestAllExtensions message;
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+
+  // When nothing is set, we expect all released messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are set we should get non-nullptr releases.
+  reflection_tester.SetAllFieldsViaReflection(&message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After Clear() we may or may not get a message from ReleaseMessage().
+  // This is implementation specific.
+  reflection_tester.SetAllFieldsViaReflection(&message);
+  message.Clear();
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      &message, TestUtil::ReflectionTester::CAN_BE_NULL);
+
+  // Test a different code path for setting after releasing.
+  TestUtil::SetAllExtensions(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(GeneratedMessageReflectionTest, ReleaseOneofMessageTest) {
+  unittest::TestOneof2 message;
+  TestUtil::ReflectionTester::SetOneofViaReflection(&message);
+
+  const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+  const Reflection* reflection = message.GetReflection();
+  const Message& sub_message = reflection->GetMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+  (void)sub_message;  // unused in somce configurations
+  Message* released = reflection->ReleaseMessage(
+      &message, descriptor->FindFieldByName("foo_lazy_message"));
+
+  EXPECT_TRUE(released != nullptr);
+  EXPECT_EQ(&sub_message, released);
+  delete released;
+
+  released = reflection->ReleaseMessage(
+      &message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released == nullptr);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseMessageTest) {
+  Arena arena;
+  unittest::TestAllTypes* message =
+      Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  // When nothing is set, we expect all released messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are set we should get non-nullptr releases.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After Clear() we may or may not get a message from ReleaseMessage().
+  // This is implementation specific.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  message->Clear();
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::CAN_BE_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseExtensionMessageTest) {
+  Arena arena;
+  unittest::TestAllExtensions* message =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+
+  // When nothing is set, we expect all released messages to be nullptr.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are set we should get non-nullptr releases.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After Clear() we may or may not get a message from ReleaseMessage().
+  // This is implementation specific.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  message->Clear();
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::CAN_BE_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseOneofMessageTest) {
+  Arena arena;
+  unittest::TestOneof2* message =
+      Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  TestUtil::ReflectionTester::SetOneofViaReflection(message);
+
+  const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+  const Reflection* reflection = message->GetReflection();
+  Message* released = reflection->ReleaseMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+
+  EXPECT_TRUE(released != nullptr);
+  delete released;
+
+  released = reflection->ReleaseMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released == nullptr);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST(GeneratedMessageReflectionTest, UsageErrors) {
+  unittest::TestAllTypes message;
+  const Reflection* reflection = message.GetReflection();
+  const Descriptor* descriptor = message.GetDescriptor();
+
+#define f(NAME) descriptor->FindFieldByName(NAME)
+
+  // Testing every single failure mode would be too much work.  Let's just
+  // check a few.
+  EXPECT_DEATH(
+      reflection->GetInt32(message,
+                           descriptor->FindFieldByName("optional_int64")),
+      "Protocol Buffer reflection usage error:\n"
+      "  Method      : google::protobuf::Reflection::GetInt32\n"
+      "  Message type: protobuf_unittest\\.TestAllTypes\n"
+      "  Field       : protobuf_unittest\\.TestAllTypes\\.optional_int64\n"
+      "  Problem     : Field is not the right type for this message:\n"
+      "    Expected  : CPPTYPE_INT32\n"
+      "    Field type: CPPTYPE_INT64");
+  EXPECT_DEATH(reflection->GetInt32(
+                   message, descriptor->FindFieldByName("repeated_int32")),
+               "Protocol Buffer reflection usage error:\n"
+               "  Method      : google::protobuf::Reflection::GetInt32\n"
+               "  Message type: protobuf_unittest.TestAllTypes\n"
+               "  Field       : protobuf_unittest.TestAllTypes.repeated_int32\n"
+               "  Problem     : Field is repeated; the method requires a "
+               "singular field.");
+  EXPECT_DEATH(
+      reflection->GetInt32(
+          message,
+          unittest::ForeignMessage::descriptor()->FindFieldByName("c")),
+      "Protocol Buffer reflection usage error:\n"
+      "  Method      : google::protobuf::Reflection::GetInt32\n"
+      "  Message type: protobuf_unittest.TestAllTypes\n"
+      "  Field       : protobuf_unittest.ForeignMessage.c\n"
+      "  Problem     : Field does not match message type.");
+  EXPECT_DEATH(
+      reflection->HasField(
+          message,
+          unittest::ForeignMessage::descriptor()->FindFieldByName("c")),
+      "Protocol Buffer reflection usage error:\n"
+      "  Method      : google::protobuf::Reflection::HasField\n"
+      "  Message type: protobuf_unittest.TestAllTypes\n"
+      "  Field       : protobuf_unittest.ForeignMessage.c\n"
+      "  Problem     : Field does not match message type.");
+
+#undef f
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+
+using internal::IsDescendant;
+
+TEST(GeneratedMessageReflection, IsDescendantMessage) {
+  unittest::TestAllTypes msg1, msg2;
+  TestUtil::SetAllFields(&msg1);
+  msg2 = msg1;
+
+  EXPECT_TRUE(IsDescendant(msg1, msg1.optional_nested_message()));
+  EXPECT_TRUE(IsDescendant(msg1, msg1.repeated_foreign_message(0)));
+
+  EXPECT_FALSE(IsDescendant(msg1, msg2.optional_nested_message()));
+  EXPECT_FALSE(IsDescendant(msg1, msg2.repeated_foreign_message(0)));
+}
+
+TEST(GeneratedMessageReflection, IsDescendantMap) {
+  unittest::TestMap msg1, msg2;
+  (*msg1.mutable_map_int32_foreign_message())[0].set_c(100);
+  TestUtil::SetAllFields(&(*msg1.mutable_map_int32_all_types())[0]);
+  msg2 = msg1;
+
+  EXPECT_TRUE(IsDescendant(msg1, msg1.map_int32_foreign_message().at(0)));
+  EXPECT_TRUE(IsDescendant(msg1, msg1.map_int32_all_types().at(0)));
+
+  EXPECT_FALSE(IsDescendant(msg1, msg2.map_int32_foreign_message().at(0)));
+  EXPECT_FALSE(IsDescendant(msg1, msg2.map_int32_all_types().at(0)));
+}
+
+TEST(GeneratedMessageReflection, IsDescendantExtension) {
+  unittest::TestAllExtensions msg1, msg2;
+  TestUtil::SetAllExtensions(&msg1);
+  msg2 = msg1;
+
+  EXPECT_TRUE(IsDescendant(
+      msg1, msg1.GetExtension(unittest::optional_nested_message_extension)));
+  EXPECT_TRUE(IsDescendant(
+      msg1,
+      msg1.GetExtension(unittest::repeated_foreign_message_extension, 0)));
+
+  EXPECT_FALSE(IsDescendant(
+      msg1, msg2.GetExtension(unittest::optional_nested_message_extension)));
+  EXPECT_FALSE(IsDescendant(
+      msg1,
+      msg2.GetExtension(unittest::repeated_foreign_message_extension, 0)));
+}
+
+TEST(GeneratedMessageReflection, IsDescendantOneof) {
+  unittest::TestOneof msg1, msg2;
+  TestUtil::SetAllFields(msg1.mutable_foo_message());
+  msg2 = msg1;
+
+  EXPECT_TRUE(IsDescendant(msg1, msg1.foo_message().optional_nested_message()));
+  EXPECT_TRUE(
+      IsDescendant(msg1, msg1.foo_message().repeated_foreign_message(0)));
+
+  EXPECT_FALSE(
+      IsDescendant(msg1, msg2.foo_message().optional_nested_message()));
+  EXPECT_FALSE(
+      IsDescendant(msg1, msg2.foo_message().repeated_foreign_message(0)));
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h
new file mode 100644
index 0000000..b1bb1de
--- /dev/null
+++ b/src/google/protobuf/generated_message_tctable_decl.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.
+
+// This file contains declarations needed in generated headers for messages
+// that use tail-call table parsing. Everything in this file is for internal
+// use only.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Additional information about this field:
+struct TcFieldData {
+  constexpr TcFieldData() : data(0) {}
+
+  // Fast table entry constructor:
+  constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
+                        uint16_t offset)
+      : data(uint64_t{offset} << 48 |      //
+             uint64_t{aux_idx} << 24 |     //
+             uint64_t{hasbit_idx} << 16 |  //
+             uint64_t{coded_tag}) {}
+
+  // Fields used in fast table parsing:
+  //
+  //     Bit:
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+  //     :   .   :   .   :   . 16|=======| [16] coded_tag()
+  //     :   .   :   .   : 24|===|   .   : [ 8] hasbit_idx()
+  //     :   .   :   . 32|===|   :   .   : [ 8] aux_idx()
+  //     :   . 48:---.---:   .   :   .   : [16] (unused)
+  //     |=======|   .   :   .   :   .   : [16] offset()
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+
+  template <typename TagType = uint16_t>
+  TagType coded_tag() const {
+    return static_cast<TagType>(data);
+  }
+  uint8_t hasbit_idx() const { return static_cast<uint8_t>(data >> 16); }
+  uint8_t aux_idx() const { return static_cast<uint8_t>(data >> 24); }
+  uint16_t offset() const { return static_cast<uint16_t>(data >> 48); }
+
+  // Fields used in mini table parsing:
+  //
+  //     Bit:
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+  //     :   .   :   .   |===============| [32] tag() (decoded)
+  //     |===============|   .   :   .   : [32] entry_offset()
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+
+  uint32_t tag() const { return static_cast<uint32_t>(data); }
+  uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
+
+  uint64_t data;
+};
+
+struct TcParseTableBase;
+
+// TailCallParseFunc is the function pointer type used in the tailcall table.
+typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL);
+
+namespace field_layout {
+struct Offset {
+  uint32_t off;
+};
+}  // namespace field_layout
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+#pragma warning(push)
+// TcParseTableBase is intentionally overaligned on 32 bit targets.
+#pragma warning(disable : 4324)
+#endif
+
+// Base class for message-level table with info for the tail-call parser.
+struct alignas(uint64_t) TcParseTableBase {
+  // Common attributes for message layout:
+  uint16_t has_bits_offset;
+  uint16_t extension_offset;
+  uint32_t extension_range_low;
+  uint32_t extension_range_high;
+  uint32_t max_field_number;
+  uint8_t fast_idx_mask;
+  uint16_t lookup_table_offset;
+  uint32_t skipmap32;
+  uint32_t field_entries_offset;
+  uint16_t num_field_entries;
+
+  uint16_t num_aux_entries;
+  uint32_t aux_offset;
+
+  const MessageLite* default_instance;
+
+  // Handler for fields which are not handled by table dispatch.
+  TailCallParseFunc fallback;
+
+  // This constructor exactly follows the field layout, so it's technically
+  // not necessary.  However, it makes it much much easier to add or re-arrange
+  // fields, because it can be overloaded with an additional constructor,
+  // temporarily allowing both old and new protocol buffer headers to be
+  // compiled.
+  constexpr TcParseTableBase(
+      uint16_t has_bits_offset, uint16_t extension_offset,
+      uint32_t extension_range_low, uint32_t extension_range_high,
+      uint32_t max_field_number, uint8_t fast_idx_mask,
+      uint16_t lookup_table_offset, uint32_t skipmap32,
+      uint32_t field_entries_offset, uint16_t num_field_entries,
+      uint16_t num_aux_entries, uint32_t aux_offset,
+      const MessageLite* default_instance, TailCallParseFunc fallback)
+      : has_bits_offset(has_bits_offset),
+        extension_offset(extension_offset),
+        extension_range_low(extension_range_low),
+        extension_range_high(extension_range_high),
+        max_field_number(max_field_number),
+        fast_idx_mask(fast_idx_mask),
+        lookup_table_offset(lookup_table_offset),
+        skipmap32(skipmap32),
+        field_entries_offset(field_entries_offset),
+        num_field_entries(num_field_entries),
+        num_aux_entries(num_aux_entries),
+        aux_offset(aux_offset),
+        default_instance(default_instance),
+        fallback(fallback) {}
+
+  // Table entry for fast-path tailcall dispatch handling.
+  struct FastFieldEntry {
+    // Target function for dispatch:
+    TailCallParseFunc target;
+    // Field data used during parse:
+    TcFieldData bits;
+  };
+  // There is always at least one table entry.
+  const FastFieldEntry* fast_entry(size_t idx) const {
+    return reinterpret_cast<const FastFieldEntry*>(this + 1) + idx;
+  }
+
+  // Returns a begin iterator (pointer) to the start of the field lookup table.
+  const uint16_t* field_lookup_begin() const {
+    return reinterpret_cast<const uint16_t*>(reinterpret_cast<uintptr_t>(this) +
+                                             lookup_table_offset);
+  }
+
+  // Field entry for all fields.
+  struct FieldEntry {
+    uint32_t offset;     // offset in the message object
+    int32_t has_idx;     // has-bit index
+    uint16_t aux_idx;    // index for `field_aux`.
+    uint16_t type_card;  // `FieldType` and `Cardinality` (see _impl.h)
+  };
+
+  // Returns a begin iterator (pointer) to the start of the field entries array.
+  const FieldEntry* field_entries_begin() const {
+    return reinterpret_cast<const FieldEntry*>(
+        reinterpret_cast<uintptr_t>(this) + field_entries_offset);
+  }
+
+  // Auxiliary entries for field types that need extra information.
+  union FieldAux {
+    constexpr FieldAux() : message_default(nullptr) {}
+    constexpr FieldAux(bool (*enum_validator)(int))
+        : enum_validator(enum_validator) {}
+    constexpr FieldAux(field_layout::Offset off) : offset(off.off) {}
+    constexpr FieldAux(int16_t range_start, uint16_t range_length)
+        : enum_range{range_start, range_length} {}
+    constexpr FieldAux(const MessageLite* msg) : message_default(msg) {}
+    bool (*enum_validator)(int);
+    struct {
+      int16_t start;    // minimum enum number (if it fits)
+      uint16_t length;  // length of range (i.e., max = start + length - 1)
+    } enum_range;
+    uint32_t offset;
+    const MessageLite* message_default;
+  };
+  const FieldAux* field_aux(uint32_t idx) const {
+    return reinterpret_cast<const FieldAux*>(reinterpret_cast<uintptr_t>(this) +
+                                             aux_offset) +
+           idx;
+  }
+  const FieldAux* field_aux(const FieldEntry* entry) const {
+    return field_aux(entry->aux_idx);
+  }
+
+  // Field name data
+  const char* name_data() const {
+    return reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(this) +
+                                         aux_offset +
+                                         num_aux_entries * sizeof(FieldAux));
+  }
+};
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+#pragma warning(pop)
+#endif
+
+static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16,
+              "Fast field entry is too big.");
+static_assert(sizeof(TcParseTableBase::FieldEntry) <= 16,
+              "Field entry is too big.");
+
+template <size_t kFastTableSizeLog2, size_t kNumFieldEntries = 0,
+          size_t kNumFieldAux = 0, size_t kNameTableSize = 0,
+          size_t kFieldLookupSize = 2>
+struct TcParseTable {
+  TcParseTableBase header;
+
+  // Entries for each field.
+  //
+  // Fields are indexed by the lowest bits of their field number. The field
+  // number is masked to fit inside the table. Note that the parsing logic
+  // generally calls `TailCallParseTableBase::fast_entry()` instead of accessing
+  // this field directly.
+  std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
+      fast_entries;
+
+  // Just big enough to find all the field entries.
+  std::array<uint16_t, kFieldLookupSize> field_lookup_table;
+  // Entries for all fields:
+  std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
+  std::array<TcParseTableBase::FieldAux, kNumFieldAux> aux_entries;
+  std::array<char, kNameTableSize> field_names;
+};
+
+// Partial specialization: if there are no aux entries, there will be no array.
+// In C++, arrays cannot have length 0, but (C++11) std::array<T, 0> is valid.
+// However, different implementations have different sizeof(std::array<T, 0>).
+// Skipping the member makes offset computations portable.
+template <size_t kFastTableSizeLog2, size_t kNumFieldEntries,
+          size_t kNameTableSize, size_t kFieldLookupSize>
+struct TcParseTable<kFastTableSizeLog2, kNumFieldEntries, 0, kNameTableSize,
+                    kFieldLookupSize> {
+  TcParseTableBase header;
+  std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
+      fast_entries;
+  std::array<uint16_t, kFieldLookupSize> field_lookup_table;
+  std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
+  std::array<char, kNameTableSize> field_names;
+};
+
+// Partial specialization: if there are no fields at all, then we can save space
+// by skipping the field numbers and entries.
+template <size_t kNameTableSize, size_t kFieldLookupSize>
+struct TcParseTable<0, 0, 0, kNameTableSize, kFieldLookupSize> {
+  TcParseTableBase header;
+  // N.B.: the fast entries are sized by log2, so 2**0 fields = 1 entry.
+  // The fast parsing loop will always use this entry, so it must be present.
+  std::array<TcParseTableBase::FastFieldEntry, 1> fast_entries;
+  std::array<uint16_t, kFieldLookupSize> field_lookup_table;
+  std::array<char, kNameTableSize> field_names;
+};
+
+static_assert(std::is_standard_layout<TcParseTable<1>>::value,
+              "TcParseTable must be standard layout.");
+
+static_assert(offsetof(TcParseTable<1>, fast_entries) ==
+                  sizeof(TcParseTableBase),
+              "Table entries must be laid out after TcParseTableBase.");
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
diff --git a/src/google/protobuf/generated_message_tctable_full.cc b/src/google/protobuf/generated_message_tctable_full.cc
new file mode 100644
index 0000000..b77bb8d
--- /dev/null
+++ b/src/google/protobuf/generated_message_tctable_full.cc
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cstdint>
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/unknown_field_set.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+const char* TcParser::GenericFallback(PROTOBUF_TC_PARAM_DECL) {
+  return GenericFallbackImpl<Message, UnknownFieldSet>(PROTOBUF_TC_PARAM_PASS);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
new file mode 100644
index 0000000..21fa533
--- /dev/null
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -0,0 +1,553 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
+
+#include <cstdint>
+#include <type_traits>
+
+#include <google/protobuf/port.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_decl.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class UnknownFieldSet;
+
+namespace internal {
+
+// Field layout enums.
+//
+// Structural information about fields is packed into a 16-bit value. The enum
+// types below represent bitwise fields, along with their respective widths,
+// shifts, and masks.
+//
+//     Bit:
+//     +-----------------------+-----------------------+
+//     |15        ..          8|7         ..          0|
+//     +-----------------------+-----------------------+
+//     :  .  :  .  :  .  :  .  :  .  :  .  : 3|========| [3] FieldType
+//     :     :     :     :     :     : 5|=====|  :     : [2] FieldCardinality
+//     :  .  :  .  :  .  :  . 8|========|  :  .  :  .  : [3] FieldRep
+//     :     :     :   10|=====|     :     :     :     : [2] TransformValidation
+//     :  .  :  .12|=====|  .  :  .  :  .  :  .  :  .  : [2] FormatDiscriminator
+//     +-----------------------+-----------------------+
+//     |15        ..          8|7         ..          0|
+//     +-----------------------+-----------------------+
+//
+namespace field_layout {
+// clang-format off
+
+// Field kind (3 bits):
+// These values broadly represent a wire type and an in-memory storage class.
+enum FieldKind : uint16_t {
+  kFkShift = 0,
+  kFkBits = 3,
+  kFkMask = ((1 << kFkBits) - 1) << kFkShift,
+
+  kFkNone = 0,
+  kFkVarint,        // WT=0     rep=8,32,64 bits
+  kFkPackedVarint,  // WT=2     rep=8,32,64 bits
+  kFkFixed,         // WT=1,5   rep=32,64 bits
+  kFkPackedFixed,   // WT=2     rep=32,64 bits
+  kFkString,        // WT=2     rep=various
+  kFkMessage,       // WT=2,3,4 rep=MessageLite*
+  // Maps are a special case of Message, but use different parsing logic.
+  kFkMap,           // WT=2     rep=Map(Lite)<various, various>
+};
+
+static_assert(kFkMap < (1 << kFkBits), "too many types");
+
+// Cardinality (2 bits):
+// These values determine how many values a field can have and its presence.
+// Packed fields are represented in FieldType.
+enum Cardinality : uint16_t {
+  kFcShift    = kFkShift + kFkBits,
+  kFcBits     = 2,
+  kFcMask     = ((1 << kFcBits) - 1) << kFcShift,
+
+  kFcSingular = 0,
+  kFcOptional = 1 << kFcShift,
+  kFcRepeated = 2 << kFcShift,
+  kFcOneof    = 3 << kFcShift,
+};
+
+// Field representation (3 bits):
+// These values are the specific refinements of storage classes in FieldType.
+enum FieldRep : uint16_t {
+  kRepShift    = kFcShift + kFcBits,
+  kRepBits     = 3,
+  kRepMask     = ((1 << kRepBits) - 1) << kRepShift,
+
+  // Numeric types (used for optional and repeated fields):
+  kRep8Bits    = 0,
+  kRep32Bits   = 2 << kRepShift,
+  kRep64Bits   = 3 << kRepShift,
+  // String types:
+  kRepAString  = 0,               // ArenaStringPtr
+  kRepIString  = 1 << kRepShift,  // InlinedString
+  kRepCord     = 2 << kRepShift,  // absl::Cord
+  kRepSPiece   = 3 << kRepShift,  // StringPieceField
+  kRepSString  = 4 << kRepShift,  // std::string*
+  // Message types (WT=2 unless otherwise noted):
+  kRepMessage  = 0,               // MessageLite*
+  kRepGroup    = 1 << kRepShift,  // MessageLite* (WT=3,4)
+  kRepLazy     = 2 << kRepShift,  // LazyField*
+  kRepIWeak    = 3 << kRepShift,  // ImplicitWeak
+};
+
+// Transform/validation (2 bits):
+// These values determine transforms or validation to/from wire format.
+enum TransformValidation : uint16_t {
+  kTvShift     = kRepShift + kRepBits,
+  kTvBits      = 2,
+  kTvMask      = ((1 << kTvBits) - 1) << kTvShift,
+
+  // Varint fields:
+  kTvZigZag    = 1 << kTvShift,
+  kTvEnum      = 2 << kTvShift,  // validate using generated _IsValid()
+  kTvRange     = 3 << kTvShift,  // validate using FieldAux::enum_range
+  // String fields:
+  kTvUtf8Debug = 1 << kTvShift,  // proto2
+  kTvUtf8      = 2 << kTvShift,  // proto3
+};
+
+static_assert((kTvEnum & kTvRange) != 0,
+              "enum validation types must share a bit");
+static_assert((kTvEnum & kTvRange & kTvZigZag) == 0,
+              "zigzag encoding is not enum validation");
+
+// Format discriminators (2 bits):
+enum FormatDiscriminator : uint16_t {
+  kFmtShift      = kTvShift + kTvBits,
+  kFmtBits       = 2,
+  kFmtMask       = ((1 << kFmtBits) - 1) << kFmtShift,
+
+  // Numeric:
+  kFmtUnsigned   = 1 << kFmtShift,  // fixed, varint
+  kFmtSigned     = 2 << kFmtShift,  // fixed, varint
+  kFmtFloating   = 3 << kFmtShift,  // fixed
+  kFmtEnum       = 3 << kFmtShift,  // varint
+  // Strings:
+  kFmtUtf8       = 1 << kFmtShift,  // string (proto3, enforce_utf8=true)
+  kFmtUtf8Escape = 2 << kFmtShift,  // string (proto2, enforce_utf8=false)
+  // Bytes:
+  kFmtArray      = 1 << kFmtShift,  // bytes
+  // Messages:
+  kFmtShow       = 1 << kFmtShift,  // message, map
+};
+
+// Update this assertion (and comments above) when adding or removing bits:
+static_assert(kFmtShift + kFmtBits == 12, "number of bits changed");
+
+// This assertion should not change unless the storage width changes:
+static_assert(kFmtShift + kFmtBits <= 16, "too many bits");
+
+// Convenience aliases (16 bits, with format):
+enum FieldType : uint16_t {
+  // Numeric types:
+  kBool            = kFkVarint | kRep8Bits,
+
+  kFixed32         = kFkFixed  | kRep32Bits | kFmtUnsigned,
+  kUInt32          = kFkVarint | kRep32Bits | kFmtUnsigned,
+  kSFixed32        = kFkFixed  | kRep32Bits | kFmtSigned,
+  kInt32           = kFkVarint | kRep32Bits | kFmtSigned,
+  kSInt32          = kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag,
+  kFloat           = kFkFixed  | kRep32Bits | kFmtFloating,
+  kEnum            = kFkVarint | kRep32Bits | kFmtEnum   | kTvEnum,
+  kEnumRange       = kFkVarint | kRep32Bits | kFmtEnum   | kTvRange,
+  kOpenEnum        = kFkVarint | kRep32Bits | kFmtEnum,
+
+  kFixed64         = kFkFixed  | kRep64Bits | kFmtUnsigned,
+  kUInt64          = kFkVarint | kRep64Bits | kFmtUnsigned,
+  kSFixed64        = kFkFixed  | kRep64Bits | kFmtSigned,
+  kInt64           = kFkVarint | kRep64Bits | kFmtSigned,
+  kSInt64          = kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag,
+  kDouble          = kFkFixed  | kRep64Bits | kFmtFloating,
+
+  kPackedBool      = kFkPackedVarint | kRep8Bits,
+
+  kPackedFixed32   = kFkPackedFixed  | kRep32Bits | kFmtUnsigned,
+  kPackedUInt32    = kFkPackedVarint | kRep32Bits | kFmtUnsigned,
+  kPackedSFixed32  = kFkPackedFixed  | kRep32Bits | kFmtSigned,
+  kPackedInt32     = kFkPackedVarint | kRep32Bits | kFmtSigned,
+  kPackedSInt32    = kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag,
+  kPackedFloat     = kFkPackedFixed  | kRep32Bits | kFmtFloating,
+  kPackedEnum      = kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvEnum,
+  kPackedEnumRange = kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvRange,
+  kPackedOpenEnum  = kFkPackedVarint | kRep32Bits | kFmtEnum,
+
+  kPackedFixed64   = kFkPackedFixed  | kRep64Bits | kFmtUnsigned,
+  kPackedUInt64    = kFkPackedVarint | kRep64Bits | kFmtUnsigned,
+  kPackedSFixed64  = kFkPackedFixed  | kRep64Bits | kFmtSigned,
+  kPackedInt64     = kFkPackedVarint | kRep64Bits | kFmtSigned,
+  kPackedSInt64    = kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag,
+  kPackedDouble    = kFkPackedFixed  | kRep64Bits | kFmtFloating,
+
+  // String types:
+  kBytes           = kFkString | kFmtArray,
+  kRawString       = kFkString | kFmtUtf8  | kTvUtf8Debug,
+  kUtf8String      = kFkString | kFmtUtf8  | kTvUtf8,
+
+  // Message types:
+  kMessage         = kFkMessage,
+
+  // Map types:
+  kMap             = kFkMap,
+};
+
+// clang-format on
+}  // namespace field_layout
+
+// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
+// defined in port_def.inc.
+//
+// Note that this is performance sensitive: changing the parameters will change
+// the registers used by the ABI calling convention, which subsequently affects
+// register selection logic inside the function.
+
+// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
+#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
+
+#ifndef NDEBUG
+template <size_t align>
+#ifndef _MSC_VER
+[[noreturn]]
+#endif
+void AlignFail(uintptr_t address) {
+  GOOGLE_LOG(FATAL) << "Unaligned (" << align << ") access at " << address;
+}
+
+extern template void AlignFail<4>(uintptr_t);
+extern template void AlignFail<8>(uintptr_t);
+#endif
+
+// TcParser implements most of the parsing logic for tailcall tables.
+class PROTOBUF_EXPORT TcParser final {
+ public:
+  static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
+  static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
+
+  static const char* ParseLoop(MessageLite* msg, const char* ptr,
+                               ParseContext* ctx,
+                               const TcParseTableBase* table);
+
+  // Functions referenced by generated fast tables (numeric types):
+  //   F: fixed      V: varint     Z: zigzag
+  //   8/32/64: storage type width (bits)
+  //   S: singular   R: repeated   P: packed
+  //   1/2: tag length (bytes)
+
+  // Fixed:
+  static const char* FastF32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64P2(PROTOBUF_TC_PARAM_DECL);
+
+  // Varint:
+  static const char* FastV8S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64P2(PROTOBUF_TC_PARAM_DECL);
+
+  // Varint (with zigzag):
+  static const char* FastZ32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (closed enum):
+  //   E: closed enum (N.B.: open enums use V32, above)
+  //   r: enum range  v: enum validator (_IsValid function)
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastErS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvR2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (string types):
+  //   B: bytes      S: string     U: UTF-8 string
+  //   (empty): ArenaStringPtr     i: InlinedString
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastBS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUR2(PROTOBUF_TC_PARAM_DECL);
+
+  static const char* FastBiS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBiS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSiS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSiS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUiS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUiS2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (message types):
+  //   M: message    G: group
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastMS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGR2(PROTOBUF_TC_PARAM_DECL);
+
+  template <typename T>
+  static inline T& RefAt(void* x, size_t offset) {
+    T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
+#ifndef NDEBUG
+    if (PROTOBUF_PREDICT_FALSE(
+            reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
+      AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
+    }
+#endif
+    return *target;
+  }
+
+  template <typename T>
+  static inline const T& RefAt(const void* x, size_t offset) {
+    const T* target =
+        reinterpret_cast<const T*>(static_cast<const char*>(x) + offset);
+#ifndef NDEBUG
+    if (PROTOBUF_PREDICT_FALSE(
+            reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
+      AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
+    }
+#endif
+    return *target;
+  }
+
+  template <typename T>
+  static inline T ReadAt(const void* x, size_t offset) {
+    T out;
+    memcpy(&out, static_cast<const char*>(x) + offset, sizeof(T));
+    return out;
+  }
+
+  // Mini parsing:
+  //
+  // This function parses a field from incoming data based on metadata stored in
+  // the message definition. If the field is not defined in the message, it is
+  // stored in either the ExtensionSet (if applicable) or the UnknownFieldSet.
+  //
+  // NOTE: Currently, this function only calls the table-level fallback
+  // function, so it should only be called as the fallback from fast table
+  // parsing.
+  static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
+
+ private:
+  friend class GeneratedTcTableLiteTest;
+
+  template <typename TagType, bool group_coding>
+  static inline const char* SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, bool group_coding>
+  static inline const char* RepeatedParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL);
+
+  static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
+      MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) {
+    const uint32_t has_bits_offset = table->has_bits_offset;
+    if (has_bits_offset) {
+      // Only the first 32 has-bits are updated. Nothing above those is stored,
+      // but e.g. messages without has-bits update the upper bits.
+      RefAt<uint32_t>(msg, has_bits_offset) = static_cast<uint32_t>(hasbits);
+    }
+  }
+
+  static const char* TagDispatch(PROTOBUF_TC_PARAM_DECL);
+  static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL);
+  static const char* ToParseLoop(PROTOBUF_TC_PARAM_DECL);
+  static const char* Error(PROTOBUF_TC_PARAM_DECL);
+
+  static const char* FastUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
+
+  class ScopedArenaSwap;
+
+  template <class MessageBaseT, class UnknownFieldsT>
+  static const char* GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL) {
+#define CHK_(x) \
+  if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr /* NOLINT */
+
+    SyncHasbits(msg, hasbits, table);
+    CHK_(ptr);
+    uint32_t tag = data.tag();
+    if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
+      ctx->SetLastTag(tag);
+      return ptr;
+    }
+    uint32_t num = tag >> 3;
+    if (table->extension_range_low <= num &&
+        num <= table->extension_range_high) {
+      return RefAt<ExtensionSet>(msg, table->extension_offset)
+          .ParseField(tag, ptr,
+                      static_cast<const MessageBaseT*>(table->default_instance),
+                      &msg->_internal_metadata_, ctx);
+    }
+    return UnknownFieldParse(
+        tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
+        ptr, ctx);
+#undef CHK_
+  }
+
+  // Note: `inline` is needed on template function declarations below to avoid
+  // -Wattributes diagnostic in GCC.
+
+  // Implementations for fast fixed field parsing functions:
+  template <typename LayoutType, typename TagType>
+  static inline const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
+  template <typename LayoutType, typename TagType>
+  static inline const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
+  template <typename LayoutType, typename TagType>
+  static inline const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast varint field parsing functions:
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
+
+  // Helper for ints > 127:
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static const char* SingularVarBigint(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast enum field parsing functions:
+  template <typename TagType, uint16_t xform_val>
+  static inline const char* SingularEnum(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, uint16_t xform_val>
+  static inline const char* RepeatedEnum(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast string field parsing functions:
+  enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
+  template <typename TagType, Utf8Type utf8>
+  static inline const char* SingularString(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, Utf8Type utf8>
+  static inline const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
+
+  // Mini field lookup:
+  static const TcParseTableBase::FieldEntry* FindFieldEntry(
+      const TcParseTableBase* table, uint32_t field_num);
+  static StringPiece MessageName(const TcParseTableBase* table);
+  static StringPiece FieldName(const TcParseTableBase* table,
+                                     const TcParseTableBase::FieldEntry*);
+  static bool ChangeOneof(const TcParseTableBase* table,
+                          const TcParseTableBase::FieldEntry& entry,
+                          uint32_t field_num, ParseContext* ctx,
+                          MessageLite* msg);
+
+  // UTF-8 validation:
+  static void ReportFastUtf8Error(uint32_t decoded_tag,
+                                  const TcParseTableBase* table);
+  static bool MpVerifyUtf8(StringPiece wire_bytes,
+                           const TcParseTableBase* table,
+                           const TcParseTableBase::FieldEntry& entry,
+                           uint16_t xform_val);
+
+  // For FindFieldEntry tests:
+  friend class FindFieldEntryTest;
+  static constexpr const uint32_t kMtSmallScanSize = 4;
+
+  // Mini parsing:
+  static const char* MpVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpPackedVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpPackedFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpString(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedString(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpMessage(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpMap(PROTOBUF_TC_PARAM_DECL);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
new file mode 100644
index 0000000..9993811
--- /dev/null
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -0,0 +1,1859 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <numeric>
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_decl.h>
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/inlined_string_field.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+using FieldEntry = TcParseTableBase::FieldEntry;
+
+//////////////////////////////////////////////////////////////////////////////
+// Template instantiations:
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef NDEBUG
+template void AlignFail<4>(uintptr_t);
+template void AlignFail<8>(uintptr_t);
+#endif
+
+const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) {
+  return GenericFallbackImpl<MessageLite, std::string>(PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Core fast parsing implementation:
+//////////////////////////////////////////////////////////////////////////////
+
+class TcParser::ScopedArenaSwap final {
+ public:
+  ScopedArenaSwap(MessageLite* msg, ParseContext* ctx)
+      : ctx_(ctx), saved_(ctx->data().arena) {
+    ctx_->data().arena = msg->GetArenaForAllocation();
+  }
+  ScopedArenaSwap(const ScopedArenaSwap&) = delete;
+  ~ScopedArenaSwap() { ctx_->data().arena = saved_; }
+
+ private:
+  ParseContext* const ctx_;
+  Arena* const saved_;
+};
+
+PROTOBUF_NOINLINE const char* TcParser::ParseLoop(
+    MessageLite* msg, const char* ptr, ParseContext* ctx,
+    const TcParseTableBase* table) {
+  ScopedArenaSwap saved(msg, ctx);
+  while (!ctx->Done(&ptr)) {
+    // Unconditionally read has bits, even if we don't have has bits.
+    // has_bits_offset will be 0 and we will just read something valid.
+    uint64_t hasbits = ReadAt<uint32_t>(msg, table->has_bits_offset);
+    ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
+    if (ptr == nullptr) break;
+    if (ctx->LastTag() != 1) break;  // Ended on terminating tag
+  }
+  return ptr;
+}
+
+  // Dispatch to the designated parse function
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
+    PROTOBUF_TC_PARAM_DECL) {
+  const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
+  const size_t idx = coded_tag & table->fast_idx_mask;
+  PROTOBUF_ASSUME((idx & 7) == 0);
+  auto* fast_entry = table->fast_entry(idx >> 3);
+  data = fast_entry->bits;
+  data.data ^= coded_tag;
+  PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
+}
+
+// We can only safely call from field to next field if the call is optimized
+// to a proper tail call. Otherwise we blow through stack. Clang and gcc
+// reliably do this optimization in opt mode, but do not perform this in debug
+// mode. Luckily the structure of the algorithm is such that it's always
+// possible to just return and use the enclosing parse loop as a trampoline.
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
+    PROTOBUF_TC_PARAM_DECL) {
+  constexpr bool always_return = !PROTOBUF_TAILCALL;
+  if (always_return || !ctx->DataAvailable(ptr)) {
+    PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  }
+  PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)data;
+  (void)ctx;
+  SyncHasbits(msg, hasbits, table);
+  return ptr;
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)data;
+  (void)ctx;
+  (void)ptr;
+  SyncHasbits(msg, hasbits, table);
+  return nullptr;
+}
+
+// On the fast path, a (matching) 1-byte tag already has the decoded value.
+static uint32_t FastDecodeTag(uint8_t coded_tag) {
+  return coded_tag;
+}
+
+// On the fast path, a (matching) 2-byte tag always needs to be decoded.
+static uint32_t FastDecodeTag(uint16_t coded_tag) {
+  uint32_t result = coded_tag;
+  result += static_cast<int8_t>(coded_tag);
+  return result >> 1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Core mini parsing implementation:
+//////////////////////////////////////////////////////////////////////////////
+
+// Field lookup table layout:
+//
+// Because it consists of a series of variable-length segments, the lookuup
+// table is organized within an array of uint16_t, and each element is either
+// a uint16_t or a uint32_t stored little-endian as a pair of uint16_t.
+//
+// Its fundamental building block maps 16 contiguously ascending field numbers
+// to their locations within the field entry table:
+
+struct SkipEntry16 {
+  uint16_t skipmap;
+  uint16_t field_entry_offset;
+};
+
+// The skipmap is a bitfield of which of those field numbers do NOT have a
+// field entry.  The lowest bit of the skipmap corresponds to the lowest of
+// the 16 field numbers, so if a proto had only fields 1, 2, 3, and 7, the
+// skipmap would contain 0b11111111'10111000.
+//
+// The field lookup table begins with a single 32-bit skipmap that maps the
+// field numbers 1 through 32.  This is because the majority of proto
+// messages only contain fields numbered 1 to 32.
+//
+// The rest of the lookup table is a repeated series of
+// { 32-bit field #,  #SkipEntry16s,  {SkipEntry16...} }
+// That is, the next thing is a pair of uint16_t that form the next
+// lowest field number that the lookup table handles.  If this number is -1,
+// that is the end of the table.  Then there is a uint16_t that is
+// the number of contiguous SkipEntry16 entries that follow, and then of
+// course the SkipEntry16s themselves.
+
+// Originally developed and tested at https://godbolt.org/z/vbc7enYcf
+
+// Returns the address of the field for `tag` in the table's field entries.
+// Returns nullptr if the field was not found.
+const TcParseTableBase::FieldEntry* TcParser::FindFieldEntry(
+    const TcParseTableBase* table, uint32_t field_num) {
+  const FieldEntry* const field_entries = table->field_entries_begin();
+
+  uint32_t fstart = 1;
+  uint32_t adj_fnum = field_num - fstart;
+
+  if (PROTOBUF_PREDICT_TRUE(adj_fnum < 32)) {
+    uint32_t skipmap = table->skipmap32;
+    uint32_t skipbit = 1 << adj_fnum;
+    if (PROTOBUF_PREDICT_FALSE(skipmap & skipbit)) return nullptr;
+    skipmap &= skipbit - 1;
+#if (__GNUC__ || __clang__) && __POPCNT__
+    // Note: here and below, skipmap typically has very few set bits
+    // (31 in the worst case, but usually zero) so a loop isn't that
+    // bad, and a compiler-generated popcount is typically only
+    // worthwhile if the processor itself has hardware popcount support.
+    adj_fnum -= __builtin_popcount(skipmap);
+#else
+    while (skipmap) {
+      --adj_fnum;
+      skipmap &= skipmap - 1;
+    }
+#endif
+    auto* entry = field_entries + adj_fnum;
+    PROTOBUF_ASSUME(entry != nullptr);
+    return entry;
+  }
+  const uint16_t* lookup_table = table->field_lookup_begin();
+  for (;;) {
+#ifdef PROTOBUF_LITTLE_ENDIAN
+    memcpy(&fstart, lookup_table, sizeof(fstart));
+#else
+    fstart = lookup_table[0] | (lookup_table[1] << 16);
+#endif
+    lookup_table += sizeof(fstart) / sizeof(*lookup_table);
+    uint32_t num_skip_entries = *lookup_table++;
+    if (field_num < fstart) return nullptr;
+    adj_fnum = field_num - fstart;
+    uint32_t skip_num = adj_fnum / 16;
+    if (PROTOBUF_PREDICT_TRUE(skip_num < num_skip_entries)) {
+      // for each group of 16 fields we have:
+      // a bitmap of 16 bits
+      // a 16-bit field-entry offset for the first of them.
+      auto* skip_data = lookup_table + (adj_fnum / 16) * (sizeof(SkipEntry16) /
+                                                          sizeof(uint16_t));
+      SkipEntry16 se = {skip_data[0], skip_data[1]};
+      adj_fnum &= 15;
+      uint32_t skipmap = se.skipmap;
+      uint16_t skipbit = 1 << adj_fnum;
+      if (PROTOBUF_PREDICT_FALSE(skipmap & skipbit)) return nullptr;
+      skipmap &= skipbit - 1;
+      adj_fnum += se.field_entry_offset;
+#if (__GNUC__ || __clang__) && __POPCNT__
+      adj_fnum -= __builtin_popcount(skipmap);
+#else
+      while (skipmap) {
+        --adj_fnum;
+        skipmap &= skipmap - 1;
+      }
+#endif
+      auto* entry = field_entries + adj_fnum;
+      PROTOBUF_ASSUME(entry != nullptr);
+      return entry;
+    }
+    lookup_table +=
+        num_skip_entries * (sizeof(SkipEntry16) / sizeof(*lookup_table));
+  }
+}
+
+// Field names are stored in a format of:
+//
+// 1) A table of name sizes, one byte each, from 1 to 255 per name.
+//    `entries` is the size of this first table.
+// 1a) padding bytes, so the table of name sizes is a multiple of
+//     eight bytes in length. They are zero.
+//
+// 2) All the names, concatenated, with neither separation nor termination.
+//
+// This is designed to be compact but not particularly fast to retrieve.
+// In particular, it takes O(n) to retrieve the name of the n'th field,
+// which is usually fine because most protos have fewer than 10 fields.
+static StringPiece FindName(const char* name_data, size_t entries,
+                                  size_t index) {
+  // The compiler unrolls these... if this isn't fast enough,
+  // there's an AVX version at https://godbolt.org/z/eojrjqzfr
+  // ARM-compatible version at https://godbolt.org/z/n5YT5Ee85
+
+  // The field name sizes are padded up to a multiple of 8, so we
+  // must pad them here.
+  size_t num_sizes = (entries + 7) & -8;
+  auto* uint8s = reinterpret_cast<const uint8_t*>(name_data);
+  size_t pos = std::accumulate(uint8s, uint8s + index, num_sizes);
+  size_t size = name_data[index];
+  auto* start = &name_data[pos];
+  return {start, size};
+}
+
+StringPiece TcParser::MessageName(const TcParseTableBase* table) {
+  return FindName(table->name_data(), table->num_field_entries + 1, 0);
+}
+
+StringPiece TcParser::FieldName(const TcParseTableBase* table,
+                                      const FieldEntry* field_entry) {
+  const FieldEntry* const field_entries = table->field_entries_begin();
+  auto field_index = static_cast<size_t>(field_entry - field_entries);
+  return FindName(table->name_data(), table->num_field_entries + 1,
+                  field_index + 1);
+}
+
+const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
+  uint32_t tag;
+  ptr = ReadTagInlined(ptr, &tag);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+
+  auto* entry = FindFieldEntry(table, tag >> 3);
+  if (entry == nullptr) {
+    data.data = tag;
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // The handler may need the tag and the entry to resolve fallback logic. Both
+  // of these are 32 bits, so pack them into (the 64-bit) `data`. Since we can't
+  // pack the entry pointer itself, just pack its offset from `table`.
+  uint64_t entry_offset = reinterpret_cast<const char*>(entry) -
+                          reinterpret_cast<const char*>(table);
+  data.data = entry_offset << 32 | tag;
+
+  using field_layout::FieldKind;
+  auto field_type = entry->type_card & FieldKind::kFkMask;
+  switch (field_type) {
+    case FieldKind::kFkNone:
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkVarint:
+      PROTOBUF_MUSTTAIL return MpVarint(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkPackedVarint:
+      PROTOBUF_MUSTTAIL return MpPackedVarint(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkFixed:
+      PROTOBUF_MUSTTAIL return MpFixed(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkPackedFixed:
+      PROTOBUF_MUSTTAIL return MpPackedFixed(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkString:
+      PROTOBUF_MUSTTAIL return MpString(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkMessage:
+      PROTOBUF_MUSTTAIL return MpMessage(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkMap:
+      PROTOBUF_MUSTTAIL return MpMap(PROTOBUF_TC_PARAM_PASS);
+    default:
+      return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+}
+
+namespace {
+
+// Offset returns the address `offset` bytes after `base`.
+inline void* Offset(void* base, uint32_t offset) {
+  return static_cast<uint8_t*>(base) + offset;
+}
+
+// InvertPacked changes tag bits from the given wire type to length
+// delimited. This is the difference expected between packed and non-packed
+// repeated fields.
+template <WireFormatLite::WireType Wt>
+inline PROTOBUF_ALWAYS_INLINE void InvertPacked(TcFieldData& data) {
+  data.data ^= Wt ^ WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+// Message fields
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename TagType, bool group_coding>
+inline PROTOBUF_ALWAYS_INLINE
+const char* TcParser::SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto saved_tag = UnalignedLoad<TagType>(ptr);
+  ptr += sizeof(TagType);
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  SyncHasbits(msg, hasbits, table);
+  auto& field = RefAt<MessageLite*>(msg, data.offset());
+  if (field == nullptr) {
+    const MessageLite* default_instance =
+        table->field_aux(data.aux_idx())->message_default;
+    field = default_instance->New(ctx->data().arena);
+  }
+  if (group_coding) {
+    return ctx->ParseGroup(field, ptr, FastDecodeTag(saved_tag));
+  }
+  return ctx->ParseMessage(field, ptr);
+}
+
+const char* TcParser::FastMS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint8_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastMS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint16_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, bool group_coding>
+inline PROTOBUF_ALWAYS_INLINE
+const char* TcParser::RepeatedParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto saved_tag = UnalignedLoad<TagType>(ptr);
+  ptr += sizeof(TagType);
+  SyncHasbits(msg, hasbits, table);
+  const MessageLite* default_instance =
+      table->field_aux(data.aux_idx())->message_default;
+  auto& field = RefAt<RepeatedPtrFieldBase>(msg, data.offset());
+  MessageLite* submsg =
+      field.Add<GenericTypeHandler<MessageLite>>(default_instance);
+  if (group_coding) {
+    return ctx->ParseGroup(submsg, ptr, FastDecodeTag(saved_tag));
+  }
+  return ctx->ParseMessage(submsg, ptr);
+}
+
+const char* TcParser::FastMR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint8_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastMR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint16_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Fixed fields
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename LayoutType, typename TagType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularFixed(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  ptr += sizeof(TagType);  // Consume tag
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  RefAt<LayoutType>(msg, data.offset()) = UnalignedLoad<LayoutType>(ptr);
+  ptr += sizeof(LayoutType);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastF32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename LayoutType, typename TagType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedFixed(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    // Check if the field can be parsed as packed repeated:
+    constexpr WireFormatLite::WireType fallback_wt =
+        sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
+                                : WireFormatLite::WIRETYPE_FIXED64;
+    InvertPacked<fallback_wt>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
+  int idx = field.size();
+  auto elem = field.Add();
+  int space = field.Capacity() - idx;
+  idx = 0;
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  do {
+    ptr += sizeof(TagType);
+    elem[idx++] = UnalignedLoad<LayoutType>(ptr);
+    ptr += sizeof(LayoutType);
+    if (idx >= space) break;
+    if (!ctx->DataAvailable(ptr)) break;
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  field.AddNAlreadyReserved(idx - 1);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastF32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// Note: some versions of GCC will fail with error "function not inlinable" if
+// corecursive functions are both marked with PROTOBUF_ALWAYS_INLINE (Clang
+// accepts this). We can still apply the attribute to one of the two functions,
+// just not both (so we do mark the Repeated variant as always inlined). This
+// also applies to PackedVarint, below.
+template <typename LayoutType, typename TagType>
+const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    // Try parsing as non-packed repeated:
+    constexpr WireFormatLite::WireType fallback_wt =
+        sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
+        : WireFormatLite::WIRETYPE_FIXED64;
+    InvertPacked<fallback_wt>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  ptr += sizeof(TagType);
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+  auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
+  int size = ReadSize(&ptr);
+  // TODO(dlj): add a tailcalling variant of ReadPackedFixed.
+  return ctx->ReadPackedFixed(ptr, size,
+                              static_cast<RepeatedField<LayoutType>*>(&field));
+}
+
+const char* TcParser::FastF32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Varint fields
+//////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE uint64_t
+shift_left_fill_with_ones(uint64_t byte, uint64_t ones) {
+  return (byte << (n * 7)) | (ones >> (64 - (n * 7)));
+}
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
+// put the new value in res.  Return whether the result was negative.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
+    uint64_t byte, uint64_t ones, int64_t& res) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+  // For the first two rounds (ptr[1] and ptr[2]), micro benchmarks show a
+  // substantial improvement from capturing the sign from the condition code
+  // register on x86-64.
+  bool sign_bit;
+  asm("shldq %3, %2, %1"
+      : "=@ccs"(sign_bit), "+r"(byte)
+      : "r"(ones), "i"(n * 7));
+  res = byte;
+  return sign_bit;
+#else
+  // Generic fallback:
+  res = (byte << (n * 7)) | (ones >> (64 - (n * 7)));
+  return static_cast<int64_t>(res) < 0;
+#endif
+}
+
+inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, uint64_t>
+Parse64FallbackPair(const char* p, int64_t res1) {
+  auto ptr = reinterpret_cast<const int8_t*>(p);
+
+  // The algorithm relies on sign extension for each byte to set all high bits
+  // when the varint continues. It also relies on asserting all of the lower
+  // bits for each successive byte read. This allows the result to be aggregated
+  // using a bitwise AND. For example:
+  //
+  //          8       1          64     57 ... 24     17  16      9  8       1
+  // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111  1111 1111  1aaa aaaa
+  // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111  11bb bbbb  b111 1111
+  // ptr[2] = 1ccc cccc ; res3 = 0000 0000 ... 000c cccc  cc11 1111  1111 1111
+  //                             ---------------------------------------------
+  //        res1 & res2 & res3 = 0000 0000 ... 000c cccc  ccbb bbbb  baaa aaaa
+  //
+  // On x86-64, a shld from a single register filled with enough 1s in the high
+  // bits can accomplish all this in one instruction. It so happens that res1
+  // has 57 high bits of ones, which is enough for the largest shift done.
+  GOOGLE_DCHECK_EQ(res1 >> 7, -1);
+  uint64_t ones = res1;  // save the high 1 bits from res1 (input to SHLD)
+  int64_t res2, res3;    // accumulated result chunks
+
+  if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
+    goto done2;
+  if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
+    goto done3;
+
+  // For the remainder of the chunks, check the sign of the AND result.
+  res1 &= shift_left_fill_with_ones<3>(ptr[3], ones);
+  if (res1 >= 0) goto done4;
+  res2 &= shift_left_fill_with_ones<4>(ptr[4], ones);
+  if (res2 >= 0) goto done5;
+  res3 &= shift_left_fill_with_ones<5>(ptr[5], ones);
+  if (res3 >= 0) goto done6;
+  res1 &= shift_left_fill_with_ones<6>(ptr[6], ones);
+  if (res1 >= 0) goto done7;
+  res2 &= shift_left_fill_with_ones<7>(ptr[7], ones);
+  if (res2 >= 0) goto done8;
+  res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
+  if (res3 >= 0) goto done9;
+
+  // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
+  // case, the continuation bit of ptr[8] already set the top bit of res3
+  // correctly, so all we have to do is check that the expected case is true.
+  if (PROTOBUF_PREDICT_TRUE(ptr[9] == 1)) goto done10;
+
+  // A value of 0, however, represents an over-serialized varint. This case
+  // should not happen, but if does (say, due to a nonconforming serializer),
+  // deassert the continuation bit that came from ptr[8].
+  if (ptr[9] == 0) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+    // Use a small instruction since this is an uncommon code path.
+    asm("btcq $63,%0" : "+r"(res3));
+#else
+    res3 ^= static_cast<uint64_t>(1) << 63;
+#endif
+    goto done10;
+  }
+
+  // If the 10th byte/ptr[9] itself has any other value, then it is too big to
+  // fit in 64 bits. If the continue bit is set, it is an unterminated varint.
+  return {nullptr, 0};
+
+done2:
+  return {p + 2, res1 & res2};
+done3:
+  return {p + 3, res1 & res2 & res3};
+done4:
+  return {p + 4, res1 & res2 & res3};
+done5:
+  return {p + 5, res1 & res2 & res3};
+done6:
+  return {p + 6, res1 & res2 & res3};
+done7:
+  return {p + 7, res1 & res2 & res3};
+done8:
+  return {p + 8, res1 & res2 & res3};
+done9:
+  return {p + 9, res1 & res2 & res3};
+done10:
+  return {p + 10, res1 & res2 & res3};
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
+                                                      uint64_t* value) {
+  int64_t byte = static_cast<int8_t>(*p);
+  if (PROTOBUF_PREDICT_TRUE(byte >= 0)) {
+    *value = byte;
+    return p + 1;
+  } else {
+    auto tmp = Parse64FallbackPair(p, byte);
+    if (PROTOBUF_PREDICT_TRUE(tmp.first)) *value = tmp.second;
+    return tmp.first;
+  }
+}
+
+template <typename FieldType, bool zigzag = false>
+inline FieldType ZigZagDecodeHelper(uint64_t value) {
+  return static_cast<FieldType>(value);
+}
+
+template <>
+inline int32_t ZigZagDecodeHelper<int32_t, true>(uint64_t value) {
+  return WireFormatLite::ZigZagDecode32(value);
+}
+
+template <>
+inline int64_t ZigZagDecodeHelper<int64_t, true>(uint64_t value) {
+  return WireFormatLite::ZigZagDecode64(value);
+}
+
+bool EnumIsValidAux(int32_t val, uint16_t xform_val,
+                    TcParseTableBase::FieldAux aux) {
+  if (xform_val == field_layout::kTvRange) {
+    auto lo = aux.enum_range.start;
+    return lo <= val && val < (lo + aux.enum_range.length);
+  }
+  return aux.enum_validator(val);
+}
+
+}  // namespace
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularVarint(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  ptr += sizeof(TagType);  // Consume tag
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+  // clang isn't smart enough to be able to only conditionally save
+  // registers to the stack, so we turn the integer-greater-than-128
+  // case into a separate routine.
+  if (PROTOBUF_PREDICT_FALSE(static_cast<int8_t>(*ptr) < 0)) {
+    PROTOBUF_MUSTTAIL return SingularVarBigint<FieldType, TagType, zigzag>(
+        PROTOBUF_TC_PARAM_PASS);
+  }
+
+  RefAt<FieldType>(msg, data.offset()) =
+      ZigZagDecodeHelper<FieldType, zigzag>(static_cast<uint8_t>(*ptr++));
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint(
+    PROTOBUF_TC_PARAM_DECL) {
+  // For some reason clang wants to save 5 registers to the stack here,
+  // but we only need four for this code, so save the data we don't need
+  // to the stack.  Happily, saving them this way uses regular store
+  // instructions rather than PUSH/POP, which saves time at the cost of greater
+  // code size, but for this heavily-used piece of code, that's fine.
+  struct Spill {
+    uint64_t field_data;
+    ::google::protobuf::MessageLite* msg;
+    const ::google::protobuf::internal::TcParseTableBase* table;
+    uint64_t hasbits;
+  };
+  volatile Spill spill = {data.data, msg, table, hasbits};
+
+  uint64_t tmp;
+  PROTOBUF_ASSUME(static_cast<int8_t>(*ptr) < 0);
+  ptr = ParseVarint(ptr, &tmp);
+
+  data.data = spill.field_data;
+  msg = spill.msg;
+  table = spill.table;
+  hasbits = spill.hasbits;
+
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  RefAt<FieldType>(msg, data.offset()) =
+      ZigZagDecodeHelper<FieldType, zigzag>(tmp);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<bool, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedVarint(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    // Try parsing as non-packed repeated:
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  do {
+    ptr += sizeof(TagType);
+    uint64_t tmp;
+    ptr = ParseVarint(ptr, &tmp);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    field.Add(ZigZagDecodeHelper<FieldType, zigzag>(tmp));
+    if (!ctx->DataAvailable(ptr)) {
+      break;
+    }
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastV8R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<bool, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<bool, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// See comment on PackedFixed for why this is not PROTOBUF_ALWAYS_INLINE.
+template <typename FieldType, typename TagType, bool zigzag>
+const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  ptr += sizeof(TagType);
+  // Since ctx->ReadPackedVarint does not use TailCall or Return, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+  auto* field = &RefAt<RepeatedField<FieldType>>(msg, data.offset());
+  return ctx->ReadPackedVarint(ptr, [field](uint64_t varint) {
+    FieldType val;
+    if (zigzag) {
+      if (sizeof(FieldType) == 8) {
+        val = WireFormatLite::ZigZagDecode64(varint);
+      } else {
+        val = WireFormatLite::ZigZagDecode32(varint);
+      }
+    } else {
+      val = varint;
+    }
+    field->Add(val);
+  });
+}
+
+const char* TcParser::FastV8P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<bool, uint8_t>(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<bool, uint16_t>(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Enum fields
+//////////////////////////////////////////////////////////////////////////////
+
+PROTOBUF_NOINLINE const char* TcParser::FastUnknownEnumFallback(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)msg;
+  (void)ctx;
+  (void)hasbits;
+
+  // If we know we want to put this field directly into the unknown field set,
+  // then we can skip the call to MiniParse and directly call table->fallback.
+  // However, we first have to update `data` to contain the decoded tag.
+  uint32_t tag;
+  ptr = ReadTag(ptr, &tag);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  data.data = tag;
+  PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, uint16_t xform_val>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  const char* ptr2 = ptr;  // Save for unknown enum case
+  ptr += sizeof(TagType);  // Consume tag
+  uint64_t tmp;
+  ptr = ParseVarint(ptr, &tmp);
+  if (ptr == nullptr) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
+  if (PROTOBUF_PREDICT_FALSE(
+          !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
+    ptr = ptr2;
+    PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  RefAt<int32_t>(msg, data.offset()) = tmp;
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastErS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, uint16_t xform_val>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedEnum(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      // Packed parsing is handled by generated fallback.
+      PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
+  do {
+    const char* ptr2 = ptr;  // save for unknown enum case
+    ptr += sizeof(TagType);
+    uint64_t tmp;
+    ptr = ParseVarint(ptr, &tmp);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    if (PROTOBUF_PREDICT_FALSE(
+            !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
+      // We can avoid duplicate work in MiniParse by directly calling
+      // table->fallback.
+      ptr = ptr2;
+      PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    field.Add(static_cast<int32_t>(tmp));
+    if (!ctx->DataAvailable(ptr)) {
+      break;
+    }
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastErR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint8_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastErR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint16_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint8_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint16_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// String/bytes fields
+//////////////////////////////////////////////////////////////////////////////
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
+                       bool emit_stacktrace);
+
+void TcParser::ReportFastUtf8Error(uint32_t decoded_tag,
+                                   const TcParseTableBase* table) {
+  uint32_t field_num = decoded_tag >> 3;
+  const auto* entry = FindFieldEntry(table, field_num);
+  PrintUTF8ErrorLog(MessageName(table), FieldName(table, entry), "parsing",
+                    false);
+}
+
+namespace {
+
+PROTOBUF_NOINLINE
+const char* SingularStringParserFallback(ArenaStringPtr* s, const char* ptr,
+                                         EpsCopyInputStream* stream) {
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+  return stream->ReadString(ptr, size, s->MutableNoCopy(nullptr));
+}
+
+}  // namespace
+
+template <typename TagType, TcParser::Utf8Type utf8>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto saved_tag = UnalignedLoad<TagType>(ptr);
+  ptr += sizeof(TagType);
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  auto& field = RefAt<ArenaStringPtr>(msg, data.offset());
+  auto arena = ctx->data().arena;
+  if (arena) {
+    ptr = ctx->ReadArenaString(ptr, &field, arena);
+  } else {
+    ptr = SingularStringParserFallback(&field, ptr, ctx);
+  }
+  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+  switch (utf8) {
+    case kNoUtf8:
+#ifdef NDEBUG
+    case kUtf8ValidateOnly:
+#endif
+      return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+    default:
+      if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) {
+        return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+      }
+      ReportFastUtf8Error(FastDecodeTag(saved_tag), table);
+      return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
+                           : ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  }
+}
+
+const char* TcParser::FastBS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// Inlined string variants:
+
+const char* TcParser::FastBiS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBiS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSiS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSiS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUiS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUiS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, TcParser::Utf8Type utf8>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  auto& field = RefAt<RepeatedPtrField<std::string>>(msg, data.offset());
+  do {
+    ptr += sizeof(TagType);
+    std::string* str = field.Add();
+    ptr = InlineGreedyStringParser(str, ptr, ctx);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    switch (utf8) {
+      case kNoUtf8:
+#ifdef NDEBUG
+      case kUtf8ValidateOnly:
+#endif
+        break;
+      default:
+        if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(*str))) {
+          break;
+        }
+        ReportFastUtf8Error(FastDecodeTag(expected_tag), table);
+        if (utf8 == kUtf8) return Error(PROTOBUF_TC_PARAM_PASS);
+        break;
+    }
+    if (!ctx->DataAvailable(ptr)) break;
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastBR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Mini parsing
+//////////////////////////////////////////////////////////////////////////////
+
+namespace {
+inline void SetHas(const TcParseTableBase* table, const FieldEntry& entry,
+                   MessageLite* msg, uint64_t& hasbits) {
+  int32_t has_idx = entry.has_idx;
+  if (has_idx < 32) {
+    hasbits |= uint64_t{1} << has_idx;
+  } else {
+    auto* hasblocks = &TcParser::RefAt<uint32_t>(msg, table->has_bits_offset);
+#if defined(__x86_64__) && defined(__GNUC__)
+    asm("bts %1, %0\n" : "+m"(*hasblocks) : "r"(has_idx));
+#else
+    auto& hasblock = hasblocks[has_idx / 32];
+    hasblock |= uint32_t{1} << (has_idx % 32);
+#endif
+  }
+}
+}  // namespace
+
+// Destroys any existing oneof union member (if necessary). Returns true if the
+// caller is responsible for initializing the object, or false if the field
+// already has the desired case.
+bool TcParser::ChangeOneof(const TcParseTableBase* table,
+                           const TcParseTableBase::FieldEntry& entry,
+                           uint32_t field_num, ParseContext* ctx,
+                           MessageLite* msg) {
+  // The _oneof_case_ array offset is stored in the first aux entry.
+  uint32_t oneof_case_offset = table->field_aux(0u)->offset;
+  // The _oneof_case_ array index is stored in the has-bit index.
+  uint32_t* oneof_case =
+      &TcParser::RefAt<uint32_t>(msg, oneof_case_offset) + entry.has_idx;
+  uint32_t current_case = *oneof_case;
+  *oneof_case = field_num;
+
+  if (current_case == 0) {
+    // If the member is empty, we don't have anything to clear. Caller is
+    // responsible for creating a new member object.
+    return true;
+  }
+  if (current_case == field_num) {
+    // If the member is already active, then it should be merged. We're done.
+    return false;
+  }
+  // Look up the value that is already stored, and dispose of it if necessary.
+  const FieldEntry* current_entry = FindFieldEntry(table, current_case);
+  uint16_t current_kind = current_entry->type_card & field_layout::kFkMask;
+  uint16_t current_rep = current_entry->type_card & field_layout::kRepMask;
+  if (current_kind == field_layout::kFkString) {
+    switch (current_rep) {
+      case field_layout::kRepAString: {
+        auto& field = RefAt<ArenaStringPtr>(msg, current_entry->offset);
+        field.Destroy();
+        break;
+      }
+      case field_layout::kRepSString:
+      case field_layout::kRepIString:
+      default:
+        GOOGLE_LOG(DFATAL) << "string rep not handled: "
+                    << (current_rep >> field_layout::kRepShift);
+        return true;
+    }
+  } else if (current_kind == field_layout::kFkMessage) {
+    switch (current_rep) {
+      case field_layout::kRepMessage:
+      case field_layout::kRepGroup:
+      case field_layout::kRepIWeak: {
+        auto& field = RefAt<MessageLite*>(msg, current_entry->offset);
+        if (!ctx->data().arena) {
+          delete field;
+        }
+        break;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "message rep not handled: "
+                    << (current_rep >> field_layout::kRepShift);
+        break;
+    }
+  }
+  return true;
+}
+
+const char* TcParser::MpFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing (wiretype fallback is handled there):
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for mismatched wiretype:
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+  if (rep == field_layout::kRep64Bits) {
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED64) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED32) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  // Set the field present:
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (card == field_layout::kFcOneof) {
+    ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+  // Copy the value:
+  if (rep == field_layout::kRep64Bits) {
+    RefAt<uint64_t>(msg, entry.offset) = UnalignedLoad<uint64_t>(ptr);
+    ptr += sizeof(uint64_t);
+  } else {
+    RefAt<uint32_t>(msg, entry.offset) = UnalignedLoad<uint32_t>(ptr);
+    ptr += sizeof(uint32_t);
+  }
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+
+  // Check for packed repeated fallback:
+  if (decoded_wiretype == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpPackedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t type_card = entry.type_card;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED64) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    constexpr auto size = sizeof(uint64_t);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      ptr = ptr2;
+      *field.Add() = UnalignedLoad<uint64_t>(ptr);
+      ptr += size;
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED32) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    constexpr auto size = sizeof(uint32_t);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      ptr = ptr2;
+      *field.Add() = UnalignedLoad<uint32_t>(ptr);
+      ptr += size;
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpPackedFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+
+  // Check for non-packed repeated fallback:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpRepeatedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+
+  int size = ReadSize(&ptr);
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    ptr = ctx->ReadPackedFixed(ptr, size, &field);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    ptr = ctx->ReadPackedFixed(ptr, size, &field);
+  }
+
+  if (ptr == nullptr) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing:
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  if ((data.tag() & 7) != WireFormatLite::WIRETYPE_VARINT) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+
+  // Parse the value:
+  const char* ptr2 = ptr;  // save for unknown enum case
+  uint64_t tmp;
+  ptr = ParseVarint(ptr, &tmp);
+  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+
+  // Transform and/or validate the value
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    if (is_zigzag) {
+      tmp = WireFormatLite::ZigZagDecode64(tmp);
+    }
+  } else if (rep == field_layout::kRep32Bits) {
+    if (is_validated_enum) {
+      if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
+        ptr = ptr2;
+        PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      }
+    } else if (is_zigzag) {
+      tmp = WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
+    }
+  }
+
+  // Mark the field as present:
+  const bool is_oneof = card == field_layout::kFcOneof;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+
+  if (rep == field_layout::kRep64Bits) {
+    RefAt<uint64_t>(msg, entry.offset) = tmp;
+  } else if (rep == field_layout::kRep32Bits) {
+    RefAt<uint32_t>(msg, entry.offset) = static_cast<uint32_t>(tmp);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    RefAt<bool>(msg, entry.offset) = static_cast<bool>(tmp);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  auto type_card = entry.type_card;
+  const uint32_t decoded_tag = data.tag();
+  auto decoded_wiretype = decoded_tag & 7;
+
+  // Check for packed repeated fallback:
+  if (decoded_wiretype == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpPackedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_VARINT) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  uint16_t xform_val = (type_card & field_layout::kTvMask);
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp);
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else if (rep == field_layout::kRep32Bits) {
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (is_validated_enum) {
+        if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
+          ptr = ptr2;
+          PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+        }
+      } else if (is_zigzag) {
+        tmp = WireFormatLite::ZigZagDecode32(tmp);
+      }
+      field.Add(tmp);
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    auto& field = RefAt<RepeatedField<bool>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      field.Add(static_cast<bool>(tmp));
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  auto type_card = entry.type_card;
+  auto decoded_wiretype = data.tag() & 7;
+
+  // Check for non-packed repeated fallback:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpRepeatedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  uint16_t xform_val = (type_card & field_layout::kTvMask);
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+  if (is_validated_enum) {
+    // TODO(b/206890171): handle enums
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto* field = &RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(ptr, [field, is_zigzag](uint64_t value) {
+      field->Add(is_zigzag ? WireFormatLite::ZigZagDecode64(value) : value);
+    });
+  } else if (rep == field_layout::kRep32Bits) {
+    auto* field = &RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(ptr, [field, is_zigzag](uint64_t value) {
+      field->Add(is_zigzag ? WireFormatLite::ZigZagDecode32(
+                                 static_cast<uint32_t>(value))
+                           : value);
+    });
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    auto* field = &RefAt<RepeatedField<bool>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(
+        ptr, [field](uint64_t value) { field->Add(value); });
+  }
+
+  return Error(PROTOBUF_TC_PARAM_PASS);
+}
+
+bool TcParser::MpVerifyUtf8(StringPiece wire_bytes,
+                            const TcParseTableBase* table,
+                            const FieldEntry& entry, uint16_t xform_val) {
+  if (xform_val == field_layout::kTvUtf8) {
+    if (!IsStructurallyValidUTF8(wire_bytes)) {
+      PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing",
+                        false);
+      return false;
+    }
+    return true;
+  }
+#ifndef NDEBUG
+  if (xform_val == field_layout::kTvUtf8Debug) {
+    if (!IsStructurallyValidUTF8(wire_bytes)) {
+      PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing",
+                        false);
+    }
+  }
+#endif  // NDEBUG
+  return true;
+}
+
+const char* TcParser::MpString(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedString(PROTOBUF_TC_PARAM_PASS);
+  }
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRepIString) {
+    // TODO(b/198211897): support InilnedStringField.
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Mark the field as present:
+  const bool is_oneof = card == field_layout::kFcOneof;
+  bool need_init = false;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    need_init = ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+
+  bool is_valid = false;
+  Arena* arena = ctx->data().arena;
+  switch (rep) {
+    case field_layout::kRepAString: {
+      auto& field = RefAt<ArenaStringPtr>(msg, entry.offset);
+      if (need_init) field.InitDefault();
+      if (arena) {
+        ptr = ctx->ReadArenaString(ptr, &field, arena);
+      } else {
+        std::string* str = field.MutableNoCopy(nullptr);
+        ptr = InlineGreedyStringParser(str, ptr, ctx);
+      }
+      if (!ptr) break;
+      is_valid = MpVerifyUtf8(field.Get(), table, entry, xform_val);
+      break;
+    }
+
+    case field_layout::kRepIString: {
+      break;
+    }
+  }
+
+  if (ptr == nullptr || !is_valid) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedString(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  switch (rep) {
+    case field_layout::kRepSString: {
+      auto& field = RefAt<RepeatedPtrField<std::string>>(msg, entry.offset);
+      const char* ptr2 = ptr;
+      uint32_t next_tag;
+      do {
+        ptr = ptr2;
+        std::string* str = field.Add();
+        ptr = InlineGreedyStringParser(str, ptr, ctx);
+        if (PROTOBUF_PREDICT_FALSE(
+                ptr == nullptr ||
+                !MpVerifyUtf8(*str, table, entry, xform_val))) {
+          return Error(PROTOBUF_TC_PARAM_PASS);
+        }
+        if (!ctx->DataAvailable(ptr)) break;
+        ptr2 = ReadTag(ptr, &next_tag);
+      } while (next_tag == decoded_tag);
+      break;
+    }
+
+#ifndef NDEBUG
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported repeated string rep: " << rep;
+      break;
+#endif
+  }
+
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing:
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedMessage(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const bool is_group = rep == field_layout::kRepGroup;
+
+  // Validate wiretype:
+  switch (rep) {
+    case field_layout::kRepMessage:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+        goto fallback;
+      }
+      break;
+    case field_layout::kRepGroup:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_START_GROUP) {
+        goto fallback;
+      }
+      break;
+    default: {
+    fallback:
+      // Lazy and implicit weak fields are handled by generated code:
+      // TODO(b/210762816): support these.
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+
+  const bool is_oneof = card == field_layout::kFcOneof;
+  bool need_init = false;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    need_init = ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+  MessageLite*& field = RefAt<MessageLite*>(msg, entry.offset);
+  if (need_init || field == nullptr) {
+    const MessageLite* default_instance =
+        table->field_aux(&entry)->message_default;
+    field = default_instance->New(ctx->data().arena);
+  }
+  SyncHasbits(msg, hasbits, table);
+  if (is_group) {
+    return ctx->ParseGroup(field, ptr, decoded_tag);
+  }
+  return ctx->ParseMessage(field, ptr);
+}
+
+const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  GOOGLE_DCHECK_EQ(type_card & field_layout::kFcMask,
+            static_cast<uint16_t>(field_layout::kFcRepeated));
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const bool is_group = rep == field_layout::kRepGroup;
+
+  // Validate wiretype:
+  switch (rep) {
+    case field_layout::kRepMessage:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+        goto fallback;
+      }
+      break;
+    case field_layout::kRepGroup:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_START_GROUP) {
+        goto fallback;
+      }
+      break;
+    default: {
+    fallback:
+      // Lazy and implicit weak fields are handled by generated code:
+      // TODO(b/210762816): support these.
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+
+  SyncHasbits(msg, hasbits, table);
+  const MessageLite* default_instance =
+      table->field_aux(&entry)->message_default;
+  auto& field = RefAt<RepeatedPtrFieldBase>(msg, entry.offset);
+  MessageLite* value =
+      field.Add<GenericTypeHandler<MessageLite>>(default_instance);
+  if (is_group) {
+    return ctx->ParseGroup(value, ptr, decoded_tag);
+  }
+  return ctx->ParseMessage(value, ptr);
+}
+
+const char* TcParser::MpMap(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  (void)entry;
+  PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/generated_message_tctable_lite_test.cc b/src/google/protobuf/generated_message_tctable_lite_test.cc
new file mode 100644
index 0000000..4310803
--- /dev/null
+++ b/src/google/protobuf/generated_message_tctable_lite_test.cc
@@ -0,0 +1,607 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstddef>
+
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+using ::testing::Eq;
+using ::testing::Not;
+
+MATCHER_P3(IsEntryForFieldNum, table, field_num, field_numbers_table,
+           StrCat(negation ? "isn't " : "",
+                        "the field entry for field number ", field_num)) {
+  if (arg == nullptr) {
+    *result_listener << "which is nullptr";
+    return false;
+  }
+  // Use the entry's index to compare field numbers.
+  size_t index = static_cast<const TcParseTableBase::FieldEntry*>(arg) -
+                 &table->field_entries[0];
+  uint32_t actual_field_num = field_numbers_table[index];
+  if (actual_field_num != field_num) {
+    *result_listener << "which is the entry for " << actual_field_num;
+    return false;
+  }
+  return true;
+}
+
+TEST(IsEntryForFieldNumTest, Matcher) {
+  // clang-format off
+  TcParseTable<0, 3, 0, 0, 2> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          0,           // max_field_number
+          0,           // fast_idx_mask,
+          offsetof(decltype(table), field_lookup_table),
+          0xFFFFFFFF - 7,  // 7 = fields 1, 2, and 3.
+          offsetof(decltype(table), field_names),
+          0,           // num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          nullptr,     // fallback function
+      }};
+  // clang-format on
+  int table_field_numbers[] = {1, 2, 3};
+  table.field_lookup_table = {65535, 65535};
+
+  auto& entries = table.field_entries;
+  EXPECT_THAT(&entries[0], IsEntryForFieldNum(&table, 1, table_field_numbers));
+  EXPECT_THAT(&entries[2], IsEntryForFieldNum(&table, 3, table_field_numbers));
+  EXPECT_THAT(&entries[1],
+              Not(IsEntryForFieldNum(&table, 3, table_field_numbers)));
+
+  EXPECT_THAT(nullptr, Not(IsEntryForFieldNum(&table, 1, table_field_numbers)));
+}
+
+}  // namespace
+
+class FindFieldEntryTest : public ::testing::Test {
+ public:
+  // Calls the private `FindFieldEntry` function.
+  template <size_t kFastTableSizeLog2, size_t kNumEntries, size_t kNumFieldAux,
+            size_t kNameTableSize, size_t kFieldLookupTableSize>
+  static const TcParseTableBase::FieldEntry* FindFieldEntry(
+      const TcParseTable<kFastTableSizeLog2, kNumEntries, kNumFieldAux,
+                         kNameTableSize, kFieldLookupTableSize>& table,
+      uint32_t tag) {
+    return TcParser::FindFieldEntry(&table.header, tag);
+  }
+
+  // Calls the private `FieldName` function.
+  template <size_t kFastTableSizeLog2, size_t kNumEntries, size_t kNumFieldAux,
+            size_t kNameTableSize, size_t kFieldLookupTableSize>
+  static StringPiece FieldName(
+      const TcParseTable<kFastTableSizeLog2, kNumEntries, kNumFieldAux,
+                         kNameTableSize, kFieldLookupTableSize>& table,
+      const TcParseTableBase::FieldEntry* entry) {
+    return TcParser::FieldName(&table.header, entry);
+  }
+
+  // Calls the private `MessageName` function.
+  template <size_t kFastTableSizeLog2, size_t kNumEntries, size_t kNumFieldAux,
+            size_t kNameTableSize, size_t kFieldLookupTableSize>
+  static StringPiece MessageName(
+      const TcParseTable<kFastTableSizeLog2, kNumEntries, kNumFieldAux,
+                         kNameTableSize, kFieldLookupTableSize>& table) {
+    return TcParser::MessageName(&table.header);
+  }
+
+  // Returns the number of fields scanned during a small scan.
+  static constexpr int small_scan_size() { return TcParser::kMtSmallScanSize; }
+};
+
+TEST_F(FindFieldEntryTest, SequentialFieldRange) {
+  // Look up fields that are within the range of `lookup_table_offset`.
+  // clang-format off
+  TcParseTable<0, 5, 0, 0, 8> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          111,         // max_field_number
+          0,           // fast_idx_mask,
+          offsetof(decltype(table), field_lookup_table),
+          0xFFFFFFFF - (1 << 1) - (1 << 2)   // fields 2, 3
+                     - (1 << 3) - (1 << 4),  // fields 4, 5
+          offsetof(decltype(table), field_entries),
+          5,           // num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_lookup_table for 2, 3, 4, 5, 111:
+      {{
+        111,      0,                  // field 111
+        1,                            // 1 skip entry
+        0xFFFE,   4,                  // 1 field, entry 4.
+        65535, 65535,                 // end of table
+      }},
+  };
+  // clang-format on
+  int table_field_numbers[] = {2, 3, 4, 5, 111};
+
+  for (int i : table_field_numbers) {
+    EXPECT_THAT(FindFieldEntry(table, i),
+                IsEntryForFieldNum(&table, i, table_field_numbers));
+  }
+  for (int i : {0, 1, 6, 7, 110, 112, 500000000}) {
+    GOOGLE_LOG(WARNING) << "Field " << i;
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, SmallScanRange) {
+  // Look up fields past `lookup_table_offset`, but before binary search.
+  ASSERT_THAT(small_scan_size(), Eq(4)) << "test needs to be updated";
+  // clang-format off
+  TcParseTable<0, 6, 0, 0, 8> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          111,         // max_field_number
+          0,           // fast_idx_mask,
+          offsetof(decltype(table), field_lookup_table),
+          0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4) - (1<<6),  // 1,3-5,7
+          offsetof(decltype(table), field_entries),
+          6,           // num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_lookup_table for 1, 3, 4, 5, 7, 111:
+      {{
+        111, 0,                                              // field 111
+        1,                                                   // 1 skip entry
+        0xFFFE, 5,                                           // 1 field, entry 5
+        65535, 65535                                         // end of table
+      }},
+  };
+  // clang-format on
+  int table_field_numbers[] = {// Sequential entries:
+                               1,
+                               // Small scan range:
+                               3, 4, 5, 7,
+                               // Binary search range:
+                               111};
+
+  for (int i : table_field_numbers) {
+    EXPECT_THAT(FindFieldEntry(table, i),
+                IsEntryForFieldNum(&table, i, table_field_numbers));
+  }
+  for (int i : {0, 2, 6, 8, 9, 110, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, BinarySearchRange) {
+  // Fields after the sequential and small-scan ranges are looked up using
+  // binary search.
+  ASSERT_THAT(small_scan_size(), Eq(4)) << "test needs to be updated";
+
+  // clang-format off
+  TcParseTable<0, 10, 0, 0, 8> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          70,          // max_field_number
+          0,           // fast_idx_mask,
+          offsetof(decltype(table), field_lookup_table),
+          0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4)   // 1, 3, 4, 5, 6
+                     - (1<<5) - (1<<7) - (1<<8) - (1<<10)  // 8, 9, 11, 12
+                     - (1<<11),
+          offsetof(decltype(table), field_entries),
+          10,          // num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_lookup_table for 1, 3, 4, 5, 6, 8, 9, 11, 12, 70
+      {{
+        70, 0,                                              // field 70
+        1,                                                  // 1 skip entry
+        0xFFFE, 9,                                          // 1 field, entry 9
+        65535, 65535                                        // end of table
+      }},
+  };
+  int table_field_numbers[] = {
+        // Sequential entries:
+        1,
+        // Small scan range:
+        3, 4, 5, 6,
+        // Binary search range:
+        8, 9, 11, 12, 70
+  };
+  // clang-format on
+  for (int i : table_field_numbers) {
+    EXPECT_THAT(FindFieldEntry(table, i),
+                IsEntryForFieldNum(&table, i, table_field_numbers));
+  }
+  for (int i : {0, 2, 7, 10, 13, 69, 71, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, OutOfRange) {
+  // Look up tags that are larger than the maximum in the message.
+  // clang-format off
+  TcParseTable<0, 3, 0, 15, 2> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          3,           // max_field_number
+          0,           // fast_idx_mask,
+          offsetof(decltype(table), field_lookup_table),
+          0xFFFFFFFF - (1<<0) - (1<<1) - (1<<2),  // fields 1, 2, 3
+          offsetof(decltype(table), field_entries),
+          3,           // num_field_entries
+          0,           // num_aux_entries
+          offsetof(decltype(table), field_names),  // no aux_entries
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      {{// field lookup table
+        65535, 65535                       // end of table
+      }},
+    {},  // "mini" table
+    // auxiliary entries (none in this test)
+    {{  // name lengths
+        "\0\1\2\3\0\0\0\0"
+          // names
+        "1"
+        "02"
+        "003"}},
+  };
+  // clang-format on
+  int table_field_numbers[] = {1, 2, 3};
+
+  for (int field_num : table_field_numbers) {
+    auto* entry = FindFieldEntry(table, field_num);
+    EXPECT_THAT(entry,
+                IsEntryForFieldNum(&table, field_num, table_field_numbers));
+
+    StringPiece name = FieldName(table, entry);
+    EXPECT_EQ(name.length(), field_num);
+    while (name[0] == '0') name.remove_prefix(1);  // strip leading zeores
+    EXPECT_EQ(name, StrCat(field_num));
+  }
+  for (int field_num : {0, 4, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, field_num), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, EmptyMessage) {
+  // Ensure that tables with no fields are handled correctly.
+  using TableType = TcParseTable<0, 0, 0, 20, 2>;
+  // clang-format off
+  TableType table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          0,           // max_field_number
+          0,           // fast_idx_mask,
+          offsetof(decltype(table), field_lookup_table),
+          0xFFFFFFFF,       // no fields
+          offsetof(decltype(table), field_names),  // no field_entries
+          0,           // num_field_entries
+          0,           // num_aux_entries
+          offsetof(TableType, field_names),
+          nullptr,     // default instance
+          nullptr,     // fallback function
+      },
+      {},  // fast_entries
+      {{// empty field lookup table
+        65535, 65535
+      }},
+      {{
+          "\13\0\0\0\0\0\0\0"
+          "MessageName"
+      }},
+  };
+  // clang-format on
+
+  for (int i : {0, 4, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+  EXPECT_THAT(MessageName(table), Eq("MessageName"));
+}
+
+// Make a monster with lots of field numbers
+
+int32_t test_all_types_table_field_numbers[] = {
+    1,   2,   3,   4,   5,   6,   7,   8,   9,   10,   //
+    11,  12,  13,  14,  15,  18,  19,  21,  22,  24,   //
+    25,  27,  31,  32,  33,  34,  35,  36,  37,  38,   //
+    39,  40,  41,  42,  43,  44,  45,  48,  49,  51,   //
+    52,  54,  55,  56,  57,  58,  59,  60,  61,  62,   //
+    63,  64,  65,  66,  67,  68,  69,  70,  71,  72,   //
+    73,  74,  75,  76,  77,  78,  79,  80,  81,  82,   //
+    83,  84,  85,  86,  87,  88,  89,  90,  91,  92,   //
+    93,  94,  95,  96,  97,  98,  99,  100, 101, 102,  //
+    111, 112, 113, 114, 115, 116, 117, 118, 119, 201,  //
+    241, 242, 243, 244, 245, 246, 247, 248, 249, 250,  //
+    251, 252, 253, 254, 255, 321, 322, 401, 402, 403,  //
+    404, 405, 406, 407, 408, 409, 410, 411, 412, 413,  //
+    414, 415, 416, 417};
+
+// clang-format off
+const TcParseTable<5, 134, 5, 2176, 55> test_all_types_table = {
+    // header:
+    {
+        0, 0, 0, 0,  // has_bits_offset, extensions
+        418, 248,    // max_field_number, fast_idx_mask
+        offsetof(decltype(test_all_types_table), field_lookup_table),
+        977895424,  // skipmap for fields 1-15,18-19,21-22,24-25,27,31-32
+        offsetof(decltype(test_all_types_table), field_entries),
+        135,         // num_field_entries
+        5,           // num_aux_entries
+        offsetof(decltype(test_all_types_table), aux_entries),
+        nullptr,     // default instance
+        nullptr,     // fallback function
+    },
+    {{
+        // tail-call table
+    }},
+    {{  // field lookup table
+        //
+        // fields 33-417, over 25 skipmap / offset pairs
+      33, 0, 25,
+      24576,  24,   18,     38,   0,      52,   0,      68,   16320,  84,
+      65408,  92,   65535,  99,   65535,  99,   65535,  99,   65535,  99,
+      65279,  99,   65535,  100,  65535,  100,  32768,  100,  65535,  115,
+      65535,  115,  65535,  115,  65535,  115,  65532,  115,  65535,  117,
+      65535,  117,  65535,  117,  65535,  117,  0,      117,  65532,  133,
+      // end of table
+      65535, 65535
+  }},
+  {{
+      // "mini" table
+  }},
+  {{  // auxiliary entries (not used in this test)
+      {-1, 4},
+      {-1, 4},
+      {-1, 4},
+      {-1, 4},
+      {-1, 4},
+    }}, {{  // name lengths
+      "\1"  // message name
+      "\16\16\17\17\17\17\20\20\21\21\16\17\15\17\16\27\30\24\25\25"
+      "\15\21\16\16\17\17\17\17\20\20\21\21\16\17\15\17\16\27\30\24"
+      "\25\25\15\17\17\21\21\21\21\23\23\25\25\17\20\15\21\20\31\32"
+      "\26\27\14\14\15\15\15\15\16\16\17\17\14\15\13\22\16\16\17\17"
+      "\17\17\20\20\21\21\16\17\15\24\14\24\14\13\12\14\13\14\12\4"
+      "\15\15\16\16\16\16\17\17\20\20\15\16\14\16\15\25\25\12\13\14"
+      "\15\13\15\12\12\13\14\14\14\16\16\15\15\16\0"
+        // names
+      "M"
+      "optional_int32"
+      "optional_int64"
+      "optional_uint32"
+      "optional_uint64"
+      "optional_sint32"
+      "optional_sint64"
+      "optional_fixed32"
+      "optional_fixed64"
+      "optional_sfixed32"
+      "optional_sfixed64"
+      "optional_float"
+      "optional_double"
+      "optional_bool"
+      "optional_string"
+      "optional_bytes"
+      "optional_nested_message"
+      "optional_foreign_message"
+      "optional_nested_enum"
+      "optional_foreign_enum"
+      "optional_string_piece"
+      "optional_cord"
+      "recursive_message"
+      "repeated_int32"
+      "repeated_int64"
+      "repeated_uint32"
+      "repeated_uint64"
+      "repeated_sint32"
+      "repeated_sint64"
+      "repeated_fixed32"
+      "repeated_fixed64"
+      "repeated_sfixed32"
+      "repeated_sfixed64"
+      "repeated_float"
+      "repeated_double"
+      "repeated_bool"
+      "repeated_string"
+      "repeated_bytes"
+      "repeated_nested_message"
+      "repeated_foreign_message"
+      "repeated_nested_enum"
+      "repeated_foreign_enum"
+      "repeated_string_piece"
+      "repeated_cord"
+      "map_int32_int32"
+      "map_int64_int64"
+      "map_uint32_uint32"
+      "map_uint64_uint64"
+      "map_sint32_sint32"
+      "map_sint64_sint64"
+      "map_fixed32_fixed32"
+      "map_fixed64_fixed64"
+      "map_sfixed32_sfixed32"
+      "map_sfixed64_sfixed64"
+      "map_int32_float"
+      "map_int32_double"
+      "map_bool_bool"
+      "map_string_string"
+      "map_string_bytes"
+      "map_string_nested_message"
+      "map_string_foreign_message"
+      "map_string_nested_enum"
+      "map_string_foreign_enum"
+      "packed_int32"
+      "packed_int64"
+      "packed_uint32"
+      "packed_uint64"
+      "packed_sint32"
+      "packed_sint64"
+      "packed_fixed32"
+      "packed_fixed64"
+      "packed_sfixed32"
+      "packed_sfixed64"
+      "packed_float"
+      "packed_double"
+      "packed_bool"
+      "packed_nested_enum"
+      "unpacked_int32"
+      "unpacked_int64"
+      "unpacked_uint32"
+      "unpacked_uint64"
+      "unpacked_sint32"
+      "unpacked_sint64"
+      "unpacked_fixed32"
+      "unpacked_fixed64"
+      "unpacked_sfixed32"
+      "unpacked_sfixed64"
+      "unpacked_float"
+      "unpacked_double"
+      "unpacked_bool"
+      "unpacked_nested_enum"
+      "oneof_uint32"
+      "oneof_nested_message"
+      "oneof_string"
+      "oneof_bytes"
+      "oneof_bool"
+      "oneof_uint64"
+      "oneof_float"
+      "oneof_double"
+      "oneof_enum"
+      "data"
+      "default_int32"
+      "default_int64"
+      "default_uint32"
+      "default_uint64"
+      "default_sint32"
+      "default_sint64"
+      "default_fixed32"
+      "default_fixed64"
+      "default_sfixed32"
+      "default_sfixed64"
+      "default_float"
+      "default_double"
+      "default_bool"
+      "default_string"
+      "default_bytes"
+      "optional_lazy_message"
+      "repeated_lazy_message"
+      "fieldname1"
+      "field_name2"
+      "_field_name3"
+      "field__name4_"
+      "field0name5"
+      "field_0_name6"
+      "fieldName7"
+      "FieldName8"
+      "field_Name9"
+      "Field_Name10"
+      "FIELD_NAME11"
+      "FIELD_name12"
+      "__field_name13"
+      "__Field_name14"
+      "field__name15"
+      "field__Name16"
+      "field_name17__"
+  }},
+};
+// clang-format on
+
+TEST_F(FindFieldEntryTest, BigMessage) {
+  EXPECT_THAT(MessageName(test_all_types_table), Eq("M"));
+  for (int field_num :
+       {1, 12, 31, 42, 57, 68, 79, 90, 101, 119, 249, 402, 412}) {
+    auto* entry = FindFieldEntry(test_all_types_table, field_num);
+    StringPiece name = FieldName(test_all_types_table, entry);
+    switch (field_num) {
+      case 1:
+        EXPECT_THAT(name, Eq("optional_int32"));
+        break;
+      case 12:
+        EXPECT_THAT(name, Eq("optional_double"));
+        break;
+      case 31:
+        EXPECT_THAT(name, Eq("repeated_int32"));
+        break;
+      case 42:
+        EXPECT_THAT(name, Eq("repeated_double"));
+        break;
+      case 57:
+        EXPECT_THAT(name, Eq("map_int64_int64"));
+        break;
+      case 68:
+        EXPECT_THAT(name, Eq("map_bool_bool"));
+        break;
+      case 79:
+        EXPECT_THAT(name, Eq("packed_sint32"));
+        break;
+      case 90:
+        EXPECT_THAT(name, Eq("unpacked_int64"));
+        break;
+      case 101:
+        EXPECT_THAT(name, Eq("unpacked_bool"));
+        break;
+      case 119:
+        EXPECT_THAT(name, Eq("oneof_enum"));
+        break;
+      case 249:
+        EXPECT_THAT(name, Eq("default_sfixed32"));
+        break;
+      case 402:
+        EXPECT_THAT(name, Eq("field_name2"));
+        break;
+      case 412:
+        EXPECT_THAT(name, Eq("FIELD_name12"));
+        break;
+    }
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
new file mode 100644
index 0000000..cad12a3
--- /dev/null
+++ b/src/google/protobuf/generated_message_util.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/generated_message_util.h>
+
+#include <atomic>
+#include <limits>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void DestroyMessage(const void* message) {
+  static_cast<const MessageLite*>(message)->~MessageLite();
+}
+void DestroyString(const void* s) {
+  static_cast<const std::string*>(s)->~basic_string();
+}
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplicitlyConstructedArenaString
+        fixed_address_empty_string{};  // NOLINT
+
+
+PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
+static bool InitProtobufDefaultsImpl() {
+  fixed_address_empty_string.DefaultConstruct();
+  OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
+
+
+  init_protobuf_defaults_state.store(true, std::memory_order_release);
+  return true;
+}
+
+void InitProtobufDefaultsSlow() {
+  static bool is_inited = InitProtobufDefaultsImpl();
+  (void)is_inited;
+}
+// Force the initialization of the empty string.
+// Normally, registration would do it, but we don't have any guarantee that
+// there is any object with reflection.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 static std::true_type init_empty_string =
+    (InitProtobufDefaultsSlow(), std::true_type{});
+
+size_t StringSpaceUsedExcludingSelfLong(const std::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();
+  }
+}
+
+template <typename T>
+const T& Get(const void* ptr) {
+  return *static_cast<const T*>(ptr);
+}
+
+// PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite.
+// WireFormatLite has a very inconvenient interface with respect to template
+// meta-programming. This class wraps the different named functions into
+// a single Serialize / SerializeToArray interface.
+template <int type>
+struct PrimitiveTypeHelper;
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
+  typedef bool Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
+  typedef int32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteInt32NoTag(Get<int32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
+  typedef int32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteSInt32NoTag(Get<int32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
+  typedef uint32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteUInt32NoTag(Get<uint32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
+  typedef int64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteInt64NoTag(Get<int64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
+  typedef int64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteSInt64NoTag(Get<int64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
+  typedef uint64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteUInt64NoTag(Get<uint64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
+  typedef uint32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteFixed32NoTag(Get<uint32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
+  typedef uint64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteFixed64NoTag(Get<uint64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
+  typedef int32_t Type;
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
+  typedef int64_t Type;
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
+  typedef float Type;
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
+  typedef double Type;
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
+  typedef std::string Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    const Type& value = *static_cast<const Type*>(ptr);
+    output->WriteVarint32(value.size());
+    output->WriteRawMaybeAliased(value.data(), value.size());
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    const Type& value = *static_cast<const Type*>(ptr);
+    return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
+
+// We want to serialize to both CodedOutputStream and directly into byte arrays
+// without duplicating the code. In fact we might want extra output channels in
+// the future.
+template <typename O, int type>
+struct OutputHelper;
+
+template <int type, typename O>
+void SerializeTo(const void* ptr, O* output) {
+  OutputHelper<O, type>::Serialize(ptr, output);
+}
+
+template <typename O>
+void WriteTagTo(uint32_t tag, O* output) {
+  SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
+}
+
+template <typename O>
+void WriteLengthTo(uint32_t length, O* output) {
+  SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
+}
+
+// Specialization for coded output stream
+template <int type>
+struct OutputHelper<io::CodedOutputStream, type> {
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    PrimitiveTypeHelper<type>::Serialize(ptr, output);
+  }
+};
+
+// Specialization for writing into a plain array
+struct ArrayOutput {
+  uint8_t* ptr;
+  bool is_deterministic;
+};
+
+template <int type>
+struct OutputHelper<ArrayOutput, type> {
+  static void Serialize(const void* ptr, ArrayOutput* output) {
+    output->ptr = PrimitiveTypeHelper<type>::SerializeToArray(ptr, output->ptr);
+  }
+};
+
+void SerializeMessageNoTable(const MessageLite* msg,
+                             io::CodedOutputStream* output) {
+  msg->SerializeWithCachedSizes(output);
+}
+
+void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
+  io::ArrayOutputStream array_stream(output->ptr, INT_MAX);
+  io::CodedOutputStream o(&array_stream);
+  o.SetSerializationDeterministic(output->is_deterministic);
+  msg->SerializeWithCachedSizes(&o);
+  output->ptr += o.ByteCount();
+}
+
+// We need to use a helper class to get access to the private members
+class AccessorHelper {
+ public:
+  static int Size(const RepeatedPtrFieldBase& x) { return x.size(); }
+  static void const* Get(const RepeatedPtrFieldBase& x, int idx) {
+    return x.raw_data()[idx];
+  }
+};
+
+void SerializeNotImplemented(int field) {
+  GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
+}
+
+// When switching to c++11 we should make these constexpr functions
+#define SERIALIZE_TABLE_OP(type, type_class) \
+  ((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
+
+template <int type>
+bool IsNull(const void* ptr) {
+  return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
+         0;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_STRING>(const void* ptr) {
+  return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
+  return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
+  return Get<const MessageLite*>(ptr) == nullptr;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
+  return Get<const MessageLite*>(ptr) == nullptr;
+}
+
+void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr,
+                         uint32_t offset, uint32_t tag, uint32_t has_offset,
+                         io::CodedOutputStream* output) {
+  reinterpret_cast<const ExtensionSet*>(ptr + offset)
+      ->SerializeWithCachedSizes(extendee, tag, has_offset, output);
+}
+
+void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset,
+                                uint32_t /*tag*/, uint32_t /*has_offset*/,
+                                io::CodedOutputStream* output) {
+  output->WriteString(
+      reinterpret_cast<const InternalMetadata*>(ptr + offset)
+          ->unknown_fields<std::string>(&internal::GetEmptyString));
+}
+
+MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
+  if (message) {
+    MessageLite* ret = message->New();
+    ret->CheckTypeAndMergeFrom(*message);
+    return ret;
+  } else {
+    return nullptr;
+  }
+}
+
+void GenericSwap(MessageLite* m1, MessageLite* m2) {
+  std::unique_ptr<MessageLite> tmp(m1->New());
+  tmp->CheckTypeAndMergeFrom(*m1);
+  m1->Clear();
+  m1->CheckTypeAndMergeFrom(*m2);
+  m2->Clear();
+  m2->CheckTypeAndMergeFrom(*tmp);
+}
+
+// Returns a message owned by this Arena.  This may require Own()ing or
+// duplicating the message.
+MessageLite* GetOwnedMessageInternal(Arena* message_arena,
+                                     MessageLite* submessage,
+                                     Arena* submessage_arena) {
+  GOOGLE_DCHECK(Arena::InternalGetOwningArena(submessage) == submessage_arena);
+  GOOGLE_DCHECK(message_arena != submessage_arena);
+  GOOGLE_DCHECK_EQ(submessage_arena, nullptr);
+  if (message_arena != nullptr && submessage_arena == nullptr) {
+    message_arena->Own(submessage);
+    return submessage;
+  } else {
+    MessageLite* ret = submessage->New(message_arena);
+    ret->CheckTypeAndMergeFrom(*submessage);
+    return ret;
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
new file mode 100644
index 0000000..71d15cd
--- /dev/null
+++ b/src/google/protobuf/generated_message_util.h
@@ -0,0 +1,214 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 miscellaneous helper code used by generated code --
+// including lite types -- but which should not be used directly by users.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+
+#include <assert.h>
+
+#include <atomic>
+#include <climits>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>  // Add direct dep on port for pb.cc
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/has_bits.h>
+#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/casts.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Arena;
+class Message;
+
+namespace io {
+class CodedInputStream;
+}
+
+namespace internal {
+
+template <typename To, typename From>
+inline To DownCast(From* f) {
+  return PROTOBUF_NAMESPACE_ID::internal::down_cast<To>(f);
+}
+template <typename To, typename From>
+inline To DownCast(From& f) {
+  return PROTOBUF_NAMESPACE_ID::internal::down_cast<To>(f);
+}
+
+
+// This fastpath inlines a single branch instead of having to make the
+// InitProtobufDefaults function call.
+// It also generates less inlined code than a function-scope static initializer.
+PROTOBUF_EXPORT extern std::atomic<bool> init_protobuf_defaults_state;
+PROTOBUF_EXPORT void InitProtobufDefaultsSlow();
+PROTOBUF_EXPORT inline void InitProtobufDefaults() {
+  if (PROTOBUF_PREDICT_FALSE(
+          !init_protobuf_defaults_state.load(std::memory_order_acquire))) {
+    InitProtobufDefaultsSlow();
+  }
+}
+
+// This used by proto1
+PROTOBUF_EXPORT inline const std::string& GetEmptyString() {
+  InitProtobufDefaults();
+  return GetEmptyStringAlreadyInited();
+}
+
+
+// True if IsInitialized() is true for all elements of t.  Type is expected
+// to be a RepeatedPtrField<some message type>.  It's useful to have this
+// helper here to keep the protobuf compiler from ever having to emit loops in
+// IsInitialized() methods.  We want the C++ compiler to inline this or not
+// as it sees fit.
+template <typename Msg>
+bool AllAreInitialized(const RepeatedPtrField<Msg>& t) {
+  for (int i = t.size(); --i >= 0;) {
+    if (!t.Get(i).IsInitialized()) return false;
+  }
+  return true;
+}
+
+// "Weak" variant of AllAreInitialized, used to implement implicit weak fields.
+// This version operates on MessageLite to avoid introducing a dependency on the
+// concrete message type.
+template <class T>
+bool AllAreInitializedWeak(const RepeatedPtrField<T>& t) {
+  for (int i = t.size(); --i >= 0;) {
+    if (!reinterpret_cast<const RepeatedPtrFieldBase&>(t)
+             .Get<ImplicitWeakTypeHandler<T> >(i)
+             .IsInitialized()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+inline bool IsPresent(const void* base, uint32_t hasbit) {
+  const uint32_t* has_bits_array = static_cast<const uint32_t*>(base);
+  return (has_bits_array[hasbit / 32] & (1u << (hasbit & 31))) != 0;
+}
+
+inline bool IsOneofPresent(const void* base, uint32_t offset, uint32_t tag) {
+  const uint32_t* oneof = reinterpret_cast<const uint32_t*>(
+      static_cast<const uint8_t*>(base) + offset);
+  return *oneof == tag >> 3;
+}
+
+typedef void (*SpecialSerializer)(const uint8_t* base, uint32_t offset,
+                                  uint32_t tag, uint32_t has_offset,
+                                  io::CodedOutputStream* output);
+
+PROTOBUF_EXPORT void ExtensionSerializer(const MessageLite* extendee,
+                                         const uint8_t* ptr, uint32_t offset,
+                                         uint32_t tag, uint32_t has_offset,
+                                         io::CodedOutputStream* output);
+PROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8_t* base,
+                                                uint32_t offset, uint32_t tag,
+                                                uint32_t has_offset,
+                                                io::CodedOutputStream* output);
+
+PROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message);
+PROTOBUF_EXPORT MessageLite* GetOwnedMessageInternal(Arena* message_arena,
+                                                     MessageLite* submessage,
+                                                     Arena* submessage_arena);
+PROTOBUF_EXPORT void GenericSwap(MessageLite* m1, MessageLite* m2);
+// We specialize GenericSwap for non-lite messages to benefit from reflection.
+PROTOBUF_EXPORT void GenericSwap(Message* m1, Message* m2);
+
+template <typename T>
+T* DuplicateIfNonNull(T* message) {
+  // The casts must be reinterpret_cast<> because T might be a forward-declared
+  // type that the compiler doesn't know is related to MessageLite.
+  return reinterpret_cast<T*>(
+      DuplicateIfNonNullInternal(reinterpret_cast<MessageLite*>(message)));
+}
+
+template <typename T>
+T* GetOwnedMessage(Arena* message_arena, T* submessage,
+                   Arena* submessage_arena) {
+  // The casts must be reinterpret_cast<> because T might be a forward-declared
+  // type that the compiler doesn't know is related to MessageLite.
+  return reinterpret_cast<T*>(GetOwnedMessageInternal(
+      message_arena, reinterpret_cast<MessageLite*>(submessage),
+      submessage_arena));
+}
+
+// Hide atomic from the public header and allow easy change to regular int
+// on platforms where the atomic might have a perf impact.
+class PROTOBUF_EXPORT CachedSize {
+ public:
+  int Get() const { return size_.load(std::memory_order_relaxed); }
+  void Set(int size) { size_.store(size, std::memory_order_relaxed); }
+
+ private:
+  std::atomic<int> size_{0};
+};
+
+PROTOBUF_EXPORT void DestroyMessage(const void* message);
+PROTOBUF_EXPORT void DestroyString(const void* s);
+// Destroy (not delete) the message
+inline void OnShutdownDestroyMessage(const void* ptr) {
+  OnShutdownRun(DestroyMessage, ptr);
+}
+// Destroy the string (call std::string destructor)
+inline void OnShutdownDestroyString(const std::string* ptr) {
+  OnShutdownRun(DestroyString, ptr);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
diff --git a/src/google/protobuf/has_bits.h b/src/google/protobuf/has_bits.h
new file mode 100644
index 0000000..f8a4587
--- /dev/null
+++ b/src/google/protobuf/has_bits.h
@@ -0,0 +1,117 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_HAS_BITS_H__
+#define GOOGLE_PROTOBUF_HAS_BITS_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template <size_t doublewords>
+class HasBits {
+ public:
+  PROTOBUF_NDEBUG_INLINE constexpr HasBits() : has_bits_{} {}
+
+  PROTOBUF_NDEBUG_INLINE void Clear() {
+    memset(has_bits_, 0, sizeof(has_bits_));
+  }
+
+  PROTOBUF_NDEBUG_INLINE uint32_t& operator[](int index) {
+    return has_bits_[index];
+  }
+
+  PROTOBUF_NDEBUG_INLINE const uint32_t& operator[](int index) const {
+    return has_bits_[index];
+  }
+
+  bool operator==(const HasBits<doublewords>& rhs) const {
+    return memcmp(has_bits_, rhs.has_bits_, sizeof(has_bits_)) == 0;
+  }
+
+  bool operator!=(const HasBits<doublewords>& rhs) const {
+    return !(*this == rhs);
+  }
+
+  void Or(const HasBits<doublewords>& rhs) {
+    for (size_t i = 0; i < doublewords; i++) has_bits_[i] |= rhs[i];
+  }
+
+  bool empty() const;
+
+ private:
+  uint32_t has_bits_[doublewords];
+};
+
+template <>
+inline bool HasBits<1>::empty() const {
+  return !has_bits_[0];
+}
+
+template <>
+inline bool HasBits<2>::empty() const {
+  return !(has_bits_[0] | has_bits_[1]);
+}
+
+template <>
+inline bool HasBits<3>::empty() const {
+  return !(has_bits_[0] | has_bits_[1] | has_bits_[2]);
+}
+
+template <>
+inline bool HasBits<4>::empty() const {
+  return !(has_bits_[0] | has_bits_[1] | has_bits_[2] | has_bits_[3]);
+}
+
+template <size_t doublewords>
+inline bool HasBits<doublewords>::empty() const {
+  for (size_t i = 0; i < doublewords; ++i) {
+    if (has_bits_[i]) return false;
+  }
+  return true;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_HAS_BITS_H__
diff --git a/src/google/protobuf/implicit_weak_message.cc b/src/google/protobuf/implicit_weak_message.cc
new file mode 100644
index 0000000..27ed6b6
--- /dev/null
+++ b/src/google/protobuf/implicit_weak_message.cc
@@ -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.
+
+#include <google/protobuf/implicit_weak_message.h>
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+const char* ImplicitWeakMessage::_InternalParse(const char* ptr,
+                                                ParseContext* ctx) {
+  return ctx->AppendString(ptr, data_);
+}
+
+struct ImplicitWeakMessageDefaultType {
+  constexpr ImplicitWeakMessageDefaultType()
+      : instance(ConstantInitialized{}) {}
+  ~ImplicitWeakMessageDefaultType() {}
+  union {
+    ImplicitWeakMessage instance;
+  };
+};
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ImplicitWeakMessageDefaultType
+    implicit_weak_message_default_instance;
+
+const ImplicitWeakMessage* ImplicitWeakMessage::default_instance() {
+  return reinterpret_cast<ImplicitWeakMessage*>(
+      &implicit_weak_message_default_instance);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/implicit_weak_message.h b/src/google/protobuf/implicit_weak_message.h
new file mode 100644
index 0000000..b894ab4
--- /dev/null
+++ b/src/google/protobuf/implicit_weak_message.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_IMPLICIT_WEAK_MESSAGE_H__
+#define GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
+
+#include <string>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// This file is logically internal-only and should only be used by protobuf
+// generated code.
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// An implementation of MessageLite that treats all data as unknown. This type
+// acts as a placeholder for an implicit weak field in the case where the true
+// message type does not get linked into the binary.
+class PROTOBUF_EXPORT ImplicitWeakMessage : public MessageLite {
+ public:
+  ImplicitWeakMessage() : data_(new std::string) {}
+  explicit constexpr ImplicitWeakMessage(ConstantInitialized)
+      : data_(nullptr) {}
+  explicit ImplicitWeakMessage(Arena* arena)
+      : MessageLite(arena), data_(new std::string) {}
+
+  ~ImplicitWeakMessage() override {
+    // data_ will be null in the default instance, but we can safely call delete
+    // here because the default instance will never be destroyed.
+    delete data_;
+  }
+
+  static const ImplicitWeakMessage* default_instance();
+
+  std::string GetTypeName() const override { return ""; }
+
+  MessageLite* New(Arena* arena) const override {
+    return Arena::CreateMessage<ImplicitWeakMessage>(arena);
+  }
+
+  void Clear() override { data_->clear(); }
+
+  bool IsInitialized() const override { return true; }
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) override {
+    const std::string* other_data =
+        static_cast<const ImplicitWeakMessage&>(other).data_;
+    if (other_data != nullptr) {
+      data_->append(*other_data);
+    }
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) final;
+
+  size_t ByteSizeLong() const override {
+    return data_ == nullptr ? 0 : data_->size();
+  }
+
+  uint8_t* _InternalSerialize(uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const final {
+    if (data_ == nullptr) {
+      return target;
+    }
+    return stream->WriteRaw(data_->data(), static_cast<int>(data_->size()),
+                            target);
+  }
+
+  int GetCachedSize() const override {
+    return data_ == nullptr ? 0 : static_cast<int>(data_->size());
+  }
+
+  typedef void InternalArenaConstructable_;
+
+ private:
+  // This std::string is allocated on the heap, but we use a raw pointer so that
+  // the default instance can be constant-initialized. In the const methods, we
+  // have to handle the possibility of data_ being null.
+  std::string* data_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImplicitWeakMessage);
+};
+
+struct ImplicitWeakMessageDefaultType;
+extern ImplicitWeakMessageDefaultType implicit_weak_message_default_instance;
+
+// A type handler for use with implicit weak repeated message fields.
+template <typename ImplicitWeakType>
+class ImplicitWeakTypeHandler {
+ public:
+  typedef MessageLite Type;
+  static constexpr bool Moveable = false;
+
+  static inline MessageLite* NewFromPrototype(const MessageLite* prototype,
+                                              Arena* arena = nullptr) {
+    return prototype->New(arena);
+  }
+
+  static inline void Delete(MessageLite* value, Arena* arena) {
+    if (arena == nullptr) {
+      delete value;
+    }
+  }
+  static inline Arena* GetArena(MessageLite* value) {
+    return value->GetArena();
+  }
+  static inline void Clear(MessageLite* value) { value->Clear(); }
+  static void Merge(const MessageLite& from, MessageLite* to) {
+    to->CheckTypeAndMergeFrom(from);
+  }
+};
+
+}  // namespace internal
+
+template <typename T>
+struct WeakRepeatedPtrField {
+  using TypeHandler = internal::ImplicitWeakTypeHandler<T>;
+  constexpr WeakRepeatedPtrField() : weak() {}
+  explicit WeakRepeatedPtrField(Arena* arena) : weak(arena) {}
+  ~WeakRepeatedPtrField() { weak.template Destroy<TypeHandler>(); }
+
+  typedef internal::RepeatedPtrIterator<MessageLite> iterator;
+  typedef internal::RepeatedPtrIterator<const MessageLite> const_iterator;
+  typedef internal::RepeatedPtrOverPtrsIterator<MessageLite*, void*>
+      pointer_iterator;
+  typedef internal::RepeatedPtrOverPtrsIterator<const MessageLite* const,
+                                                const void* const>
+      const_pointer_iterator;
+
+  iterator begin() { return iterator(base().raw_data()); }
+  const_iterator begin() const { return iterator(base().raw_data()); }
+  const_iterator cbegin() const { return begin(); }
+  iterator end() { return begin() + base().size(); }
+  const_iterator end() const { return begin() + base().size(); }
+  const_iterator cend() const { return end(); }
+  pointer_iterator pointer_begin() {
+    return pointer_iterator(base().raw_mutable_data());
+  }
+  const_pointer_iterator pointer_begin() const {
+    return const_pointer_iterator(base().raw_mutable_data());
+  }
+  pointer_iterator pointer_end() {
+    return pointer_iterator(base().raw_mutable_data() + base().size());
+  }
+  const_pointer_iterator pointer_end() const {
+    return const_pointer_iterator(base().raw_mutable_data() + base().size());
+  }
+
+  MessageLite* AddWeak(const MessageLite* prototype) {
+    return base().AddWeak(prototype);
+  }
+  T* Add() { return weak.Add(); }
+  void Clear() { base().template Clear<TypeHandler>(); }
+  void MergeFrom(const WeakRepeatedPtrField& other) {
+    base().template MergeFrom<TypeHandler>(other.base());
+  }
+  void InternalSwap(WeakRepeatedPtrField* other) {
+    base().InternalSwap(&other->base());
+  }
+
+  const internal::RepeatedPtrFieldBase& base() const { return weak; }
+  internal::RepeatedPtrFieldBase& base() { return weak; }
+  // Union disables running the destructor. Which would create a strong link.
+  // Instead we explicitly destroy the underlying base through the virtual
+  // destructor.
+  union {
+    RepeatedPtrField<T> weak;
+  };
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
diff --git a/src/google/protobuf/inlined_string_field.cc b/src/google/protobuf/inlined_string_field.cc
new file mode 100644
index 0000000..0c3e476
--- /dev/null
+++ b/src/google/protobuf/inlined_string_field.cc
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/inlined_string_field.h>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+
+std::string* InlinedStringField::Mutable(const LazyString& /*default_value*/,
+                                         Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  if (arena == nullptr || !donated) {
+    return UnsafeMutablePointer();
+  }
+  return MutableSlow(arena, donated, donating_states, mask, msg);
+}
+
+std::string* InlinedStringField::Mutable(Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  if (arena == nullptr || !donated) {
+    return UnsafeMutablePointer();
+  }
+  return MutableSlow(arena, donated, donating_states, mask, msg);
+}
+
+std::string* InlinedStringField::MutableSlow(::google::protobuf::Arena* arena,
+                                             bool donated,
+                                             uint32_t* donating_states,
+                                             uint32_t mask, MessageLite* msg) {
+  (void)mask;
+  (void)msg;
+  return UnsafeMutablePointer();
+}
+
+void InlinedStringField::SetAllocated(const std::string* default_value,
+                                      std::string* value, Arena* arena,
+                                      bool donated, uint32_t* donating_states,
+                                      uint32_t mask, MessageLite* msg) {
+  (void)mask;
+  (void)msg;
+  SetAllocatedNoArena(default_value, value);
+}
+
+void InlinedStringField::Set(std::string&& value, Arena* arena, bool donated,
+                             uint32_t* donating_states, uint32_t mask,
+                             MessageLite* msg) {
+  (void)donating_states;
+  (void)mask;
+  (void)msg;
+  SetNoArena(std::move(value));
+}
+
+std::string* InlinedStringField::Release() {
+  auto* released = new std::string(std::move(*get_mutable()));
+  get_mutable()->clear();
+  return released;
+}
+
+std::string* InlinedStringField::Release(Arena* arena, bool donated) {
+  // We can not steal donated arena strings.
+  std::string* released = (arena != nullptr && donated)
+                              ? new std::string(*get_mutable())
+                              : new std::string(std::move(*get_mutable()));
+  get_mutable()->clear();
+  return released;
+}
+
+void InlinedStringField::ClearToDefault(const LazyString& default_value,
+                                        Arena* arena, bool donated) {
+  (void)arena;
+  get_mutable()->assign(default_value.get());
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/inlined_string_field.h b/src/google/protobuf/inlined_string_field.h
new file mode 100644
index 0000000..79e37d4
--- /dev/null
+++ b/src/google/protobuf/inlined_string_field.h
@@ -0,0 +1,532 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INLINED_STRING_FIELD_H__
+#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
+
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Arena;
+
+namespace internal {
+
+// InlinedStringField wraps a std::string instance and exposes an API similar to
+// ArenaStringPtr's wrapping of a std::string* instance.
+//
+// default_value parameters are taken for consistency with ArenaStringPtr, but
+// are not used for most methods. With inlining, these should be removed from
+// the generated binary.
+//
+// InlinedStringField has a donating mechanism that allows string buffer
+// allocated on arena. A string is donated means both the string container and
+// the data buffer are on arena. The donating mechanism here is similar to the
+// one in ArenaStringPtr with some differences:
+//
+// When an InlinedStringField is constructed, the donating state is true. This
+// is because the string container is directly stored in the message on the
+// arena:
+//
+//   Construction: donated=true
+//   Arena:
+//   +-----------------------+
+//   |Message foo:           |
+//   | +-------------------+ |
+//   | |InlinedStringField:| |
+//   | | +-----+           | |
+//   | | | | | |           | |
+//   | | +-----+           | |
+//   | +-------------------+ |
+//   +-----------------------+
+//
+// When lvalue Set is called, the donating state is still true. String data will
+// be allocated on the arena:
+//
+//   Lvalue Set: donated=true
+//   Arena:
+//   +-----------------------+
+//   |Message foo:           |
+//   | +-------------------+ |
+//   | |InlinedStringField:| |
+//   | | +-----+           | |
+//   | | | | | |           | |
+//   | | +|----+           | |
+//   | +--|----------------+ |
+//   |    V                  |
+//   |  +----------------+   |
+//   |  |'f','o','o',... |   |
+//   |  +----------------+   |
+//   +-----------------------+
+//
+// Some operations will undonate a donated string, including: Mutable,
+// SetAllocated, Rvalue Set, and Swap with a non-donated string.
+//
+// For more details of the donating states transitions, go/pd-inlined-string.
+class PROTOBUF_EXPORT InlinedStringField {
+ public:
+  InlinedStringField() { Init(); }
+  inline void Init() { new (get_mutable()) std::string(); }
+  // Add the dummy parameter just to make InlinedStringField(nullptr)
+  // unambiguous.
+  constexpr InlinedStringField(
+      const ExplicitlyConstructed<std::string>* /*default_value*/,
+      bool /*dummy*/)
+      : value_{} {}
+  explicit InlinedStringField(const std::string& default_value);
+  explicit InlinedStringField(Arena* arena);
+  ~InlinedStringField() { Destruct(); }
+
+  // Lvalue Set. To save space, we pack the donating states of multiple
+  // InlinedStringFields into an uint32_t `donating_states`. The `mask`
+  // indicates the position of the bit for this InlinedStringField. `donated` is
+  // whether this field is donated.
+  //
+  // The caller should guarantee that:
+  //
+  //   `donated == ((donating_states & ~mask) != 0)`
+  //
+  // This method never changes the `donating_states`.
+  void Set(ConstStringParam value, Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  // Rvalue Set. If this field is donated, this method will undonate this field
+  // by mutating the `donating_states` according to `mask`.
+  void Set(std::string&& value, Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void Set(const char* str, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void Set(const char* str, size_t size, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  template <typename RefWrappedType>
+  void Set(std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+           uint32_t mask, MessageLite* msg);
+
+  void SetBytes(ConstStringParam value, Arena* arena, bool donated,
+                uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void SetBytes(std::string&& value, Arena* arena, bool donated,
+                uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void SetBytes(const char* str, ::google::protobuf::Arena* arena, bool donated,
+                uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void SetBytes(const void* p, size_t size, ::google::protobuf::Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg);
+
+  template <typename RefWrappedType>
+  void SetBytes(std::reference_wrapper<RefWrappedType> const_string_ref,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask, MessageLite* msg);
+
+  PROTOBUF_NDEBUG_INLINE void SetNoArena(StringPiece value);
+  PROTOBUF_NDEBUG_INLINE void SetNoArena(std::string&& value);
+
+  // Basic accessors.
+  PROTOBUF_NDEBUG_INLINE const std::string& Get() const { return GetNoArena(); }
+  PROTOBUF_NDEBUG_INLINE const std::string& GetNoArena() const;
+
+  // Mutable returns a std::string* instance that is heap-allocated. If this
+  // field is donated, this method undonates this field by mutating the
+  // `donating_states` according to `mask`, and copies the content of the
+  // original string to the returning string.
+  std::string* Mutable(Arena* arena, bool donated, uint32_t* donating_states,
+                       uint32_t mask, MessageLite* msg);
+  std::string* Mutable(const LazyString& default_value, Arena* arena,
+                       bool donated, uint32_t* donating_states, uint32_t mask,
+                       MessageLite* msg);
+
+  // Mutable(nullptr_t) is an overload to explicitly support Mutable(nullptr)
+  // calls used by the internal parser logic. This provides API equivalence with
+  // ArenaStringPtr, while still protecting against calls with arena pointers.
+  std::string* Mutable(std::nullptr_t);
+  std::string* MutableNoCopy(std::nullptr_t);
+
+  // Takes a std::string that is heap-allocated, and takes ownership. The
+  // std::string's destructor is registered with the arena. Used to implement
+  // set_allocated_<field> in generated classes.
+  //
+  // If this field is donated, this method undonates this field by mutating the
+  // `donating_states` according to `mask`.
+  void SetAllocated(const std::string* default_value, std::string* value,
+                    Arena* arena, bool donated, uint32_t* donating_states,
+                    uint32_t mask, MessageLite* msg);
+
+  void SetAllocatedNoArena(const std::string* default_value,
+                           std::string* value);
+
+  // Release returns a std::string* instance that is heap-allocated and is not
+  // Own()'d by any arena. If the field is not set, this returns nullptr. The
+  // caller retains ownership. Clears this field back to nullptr state. Used to
+  // implement release_<field>() methods on generated classes.
+  PROTOBUF_NODISCARD std::string* Release(Arena* arena, bool donated);
+  PROTOBUF_NODISCARD std::string* Release();
+
+  // --------------------------------------------------------
+  // Below functions will be removed in subsequent code change
+  // --------------------------------------------------------
+#ifdef DEPRECATED_METHODS_TO_BE_DELETED
+  PROTOBUF_NODISCARD std::string* Release(const std::string*, Arena* arena,
+                                          bool donated) {
+    return Release(arena, donated);
+  }
+
+  PROTOBUF_NODISCARD std::string* ReleaseNonDefault(const std::string*,
+                                                    Arena* arena) {
+    return Release();
+  }
+
+  std::string* ReleaseNonDefaultNoArena(const std::string* default_value) {
+    return Release();
+  }
+
+  void Set(const std::string*, ConstStringParam value, Arena* arena,
+           bool donated, uint32_t* donating_states, uint32_t mask,
+           MessageLite* msg) {
+    Set(value, arena, donated, donating_states, mask, msg);
+  }
+
+  void Set(const std::string*, std::string&& value, Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg) {
+    Set(std::move(value), arena, donated, donating_states, mask, msg);
+  }
+
+
+  template <typename FirstParam>
+  void Set(FirstParam, const char* str, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg) {
+    Set(str, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam>
+  void Set(FirstParam p1, const char* str, size_t size, ::google::protobuf::Arena* arena,
+           bool donated, uint32_t* donating_states, uint32_t mask,
+           MessageLite* msg) {
+    Set(str, size, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam, typename RefWrappedType>
+  void Set(FirstParam p1,
+           std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+           uint32_t mask, MessageLite* msg) {
+    Set(const_string_ref, arena, donated, donating_states, mask, msg);
+  }
+
+  void SetBytes(const std::string*, ConstStringParam value, Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
+    Set(value, arena, donated, donating_states, mask, msg);
+  }
+
+
+  void SetBytes(const std::string*, std::string&& value, Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
+    Set(std::move(value), arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam>
+  void SetBytes(FirstParam p1, const char* str, ::google::protobuf::Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
+    SetBytes(str, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam>
+  void SetBytes(FirstParam p1, const void* p, size_t size,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask, MessageLite* msg) {
+    SetBytes(p, size, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam, typename RefWrappedType>
+  void SetBytes(FirstParam p1,
+                std::reference_wrapper<RefWrappedType> const_string_ref,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask, MessageLite* msg) {
+    SetBytes(const_string_ref.get(), arena, donated, donating_states, mask,
+             msg);
+  }
+
+  void SetNoArena(const std::string*, StringPiece value) {
+    SetNoArena(value);
+  }
+  void SetNoArena(const std::string*, std::string&& value) {
+    SetNoArena(std::move(value));
+  }
+
+  std::string* Mutable(ArenaStringPtr::EmptyDefault, Arena* arena, bool donated,
+                       uint32_t* donating_states, uint32_t mask,
+                       MessageLite* msg) {
+    return Mutable(arena, donated, donating_states, mask, msg);
+  }
+
+  PROTOBUF_NDEBUG_INLINE std::string* MutableNoArenaNoDefault(
+      const std::string* /*default_value*/) {
+    return MutableNoCopy(nullptr);
+  }
+
+#endif  // DEPRECATED_METHODS_TO_BE_DELETED
+
+  // 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 PROTOBUF_NDEBUG_INLINE static void InternalSwap(
+      InlinedStringField* lhs, Arena* lhs_arena, bool lhs_arena_dtor_registered,
+      MessageLite* lhs_msg,  //
+      InlinedStringField* rhs, Arena* rhs_arena, bool rhs_arena_dtor_registered,
+      MessageLite* rhs_msg);
+
+  // Frees storage (if not on an arena).
+  PROTOBUF_NDEBUG_INLINE void Destroy(const std::string* default_value,
+                                      Arena* arena) {
+    if (arena == nullptr) {
+      DestroyNoArena(default_value);
+    }
+  }
+  PROTOBUF_NDEBUG_INLINE void DestroyNoArena(const std::string* default_value);
+
+  // Clears content, but keeps allocated std::string, to avoid the overhead of
+  // heap operations. After this returns, the content (as seen by the user) will
+  // always be the empty std::string.
+  PROTOBUF_NDEBUG_INLINE void ClearToEmpty() { ClearNonDefaultToEmpty(); }
+  PROTOBUF_NDEBUG_INLINE void ClearNonDefaultToEmpty() {
+    get_mutable()->clear();
+  }
+
+  // Clears content, but keeps allocated std::string if arena != nullptr, to
+  // avoid the overhead of heap operations. After this returns, the content (as
+  // seen by the user) will always be equal to |default_value|.
+  void ClearToDefault(const LazyString& default_value, Arena* arena,
+                      bool donated);
+
+  // Generated code / reflection only! Returns a mutable pointer to the string.
+  PROTOBUF_NDEBUG_INLINE std::string* UnsafeMutablePointer();
+
+  // InlinedStringField doesn't have things like the `default_value` pointer in
+  // ArenaStringPtr.
+  static constexpr bool IsDefault() { return false; }
+  static constexpr bool IsDefault(const std::string*) { return false; }
+
+ private:
+  void Destruct() { get_mutable()->~basic_string(); }
+
+  PROTOBUF_NDEBUG_INLINE std::string* get_mutable();
+  PROTOBUF_NDEBUG_INLINE const std::string* get_const() const;
+
+  alignas(std::string) char value_[sizeof(std::string)];
+
+  std::string* MutableSlow(::google::protobuf::Arena* arena, bool donated,
+                           uint32_t* donating_states, uint32_t mask,
+                           MessageLite* msg);
+
+
+  // When constructed in an Arena, we want our destructor to be skipped.
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+};
+
+inline std::string* InlinedStringField::get_mutable() {
+  return reinterpret_cast<std::string*>(&value_);
+}
+
+inline const std::string* InlinedStringField::get_const() const {
+  return reinterpret_cast<const std::string*>(&value_);
+}
+
+inline InlinedStringField::InlinedStringField(
+    const std::string& default_value) {
+  new (get_mutable()) std::string(default_value);
+}
+
+
+inline InlinedStringField::InlinedStringField(Arena* /*arena*/) { Init(); }
+
+inline const std::string& InlinedStringField::GetNoArena() const {
+  return *get_const();
+}
+
+inline void InlinedStringField::SetAllocatedNoArena(
+    const std::string* /*default_value*/, std::string* value) {
+  if (value == nullptr) {
+    // Currently, inlined string field can't have non empty default.
+    get_mutable()->clear();
+  } else {
+    get_mutable()->assign(std::move(*value));
+    delete value;
+  }
+}
+
+inline void InlinedStringField::DestroyNoArena(const std::string*) {
+  // This is invoked from the generated message's ArenaDtor, which is used to
+  // clean up objects not allocated on the Arena.
+  this->~InlinedStringField();
+}
+
+inline void InlinedStringField::SetNoArena(StringPiece value) {
+  get_mutable()->assign(value.data(), value.length());
+}
+
+inline void InlinedStringField::SetNoArena(std::string&& value) {
+  get_mutable()->assign(std::move(value));
+}
+
+// Caller should make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
+inline PROTOBUF_NDEBUG_INLINE void InlinedStringField::InternalSwap(
+    InlinedStringField* lhs, Arena* lhs_arena, bool lhs_arena_dtor_registered,
+    MessageLite* lhs_msg,  //
+    InlinedStringField* rhs, Arena* rhs_arena, bool rhs_arena_dtor_registered,
+    MessageLite* rhs_msg) {
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  lhs->get_mutable()->swap(*rhs->get_mutable());
+  if (!lhs_arena_dtor_registered && rhs_arena_dtor_registered) {
+    lhs_msg->OnDemandRegisterArenaDtor(lhs_arena);
+  } else if (lhs_arena_dtor_registered && !rhs_arena_dtor_registered) {
+    rhs_msg->OnDemandRegisterArenaDtor(rhs_arena);
+  }
+#else
+  (void)lhs_arena;
+  (void)rhs_arena;
+  (void)lhs_arena_dtor_registered;
+  (void)rhs_arena_dtor_registered;
+  (void)lhs_msg;
+  (void)rhs_msg;
+  lhs->get_mutable()->swap(*rhs->get_mutable());
+#endif
+}
+
+inline void InlinedStringField::Set(ConstStringParam value, Arena* arena,
+                                    bool donated, uint32_t* /*donating_states*/,
+                                    uint32_t /*mask*/, MessageLite* /*msg*/) {
+  (void)arena;
+  (void)donated;
+  SetNoArena(value);
+}
+
+inline void InlinedStringField::Set(const char* str, ::google::protobuf::Arena* arena,
+                                    bool donated, uint32_t* donating_states,
+                                    uint32_t mask, MessageLite* msg) {
+  Set(ConstStringParam(str), arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::Set(const char* str, size_t size,
+                                    ::google::protobuf::Arena* arena, bool donated,
+                                    uint32_t* donating_states, uint32_t mask,
+                                    MessageLite* msg) {
+  Set(ConstStringParam{str, size}, arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(ConstStringParam value, Arena* arena,
+                                         bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(value, arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(std::string&& value, Arena* arena,
+                                         bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(std::move(value), arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(const char* str,
+                                         ::google::protobuf::Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(str, arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(const void* p, size_t size,
+                                         ::google::protobuf::Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(static_cast<const char*>(p), size, arena, donated, donating_states, mask,
+      msg);
+}
+
+template <typename RefWrappedType>
+inline void InlinedStringField::Set(
+    std::reference_wrapper<RefWrappedType> const_string_ref,
+    ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+    uint32_t mask, MessageLite* msg) {
+  Set(const_string_ref.get(), arena, donated, donating_states, mask, msg);
+}
+
+template <typename RefWrappedType>
+inline void InlinedStringField::SetBytes(
+    std::reference_wrapper<RefWrappedType> const_string_ref,
+    ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+    uint32_t mask, MessageLite* msg) {
+  Set(const_string_ref.get(), arena, donated, donating_states, mask, msg);
+}
+
+inline std::string* InlinedStringField::UnsafeMutablePointer() {
+  return get_mutable();
+}
+
+inline std::string* InlinedStringField::Mutable(std::nullptr_t) {
+  return get_mutable();
+}
+
+inline std::string* InlinedStringField::MutableNoCopy(std::nullptr_t) {
+  return get_mutable();
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
diff --git a/src/google/protobuf/inlined_string_field_unittest.cc b/src/google/protobuf/inlined_string_field_unittest.cc
new file mode 100644
index 0000000..9efe6e9
--- /dev/null
+++ b/src/google/protobuf/inlined_string_field_unittest.cc
@@ -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.
+
+#include <google/protobuf/inlined_string_field.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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.h>
+#include <google/protobuf/arenastring.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+namespace google {
+namespace protobuf {
+
+using internal::ArenaStringPtr;
+using internal::InlinedStringField;
+
+namespace {
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
new file mode 100644
index 0000000..487e1b8
--- /dev/null
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -0,0 +1,967 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 implementation is heavily optimized to make reads and writes
+// of small values (especially varints) as fast as possible.  In
+// particular, we optimize for the common case that a read or a write
+// will not cross the end of the buffer, since we can avoid a lot
+// of branching in this case.
+
+#include <google/protobuf/io/coded_stream.h>
+
+#include <limits.h>
+
+#include <algorithm>
+#include <cstring>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+namespace {
+
+static const int kMaxVarintBytes = 10;
+static const int kMaxVarint32Bytes = 5;
+
+
+inline bool NextNonEmpty(ZeroCopyInputStream* input, const void** data,
+                         int* size) {
+  bool success;
+  do {
+    success = input->Next(data, size);
+  } while (success && *size == 0);
+  return success;
+}
+
+}  // namespace
+
+// CodedInputStream ==================================================
+
+CodedInputStream::~CodedInputStream() {
+  if (input_ != NULL) {
+    BackUpInputToCurrentPosition();
+  }
+}
+
+// Static.
+int CodedInputStream::default_recursion_limit_ = 100;
+
+
+void CodedInputStream::BackUpInputToCurrentPosition() {
+  int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
+  if (backup_bytes > 0) {
+    input_->BackUp(backup_bytes);
+
+    // total_bytes_read_ doesn't include overflow_bytes_.
+    total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
+    buffer_end_ = buffer_;
+    buffer_size_after_limit_ = 0;
+    overflow_bytes_ = 0;
+  }
+}
+
+inline void CodedInputStream::RecomputeBufferLimits() {
+  buffer_end_ += buffer_size_after_limit_;
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
+  if (closest_limit < total_bytes_read_) {
+    // The limit position is in the current buffer.  We must adjust
+    // the buffer size accordingly.
+    buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
+    buffer_end_ -= buffer_size_after_limit_;
+  } else {
+    buffer_size_after_limit_ = 0;
+  }
+}
+
+CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
+  // Current position relative to the beginning of the stream.
+  int current_position = CurrentPosition();
+
+  Limit old_limit = current_limit_;
+
+  // security: byte_limit is possibly evil, so check for negative values
+  // and overflow. Also check that the new requested limit is before the
+  // previous limit; otherwise we continue to enforce the previous limit.
+  if (PROTOBUF_PREDICT_TRUE(byte_limit >= 0 &&
+                            byte_limit <= INT_MAX - current_position &&
+                            byte_limit < current_limit_ - current_position)) {
+    current_limit_ = current_position + byte_limit;
+    RecomputeBufferLimits();
+  }
+
+  return old_limit;
+}
+
+void CodedInputStream::PopLimit(Limit limit) {
+  // The limit passed in is actually the *old* limit, which we returned from
+  // PushLimit().
+  current_limit_ = limit;
+  RecomputeBufferLimits();
+
+  // We may no longer be at a legitimate message end.  ReadTag() needs to be
+  // called again to find out.
+  legitimate_message_end_ = false;
+}
+
+std::pair<CodedInputStream::Limit, int>
+CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
+  return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
+}
+
+CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
+  uint32_t length;
+  return PushLimit(ReadVarint32(&length) ? length : 0);
+}
+
+bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_);
+  ++recursion_budget_;
+  return result;
+}
+
+bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  return result;
+}
+
+int CodedInputStream::BytesUntilLimit() const {
+  if (current_limit_ == INT_MAX) return -1;
+  int current_position = CurrentPosition();
+
+  return current_limit_ - current_position;
+}
+
+void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) {
+  // Make sure the limit isn't already past, since this could confuse other
+  // code.
+  int current_position = CurrentPosition();
+  total_bytes_limit_ = std::max(current_position, total_bytes_limit);
+  RecomputeBufferLimits();
+}
+
+int CodedInputStream::BytesUntilTotalBytesLimit() const {
+  if (total_bytes_limit_ == INT_MAX) return -1;
+  return total_bytes_limit_ - CurrentPosition();
+}
+
+void CodedInputStream::PrintTotalBytesLimitError() {
+  GOOGLE_LOG(ERROR)
+      << "A protocol message was rejected because it was too "
+         "big (more than "
+      << total_bytes_limit_
+      << " bytes).  To increase the limit (or to disable these "
+         "warnings), see CodedInputStream::SetTotalBytesLimit() "
+         "in third_party/protobuf/io/coded_stream.h.";
+}
+
+bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
+  if (buffer_size_after_limit_ > 0) {
+    // We hit a limit inside this buffer.  Advance to the limit and fail.
+    Advance(original_buffer_size);
+    return false;
+  }
+
+  count -= original_buffer_size;
+  buffer_ = NULL;
+  buffer_end_ = buffer_;
+
+  // Make sure this skip doesn't try to skip past the current limit.
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
+  int bytes_until_limit = closest_limit - total_bytes_read_;
+  if (bytes_until_limit < count) {
+    // We hit the limit.  Skip up to it then fail.
+    if (bytes_until_limit > 0) {
+      total_bytes_read_ = closest_limit;
+      input_->Skip(bytes_until_limit);
+    }
+    return false;
+  }
+
+  if (!input_->Skip(count)) {
+    total_bytes_read_ = input_->ByteCount();
+    return false;
+  }
+  total_bytes_read_ += count;
+  return true;
+}
+
+bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
+  if (BufferSize() == 0 && !Refresh()) return false;
+
+  *data = buffer_;
+  *size = BufferSize();
+  return true;
+}
+
+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_t*>(buffer) + current_buffer_size;
+    size -= current_buffer_size;
+    Advance(current_buffer_size);
+    if (!Refresh()) return false;
+  }
+
+  memcpy(buffer, buffer_, size);
+  Advance(size);
+
+  return true;
+}
+
+bool CodedInputStream::ReadString(std::string* buffer, int size) {
+  if (size < 0) return false;  // security: size is often user-supplied
+
+  if (BufferSize() >= size) {
+    STLStringResizeUninitialized(buffer, size);
+    std::pair<char*, bool> z = as_string_data(buffer);
+    if (z.second) {
+      // Oddly enough, memcpy() requires its first two args to be non-NULL even
+      // if we copy 0 bytes.  So, we have ensured that z.first is non-NULL here.
+      GOOGLE_DCHECK(z.first != NULL);
+      memcpy(z.first, buffer_, size);
+      Advance(size);
+    }
+    return true;
+  }
+
+  return ReadStringFallback(buffer, size);
+}
+
+bool CodedInputStream::ReadStringFallback(std::string* buffer, int size) {
+  if (!buffer->empty()) {
+    buffer->clear();
+  }
+
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
+  if (closest_limit != INT_MAX) {
+    int bytes_to_limit = closest_limit - CurrentPosition();
+    if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
+      buffer->reserve(size);
+    }
+  }
+
+  int current_buffer_size;
+  while ((current_buffer_size = BufferSize()) < size) {
+    // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
+    if (current_buffer_size != 0) {
+      // Note:  string1.append(string2) is O(string2.size()) (as opposed to
+      //   O(string1.size() + string2.size()), which would be bad).
+      buffer->append(reinterpret_cast<const char*>(buffer_),
+                     current_buffer_size);
+    }
+    size -= current_buffer_size;
+    Advance(current_buffer_size);
+    if (!Refresh()) return false;
+  }
+
+  buffer->append(reinterpret_cast<const char*>(buffer_), size);
+  Advance(size);
+
+  return true;
+}
+
+
+bool CodedInputStream::ReadLittleEndian32Fallback(uint32_t* value) {
+  uint8_t bytes[sizeof(*value)];
+
+  const uint8_t* ptr;
+  if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
+    // Fast path:  Enough bytes in the buffer to read directly.
+    ptr = buffer_;
+    Advance(sizeof(*value));
+  } else {
+    // Slow path:  Had to read past the end of the buffer.
+    if (!ReadRaw(bytes, sizeof(*value))) return false;
+    ptr = bytes;
+  }
+  ReadLittleEndian32FromArray(ptr, value);
+  return true;
+}
+
+bool CodedInputStream::ReadLittleEndian64Fallback(uint64_t* value) {
+  uint8_t bytes[sizeof(*value)];
+
+  const uint8_t* ptr;
+  if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
+    // Fast path:  Enough bytes in the buffer to read directly.
+    ptr = buffer_;
+    Advance(sizeof(*value));
+  } else {
+    // Slow path:  Had to read past the end of the buffer.
+    if (!ReadRaw(bytes, sizeof(*value))) return false;
+    ptr = bytes;
+  }
+  ReadLittleEndian64FromArray(ptr, value);
+  return true;
+}
+
+namespace {
+
+// Decodes varint64 with known size, N, and returns next pointer. Knowing N at
+// compile time, compiler can generate optimal code. For example, instead of
+// subtracting 0x80 at each iteration, it subtracts properly shifted mask once.
+template <size_t N>
+const uint8_t* DecodeVarint64KnownSize(const uint8_t* buffer, uint64_t* value) {
+  GOOGLE_DCHECK_GT(N, 0);
+  uint64_t result = static_cast<uint64_t>(buffer[N - 1]) << (7 * (N - 1));
+  for (size_t i = 0, offset = 0; i < N - 1; i++, offset += 7) {
+    result += static_cast<uint64_t>(buffer[i] - 0x80) << offset;
+  }
+  *value = result;
+  return buffer + N;
+}
+
+// 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.
+PROTOBUF_ALWAYS_INLINE
+::std::pair<bool, const uint8_t*> ReadVarint32FromArray(uint32_t first_byte,
+                                                      const uint8_t* buffer,
+                                                      uint32_t* value);
+inline ::std::pair<bool, const uint8_t*> ReadVarint32FromArray(
+    uint32_t first_byte, const uint8_t* buffer, uint32_t* 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_t* ptr = buffer;
+  uint32_t b;
+  uint32_t 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;
+  result -= 0x80 << 14;
+  b = *(ptr++);
+  result += b << 21;
+  if (!(b & 0x80)) goto done;
+  result -= 0x80 << 21;
+  b = *(ptr++);
+  result += b << 28;
+  if (!(b & 0x80)) goto done;
+  // "result -= 0x80 << 28" is irrelevant.
+
+  // If the input is larger than 32 bits, we still need to read it all
+  // and discard the high-order bits.
+  for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
+    b = *(ptr++);
+    if (!(b & 0x80)) goto done;
+  }
+
+  // We have overrun the maximum size of a varint (10 bytes).  Assume
+  // the data is corrupt.
+  return std::make_pair(false, ptr);
+
+done:
+  *value = result;
+  return std::make_pair(true, ptr);
+}
+
+PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
+    const uint8_t* buffer, uint64_t* value);
+inline ::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
+    const uint8_t* buffer, uint64_t* value) {
+  // Assumes varint64 is at least 2 bytes.
+  GOOGLE_DCHECK_GE(buffer[0], 128);
+
+  const uint8_t* next;
+  if (buffer[1] < 128) {
+    next = DecodeVarint64KnownSize<2>(buffer, value);
+  } else if (buffer[2] < 128) {
+    next = DecodeVarint64KnownSize<3>(buffer, value);
+  } else if (buffer[3] < 128) {
+    next = DecodeVarint64KnownSize<4>(buffer, value);
+  } else if (buffer[4] < 128) {
+    next = DecodeVarint64KnownSize<5>(buffer, value);
+  } else if (buffer[5] < 128) {
+    next = DecodeVarint64KnownSize<6>(buffer, value);
+  } else if (buffer[6] < 128) {
+    next = DecodeVarint64KnownSize<7>(buffer, value);
+  } else if (buffer[7] < 128) {
+    next = DecodeVarint64KnownSize<8>(buffer, value);
+  } else if (buffer[8] < 128) {
+    next = DecodeVarint64KnownSize<9>(buffer, value);
+  } else if (buffer[9] < 128) {
+    next = DecodeVarint64KnownSize<10>(buffer, value);
+  } else {
+    // We have overrun the maximum size of a varint (10 bytes). Assume
+    // the data is corrupt.
+    return std::make_pair(false, buffer + 11);
+  }
+
+  return std::make_pair(true, next);
+}
+
+}  // namespace
+
+bool CodedInputStream::ReadVarint32Slow(uint32_t* value) {
+  // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+  // for one-byte varints.
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  *value = static_cast<uint32_t>(p.first);
+  return p.second;
+}
+
+int64_t CodedInputStream::ReadVarint32Fallback(uint32_t 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))) {
+    GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
+        << "Caller should provide us with *buffer_ when buffer is non-empty";
+    uint32_t temp;
+    ::std::pair<bool, const uint8_t*> 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%
+    uint32_t temp;
+    return ReadVarint32Slow(&temp) ? static_cast<int64_t>(temp) : -1;
+  }
+}
+
+int CodedInputStream::ReadVarintSizeAsIntSlow() {
+  // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+  // for one-byte varints.
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  if (!p.second || p.first > static_cast<uint64_t>(INT_MAX)) return -1;
+  return p.first;
+}
+
+int CodedInputStream::ReadVarintSizeAsIntFallback() {
+  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))) {
+    uint64_t temp;
+    ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first || temp > static_cast<uint64_t>(INT_MAX)) 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 ReadVarintSizeAsIntSlow();
+  }
+}
+
+uint32_t CodedInputStream::ReadTagSlow() {
+  if (buffer_ == buffer_end_) {
+    // Call refresh.
+    if (!Refresh()) {
+      // Refresh failed.  Make sure that it failed due to EOF, not because
+      // we hit total_bytes_limit_, which, unlike normal limits, is not a
+      // valid place to end a message.
+      int current_position = total_bytes_read_ - buffer_size_after_limit_;
+      if (current_position >= total_bytes_limit_) {
+        // Hit total_bytes_limit_.  But if we also hit the normal limit,
+        // we're still OK.
+        legitimate_message_end_ = current_limit_ == total_bytes_limit_;
+      } else {
+        legitimate_message_end_ = true;
+      }
+      return 0;
+    }
+  }
+
+  // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
+  // again, since we have now refreshed the buffer.
+  uint64_t result = 0;
+  if (!ReadVarint64(&result)) return 0;
+  return static_cast<uint32_t>(result);
+}
+
+uint32_t CodedInputStream::ReadTagFallback(uint32_t 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))) {
+    GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
+    if (first_byte_or_zero == 0) {
+      ++buffer_;
+      return 0;
+    }
+    uint32_t tag;
+    ::std::pair<bool, const uint8_t*> 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
+    // detect this case without making another function call.
+    if ((buf_size == 0) &&
+        ((buffer_size_after_limit_ > 0) ||
+         (total_bytes_read_ == current_limit_)) &&
+        // Make sure that the limit we hit is not total_bytes_limit_, since
+        // in that case we still need to call Refresh() so that it prints an
+        // error.
+        total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
+      // We hit a byte limit.
+      legitimate_message_end_ = true;
+      return 0;
+    }
+    return ReadTagSlow();
+  }
+}
+
+bool CodedInputStream::ReadVarint64Slow(uint64_t* value) {
+  // Slow path:  This read might cross the end of the buffer, so we
+  // need to check and refresh the buffer if and when it does.
+
+  uint64_t result = 0;
+  int count = 0;
+  uint32_t b;
+
+  do {
+    if (count == kMaxVarintBytes) {
+      *value = 0;
+      return false;
+    }
+    while (buffer_ == buffer_end_) {
+      if (!Refresh()) {
+        *value = 0;
+        return false;
+      }
+    }
+    b = *buffer_;
+    result |= static_cast<uint64_t>(b & 0x7F) << (7 * count);
+    Advance(1);
+    ++count;
+  } while (b & 0x80);
+
+  *value = result;
+  return true;
+}
+
+std::pair<uint64_t, 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.
+      (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+    uint64_t temp;
+    ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first) {
+      return std::make_pair(0, false);
+    }
+    buffer_ = p.second;
+    return std::make_pair(temp, true);
+  } else {
+    uint64_t temp;
+    bool success = ReadVarint64Slow(&temp);
+    return std::make_pair(temp, success);
+  }
+}
+
+bool CodedInputStream::Refresh() {
+  GOOGLE_DCHECK_EQ(0, BufferSize());
+
+  if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
+      total_bytes_read_ == current_limit_) {
+    // We've hit a limit.  Stop.
+    int current_position = total_bytes_read_ - buffer_size_after_limit_;
+
+    if (current_position >= total_bytes_limit_ &&
+        total_bytes_limit_ != current_limit_) {
+      // Hit total_bytes_limit_.
+      PrintTotalBytesLimitError();
+    }
+
+    return false;
+  }
+
+  const void* void_buffer;
+  int buffer_size;
+  if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
+    buffer_ = reinterpret_cast<const uint8_t*>(void_buffer);
+    buffer_end_ = buffer_ + buffer_size;
+    GOOGLE_CHECK_GE(buffer_size, 0);
+
+    if (total_bytes_read_ <= INT_MAX - buffer_size) {
+      total_bytes_read_ += buffer_size;
+    } else {
+      // Overflow.  Reset buffer_end_ to not include the bytes beyond INT_MAX.
+      // We can't get that far anyway, because total_bytes_limit_ is guaranteed
+      // to be less than it.  We need to keep track of the number of bytes
+      // we discarded, though, so that we can call input_->BackUp() to back
+      // up over them on destruction.
+
+      // The following line is equivalent to:
+      //   overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
+      // except that it avoids overflows.  Signed integer overflow has
+      // undefined results according to the C standard.
+      overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
+      buffer_end_ -= overflow_bytes_;
+      total_bytes_read_ = INT_MAX;
+    }
+
+    RecomputeBufferLimits();
+    return true;
+  } else {
+    buffer_ = NULL;
+    buffer_end_ = NULL;
+    return false;
+  }
+}
+
+// CodedOutputStream =================================================
+
+void EpsCopyOutputStream::EnableAliasing(bool enabled) {
+  aliasing_enabled_ = enabled && stream_->AllowsAliasing();
+}
+
+int64_t EpsCopyOutputStream::ByteCount(uint8_t* ptr) const {
+  // Calculate the current offset relative to the end of the stream buffer.
+  int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes);
+  return stream_->ByteCount() - delta;
+}
+
+// Flushes what's written out to the underlying ZeroCopyOutputStream buffers.
+// Returns the size remaining in the buffer and sets buffer_end_ to the start
+// of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value)
+int EpsCopyOutputStream::Flush(uint8_t* ptr) {
+  while (buffer_end_ && ptr > end_) {
+    int overrun = ptr - end_;
+    GOOGLE_DCHECK(!had_error_);
+    GOOGLE_DCHECK(overrun <= kSlopBytes);  // NOLINT
+    ptr = Next() + overrun;
+    if (had_error_) return 0;
+  }
+  int s;
+  if (buffer_end_) {
+    std::memcpy(buffer_end_, buffer_, ptr - buffer_);
+    buffer_end_ += ptr - buffer_;
+    s = end_ - ptr;
+  } else {
+    // The stream is writing directly in the ZeroCopyOutputStream buffer.
+    s = end_ + kSlopBytes - ptr;
+    buffer_end_ = ptr;
+  }
+  GOOGLE_DCHECK(s >= 0);  // NOLINT
+  return s;
+}
+
+uint8_t* EpsCopyOutputStream::Trim(uint8_t* ptr) {
+  if (had_error_) return ptr;
+  int s = Flush(ptr);
+  stream_->BackUp(s);
+  // Reset to initial state (expecting new buffer)
+  buffer_end_ = end_ = buffer_;
+  return buffer_;
+}
+
+
+uint8_t* EpsCopyOutputStream::FlushAndResetBuffer(uint8_t* ptr) {
+  if (had_error_) return buffer_;
+  int s = Flush(ptr);
+  if (had_error_) return buffer_;
+  return SetInitialBuffer(buffer_end_, s);
+}
+
+bool EpsCopyOutputStream::Skip(int count, uint8_t** pp) {
+  if (count < 0) return false;
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  int size = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  void* data = buffer_end_;
+  while (count > size) {
+    count -= size;
+    if (!stream_->Next(&data, &size)) {
+      *pp = Error();
+      return false;
+    }
+  }
+  *pp = SetInitialBuffer(static_cast<uint8_t*>(data) + count, size - count);
+  return true;
+}
+
+bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size,
+                                                 uint8_t** pp) {
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  *size = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  *data = buffer_end_;
+  while (*size == 0) {
+    if (!stream_->Next(data, size)) {
+      *pp = Error();
+      return false;
+    }
+  }
+  *pp = SetInitialBuffer(*data, *size);
+  return true;
+}
+
+uint8_t* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size,
+                                                               uint8_t** pp) {
+  if (had_error_) {
+    *pp = buffer_;
+    return nullptr;
+  }
+  int s = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return nullptr;
+  }
+  if (s >= size) {
+    auto res = buffer_end_;
+    *pp = SetInitialBuffer(buffer_end_ + size, s - size);
+    return res;
+  } else {
+    *pp = SetInitialBuffer(buffer_end_, s);
+    return nullptr;
+  }
+}
+
+uint8_t* EpsCopyOutputStream::Next() {
+  GOOGLE_DCHECK(!had_error_);  // NOLINT
+  if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error();
+  if (buffer_end_) {
+    // We're in the patch buffer and need to fill up the previous buffer.
+    std::memcpy(buffer_end_, buffer_, end_ - buffer_);
+    uint8_t* ptr;
+    int size;
+    do {
+      void* data;
+      if (PROTOBUF_PREDICT_FALSE(!stream_->Next(&data, &size))) {
+        // Stream has an error, we use the patch buffer to continue to be
+        // able to write.
+        return Error();
+      }
+      ptr = static_cast<uint8_t*>(data);
+    } while (size == 0);
+    if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
+      std::memcpy(ptr, end_, kSlopBytes);
+      end_ = ptr + size - kSlopBytes;
+      buffer_end_ = nullptr;
+      return ptr;
+    } else {
+      GOOGLE_DCHECK(size > 0);  // NOLINT
+      // Buffer to small
+      std::memmove(buffer_, end_, kSlopBytes);
+      buffer_end_ = ptr;
+      end_ = buffer_ + size;
+      return buffer_;
+    }
+  } else {
+    std::memcpy(buffer_, end_, kSlopBytes);
+    buffer_end_ = end_;
+    end_ = buffer_ + kSlopBytes;
+    return buffer_;
+  }
+}
+
+uint8_t* EpsCopyOutputStream::EnsureSpaceFallback(uint8_t* ptr) {
+  do {
+    if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_;
+    int overrun = ptr - end_;
+    GOOGLE_DCHECK(overrun >= 0);           // NOLINT
+    GOOGLE_DCHECK(overrun <= kSlopBytes);  // NOLINT
+    ptr = Next() + overrun;
+  } while (ptr >= end_);
+  GOOGLE_DCHECK(ptr < end_);  // NOLINT
+  return ptr;
+}
+
+uint8_t* EpsCopyOutputStream::WriteRawFallback(const void* data, int size,
+                                             uint8_t* ptr) {
+  int s = GetSize(ptr);
+  while (s < size) {
+    std::memcpy(ptr, data, s);
+    size -= s;
+    data = static_cast<const uint8_t*>(data) + s;
+    ptr = EnsureSpaceFallback(ptr + s);
+    s = GetSize(ptr);
+  }
+  std::memcpy(ptr, data, size);
+  return ptr + size;
+}
+
+uint8_t* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size,
+                                            uint8_t* ptr) {
+  if (size < GetSize(ptr)
+  ) {
+    return WriteRaw(data, size, ptr);
+  } else {
+    ptr = Trim(ptr);
+    if (stream_->WriteAliasedRaw(data, size)) return ptr;
+    return Error();
+  }
+}
+
+#ifndef PROTOBUF_LITTLE_ENDIAN
+uint8_t* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size,
+                                                   uint8_t* ptr) {
+  auto p = static_cast<const uint8_t*>(data);
+  auto end = p + size;
+  while (end - p >= kSlopBytes) {
+    ptr = EnsureSpace(ptr);
+    uint32_t buffer[4];
+    static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
+    std::memcpy(buffer, p, kSlopBytes);
+    p += kSlopBytes;
+    for (auto x : buffer)
+      ptr = CodedOutputStream::WriteLittleEndian32ToArray(x, ptr);
+  }
+  while (p < end) {
+    ptr = EnsureSpace(ptr);
+    uint32_t buffer;
+    std::memcpy(&buffer, p, 4);
+    p += 4;
+    ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr);
+  }
+  return ptr;
+}
+
+uint8_t* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size,
+                                                   uint8_t* ptr) {
+  auto p = static_cast<const uint8_t*>(data);
+  auto end = p + size;
+  while (end - p >= kSlopBytes) {
+    ptr = EnsureSpace(ptr);
+    uint64_t buffer[2];
+    static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
+    std::memcpy(buffer, p, kSlopBytes);
+    p += kSlopBytes;
+    for (auto x : buffer)
+      ptr = CodedOutputStream::WriteLittleEndian64ToArray(x, ptr);
+  }
+  while (p < end) {
+    ptr = EnsureSpace(ptr);
+    uint64_t buffer;
+    std::memcpy(&buffer, p, 8);
+    p += 8;
+    ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr);
+  }
+  return ptr;
+}
+#endif
+
+
+uint8_t* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32_t num,
+                                                           const std::string& s,
+                                                           uint8_t* ptr) {
+  ptr = EnsureSpace(ptr);
+  uint32_t size = s.size();
+  ptr = WriteLengthDelim(num, size, ptr);
+  return WriteRawMaybeAliased(s.data(), size, ptr);
+}
+
+uint8_t* EpsCopyOutputStream::WriteStringOutline(uint32_t num, const std::string& s,
+                                               uint8_t* ptr) {
+  ptr = EnsureSpace(ptr);
+  uint32_t size = s.size();
+  ptr = WriteLengthDelim(num, size, ptr);
+  return WriteRaw(s.data(), size, ptr);
+}
+
+std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
+    false};
+
+CodedOutputStream::~CodedOutputStream() { Trim(); }
+
+
+uint8_t* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str,
+                                                     uint8_t* target) {
+  GOOGLE_DCHECK_LE(str.size(), std::numeric_limits<uint32_t>::max());
+  target = WriteVarint32ToArray(str.size(), target);
+  return WriteStringToArray(str, target);
+}
+
+uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLineHelper(uint32_t value,
+                                                              uint8_t* target) {
+  GOOGLE_DCHECK_GE(value, 0x80);
+  target[0] |= static_cast<uint8_t>(0x80);
+  value >>= 7;
+  target[1] = static_cast<uint8_t>(value);
+  if (value < 0x80) {
+    return target + 2;
+  }
+  target += 2;
+  do {
+    // Turn on continuation bit in the byte we just wrote.
+    target[-1] |= static_cast<uint8_t>(0x80);
+    value >>= 7;
+    *target = static_cast<uint8_t>(value);
+    ++target;
+  } while (value >= 0x80);
+  return target;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
new file mode 100644
index 0000000..c8fc994
--- /dev/null
+++ b/src/google/protobuf/io/coded_stream.h
@@ -0,0 +1,1799 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 the CodedInputStream and CodedOutputStream classes,
+// which wrap a ZeroCopyInputStream or ZeroCopyOutputStream, respectively,
+// and allow you to read or write individual pieces of data in various
+// formats.  In particular, these implement the varint encoding for
+// integers, a simple variable-length encoding in which smaller numbers
+// take fewer bytes.
+//
+// Typically these classes will only be used internally by the protocol
+// buffer library in order to encode and decode protocol buffers.  Clients
+// of the library only need to know about this class if they wish to write
+// custom message parsing or serialization procedures.
+//
+// CodedOutputStream example:
+//   // Write some data to "myfile".  First we write a 4-byte "magic number"
+//   // to identify the file type, then write a length-delimited string.  The
+//   // string is composed of a varint giving the length followed by the raw
+//   // bytes.
+//   int fd = open("myfile", O_CREAT | O_WRONLY);
+//   ZeroCopyOutputStream* raw_output = new FileOutputStream(fd);
+//   CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
+//
+//   int magic_number = 1234;
+//   char text[] = "Hello world!";
+//   coded_output->WriteLittleEndian32(magic_number);
+//   coded_output->WriteVarint32(strlen(text));
+//   coded_output->WriteRaw(text, strlen(text));
+//
+//   delete coded_output;
+//   delete raw_output;
+//   close(fd);
+//
+// CodedInputStream example:
+//   // Read a file created by the above code.
+//   int fd = open("myfile", O_RDONLY);
+//   ZeroCopyInputStream* raw_input = new FileInputStream(fd);
+//   CodedInputStream* coded_input = new CodedInputStream(raw_input);
+//
+//   coded_input->ReadLittleEndian32(&magic_number);
+//   if (magic_number != 1234) {
+//     cerr << "File not in expected format." << endl;
+//     return;
+//   }
+//
+//   uint32_t size;
+//   coded_input->ReadVarint32(&size);
+//
+//   char* text = new char[size + 1];
+//   coded_input->ReadRaw(buffer, size);
+//   text[size] = '\0';
+//
+//   delete coded_input;
+//   delete raw_input;
+//   close(fd);
+//
+//   cout << "Text is: " << text << endl;
+//   delete [] text;
+//
+// For those who are interested, varint encoding is defined as follows:
+//
+// The encoding operates on unsigned integers of up to 64 bits in length.
+// Each byte of the encoded value has the format:
+// * bits 0-6: Seven bits of the number being encoded.
+// * bit 7: Zero if this is the last byte in the encoding (in which
+//   case all remaining bits of the number are zero) or 1 if
+//   more bytes follow.
+// The first byte contains the least-significant 7 bits of the number, the
+// second byte (if present) contains the next-least-significant 7 bits,
+// and so on.  So, the binary number 1011000101011 would be encoded in two
+// bytes as "10101011 00101100".
+//
+// In theory, varint could be used to encode integers of any length.
+// However, for practicality we set a limit at 64 bits.  The maximum encoded
+// length of a number is thus 10 bytes.
+
+#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
+#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
+
+
+#include <assert.h>
+
+#include <atomic>
+#include <climits>
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#if defined(_MSC_VER) && _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
+
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/port.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class DescriptorPool;
+class MessageFactory;
+class ZeroCopyCodedInputStream;
+
+namespace internal {
+void MapTestForceDeterministic();
+class EpsCopyByteStream;
+}  // namespace internal
+
+namespace io {
+
+// Defined in this file.
+class CodedInputStream;
+class CodedOutputStream;
+
+// Defined in other files.
+class ZeroCopyInputStream;   // zero_copy_stream.h
+class ZeroCopyOutputStream;  // zero_copy_stream.h
+
+// Class which reads and decodes binary data which is composed of varint-
+// encoded integers and fixed-width pieces.  Wraps a ZeroCopyInputStream.
+// Most users will not need to deal with CodedInputStream.
+//
+// Most methods of CodedInputStream that return a bool return false if an
+// underlying I/O error occurs or if the data is malformed.  Once such a
+// failure occurs, the CodedInputStream is broken and is no longer useful.
+// After a failure, callers also should assume writes to "out" args may have
+// occurred, though nothing useful can be determined from those writes.
+class PROTOBUF_EXPORT CodedInputStream {
+ public:
+  // Create a CodedInputStream that reads from the given ZeroCopyInputStream.
+  explicit CodedInputStream(ZeroCopyInputStream* input);
+
+  // Create a CodedInputStream that reads from the given flat array.  This is
+  // faster than using an ArrayInputStream.  PushLimit(size) is implied by
+  // this constructor.
+  explicit CodedInputStream(const uint8_t* buffer, int size);
+
+  // Destroy the CodedInputStream and position the underlying
+  // ZeroCopyInputStream at the first unread byte.  If an error occurred while
+  // reading (causing a method to return false), then the exact position of
+  // the input stream may be anywhere between the last value that was read
+  // successfully and the stream's byte limit.
+  ~CodedInputStream();
+
+  // Return true if this CodedInputStream reads from a flat array instead of
+  // a ZeroCopyInputStream.
+  inline bool IsFlat() const;
+
+  // Skips a number of bytes.  Returns false if an underlying read error
+  // occurs.
+  inline bool Skip(int count);
+
+  // Sets *data to point directly at the unread part of the CodedInputStream's
+  // underlying buffer, and *size to the size of that buffer, but does not
+  // advance the stream's current position.  This will always either produce
+  // a non-empty buffer or return false.  If the caller consumes any of
+  // this data, it should then call Skip() to skip over the consumed bytes.
+  // This may be useful for implementing external fast parsing routines for
+  // types of data not covered by the CodedInputStream interface.
+  bool GetDirectBufferPointer(const void** data, int* size);
+
+  // Like GetDirectBufferPointer, but this method is inlined, and does not
+  // attempt to Refresh() if the buffer is currently empty.
+  PROTOBUF_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 ReadRaw, but reads into a string.
+  bool ReadString(std::string* buffer, int size);
+
+
+  // Read a 32-bit little-endian integer.
+  bool ReadLittleEndian32(uint32_t* value);
+  // Read a 64-bit little-endian integer.
+  bool ReadLittleEndian64(uint64_t* value);
+
+  // These methods read from an externally provided buffer. The caller is
+  // responsible for ensuring that the buffer has sufficient space.
+  // Read a 32-bit little-endian integer.
+  static const uint8_t* ReadLittleEndian32FromArray(const uint8_t* buffer,
+                                                    uint32_t* value);
+  // Read a 64-bit little-endian integer.
+  static const uint8_t* ReadLittleEndian64FromArray(const uint8_t* buffer,
+                                                    uint64_t* value);
+
+  // Read an unsigned integer with Varint encoding, truncating to 32 bits.
+  // Reading a 32-bit value is equivalent to reading a 64-bit one and casting
+  // it to uint32_t, but may be more efficient.
+  bool ReadVarint32(uint32_t* value);
+  // Read an unsigned integer with Varint encoding.
+  bool ReadVarint64(uint64_t* value);
+
+  // Reads a varint off the wire into an "int". This should be used for reading
+  // sizes off the wire (sizes of strings, submessages, bytes fields, etc).
+  //
+  // The value from the wire is interpreted as unsigned.  If its value exceeds
+  // the representable value of an integer on this platform, instead of
+  // truncating we return false. Truncating (as performed by ReadVarint32()
+  // above) is an acceptable approach for fields representing an integer, but
+  // when we are parsing a size from the wire, truncating the value would result
+  // in us misparsing the payload.
+  bool ReadVarintSizeAsInt(int* value);
+
+  // Read a tag.  This calls ReadVarint32() and returns the result, or returns
+  // zero (which is not a valid tag) if ReadVarint32() fails.  Also, ReadTag
+  // (but not ReadTagNoLastTag) updates the last tag value, which can be checked
+  // with LastTagWas().
+  //
+  // 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.
+  PROTOBUF_ALWAYS_INLINE uint32_t ReadTag() {
+    return last_tag_ = ReadTagNoLastTag();
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint32_t ReadTagNoLastTag();
+
+  // This usually a faster alternative to ReadTag() when cutoff is a manifest
+  // constant.  It does particularly well for cutoff >= 127.  The first part
+  // of the return value is the tag that was read, though it can also be 0 in
+  // the cases where ReadTag() would return 0.  If the second part is true
+  // then the tag is known to be in [0, cutoff].  If not, the tag either is
+  // 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.)
+  PROTOBUF_ALWAYS_INLINE
+  std::pair<uint32_t, bool> ReadTagWithCutoff(uint32_t cutoff) {
+    std::pair<uint32_t, bool> result = ReadTagWithCutoffNoLastTag(cutoff);
+    last_tag_ = result.first;
+    return result;
+  }
+
+  PROTOBUF_ALWAYS_INLINE
+  std::pair<uint32_t, bool> ReadTagWithCutoffNoLastTag(uint32_t cutoff);
+
+  // Usually returns true if calling ReadVarint32() now would produce the given
+  // value.  Will always return false if ReadVarint32() would not return the
+  // given value.  If ExpectTag() returns true, it also advances past
+  // the varint.  For best performance, use a compile-time constant as the
+  // 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.
+  PROTOBUF_ALWAYS_INLINE bool ExpectTag(uint32_t 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
+  // of the expected size. For best performance, use a compile-time constant as
+  // the expected tag parameter.
+  //
+  // Returns a pointer beyond the expected tag if it was found, or NULL if it
+  // was not.
+  PROTOBUF_ALWAYS_INLINE
+  static const uint8_t* ExpectTagFromArray(const uint8_t* buffer,
+                                           uint32_t 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
+  // call to LastTagWas() will act as if ReadTag() had been called and returned
+  // zero, and ConsumedEntireMessage() will return true.
+  bool ExpectAtEnd();
+
+  // If the last call to ReadTag() or ReadTagWithCutoff() returned the given
+  // value, returns true.  Otherwise, returns false.
+  // ReadTagNoLastTag/ReadTagWithCutoffNoLastTag do not preserve the last
+  // returned value.
+  //
+  // This is needed because parsers for some types of embedded messages
+  // (with field type TYPE_GROUP) don't actually know that they've reached the
+  // end of a message until they see an ENDGROUP tag, which was actually part
+  // of the enclosing message.  The enclosing message would like to check that
+  // tag to make sure it had the right number, so it calls LastTagWas() on
+  // return from the embedded parser to check.
+  bool LastTagWas(uint32_t expected);
+  void SetLastTag(uint32_t tag) { last_tag_ = tag; }
+
+  // When parsing message (but NOT a group), this method must be called
+  // immediately after MergeFromCodedStream() returns (if it returns true)
+  // to further verify that the message ended in a legitimate way.  For
+  // example, this verifies that parsing did not end on an end-group tag.
+  // It also checks for some cases where, due to optimizations,
+  // MergeFromCodedStream() can incorrectly return true.
+  bool ConsumedEntireMessage();
+  void SetConsumed() { legitimate_message_end_ = true; }
+
+  // Limits ----------------------------------------------------------
+  // Limits are used when parsing length-delimited embedded messages.
+  // After the message's length is read, PushLimit() is used to prevent
+  // the CodedInputStream from reading beyond that length.  Once the
+  // embedded message has been parsed, PopLimit() is called to undo the
+  // limit.
+
+  // Opaque type used with PushLimit() and PopLimit().  Do not modify
+  // values of this type yourself.  The only reason that this isn't a
+  // struct with private internals is for efficiency.
+  typedef int Limit;
+
+  // Places a limit on the number of bytes that the stream may read,
+  // starting from the current position.  Once the stream hits this limit,
+  // it will act like the end of the input has been reached until PopLimit()
+  // is called.
+  //
+  // As the names imply, the stream conceptually has a stack of limits.  The
+  // shortest limit on the stack is always enforced, even if it is not the
+  // top limit.
+  //
+  // The value returned by PushLimit() is opaque to the caller, and must
+  // be passed unchanged to the corresponding call to PopLimit().
+  Limit PushLimit(int byte_limit);
+
+  // Pops the last limit pushed by PushLimit().  The input must be the value
+  // returned by that call to PushLimit().
+  void PopLimit(Limit limit);
+
+  // Returns the number of bytes left until the nearest limit on the
+  // stack is hit, or -1 if no limits are in place.
+  int BytesUntilLimit() const;
+
+  // Returns current position relative to the beginning of the input stream.
+  int CurrentPosition() const;
+
+  // Total Bytes Limit -----------------------------------------------
+  // To prevent malicious users from sending excessively large messages
+  // and causing memory exhaustion, CodedInputStream imposes a hard limit on
+  // the total number of bytes it will read.
+
+  // Sets the maximum number of bytes that this CodedInputStream will read
+  // before refusing to continue.  To prevent servers from allocating enormous
+  // amounts of memory to hold parsed messages, the maximum message length
+  // should be limited to the shortest length that will not harm usability.
+  // The default limit is INT_MAX (~2GB) and apps should set shorter limits
+  // if possible. An error will always be printed to stderr if the limit is
+  // reached.
+  //
+  // Note: setting a limit less than the current read position is interpreted
+  // as a limit on the current position.
+  //
+  // This is unrelated to PushLimit()/PopLimit().
+  void SetTotalBytesLimit(int total_bytes_limit);
+
+  // The Total Bytes Limit minus the Current Position, or -1 if the total bytes
+  // limit is INT_MAX.
+  int BytesUntilTotalBytesLimit() const;
+
+  // Recursion Limit -------------------------------------------------
+  // To prevent corrupt or malicious messages from causing stack overflows,
+  // we must keep track of the depth of recursion when parsing embedded
+  // messages and groups.  CodedInputStream keeps track of this because it
+  // is the only object that is passed down the stack during parsing.
+
+  // Sets the maximum recursion depth.  The default is 100.
+  void SetRecursionLimit(int limit);
+  int RecursionBudget() { return recursion_budget_; }
+
+  static int GetDefaultRecursionLimit() { return default_recursion_limit_; }
+
+  // Increments the current recursion depth.  Returns true if the depth is
+  // under the limit, false if it has gone over.
+  bool IncrementRecursionDepth();
+
+  // Decrements the recursion depth if possible.
+  void DecrementRecursionDepth();
+
+  // Decrements the recursion depth blindly.  This is faster than
+  // DecrementRecursionDepth().  It should be used only if all previous
+  // increments to recursion depth were successful.
+  void UnsafeDecrementRecursionDepth();
+
+  // Shorthand for make_pair(PushLimit(byte_limit), --recursion_budget_).
+  // Using this can reduce code size and complexity in some cases.  The caller
+  // is expected to check that the second part of the result is non-negative (to
+  // bail out if the depth of recursion is too high) and, if all is well, to
+  // later pass the first part of the result to PopLimit() or similar.
+  std::pair<CodedInputStream::Limit, int> IncrementRecursionDepthAndPushLimit(
+      int byte_limit);
+
+  // Shorthand for PushLimit(ReadVarint32(&length) ? length : 0).
+  Limit ReadLengthAndPushLimit();
+
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  UnsafeDecrementRecursionDepth();
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  // Do not use unless the current recursion depth is greater than zero.
+  bool DecrementRecursionDepthAndPopLimit(Limit limit);
+
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  bool CheckEntireMessageConsumedAndPopLimit(Limit limit);
+
+  // Extension Registry ----------------------------------------------
+  // ADVANCED USAGE:  99.9% of people can ignore this section.
+  //
+  // By default, when parsing extensions, the parser looks for extension
+  // definitions in the pool which owns the outer message's Descriptor.
+  // However, you may call SetExtensionRegistry() to provide an alternative
+  // pool instead.  This makes it possible, for example, to parse a message
+  // using a generated class, but represent some extensions using
+  // DynamicMessage.
+
+  // Set the pool used to look up extensions.  Most users do not need to call
+  // this as the correct pool will be chosen automatically.
+  //
+  // WARNING:  It is very easy to misuse this.  Carefully read the requirements
+  //   below.  Do not use this unless you are sure you need it.  Almost no one
+  //   does.
+  //
+  // Let's say you are parsing a message into message object m, and you want
+  // to take advantage of SetExtensionRegistry().  You must follow these
+  // requirements:
+  //
+  // The given DescriptorPool must contain m->GetDescriptor().  It is not
+  // sufficient for it to simply contain a descriptor that has the same name
+  // and content -- it must be the *exact object*.  In other words:
+  //   assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) ==
+  //          m->GetDescriptor());
+  // There are two ways to satisfy this requirement:
+  // 1) Use m->GetDescriptor()->pool() as the pool.  This is generally useless
+  //    because this is the pool that would be used anyway if you didn't call
+  //    SetExtensionRegistry() at all.
+  // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an
+  //    "underlay".  Read the documentation for DescriptorPool for more
+  //    information about underlays.
+  //
+  // You must also provide a MessageFactory.  This factory will be used to
+  // construct Message objects representing extensions.  The factory's
+  // GetPrototype() MUST return non-NULL for any Descriptor which can be found
+  // through the provided pool.
+  //
+  // If the provided factory might return instances of protocol-compiler-
+  // generated (i.e. compiled-in) types, or if the outer message object m is
+  // a generated type, then the given factory MUST have this property:  If
+  // GetPrototype() is given a Descriptor which resides in
+  // DescriptorPool::generated_pool(), the factory MUST return the same
+  // prototype which MessageFactory::generated_factory() would return.  That
+  // is, given a descriptor for a generated type, the factory must return an
+  // instance of the generated class (NOT DynamicMessage).  However, when
+  // given a descriptor for a type that is NOT in generated_pool, the factory
+  // is free to return any implementation.
+  //
+  // The reason for this requirement is that generated sub-objects may be
+  // accessed via the standard (non-reflection) extension accessor methods,
+  // and these methods will down-cast the object to the generated class type.
+  // If the object is not actually of that type, the results would be undefined.
+  // On the other hand, if an extension is not compiled in, then there is no
+  // way the code could end up accessing it via the standard accessors -- the
+  // only way to access the extension is via reflection.  When using reflection,
+  // DynamicMessage and generated messages are indistinguishable, so it's fine
+  // if these objects are represented using DynamicMessage.
+  //
+  // Using DynamicMessageFactory on which you have called
+  // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the
+  // above requirement.
+  //
+  // If either pool or factory is NULL, both must be NULL.
+  //
+  // Note that this feature is ignored when parsing "lite" messages as they do
+  // not have descriptors.
+  void SetExtensionRegistry(const DescriptorPool* pool,
+                            MessageFactory* factory);
+
+  // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool
+  // has been provided.
+  const DescriptorPool* GetExtensionPool();
+
+  // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no
+  // factory has been provided.
+  MessageFactory* GetExtensionFactory();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream);
+
+  const uint8_t* buffer_;
+  const uint8_t* buffer_end_;  // pointer to the end of the buffer.
+  ZeroCopyInputStream* input_;
+  int total_bytes_read_;  // total bytes read from input_, including
+                          // the current buffer
+
+  // If total_bytes_read_ surpasses INT_MAX, we record the extra bytes here
+  // so that we can BackUp() on destruction.
+  int overflow_bytes_;
+
+  // LastTagWas() stuff.
+  uint32_t last_tag_;  // result of last ReadTag() or ReadTagWithCutoff().
+
+  // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly
+  // at EOF, or by ExpectAtEnd() when it returns true.  This happens when we
+  // reach the end of a message and attempt to read another tag.
+  bool legitimate_message_end_;
+
+  // See EnableAliasing().
+  bool aliasing_enabled_;
+
+  // Limits
+  Limit current_limit_;  // if position = -1, no limit is applied
+
+  // For simplicity, if the current buffer crosses a limit (either a normal
+  // limit created by PushLimit() or the total bytes limit), buffer_size_
+  // only tracks the number of bytes before that limit.  This field
+  // contains the number of bytes after it.  Note that this implies that if
+  // buffer_size_ == 0 and buffer_size_after_limit_ > 0, we know we've
+  // hit a limit.  However, if both are zero, it doesn't necessarily mean
+  // we aren't at a limit -- the buffer may have ended exactly at the limit.
+  int buffer_size_after_limit_;
+
+  // Maximum number of bytes to read, period.  This is unrelated to
+  // current_limit_.  Set using SetTotalBytesLimit().
+  int total_bytes_limit_;
+
+  // Current recursion budget, controlled by IncrementRecursionDepth() and
+  // similar.  Starts at recursion_limit_ and goes down: if this reaches
+  // -1 we are over budget.
+  int recursion_budget_;
+  // Recursion depth limit, set by SetRecursionLimit().
+  int recursion_limit_;
+
+  // See SetExtensionRegistry().
+  const DescriptorPool* extension_pool_;
+  MessageFactory* extension_factory_;
+
+  // Private member functions.
+
+  // Fallback when Skip() goes past the end of the current buffer.
+  bool SkipFallback(int count, int original_buffer_size);
+
+  // Advance the buffer by a given number of bytes.
+  void Advance(int amount);
+
+  // Back up input_ to the current buffer position.
+  void BackUpInputToCurrentPosition();
+
+  // Recomputes the value of buffer_size_after_limit_.  Must be called after
+  // current_limit_ or total_bytes_limit_ changes.
+  void RecomputeBufferLimits();
+
+  // Writes an error message saying that we hit total_bytes_limit_.
+  void PrintTotalBytesLimitError();
+
+  // Called when the buffer runs out to request more data.  Implies an
+  // Advance(BufferSize()).
+  bool Refresh();
+
+  // When parsing varints, we optimize for the common case of small values, and
+  // then optimize for the case when the varint fits within the current buffer
+  // piece. The Fallback method is used when we can't use the one-byte
+  // 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.  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_t it read otherwise.  The latter has a bool
+  // indicating success or failure as part of its return type.
+  int64_t ReadVarint32Fallback(uint32_t first_byte_or_zero);
+  int ReadVarintSizeAsIntFallback();
+  std::pair<uint64_t, bool> ReadVarint64Fallback();
+  bool ReadVarint32Slow(uint32_t* value);
+  bool ReadVarint64Slow(uint64_t* value);
+  int ReadVarintSizeAsIntSlow();
+  bool ReadLittleEndian32Fallback(uint32_t* value);
+  bool ReadLittleEndian64Fallback(uint64_t* value);
+
+  // 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_t ReadTagFallback(uint32_t first_byte_or_zero);
+  uint32_t ReadTagSlow();
+  bool ReadStringFallback(std::string* buffer, int size);
+
+  // Return the size of the buffer.
+  int BufferSize() const;
+
+  static const int kDefaultTotalBytesLimit = INT_MAX;
+
+  static int default_recursion_limit_;  // 100 by default.
+
+  friend class google::protobuf::ZeroCopyCodedInputStream;
+  friend class google::protobuf::internal::EpsCopyByteStream;
+};
+
+// EpsCopyOutputStream wraps a ZeroCopyOutputStream and exposes a new stream,
+// which has the property you can write kSlopBytes (16 bytes) from the current
+// position without bounds checks. The cursor into the stream is managed by
+// the user of the class and is an explicit parameter in the methods. Careful
+// use of this class, ie. keep ptr a local variable, eliminates the need to
+// for the compiler to sync the ptr value between register and memory.
+class PROTOBUF_EXPORT EpsCopyOutputStream {
+ public:
+  enum { kSlopBytes = 16 };
+
+  // Initialize from a stream.
+  EpsCopyOutputStream(ZeroCopyOutputStream* stream, bool deterministic,
+                      uint8_t** pp)
+      : end_(buffer_),
+        stream_(stream),
+        is_serialization_deterministic_(deterministic) {
+    *pp = buffer_;
+  }
+
+  // Only for array serialization. No overflow protection, end_ will be the
+  // pointed to the end of the array. When using this the total size is already
+  // known, so no need to maintain the slop region.
+  EpsCopyOutputStream(void* data, int size, bool deterministic)
+      : end_(static_cast<uint8_t*>(data) + size),
+        buffer_end_(nullptr),
+        stream_(nullptr),
+        is_serialization_deterministic_(deterministic) {}
+
+  // Initialize from stream but with the first buffer already given (eager).
+  EpsCopyOutputStream(void* data, int size, ZeroCopyOutputStream* stream,
+                      bool deterministic, uint8_t** pp)
+      : stream_(stream), is_serialization_deterministic_(deterministic) {
+    *pp = SetInitialBuffer(data, size);
+  }
+
+  // Flush everything that's written into the underlying ZeroCopyOutputStream
+  // and trims the underlying stream to the location of ptr.
+  uint8_t* Trim(uint8_t* ptr);
+
+  // After this it's guaranteed you can safely write kSlopBytes to ptr. This
+  // will never fail! The underlying stream can produce an error. Use HadError
+  // to check for errors.
+  PROTOBUF_NODISCARD uint8_t* EnsureSpace(uint8_t* ptr) {
+    if (PROTOBUF_PREDICT_FALSE(ptr >= end_)) {
+      return EnsureSpaceFallback(ptr);
+    }
+    return ptr;
+  }
+
+  uint8_t* WriteRaw(const void* data, int size, uint8_t* ptr) {
+    if (PROTOBUF_PREDICT_FALSE(end_ - ptr < size)) {
+      return WriteRawFallback(data, size, ptr);
+    }
+    std::memcpy(ptr, data, size);
+    return ptr + size;
+  }
+  // Writes the buffer specified by data, size to the stream. Possibly by
+  // aliasing the buffer (ie. not copying the data). The caller is responsible
+  // to make sure the buffer is alive for the duration of the
+  // ZeroCopyOutputStream.
+#ifndef NDEBUG
+  PROTOBUF_NOINLINE
+#endif
+  uint8_t* WriteRawMaybeAliased(const void* data, int size, uint8_t* ptr) {
+    if (aliasing_enabled_) {
+      return WriteAliasedRaw(data, size, ptr);
+    } else {
+      return WriteRaw(data, size, ptr);
+    }
+  }
+
+
+#ifndef NDEBUG
+  PROTOBUF_NOINLINE
+#endif
+  uint8_t* WriteStringMaybeAliased(uint32_t num, const std::string& s,
+                                   uint8_t* ptr) {
+    std::ptrdiff_t size = s.size();
+    if (PROTOBUF_PREDICT_FALSE(
+            size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
+      return WriteStringMaybeAliasedOutline(num, s, ptr);
+    }
+    ptr = UnsafeVarint((num << 3) | 2, ptr);
+    *ptr++ = static_cast<uint8_t>(size);
+    std::memcpy(ptr, s.data(), size);
+    return ptr + size;
+  }
+  uint8_t* WriteBytesMaybeAliased(uint32_t num, const std::string& s,
+                                  uint8_t* ptr) {
+    return WriteStringMaybeAliased(num, s, ptr);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteString(uint32_t num, const T& s,
+                                              uint8_t* ptr) {
+    std::ptrdiff_t size = s.size();
+    if (PROTOBUF_PREDICT_FALSE(
+            size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
+      return WriteStringOutline(num, s, ptr);
+    }
+    ptr = UnsafeVarint((num << 3) | 2, ptr);
+    *ptr++ = static_cast<uint8_t>(size);
+    std::memcpy(ptr, s.data(), size);
+    return ptr + size;
+  }
+  template <typename T>
+#ifndef NDEBUG
+  PROTOBUF_NOINLINE
+#endif
+  uint8_t* WriteBytes(uint32_t num, const T& s, uint8_t* ptr) {
+    return WriteString(num, s, ptr);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteInt32Packed(int num, const T& r,
+                                                   int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteUInt32Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode32);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteSInt32Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, ZigZagEncode32);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteInt64Packed(int num, const T& r,
+                                                   int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteUInt64Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteSInt64Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, ZigZagEncode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteEnumPacked(int num, const T& r, int size,
+                                                  uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteFixedPacked(int num, const T& r,
+                                                   uint8_t* ptr) {
+    ptr = EnsureSpace(ptr);
+    constexpr auto element_size = sizeof(typename T::value_type);
+    auto size = r.size() * element_size;
+    ptr = WriteLengthDelim(num, size, ptr);
+    return WriteRawLittleEndian<element_size>(r.data(), static_cast<int>(size),
+                                              ptr);
+  }
+
+  // Returns true if there was an underlying I/O error since this object was
+  // created.
+  bool HadError() const { return had_error_; }
+
+  // Instructs the EpsCopyOutputStream to allow the underlying
+  // ZeroCopyOutputStream to hold pointers to the original structure instead of
+  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
+  // underlying stream does not support aliasing, then enabling it has no
+  // affect.  For now, this only affects the behavior of
+  // WriteRawMaybeAliased().
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  void EnableAliasing(bool enabled);
+
+  // See documentation on CodedOutputStream::SetSerializationDeterministic.
+  void SetSerializationDeterministic(bool value) {
+    is_serialization_deterministic_ = value;
+  }
+
+  // See documentation on CodedOutputStream::IsSerializationDeterministic.
+  bool IsSerializationDeterministic() const {
+    return is_serialization_deterministic_;
+  }
+
+  // The number of bytes written to the stream at position ptr, relative to the
+  // stream's overall position.
+  int64_t ByteCount(uint8_t* ptr) const;
+
+
+ private:
+  uint8_t* end_;
+  uint8_t* buffer_end_ = buffer_;
+  uint8_t buffer_[2 * kSlopBytes];
+  ZeroCopyOutputStream* stream_;
+  bool had_error_ = false;
+  bool aliasing_enabled_ = false;  // See EnableAliasing().
+  bool is_serialization_deterministic_;
+  bool skip_check_consistency = false;
+
+  uint8_t* EnsureSpaceFallback(uint8_t* ptr);
+  inline uint8_t* Next();
+  int Flush(uint8_t* ptr);
+  std::ptrdiff_t GetSize(uint8_t* ptr) const {
+    GOOGLE_DCHECK(ptr <= end_ + kSlopBytes);  // NOLINT
+    return end_ + kSlopBytes - ptr;
+  }
+
+  uint8_t* Error() {
+    had_error_ = true;
+    // We use the patch buffer to always guarantee space to write to.
+    end_ = buffer_ + kSlopBytes;
+    return buffer_;
+  }
+
+  static constexpr int TagSize(uint32_t tag) {
+    return (tag < (1 << 7))    ? 1
+           : (tag < (1 << 14)) ? 2
+           : (tag < (1 << 21)) ? 3
+           : (tag < (1 << 28)) ? 4
+                               : 5;
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteTag(uint32_t num, uint32_t wt,
+                                           uint8_t* ptr) {
+    GOOGLE_DCHECK(ptr < end_);  // NOLINT
+    return UnsafeVarint((num << 3) | wt, ptr);
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteLengthDelim(int num, uint32_t size,
+                                                   uint8_t* ptr) {
+    ptr = WriteTag(num, 2, ptr);
+    return UnsafeWriteSize(size, ptr);
+  }
+
+  uint8_t* WriteRawFallback(const void* data, int size, uint8_t* ptr);
+
+  uint8_t* WriteAliasedRaw(const void* data, int size, uint8_t* ptr);
+
+  uint8_t* WriteStringMaybeAliasedOutline(uint32_t num, const std::string& s,
+                                          uint8_t* ptr);
+  uint8_t* WriteStringOutline(uint32_t num, const std::string& s, uint8_t* ptr);
+
+  template <typename T, typename E>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteVarintPacked(int num, const T& r,
+                                                    int size, uint8_t* ptr,
+                                                    const E& encode) {
+    ptr = EnsureSpace(ptr);
+    ptr = WriteLengthDelim(num, size, ptr);
+    auto it = r.data();
+    auto end = it + r.size();
+    do {
+      ptr = EnsureSpace(ptr);
+      ptr = UnsafeVarint(encode(*it++), ptr);
+    } while (it < end);
+    return ptr;
+  }
+
+  static uint32_t Encode32(uint32_t v) { return v; }
+  static uint64_t Encode64(uint64_t v) { return v; }
+  static uint32_t ZigZagEncode32(int32_t v) {
+    return (static_cast<uint32_t>(v) << 1) ^ static_cast<uint32_t>(v >> 31);
+  }
+  static uint64_t ZigZagEncode64(int64_t v) {
+    return (static_cast<uint64_t>(v) << 1) ^ static_cast<uint64_t>(v >> 63);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static uint8_t* UnsafeVarint(T value, uint8_t* ptr) {
+    static_assert(std::is_unsigned<T>::value,
+                  "Varint serialization must be unsigned");
+    ptr[0] = static_cast<uint8_t>(value);
+    if (value < 0x80) {
+      return ptr + 1;
+    }
+    // Turn on continuation bit in the byte we just wrote.
+    ptr[0] |= static_cast<uint8_t>(0x80);
+    value >>= 7;
+    ptr[1] = static_cast<uint8_t>(value);
+    if (value < 0x80) {
+      return ptr + 2;
+    }
+    ptr += 2;
+    do {
+      // Turn on continuation bit in the byte we just wrote.
+      ptr[-1] |= static_cast<uint8_t>(0x80);
+      value >>= 7;
+      *ptr = static_cast<uint8_t>(value);
+      ++ptr;
+    } while (value >= 0x80);
+    return ptr;
+  }
+
+  PROTOBUF_ALWAYS_INLINE static uint8_t* UnsafeWriteSize(uint32_t value,
+                                                         uint8_t* ptr) {
+    while (PROTOBUF_PREDICT_FALSE(value >= 0x80)) {
+      *ptr = static_cast<uint8_t>(value | 0x80);
+      value >>= 7;
+      ++ptr;
+    }
+    *ptr++ = static_cast<uint8_t>(value);
+    return ptr;
+  }
+
+  template <int S>
+  uint8_t* WriteRawLittleEndian(const void* data, int size, uint8_t* ptr);
+#if !defined(PROTOBUF_LITTLE_ENDIAN) || \
+    defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  uint8_t* WriteRawLittleEndian32(const void* data, int size, uint8_t* ptr);
+  uint8_t* WriteRawLittleEndian64(const void* data, int size, uint8_t* ptr);
+#endif
+
+  // These methods are for CodedOutputStream. Ideally they should be private
+  // but to match current behavior of CodedOutputStream as close as possible
+  // we allow it some functionality.
+ public:
+  uint8_t* SetInitialBuffer(void* data, int size) {
+    auto ptr = static_cast<uint8_t*>(data);
+    if (size > kSlopBytes) {
+      end_ = ptr + size - kSlopBytes;
+      buffer_end_ = nullptr;
+      return ptr;
+    } else {
+      end_ = buffer_ + size;
+      buffer_end_ = ptr;
+      return buffer_;
+    }
+  }
+
+ private:
+  // Needed by CodedOutputStream HadError. HadError needs to flush the patch
+  // buffers to ensure there is no error as of yet.
+  uint8_t* FlushAndResetBuffer(uint8_t*);
+
+  // The following functions mimic the old CodedOutputStream behavior as close
+  // as possible. They flush the current state to the stream, behave as
+  // the old CodedOutputStream and then return to normal operation.
+  bool Skip(int count, uint8_t** pp);
+  bool GetDirectBufferPointer(void** data, int* size, uint8_t** pp);
+  uint8_t* GetDirectBufferForNBytesAndAdvance(int size, uint8_t** pp);
+
+  friend class CodedOutputStream;
+};
+
+template <>
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<1>(const void* data,
+                                                             int size,
+                                                             uint8_t* ptr) {
+  return WriteRaw(data, size, ptr);
+}
+template <>
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<4>(const void* data,
+                                                             int size,
+                                                             uint8_t* ptr) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  return WriteRaw(data, size, ptr);
+#else
+  return WriteRawLittleEndian32(data, size, ptr);
+#endif
+}
+template <>
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<8>(const void* data,
+                                                             int size,
+                                                             uint8_t* ptr) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  return WriteRaw(data, size, ptr);
+#else
+  return WriteRawLittleEndian64(data, size, ptr);
+#endif
+}
+
+// Class which encodes and writes binary data which is composed of varint-
+// encoded integers and fixed-width pieces.  Wraps a ZeroCopyOutputStream.
+// Most users will not need to deal with CodedOutputStream.
+//
+// Most methods of CodedOutputStream which return a bool return false if an
+// underlying I/O error occurs.  Once such a failure occurs, the
+// CodedOutputStream is broken and is no longer useful. The Write* methods do
+// not return the stream status, but will invalidate the stream if an error
+// occurs. The client can probe HadError() to determine the status.
+//
+// Note that every method of CodedOutputStream which writes some data has
+// a corresponding static "ToArray" version. These versions write directly
+// to the provided buffer, returning a pointer past the last written byte.
+// They require that the buffer has sufficient capacity for the encoded data.
+// This allows an optimization where we check if an output stream has enough
+// space for an entire message before we start writing and, if there is, we
+// call only the ToArray methods to avoid doing bound checks for each
+// individual value.
+// i.e., in the example above:
+//
+//   CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
+//   int magic_number = 1234;
+//   char text[] = "Hello world!";
+//
+//   int coded_size = sizeof(magic_number) +
+//                    CodedOutputStream::VarintSize32(strlen(text)) +
+//                    strlen(text);
+//
+//   uint8_t* buffer =
+//       coded_output->GetDirectBufferForNBytesAndAdvance(coded_size);
+//   if (buffer != nullptr) {
+//     // The output stream has enough space in the buffer: write directly to
+//     // the array.
+//     buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number,
+//                                                            buffer);
+//     buffer = CodedOutputStream::WriteVarint32ToArray(strlen(text), buffer);
+//     buffer = CodedOutputStream::WriteRawToArray(text, strlen(text), buffer);
+//   } else {
+//     // Make bound-checked writes, which will ask the underlying stream for
+//     // more space as needed.
+//     coded_output->WriteLittleEndian32(magic_number);
+//     coded_output->WriteVarint32(strlen(text));
+//     coded_output->WriteRaw(text, strlen(text));
+//   }
+//
+//   delete coded_output;
+class PROTOBUF_EXPORT CodedOutputStream {
+ public:
+  // Creates a CodedOutputStream that writes to the given `stream`.
+  // The provided stream must publicly derive from `ZeroCopyOutputStream`.
+  template <class Stream, class = typename std::enable_if<std::is_base_of<
+                              ZeroCopyOutputStream, Stream>::value>::type>
+  explicit CodedOutputStream(Stream* stream);
+
+  // Creates a CodedOutputStream that writes to the given `stream`, and does
+  // an 'eager initialization' of the internal state if `eager_init` is true.
+  // The provided stream must publicly derive from `ZeroCopyOutputStream`.
+  template <class Stream, class = typename std::enable_if<std::is_base_of<
+                              ZeroCopyOutputStream, Stream>::value>::type>
+  CodedOutputStream(Stream* stream, bool eager_init);
+
+  // Destroy the CodedOutputStream and position the underlying
+  // ZeroCopyOutputStream immediately after the last byte written.
+  ~CodedOutputStream();
+
+  // Returns true if there was an underlying I/O error since this object was
+  // created. On should call Trim before this function in order to catch all
+  // errors.
+  bool HadError() {
+    cur_ = impl_.FlushAndResetBuffer(cur_);
+    GOOGLE_DCHECK(cur_);
+    return impl_.HadError();
+  }
+
+  // Trims any unused space in the underlying buffer so that its size matches
+  // the number of bytes written by this stream. The underlying buffer will
+  // automatically be trimmed when this stream is destroyed; this call is only
+  // necessary if the underlying buffer is accessed *before* the stream is
+  // destroyed.
+  void Trim() { cur_ = impl_.Trim(cur_); }
+
+  // Skips a number of bytes, leaving the bytes unmodified in the underlying
+  // buffer.  Returns false if an underlying write error occurs.  This is
+  // mainly useful with GetDirectBufferPointer().
+  // Note of caution, the skipped bytes may contain uninitialized data. The
+  // caller must make sure that the skipped bytes are properly initialized,
+  // otherwise you might leak bytes from your heap.
+  bool Skip(int count) { return impl_.Skip(count, &cur_); }
+
+  // Sets *data to point directly at the unwritten part of the
+  // CodedOutputStream's underlying buffer, and *size to the size of that
+  // buffer, but does not advance the stream's current position.  This will
+  // always either produce a non-empty buffer or return false.  If the caller
+  // writes any data to this buffer, it should then call Skip() to skip over
+  // the consumed bytes.  This may be useful for implementing external fast
+  // serialization routines for types of data not covered by the
+  // CodedOutputStream interface.
+  bool GetDirectBufferPointer(void** data, int* size) {
+    return impl_.GetDirectBufferPointer(data, size, &cur_);
+  }
+
+  // If there are at least "size" bytes available in the current buffer,
+  // returns a pointer directly into the buffer and advances over these bytes.
+  // The caller may then write directly into this buffer (e.g. using the
+  // *ToArray static methods) rather than go through CodedOutputStream.  If
+  // there are not enough bytes available, returns NULL.  The return pointer is
+  // invalidated as soon as any other non-const method of CodedOutputStream
+  // is called.
+  inline uint8_t* GetDirectBufferForNBytesAndAdvance(int size) {
+    return impl_.GetDirectBufferForNBytesAndAdvance(size, &cur_);
+  }
+
+  // Write raw bytes, copying them from the given buffer.
+  void WriteRaw(const void* buffer, int size) {
+    cur_ = impl_.WriteRaw(buffer, size, cur_);
+  }
+  // Like WriteRaw()  but will try to write aliased data if aliasing is
+  // turned on.
+  void WriteRawMaybeAliased(const void* data, int size);
+  // Like WriteRaw()  but writing directly to the target array.
+  // This is _not_ inlined, as the compiler often optimizes memcpy into inline
+  // copy loops. Since this gets called by every field with string or bytes
+  // type, inlining may lead to a significant amount of code bloat, with only a
+  // minor performance gain.
+  static uint8_t* WriteRawToArray(const void* buffer, int size,
+                                  uint8_t* target);
+
+  // Equivalent to WriteRaw(str.data(), str.size()).
+  void WriteString(const std::string& str);
+  // Like WriteString()  but writing directly to the target array.
+  static uint8_t* WriteStringToArray(const std::string& str, uint8_t* target);
+  // Write the varint-encoded size of str followed by str.
+  static uint8_t* WriteStringWithSizeToArray(const std::string& str,
+                                             uint8_t* target);
+
+
+  // Write a 32-bit little-endian integer.
+  void WriteLittleEndian32(uint32_t value) {
+    cur_ = impl_.EnsureSpace(cur_);
+    SetCur(WriteLittleEndian32ToArray(value, Cur()));
+  }
+  // Like WriteLittleEndian32()  but writing directly to the target array.
+  static uint8_t* WriteLittleEndian32ToArray(uint32_t value, uint8_t* target);
+  // Write a 64-bit little-endian integer.
+  void WriteLittleEndian64(uint64_t value) {
+    cur_ = impl_.EnsureSpace(cur_);
+    SetCur(WriteLittleEndian64ToArray(value, Cur()));
+  }
+  // Like WriteLittleEndian64()  but writing directly to the target array.
+  static uint8_t* WriteLittleEndian64ToArray(uint64_t value, uint8_t* target);
+
+  // Write an unsigned integer with Varint encoding.  Writing a 32-bit value
+  // is equivalent to casting it to uint64_t and writing it as a 64-bit value,
+  // but may be more efficient.
+  void WriteVarint32(uint32_t value);
+  // Like WriteVarint32()  but writing directly to the target array.
+  static uint8_t* WriteVarint32ToArray(uint32_t value, uint8_t* target);
+  // Like WriteVarint32()  but writing directly to the target array, and with
+  // the less common-case paths being out of line rather than inlined.
+  static uint8_t* WriteVarint32ToArrayOutOfLine(uint32_t value,
+                                                uint8_t* target);
+  // Write an unsigned integer with Varint encoding.
+  void WriteVarint64(uint64_t value);
+  // Like WriteVarint64()  but writing directly to the target array.
+  static uint8_t* WriteVarint64ToArray(uint64_t value, uint8_t* target);
+
+  // Equivalent to WriteVarint32() except when the value is negative,
+  // in which case it must be sign-extended to a full 10 bytes.
+  void WriteVarint32SignExtended(int32_t value);
+  // Like WriteVarint32SignExtended()  but writing directly to the target array.
+  static uint8_t* WriteVarint32SignExtendedToArray(int32_t value,
+                                                   uint8_t* target);
+
+  // This is identical to WriteVarint32(), but optimized for writing tags.
+  // In particular, if the input is a compile-time constant, this method
+  // compiles down to a couple instructions.
+  // Always inline because otherwise the aforementioned optimization can't work,
+  // but GCC by default doesn't want to inline this.
+  void WriteTag(uint32_t value);
+  // Like WriteTag()  but writing directly to the target array.
+  PROTOBUF_ALWAYS_INLINE
+  static uint8_t* WriteTagToArray(uint32_t value, uint8_t* target);
+
+  // Returns the number of bytes needed to encode the given value as a varint.
+  static size_t VarintSize32(uint32_t value);
+  // Returns the number of bytes needed to encode the given value as a varint.
+  static size_t VarintSize64(uint64_t value);
+
+  // If negative, 10 bytes.  Otherwise, same as VarintSize32().
+  static size_t VarintSize32SignExtended(int32_t value);
+
+  // Same as above, plus one.  The additional one comes at no compute cost.
+  static size_t VarintSize32PlusOne(uint32_t value);
+  static size_t VarintSize64PlusOne(uint64_t value);
+  static size_t VarintSize32SignExtendedPlusOne(int32_t value);
+
+  // Compile-time equivalent of VarintSize32().
+  template <uint32_t Value>
+  struct StaticVarintSize32 {
+    static const size_t value = (Value < (1 << 7))    ? 1
+                                : (Value < (1 << 14)) ? 2
+                                : (Value < (1 << 21)) ? 3
+                                : (Value < (1 << 28)) ? 4
+                                                      : 5;
+  };
+
+  // Returns the total number of bytes written since this object was created.
+  int ByteCount() const {
+    return static_cast<int>(impl_.ByteCount(cur_) - start_count_);
+  }
+
+  // Instructs the CodedOutputStream to allow the underlying
+  // ZeroCopyOutputStream to hold pointers to the original structure instead of
+  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
+  // underlying stream does not support aliasing, then enabling it has no
+  // affect.  For now, this only affects the behavior of
+  // WriteRawMaybeAliased().
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  void EnableAliasing(bool enabled) { impl_.EnableAliasing(enabled); }
+
+  // Indicate to the serializer whether the user wants deterministic
+  // serialization. The default when this is not called comes from the global
+  // default, controlled by SetDefaultSerializationDeterministic.
+  //
+  // What deterministic serialization means is entirely up to the driver of the
+  // serialization process (i.e. the caller of methods like WriteVarint32). In
+  // the case of serializing a proto buffer message using one of the methods of
+  // MessageLite, this means that for a given binary equal messages will always
+  // be serialized to the same bytes. This implies:
+  //
+  //   * Repeated serialization of a message will return the same bytes.
+  //
+  //   * Different processes running the same binary (including on different
+  //     machines) will serialize equal messages to the same bytes.
+  //
+  // Note that this is *not* canonical across languages. It is also unstable
+  // across different builds with intervening message definition changes, due to
+  // unknown fields. Users who need canonical serialization (e.g. persistent
+  // storage in a canonical form, fingerprinting) should define their own
+  // canonicalization specification and implement the serializer using
+  // reflection APIs rather than relying on this API.
+  void SetSerializationDeterministic(bool value) {
+    impl_.SetSerializationDeterministic(value);
+  }
+
+  // Return whether the user wants deterministic serialization. See above.
+  bool IsSerializationDeterministic() const {
+    return impl_.IsSerializationDeterministic();
+  }
+
+  static bool IsDefaultSerializationDeterministic() {
+    return default_serialization_deterministic_.load(
+               std::memory_order_relaxed) != 0;
+  }
+
+  template <typename Func>
+  void Serialize(const Func& func);
+
+  uint8_t* Cur() const { return cur_; }
+  void SetCur(uint8_t* ptr) { cur_ = ptr; }
+  EpsCopyOutputStream* EpsCopy() { return &impl_; }
+
+ private:
+  template <class Stream>
+  void InitEagerly(Stream* stream);
+
+  EpsCopyOutputStream impl_;
+  uint8_t* cur_;
+  int64_t start_count_;
+  static std::atomic<bool> default_serialization_deterministic_;
+
+  // See above.  Other projects may use "friend" to allow them to call this.
+  // After SetDefaultSerializationDeterministic() completes, all protocol
+  // buffer serializations will be deterministic by default.  Thread safe.
+  // However, the meaning of "after" is subtle here: to be safe, each thread
+  // that wants deterministic serialization by default needs to call
+  // SetDefaultSerializationDeterministic() or ensure on its own that another
+  // thread has done so.
+  friend void internal::MapTestForceDeterministic();
+  static void SetDefaultSerializationDeterministic() {
+    default_serialization_deterministic_.store(true, std::memory_order_relaxed);
+  }
+  // REQUIRES: value >= 0x80, and that (value & 7f) has been written to *target.
+  static uint8_t* WriteVarint32ToArrayOutOfLineHelper(uint32_t value,
+                                                      uint8_t* target);
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
+};
+
+// inline methods ====================================================
+// The vast majority of varints are only one byte.  These inline
+// methods optimize for that case.
+
+inline bool CodedInputStream::ReadVarint32(uint32_t* value) {
+  uint32_t v = 0;
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
+  }
+  int64_t result = ReadVarint32Fallback(v);
+  *value = static_cast<uint32_t>(result);
+  return result >= 0;
+}
+
+inline bool CodedInputStream::ReadVarint64(uint64_t* value) {
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) {
+    *value = *buffer_;
+    Advance(1);
+    return true;
+  }
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  *value = p.first;
+  return p.second;
+}
+
+inline bool CodedInputStream::ReadVarintSizeAsInt(int* value) {
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    int v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
+  }
+  *value = ReadVarintSizeAsIntFallback();
+  return *value >= 0;
+}
+
+// static
+inline const uint8_t* CodedInputStream::ReadLittleEndian32FromArray(
+    const uint8_t* buffer, uint32_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(value, buffer, sizeof(*value));
+  return buffer + sizeof(*value);
+#else
+  *value = (static_cast<uint32_t>(buffer[0])) |
+           (static_cast<uint32_t>(buffer[1]) << 8) |
+           (static_cast<uint32_t>(buffer[2]) << 16) |
+           (static_cast<uint32_t>(buffer[3]) << 24);
+  return buffer + sizeof(*value);
+#endif
+}
+// static
+inline const uint8_t* CodedInputStream::ReadLittleEndian64FromArray(
+    const uint8_t* buffer, uint64_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(value, buffer, sizeof(*value));
+  return buffer + sizeof(*value);
+#else
+  uint32_t part0 = (static_cast<uint32_t>(buffer[0])) |
+                   (static_cast<uint32_t>(buffer[1]) << 8) |
+                   (static_cast<uint32_t>(buffer[2]) << 16) |
+                   (static_cast<uint32_t>(buffer[3]) << 24);
+  uint32_t part1 = (static_cast<uint32_t>(buffer[4])) |
+                   (static_cast<uint32_t>(buffer[5]) << 8) |
+                   (static_cast<uint32_t>(buffer[6]) << 16) |
+                   (static_cast<uint32_t>(buffer[7]) << 24);
+  *value = static_cast<uint64_t>(part0) | (static_cast<uint64_t>(part1) << 32);
+  return buffer + sizeof(*value);
+#endif
+}
+
+inline bool CodedInputStream::ReadLittleEndian32(uint32_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  if (PROTOBUF_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
+    buffer_ = ReadLittleEndian32FromArray(buffer_, value);
+    return true;
+  } else {
+    return ReadLittleEndian32Fallback(value);
+  }
+#else
+  return ReadLittleEndian32Fallback(value);
+#endif
+}
+
+inline bool CodedInputStream::ReadLittleEndian64(uint64_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  if (PROTOBUF_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
+    buffer_ = ReadLittleEndian64FromArray(buffer_, value);
+    return true;
+  } else {
+    return ReadLittleEndian64Fallback(value);
+  }
+#else
+  return ReadLittleEndian64Fallback(value);
+#endif
+}
+
+inline uint32_t CodedInputStream::ReadTagNoLastTag() {
+  uint32_t v = 0;
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      Advance(1);
+      return v;
+    }
+  }
+  v = ReadTagFallback(v);
+  return v;
+}
+
+inline std::pair<uint32_t, bool> CodedInputStream::ReadTagWithCutoffNoLastTag(
+    uint32_t cutoff) {
+  // 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_t first_byte_or_zero = 0;
+  if (PROTOBUF_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_t>(buffer_[0]) > 0) {
+      const uint32_t kMax1ByteVarint = 0x7f;
+      uint32_t tag = buffer_[0];
+      Advance(1);
+      return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
+    }
+    // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
+    // and tag is two bytes.  The latter is tested by bitwise-and-not of the
+    // first byte and the second byte.
+    if (cutoff >= 0x80 && PROTOBUF_PREDICT_TRUE(buffer_ + 1 < buffer_end_) &&
+        PROTOBUF_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) {
+      const uint32_t kMax2ByteVarint = (0x7f << 7) + 0x7f;
+      uint32_t tag = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
+      Advance(2);
+      // It might make sense to test for tag == 0 now, but it is so rare that
+      // that we don't bother.  A varint-encoded 0 should be one byte unless
+      // the encoder lost its mind.  The second part of the return value of
+      // this function is allowed to be either true or false if the tag is 0,
+      // so we don't have to check for tag == 0.  We may need to check whether
+      // it exceeds cutoff.
+      bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
+      return std::make_pair(tag, at_or_below_cutoff);
+    }
+  }
+  // Slow path
+  const uint32_t tag = ReadTagFallback(first_byte_or_zero);
+  return std::make_pair(tag, static_cast<uint32_t>(tag - 1) < cutoff);
+}
+
+inline bool CodedInputStream::LastTagWas(uint32_t expected) {
+  return last_tag_ == expected;
+}
+
+inline bool CodedInputStream::ConsumedEntireMessage() {
+  return legitimate_message_end_;
+}
+
+inline bool CodedInputStream::ExpectTag(uint32_t expected) {
+  if (expected < (1 << 7)) {
+    if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_) &&
+        buffer_[0] == expected) {
+      Advance(1);
+      return true;
+    } else {
+      return false;
+    }
+  } else if (expected < (1 << 14)) {
+    if (PROTOBUF_PREDICT_TRUE(BufferSize() >= 2) &&
+        buffer_[0] == static_cast<uint8_t>(expected | 0x80) &&
+        buffer_[1] == static_cast<uint8_t>(expected >> 7)) {
+      Advance(2);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    // Don't bother optimizing for larger values.
+    return false;
+  }
+}
+
+inline const uint8_t* CodedInputStream::ExpectTagFromArray(
+    const uint8_t* buffer, uint32_t expected) {
+  if (expected < (1 << 7)) {
+    if (buffer[0] == expected) {
+      return buffer + 1;
+    }
+  } else if (expected < (1 << 14)) {
+    if (buffer[0] == static_cast<uint8_t>(expected | 0x80) &&
+        buffer[1] == static_cast<uint8_t>(expected >> 7)) {
+      return buffer + 2;
+    }
+  }
+  return nullptr;
+}
+
+inline void CodedInputStream::GetDirectBufferPointerInline(const void** data,
+                                                           int* size) {
+  *data = buffer_;
+  *size = static_cast<int>(buffer_end_ - buffer_);
+}
+
+inline bool CodedInputStream::ExpectAtEnd() {
+  // If we are at a limit we know no more bytes can be read.  Otherwise, it's
+  // hard to say without calling Refresh(), and we'd rather not do that.
+
+  if (buffer_ == buffer_end_ && ((buffer_size_after_limit_ != 0) ||
+                                 (total_bytes_read_ == current_limit_))) {
+    last_tag_ = 0;                   // Pretend we called ReadTag()...
+    legitimate_message_end_ = true;  // ... and it hit EOF.
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline int CodedInputStream::CurrentPosition() const {
+  return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
+}
+
+inline void CodedInputStream::Advance(int amount) { buffer_ += amount; }
+
+inline void CodedInputStream::SetRecursionLimit(int limit) {
+  recursion_budget_ += limit - recursion_limit_;
+  recursion_limit_ = limit;
+}
+
+inline bool CodedInputStream::IncrementRecursionDepth() {
+  --recursion_budget_;
+  return recursion_budget_ >= 0;
+}
+
+inline void CodedInputStream::DecrementRecursionDepth() {
+  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;
+  extension_factory_ = factory;
+}
+
+inline const DescriptorPool* CodedInputStream::GetExtensionPool() {
+  return extension_pool_;
+}
+
+inline MessageFactory* CodedInputStream::GetExtensionFactory() {
+  return extension_factory_;
+}
+
+inline int CodedInputStream::BufferSize() const {
+  return static_cast<int>(buffer_end_ - buffer_);
+}
+
+inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
+    : buffer_(nullptr),
+      buffer_end_(nullptr),
+      input_(input),
+      total_bytes_read_(0),
+      overflow_bytes_(0),
+      last_tag_(0),
+      legitimate_message_end_(false),
+      aliasing_enabled_(false),
+      current_limit_(std::numeric_limits<int32_t>::max()),
+      buffer_size_after_limit_(0),
+      total_bytes_limit_(kDefaultTotalBytesLimit),
+      recursion_budget_(default_recursion_limit_),
+      recursion_limit_(default_recursion_limit_),
+      extension_pool_(nullptr),
+      extension_factory_(nullptr) {
+  // Eagerly Refresh() so buffer space is immediately available.
+  Refresh();
+}
+
+inline CodedInputStream::CodedInputStream(const uint8_t* buffer, int size)
+    : buffer_(buffer),
+      buffer_end_(buffer + size),
+      input_(nullptr),
+      total_bytes_read_(size),
+      overflow_bytes_(0),
+      last_tag_(0),
+      legitimate_message_end_(false),
+      aliasing_enabled_(false),
+      current_limit_(size),
+      buffer_size_after_limit_(0),
+      total_bytes_limit_(kDefaultTotalBytesLimit),
+      recursion_budget_(default_recursion_limit_),
+      recursion_limit_(default_recursion_limit_),
+      extension_pool_(nullptr),
+      extension_factory_(nullptr) {
+  // Note that setting current_limit_ == size is important to prevent some
+  // code paths from trying to access input_ and segfaulting.
+}
+
+inline bool CodedInputStream::IsFlat() const { return input_ == nullptr; }
+
+inline bool CodedInputStream::Skip(int count) {
+  if (count < 0) return false;  // security: count is often user-supplied
+
+  const int original_buffer_size = BufferSize();
+
+  if (count <= original_buffer_size) {
+    // Just skipping within the current buffer.  Easy.
+    Advance(count);
+    return true;
+  }
+
+  return SkipFallback(count, original_buffer_size);
+}
+
+template <class Stream, class>
+inline CodedOutputStream::CodedOutputStream(Stream* stream)
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
+  InitEagerly(stream);
+}
+
+template <class Stream, class>
+inline CodedOutputStream::CodedOutputStream(Stream* stream, bool eager_init)
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
+  if (eager_init) {
+    InitEagerly(stream);
+  }
+}
+
+template <class Stream>
+inline void CodedOutputStream::InitEagerly(Stream* stream) {
+  void* data;
+  int size;
+  if (PROTOBUF_PREDICT_TRUE(stream->Next(&data, &size) && size > 0)) {
+    cur_ = impl_.SetInitialBuffer(data, size);
+  }
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint32ToArray(uint32_t value,
+                                                        uint8_t* target) {
+  return EpsCopyOutputStream::UnsafeVarint(value, target);
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLine(
+    uint32_t value, uint8_t* target) {
+  target[0] = static_cast<uint8_t>(value);
+  if (value < 0x80) {
+    return target + 1;
+  } else {
+    return WriteVarint32ToArrayOutOfLineHelper(value, target);
+  }
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint64ToArray(uint64_t value,
+                                                        uint8_t* target) {
+  return EpsCopyOutputStream::UnsafeVarint(value, target);
+}
+
+inline void CodedOutputStream::WriteVarint32SignExtended(int32_t value) {
+  WriteVarint64(static_cast<uint64_t>(value));
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint32SignExtendedToArray(
+    int32_t value, uint8_t* target) {
+  return WriteVarint64ToArray(static_cast<uint64_t>(value), target);
+}
+
+inline uint8_t* CodedOutputStream::WriteLittleEndian32ToArray(uint32_t value,
+                                                              uint8_t* target) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(target, &value, sizeof(value));
+#else
+  target[0] = static_cast<uint8_t>(value);
+  target[1] = static_cast<uint8_t>(value >> 8);
+  target[2] = static_cast<uint8_t>(value >> 16);
+  target[3] = static_cast<uint8_t>(value >> 24);
+#endif
+  return target + sizeof(value);
+}
+
+inline uint8_t* CodedOutputStream::WriteLittleEndian64ToArray(uint64_t value,
+                                                              uint8_t* target) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(target, &value, sizeof(value));
+#else
+  uint32_t part0 = static_cast<uint32_t>(value);
+  uint32_t part1 = static_cast<uint32_t>(value >> 32);
+
+  target[0] = static_cast<uint8_t>(part0);
+  target[1] = static_cast<uint8_t>(part0 >> 8);
+  target[2] = static_cast<uint8_t>(part0 >> 16);
+  target[3] = static_cast<uint8_t>(part0 >> 24);
+  target[4] = static_cast<uint8_t>(part1);
+  target[5] = static_cast<uint8_t>(part1 >> 8);
+  target[6] = static_cast<uint8_t>(part1 >> 16);
+  target[7] = static_cast<uint8_t>(part1 >> 24);
+#endif
+  return target + sizeof(value);
+}
+
+inline void CodedOutputStream::WriteVarint32(uint32_t value) {
+  cur_ = impl_.EnsureSpace(cur_);
+  SetCur(WriteVarint32ToArray(value, Cur()));
+}
+
+inline void CodedOutputStream::WriteVarint64(uint64_t value) {
+  cur_ = impl_.EnsureSpace(cur_);
+  SetCur(WriteVarint64ToArray(value, Cur()));
+}
+
+inline void CodedOutputStream::WriteTag(uint32_t value) {
+  WriteVarint32(value);
+}
+
+inline uint8_t* CodedOutputStream::WriteTagToArray(uint32_t value,
+                                                   uint8_t* target) {
+  return WriteVarint32ToArray(value, target);
+}
+
+inline size_t CodedOutputStream::VarintSize32(uint32_t value) {
+  // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
+  // Use an explicit multiplication to implement the divide of
+  // a number in the 1..31 range.
+  // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
+  // undefined.
+  uint32_t log2value = Bits::Log2FloorNonZero(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize32PlusOne(uint32_t value) {
+  // Same as above, but one more.
+  uint32_t log2value = Bits::Log2FloorNonZero(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73 + 64) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize64(uint64_t value) {
+  // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
+  // Use an explicit multiplication to implement the divide of
+  // a number in the 1..63 range.
+  // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
+  // undefined.
+  uint32_t log2value = Bits::Log2FloorNonZero64(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize64PlusOne(uint64_t value) {
+  // Same as above, but one more.
+  uint32_t log2value = Bits::Log2FloorNonZero64(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73 + 64) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize32SignExtended(int32_t value) {
+  return VarintSize64(static_cast<uint64_t>(int64_t{value}));
+}
+
+inline size_t CodedOutputStream::VarintSize32SignExtendedPlusOne(
+    int32_t value) {
+  return VarintSize64PlusOne(static_cast<uint64_t>(int64_t{value}));
+}
+
+inline void CodedOutputStream::WriteString(const std::string& str) {
+  WriteRaw(str.data(), static_cast<int>(str.size()));
+}
+
+inline void CodedOutputStream::WriteRawMaybeAliased(const void* data,
+                                                    int size) {
+  cur_ = impl_.WriteRawMaybeAliased(data, size, cur_);
+}
+
+inline uint8_t* CodedOutputStream::WriteRawToArray(const void* data, int size,
+                                                   uint8_t* target) {
+  memcpy(target, data, size);
+  return target + size;
+}
+
+inline uint8_t* CodedOutputStream::WriteStringToArray(const std::string& str,
+                                                      uint8_t* target) {
+  return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
+#pragma runtime_checks("c", restore)
+#endif  // _MSC_VER && !defined(__INTEL_COMPILER)
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
new file mode 100644
index 0000000..b32bf45
--- /dev/null
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -0,0 +1,1348 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 tests and benchmarks.
+
+#include <google/protobuf/io/coded_stream.h>
+
+#include <limits.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/casts.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace {
+
+
+// ===================================================================
+// Data-Driven Test Infrastructure
+
+// TEST_1D and TEST_2D are macros I'd eventually like to see added to
+// gTest.  These macros can be used to declare tests which should be
+// run multiple times, once for each item in some input array.  TEST_1D
+// tests all cases in a single input array.  TEST_2D tests all
+// combinations of cases from two arrays.  The arrays must be statically
+// defined such that the GOOGLE_ARRAYSIZE() macro works on them.  Example:
+//
+// int kCases[] = {1, 2, 3, 4}
+// TEST_1D(MyFixture, MyTest, kCases) {
+//   EXPECT_GT(kCases_case, 0);
+// }
+//
+// This test iterates through the numbers 1, 2, 3, and 4 and tests that
+// they are all grater than zero.  In case of failure, the exact case
+// which failed will be printed.  The case type must be printable using
+// ostream::operator<<.
+
+// TODO(kenton):  gTest now supports "parameterized tests" which would be
+//   a better way to accomplish this.  Rewrite when time permits.
+
+#define TEST_1D(FIXTURE, NAME, CASES)                             \
+  class FIXTURE##_##NAME##_DD : public FIXTURE {                  \
+   protected:                                                     \
+    template <typename CaseType>                                  \
+    void DoSingleCase(const CaseType& CASES##_case);              \
+  };                                                              \
+                                                                  \
+  TEST_F(FIXTURE##_##NAME##_DD, NAME) {                           \
+    for (size_t i = 0; i < GOOGLE_ARRAYSIZE(CASES); i++) {               \
+      SCOPED_TRACE(testing::Message()                             \
+                   << #CASES " case #" << i << ": " << CASES[i]); \
+      DoSingleCase(CASES[i]);                                     \
+    }                                                             \
+  }                                                               \
+                                                                  \
+  template <typename CaseType>                                    \
+  void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType& CASES##_case)
+
+#define TEST_2D(FIXTURE, NAME, CASES1, CASES2)                              \
+  class FIXTURE##_##NAME##_DD : public FIXTURE {                            \
+   protected:                                                               \
+    template <typename CaseType1, typename CaseType2>                       \
+    void DoSingleCase(const CaseType1& CASES1##_case,                       \
+                      const CaseType2& CASES2##_case);                      \
+  };                                                                        \
+                                                                            \
+  TEST_F(FIXTURE##_##NAME##_DD, NAME) {                                     \
+    for (size_t i = 0; i < GOOGLE_ARRAYSIZE(CASES1); i++) {                        \
+      for (size_t j = 0; j < GOOGLE_ARRAYSIZE(CASES2); j++) {                      \
+        SCOPED_TRACE(testing::Message()                                     \
+                     << #CASES1 " case #" << i << ": " << CASES1[i] << ", " \
+                     << #CASES2 " case #" << j << ": " << CASES2[j]);       \
+        DoSingleCase(CASES1[i], CASES2[j]);                                 \
+      }                                                                     \
+    }                                                                       \
+  }                                                                         \
+                                                                            \
+  template <typename CaseType1, typename CaseType2>                         \
+  void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType1& CASES1##_case,  \
+                                           const CaseType2& CASES2##_case)
+
+// ===================================================================
+
+class CodedStreamTest : public testing::Test {
+ protected:
+  // Buffer used during most of the tests. This assumes tests run sequentially.
+  static constexpr int kBufferSize = 1024 * 64;
+  static uint8_t buffer_[kBufferSize];
+};
+
+uint8_t CodedStreamTest::buffer_[CodedStreamTest::kBufferSize];
+
+// We test each operation over a variety of block sizes to insure that
+// we test cases where reads or writes cross buffer boundaries, cases
+// where they don't, and cases where there is so much buffer left that
+// we can use special optimized paths that don't worry about bounds
+// checks.
+const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
+
+
+// -------------------------------------------------------------------
+// Varint tests.
+
+struct VarintCase {
+  uint8_t bytes[10];  // Encoded bytes.
+  size_t size;        // Encoded size, in bytes.
+  uint64_t value;     // Parsed value.
+};
+
+inline std::ostream& operator<<(std::ostream& os, const VarintCase& c) {
+  return os << c.value;
+}
+
+VarintCase kVarintCases[] = {
+    // 32-bit values
+    {{0x00}, 1, 0},
+    {{0x01}, 1, 1},
+    {{0x7f}, 1, 127},
+    {{0xa2, 0x74}, 2, (0x22 << 0) | (0x74 << 7)},  // 14882
+    {{0xbe, 0xf7, 0x92, 0x84, 0x0b},
+     5,  // 2961488830
+     (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+         (uint64_t{0x0bu} << 28)},
+
+    // 64-bit
+    {{0xbe, 0xf7, 0x92, 0x84, 0x1b},
+     5,  // 7256456126
+     (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+         (uint64_t{0x1bu} << 28)},
+    {{0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49},
+     8,  // 41256202580718336
+     (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+         (uint64_t{0x43u} << 28) | (uint64_t{0x49u} << 35) |
+         (uint64_t{0x24u} << 42) | (uint64_t{0x49u} << 49)},
+    // 11964378330978735131
+    {{0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01},
+     10,
+     (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+         (uint64_t{0x3bu} << 28) | (uint64_t{0x56u} << 35) |
+         (uint64_t{0x00u} << 42) | (uint64_t{0x05u} << 49) |
+         (uint64_t{0x26u} << 56) | (uint64_t{0x01u} << 63)},
+};
+
+TEST_2D(CodedStreamTest, ReadVarint32, kVarintCases, kBlockSizes) {
+  memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    uint32_t value;
+    EXPECT_TRUE(coded_input.ReadVarint32(&value));
+    EXPECT_EQ(static_cast<uint32_t>(kVarintCases_case.value), value);
+  }
+
+  EXPECT_EQ(kVarintCases_case.size, input.ByteCount());
+}
+
+TEST_2D(CodedStreamTest, ReadTag, kVarintCases, kBlockSizes) {
+  memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    uint32_t expected_value = static_cast<uint32_t>(kVarintCases_case.value);
+    EXPECT_EQ(expected_value, coded_input.ReadTag());
+
+    EXPECT_TRUE(coded_input.LastTagWas(expected_value));
+    EXPECT_FALSE(coded_input.LastTagWas(expected_value + 1));
+  }
+
+  EXPECT_EQ(kVarintCases_case.size, input.ByteCount());
+}
+
+// This is the regression test that verifies that there is no issues
+// with the empty input buffers handling.
+TEST_F(CodedStreamTest, EmptyInputBeforeEos) {
+  class In : public ZeroCopyInputStream {
+   public:
+    In() : count_(0) {}
+
+   private:
+    bool Next(const void** data, int* size) override {
+      *data = nullptr;
+      *size = 0;
+      return count_++ < 2;
+    }
+    void BackUp(int count) override { GOOGLE_LOG(FATAL) << "Tests never call this."; }
+    bool Skip(int count) override {
+      GOOGLE_LOG(FATAL) << "Tests never call this.";
+      return false;
+    }
+    int64_t ByteCount() const override { return 0; }
+    int count_;
+  } in;
+  CodedInputStream input(&in);
+  input.ReadTagNoLastTag();
+  EXPECT_TRUE(input.ConsumedEntireMessage());
+}
+
+TEST_1D(CodedStreamTest, ExpectTag, kVarintCases) {
+  // Leave one byte at the beginning of the buffer so we can read it
+  // to force the first buffer to be loaded.
+  buffer_[0] = '\0';
+  memcpy(buffer_ + 1, kVarintCases_case.bytes, kVarintCases_case.size);
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+
+  {
+    CodedInputStream coded_input(&input);
+
+    // Read one byte to force coded_input.Refill() to be called.  Otherwise,
+    // ExpectTag() will return a false negative.
+    uint8_t dummy;
+    coded_input.ReadRaw(&dummy, 1);
+    EXPECT_EQ((uint)'\0', (uint)dummy);
+
+    uint32_t expected_value = static_cast<uint32_t>(kVarintCases_case.value);
+
+    // ExpectTag() produces false negatives for large values.
+    if (kVarintCases_case.size <= 2) {
+      EXPECT_FALSE(coded_input.ExpectTag(expected_value + 1));
+      EXPECT_TRUE(coded_input.ExpectTag(expected_value));
+    } else {
+      EXPECT_FALSE(coded_input.ExpectTag(expected_value));
+    }
+  }
+
+  if (kVarintCases_case.size <= 2) {
+    EXPECT_EQ(kVarintCases_case.size + 1, input.ByteCount());
+  } else {
+    EXPECT_EQ(1, input.ByteCount());
+  }
+}
+
+TEST_1D(CodedStreamTest, ExpectTagFromArray, kVarintCases) {
+  memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
+
+  const uint32_t expected_value =
+      static_cast<uint32_t>(kVarintCases_case.value);
+
+  // If the expectation succeeds, it should return a pointer past the tag.
+  if (kVarintCases_case.size <= 2) {
+    EXPECT_TRUE(nullptr == CodedInputStream::ExpectTagFromArray(
+                            buffer_, expected_value + 1));
+    EXPECT_TRUE(buffer_ + kVarintCases_case.size ==
+                CodedInputStream::ExpectTagFromArray(buffer_, expected_value));
+  } else {
+    EXPECT_TRUE(nullptr ==
+                CodedInputStream::ExpectTagFromArray(buffer_, expected_value));
+  }
+}
+
+TEST_2D(CodedStreamTest, ReadVarint64, kVarintCases, kBlockSizes) {
+  memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    uint64_t value;
+    EXPECT_TRUE(coded_input.ReadVarint64(&value));
+    EXPECT_EQ(kVarintCases_case.value, value);
+  }
+
+  EXPECT_EQ(kVarintCases_case.size, input.ByteCount());
+}
+
+TEST_2D(CodedStreamTest, WriteVarint32, kVarintCases, kBlockSizes) {
+  if (kVarintCases_case.value > uint64_t{0x00000000FFFFFFFFu}) {
+    // Skip this test for the 64-bit values.
+    return;
+  }
+
+  ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedOutputStream coded_output(&output);
+
+    coded_output.WriteVarint32(static_cast<uint32_t>(kVarintCases_case.value));
+    EXPECT_FALSE(coded_output.HadError());
+
+    EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount());
+  }
+
+  EXPECT_EQ(kVarintCases_case.size, output.ByteCount());
+  EXPECT_EQ(0,
+            memcmp(buffer_, kVarintCases_case.bytes, kVarintCases_case.size));
+}
+
+TEST_2D(CodedStreamTest, WriteVarint64, kVarintCases, kBlockSizes) {
+  ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedOutputStream coded_output(&output);
+
+    coded_output.WriteVarint64(kVarintCases_case.value);
+    EXPECT_FALSE(coded_output.HadError());
+
+    EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount());
+  }
+
+  EXPECT_EQ(kVarintCases_case.size, output.ByteCount());
+  EXPECT_EQ(0,
+            memcmp(buffer_, kVarintCases_case.bytes, kVarintCases_case.size));
+}
+
+// This test causes gcc 3.3.5 (and earlier?) to give the cryptic error:
+//   "sorry, unimplemented: `method_call_expr' not supported by dump_expr"
+#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
+
+int32_t kSignExtendedVarintCases[] = {0, 1, -1, 1237894, -37895138};
+
+TEST_2D(CodedStreamTest, WriteVarint32SignExtended, kSignExtendedVarintCases,
+        kBlockSizes) {
+  ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedOutputStream coded_output(&output);
+
+    coded_output.WriteVarint32SignExtended(kSignExtendedVarintCases_case);
+    EXPECT_FALSE(coded_output.HadError());
+
+    if (kSignExtendedVarintCases_case < 0) {
+      EXPECT_EQ(10, coded_output.ByteCount());
+    } else {
+      EXPECT_LE(coded_output.ByteCount(), 5);
+    }
+  }
+
+  if (kSignExtendedVarintCases_case < 0) {
+    EXPECT_EQ(10, output.ByteCount());
+  } else {
+    EXPECT_LE(output.ByteCount(), 5);
+  }
+
+  // Read value back in as a varint64 and insure it matches.
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+
+  {
+    CodedInputStream coded_input(&input);
+
+    uint64_t value;
+    EXPECT_TRUE(coded_input.ReadVarint64(&value));
+
+    EXPECT_EQ(kSignExtendedVarintCases_case, static_cast<int64_t>(value));
+  }
+
+  EXPECT_EQ(output.ByteCount(), input.ByteCount());
+}
+
+#endif
+
+
+// -------------------------------------------------------------------
+// Varint failure test.
+
+struct VarintErrorCase {
+  uint8_t bytes[12];
+  size_t size;
+  bool can_parse;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const VarintErrorCase& c) {
+  return os << "size " << c.size;
+}
+
+const VarintErrorCase kVarintErrorCases[] = {
+    // Control case.  (Insures that there isn't something else wrong that
+    // makes parsing always fail.)
+    {{0x00}, 1, true},
+
+    // No input data.
+    {{}, 0, false},
+
+    // Input ends unexpectedly.
+    {{0xf0, 0xab}, 2, false},
+
+    // Input ends unexpectedly after 32 bits.
+    {{0xf0, 0xab, 0xc9, 0x9a, 0xf8, 0xb2}, 6, false},
+
+    // Longer than 10 bytes.
+    {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01},
+     11,
+     false},
+};
+
+TEST_2D(CodedStreamTest, ReadVarint32Error, kVarintErrorCases, kBlockSizes) {
+  memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
+  ArrayInputStream input(buffer_, static_cast<int>(kVarintErrorCases_case.size),
+                         kBlockSizes_case);
+  CodedInputStream coded_input(&input);
+
+  uint32_t value;
+  EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint32(&value));
+}
+
+TEST_2D(CodedStreamTest, ReadVarint32Error_LeavesValueInInitializedState,
+        kVarintErrorCases, kBlockSizes) {
+  memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
+  ArrayInputStream input(buffer_, static_cast<int>(kVarintErrorCases_case.size),
+                         kBlockSizes_case);
+  CodedInputStream coded_input(&input);
+
+  uint32_t value = 0;
+  EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint32(&value));
+  // While the specific value following a failure is not critical, we do want to
+  // ensure that it doesn't get set to an uninitialized value. (This check fails
+  // in MSAN mode if value has been set to an uninitialized value.)
+  EXPECT_EQ(value, value);
+}
+
+TEST_2D(CodedStreamTest, ReadVarint64Error, kVarintErrorCases, kBlockSizes) {
+  memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
+  ArrayInputStream input(buffer_, static_cast<int>(kVarintErrorCases_case.size),
+                         kBlockSizes_case);
+  CodedInputStream coded_input(&input);
+
+  uint64_t value;
+  EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint64(&value));
+}
+
+TEST_2D(CodedStreamTest, ReadVarint64Error_LeavesValueInInitializedState,
+        kVarintErrorCases, kBlockSizes) {
+  memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
+  ArrayInputStream input(buffer_, static_cast<int>(kVarintErrorCases_case.size),
+                         kBlockSizes_case);
+  CodedInputStream coded_input(&input);
+
+  uint64_t value = 0;
+  EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint64(&value));
+  // While the specific value following a failure is not critical, we do want to
+  // ensure that it doesn't get set to an uninitialized value. (This check fails
+  // in MSAN mode if value has been set to an uninitialized value.)
+  EXPECT_EQ(value, value);
+}
+
+// -------------------------------------------------------------------
+// VarintSize
+
+struct VarintSizeCase {
+  uint64_t value;
+  int size;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const VarintSizeCase& c) {
+  return os << c.value;
+}
+
+VarintSizeCase kVarintSizeCases[] = {
+    {0u, 1},
+    {1u, 1},
+    {127u, 1},
+    {128u, 2},
+    {758923u, 3},
+    {4000000000u, 5},
+    {uint64_t{41256202580718336u}, 8},
+    {uint64_t{11964378330978735131u}, 10},
+};
+
+TEST_1D(CodedStreamTest, VarintSize32, kVarintSizeCases) {
+  if (kVarintSizeCases_case.value > 0xffffffffu) {
+    // Skip 64-bit values.
+    return;
+  }
+
+  EXPECT_EQ(kVarintSizeCases_case.size,
+            CodedOutputStream::VarintSize32(
+                static_cast<uint32_t>(kVarintSizeCases_case.value)));
+}
+
+TEST_1D(CodedStreamTest, VarintSize64, kVarintSizeCases) {
+  EXPECT_EQ(kVarintSizeCases_case.size,
+            CodedOutputStream::VarintSize64(kVarintSizeCases_case.value));
+}
+
+TEST_F(CodedStreamTest, VarintSize32PowersOfTwo) {
+  int expected = 1;
+  for (int i = 1; i < 32; i++) {
+    if (i % 7 == 0) {
+      expected += 1;
+    }
+    EXPECT_EQ(expected, CodedOutputStream::VarintSize32(
+                            static_cast<uint32_t>(0x1u << i)));
+  }
+}
+
+TEST_F(CodedStreamTest, VarintSize64PowersOfTwo) {
+  int expected = 1;
+  for (int i = 1; i < 64; i++) {
+    if (i % 7 == 0) {
+      expected += 1;
+    }
+    EXPECT_EQ(expected, CodedOutputStream::VarintSize64(uint64_t{1} << i));
+  }
+}
+
+// -------------------------------------------------------------------
+// Fixed-size int tests
+
+struct Fixed32Case {
+  uint8_t bytes[sizeof(uint32_t)];  // Encoded bytes.
+  uint32_t value;                   // Parsed value.
+};
+
+struct Fixed64Case {
+  uint8_t bytes[sizeof(uint64_t)];  // Encoded bytes.
+  uint64_t value;                   // Parsed value.
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
+  return os << "0x" << std::hex << c.value << std::dec;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
+  return os << "0x" << std::hex << c.value << std::dec;
+}
+
+Fixed32Case kFixed32Cases[] = {
+    {{0xef, 0xcd, 0xab, 0x90}, 0x90abcdefu},
+    {{0x12, 0x34, 0x56, 0x78}, 0x78563412u},
+};
+
+Fixed64Case kFixed64Cases[] = {
+    {{0xef, 0xcd, 0xab, 0x90, 0x12, 0x34, 0x56, 0x78},
+     uint64_t{0x7856341290abcdefu}},
+    {{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88},
+     uint64_t{0x8877665544332211u}},
+};
+
+TEST_2D(CodedStreamTest, ReadLittleEndian32, kFixed32Cases, kBlockSizes) {
+  memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    uint32_t value;
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(kFixed32Cases_case.value, value);
+  }
+
+  EXPECT_EQ(sizeof(uint32_t), input.ByteCount());
+}
+
+TEST_2D(CodedStreamTest, ReadLittleEndian64, kFixed64Cases, kBlockSizes) {
+  memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    uint64_t value;
+    EXPECT_TRUE(coded_input.ReadLittleEndian64(&value));
+    EXPECT_EQ(kFixed64Cases_case.value, value);
+  }
+
+  EXPECT_EQ(sizeof(uint64_t), input.ByteCount());
+}
+
+TEST_2D(CodedStreamTest, WriteLittleEndian32, kFixed32Cases, kBlockSizes) {
+  ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedOutputStream coded_output(&output);
+
+    coded_output.WriteLittleEndian32(kFixed32Cases_case.value);
+    EXPECT_FALSE(coded_output.HadError());
+
+    EXPECT_EQ(sizeof(uint32_t), coded_output.ByteCount());
+  }
+
+  EXPECT_EQ(sizeof(uint32_t), output.ByteCount());
+  EXPECT_EQ(0, memcmp(buffer_, kFixed32Cases_case.bytes, sizeof(uint32_t)));
+}
+
+TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) {
+  ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedOutputStream coded_output(&output);
+
+    coded_output.WriteLittleEndian64(kFixed64Cases_case.value);
+    EXPECT_FALSE(coded_output.HadError());
+
+    EXPECT_EQ(sizeof(uint64_t), coded_output.ByteCount());
+  }
+
+  EXPECT_EQ(sizeof(uint64_t), output.ByteCount());
+  EXPECT_EQ(0, memcmp(buffer_, kFixed64Cases_case.bytes, sizeof(uint64_t)));
+}
+
+// Tests using the static methods to read fixed-size values from raw arrays.
+
+TEST_1D(CodedStreamTest, ReadLittleEndian32FromArray, kFixed32Cases) {
+  memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes));
+
+  uint32_t value;
+  const uint8_t* end =
+      CodedInputStream::ReadLittleEndian32FromArray(buffer_, &value);
+  EXPECT_EQ(kFixed32Cases_case.value, value);
+  EXPECT_TRUE(end == buffer_ + sizeof(value));
+}
+
+TEST_1D(CodedStreamTest, ReadLittleEndian64FromArray, kFixed64Cases) {
+  memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes));
+
+  uint64_t value;
+  const uint8_t* end =
+      CodedInputStream::ReadLittleEndian64FromArray(buffer_, &value);
+  EXPECT_EQ(kFixed64Cases_case.value, value);
+  EXPECT_TRUE(end == buffer_ + sizeof(value));
+}
+
+// -------------------------------------------------------------------
+// Raw reads and writes
+
+const char kRawBytes[] = "Some bytes which will be written and read raw.";
+
+TEST_1D(CodedStreamTest, ReadRaw, kBlockSizes) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+  char read_buffer[sizeof(kRawBytes)];
+
+  {
+    CodedInputStream coded_input(&input);
+
+    EXPECT_TRUE(coded_input.ReadRaw(read_buffer, sizeof(kRawBytes)));
+    EXPECT_EQ(0, memcmp(kRawBytes, read_buffer, sizeof(kRawBytes)));
+  }
+
+  EXPECT_EQ(sizeof(kRawBytes), input.ByteCount());
+}
+
+TEST_1D(CodedStreamTest, WriteRaw, kBlockSizes) {
+  ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedOutputStream coded_output(&output);
+
+    coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes));
+    EXPECT_FALSE(coded_output.HadError());
+
+    EXPECT_EQ(sizeof(kRawBytes), coded_output.ByteCount());
+  }
+
+  EXPECT_EQ(sizeof(kRawBytes), output.ByteCount());
+  EXPECT_EQ(0, memcmp(buffer_, kRawBytes, sizeof(kRawBytes)));
+}
+
+TEST_1D(CodedStreamTest, ReadString, kBlockSizes) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    std::string str;
+    EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    EXPECT_EQ(kRawBytes, str);
+  }
+
+  EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+// Check to make sure ReadString doesn't crash on impossibly large strings.
+TEST_1D(CodedStreamTest, ReadStringImpossiblyLarge, kBlockSizes) {
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    std::string str;
+    // Try to read a gigabyte.
+    EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
+  }
+}
+
+TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) {
+  // Same test as above, except directly use a buffer. This used to cause
+  // crashes while the above did not.
+  uint8_t buffer[8];
+  CodedInputStream coded_input(buffer, 8);
+  std::string str;
+  EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
+}
+
+TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
+  std::unique_ptr<uint8_t[]> buffer(new uint8_t[8]);
+  CodedInputStream coded_input(buffer.get(), 8);
+  std::string str;
+  EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
+}
+
+TEST_1D(CodedStreamTest, ReadStringReservesMemoryOnTotalLimit, kBlockSizes) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.SetTotalBytesLimit(sizeof(kRawBytes));
+    EXPECT_EQ(sizeof(kRawBytes), coded_input.BytesUntilTotalBytesLimit());
+
+    std::string str;
+    EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    EXPECT_EQ(sizeof(kRawBytes) - strlen(kRawBytes),
+              coded_input.BytesUntilTotalBytesLimit());
+    EXPECT_EQ(kRawBytes, str);
+    // TODO(liujisi): Replace with a more meaningful test (see cl/60966023).
+    EXPECT_GE(str.capacity(), strlen(kRawBytes));
+  }
+
+  EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+TEST_1D(CodedStreamTest, ReadStringReservesMemoryOnPushedLimit, kBlockSizes) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.PushLimit(sizeof(buffer_));
+
+    std::string str;
+    EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    EXPECT_EQ(kRawBytes, str);
+    // TODO(liujisi): Replace with a more meaningful test (see cl/60966023).
+    EXPECT_GE(str.capacity(), strlen(kRawBytes));
+  }
+
+  EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationIfLimitsNotSet) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    std::string str;
+    EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    EXPECT_EQ(kRawBytes, str);
+    // Note: this check depends on string class implementation. It
+    // expects that string will allocate more than strlen(kRawBytes)
+    // if the content of kRawBytes is appended to string in small
+    // chunks.
+    // TODO(liujisi): Replace with a more meaningful test (see cl/60966023).
+    EXPECT_GE(str.capacity(), strlen(kRawBytes));
+  }
+
+  EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsNegative) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.PushLimit(sizeof(buffer_));
+
+    std::string str;
+    EXPECT_FALSE(coded_input.ReadString(&str, -1));
+    // Note: this check depends on string class implementation. It
+    // expects that string will always allocate the same amount of
+    // memory for an empty string.
+    EXPECT_EQ(std::string().capacity(), str.capacity());
+  }
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsLarge) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.PushLimit(sizeof(buffer_));
+
+    std::string str;
+    EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
+    EXPECT_GT(1 << 30, str.capacity());
+  }
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsOverTheLimit) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.PushLimit(16);
+
+    std::string str;
+    EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    // Note: this check depends on string class implementation. It
+    // expects that string will allocate less than strlen(kRawBytes)
+    // for an empty string.
+    EXPECT_GT(strlen(kRawBytes), str.capacity());
+  }
+}
+
+TEST_F(CodedStreamTest, ReadStringNoReservationSizeIsOverTheTotalBytesLimit) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.SetTotalBytesLimit(16);
+
+    std::string str;
+    EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    // Note: this check depends on string class implementation. It
+    // expects that string will allocate less than strlen(kRawBytes)
+    // for an empty string.
+    EXPECT_GT(strlen(kRawBytes), str.capacity());
+  }
+}
+
+TEST_F(CodedStreamTest,
+       ReadStringNoReservationSizeIsOverTheClosestLimit_GlobalLimitIsCloser) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.PushLimit(sizeof(buffer_));
+    coded_input.SetTotalBytesLimit(16);
+
+    std::string str;
+    EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    // Note: this check depends on string class implementation. It
+    // expects that string will allocate less than strlen(kRawBytes)
+    // for an empty string.
+    EXPECT_GT(strlen(kRawBytes), str.capacity());
+  }
+}
+
+TEST_F(CodedStreamTest,
+       ReadStringNoReservationSizeIsOverTheClosestLimit_LocalLimitIsCloser) {
+  memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
+  // Buffer size in the input must be smaller than sizeof(kRawBytes),
+  // otherwise check against capacity will fail as ReadStringInline()
+  // will handle the reading and will reserve the memory as needed.
+  ArrayInputStream input(buffer_, sizeof(buffer_), 32);
+
+  {
+    CodedInputStream coded_input(&input);
+    coded_input.PushLimit(16);
+    coded_input.SetTotalBytesLimit(sizeof(buffer_));
+    EXPECT_EQ(sizeof(buffer_), coded_input.BytesUntilTotalBytesLimit());
+
+    std::string str;
+    EXPECT_FALSE(coded_input.ReadString(&str, strlen(kRawBytes)));
+    // Note: this check depends on string class implementation. It
+    // expects that string will allocate less than strlen(kRawBytes)
+    // for an empty string.
+    EXPECT_GT(strlen(kRawBytes), str.capacity());
+  }
+}
+
+
+// -------------------------------------------------------------------
+// Skip
+
+const char kSkipTestBytes[] =
+    "<Before skipping><To be skipped><After skipping>";
+
+TEST_1D(CodedStreamTest, SkipInput, kBlockSizes) {
+  memcpy(buffer_, kSkipTestBytes, sizeof(kSkipTestBytes));
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    std::string str;
+    EXPECT_TRUE(coded_input.ReadString(&str, strlen("<Before skipping>")));
+    EXPECT_EQ("<Before skipping>", str);
+    EXPECT_TRUE(coded_input.Skip(strlen("<To be skipped>")));
+    EXPECT_TRUE(coded_input.ReadString(&str, strlen("<After skipping>")));
+    EXPECT_EQ("<After skipping>", str);
+  }
+
+  EXPECT_EQ(strlen(kSkipTestBytes), input.ByteCount());
+}
+
+// -------------------------------------------------------------------
+// GetDirectBufferPointer
+
+TEST_F(CodedStreamTest, GetDirectBufferPointerInput) {
+  ArrayInputStream input(buffer_, sizeof(buffer_), 8);
+  CodedInputStream coded_input(&input);
+
+  const void* ptr;
+  int size;
+
+  EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+  EXPECT_EQ(buffer_, ptr);
+  EXPECT_EQ(8, size);
+
+  // Peeking again should return the same pointer.
+  EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+  EXPECT_EQ(buffer_, ptr);
+  EXPECT_EQ(8, size);
+
+  // Skip forward in the same buffer then peek again.
+  EXPECT_TRUE(coded_input.Skip(3));
+  EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+  EXPECT_EQ(buffer_ + 3, ptr);
+  EXPECT_EQ(5, size);
+
+  // Skip to end of buffer and peek -- should get next buffer.
+  EXPECT_TRUE(coded_input.Skip(5));
+  EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+  EXPECT_EQ(buffer_ + 8, ptr);
+  EXPECT_EQ(8, size);
+}
+
+TEST_F(CodedStreamTest, GetDirectBufferPointerInlineInput) {
+  ArrayInputStream input(buffer_, sizeof(buffer_), 8);
+  CodedInputStream coded_input(&input);
+
+  const void* ptr;
+  int size;
+
+  coded_input.GetDirectBufferPointerInline(&ptr, &size);
+  EXPECT_EQ(buffer_, ptr);
+  EXPECT_EQ(8, size);
+
+  // Peeking again should return the same pointer.
+  coded_input.GetDirectBufferPointerInline(&ptr, &size);
+  EXPECT_EQ(buffer_, ptr);
+  EXPECT_EQ(8, size);
+
+  // Skip forward in the same buffer then peek again.
+  EXPECT_TRUE(coded_input.Skip(3));
+  coded_input.GetDirectBufferPointerInline(&ptr, &size);
+  EXPECT_EQ(buffer_ + 3, ptr);
+  EXPECT_EQ(5, size);
+
+  // Skip to end of buffer and peek -- should return false and provide an empty
+  // buffer. It does not try to Refresh().
+  EXPECT_TRUE(coded_input.Skip(5));
+  coded_input.GetDirectBufferPointerInline(&ptr, &size);
+  EXPECT_EQ(buffer_ + 8, ptr);
+  EXPECT_EQ(0, size);
+}
+
+// -------------------------------------------------------------------
+// Limits
+
+TEST_1D(CodedStreamTest, BasicLimit, kBlockSizes) {
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+    CodedInputStream::Limit limit = coded_input.PushLimit(8);
+
+    // Read until we hit the limit.
+    uint32_t value;
+    EXPECT_EQ(8, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(4, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+    EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+
+    coded_input.PopLimit(limit);
+
+    EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+  }
+
+  EXPECT_EQ(12, input.ByteCount());
+}
+
+// Test what happens when we push two limits where the second (top) one is
+// shorter.
+TEST_1D(CodedStreamTest, SmallLimitOnTopOfBigLimit, kBlockSizes) {
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+    CodedInputStream::Limit limit1 = coded_input.PushLimit(8);
+    EXPECT_EQ(8, coded_input.BytesUntilLimit());
+    CodedInputStream::Limit limit2 = coded_input.PushLimit(4);
+
+    uint32_t value;
+
+    // Read until we hit limit2, the top and shortest limit.
+    EXPECT_EQ(4, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+    EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+
+    coded_input.PopLimit(limit2);
+
+    // Read until we hit limit1.
+    EXPECT_EQ(4, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+    EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+
+    coded_input.PopLimit(limit1);
+
+    // No more limits.
+    EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+  }
+
+  EXPECT_EQ(12, input.ByteCount());
+}
+
+// Test what happens when we push two limits where the second (top) one is
+// longer.  In this case, the top limit is shortened to match the previous
+// limit.
+TEST_1D(CodedStreamTest, BigLimitOnTopOfSmallLimit, kBlockSizes) {
+  ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
+
+  {
+    CodedInputStream coded_input(&input);
+
+    EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+    CodedInputStream::Limit limit1 = coded_input.PushLimit(4);
+    EXPECT_EQ(4, coded_input.BytesUntilLimit());
+    CodedInputStream::Limit limit2 = coded_input.PushLimit(8);
+
+    uint32_t value;
+
+    // Read until we hit limit2.  Except, wait!  limit1 is shorter, so
+    // we end up hitting that first, despite having 4 bytes to go on
+    // limit2.
+    EXPECT_EQ(4, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+    EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+
+    coded_input.PopLimit(limit2);
+
+    // OK, popped limit2, now limit1 is on top, which we've already hit.
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+    EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
+    EXPECT_EQ(0, coded_input.BytesUntilLimit());
+
+    coded_input.PopLimit(limit1);
+
+    // No more limits.
+    EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+    EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+  }
+
+  EXPECT_EQ(8, input.ByteCount());
+}
+
+TEST_F(CodedStreamTest, ExpectAtEnd) {
+  // Test ExpectAtEnd(), which is based on limits.
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+
+  EXPECT_FALSE(coded_input.ExpectAtEnd());
+
+  CodedInputStream::Limit limit = coded_input.PushLimit(4);
+
+  uint32_t value;
+  EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
+  EXPECT_TRUE(coded_input.ExpectAtEnd());
+
+  coded_input.PopLimit(limit);
+  EXPECT_FALSE(coded_input.ExpectAtEnd());
+}
+
+TEST_F(CodedStreamTest, NegativeLimit) {
+  // Check what happens when we push a negative limit.
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+
+  CodedInputStream::Limit limit = coded_input.PushLimit(-1234);
+  // BytesUntilLimit() returns -1 to mean "no limit", which actually means
+  // "the limit is INT_MAX relative to the beginning of the stream".
+  EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+  coded_input.PopLimit(limit);
+}
+
+TEST_F(CodedStreamTest, NegativeLimitAfterReading) {
+  // Check what happens when we push a negative limit.
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+  ASSERT_TRUE(coded_input.Skip(128));
+
+  CodedInputStream::Limit limit = coded_input.PushLimit(-64);
+  // BytesUntilLimit() returns -1 to mean "no limit", which actually means
+  // "the limit is INT_MAX relative to the beginning of the stream".
+  EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+  coded_input.PopLimit(limit);
+}
+
+TEST_F(CodedStreamTest, OverflowLimit) {
+  // Check what happens when we push a limit large enough that its absolute
+  // position is more than 2GB into the stream.
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+  ASSERT_TRUE(coded_input.Skip(128));
+
+  CodedInputStream::Limit limit = coded_input.PushLimit(INT_MAX);
+  // BytesUntilLimit() returns -1 to mean "no limit", which actually means
+  // "the limit is INT_MAX relative to the beginning of the stream".
+  EXPECT_EQ(-1, coded_input.BytesUntilLimit());
+  coded_input.PopLimit(limit);
+}
+
+TEST_F(CodedStreamTest, TotalBytesLimit) {
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+  coded_input.SetTotalBytesLimit(16);
+  EXPECT_EQ(16, coded_input.BytesUntilTotalBytesLimit());
+
+  std::string str;
+  EXPECT_TRUE(coded_input.ReadString(&str, 16));
+  EXPECT_EQ(0, coded_input.BytesUntilTotalBytesLimit());
+
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog error_log;
+    EXPECT_FALSE(coded_input.ReadString(&str, 1));
+    errors = error_log.GetMessages(ERROR);
+  }
+
+  ASSERT_EQ(1, errors.size());
+  EXPECT_PRED_FORMAT2(testing::IsSubstring,
+                      "A protocol message was rejected because it was too big",
+                      errors[0]);
+
+  coded_input.SetTotalBytesLimit(32);
+  EXPECT_EQ(16, coded_input.BytesUntilTotalBytesLimit());
+  EXPECT_TRUE(coded_input.ReadString(&str, 16));
+  EXPECT_EQ(0, coded_input.BytesUntilTotalBytesLimit());
+}
+
+TEST_F(CodedStreamTest, TotalBytesLimitNotValidMessageEnd) {
+  // total_bytes_limit_ is not a valid place for a message to end.
+
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+
+  // Set both total_bytes_limit and a regular limit at 16 bytes.
+  coded_input.SetTotalBytesLimit(16);
+  CodedInputStream::Limit limit = coded_input.PushLimit(16);
+
+  // Read 16 bytes.
+  std::string str;
+  EXPECT_TRUE(coded_input.ReadString(&str, 16));
+
+  // Read a tag.  Should fail, but report being a valid endpoint since it's
+  // a regular limit.
+  EXPECT_EQ(0, coded_input.ReadTagNoLastTag());
+  EXPECT_TRUE(coded_input.ConsumedEntireMessage());
+
+  // Pop the limit.
+  coded_input.PopLimit(limit);
+
+  // Read a tag.  Should fail, and report *not* being a valid endpoint, since
+  // this time we're hitting the total bytes limit.
+  EXPECT_EQ(0, coded_input.ReadTagNoLastTag());
+  EXPECT_FALSE(coded_input.ConsumedEntireMessage());
+}
+
+TEST_F(CodedStreamTest, RecursionLimit) {
+  ArrayInputStream input(buffer_, sizeof(buffer_));
+  CodedInputStream coded_input(&input);
+  coded_input.SetRecursionLimit(4);
+
+  // This is way too much testing for a counter.
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 1
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 2
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 3
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 4
+  EXPECT_FALSE(coded_input.IncrementRecursionDepth());  // 5
+  EXPECT_FALSE(coded_input.IncrementRecursionDepth());  // 6
+  coded_input.DecrementRecursionDepth();                // 5
+  EXPECT_FALSE(coded_input.IncrementRecursionDepth());  // 6
+  coded_input.DecrementRecursionDepth();                // 5
+  coded_input.DecrementRecursionDepth();                // 4
+  coded_input.DecrementRecursionDepth();                // 3
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 4
+  EXPECT_FALSE(coded_input.IncrementRecursionDepth());  // 5
+  coded_input.DecrementRecursionDepth();                // 4
+  coded_input.DecrementRecursionDepth();                // 3
+  coded_input.DecrementRecursionDepth();                // 2
+  coded_input.DecrementRecursionDepth();                // 1
+  coded_input.DecrementRecursionDepth();                // 0
+  coded_input.DecrementRecursionDepth();                // 0
+  coded_input.DecrementRecursionDepth();                // 0
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 1
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 2
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 3
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 4
+  EXPECT_FALSE(coded_input.IncrementRecursionDepth());  // 5
+
+  coded_input.SetRecursionLimit(6);
+  EXPECT_TRUE(coded_input.IncrementRecursionDepth());   // 6
+  EXPECT_FALSE(coded_input.IncrementRecursionDepth());  // 7
+}
+
+
+class ReallyBigInputStream : public ZeroCopyInputStream {
+ public:
+  ReallyBigInputStream() : backup_amount_(0), buffer_count_(0) {}
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override {
+    // We only expect BackUp() to be called at the end.
+    EXPECT_EQ(0, backup_amount_);
+
+    switch (buffer_count_++) {
+      case 0:
+        *data = buffer_;
+        *size = sizeof(buffer_);
+        return true;
+      case 1:
+        // Return an enormously large buffer that, when combined with the 1k
+        // returned already, should overflow the total_bytes_read_ counter in
+        // CodedInputStream.  Note that we'll only read the first 1024 bytes
+        // of this buffer so it's OK that we have it point at buffer_.
+        *data = buffer_;
+        *size = INT_MAX;
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  void BackUp(int count) override { backup_amount_ = count; }
+
+  bool Skip(int count) override {
+    GOOGLE_LOG(FATAL) << "Not implemented.";
+    return false;
+  }
+  int64_t ByteCount() const override {
+    GOOGLE_LOG(FATAL) << "Not implemented.";
+    return 0;
+  }
+
+  int backup_amount_;
+
+ private:
+  char buffer_[1024];
+  int64_t buffer_count_;
+};
+
+TEST_F(CodedStreamTest, InputOver2G) {
+  // CodedInputStream should gracefully handle input over 2G and call
+  // input.BackUp() with the correct number of bytes on destruction.
+  ReallyBigInputStream input;
+
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog error_log;
+    CodedInputStream coded_input(&input);
+    std::string str;
+    EXPECT_TRUE(coded_input.ReadString(&str, 512));
+    EXPECT_TRUE(coded_input.ReadString(&str, 1024));
+    errors = error_log.GetMessages(ERROR);
+  }
+
+  EXPECT_EQ(INT_MAX - 512, input.backup_amount_);
+  EXPECT_EQ(0, errors.size());
+}
+
+}  // namespace
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
new file mode 100644
index 0000000..a5284b3
--- /dev/null
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -0,0 +1,334 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: brianolson@google.com (Brian Olson)
+//
+// This file contains the implementation of classes GzipInputStream and
+// GzipOutputStream.
+
+
+#if HAVE_ZLIB
+#include <google/protobuf/io/gzip_stream.h>
+#include <google/protobuf/port.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+static const int kDefaultBufferSize = 65536;
+
+GzipInputStream::GzipInputStream(ZeroCopyInputStream* sub_stream, Format format,
+                                 int buffer_size)
+    : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
+  zcontext_.state = Z_NULL;
+  zcontext_.zalloc = Z_NULL;
+  zcontext_.zfree = Z_NULL;
+  zcontext_.opaque = Z_NULL;
+  zcontext_.total_out = 0;
+  zcontext_.next_in = NULL;
+  zcontext_.avail_in = 0;
+  zcontext_.total_in = 0;
+  zcontext_.msg = NULL;
+  if (buffer_size == -1) {
+    output_buffer_length_ = kDefaultBufferSize;
+  } else {
+    output_buffer_length_ = buffer_size;
+  }
+  output_buffer_ = operator new(output_buffer_length_);
+  GOOGLE_CHECK(output_buffer_ != NULL);
+  zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
+  zcontext_.avail_out = output_buffer_length_;
+  output_position_ = output_buffer_;
+}
+GzipInputStream::~GzipInputStream() {
+  internal::SizedDelete(output_buffer_, output_buffer_length_);
+  zerror_ = inflateEnd(&zcontext_);
+}
+
+static inline int internalInflateInit2(z_stream* zcontext,
+                                       GzipInputStream::Format format) {
+  int windowBitsFormat = 0;
+  switch (format) {
+    case GzipInputStream::GZIP:
+      windowBitsFormat = 16;
+      break;
+    case GzipInputStream::AUTO:
+      windowBitsFormat = 32;
+      break;
+    case GzipInputStream::ZLIB:
+      windowBitsFormat = 0;
+      break;
+  }
+  return inflateInit2(zcontext, /* windowBits */ 15 | windowBitsFormat);
+}
+
+int GzipInputStream::Inflate(int flush) {
+  if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
+    // previous inflate filled output buffer. don't change input params yet.
+  } else if (zcontext_.avail_in == 0) {
+    const void* in;
+    int in_size;
+    bool first = zcontext_.next_in == NULL;
+    bool ok = sub_stream_->Next(&in, &in_size);
+    if (!ok) {
+      zcontext_.next_out = NULL;
+      zcontext_.avail_out = 0;
+      return Z_STREAM_END;
+    }
+    zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
+    zcontext_.avail_in = in_size;
+    if (first) {
+      int error = internalInflateInit2(&zcontext_, format_);
+      if (error != Z_OK) {
+        return error;
+      }
+    }
+  }
+  zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
+  zcontext_.avail_out = output_buffer_length_;
+  output_position_ = output_buffer_;
+  int error = inflate(&zcontext_, flush);
+  return error;
+}
+
+void GzipInputStream::DoNextOutput(const void** data, int* size) {
+  *data = output_position_;
+  *size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
+  output_position_ = zcontext_.next_out;
+}
+
+// implements ZeroCopyInputStream ----------------------------------
+bool GzipInputStream::Next(const void** data, int* size) {
+  bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) ||
+            (zerror_ == Z_BUF_ERROR);
+  if ((!ok) || (zcontext_.next_out == NULL)) {
+    return false;
+  }
+  if (zcontext_.next_out != output_position_) {
+    DoNextOutput(data, size);
+    return true;
+  }
+  if (zerror_ == Z_STREAM_END) {
+    if (zcontext_.next_out != NULL) {
+      // sub_stream_ may have concatenated streams to follow
+      zerror_ = inflateEnd(&zcontext_);
+      byte_count_ += zcontext_.total_out;
+      if (zerror_ != Z_OK) {
+        return false;
+      }
+      zerror_ = internalInflateInit2(&zcontext_, format_);
+      if (zerror_ != Z_OK) {
+        return false;
+      }
+    } else {
+      *data = NULL;
+      *size = 0;
+      return false;
+    }
+  }
+  zerror_ = Inflate(Z_NO_FLUSH);
+  if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
+    // The underlying stream's Next returned false inside Inflate.
+    return false;
+  }
+  ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) ||
+       (zerror_ == Z_BUF_ERROR);
+  if (!ok) {
+    return false;
+  }
+  DoNextOutput(data, size);
+  return true;
+}
+void GzipInputStream::BackUp(int count) {
+  output_position_ = reinterpret_cast<void*>(
+      reinterpret_cast<uintptr_t>(output_position_) - count);
+}
+bool GzipInputStream::Skip(int count) {
+  const void* data;
+  int size = 0;
+  bool ok = Next(&data, &size);
+  while (ok && (size < count)) {
+    count -= size;
+    ok = Next(&data, &size);
+  }
+  if (size > count) {
+    BackUp(size - count);
+  }
+  return ok;
+}
+int64_t GzipInputStream::ByteCount() const {
+  int64_t ret = byte_count_ + zcontext_.total_out;
+  if (zcontext_.next_out != NULL && output_position_ != NULL) {
+    ret += reinterpret_cast<uintptr_t>(zcontext_.next_out) -
+           reinterpret_cast<uintptr_t>(output_position_);
+  }
+  return ret;
+}
+
+// =========================================================================
+
+GzipOutputStream::Options::Options()
+    : format(GZIP),
+      buffer_size(kDefaultBufferSize),
+      compression_level(Z_DEFAULT_COMPRESSION),
+      compression_strategy(Z_DEFAULT_STRATEGY) {}
+
+GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
+  Init(sub_stream, Options());
+}
+
+GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
+                                   const Options& options) {
+  Init(sub_stream, options);
+}
+
+void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
+                            const Options& options) {
+  sub_stream_ = sub_stream;
+  sub_data_ = NULL;
+  sub_data_size_ = 0;
+
+  input_buffer_length_ = options.buffer_size;
+  input_buffer_ = operator new(input_buffer_length_);
+  GOOGLE_CHECK(input_buffer_ != NULL);
+
+  zcontext_.zalloc = Z_NULL;
+  zcontext_.zfree = Z_NULL;
+  zcontext_.opaque = Z_NULL;
+  zcontext_.next_out = NULL;
+  zcontext_.avail_out = 0;
+  zcontext_.total_out = 0;
+  zcontext_.next_in = NULL;
+  zcontext_.avail_in = 0;
+  zcontext_.total_in = 0;
+  zcontext_.msg = NULL;
+  // default to GZIP format
+  int windowBitsFormat = 16;
+  if (options.format == ZLIB) {
+    windowBitsFormat = 0;
+  }
+  zerror_ =
+      deflateInit2(&zcontext_, options.compression_level, Z_DEFLATED,
+                   /* windowBits */ 15 | windowBitsFormat,
+                   /* memLevel (default) */ 8, options.compression_strategy);
+}
+
+GzipOutputStream::~GzipOutputStream() {
+  Close();
+  internal::SizedDelete(input_buffer_, input_buffer_length_);
+}
+
+// private
+int GzipOutputStream::Deflate(int flush) {
+  int error = Z_OK;
+  do {
+    if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
+      bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
+      if (!ok) {
+        sub_data_ = NULL;
+        sub_data_size_ = 0;
+        return Z_BUF_ERROR;
+      }
+      GOOGLE_CHECK_GT(sub_data_size_, 0);
+      zcontext_.next_out = static_cast<Bytef*>(sub_data_);
+      zcontext_.avail_out = sub_data_size_;
+    }
+    error = deflate(&zcontext_, flush);
+  } while (error == Z_OK && zcontext_.avail_out == 0);
+  if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) {
+    // Notify lower layer of data.
+    sub_stream_->BackUp(zcontext_.avail_out);
+    // We don't own the buffer anymore.
+    sub_data_ = NULL;
+    sub_data_size_ = 0;
+  }
+  return error;
+}
+
+// implements ZeroCopyOutputStream ---------------------------------
+bool GzipOutputStream::Next(void** data, int* size) {
+  if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
+    return false;
+  }
+  if (zcontext_.avail_in != 0) {
+    zerror_ = Deflate(Z_NO_FLUSH);
+    if (zerror_ != Z_OK) {
+      return false;
+    }
+  }
+  if (zcontext_.avail_in == 0) {
+    // all input was consumed. reset the buffer.
+    zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
+    zcontext_.avail_in = input_buffer_length_;
+    *data = input_buffer_;
+    *size = input_buffer_length_;
+  } else {
+    // The loop in Deflate should consume all avail_in
+    GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
+  }
+  return true;
+}
+void GzipOutputStream::BackUp(int count) {
+  GOOGLE_CHECK_GE(zcontext_.avail_in, static_cast<uInt>(count));
+  zcontext_.avail_in -= count;
+}
+int64_t GzipOutputStream::ByteCount() const {
+  return zcontext_.total_in + zcontext_.avail_in;
+}
+
+bool GzipOutputStream::Flush() {
+  zerror_ = Deflate(Z_FULL_FLUSH);
+  // Return true if the flush succeeded or if it was a no-op.
+  return (zerror_ == Z_OK) ||
+         (zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
+          zcontext_.avail_out != 0);
+}
+
+bool GzipOutputStream::Close() {
+  if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
+    return false;
+  }
+  do {
+    zerror_ = Deflate(Z_FINISH);
+  } while (zerror_ == Z_OK);
+  zerror_ = deflateEnd(&zcontext_);
+  bool ok = zerror_ == Z_OK;
+  zerror_ = Z_STREAM_END;
+  return ok;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // HAVE_ZLIB
diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h
new file mode 100644
index 0000000..4cf71b6
--- /dev/null
+++ b/src/google/protobuf/io/gzip_stream.h
@@ -0,0 +1,205 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: brianolson@google.com (Brian Olson)
+//
+// This file contains the definition for classes GzipInputStream and
+// GzipOutputStream.
+//
+// GzipInputStream decompresses data from an underlying
+// ZeroCopyInputStream and provides the decompressed data as a
+// ZeroCopyInputStream.
+//
+// GzipOutputStream is an ZeroCopyOutputStream that compresses data to
+// an underlying ZeroCopyOutputStream.
+
+#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
+#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
+
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/port.h>
+#include "zlib.h"
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// A ZeroCopyInputStream that reads compressed data through zlib
+class PROTOBUF_EXPORT GzipInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Format key for constructor
+  enum Format {
+    // zlib will autodetect gzip header or deflate stream
+    AUTO = 0,
+
+    // GZIP streams have some extra header data for file attributes.
+    GZIP = 1,
+
+    // Simpler zlib stream format.
+    ZLIB = 2,
+  };
+
+  // buffer_size and format may be -1 for default of 64kB and GZIP format
+  explicit GzipInputStream(ZeroCopyInputStream* sub_stream,
+                           Format format = AUTO, int buffer_size = -1);
+  virtual ~GzipInputStream();
+
+  // Return last error message or NULL if no error.
+  inline const char* ZlibErrorMessage() const { return zcontext_.msg; }
+  inline int ZlibErrorCode() const { return zerror_; }
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  Format format_;
+
+  ZeroCopyInputStream* sub_stream_;
+
+  z_stream zcontext_;
+  int zerror_;
+
+  void* output_buffer_;
+  void* output_position_;
+  size_t output_buffer_length_;
+  int64_t byte_count_;
+
+  int Inflate(int flush);
+  void DoNextOutput(const void** data, int* size);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
+};
+
+class PROTOBUF_EXPORT GzipOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Format key for constructor
+  enum Format {
+    // GZIP streams have some extra header data for file attributes.
+    GZIP = 1,
+
+    // Simpler zlib stream format.
+    ZLIB = 2,
+  };
+
+  struct PROTOBUF_EXPORT Options {
+    // Defaults to GZIP.
+    Format format;
+
+    // What size buffer to use internally.  Defaults to 64kB.
+    int buffer_size;
+
+    // A number between 0 and 9, where 0 is no compression and 9 is best
+    // compression.  Defaults to Z_DEFAULT_COMPRESSION (see zlib.h).
+    int compression_level;
+
+    // Defaults to Z_DEFAULT_STRATEGY.  Can also be set to Z_FILTERED,
+    // Z_HUFFMAN_ONLY, or Z_RLE.  See the documentation for deflateInit2 in
+    // zlib.h for definitions of these constants.
+    int compression_strategy;
+
+    Options();  // Initializes with default values.
+  };
+
+  // Create a GzipOutputStream with default options.
+  explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream);
+
+  // Create a GzipOutputStream with the given options.
+  GzipOutputStream(ZeroCopyOutputStream* sub_stream, const Options& options);
+
+  virtual ~GzipOutputStream();
+
+  // Return last error message or NULL if no error.
+  inline const char* ZlibErrorMessage() const { return zcontext_.msg; }
+  inline int ZlibErrorCode() const { return zerror_; }
+
+  // Flushes data written so far to zipped data in the underlying stream.
+  // It is the caller's responsibility to flush the underlying stream if
+  // necessary.
+  // Compression may be less efficient stopping and starting around flushes.
+  // Returns true if no error.
+  //
+  // Please ensure that block size is > 6. Here is an excerpt from the zlib
+  // doc that explains why:
+  //
+  // In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out
+  // is greater than six to avoid repeated flush markers due to
+  // avail_out == 0 on return.
+  bool Flush();
+
+  // Writes out all data and closes the gzip stream.
+  // It is the caller's responsibility to close the underlying stream if
+  // necessary.
+  // Returns true if no error.
+  bool Close();
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  ZeroCopyOutputStream* sub_stream_;
+  // Result from calling Next() on sub_stream_
+  void* sub_data_;
+  int sub_data_size_;
+
+  z_stream zcontext_;
+  int zerror_;
+  void* input_buffer_;
+  size_t input_buffer_length_;
+
+  // Shared constructor code.
+  void Init(ZeroCopyOutputStream* sub_stream, const Options& options);
+
+  // Do some compression.
+  // Takes zlib flush mode.
+  // Returns zlib error code.
+  int Deflate(int flush);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream);
+};
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
diff --git a/src/google/protobuf/io/gzip_stream_unittest.sh b/src/google/protobuf/io/gzip_stream_unittest.sh
new file mode 100755
index 0000000..16251a9
--- /dev/null
+++ b/src/google/protobuf/io/gzip_stream_unittest.sh
@@ -0,0 +1,44 @@
+#!/bin/sh -x
+#
+# Protocol Buffers - Google's data interchange format
+# Copyright 2009 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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: brianolson@google.com (Brian Olson)
+#
+# Test compatibility between command line gzip/gunzip binaries and
+# ZeroCopyStream versions.
+
+TESTFILE=Makefile
+
+(./zcgzip < ${TESTFILE} | gunzip | cmp - ${TESTFILE}) && \
+(gzip < ${TESTFILE} | ./zcgunzip | cmp - ${TESTFILE})
+
+# Result of "(cmd) && (cmd)" implicitly becomes result of this script
+# and thus the test.
diff --git a/src/google/protobuf/io/io_win32.cc b/src/google/protobuf/io/io_win32.cc
new file mode 100644
index 0000000..4e81908
--- /dev/null
+++ b/src/google/protobuf/io/io_win32.cc
@@ -0,0 +1,471 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: laszlocsomor@google.com (Laszlo Csomor)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+// Implementation for long-path-aware open/mkdir/access/etc. on Windows, as well
+// as for the supporting utility functions.
+//
+// These functions convert the input path to an absolute Windows path
+// with "\\?\" prefix, then pass that to _wopen/_wmkdir/_waccess/etc.
+// (declared in <io.h>) respectively. This allows working with files/directories
+// whose paths are longer than MAX_PATH (260 chars).
+//
+// This file is only used on Windows, it's empty on other platforms.
+
+#if defined(_WIN32) && !defined(_XBOX_ONE)
+
+// Comment this out to fall back to using the ANSI versions (open, mkdir, ...)
+// instead of the Unicode ones (_wopen, _wmkdir, ...). Doing so can be useful to
+// debug failing tests if that's caused by the long path support.
+#define SUPPORT_LONGPATHS
+
+#include <google/protobuf/io/io_win32.h>
+
+#include <ctype.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <wctype.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+
+#include <windows.h>
+
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace win32 {
+namespace {
+
+using std::string;
+using std::wstring;
+
+template <typename char_type>
+struct CharTraits {
+  static bool is_alpha(char_type ch);
+};
+
+template <>
+struct CharTraits<char> {
+  static bool is_alpha(char ch) { return isalpha(ch); }
+};
+
+template <>
+struct CharTraits<wchar_t> {
+  static bool is_alpha(wchar_t ch) { return iswalpha(ch); }
+};
+
+template <typename char_type>
+bool null_or_empty(const char_type* s) {
+  return s == nullptr || *s == 0;
+}
+
+// Returns true if the path starts with a drive letter, e.g. "c:".
+// Note that this won't check for the "\" after the drive letter, so this also
+// returns true for "c:foo" (which is "c:\${PWD}\foo").
+// This check requires that a path not have a longpath prefix ("\\?\").
+template <typename char_type>
+bool has_drive_letter(const char_type* ch) {
+  return CharTraits<char_type>::is_alpha(ch[0]) && ch[1] == ':';
+}
+
+// Returns true if the path starts with a longpath prefix ("\\?\").
+template <typename char_type>
+bool has_longpath_prefix(const char_type* path) {
+  return path[0] == '\\' && path[1] == '\\' && path[2] == '?' &&
+         path[3] == '\\';
+}
+
+template <typename char_type>
+bool is_separator(char_type c) {
+  return c == '/' || c == '\\';
+}
+
+// Returns true if the path starts with a drive specifier (e.g. "c:\").
+template <typename char_type>
+bool is_path_absolute(const char_type* path) {
+  return has_drive_letter(path) && is_separator(path[2]);
+}
+
+template <typename char_type>
+bool is_drive_relative(const char_type* path) {
+  return has_drive_letter(path) && (path[2] == 0 || !is_separator(path[2]));
+}
+
+wstring join_paths(const wstring& path1, const wstring& path2) {
+  if (path1.empty() || is_path_absolute(path2.c_str()) ||
+      has_longpath_prefix(path2.c_str())) {
+    return path2;
+  }
+  if (path2.empty()) {
+    return path1;
+  }
+
+  if (is_separator(path1[path1.size() - 1])) {
+    return is_separator(path2[0]) ? (path1 + path2.substr(1))
+                                       : (path1 + path2);
+  } else {
+    return is_separator(path2[0]) ? (path1 + path2)
+                                       : (path1 + L'\\' + path2);
+  }
+}
+
+wstring normalize(wstring path) {
+  if (has_longpath_prefix(path.c_str())) {
+    path = path.substr(4);
+  }
+
+  static const wstring dot(L".");
+  static const wstring dotdot(L"..");
+  const WCHAR* p = path.c_str();
+
+  std::vector<wstring> segments;
+  int segment_start = -1;
+  // Find the path segments in `path` (separated by "/").
+  for (int i = 0;; ++i) {
+    if (!is_separator(p[i]) && p[i] != L'\0') {
+      // The current character does not end a segment, so start one unless it's
+      // already started.
+      if (segment_start < 0) {
+        segment_start = i;
+      }
+    } else if (segment_start >= 0 && i > segment_start) {
+      // The current character is "/" or "\0", so this ends a segment.
+      // Add that to `segments` if there's anything to add; handle "." and "..".
+      wstring segment(p, segment_start, i - segment_start);
+      segment_start = -1;
+      if (segment == dotdot) {
+        if (!segments.empty() &&
+            (!has_drive_letter(segments[0].c_str()) || segments.size() > 1)) {
+          segments.pop_back();
+        }
+      } else if (segment != dot && !segment.empty()) {
+        segments.push_back(segment);
+      }
+    }
+    if (p[i] == L'\0') {
+      break;
+    }
+  }
+
+  // Handle the case when `path` is just a drive specifier (or some degenerate
+  // form of it, e.g. "c:\..").
+  if (segments.size() == 1 && segments[0].size() == 2 &&
+      has_drive_letter(segments[0].c_str())) {
+    return segments[0] + L'\\';
+  }
+
+  // Join all segments.
+  bool first = true;
+  std::wstringstream result;
+  for (int i = 0; i < segments.size(); ++i) {
+    if (!first) {
+      result << L'\\';
+    }
+    first = false;
+    result << segments[i];
+  }
+  // Preserve trailing separator if the input contained it.
+  if (!path.empty() && is_separator(p[path.size() - 1])) {
+    result << L'\\';
+  }
+  return result.str();
+}
+
+bool as_windows_path(const char* path, wstring* result) {
+  if (null_or_empty(path)) {
+    result->clear();
+    return true;
+  }
+  wstring wpath;
+  if (!strings::utf8_to_wcs(path, &wpath)) {
+    return false;
+  }
+  if (has_longpath_prefix(wpath.c_str())) {
+    *result = wpath;
+    return true;
+  }
+  if (is_separator(path[0]) || is_drive_relative(path)) {
+    return false;
+  }
+
+
+  if (!is_path_absolute(wpath.c_str())) {
+    int size = ::GetCurrentDirectoryW(0, nullptr);
+    if (size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+      return false;
+    }
+    std::unique_ptr<WCHAR[]> wcwd(new WCHAR[size]);
+    ::GetCurrentDirectoryW(size, wcwd.get());
+    wpath = join_paths(wcwd.get(), wpath);
+  }
+  wpath = normalize(wpath);
+  if (!has_longpath_prefix(wpath.c_str())) {
+    // Add the "\\?\" prefix unconditionally. This way we prevent the Win32 API
+    // from processing the path and "helpfully" removing trailing dots from the
+    // path, for example.
+    // See https://github.com/bazelbuild/bazel/issues/2935
+    wpath = wstring(L"\\\\?\\") + wpath;
+  }
+  *result = wpath;
+  return true;
+}
+
+}  // namespace
+
+int open(const char* path, int flags, int mode) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wopen(wpath.c_str(), flags, mode);
+#else
+  return ::_open(path, flags, mode);
+#endif
+}
+
+int mkdir(const char* path, int /*_mode*/) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wmkdir(wpath.c_str());
+#else   // not SUPPORT_LONGPATHS
+  return ::_mkdir(path);
+#endif  // not SUPPORT_LONGPATHS
+}
+
+int access(const char* path, int mode) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_waccess(wpath.c_str(), mode);
+#else
+  return ::_access(path, mode);
+#endif
+}
+
+int chdir(const char* path) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wchdir(wpath.c_str());
+#else
+  return ::_chdir(path);
+#endif
+}
+
+int stat(const char* path, struct _stat* buffer) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wstat(wpath.c_str(), buffer);
+#else   // not SUPPORT_LONGPATHS
+  return ::_stat(path, buffer);
+#endif  // not SUPPORT_LONGPATHS
+}
+
+FILE* fopen(const char* path, const char* mode) {
+#ifdef SUPPORT_LONGPATHS
+  if (null_or_empty(path)) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return nullptr;
+  }
+  wstring wmode;
+  if (!strings::utf8_to_wcs(mode, &wmode)) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  return ::_wfopen(wpath.c_str(), wmode.c_str());
+#else
+  return ::fopen(path, mode);
+#endif
+}
+
+int close(int fd) { return ::_close(fd); }
+
+int dup(int fd) { return ::_dup(fd); }
+
+int dup2(int fd1, int fd2) { return ::_dup2(fd1, fd2); }
+
+int read(int fd, void* buffer, size_t size) {
+  return ::_read(fd, buffer, size);
+}
+
+int setmode(int fd, int mode) { return ::_setmode(fd, mode); }
+
+int write(int fd, const void* buffer, size_t size) {
+  return ::_write(fd, buffer, size);
+}
+
+wstring testonly_utf8_to_winpath(const char* path) {
+  wstring wpath;
+  return as_windows_path(path, &wpath) ? wpath : wstring();
+}
+
+ExpandWildcardsResult ExpandWildcards(
+    const string& path, std::function<void(const string&)> consume) {
+  if (path.find_first_of("*?") == string::npos) {
+    // There are no wildcards in the path, we don't need to expand it.
+    consume(path);
+    return ExpandWildcardsResult::kSuccess;
+  }
+
+  wstring wpath;
+  if (!as_windows_path(path.c_str(), &wpath)) {
+    return ExpandWildcardsResult::kErrorInputPathConversion;
+  }
+
+  static const wstring kDot = L".";
+  static const wstring kDotDot = L"..";
+  WIN32_FIND_DATAW metadata;
+  HANDLE handle = ::FindFirstFileW(wpath.c_str(), &metadata);
+  if (handle == INVALID_HANDLE_VALUE) {
+    // The pattern does not match any files (or directories).
+    return ExpandWildcardsResult::kErrorNoMatchingFile;
+  }
+
+  string::size_type pos = path.find_last_of("\\/");
+  string dirname;
+  if (pos != string::npos) {
+    dirname = path.substr(0, pos + 1);
+  }
+
+  ExpandWildcardsResult matched = ExpandWildcardsResult::kErrorNoMatchingFile;
+  do {
+    // Ignore ".", "..", and directories.
+    if ((metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 &&
+        kDot != metadata.cFileName && kDotDot != metadata.cFileName) {
+      matched = ExpandWildcardsResult::kSuccess;
+      string filename;
+      if (!strings::wcs_to_utf8(metadata.cFileName, &filename)) {
+        matched = ExpandWildcardsResult::kErrorOutputPathConversion;
+        break;
+      }
+
+      if (dirname.empty()) {
+        consume(filename);
+      } else {
+        consume(dirname + filename);
+      }
+    }
+  } while (::FindNextFileW(handle, &metadata));
+  FindClose(handle);
+  return matched;
+}
+
+namespace strings {
+
+bool wcs_to_mbs(const WCHAR* s, string* out, bool outUtf8) {
+  if (null_or_empty(s)) {
+    out->clear();
+    return true;
+  }
+  BOOL usedDefaultChar = FALSE;
+  SetLastError(0);
+  int size = WideCharToMultiByte(
+      outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, nullptr, 0, nullptr,
+      outUtf8 ? nullptr : &usedDefaultChar);
+  if ((size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+      || usedDefaultChar) {
+    return false;
+  }
+  std::unique_ptr<CHAR[]> astr(new CHAR[size]);
+  WideCharToMultiByte(
+      outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, astr.get(), size, nullptr, nullptr);
+  out->assign(astr.get());
+  return true;
+}
+
+bool mbs_to_wcs(const char* s, wstring* out, bool inUtf8) {
+  if (null_or_empty(s)) {
+    out->clear();
+    return true;
+  }
+
+  SetLastError(0);
+  int size =
+      MultiByteToWideChar(inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, nullptr, 0);
+  if (size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return false;
+  }
+  std::unique_ptr<WCHAR[]> wstr(new WCHAR[size]);
+  MultiByteToWideChar(
+      inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, wstr.get(), size + 1);
+  out->assign(wstr.get());
+  return true;
+}
+
+bool utf8_to_wcs(const char* input, wstring* out) {
+  return mbs_to_wcs(input, out, true);
+}
+
+bool wcs_to_utf8(const wchar_t* input, string* out) {
+  return wcs_to_mbs(input, out, true);
+}
+
+}  // namespace strings
+}  // namespace win32
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // defined(_WIN32)
diff --git a/src/google/protobuf/io/io_win32.h b/src/google/protobuf/io/io_win32.h
new file mode 100644
index 0000000..a72b4ea
--- /dev/null
+++ b/src/google/protobuf/io/io_win32.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.
+
+// Author: laszlocsomor@google.com (Laszlo Csomor)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+// This file contains the declarations for Windows implementations of
+// commonly used POSIX functions such as open(2) and access(2), as well
+// as macro definitions for flags of these functions.
+//
+// By including this file you'll redefine open/access/etc. to
+// ::google::protobuf::io::win32::{open/access/etc.}.
+// Make sure you don't include a header that attempts to redeclare or
+// redefine these functions, that'll lead to confusing compilation
+// errors. It's best to #include this file as the last one to ensure that.
+//
+// This file is only used on Windows, it's empty on other platforms.
+
+#ifndef GOOGLE_PROTOBUF_IO_IO_WIN32_H__
+#define GOOGLE_PROTOBUF_IO_IO_WIN32_H__
+
+#if defined(_WIN32)
+
+#include <functional>
+#include <string>
+
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// Compilers on Windows other than MSVC (e.g. Cygwin, MinGW32) define the
+// following functions already, except for mkdir.
+namespace google {
+namespace protobuf {
+namespace io {
+namespace win32 {
+
+PROTOBUF_EXPORT FILE* fopen(const char* path, const char* mode);
+PROTOBUF_EXPORT int access(const char* path, int mode);
+PROTOBUF_EXPORT int chdir(const char* path);
+PROTOBUF_EXPORT int close(int fd);
+PROTOBUF_EXPORT int dup(int fd);
+PROTOBUF_EXPORT int dup2(int fd1, int fd2);
+PROTOBUF_EXPORT int mkdir(const char* path, int _mode);
+PROTOBUF_EXPORT int open(const char* path, int flags, int mode = 0);
+PROTOBUF_EXPORT int read(int fd, void* buffer, size_t size);
+PROTOBUF_EXPORT int setmode(int fd, int mode);
+PROTOBUF_EXPORT int stat(const char* path, struct _stat* buffer);
+PROTOBUF_EXPORT int write(int fd, const void* buffer, size_t size);
+PROTOBUF_EXPORT std::wstring testonly_utf8_to_winpath(const char* path);
+
+enum class ExpandWildcardsResult {
+  kSuccess = 0,
+  kErrorNoMatchingFile = 1,
+  kErrorInputPathConversion = 2,
+  kErrorOutputPathConversion = 3,
+};
+
+// Expand wildcards in a path pattern, feed the result to a consumer function.
+//
+// `path` must be a valid, Windows-style path. It may be absolute, or relative
+// to the current working directory, and it may contain wildcards ("*" and "?")
+// in the last path segment. This function passes all matching file names to
+// `consume`. The resulting paths may not be absolute nor normalized.
+//
+// The function returns a value from `ExpandWildcardsResult`.
+PROTOBUF_EXPORT ExpandWildcardsResult ExpandWildcards(
+    const std::string& path, std::function<void(const std::string&)> consume);
+
+namespace strings {
+
+// Convert from UTF-16 to Active-Code-Page-encoded or to UTF-8-encoded text.
+PROTOBUF_EXPORT bool wcs_to_mbs(const wchar_t* s, std::string* out,
+                                bool outUtf8);
+
+// Convert from Active-Code-Page-encoded or UTF-8-encoded text to UTF-16.
+PROTOBUF_EXPORT bool mbs_to_wcs(const char* s, std::wstring* out, bool inUtf8);
+
+// Convert from UTF-8-encoded text to UTF-16.
+PROTOBUF_EXPORT bool utf8_to_wcs(const char* input, std::wstring* out);
+
+// Convert from UTF-16-encoded text to UTF-8.
+PROTOBUF_EXPORT bool wcs_to_utf8(const wchar_t* input, std::string* out);
+
+}  // namespace strings
+
+}  // namespace win32
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#ifndef W_OK
+#define W_OK 02  // not defined by MSVC for whatever reason
+#endif
+
+#ifndef F_OK
+#define F_OK 00  // not defined by MSVC for whatever reason
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // defined(_WIN32)
+
+#endif  // GOOGLE_PROTOBUF_IO_IO_WIN32_H__
diff --git a/src/google/protobuf/io/io_win32_unittest.cc b/src/google/protobuf/io/io_win32_unittest.cc
new file mode 100644
index 0000000..e8f378f
--- /dev/null
+++ b/src/google/protobuf/io/io_win32_unittest.cc
@@ -0,0 +1,631 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: laszlocsomor@google.com (Laszlo Csomor)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+// Unit tests for long-path-aware open/mkdir/access/etc. on Windows, as well as
+// for the supporting utility functions.
+//
+// This file is only used on Windows, it's empty on other platforms.
+
+#if defined(_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <google/protobuf/io/io_win32.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <wchar.h>
+#include <windows.h>
+
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace win32 {
+namespace {
+
+const char kUtf8Text[] = {
+    'h', 'i', ' ',
+    // utf-8: 11010000 10011111, utf-16: 100 0001 1111 = 0x041F
+    static_cast<char>(0xd0), static_cast<char>(0x9f),
+    // utf-8: 11010001 10000000, utf-16: 100 0100 0000 = 0x0440
+    static_cast<char>(0xd1), static_cast<char>(0x80),
+    // utf-8: 11010000 10111000, utf-16: 100 0011 1000 = 0x0438
+    static_cast<char>(0xd0), static_cast<char>(0xb8),
+    // utf-8: 11010000 10110010, utf-16: 100 0011 0010 = 0x0432
+    static_cast<char>(0xd0), static_cast<char>(0xb2),
+    // utf-8: 11010000 10110101, utf-16: 100 0011 0101 = 0x0435
+    static_cast<char>(0xd0), static_cast<char>(0xb5),
+    // utf-8: 11010001 10000010, utf-16: 100 0100 0010 = 0x0442
+    static_cast<char>(0xd1), static_cast<char>(0x82), 0
+};
+
+const wchar_t kUtf16Text[] = {
+  L'h', L'i', L' ',
+  L'\x41f', L'\x440', L'\x438', L'\x432', L'\x435', L'\x442', 0
+};
+
+using std::string;
+using std::vector;
+using std::wstring;
+
+class IoWin32Test : public ::testing::Test {
+ public:
+  void SetUp();
+  void TearDown();
+
+ protected:
+  bool CreateAllUnder(wstring path);
+  bool DeleteAllUnder(wstring path);
+
+  WCHAR working_directory[MAX_PATH];
+  string test_tmpdir;
+  wstring wtest_tmpdir;
+};
+
+#define ASSERT_INITIALIZED              \
+  {                                     \
+    EXPECT_FALSE(test_tmpdir.empty());  \
+    EXPECT_FALSE(wtest_tmpdir.empty()); \
+  }
+
+namespace {
+void StripTrailingSlashes(string* str) {
+  int i = str->size() - 1;
+  for (; i >= 0 && ((*str)[i] == '/' || (*str)[i] == '\\'); --i) {}
+  str->resize(i+1);
+}
+
+bool GetEnvVarAsUtf8(const WCHAR* name, string* result) {
+  DWORD size = ::GetEnvironmentVariableW(name, nullptr, 0);
+  if (size > 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
+    std::unique_ptr<WCHAR[]> wcs(new WCHAR[size]);
+    ::GetEnvironmentVariableW(name, wcs.get(), size);
+    // GetEnvironmentVariableA retrieves an Active-Code-Page-encoded text which
+    // we'd first need to convert to UTF-16 then to UTF-8, because there seems
+    // to be no API function to do that conversion directly.
+    // GetEnvironmentVariableW retrieves an UTF-16-encoded text, which we need
+    // to convert to UTF-8.
+    return strings::wcs_to_utf8(wcs.get(), result);
+  } else {
+    return false;
+  }
+}
+
+bool GetCwdAsUtf8(string* result) {
+  DWORD size = ::GetCurrentDirectoryW(0, nullptr);
+  if (size > 0) {
+    std::unique_ptr<WCHAR[]> wcs(new WCHAR[size]);
+    ::GetCurrentDirectoryW(size, wcs.get());
+    // GetCurrentDirectoryA retrieves an Active-Code-Page-encoded text which
+    // we'd first need to convert to UTF-16 then to UTF-8, because there seems
+    // to be no API function to do that conversion directly.
+    // GetCurrentDirectoryW retrieves an UTF-16-encoded text, which we need
+    // to convert to UTF-8.
+    return strings::wcs_to_utf8(wcs.get(), result);
+  } else {
+    return false;
+  }
+}
+
+bool CreateEmptyFile(const wstring& path) {
+  HANDLE h = CreateFileW(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+                         FILE_ATTRIBUTE_NORMAL, NULL);
+  if (h == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+  CloseHandle(h);
+  return true;
+}
+
+}  // namespace
+
+void IoWin32Test::SetUp() {
+  test_tmpdir.clear();
+  wtest_tmpdir.clear();
+  DWORD size = ::GetCurrentDirectoryW(MAX_PATH, working_directory);
+  EXPECT_GT(size, 0U);
+  EXPECT_LT(size, static_cast<DWORD>(MAX_PATH));
+
+  string tmp;
+  bool ok = false;
+  if (!ok) {
+    // Bazel sets this environment variable when it runs tests.
+    ok = GetEnvVarAsUtf8(L"TEST_TMPDIR", &tmp);
+  }
+  if (!ok) {
+    // Bazel 0.8.0 sets this environment for every build and test action.
+    ok = GetEnvVarAsUtf8(L"TEMP", &tmp);
+  }
+  if (!ok) {
+    // Bazel 0.8.0 sets this environment for every build and test action.
+    ok = GetEnvVarAsUtf8(L"TMP", &tmp);
+  }
+  if (!ok) {
+    // Fall back to using the current directory.
+    ok = GetCwdAsUtf8(&tmp);
+  }
+  if (!ok || tmp.empty()) {
+    FAIL() << "Cannot find a temp directory.";
+  }
+
+  StripTrailingSlashes(&tmp);
+  std::stringstream result;
+  // Deleting files and directories is asynchronous on Windows, and if TearDown
+  // just deleted the previous temp directory, sometimes we cannot recreate the
+  // same directory.
+  // Use a counter so every test method gets its own temp directory.
+  static unsigned int counter = 0;
+  result << tmp << "\\w32tst" << counter++ << ".tmp";
+  test_tmpdir = result.str();
+  wtest_tmpdir = testonly_utf8_to_winpath(test_tmpdir.c_str());
+  ASSERT_FALSE(wtest_tmpdir.empty());
+  ASSERT_TRUE(DeleteAllUnder(wtest_tmpdir));
+  ASSERT_TRUE(CreateAllUnder(wtest_tmpdir));
+}
+
+void IoWin32Test::TearDown() {
+  if (!wtest_tmpdir.empty()) {
+    DeleteAllUnder(wtest_tmpdir);
+  }
+  ::SetCurrentDirectoryW(working_directory);
+}
+
+bool IoWin32Test::CreateAllUnder(wstring path) {
+  // Prepend UNC prefix if the path doesn't have it already. Don't bother
+  // checking if the path is shorter than MAX_PATH, let's just do it
+  // unconditionally.
+  if (path.find(L"\\\\?\\") != 0) {
+    path = wstring(L"\\\\?\\") + path;
+  }
+  if (::CreateDirectoryW(path.c_str(), nullptr) ||
+      GetLastError() == ERROR_ALREADY_EXISTS ||
+      GetLastError() == ERROR_ACCESS_DENIED) {
+    return true;
+  }
+  if (GetLastError() == ERROR_PATH_NOT_FOUND) {
+    size_t pos = path.find_last_of(L'\\');
+    if (pos != wstring::npos) {
+      wstring parent(path, 0, pos);
+      if (CreateAllUnder(parent) && CreateDirectoryW(path.c_str(), nullptr)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool IoWin32Test::DeleteAllUnder(wstring path) {
+  static const wstring kDot(L".");
+  static const wstring kDotDot(L"..");
+
+  // Prepend UNC prefix if the path doesn't have it already. Don't bother
+  // checking if the path is shorter than MAX_PATH, let's just do it
+  // unconditionally.
+  if (path.find(L"\\\\?\\") != 0) {
+    path = wstring(L"\\\\?\\") + path;
+  }
+  // Append "\" if necessary.
+  if (path[path.size() - 1] != L'\\') {
+    path.push_back(L'\\');
+  }
+
+  WIN32_FIND_DATAW metadata;
+  HANDLE handle = ::FindFirstFileW((path + L"*").c_str(), &metadata);
+  if (handle == INVALID_HANDLE_VALUE) {
+    return true;  // directory doesn't exist
+  }
+
+  bool result = true;
+  do {
+    wstring childname = metadata.cFileName;
+    if (kDot != childname && kDotDot != childname) {
+      wstring childpath = path + childname;
+      if ((metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+        // If this is not a junction, delete its contents recursively.
+        // Finally delete this directory/junction too.
+        if (((metadata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0 &&
+             !DeleteAllUnder(childpath)) ||
+            !::RemoveDirectoryW(childpath.c_str())) {
+          result = false;
+          break;
+        }
+      } else {
+        if (!::DeleteFileW(childpath.c_str())) {
+          result = false;
+          break;
+        }
+      }
+    }
+  } while (::FindNextFileW(handle, &metadata));
+  ::FindClose(handle);
+  return result;
+}
+
+TEST_F(IoWin32Test, AccessTest) {
+  ASSERT_INITIALIZED;
+
+  string path = test_tmpdir;
+  while (path.size() < MAX_PATH - 30) {
+    path += "\\accesstest";
+    EXPECT_EQ(mkdir(path.c_str(), 0644), 0);
+  }
+  string file = path + "\\file.txt";
+  int fd = open(file.c_str(), O_CREAT | O_WRONLY, 0644);
+  if (fd > 0) {
+    EXPECT_EQ(close(fd), 0);
+  } else {
+    EXPECT_TRUE(false);
+  }
+
+  EXPECT_EQ(access(test_tmpdir.c_str(), F_OK), 0);
+  EXPECT_EQ(access(path.c_str(), F_OK), 0);
+  EXPECT_EQ(access(path.c_str(), W_OK), 0);
+  EXPECT_EQ(access(file.c_str(), F_OK | W_OK), 0);
+  EXPECT_NE(access((file + ".blah").c_str(), F_OK), 0);
+  EXPECT_NE(access((file + ".blah").c_str(), W_OK), 0);
+
+  EXPECT_EQ(access(".", F_OK), 0);
+  EXPECT_EQ(access(".", W_OK), 0);
+  EXPECT_EQ(access((test_tmpdir + "/accesstest").c_str(), F_OK | W_OK), 0);
+  ASSERT_EQ(access((test_tmpdir + "/./normalize_me/.././accesstest").c_str(),
+                   F_OK | W_OK),
+            0);
+  EXPECT_NE(access("io_win32_unittest.AccessTest.nonexistent", F_OK), 0);
+  EXPECT_NE(access("io_win32_unittest.AccessTest.nonexistent", W_OK), 0);
+
+  ASSERT_EQ(access("c:bad", F_OK), -1);
+  ASSERT_EQ(errno, ENOENT);
+  ASSERT_EQ(access("/tmp/bad", F_OK), -1);
+  ASSERT_EQ(errno, ENOENT);
+  ASSERT_EQ(access("\\bad", F_OK), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+TEST_F(IoWin32Test, OpenTest) {
+  ASSERT_INITIALIZED;
+
+  string path = test_tmpdir;
+  while (path.size() < MAX_PATH) {
+    path += "\\opentest";
+    EXPECT_EQ(mkdir(path.c_str(), 0644), 0);
+  }
+  string file = path + "\\file.txt";
+  int fd = open(file.c_str(), O_CREAT | O_WRONLY, 0644);
+  if (fd > 0) {
+    EXPECT_EQ(write(fd, "hello", 5), 5);
+    EXPECT_EQ(close(fd), 0);
+  } else {
+    EXPECT_TRUE(false);
+  }
+
+  ASSERT_EQ(open("c:bad.txt", O_CREAT | O_WRONLY, 0644), -1);
+  ASSERT_EQ(errno, ENOENT);
+  ASSERT_EQ(open("/tmp/bad.txt", O_CREAT | O_WRONLY, 0644), -1);
+  ASSERT_EQ(errno, ENOENT);
+  ASSERT_EQ(open("\\bad.txt", O_CREAT | O_WRONLY, 0644), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+TEST_F(IoWin32Test, MkdirTest) {
+  ASSERT_INITIALIZED;
+
+  string path = test_tmpdir;
+  do {
+    path += "\\mkdirtest";
+    ASSERT_EQ(mkdir(path.c_str(), 0644), 0);
+  } while (path.size() <= MAX_PATH);
+
+  ASSERT_EQ(mkdir("c:bad", 0644), -1);
+  ASSERT_EQ(errno, ENOENT);
+  ASSERT_EQ(mkdir("/tmp/bad", 0644), -1);
+  ASSERT_EQ(errno, ENOENT);
+  ASSERT_EQ(mkdir("\\bad", 0644), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+TEST_F(IoWin32Test, MkdirTestNonAscii) {
+  ASSERT_INITIALIZED;
+
+  // Create a non-ASCII path.
+  // Ensure that we can create the directory using CreateDirectoryW.
+  EXPECT_TRUE(CreateDirectoryW((wtest_tmpdir + L"\\1").c_str(), nullptr));
+  EXPECT_TRUE(CreateDirectoryW((wtest_tmpdir + L"\\1\\" + kUtf16Text).c_str(), nullptr));
+  // Ensure that we can create a very similarly named directory using mkdir.
+  // We don't attempt to delete and recreate the same directory, because on
+  // Windows, deleting files and directories seems to be asynchronous.
+  EXPECT_EQ(mkdir((test_tmpdir + "\\2").c_str(), 0644), 0);
+  EXPECT_EQ(mkdir((test_tmpdir + "\\2\\" + kUtf8Text).c_str(), 0644), 0);
+}
+
+TEST_F(IoWin32Test, ChdirTest) {
+  string path("C:\\");
+  EXPECT_EQ(access(path.c_str(), F_OK), 0);
+  ASSERT_EQ(chdir(path.c_str()), 0);
+
+  // Do not try to chdir into the test_tmpdir, it may already contain directory
+  // names with trailing dots.
+  // Instead test here with an obviously dot-trailed path. If the win32_chdir
+  // function would not convert the path to absolute and prefix with "\\?\" then
+  // the Win32 API would ignore the trailing dot, but because of the prefixing
+  // there'll be no path processing done, so we'll actually attempt to chdir
+  // into "C:\some\path\foo."
+  path = test_tmpdir + "/foo.";
+  EXPECT_EQ(mkdir(path.c_str(), 644), 0);
+  EXPECT_EQ(access(path.c_str(), F_OK), 0);
+  ASSERT_NE(chdir(path.c_str()), 0);
+}
+
+TEST_F(IoWin32Test, ChdirTestNonAscii) {
+  ASSERT_INITIALIZED;
+
+  // Create a directory with a non-ASCII path and ensure we can cd into it.
+  wstring wNonAscii(wtest_tmpdir + L"\\" + kUtf16Text);
+  string nonAscii;
+  EXPECT_TRUE(strings::wcs_to_utf8(wNonAscii.c_str(), &nonAscii));
+  EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(), nullptr));
+  WCHAR cwd[MAX_PATH];
+  EXPECT_TRUE(GetCurrentDirectoryW(MAX_PATH, cwd));
+  // Ensure that we can cd into the path using SetCurrentDirectoryW.
+  EXPECT_TRUE(SetCurrentDirectoryW(wNonAscii.c_str()));
+  EXPECT_TRUE(SetCurrentDirectoryW(cwd));
+  // Ensure that we can cd into the path using chdir.
+  ASSERT_EQ(chdir(nonAscii.c_str()), 0);
+  // Ensure that the GetCurrentDirectoryW returns the desired path.
+  EXPECT_TRUE(GetCurrentDirectoryW(MAX_PATH, cwd));
+  ASSERT_EQ(wNonAscii, cwd);
+}
+
+TEST_F(IoWin32Test, ExpandWildcardsInRelativePathTest) {
+  wstring wNonAscii(wtest_tmpdir + L"\\" + kUtf16Text);
+  EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(), nullptr));
+  // Create mock files we will test pattern matching on.
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_a.proto"));
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_b.proto"));
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\bar.proto"));
+  // `cd` into `wtest_tmpdir`.
+  EXPECT_TRUE(SetCurrentDirectoryW(wtest_tmpdir.c_str()));
+
+  int found_a = 0;
+  int found_b = 0;
+  vector<string> found_bad;
+  // Assert matching a relative path pattern. Results should also be relative.
+  ExpandWildcardsResult result =
+      ExpandWildcards(string(kUtf8Text) + "\\foo*.proto",
+                      [&found_a, &found_b, &found_bad](const string& p) {
+                        if (p == string(kUtf8Text) + "\\foo_a.proto") {
+                          found_a++;
+                        } else if (p == string(kUtf8Text) + "\\foo_b.proto") {
+                          found_b++;
+                        } else {
+                          found_bad.push_back(p);
+                        }
+                      });
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+  EXPECT_EQ(found_a, 1);
+  EXPECT_EQ(found_b, 1);
+  if (!found_bad.empty()) {
+    FAIL() << found_bad[0];
+  }
+
+  // Assert matching the exact filename.
+  found_a = 0;
+  found_bad.clear();
+  result = ExpandWildcards(string(kUtf8Text) + "\\foo_a.proto",
+                           [&found_a, &found_bad](const string& p) {
+                             if (p == string(kUtf8Text) + "\\foo_a.proto") {
+                               found_a++;
+                             } else {
+                               found_bad.push_back(p);
+                             }
+                           });
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+  EXPECT_EQ(found_a, 1);
+  if (!found_bad.empty()) {
+    FAIL() << found_bad[0];
+  }
+}
+
+TEST_F(IoWin32Test, ExpandWildcardsInAbsolutePathTest) {
+  wstring wNonAscii(wtest_tmpdir + L"\\" + kUtf16Text);
+  EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(), nullptr));
+  // Create mock files we will test pattern matching on.
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_a.proto"));
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_b.proto"));
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\bar.proto"));
+
+  int found_a = 0;
+  int found_b = 0;
+  vector<string> found_bad;
+  // Assert matching an absolute path. The results should also use absolute
+  // path.
+  ExpandWildcardsResult result =
+      ExpandWildcards(string(test_tmpdir) + "\\" + kUtf8Text + "\\foo*.proto",
+                      [this, &found_a, &found_b, &found_bad](const string& p) {
+                        if (p == string(this->test_tmpdir) + "\\" + kUtf8Text +
+                                     "\\foo_a.proto") {
+                          found_a++;
+                        } else if (p == string(this->test_tmpdir) + "\\" +
+                                            kUtf8Text + "\\foo_b.proto") {
+                          found_b++;
+                        } else {
+                          found_bad.push_back(p);
+                        }
+                      });
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+  EXPECT_EQ(found_a, 1);
+  EXPECT_EQ(found_b, 1);
+  if (!found_bad.empty()) {
+    FAIL() << found_bad[0];
+  }
+
+  // Assert matching the exact filename.
+  found_a = 0;
+  found_bad.clear();
+  result =
+      ExpandWildcards(string(test_tmpdir) + "\\" + kUtf8Text + "\\foo_a.proto",
+                      [this, &found_a, &found_bad](const string& p) {
+                        if (p == string(this->test_tmpdir) + "\\" + kUtf8Text +
+                                     "\\foo_a.proto") {
+                          found_a++;
+                        } else {
+                          found_bad.push_back(p);
+                        }
+                      });
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+  EXPECT_EQ(found_a, 1);
+  if (!found_bad.empty()) {
+    FAIL() << found_bad[0];
+  }
+}
+
+TEST_F(IoWin32Test, ExpandWildcardsIgnoresDirectoriesTest) {
+  wstring wNonAscii(wtest_tmpdir + L"\\" + kUtf16Text);
+  EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(), nullptr));
+  // Create mock files we will test pattern matching on.
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_a.proto"));
+  EXPECT_TRUE(
+      CreateDirectoryW((wNonAscii + L"\\foo_b.proto").c_str(), nullptr));
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_c.proto"));
+  // `cd` into `wtest_tmpdir`.
+  EXPECT_TRUE(SetCurrentDirectoryW(wtest_tmpdir.c_str()));
+
+  int found_a = 0;
+  int found_c = 0;
+  vector<string> found_bad;
+  // Assert that the pattern matches exactly the expected files, and using the
+  // absolute path as did the input pattern.
+  ExpandWildcardsResult result =
+      ExpandWildcards(string(kUtf8Text) + "\\foo*.proto",
+                      [&found_a, &found_c, &found_bad](const string& p) {
+                        if (p == string(kUtf8Text) + "\\foo_a.proto") {
+                          found_a++;
+                        } else if (p == string(kUtf8Text) + "\\foo_c.proto") {
+                          found_c++;
+                        } else {
+                          found_bad.push_back(p);
+                        }
+                      });
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+  EXPECT_EQ(found_a, 1);
+  EXPECT_EQ(found_c, 1);
+  if (!found_bad.empty()) {
+    FAIL() << found_bad[0];
+  }
+}
+
+TEST_F(IoWin32Test, ExpandWildcardsFailsIfNoFileMatchesTest) {
+  wstring wNonAscii(wtest_tmpdir + L"\\" + kUtf16Text);
+  EXPECT_TRUE(CreateDirectoryW(wNonAscii.c_str(), nullptr));
+  // Create mock files we will test pattern matching on.
+  EXPECT_TRUE(CreateEmptyFile(wNonAscii + L"\\foo_a.proto"));
+  // `cd` into `wtest_tmpdir`.
+  EXPECT_TRUE(SetCurrentDirectoryW(wtest_tmpdir.c_str()));
+
+  // Control test: should match foo*.proto
+  ExpandWildcardsResult result =
+      ExpandWildcards(string(kUtf8Text) + "\\foo*.proto", [](const string&) {});
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+
+  // Control test: should match foo_a.proto
+  result = ExpandWildcards(string(kUtf8Text) + "\\foo_a.proto",
+                           [](const string&) {});
+  EXPECT_EQ(result, ExpandWildcardsResult::kSuccess);
+
+  // Actual test: should not match anything.
+  result =
+      ExpandWildcards(string(kUtf8Text) + "\\bar*.proto", [](const string&) {});
+  ASSERT_EQ(result, ExpandWildcardsResult::kErrorNoMatchingFile);
+}
+
+TEST_F(IoWin32Test, AsWindowsPathTest) {
+  DWORD size = GetCurrentDirectoryW(0, nullptr);
+  std::unique_ptr<wchar_t[]> cwd_str(new wchar_t[size]);
+  EXPECT_GT(GetCurrentDirectoryW(size, cwd_str.get()), 0U);
+  wstring cwd = wstring(L"\\\\?\\") + cwd_str.get();
+
+  ASSERT_EQ(testonly_utf8_to_winpath("relative_mkdirtest"),
+            cwd + L"\\relative_mkdirtest");
+  ASSERT_EQ(testonly_utf8_to_winpath("preserve//\\trailing///"),
+            cwd + L"\\preserve\\trailing\\");
+  ASSERT_EQ(testonly_utf8_to_winpath("./normalize_me\\/../blah"),
+            cwd + L"\\blah");
+  std::ostringstream relpath;
+  for (wchar_t* p = cwd_str.get(); *p; ++p) {
+    if (*p == '/' || *p == '\\') {
+      relpath << "../";
+    }
+  }
+  relpath << ".\\/../\\./beyond-toplevel";
+  ASSERT_EQ(testonly_utf8_to_winpath(relpath.str().c_str()),
+            wstring(L"\\\\?\\") + cwd_str.get()[0] + L":\\beyond-toplevel");
+
+  // Absolute unix paths lack drive letters, driveless absolute windows paths
+  // do too. Neither can be converted to a drive-specifying absolute Windows
+  // path.
+  ASSERT_EQ(testonly_utf8_to_winpath("/absolute/unix/path"), L"");
+  // Though valid on Windows, we also don't support UNC paths (\\UNC\\blah).
+  ASSERT_EQ(testonly_utf8_to_winpath("\\driveless\\absolute"), L"");
+  // Though valid in cmd.exe, drive-relative paths are not supported.
+  ASSERT_EQ(testonly_utf8_to_winpath("c:foo"), L"");
+  ASSERT_EQ(testonly_utf8_to_winpath("c:/foo"), L"\\\\?\\c:\\foo");
+  ASSERT_EQ(testonly_utf8_to_winpath("\\\\?\\C:\\foo"), L"\\\\?\\C:\\foo");
+}
+
+TEST_F(IoWin32Test, Utf8Utf16ConversionTest) {
+  string mbs;
+  wstring wcs;
+  ASSERT_TRUE(strings::utf8_to_wcs(kUtf8Text, &wcs));
+  ASSERT_TRUE(strings::wcs_to_utf8(kUtf16Text, &mbs));
+  ASSERT_EQ(wcs, kUtf16Text);
+  ASSERT_EQ(mbs, kUtf8Text);
+}
+
+}  // namespace
+}  // namespace win32
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // defined(_WIN32)
+
diff --git a/src/google/protobuf/io/package_info.h b/src/google/protobuf/io/package_info.h
new file mode 100644
index 0000000..46c3dac
--- /dev/null
+++ b/src/google/protobuf/io/package_info.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file exists solely to document the google::protobuf::io namespace.
+// It is not compiled into anything, but it may be read by an automated
+// documentation generator.
+
+namespace google {
+namespace protobuf {
+
+// Auxiliary classes used for I/O.
+//
+// The Protocol Buffer library uses the classes in this package to deal with
+// I/O and encoding/decoding raw bytes.  Most users will not need to
+// deal with this package.  However, users who want to adapt the system to
+// work with their own I/O abstractions -- e.g., to allow Protocol Buffers
+// to be read from a different kind of input stream without the need for a
+// temporary buffer -- should take a closer look.
+namespace io {}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
new file mode 100644
index 0000000..47bd00b
--- /dev/null
+++ b/src/google/protobuf/io/printer.cc
@@ -0,0 +1,403 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/io/printer.h>
+
+#include <cctype>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
+    : variable_delimiter_(variable_delimiter),
+      output_(output),
+      buffer_(NULL),
+      buffer_size_(0),
+      offset_(0),
+      at_start_of_line_(true),
+      failed_(false),
+      annotation_collector_(NULL) {}
+
+Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
+                 AnnotationCollector* annotation_collector)
+    : variable_delimiter_(variable_delimiter),
+      output_(output),
+      buffer_(NULL),
+      buffer_size_(0),
+      offset_(0),
+      at_start_of_line_(true),
+      failed_(false),
+      annotation_collector_(annotation_collector) {}
+
+Printer::~Printer() {
+  // Only BackUp() if we invoked Next() at least once, and we have never failed.
+  // Note that we always call `Backup`, i.e. we call BackUp(0) as some output
+  // streams have buffered output, and BackUp() serves as a flush event in such
+  // implementations.
+  if (buffer_ != nullptr && !failed_) {
+    output_->BackUp(buffer_size_);
+  }
+}
+
+bool Printer::GetSubstitutionRange(const char* varname,
+                                   std::pair<size_t, size_t>* range) {
+  std::map<std::string, std::pair<size_t, size_t> >::const_iterator iter =
+      substitutions_.find(varname);
+  if (iter == substitutions_.end()) {
+    GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
+    return false;
+  }
+  if (iter->second.first > iter->second.second) {
+    GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
+                << varname;
+    return false;
+  }
+  *range = iter->second;
+  return true;
+}
+
+void Printer::Annotate(const char* begin_varname, const char* end_varname,
+                       const std::string& file_path,
+                       const std::vector<int>& path) {
+  if (annotation_collector_ == NULL) {
+    // Can't generate signatures with this Printer.
+    return;
+  }
+  std::pair<size_t, size_t> begin, end;
+  if (!GetSubstitutionRange(begin_varname, &begin) ||
+      !GetSubstitutionRange(end_varname, &end)) {
+    return;
+  }
+  if (begin.first > end.second) {
+    GOOGLE_LOG(DFATAL) << "  Annotation has negative length from " << begin_varname
+                << " to " << end_varname;
+  } else {
+    annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
+                                         path);
+  }
+}
+
+void Printer::Print(const std::map<std::string, std::string>& variables,
+                    const char* text) {
+  int size = strlen(text);
+  int pos = 0;  // The number of bytes we've written so far.
+  substitutions_.clear();
+  line_start_variables_.clear();
+
+  for (int i = 0; i < size; i++) {
+    if (text[i] == '\n') {
+      // Saw newline.  If there is more text, we may need to insert an indent
+      // here.  So, write what we have so far, including the '\n'.
+      WriteRaw(text + pos, i - pos + 1);
+      pos = i + 1;
+
+      // Setting this true will cause the next WriteRaw() to insert an indent
+      // first.
+      at_start_of_line_ = true;
+      line_start_variables_.clear();
+
+    } else if (text[i] == variable_delimiter_) {
+      // Saw the start of a variable name.
+
+      // Write what we have so far.
+      WriteRaw(text + pos, i - pos);
+      pos = i + 1;
+
+      // Find closing delimiter.
+      const char* end = strchr(text + pos, variable_delimiter_);
+      if (end == NULL) {
+        GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
+        end = text + pos;
+      }
+      int endpos = end - text;
+
+      std::string varname(text + pos, endpos - pos);
+      if (varname.empty()) {
+        // Two delimiters in a row reduce to a literal delimiter character.
+        WriteRaw(&variable_delimiter_, 1);
+      } else {
+        // Replace with the variable's value.
+        std::map<std::string, std::string>::const_iterator iter =
+            variables.find(varname);
+        if (iter == variables.end()) {
+          GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
+        } else {
+          if (at_start_of_line_ && iter->second.empty()) {
+            line_start_variables_.push_back(varname);
+          }
+          WriteRaw(iter->second.data(), iter->second.size());
+          std::pair<std::map<std::string, std::pair<size_t, size_t> >::iterator,
+                    bool>
+              inserted = substitutions_.insert(std::make_pair(
+                  varname,
+                  std::make_pair(offset_ - iter->second.size(), offset_)));
+          if (!inserted.second) {
+            // This variable was used multiple times.  Make its span have
+            // negative length so we can detect it if it gets used in an
+            // annotation.
+            inserted.first->second = std::make_pair(1, 0);
+          }
+        }
+      }
+
+      // Advance past this variable.
+      i = endpos;
+      pos = endpos + 1;
+    }
+  }
+
+  // Write the rest.
+  WriteRaw(text + pos, size - pos);
+}
+
+void Printer::Indent() { indent_ += "  "; }
+
+void Printer::Outdent() {
+  if (indent_.empty()) {
+    GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
+    return;
+  }
+
+  indent_.resize(indent_.size() - 2);
+}
+
+void Printer::PrintRaw(const std::string& data) {
+  WriteRaw(data.data(), data.size());
+}
+
+void Printer::PrintRaw(const char* data) {
+  if (failed_) return;
+  WriteRaw(data, strlen(data));
+}
+
+void Printer::WriteRaw(const char* data, int size) {
+  if (failed_) return;
+  if (size == 0) return;
+
+  if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
+    // Insert an indent.
+    at_start_of_line_ = false;
+    CopyToBuffer(indent_.data(), indent_.size());
+    if (failed_) return;
+    // Fix up empty variables (e.g., "{") that should be annotated as
+    // coming after the indent.
+    for (std::vector<std::string>::iterator i = line_start_variables_.begin();
+         i != line_start_variables_.end(); ++i) {
+      substitutions_[*i].first += indent_.size();
+      substitutions_[*i].second += indent_.size();
+    }
+  }
+
+  // If we're going to write any data, clear line_start_variables_, since
+  // we've either updated them in the block above or they no longer refer to
+  // the current line.
+  line_start_variables_.clear();
+
+  CopyToBuffer(data, size);
+}
+
+bool Printer::Next() {
+  do {
+    void* void_buffer;
+    if (!output_->Next(&void_buffer, &buffer_size_)) {
+      failed_ = true;
+      return false;
+    }
+    buffer_ = reinterpret_cast<char*>(void_buffer);
+  } while (buffer_size_ == 0);
+  return true;
+}
+
+void Printer::CopyToBuffer(const char* data, int size) {
+  if (failed_) return;
+  if (size == 0) return;
+
+  while (size > buffer_size_) {
+    // Data exceeds space in the buffer.  Copy what we can and request a
+    // new buffer.
+    if (buffer_size_ > 0) {
+      memcpy(buffer_, data, buffer_size_);
+      offset_ += buffer_size_;
+      data += buffer_size_;
+      size -= buffer_size_;
+    }
+    void* void_buffer;
+    failed_ = !output_->Next(&void_buffer, &buffer_size_);
+    if (failed_) return;
+    buffer_ = reinterpret_cast<char*>(void_buffer);
+  }
+
+  // Buffer is big enough to receive the data; copy it.
+  memcpy(buffer_, data, size);
+  buffer_ += size;
+  buffer_size_ -= size;
+  offset_ += size;
+}
+
+void Printer::IndentIfAtStart() {
+  if (at_start_of_line_) {
+    CopyToBuffer(indent_.data(), indent_.size());
+    at_start_of_line_ = false;
+  }
+}
+
+void Printer::FormatInternal(const std::vector<std::string>& args,
+                             const std::map<std::string, std::string>& vars,
+                             const char* format) {
+  auto save = format;
+  int arg_index = 0;
+  std::vector<AnnotationCollector::Annotation> annotations;
+  while (*format) {
+    char c = *format++;
+    switch (c) {
+      case '$':
+        format = WriteVariable(args, vars, format, &arg_index, &annotations);
+        continue;
+      case '\n':
+        at_start_of_line_ = true;
+        line_start_variables_.clear();
+        break;
+      default:
+        IndentIfAtStart();
+        break;
+    }
+    push_back(c);
+  }
+  if (arg_index != static_cast<int>(args.size())) {
+    GOOGLE_LOG(FATAL) << " Unused arguments. " << save;
+  }
+  if (!annotations.empty()) {
+    GOOGLE_LOG(FATAL) << " Annotation range is not-closed, expect $}$. " << save;
+  }
+}
+
+const char* Printer::WriteVariable(
+    const std::vector<std::string>& args,
+    const std::map<std::string, std::string>& vars, const char* format,
+    int* arg_index, std::vector<AnnotationCollector::Annotation>* annotations) {
+  auto start = format;
+  auto end = strchr(format, '$');
+  if (!end) {
+    GOOGLE_LOG(FATAL) << " Unclosed variable name.";
+  }
+  format = end + 1;
+  if (end == start) {
+    // "$$" is an escape for just '$'
+    IndentIfAtStart();
+    push_back('$');
+    return format;
+  }
+  if (*start == '{') {
+    GOOGLE_CHECK(std::isdigit(start[1]));
+    GOOGLE_CHECK_EQ(end - start, 2);
+    int idx = start[1] - '1';
+    if (idx < 0 || static_cast<size_t>(idx) >= args.size()) {
+      GOOGLE_LOG(FATAL) << "Annotation ${" << idx + 1 << "$ is out of bounds.";
+    }
+    if (idx > *arg_index) {
+      GOOGLE_LOG(FATAL) << "Annotation arg must be in correct order as given. Expected"
+                 << " ${" << (*arg_index) + 1 << "$ got ${" << idx + 1 << "$.";
+    } else if (idx == *arg_index) {
+      (*arg_index)++;
+    }
+    IndentIfAtStart();
+    annotations->push_back({{offset_, 0}, args[idx]});
+    return format;
+  } else if (*start == '}') {
+    GOOGLE_CHECK(annotations);
+    if (annotations->empty()) {
+      GOOGLE_LOG(FATAL) << "Unexpected end of annotation found.";
+    }
+    auto& a = annotations->back();
+    a.first.second = offset_;
+    if (annotation_collector_) annotation_collector_->AddAnnotationNew(a);
+    annotations->pop_back();
+    return format;
+  }
+  auto start_var = start;
+  while (start_var < end && *start_var == ' ') start_var++;
+  if (start_var == end) {
+    GOOGLE_LOG(FATAL) << " Empty variable.";
+  }
+  auto end_var = end;
+  while (start_var < end_var && *(end_var - 1) == ' ') end_var--;
+  std::string var_name{
+      start_var, static_cast<std::string::size_type>(end_var - start_var)};
+  std::string sub;
+  if (std::isdigit(var_name[0])) {
+    GOOGLE_CHECK_EQ(var_name.size(), 1U);  // No need for multi-digits
+    int idx = var_name[0] - '1';   // Start counting at 1
+    GOOGLE_CHECK_GE(idx, 0);
+    if (static_cast<size_t>(idx) >= args.size()) {
+      GOOGLE_LOG(FATAL) << "Argument $" << idx + 1 << "$ is out of bounds.";
+    }
+    if (idx > *arg_index) {
+      GOOGLE_LOG(FATAL) << "Arguments must be used in same order as given. Expected $"
+                 << (*arg_index) + 1 << "$ got $" << idx + 1 << "$.";
+    } else if (idx == *arg_index) {
+      (*arg_index)++;
+    }
+    sub = args[idx];
+  } else {
+    auto it = vars.find(var_name);
+    if (it == vars.end()) {
+      GOOGLE_LOG(FATAL) << " Unknown variable: " << var_name << ".";
+    }
+    sub = it->second;
+  }
+
+  // By returning here in case of empty we also skip possible spaces inside
+  // the $...$, i.e. "void$ dllexpor$ f();" -> "void f();" in the empty case.
+  if (sub.empty()) return format;
+
+  // We're going to write something non-empty so we need a possible indent.
+  IndentIfAtStart();
+
+  // Write the possible spaces in front.
+  CopyToBuffer(start, start_var - start);
+  // Write a non-empty substituted variable.
+  CopyToBuffer(sub.c_str(), sub.size());
+  // Finish off with writing possible trailing spaces.
+  CopyToBuffer(end_var, end - end_var);
+  return format;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
new file mode 100644
index 0000000..92a4321
--- /dev/null
+++ b/src/google/protobuf/io/printer.h
@@ -0,0 +1,387 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Utility class for writing text to a ZeroCopyOutputStream.
+
+#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
+#define GOOGLE_PROTOBUF_IO_PRINTER_H__
+
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+class ZeroCopyOutputStream;  // zero_copy_stream.h
+
+// Records annotations about a Printer's output.
+class PROTOBUF_EXPORT AnnotationCollector {
+ public:
+  // Annotation is a offset range and a payload pair.
+  typedef std::pair<std::pair<size_t, size_t>, std::string> Annotation;
+
+  // Records that the bytes in file_path beginning with begin_offset and ending
+  // before end_offset are associated with the SourceCodeInfo-style path.
+  virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
+                             const std::string& file_path,
+                             const std::vector<int>& path) = 0;
+
+  // TODO(gerbens) I don't see why we need virtuals here. Just a vector of
+  // range, payload pairs stored in a context should suffice.
+  virtual void AddAnnotationNew(Annotation& /* a */) {}
+
+  virtual ~AnnotationCollector() {}
+};
+
+// Records annotations about a Printer's output to the given protocol buffer,
+// assuming that the buffer has an ::Annotation message exposing path,
+// source_file, begin and end fields.
+template <typename AnnotationProto>
+class AnnotationProtoCollector : public AnnotationCollector {
+ public:
+  // annotation_proto is the protocol buffer to which new Annotations should be
+  // added. It is not owned by the AnnotationProtoCollector.
+  explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
+      : annotation_proto_(annotation_proto) {}
+
+  // Override for AnnotationCollector::AddAnnotation.
+  void AddAnnotation(size_t begin_offset, size_t end_offset,
+                     const std::string& file_path,
+                     const std::vector<int>& path) override {
+    typename AnnotationProto::Annotation* annotation =
+        annotation_proto_->add_annotation();
+    for (int i = 0; i < path.size(); ++i) {
+      annotation->add_path(path[i]);
+    }
+    annotation->set_source_file(file_path);
+    annotation->set_begin(begin_offset);
+    annotation->set_end(end_offset);
+  }
+  // Override for AnnotationCollector::AddAnnotation.
+  void AddAnnotationNew(Annotation& a) override {
+    auto* annotation = annotation_proto_->add_annotation();
+    annotation->ParseFromString(a.second);
+    annotation->set_begin(a.first.first);
+    annotation->set_end(a.first.second);
+  }
+
+ private:
+  // The protocol buffer to which new annotations should be added.
+  AnnotationProto* const annotation_proto_;
+};
+
+// This simple utility class assists in code generation.  It basically
+// allows the caller to define a set of variables and then output some
+// text with variable substitutions.  Example usage:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["name"] = "Bob";
+//   printer.Print(vars, "My name is $name$.");
+//
+// The above writes "My name is Bob." to the output stream.
+//
+// Printer aggressively enforces correct usage, crashing (with assert failures)
+// in the case of undefined variables in debug builds. This helps greatly in
+// debugging code which uses it.
+//
+// If a Printer is constructed with an AnnotationCollector, it will provide it
+// with annotations that connect the Printer's output to paths that can identify
+// various descriptors.  In the above example, if person_ is a descriptor that
+// identifies Bob, we can associate the output string "My name is Bob." with
+// a source path pointing to that descriptor with:
+//
+//   printer.Annotate("name", person_);
+//
+// The AnnotationCollector will be sent an annotation linking the output range
+// covering "Bob" to the logical path provided by person_.  Tools may use
+// this association to (for example) link "Bob" in the output back to the
+// source file that defined the person_ descriptor identifying Bob.
+//
+// Annotate can only examine variables substituted during the last call to
+// Print.  It is invalid to refer to a variable that was used multiple times
+// in a single Print call.
+//
+// In full generality, one may specify a range of output text using a beginning
+// substitution variable and an ending variable.  The resulting annotation will
+// span from the first character of the substituted value for the beginning
+// variable to the last character of the substituted value for the ending
+// variable.  For example, the Annotate call above is equivalent to this one:
+//
+//   printer.Annotate("name", "name", person_);
+//
+// This is useful if multiple variables combine to form a single span of output
+// that should be annotated with the same source path.  For example:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["first"] = "Alice";
+//   vars["last"] = "Smith";
+//   printer.Print(vars, "My name is $first$ $last$.");
+//   printer.Annotate("first", "last", person_);
+//
+// This code would associate the span covering "Alice Smith" in the output with
+// the person_ descriptor.
+//
+// Note that the beginning variable must come before (or overlap with, in the
+// case of zero-sized substitution values) the ending variable.
+//
+// It is also sometimes useful to use variables with zero-sized values as
+// markers.  This avoids issues with multiple references to the same variable
+// and also allows annotation ranges to span literal text from the Print
+// templates:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["foo"] = "bar";
+//   vars["function"] = "call";
+//   vars["mark"] = "";
+//   printer.Print(vars, "$function$($foo$,$foo$)$mark$");
+//   printer.Annotate("function", "mark", call_);
+//
+// This code associates the span covering "call(bar,bar)" in the output with the
+// call_ descriptor.
+
+class PROTOBUF_EXPORT Printer {
+ public:
+  // Create a printer that writes text to the given output stream.  Use the
+  // given character as the delimiter for variables.
+  Printer(ZeroCopyOutputStream* output, char variable_delimiter);
+
+  // Create a printer that writes text to the given output stream.  Use the
+  // given character as the delimiter for variables.  If annotation_collector
+  // is not null, Printer will provide it with annotations about code written
+  // to the stream.  annotation_collector is not owned by Printer.
+  Printer(ZeroCopyOutputStream* output, char variable_delimiter,
+          AnnotationCollector* annotation_collector);
+
+  ~Printer();
+
+  // Link a substitution variable emitted by the last call to Print to the
+  // object described by descriptor.
+  template <typename SomeDescriptor>
+  void Annotate(const char* varname, const SomeDescriptor* descriptor) {
+    Annotate(varname, varname, descriptor);
+  }
+
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the object described by descriptor. The range
+  // begins at begin_varname's value and ends after the last character of the
+  // value substituted for end_varname.
+  template <typename SomeDescriptor>
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const SomeDescriptor* descriptor) {
+    if (annotation_collector_ == NULL) {
+      // Annotations aren't turned on for this Printer, so don't pay the cost
+      // of building the location path.
+      return;
+    }
+    std::vector<int> path;
+    descriptor->GetLocationPath(&path);
+    Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
+  }
+
+  // Link a substitution variable emitted by the last call to Print to the file
+  // with path file_name.
+  void Annotate(const char* varname, const std::string& file_name) {
+    Annotate(varname, varname, file_name);
+  }
+
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the file with path file_name. The range begins
+  // at begin_varname's value and ends after the last character of the value
+  // substituted for end_varname.
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const std::string& file_name) {
+    if (annotation_collector_ == NULL) {
+      // Annotations aren't turned on for this Printer.
+      return;
+    }
+    std::vector<int> empty_path;
+    Annotate(begin_varname, end_varname, file_name, empty_path);
+  }
+
+  // Print some text after applying variable substitutions.  If a particular
+  // variable in the text is not defined, this will crash.  Variables to be
+  // substituted are identified by their names surrounded by delimiter
+  // characters (as given to the constructor).  The variable bindings are
+  // defined by the given map.
+  void Print(const std::map<std::string, std::string>& variables,
+             const char* text);
+
+  // Like the first Print(), except the substitutions are given as parameters.
+  template <typename... Args>
+  void Print(const char* text, const Args&... args) {
+    std::map<std::string, std::string> vars;
+    PrintInternal(&vars, text, args...);
+  }
+
+  // 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.
+  void Indent();
+
+  // Reduces the current indent level by two spaces, or crashes if the indent
+  // level is zero.
+  void Outdent();
+
+  // Write a string to the output buffer.
+  // This method does not look for newlines to add indentation.
+  void PrintRaw(const std::string& data);
+
+  // Write a zero-delimited string to output buffer.
+  // This method does not look for newlines to add indentation.
+  void PrintRaw(const char* data);
+
+  // Write some bytes to the output buffer.
+  // This method does not look for newlines to add indentation.
+  void WriteRaw(const char* data, int size);
+
+  // FormatInternal is a helper function not meant to use directly, use
+  // compiler::cpp::Formatter instead. This function is meant to support
+  // formatting text using named variables (eq. "$foo$) from a lookup map (vars)
+  // and variables directly supplied by arguments (eq "$1$" meaning first
+  // argument which is the zero index element of args).
+  void FormatInternal(const std::vector<std::string>& args,
+                      const std::map<std::string, std::string>& vars,
+                      const char* format);
+
+  // True if any write to the underlying stream failed.  (We don't just
+  // crash in this case because this is an I/O failure, not a programming
+  // error.)
+  bool failed() const { return failed_; }
+
+ private:
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the object found at the SourceCodeInfo-style path
+  // in a file with path file_path. The range begins at the start of
+  // begin_varname's value and ends after the last character of the value
+  // substituted for end_varname. Note that begin_varname and end_varname
+  // may refer to the same variable.
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const std::string& file_path, const std::vector<int>& path);
+
+  // Base case
+  void PrintInternal(std::map<std::string, std::string>* vars,
+                     const char* text) {
+    Print(*vars, text);
+  }
+
+  template <typename... Args>
+  void PrintInternal(std::map<std::string, std::string>* vars, const char* text,
+                     const char* key, const std::string& value,
+                     const Args&... args) {
+    (*vars)[key] = value;
+    PrintInternal(vars, text, args...);
+  }
+
+  // Copy size worth of bytes from data to buffer_.
+  void CopyToBuffer(const char* data, int size);
+
+  void push_back(char c) {
+    if (failed_) return;
+    if (buffer_size_ == 0) {
+      if (!Next()) return;
+    }
+    *buffer_++ = c;
+    buffer_size_--;
+    offset_++;
+  }
+
+  bool Next();
+
+  inline void IndentIfAtStart();
+  const char* WriteVariable(
+      const std::vector<std::string>& args,
+      const std::map<std::string, std::string>& vars, const char* format,
+      int* arg_index,
+      std::vector<AnnotationCollector::Annotation>* annotations);
+
+  const char variable_delimiter_;
+
+  ZeroCopyOutputStream* const output_;
+  char* buffer_;
+  int buffer_size_;
+  // The current position, in bytes, in the output stream.  This is equivalent
+  // to the total number of bytes that have been written so far.  This value is
+  // used to calculate annotation ranges in the substitutions_ map below.
+  size_t offset_;
+
+  std::string indent_;
+  bool at_start_of_line_;
+  bool failed_;
+
+  // A map from variable name to [start, end) offsets in the output buffer.
+  // These refer to the offsets used for a variable after the last call to
+  // Print.  If a variable was used more than once, the entry used in
+  // this map is set to a negative-length span.  For singly-used variables, the
+  // start offset is the beginning of the substitution; the end offset is the
+  // last byte of the substitution plus one (such that (end - start) is the
+  // length of the substituted string).
+  std::map<std::string, std::pair<size_t, size_t> > substitutions_;
+
+  // Keeps track of the keys in substitutions_ that need to be updated when
+  // indents are inserted. These are keys that refer to the beginning of the
+  // current line.
+  std::vector<std::string> line_start_variables_;
+
+  // Returns true and sets range to the substitution range in the output for
+  // varname if varname was used once in the last call to Print. If varname
+  // was not used, or if it was used multiple times, returns false (and
+  // fails a debug assertion).
+  bool GetSubstitutionRange(const char* varname,
+                            std::pair<size_t, size_t>* range);
+
+  // If non-null, annotation_collector_ is used to store annotations about
+  // generated code.
+  AnnotationCollector* const annotation_collector_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
+};
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_PRINTER_H__
diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc
new file mode 100644
index 0000000..ed54d1d
--- /dev/null
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -0,0 +1,735 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/io/printer.h>
+
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// Each test repeats over several block sizes in order to test both cases
+// where particular writes cross a buffer boundary and cases where they do
+// not.
+
+TEST(Printer, EmptyPrinter) {
+  char buffer[8192];
+  const int block_size = 100;
+  ArrayOutputStream output(buffer, GOOGLE_ARRAYSIZE(buffer), block_size);
+  Printer printer(&output, '\0');
+  EXPECT_TRUE(!printer.failed());
+}
+
+TEST(Printer, BasicPrinting) {
+  char buffer[8192];
+
+  for (int block_size = 1; block_size < 512; block_size *= 2) {
+    ArrayOutputStream output(buffer, sizeof(buffer), block_size);
+
+    {
+      Printer printer(&output, '\0');
+
+      printer.Print("Hello World!");
+      printer.Print("  This is the same line.\n");
+      printer.Print("But this is a new one.\nAnd this is another one.");
+
+      EXPECT_FALSE(printer.failed());
+    }
+
+    buffer[output.ByteCount()] = '\0';
+
+    EXPECT_STREQ(
+        "Hello World!  This is the same line.\n"
+        "But this is a new one.\n"
+        "And this is another one.",
+        buffer);
+  }
+}
+
+TEST(Printer, WriteRaw) {
+  char buffer[8192];
+
+  for (int block_size = 1; block_size < 512; block_size *= 2) {
+    ArrayOutputStream output(buffer, sizeof(buffer), block_size);
+
+    {
+      std::string string_obj = "From an object\n";
+      Printer printer(&output, '$');
+      printer.WriteRaw("Hello World!", 12);
+      printer.PrintRaw("  This is the same line.\n");
+      printer.PrintRaw("But this is a new one.\nAnd this is another one.");
+      printer.WriteRaw("\n", 1);
+      printer.PrintRaw(string_obj);
+      EXPECT_FALSE(printer.failed());
+    }
+
+    buffer[output.ByteCount()] = '\0';
+
+    EXPECT_STREQ(
+        "Hello World!  This is the same line.\n"
+        "But this is a new one.\n"
+        "And this is another one."
+        "\n"
+        "From an object\n",
+        buffer);
+  }
+}
+
+TEST(Printer, VariableSubstitution) {
+  char buffer[8192];
+
+  for (int block_size = 1; block_size < 512; block_size *= 2) {
+    ArrayOutputStream output(buffer, sizeof(buffer), block_size);
+
+    {
+      Printer printer(&output, '$');
+      std::map<std::string, std::string> vars;
+
+      vars["foo"] = "World";
+      vars["bar"] = "$foo$";
+      vars["abcdefg"] = "1234";
+
+      printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
+      printer.PrintRaw("RawBit\n");
+      printer.Print(vars, "$abcdefg$\nA literal dollar sign:  $$");
+
+      vars["foo"] = "blah";
+      printer.Print(vars, "\nNow foo = $foo$.");
+
+      EXPECT_FALSE(printer.failed());
+    }
+
+    buffer[output.ByteCount()] = '\0';
+
+    EXPECT_STREQ(
+        "Hello World!\n"
+        "bar = $foo$\n"
+        "RawBit\n"
+        "1234\n"
+        "A literal dollar sign:  $\n"
+        "Now foo = blah.",
+        buffer);
+  }
+}
+
+TEST(Printer, InlineVariableSubstitution) {
+  char buffer[8192];
+
+  ArrayOutputStream output(buffer, sizeof(buffer));
+
+  {
+    Printer printer(&output, '$');
+    printer.Print("Hello $foo$!\n", "foo", "World");
+    printer.PrintRaw("RawBit\n");
+    printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
+    EXPECT_FALSE(printer.failed());
+  }
+
+  buffer[output.ByteCount()] = '\0';
+
+  EXPECT_STREQ(
+      "Hello World!\n"
+      "RawBit\n"
+      "one two\n",
+      buffer);
+}
+
+// MockDescriptorFile defines only those members that Printer uses to write out
+// annotations.
+class MockDescriptorFile {
+ public:
+  explicit MockDescriptorFile(const std::string& file) : file_(file) {}
+
+  // The mock filename for this file.
+  const std::string& name() const { return file_; }
+
+ private:
+  std::string file_;
+};
+
+// MockDescriptor defines only those members that Printer uses to write out
+// annotations.
+class MockDescriptor {
+ public:
+  MockDescriptor(const std::string& file, const std::vector<int>& path)
+      : file_(file), path_(path) {}
+
+  // The mock file in which this descriptor was defined.
+  const MockDescriptorFile* file() const { return &file_; }
+
+ private:
+  // Allows access to GetLocationPath.
+  friend class Printer;
+
+  // Copies the pre-stored path to output.
+  void GetLocationPath(std::vector<int>* output) const { *output = path_; }
+
+  MockDescriptorFile file_;
+  std::vector<int> path_;
+};
+
+TEST(Printer, AnnotateMap) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    std::map<std::string, std::string> vars;
+    vars["foo"] = "3";
+    vars["bar"] = "5";
+    printer.Print(vars, "012$foo$4$bar$\n");
+    std::vector<int> path_1;
+    path_1.push_back(33);
+    std::vector<int> path_2;
+    path_2.push_back(11);
+    path_2.push_back(22);
+    MockDescriptor descriptor_1("path_1", path_1);
+    MockDescriptor descriptor_2("path_2", path_2);
+    printer.Annotate("foo", "foo", &descriptor_1);
+    printer.Annotate("bar", "bar", &descriptor_2);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(2, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(0)
+                                                 : &info.annotation(1);
+  const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(1)
+                                                 : &info.annotation(0);
+  ASSERT_EQ(1, foo->path_size());
+  ASSERT_EQ(2, bar->path_size());
+  EXPECT_EQ(33, foo->path(0));
+  EXPECT_EQ(11, bar->path(0));
+  EXPECT_EQ(22, bar->path(1));
+  EXPECT_EQ("path_1", foo->source_file());
+  EXPECT_EQ("path_2", bar->source_file());
+  EXPECT_EQ(3, foo->begin());
+  EXPECT_EQ(4, foo->end());
+  EXPECT_EQ(5, bar->begin());
+  EXPECT_EQ(6, bar->end());
+}
+
+TEST(Printer, AnnotateInline) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
+    std::vector<int> path_1;
+    path_1.push_back(33);
+    std::vector<int> path_2;
+    path_2.push_back(11);
+    path_2.push_back(22);
+    MockDescriptor descriptor_1("path_1", path_1);
+    MockDescriptor descriptor_2("path_2", path_2);
+    printer.Annotate("foo", "foo", &descriptor_1);
+    printer.Annotate("bar", "bar", &descriptor_2);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(2, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(0)
+                                                 : &info.annotation(1);
+  const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(1)
+                                                 : &info.annotation(0);
+  ASSERT_EQ(1, foo->path_size());
+  ASSERT_EQ(2, bar->path_size());
+  EXPECT_EQ(33, foo->path(0));
+  EXPECT_EQ(11, bar->path(0));
+  EXPECT_EQ(22, bar->path(1));
+  EXPECT_EQ("path_1", foo->source_file());
+  EXPECT_EQ("path_2", bar->source_file());
+  EXPECT_EQ(3, foo->begin());
+  EXPECT_EQ(4, foo->end());
+  EXPECT_EQ(5, bar->begin());
+  EXPECT_EQ(6, bar->end());
+}
+
+TEST(Printer, AnnotateRange) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
+    std::vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("foo", "bar", &descriptor);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foobar = &info.annotation(0);
+  ASSERT_EQ(1, foobar->path_size());
+  EXPECT_EQ(33, foobar->path(0));
+  EXPECT_EQ("path", foobar->source_file());
+  EXPECT_EQ(3, foobar->begin());
+  EXPECT_EQ(6, foobar->end());
+}
+
+TEST(Printer, AnnotateEmptyRange) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz",
+                  "", "bam", "");
+    std::vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("baz", "bam", &descriptor);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* bazbam = &info.annotation(0);
+  ASSERT_EQ(1, bazbam->path_size());
+  EXPECT_EQ(33, bazbam->path(0));
+  EXPECT_EQ("path", bazbam->source_file());
+  EXPECT_EQ(5, bazbam->begin());
+  EXPECT_EQ(5, bazbam->end());
+}
+
+TEST(Printer, AnnotateDespiteUnrelatedMultipleUses) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5");
+    std::vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("bar", "bar", &descriptor);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("0123435\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* bar = &info.annotation(0);
+  ASSERT_EQ(1, bar->path_size());
+  EXPECT_EQ(33, bar->path(0));
+  EXPECT_EQ("path", bar->source_file());
+  EXPECT_EQ(6, bar->begin());
+  EXPECT_EQ(7, bar->end());
+}
+
+TEST(Printer, AnnotateIndent) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("0\n");
+    printer.Indent();
+    printer.Print("$foo$", "foo", "4");
+    std::vector<int> path;
+    path.push_back(44);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("foo", &descriptor);
+    printer.Print(",\n");
+    printer.Print("$bar$", "bar", "9");
+    path[0] = 99;
+    MockDescriptor descriptor_two("path", path);
+    printer.Annotate("bar", &descriptor_two);
+    printer.Print("\n${$$D$$}$\n", "{", "", "}", "", "D", "d");
+    path[0] = 1313;
+    MockDescriptor descriptor_three("path", path);
+    printer.Annotate("{", "}", &descriptor_three);
+    printer.Outdent();
+    printer.Print("\n");
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("0\n  4,\n  9\n  d\n\n", buffer);
+  ASSERT_EQ(3, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foo = &info.annotation(0);
+  ASSERT_EQ(1, foo->path_size());
+  EXPECT_EQ(44, foo->path(0));
+  EXPECT_EQ("path", foo->source_file());
+  EXPECT_EQ(4, foo->begin());
+  EXPECT_EQ(5, foo->end());
+  const GeneratedCodeInfo::Annotation* bar = &info.annotation(1);
+  ASSERT_EQ(1, bar->path_size());
+  EXPECT_EQ(99, bar->path(0));
+  EXPECT_EQ("path", bar->source_file());
+  EXPECT_EQ(9, bar->begin());
+  EXPECT_EQ(10, bar->end());
+  const GeneratedCodeInfo::Annotation* braces = &info.annotation(2);
+  ASSERT_EQ(1, braces->path_size());
+  EXPECT_EQ(1313, braces->path(0));
+  EXPECT_EQ("path", braces->source_file());
+  EXPECT_EQ(13, braces->begin());
+  EXPECT_EQ(14, braces->end());
+}
+
+TEST(Printer, AnnotateIndentNewline) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Indent();
+    printer.Print("$A$$N$$B$C\n", "A", "", "N", "\nz", "B", "");
+    std::vector<int> path;
+    path.push_back(0);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("A", "B", &descriptor);
+    printer.Outdent();
+    printer.Print("\n");
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("\nz  C\n\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* ab = &info.annotation(0);
+  ASSERT_EQ(1, ab->path_size());
+  EXPECT_EQ(0, ab->path(0));
+  EXPECT_EQ("path", ab->source_file());
+  EXPECT_EQ(0, ab->begin());
+  EXPECT_EQ(4, ab->end());
+}
+
+TEST(Printer, Indenting) {
+  char buffer[8192];
+
+  for (int block_size = 1; block_size < 512; block_size *= 2) {
+    ArrayOutputStream output(buffer, sizeof(buffer), block_size);
+
+    {
+      Printer printer(&output, '$');
+      std::map<std::string, std::string> vars;
+
+      vars["newline"] = "\n";
+
+      printer.Print("This is not indented.\n");
+      printer.Indent();
+      printer.Print("This is indented\nAnd so is this\n");
+      printer.Outdent();
+      printer.Print("But this is not.");
+      printer.Indent();
+      printer.Print(
+          "  And this is still the same line.\n"
+          "But this is indented.\n");
+      printer.PrintRaw("RawBit has indent at start\n");
+      printer.PrintRaw("but not after a raw newline\n");
+      printer.Print(vars,
+                    "Note that a newline in a variable will break "
+                    "indenting, as we see$newline$here.\n");
+      printer.Indent();
+      printer.Print("And this");
+      printer.Outdent();
+      printer.Outdent();
+      printer.Print(" is double-indented\nBack to normal.");
+
+      EXPECT_FALSE(printer.failed());
+    }
+
+    buffer[output.ByteCount()] = '\0';
+
+    EXPECT_STREQ(
+        "This is not indented.\n"
+        "  This is indented\n"
+        "  And so is this\n"
+        "But this is not.  And this is still the same line.\n"
+        "  But this is indented.\n"
+        "  RawBit has indent at start\n"
+        "but not after a raw newline\n"
+        "Note that a newline in a variable will break indenting, as we see\n"
+        "here.\n"
+        "    And this is double-indented\n"
+        "Back to normal.",
+        buffer);
+  }
+}
+
+// Death tests do not work on Windows as of yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(Printer, Death) {
+  char buffer[8192];
+
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  Printer printer(&output, '$');
+
+  EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
+  EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
+  EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
+}
+
+TEST(Printer, AnnotateMultipleUsesDeath) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$foo$\n", "foo", "3");
+    std::vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    EXPECT_DEBUG_DEATH(printer.Annotate("foo", "foo", &descriptor), "multiple");
+  }
+}
+
+TEST(Printer, AnnotateNegativeLengthDeath) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
+    std::vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    EXPECT_DEBUG_DEATH(printer.Annotate("bar", "foo", &descriptor), "negative");
+  }
+}
+
+TEST(Printer, AnnotateUndefinedDeath) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$foo$\n", "foo", "3");
+    std::vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    EXPECT_DEBUG_DEATH(printer.Annotate("bar", "bar", &descriptor),
+                       "Undefined");
+  }
+}
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST(Printer, WriteFailurePartial) {
+  char buffer[17];
+
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  Printer printer(&output, '$');
+
+  // Print 16 bytes to almost fill the buffer (should not fail).
+  printer.Print("0123456789abcdef");
+  EXPECT_FALSE(printer.failed());
+
+  // Try to print 2 chars. Only one fits.
+  printer.Print("<>");
+  EXPECT_TRUE(printer.failed());
+
+  // Anything else should fail too.
+  printer.Print(" ");
+  EXPECT_TRUE(printer.failed());
+  printer.Print("blah");
+  EXPECT_TRUE(printer.failed());
+
+  // Buffer should contain the first 17 bytes written.
+  EXPECT_EQ("0123456789abcdef<", std::string(buffer, sizeof(buffer)));
+}
+
+TEST(Printer, WriteFailureExact) {
+  char buffer[16];
+
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  Printer printer(&output, '$');
+
+  // Print 16 bytes to fill the buffer exactly (should not fail).
+  printer.Print("0123456789abcdef");
+  EXPECT_FALSE(printer.failed());
+
+  // Try to print one more byte (should fail).
+  printer.Print(" ");
+  EXPECT_TRUE(printer.failed());
+
+  // Should not crash
+  printer.Print("blah");
+  EXPECT_TRUE(printer.failed());
+
+  // Buffer should contain the first 16 bytes written.
+  EXPECT_EQ("0123456789abcdef", std::string(buffer, sizeof(buffer)));
+}
+
+TEST(Printer, FormatInternal) {
+  std::vector<std::string> args{"arg1", "arg2"};
+  std::map<std::string, std::string> vars{
+      {"foo", "bar"}, {"baz", "bla"}, {"empty", ""}};
+  // Substitution tests
+  {
+    // Direct arg substitution
+    std::string s;
+    {
+      StringOutputStream output(&s);
+      Printer printer(&output, '$');
+      printer.FormatInternal(args, vars, "$1$ $2$");
+    }
+    EXPECT_EQ("arg1 arg2", s);
+  }
+  {
+    // Variable substitution including spaces left
+    std::string s;
+    {
+      StringOutputStream output(&s);
+      Printer printer(&output, '$');
+      printer.FormatInternal({}, vars, "$foo$$ baz$$ empty$");
+    }
+    EXPECT_EQ("bar bla", s);
+  }
+  {
+    // Variable substitution including spaces right
+    std::string s;
+    {
+      StringOutputStream output(&s);
+      Printer printer(&output, '$');
+      printer.FormatInternal({}, vars, "$empty $$foo $$baz$");
+    }
+    EXPECT_EQ("bar bla", s);
+  }
+  {
+    // Mixed variable substitution
+    std::string s;
+    {
+      StringOutputStream output(&s);
+      Printer printer(&output, '$');
+      printer.FormatInternal(args, vars, "$empty $$1$ $foo $$2$ $baz$");
+    }
+    EXPECT_EQ("arg1 bar arg2 bla", s);
+  }
+
+  // Indentation tests
+  {
+    // Empty lines shouldn't indent.
+    std::string s;
+    {
+      StringOutputStream output(&s);
+      Printer printer(&output, '$');
+      printer.Indent();
+      printer.FormatInternal(args, vars, "$empty $\n\n$1$ $foo $$2$\n$baz$");
+      printer.Outdent();
+    }
+    EXPECT_EQ("\n\n  arg1 bar arg2\n  bla", s);
+  }
+  {
+    // Annotations should respect indentation.
+    std::string s;
+    GeneratedCodeInfo info;
+    {
+      StringOutputStream output(&s);
+      AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+      Printer printer(&output, '$', &info_collector);
+      printer.Indent();
+      GeneratedCodeInfo::Annotation annotation;
+      annotation.set_source_file("file.proto");
+      annotation.add_path(33);
+      std::vector<std::string> args{annotation.SerializeAsString(), "arg1",
+                                    "arg2"};
+      printer.FormatInternal(args, vars, "$empty $\n\n${1$$2$$}$ $3$\n$baz$");
+      printer.Outdent();
+    }
+    EXPECT_EQ("\n\n  arg1 arg2\n  bla", s);
+    ASSERT_EQ(1, info.annotation_size());
+    const GeneratedCodeInfo::Annotation* arg1 = &info.annotation(0);
+    ASSERT_EQ(1, arg1->path_size());
+    EXPECT_EQ(33, arg1->path(0));
+    EXPECT_EQ("file.proto", arg1->source_file());
+    EXPECT_EQ(4, arg1->begin());
+    EXPECT_EQ(8, arg1->end());
+  }
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  // Death tests in case of illegal format strings.
+  {
+    // Unused arguments
+    std::string s;
+    StringOutputStream output(&s);
+    Printer printer(&output, '$');
+    EXPECT_DEATH(printer.FormatInternal(args, vars, "$empty $$1$"), "Unused");
+  }
+  {
+    // Wrong order arguments
+    std::string s;
+    StringOutputStream output(&s);
+    Printer printer(&output, '$');
+    EXPECT_DEATH(printer.FormatInternal(args, vars, "$2$ $1$"), "order");
+  }
+  {
+    // Zero is illegal argument
+    std::string s;
+    StringOutputStream output(&s);
+    Printer printer(&output, '$');
+    EXPECT_DEATH(printer.FormatInternal(args, vars, "$0$"), "failed");
+  }
+  {
+    // Argument out of bounds
+    std::string s;
+    StringOutputStream output(&s);
+    Printer printer(&output, '$');
+    EXPECT_DEATH(printer.FormatInternal(args, vars, "$1$ $2$ $3$"), "bounds");
+  }
+  {
+    // Unknown variable
+    std::string s;
+    StringOutputStream output(&s);
+    Printer printer(&output, '$');
+    EXPECT_DEATH(printer.FormatInternal(args, vars, "$huh$ $1$$2$"), "Unknown");
+  }
+  {
+    // Illegal variable
+    std::string s;
+    StringOutputStream output(&s);
+    Printer printer(&output, '$');
+    EXPECT_DEATH(printer.FormatInternal({}, vars, "$ $"), "Empty");
+  }
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/strtod.cc b/src/google/protobuf/io/strtod.cc
new file mode 100644
index 0000000..03acb5b
--- /dev/null
+++ b/src/google/protobuf/io/strtod.cc
@@ -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.
+
+#include <google/protobuf/io/strtod.h>
+
+#include <cstdio>
+#include <cstring>
+#include <limits>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// This approximately 0x1.ffffffp127, but we don't use 0x1.ffffffp127 because
+// it won't compile in MSVC.
+const double MAX_FLOAT_AS_DOUBLE_ROUNDED = 3.4028235677973366e+38;
+
+float SafeDoubleToFloat(double value) {
+  // static_cast<float> on a number larger than float can result in illegal
+  // instruction error, so we need to manually convert it to infinity or max.
+  if (value > std::numeric_limits<float>::max()) {
+    // Max float value is about 3.4028234664E38 when represented as a double.
+    // However, when printing float as text, it will be rounded as
+    // 3.4028235e+38. If we parse the value of 3.4028235e+38 from text and
+    // compare it to 3.4028234664E38, we may think that it is larger, but
+    // actually, any number between these two numbers could only be represented
+    // as the same max float number in float, so we should treat them the same
+    // as max float.
+    if (value <= MAX_FLOAT_AS_DOUBLE_ROUNDED) {
+      return std::numeric_limits<float>::max();
+    }
+    return std::numeric_limits<float>::infinity();
+  } else if (value < -std::numeric_limits<float>::max()) {
+    if (value >= -MAX_FLOAT_AS_DOUBLE_ROUNDED) {
+      return -std::numeric_limits<float>::max();
+    }
+    return -std::numeric_limits<float>::infinity();
+  } else {
+    return static_cast<float>(value);
+  }
+}
+
+double NoLocaleStrtod(const char* str, char** endptr) {
+  return google::protobuf::internal::NoLocaleStrtod(str, endptr);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/strtod.h b/src/google/protobuf/io/strtod.h
new file mode 100644
index 0000000..38f544a
--- /dev/null
+++ b/src/google/protobuf/io/strtod.h
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 locale-independent version of strtod(), used to parse floating
+// point default values in .proto files, where the decimal separator
+// is always a dot.
+
+#ifndef GOOGLE_PROTOBUF_IO_STRTOD_H__
+#define GOOGLE_PROTOBUF_IO_STRTOD_H__
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// A locale-independent version of the standard strtod(), which always
+// 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
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_IO_STRTOD_H__
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
new file mode 100644
index 0000000..f9e0776
--- /dev/null
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -0,0 +1,1239 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Here we have a hand-written lexer.  At first you might ask yourself,
+// "Hand-written text processing?  Is Kenton crazy?!"  Well, first of all,
+// yes I am crazy, but that's beside the point.  There are actually reasons
+// why I ended up writing this this way.
+//
+// The traditional approach to lexing is to use lex to generate a lexer for
+// you.  Unfortunately, lex's output is ridiculously ugly and difficult to
+// integrate cleanly with C++ code, especially abstract code or code meant
+// as a library.  Better parser-generators exist but would add dependencies
+// which most users won't already have, which we'd like to avoid.  (GNU flex
+// has a C++ output option, but it's still ridiculously ugly, non-abstract,
+// and not library-friendly.)
+//
+// The next approach that any good software engineer should look at is to
+// use regular expressions.  And, indeed, I did.  I have code which
+// implements this same class using regular expressions.  It's about 200
+// lines shorter.  However:
+// - Rather than error messages telling you "This string has an invalid
+//   escape sequence at line 5, column 45", you get error messages like
+//   "Parse error on line 5".  Giving more precise errors requires adding
+//   a lot of code that ends up basically as complex as the hand-coded
+//   version anyway.
+// - The regular expression to match a string literal looks like this:
+//     kString  = new RE("(\"([^\"\\\\]|"              // non-escaped
+//                       "\\\\[abfnrtv?\"'\\\\0-7]|"   // normal escape
+//                       "\\\\x[0-9a-fA-F])*\"|"       // hex escape
+//                       "\'([^\'\\\\]|"        // Also support single-quotes.
+//                       "\\\\[abfnrtv?\"'\\\\0-7]|"
+//                       "\\\\x[0-9a-fA-F])*\')");
+//   Verifying the correctness of this line noise is actually harder than
+//   verifying the correctness of ConsumeString(), defined below.  I'm not
+//   even confident that the above is correct, after staring at it for some
+//   time.
+// - PCRE is fast, but there's still more overhead involved than the code
+//   below.
+// - Sadly, regular expressions are not part of the C standard library, so
+//   using them would require depending on some other library.  For the
+//   open source release, this could be really annoying.  Nobody likes
+//   downloading one piece of software just to find that they need to
+//   download something else to make it work, and in all likelihood
+//   people downloading Protocol Buffers will already be doing so just
+//   to make something else work.  We could include a copy of PCRE with
+//   our code, but that obligates us to keep it up-to-date and just seems
+//   like a big waste just to save 200 lines of code.
+//
+// On a similar but unrelated note, I'm even scared to use ctype.h.
+// Apparently functions like isalpha() are locale-dependent.  So, if we used
+// that, then if this code is being called from some program that doesn't
+// have its locale set to "C", it would behave strangely.  We can't just set
+// the locale to "C" ourselves since we might break the calling program that
+// way, particularly if it is multi-threaded.  WTF?  Someone please let me
+// (Kenton) know if I'm missing something here...
+//
+// I'd love to hear about other alternatives, though, as this code isn't
+// exactly pretty.
+
+#include <google/protobuf/io/tokenizer.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace {
+
+// As mentioned above, I don't trust ctype.h due to the presence of "locales".
+// So, I have written replacement functions here.  Someone please smack me if
+// this is a bad idea or if there is some way around this.
+//
+// These "character classes" are designed to be used in template methods.
+// For instance, Tokenizer::ConsumeZeroOrMore<Whitespace>() will eat
+// whitespace.
+
+// Note:  No class is allowed to contain '\0', since this is used to mark end-
+//   of-input and is handled specially.
+
+#define CHARACTER_CLASS(NAME, EXPRESSION)                     \
+  class NAME {                                                \
+   public:                                                    \
+    static inline bool InClass(char c) { return EXPRESSION; } \
+  }
+
+CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || c == '\r' ||
+                                c == '\v' || c == '\f');
+CHARACTER_CLASS(WhitespaceNoNewline,
+                c == ' ' || c == '\t' || c == '\r' || c == '\v' || c == '\f');
+
+CHARACTER_CLASS(Unprintable, c<' ' && c> '\0');
+
+CHARACTER_CLASS(Digit, '0' <= c && c <= '9');
+CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7');
+CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
+                              ('A' <= c && c <= 'F'));
+
+CHARACTER_CLASS(Letter,
+                ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_'));
+
+CHARACTER_CLASS(Alphanumeric, ('a' <= c && c <= 'z') ||
+                                  ('A' <= c && c <= 'Z') ||
+                                  ('0' <= c && c <= '9') || (c == '_'));
+
+CHARACTER_CLASS(Escape, c == 'a' || c == 'b' || c == 'f' || c == 'n' ||
+                            c == 'r' || c == 't' || c == 'v' || c == '\\' ||
+                            c == '?' || c == '\'' || c == '\"');
+
+#undef CHARACTER_CLASS
+
+// Given a char, interpret it as a numeric digit and return its value.
+// This supports any number base up to 36.
+// Represents integer values of digits.
+// Uses 36 to indicate an invalid character since we support
+// bases up to 36.
+static const int8_t kAsciiToInt[256] = {
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 00-0F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 10-1F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // ' '-'/'
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,                           // '0'-'9'
+    36, 36, 36, 36, 36, 36, 36,                                      // ':'-'@'
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  // 'A'-'P'
+    26, 27, 28, 29, 30, 31, 32, 33, 34, 35,                          // 'Q'-'Z'
+    36, 36, 36, 36, 36, 36,                                          // '['-'`'
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  // 'a'-'p'
+    26, 27, 28, 29, 30, 31, 32, 33, 34, 35,                          // 'q'-'z'
+    36, 36, 36, 36, 36,                                              // '{'-DEL
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 80-8F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 90-9F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // A0-AF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // B0-BF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // C0-CF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // D0-DF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // E0-EF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // F0-FF
+};
+
+inline int DigitValue(char digit) { return kAsciiToInt[digit & 0xFF]; }
+
+// Inline because it's only used in one place.
+inline char TranslateEscape(char c) {
+  switch (c) {
+    case 'a':
+      return '\a';
+    case 'b':
+      return '\b';
+    case 'f':
+      return '\f';
+    case 'n':
+      return '\n';
+    case 'r':
+      return '\r';
+    case 't':
+      return '\t';
+    case 'v':
+      return '\v';
+    case '\\':
+      return '\\';
+    case '?':
+      return '\?';  // Trigraphs = :(
+    case '\'':
+      return '\'';
+    case '"':
+      return '\"';
+
+    // We expect escape sequences to have been validated separately.
+    default:
+      return '?';
+  }
+}
+
+}  // anonymous namespace
+
+ErrorCollector::~ErrorCollector() {}
+
+// ===================================================================
+
+Tokenizer::Tokenizer(ZeroCopyInputStream* input,
+                     ErrorCollector* error_collector)
+    : input_(input),
+      error_collector_(error_collector),
+      buffer_(NULL),
+      buffer_size_(0),
+      buffer_pos_(0),
+      read_error_(false),
+      line_(0),
+      column_(0),
+      record_target_(NULL),
+      record_start_(-1),
+      allow_f_after_float_(false),
+      comment_style_(CPP_COMMENT_STYLE),
+      require_space_after_number_(true),
+      allow_multiline_strings_(false) {
+  current_.line = 0;
+  current_.column = 0;
+  current_.end_column = 0;
+  current_.type = TYPE_START;
+
+  Refresh();
+}
+
+Tokenizer::~Tokenizer() {
+  // If we had any buffer left unread, return it to the underlying stream
+  // so that someone else can read it.
+  if (buffer_size_ > buffer_pos_) {
+    input_->BackUp(buffer_size_ - buffer_pos_);
+  }
+}
+
+bool Tokenizer::report_whitespace() const { return report_whitespace_; }
+// Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
+void Tokenizer::set_report_whitespace(bool report) {
+  report_whitespace_ = report;
+  report_newlines_ &= report;
+}
+
+// If true, newline tokens are reported by Next().
+bool Tokenizer::report_newlines() const { return report_newlines_; }
+// Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
+void Tokenizer::set_report_newlines(bool report) {
+  report_newlines_ = report;
+  report_whitespace_ |= report;  // enable report_whitespace if necessary
+}
+
+// -------------------------------------------------------------------
+// Internal helpers.
+
+void Tokenizer::NextChar() {
+  // Update our line and column counters based on the character being
+  // consumed.
+  if (current_char_ == '\n') {
+    ++line_;
+    column_ = 0;
+  } else if (current_char_ == '\t') {
+    column_ += kTabWidth - column_ % kTabWidth;
+  } else {
+    ++column_;
+  }
+
+  // Advance to the next character.
+  ++buffer_pos_;
+  if (buffer_pos_ < buffer_size_) {
+    current_char_ = buffer_[buffer_pos_];
+  } else {
+    Refresh();
+  }
+}
+
+void Tokenizer::Refresh() {
+  if (read_error_) {
+    current_char_ = '\0';
+    return;
+  }
+
+  // If we're in a token, append the rest of the buffer to it.
+  if (record_target_ != NULL && record_start_ < buffer_size_) {
+    record_target_->append(buffer_ + record_start_,
+                           buffer_size_ - record_start_);
+    record_start_ = 0;
+  }
+
+  const void* data = NULL;
+  buffer_ = NULL;
+  buffer_pos_ = 0;
+  do {
+    if (!input_->Next(&data, &buffer_size_)) {
+      // end of stream (or read error)
+      buffer_size_ = 0;
+      read_error_ = true;
+      current_char_ = '\0';
+      return;
+    }
+  } while (buffer_size_ == 0);
+
+  buffer_ = static_cast<const char*>(data);
+
+  current_char_ = buffer_[0];
+}
+
+inline void Tokenizer::RecordTo(std::string* target) {
+  record_target_ = target;
+  record_start_ = buffer_pos_;
+}
+
+inline void Tokenizer::StopRecording() {
+  // Note:  The if() is necessary because some STL implementations crash when
+  //   you call string::append(NULL, 0), presumably because they are trying to
+  //   be helpful by detecting the NULL pointer, even though there's nothing
+  //   wrong with reading zero bytes from NULL.
+  if (buffer_pos_ != record_start_) {
+    record_target_->append(buffer_ + record_start_,
+                           buffer_pos_ - record_start_);
+  }
+  record_target_ = NULL;
+  record_start_ = -1;
+}
+
+inline void Tokenizer::StartToken() {
+  current_.type = TYPE_START;  // Just for the sake of initializing it.
+  current_.text.clear();
+  current_.line = line_;
+  current_.column = column_;
+  RecordTo(&current_.text);
+}
+
+inline void Tokenizer::EndToken() {
+  StopRecording();
+  current_.end_column = column_;
+}
+
+// -------------------------------------------------------------------
+// Helper methods that consume characters.
+
+template <typename CharacterClass>
+inline bool Tokenizer::LookingAt() {
+  return CharacterClass::InClass(current_char_);
+}
+
+template <typename CharacterClass>
+inline bool Tokenizer::TryConsumeOne() {
+  if (CharacterClass::InClass(current_char_)) {
+    NextChar();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline bool Tokenizer::TryConsume(char c) {
+  if (current_char_ == c) {
+    NextChar();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+template <typename CharacterClass>
+inline void Tokenizer::ConsumeZeroOrMore() {
+  while (CharacterClass::InClass(current_char_)) {
+    NextChar();
+  }
+}
+
+template <typename CharacterClass>
+inline void Tokenizer::ConsumeOneOrMore(const char* error) {
+  if (!CharacterClass::InClass(current_char_)) {
+    AddError(error);
+  } else {
+    do {
+      NextChar();
+    } while (CharacterClass::InClass(current_char_));
+  }
+}
+
+// -------------------------------------------------------------------
+// Methods that read whole patterns matching certain kinds of tokens
+// or comments.
+
+void Tokenizer::ConsumeString(char delimiter) {
+  while (true) {
+    switch (current_char_) {
+      case '\0':
+        AddError("Unexpected end of string.");
+        return;
+
+      case '\n': {
+        if (!allow_multiline_strings_) {
+          AddError("String literals cannot cross line boundaries.");
+          return;
+        }
+        NextChar();
+        break;
+      }
+
+      case '\\': {
+        // An escape sequence.
+        NextChar();
+        if (TryConsumeOne<Escape>()) {
+          // Valid escape sequence.
+        } else if (TryConsumeOne<OctalDigit>()) {
+          // 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')) {
+          if (!TryConsumeOne<HexDigit>()) {
+            AddError("Expected hex digits for escape sequence.");
+          }
+          // Possibly followed by another hex digit, but again we don't care.
+        } else if (TryConsume('u')) {
+          if (!TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
+              !TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>()) {
+            AddError("Expected four hex digits for \\u escape sequence.");
+          }
+        } else if (TryConsume('U')) {
+          // We expect 8 hex digits; but only the range up to 0x10ffff is
+          // legal.
+          if (!TryConsume('0') || !TryConsume('0') ||
+              !(TryConsume('0') || TryConsume('1')) ||
+              !TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
+              !TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
+              !TryConsumeOne<HexDigit>()) {
+            AddError(
+                "Expected eight hex digits up to 10ffff for \\U escape "
+                "sequence");
+          }
+        } else {
+          AddError("Invalid escape sequence in string literal.");
+        }
+        break;
+      }
+
+      default: {
+        if (current_char_ == delimiter) {
+          NextChar();
+          return;
+        }
+        NextChar();
+        break;
+      }
+    }
+  }
+}
+
+Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
+                                              bool started_with_dot) {
+  bool is_float = false;
+
+  if (started_with_zero && (TryConsume('x') || TryConsume('X'))) {
+    // A hex number (started with "0x").
+    ConsumeOneOrMore<HexDigit>("\"0x\" must be followed by hex digits.");
+
+  } else if (started_with_zero && LookingAt<Digit>()) {
+    // An octal number (had a leading zero).
+    ConsumeZeroOrMore<OctalDigit>();
+    if (LookingAt<Digit>()) {
+      AddError("Numbers starting with leading zero must be in octal.");
+      ConsumeZeroOrMore<Digit>();
+    }
+
+  } else {
+    // A decimal number.
+    if (started_with_dot) {
+      is_float = true;
+      ConsumeZeroOrMore<Digit>();
+    } else {
+      ConsumeZeroOrMore<Digit>();
+
+      if (TryConsume('.')) {
+        is_float = true;
+        ConsumeZeroOrMore<Digit>();
+      }
+    }
+
+    if (TryConsume('e') || TryConsume('E')) {
+      is_float = true;
+      TryConsume('-') || TryConsume('+');
+      ConsumeOneOrMore<Digit>("\"e\" must be followed by exponent.");
+    }
+
+    if (allow_f_after_float_ && (TryConsume('f') || TryConsume('F'))) {
+      is_float = true;
+    }
+  }
+
+  if (LookingAt<Letter>() && require_space_after_number_) {
+    AddError("Need space between number and identifier.");
+  } else if (current_char_ == '.') {
+    if (is_float) {
+      AddError(
+          "Already saw decimal point or exponent; can't have another one.");
+    } else {
+      AddError("Hex and octal numbers must be integers.");
+    }
+  }
+
+  return is_float ? TYPE_FLOAT : TYPE_INTEGER;
+}
+
+void Tokenizer::ConsumeLineComment(std::string* content) {
+  if (content != NULL) RecordTo(content);
+
+  while (current_char_ != '\0' && current_char_ != '\n') {
+    NextChar();
+  }
+  TryConsume('\n');
+
+  if (content != NULL) StopRecording();
+}
+
+void Tokenizer::ConsumeBlockComment(std::string* content) {
+  int start_line = line_;
+  int start_column = column_ - 2;
+
+  if (content != NULL) RecordTo(content);
+
+  while (true) {
+    while (current_char_ != '\0' && current_char_ != '*' &&
+           current_char_ != '/' && current_char_ != '\n') {
+      NextChar();
+    }
+
+    if (TryConsume('\n')) {
+      if (content != NULL) StopRecording();
+
+      // Consume leading whitespace and asterisk;
+      ConsumeZeroOrMore<WhitespaceNoNewline>();
+      if (TryConsume('*')) {
+        if (TryConsume('/')) {
+          // End of comment.
+          break;
+        }
+      }
+
+      if (content != NULL) RecordTo(content);
+    } else if (TryConsume('*') && TryConsume('/')) {
+      // End of comment.
+      if (content != NULL) {
+        StopRecording();
+        // Strip trailing "*/".
+        content->erase(content->size() - 2);
+      }
+      break;
+    } else if (TryConsume('/') && current_char_ == '*') {
+      // Note:  We didn't consume the '*' because if there is a '/' after it
+      //   we want to interpret that as the end of the comment.
+      AddError(
+          "\"/*\" inside block comment.  Block comments cannot be nested.");
+    } else if (current_char_ == '\0') {
+      AddError("End-of-file inside block comment.");
+      error_collector_->AddError(start_line, start_column,
+                                 "  Comment started here.");
+      if (content != NULL) StopRecording();
+      break;
+    }
+  }
+}
+
+Tokenizer::NextCommentStatus Tokenizer::TryConsumeCommentStart() {
+  if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
+    if (TryConsume('/')) {
+      return LINE_COMMENT;
+    } else if (TryConsume('*')) {
+      return BLOCK_COMMENT;
+    } else {
+      // Oops, it was just a slash.  Return it.
+      current_.type = TYPE_SYMBOL;
+      current_.text = "/";
+      current_.line = line_;
+      current_.column = column_ - 1;
+      current_.end_column = column_;
+      return SLASH_NOT_COMMENT;
+    }
+  } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
+    return LINE_COMMENT;
+  } else {
+    return NO_COMMENT;
+  }
+}
+
+bool Tokenizer::TryConsumeWhitespace() {
+  if (report_newlines_) {
+    if (TryConsumeOne<WhitespaceNoNewline>()) {
+      ConsumeZeroOrMore<WhitespaceNoNewline>();
+      current_.type = TYPE_WHITESPACE;
+      return true;
+    }
+    return false;
+  }
+  if (TryConsumeOne<Whitespace>()) {
+    ConsumeZeroOrMore<Whitespace>();
+    current_.type = TYPE_WHITESPACE;
+    return report_whitespace_;
+  }
+  return false;
+}
+
+bool Tokenizer::TryConsumeNewline() {
+  if (!report_whitespace_ || !report_newlines_) {
+    return false;
+  }
+  if (TryConsume('\n')) {
+    current_.type = TYPE_NEWLINE;
+    return true;
+  }
+  return false;
+}
+
+// -------------------------------------------------------------------
+
+bool Tokenizer::Next() {
+  previous_ = current_;
+
+  while (!read_error_) {
+    StartToken();
+    bool report_token = TryConsumeWhitespace() || TryConsumeNewline();
+    EndToken();
+    if (report_token) {
+      return true;
+    }
+
+    switch (TryConsumeCommentStart()) {
+      case LINE_COMMENT:
+        ConsumeLineComment(NULL);
+        continue;
+      case BLOCK_COMMENT:
+        ConsumeBlockComment(NULL);
+        continue;
+      case SLASH_NOT_COMMENT:
+        return true;
+      case NO_COMMENT:
+        break;
+    }
+
+    // Check for EOF before continuing.
+    if (read_error_) break;
+
+    if (LookingAt<Unprintable>() || current_char_ == '\0') {
+      AddError("Invalid control characters encountered in text.");
+      NextChar();
+      // Skip more unprintable characters, too.  But, remember that '\0' is
+      // also what current_char_ is set to after EOF / read error.  We have
+      // to be careful not to go into an infinite loop of trying to consume
+      // it, so make sure to check read_error_ explicitly before consuming
+      // '\0'.
+      while (TryConsumeOne<Unprintable>() ||
+             (!read_error_ && TryConsume('\0'))) {
+        // Ignore.
+      }
+
+    } else {
+      // Reading some sort of token.
+      StartToken();
+
+      if (TryConsumeOne<Letter>()) {
+        ConsumeZeroOrMore<Alphanumeric>();
+        current_.type = TYPE_IDENTIFIER;
+      } else if (TryConsume('0')) {
+        current_.type = ConsumeNumber(true, false);
+      } else if (TryConsume('.')) {
+        // This could be the beginning of a floating-point number, or it could
+        // just be a '.' symbol.
+
+        if (TryConsumeOne<Digit>()) {
+          // It's a floating-point number.
+          if (previous_.type == TYPE_IDENTIFIER &&
+              current_.line == previous_.line &&
+              current_.column == previous_.end_column) {
+            // We don't accept syntax like "blah.123".
+            error_collector_->AddError(
+                line_, column_ - 2,
+                "Need space between identifier and decimal point.");
+          }
+          current_.type = ConsumeNumber(false, true);
+        } else {
+          current_.type = TYPE_SYMBOL;
+        }
+      } else if (TryConsumeOne<Digit>()) {
+        current_.type = ConsumeNumber(false, false);
+      } else if (TryConsume('\"')) {
+        ConsumeString('\"');
+        current_.type = TYPE_STRING;
+      } else if (TryConsume('\'')) {
+        ConsumeString('\'');
+        current_.type = TYPE_STRING;
+      } else {
+        // Check if the high order bit is set.
+        if (current_char_ & 0x80) {
+          error_collector_->AddError(
+              line_, column_,
+              StringPrintf("Interpreting non ascii codepoint %d.",
+                              static_cast<unsigned char>(current_char_)));
+        }
+        NextChar();
+        current_.type = TYPE_SYMBOL;
+      }
+
+      EndToken();
+      return true;
+    }
+  }
+
+  // EOF
+  current_.type = TYPE_END;
+  current_.text.clear();
+  current_.line = line_;
+  current_.column = column_;
+  current_.end_column = column_;
+  return false;
+}
+
+namespace {
+
+// Helper class for collecting comments and putting them in the right places.
+//
+// This basically just buffers the most recent comment until it can be decided
+// exactly where that comment should be placed.  When Flush() is called, the
+// current comment goes into either prev_trailing_comments or detached_comments.
+// When the CommentCollector is destroyed, the last buffered comment goes into
+// next_leading_comments.
+class CommentCollector {
+ public:
+  CommentCollector(std::string* prev_trailing_comments,
+                   std::vector<std::string>* detached_comments,
+                   std::string* next_leading_comments)
+      : prev_trailing_comments_(prev_trailing_comments),
+        detached_comments_(detached_comments),
+        next_leading_comments_(next_leading_comments),
+        has_comment_(false),
+        is_line_comment_(false),
+        can_attach_to_prev_(true) {
+    if (prev_trailing_comments != NULL) prev_trailing_comments->clear();
+    if (detached_comments != NULL) detached_comments->clear();
+    if (next_leading_comments != NULL) next_leading_comments->clear();
+  }
+
+  ~CommentCollector() {
+    // Whatever is in the buffer is a leading comment.
+    if (next_leading_comments_ != NULL && has_comment_) {
+      comment_buffer_.swap(*next_leading_comments_);
+    }
+  }
+
+  // About to read a line comment.  Get the comment buffer pointer in order to
+  // read into it.
+  std::string* GetBufferForLineComment() {
+    // We want to combine with previous line comments, but not block comments.
+    if (has_comment_ && !is_line_comment_) {
+      Flush();
+    }
+    has_comment_ = true;
+    is_line_comment_ = true;
+    return &comment_buffer_;
+  }
+
+  // About to read a block comment.  Get the comment buffer pointer in order to
+  // read into it.
+  std::string* GetBufferForBlockComment() {
+    if (has_comment_) {
+      Flush();
+    }
+    has_comment_ = true;
+    is_line_comment_ = false;
+    return &comment_buffer_;
+  }
+
+  void ClearBuffer() {
+    comment_buffer_.clear();
+    has_comment_ = false;
+  }
+
+  // Called once we know that the comment buffer is complete and is *not*
+  // connected to the next token.
+  void Flush() {
+    if (has_comment_) {
+      if (can_attach_to_prev_) {
+        if (prev_trailing_comments_ != NULL) {
+          prev_trailing_comments_->append(comment_buffer_);
+        }
+        can_attach_to_prev_ = false;
+      } else {
+        if (detached_comments_ != NULL) {
+          detached_comments_->push_back(comment_buffer_);
+        }
+      }
+      ClearBuffer();
+    }
+  }
+
+  void DetachFromPrev() { can_attach_to_prev_ = false; }
+
+ private:
+  std::string* prev_trailing_comments_;
+  std::vector<std::string>* detached_comments_;
+  std::string* next_leading_comments_;
+
+  std::string comment_buffer_;
+
+  // True if any comments were read into comment_buffer_.  This can be true even
+  // if comment_buffer_ is empty, namely if the comment was "/**/".
+  bool has_comment_;
+
+  // Is the comment in the comment buffer a line comment?
+  bool is_line_comment_;
+
+  // Is it still possible that we could be reading a comment attached to the
+  // previous token?
+  bool can_attach_to_prev_;
+};
+
+}  // namespace
+
+bool Tokenizer::NextWithComments(std::string* prev_trailing_comments,
+                                 std::vector<std::string>* detached_comments,
+                                 std::string* next_leading_comments) {
+  CommentCollector collector(prev_trailing_comments, detached_comments,
+                             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(static_cast<char>(0xEF))) {
+      if (!TryConsume(static_cast<char>(0xBB)) ||
+          !TryConsume(static_cast<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
+    // declaration.
+    ConsumeZeroOrMore<WhitespaceNoNewline>();
+    switch (TryConsumeCommentStart()) {
+      case LINE_COMMENT:
+        ConsumeLineComment(collector.GetBufferForLineComment());
+
+        // Don't allow comments on subsequent lines to be attached to a trailing
+        // comment.
+        collector.Flush();
+        break;
+      case BLOCK_COMMENT:
+        ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+        ConsumeZeroOrMore<WhitespaceNoNewline>();
+        if (!TryConsume('\n')) {
+          // Oops, the next token is on the same line.  If we recorded a comment
+          // we really have no idea which token it should be attached to.
+          collector.ClearBuffer();
+          return Next();
+        }
+
+        // Don't allow comments on subsequent lines to be attached to a trailing
+        // comment.
+        collector.Flush();
+        break;
+      case SLASH_NOT_COMMENT:
+        return true;
+      case NO_COMMENT:
+        if (!TryConsume('\n')) {
+          // The next token is on the same line.  There are no comments.
+          return Next();
+        }
+        break;
+    }
+  }
+
+  // OK, we are now on the line *after* the previous token.
+  while (true) {
+    ConsumeZeroOrMore<WhitespaceNoNewline>();
+
+    switch (TryConsumeCommentStart()) {
+      case LINE_COMMENT:
+        ConsumeLineComment(collector.GetBufferForLineComment());
+        break;
+      case BLOCK_COMMENT:
+        ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+        // Consume the rest of the line so that we don't interpret it as a
+        // blank line the next time around the loop.
+        ConsumeZeroOrMore<WhitespaceNoNewline>();
+        TryConsume('\n');
+        break;
+      case SLASH_NOT_COMMENT:
+        return true;
+      case NO_COMMENT:
+        if (TryConsume('\n')) {
+          // Completely blank line.
+          collector.Flush();
+          collector.DetachFromPrev();
+        } else {
+          bool result = Next();
+          if (!result || current_.text == "}" || current_.text == "]" ||
+              current_.text == ")") {
+            // It looks like we're at the end of a scope.  In this case it
+            // makes no sense to attach a comment to the following token.
+            collector.Flush();
+          }
+          return result;
+        }
+        break;
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+// Token-parsing helpers.  Remember that these don't need to report
+// errors since any errors should already have been reported while
+// tokenizing.  Also, these can assume that whatever text they
+// are given is text that the tokenizer actually parsed as a token
+// of the given type.
+
+bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
+                             uint64_t* output) {
+  // We can't just use strtoull() because (a) it accepts negative numbers,
+  // (b) We want additional range checks, (c) it reports overflows via errno.
+
+#if 0
+  const char *str_begin = text.c_str();
+  if (*str_begin == '-') return false;
+  char *str_end = nullptr;
+  errno = 0;
+  *output = std::strtoull(str_begin, &str_end, 0);
+  return (errno == 0 && str_end && *str_end == '\0' && *output <= max_value);
+#endif
+
+  const char* ptr = text.c_str();
+  int base = 10;
+  uint64_t overflow_if_mul_base = (kuint64max / 10) + 1;
+  if (ptr[0] == '0') {
+    if (ptr[1] == 'x' || ptr[1] == 'X') {
+      // This is hex.
+      base = 16;
+      overflow_if_mul_base = (kuint64max / 16) + 1;
+      ptr += 2;
+    } else {
+      // This is octal.
+      base = 8;
+      overflow_if_mul_base = (kuint64max / 8) + 1;
+    }
+  }
+
+  uint64_t result = 0;
+  // For all the leading '0's, and also the first non-zero character, we
+  // don't need to multiply.
+  while (*ptr != '\0') {
+    int digit = DigitValue(*ptr++);
+    if (digit >= base) {
+      // The token provided by Tokenizer is invalid. i.e., 099 is an invalid
+      // token, but Tokenizer still think it's integer.
+      return false;
+    }
+    if (digit != 0) {
+      result = digit;
+      break;
+    }
+  }
+  for (; *ptr != '\0'; ptr++) {
+    int digit = DigitValue(*ptr);
+    if (digit < 0 || digit >= base) {
+      // The token provided by Tokenizer is invalid. i.e., 099 is an invalid
+      // token, but Tokenizer still think it's integer.
+      return false;
+    }
+    if (result >= overflow_if_mul_base) {
+      // We know the multiply we're about to do will overflow, so exit now.
+      return false;
+    }
+    // We know that result * base won't overflow, but adding digit might...
+    result = result * base + digit;
+    // C++ guarantees defined "wrap" semantics when unsigned integer
+    // operations overflow, making this a fast way to check if adding
+    // digit made result overflow, and thus, wrap around.
+    if (result < static_cast<uint64_t>(base)) return false;
+  }
+  if (result > max_value) return false;
+
+  *output = result;
+  return true;
+}
+
+double Tokenizer::ParseFloat(const std::string& text) {
+  const char* start = text.c_str();
+  char* end;
+  double result = NoLocaleStrtod(start, &end);
+
+  // "1e" is not a valid float, but if the tokenizer reads it, it will
+  // report an error but still return it as a valid token.  We need to
+  // accept anything the tokenizer could possibly return, error or not.
+  if (*end == 'e' || *end == 'E') {
+    ++end;
+    if (*end == '-' || *end == '+') ++end;
+  }
+
+  // If the Tokenizer had allow_f_after_float_ enabled, the float may be
+  // suffixed with the letter 'f'.
+  if (*end == 'f' || *end == 'F') {
+    ++end;
+  }
+
+  GOOGLE_LOG_IF(DFATAL,
+         static_cast<size_t>(end - start) != text.size() || *start == '-')
+      << " Tokenizer::ParseFloat() passed text that could not have been"
+         " tokenized as a float: "
+      << CEscape(text);
+  return result;
+}
+
+// Helper to append a Unicode code point to a string as UTF8, without bringing
+// in any external dependencies.
+static void AppendUTF8(uint32_t code_point, std::string* output) {
+  uint32_t 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 if (code_point <= 0x10ffff) {
+    tmp = 0xf0808080 | ((code_point & 0x1c0000) << 6) |
+          ((code_point & 0x03f000) << 4) | ((code_point & 0x000fc0) << 2) |
+          (code_point & 0x003f);
+    len = 4;
+  } else {
+    // Unicode code points end at 0x10FFFF, so this is out-of-range.
+    // ConsumeString permits hex values up to 0x1FFFFF, and FetchUnicodePoint
+    // doesn't perform a range check.
+    StringAppendF(output, "\\U%08x", code_point);
+    return;
+  }
+  tmp = ghtonl(tmp);
+  output->append(reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+}
+
+// Try to read <len> hex digits from ptr, and stuff the numeric result into
+// *result. Returns true if that many digits were successfully consumed.
+static bool ReadHexDigits(const char* ptr, int len, uint32_t* result) {
+  *result = 0;
+  if (len == 0) return false;
+  for (const char* end = ptr + len; ptr < end; ++ptr) {
+    if (*ptr == '\0') return false;
+    *result = (*result << 4) + DigitValue(*ptr);
+  }
+  return true;
+}
+
+// Handling UTF-16 surrogate pairs. UTF-16 encodes code points in the range
+// 0x10000...0x10ffff as a pair of numbers, a head surrogate followed by a trail
+// surrogate. These numbers are in a reserved range of Unicode code points, so
+// if we encounter such a pair we know how to parse it and convert it into a
+// single code point.
+static const uint32_t kMinHeadSurrogate = 0xd800;
+static const uint32_t kMaxHeadSurrogate = 0xdc00;
+static const uint32_t kMinTrailSurrogate = 0xdc00;
+static const uint32_t kMaxTrailSurrogate = 0xe000;
+
+static inline bool IsHeadSurrogate(uint32_t code_point) {
+  return (code_point >= kMinHeadSurrogate) && (code_point < kMaxHeadSurrogate);
+}
+
+static inline bool IsTrailSurrogate(uint32_t code_point) {
+  return (code_point >= kMinTrailSurrogate) &&
+         (code_point < kMaxTrailSurrogate);
+}
+
+// Combine a head and trail surrogate into a single Unicode code point.
+static uint32_t AssembleUTF16(uint32_t head_surrogate,
+                              uint32_t trail_surrogate) {
+  GOOGLE_DCHECK(IsHeadSurrogate(head_surrogate));
+  GOOGLE_DCHECK(IsTrailSurrogate(trail_surrogate));
+  return 0x10000 + (((head_surrogate - kMinHeadSurrogate) << 10) |
+                    (trail_surrogate - kMinTrailSurrogate));
+}
+
+// Convert the escape sequence parameter to a number of expected hex digits.
+static inline int UnicodeLength(char key) {
+  if (key == 'u') return 4;
+  if (key == 'U') return 8;
+  return 0;
+}
+
+// Given a pointer to the 'u' or 'U' starting a Unicode escape sequence, attempt
+// to parse that sequence. On success, returns a pointer to the first char
+// beyond that sequence, and fills in *code_point. On failure, returns ptr
+// itself.
+static const char* FetchUnicodePoint(const char* ptr, uint32_t* code_point) {
+  const char* p = ptr;
+  // Fetch the code point.
+  const int len = UnicodeLength(*p++);
+  if (!ReadHexDigits(p, len, code_point)) return ptr;
+  p += len;
+
+  // Check if the code point we read is a "head surrogate." If so, then we
+  // expect it to be immediately followed by another code point which is a valid
+  // "trail surrogate," and together they form a UTF-16 pair which decodes into
+  // a single Unicode point. Trail surrogates may only use \u, not \U.
+  if (IsHeadSurrogate(*code_point) && *p == '\\' && *(p + 1) == 'u') {
+    uint32_t trail_surrogate;
+    if (ReadHexDigits(p + 2, 4, &trail_surrogate) &&
+        IsTrailSurrogate(trail_surrogate)) {
+      *code_point = AssembleUTF16(*code_point, trail_surrogate);
+      p += 6;
+    }
+    // If this failed, then we just emit the head surrogate as a code point.
+    // It's bogus, but so is the string.
+  }
+
+  return p;
+}
+
+// The text string must begin and end with single or double quote
+// characters.
+void Tokenizer::ParseStringAppend(const std::string& text,
+                                  std::string* output) {
+  // Reminder: text[0] is always a quote character.  (If text is
+  // empty, it's invalid, so we'll just return).
+  const size_t text_size = text.size();
+  if (text_size == 0) {
+    GOOGLE_LOG(DFATAL) << " Tokenizer::ParseStringAppend() passed text that could not"
+                   " have been tokenized as a string: "
+                << CEscape(text);
+    return;
+  }
+
+  // Reserve room for new string. The branch is necessary because if
+  // there is already space available the reserve() call might
+  // downsize the output.
+  const size_t new_len = text_size + output->size();
+  if (new_len > output->capacity()) {
+    output->reserve(new_len);
+  }
+
+  // Loop through the string copying characters to "output" and
+  // interpreting escape sequences.  Note that any invalid escape
+  // sequences or other errors were already reported while tokenizing.
+  // In this case we do not need to produce valid results.
+  for (const char* ptr = text.c_str() + 1; *ptr != '\0'; ptr++) {
+    if (*ptr == '\\' && ptr[1] != '\0') {
+      // An escape sequence.
+      ++ptr;
+
+      if (OctalDigit::InClass(*ptr)) {
+        // An octal escape.  May one, two, or three digits.
+        int code = DigitValue(*ptr);
+        if (OctalDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = code * 8 + DigitValue(*ptr);
+        }
+        if (OctalDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = code * 8 + DigitValue(*ptr);
+        }
+        output->push_back(static_cast<char>(code));
+
+      } else if (*ptr == 'x') {
+        // A hex escape.  May zero, one, or two digits.  (The zero case
+        // will have been caught as an error earlier.)
+        int code = 0;
+        if (HexDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = DigitValue(*ptr);
+        }
+        if (HexDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = code * 16 + DigitValue(*ptr);
+        }
+        output->push_back(static_cast<char>(code));
+
+      } else if (*ptr == 'u' || *ptr == 'U') {
+        uint32_t unicode;
+        const char* end = FetchUnicodePoint(ptr, &unicode);
+        if (end == ptr) {
+          // Failure: Just dump out what we saw, don't try to parse it.
+          output->push_back(*ptr);
+        } else {
+          AppendUTF8(unicode, output);
+          ptr = end - 1;  // Because we're about to ++ptr.
+        }
+      } else {
+        // Some other escape code.
+        output->push_back(TranslateEscape(*ptr));
+      }
+
+    } else if (*ptr == text[0] && ptr[1] == '\0') {
+      // Ignore final quote matching the starting quote.
+    } else {
+      output->push_back(*ptr);
+    }
+  }
+}
+
+template <typename CharacterClass>
+static bool AllInClass(const std::string& s) {
+  for (const char character : s) {
+    if (!CharacterClass::InClass(character)) return false;
+  }
+  return true;
+}
+
+bool Tokenizer::IsIdentifier(const std::string& text) {
+  // Mirrors IDENTIFIER definition in Tokenizer::Next() above.
+  if (text.size() == 0) return false;
+  if (!Letter::InClass(text.at(0))) return false;
+  if (!AllInClass<Alphanumeric>(text.substr(1))) return false;
+  return true;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
new file mode 100644
index 0000000..4abab7e
--- /dev/null
+++ b/src/google/protobuf/io/tokenizer.h
@@ -0,0 +1,442 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Class for parsing tokenized text from a ZeroCopyInputStream.
+
+#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
+#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
+
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+class ZeroCopyInputStream;  // zero_copy_stream.h
+
+// Defined in this file.
+class ErrorCollector;
+class Tokenizer;
+
+// By "column number", the proto compiler refers to a count of the number
+// of bytes before a given byte, except that a tab character advances to
+// the next multiple of 8 bytes.  Note in particular that column numbers
+// are zero-based, while many user interfaces use one-based column numbers.
+typedef int ColumnNumber;
+
+// Abstract interface for an object which collects the errors that occur
+// during parsing.  A typical implementation might simply print the errors
+// to stdout.
+class PROTOBUF_EXPORT ErrorCollector {
+ public:
+  inline ErrorCollector() {}
+  virtual ~ErrorCollector();
+
+  // Indicates that there was an error in the input at the given line and
+  // column numbers.  The numbers are zero-based, so you may want to add
+  // 1 to each before printing them.
+  virtual void AddError(int line, ColumnNumber column,
+                        const std::string& message) = 0;
+
+  // Indicates that there was a warning in the input at the given line and
+  // column numbers.  The numbers are zero-based, so you may want to add
+  // 1 to each before printing them.
+  virtual void AddWarning(int /* line */, ColumnNumber /* column */,
+                          const std::string& /* message */) {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
+};
+
+// This class converts a stream of raw text into a stream of tokens for
+// the protocol definition parser to parse.  The tokens recognized are
+// similar to those that make up the C language; see the TokenType enum for
+// precise descriptions.  Whitespace and comments are skipped.  By default,
+// C- and C++-style comments are recognized, but other styles can be used by
+// calling set_comment_style().
+class PROTOBUF_EXPORT Tokenizer {
+ public:
+  // Construct a Tokenizer that reads and tokenizes text from the given
+  // input stream and writes errors to the given error_collector.
+  // The caller keeps ownership of input and error_collector.
+  Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector);
+  ~Tokenizer();
+
+  enum TokenType {
+    TYPE_START,  // Next() has not yet been called.
+    TYPE_END,    // End of input reached.  "text" is empty.
+
+    TYPE_IDENTIFIER,  // A sequence of letters, digits, and underscores, not
+                      // starting with a digit.  It is an error for a number
+                      // to be followed by an identifier with no space in
+                      // between.
+    TYPE_INTEGER,     // A sequence of digits representing an integer.  Normally
+                      // the digits are decimal, but a prefix of "0x" indicates
+                      // a hex number and a leading zero indicates octal, just
+                      // like with C numeric literals.  A leading negative sign
+                      // is NOT included in the token; it's up to the parser to
+                      // interpret the unary minus operator on its own.
+    TYPE_FLOAT,       // A floating point literal, with a fractional part and/or
+                      // an exponent.  Always in decimal.  Again, never
+                      // negative.
+    TYPE_STRING,      // A quoted sequence of escaped characters.  Either single
+                      // or double quotes can be used, but they must match.
+                      // A string literal cannot cross a line break.
+    TYPE_SYMBOL,      // Any other printable character, like '!' or '+'.
+                      // Symbols are always a single character, so "!+$%" is
+                      // four tokens.
+    TYPE_WHITESPACE,  // A sequence of whitespace.  This token type is only
+                      // produced if report_whitespace() is true.  It is not
+                      // reported for whitespace within comments or strings.
+    TYPE_NEWLINE,     // A newline (\n).  This token type is only
+                      // produced if report_whitespace() is true and
+                      // report_newlines() is true.  It is not reported for
+                      // newlines in comments or strings.
+  };
+
+  // Structure representing a token read from the token stream.
+  struct Token {
+    TokenType type;
+    std::string text;  // The exact text of the token as it appeared in
+                       // the input.  e.g. tokens of TYPE_STRING will still
+                       // be escaped and in quotes.
+
+    // "line" and "column" specify the position of the first character of
+    // the token within the input stream.  They are zero-based.
+    int line;
+    ColumnNumber column;
+    ColumnNumber end_column;
+  };
+
+  // Get the current token.  This is updated when Next() is called.  Before
+  // the first call to Next(), current() has type TYPE_START and no contents.
+  const Token& current();
+
+  // Return the previous token -- i.e. what current() returned before the
+  // previous call to Next().
+  const Token& previous();
+
+  // Advance to the next token.  Returns false if the end of the input is
+  // reached.
+  bool Next();
+
+  // Like Next(), but also collects comments which appear between the previous
+  // and next tokens.
+  //
+  // Comments which appear to be attached to the previous token are stored
+  // in *prev_tailing_comments.  Comments which appear to be attached to the
+  // next token are stored in *next_leading_comments.  Comments appearing in
+  // between which do not appear to be attached to either will be added to
+  // detached_comments.  Any of these parameters can be NULL to simply discard
+  // the comments.
+  //
+  // A series of line comments appearing on consecutive lines, with no other
+  // tokens appearing on those lines, will be treated as a single comment.
+  //
+  // Only the comment content is returned; 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.  This is not attached to qux or corge
+  //   // because there are blank lines separating it from both.
+  //
+  //   optional string corge = 5;
+  //   /* Block comment attached
+  //    * to corge.  Leading asterisks
+  //    * will be removed. */
+  //   /* Block comment attached to
+  //    * grault. */
+  //   optional int32 grault = 6;
+  bool NextWithComments(std::string* prev_trailing_comments,
+                        std::vector<std::string>* detached_comments,
+                        std::string* next_leading_comments);
+
+  // Parse helpers ---------------------------------------------------
+
+  // Parses a TYPE_FLOAT token.  This never fails, so long as the text actually
+  // comes from a TYPE_FLOAT token parsed by Tokenizer.  If it doesn't, the
+  // result is undefined (possibly an assert failure).
+  static double ParseFloat(const std::string& text);
+
+  // Parses a TYPE_STRING token.  This never fails, so long as the text actually
+  // comes from a TYPE_STRING token parsed by Tokenizer.  If it doesn't, the
+  // result is undefined (possibly an assert failure).
+  static void ParseString(const std::string& text, std::string* output);
+
+  // Identical to ParseString, but appends to output.
+  static void ParseStringAppend(const std::string& text, std::string* output);
+
+  // Parses a TYPE_INTEGER token.  Returns false if the result would be
+  // greater than max_value.  Otherwise, returns true and sets *output to the
+  // result.  If the text is not from a Token of type TYPE_INTEGER originally
+  // parsed by a Tokenizer, the result is undefined (possibly an assert
+  // failure).
+  static bool ParseInteger(const std::string& text, uint64_t max_value,
+                           uint64_t* output);
+
+  // Options ---------------------------------------------------------
+
+  // Set true to allow floats to be suffixed with the letter 'f'.  Tokens
+  // which would otherwise be integers but which have the 'f' suffix will be
+  // forced to be interpreted as floats.  For all other purposes, the 'f' is
+  // ignored.
+  void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
+
+  // Valid values for set_comment_style().
+  enum CommentStyle {
+    // Line comments begin with "//", block comments are delimited by "/*" and
+    // "*/".
+    CPP_COMMENT_STYLE,
+    // Line comments begin with "#".  No way to write block comments.
+    SH_COMMENT_STYLE
+  };
+
+  // Sets the comment style.
+  void set_comment_style(CommentStyle style) { comment_style_ = style; }
+
+  // Whether to require whitespace between a number and a field name.
+  // Default is true. Do not use this; for Google-internal cleanup only.
+  void set_require_space_after_number(bool require) {
+    require_space_after_number_ = require;
+  }
+
+  // Whether to allow string literals to span multiple lines. Default is false.
+  // Do not use this; for Google-internal cleanup only.
+  void set_allow_multiline_strings(bool allow) {
+    allow_multiline_strings_ = allow;
+  }
+
+  // If true, whitespace tokens are reported by Next().
+  // Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
+  bool report_whitespace() const;
+  void set_report_whitespace(bool report);
+
+  // If true, newline tokens are reported by Next().
+  // Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
+  bool report_newlines() const;
+  void set_report_newlines(bool report);
+
+  // External helper: validate an identifier.
+  static bool IsIdentifier(const std::string& text);
+
+  // -----------------------------------------------------------------
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
+
+  Token current_;   // Returned by current().
+  Token previous_;  // Returned by previous().
+
+  ZeroCopyInputStream* input_;
+  ErrorCollector* error_collector_;
+
+  char current_char_;   // == buffer_[buffer_pos_], updated by NextChar().
+  const char* buffer_;  // Current buffer returned from input_.
+  int buffer_size_;     // Size of buffer_.
+  int buffer_pos_;      // Current position within the buffer.
+  bool read_error_;     // Did we previously encounter a read error?
+
+  // Line and column number of current_char_ within the whole input stream.
+  int line_;
+  ColumnNumber column_;
+
+  // String to which text should be appended as we advance through it.
+  // Call RecordTo(&str) to start recording and StopRecording() to stop.
+  // E.g. StartToken() calls RecordTo(&current_.text).  record_start_ is the
+  // position within the current buffer where recording started.
+  std::string* record_target_;
+  int record_start_;
+
+  // Options.
+  bool allow_f_after_float_;
+  CommentStyle comment_style_;
+  bool require_space_after_number_;
+  bool allow_multiline_strings_;
+  bool report_whitespace_ = false;
+  bool report_newlines_ = false;
+
+  // Since we count columns we need to interpret tabs somehow.  We'll take
+  // the standard 8-character definition for lack of any way to do better.
+  // This must match the documentation of ColumnNumber.
+  static const int kTabWidth = 8;
+
+  // -----------------------------------------------------------------
+  // Helper methods.
+
+  // Consume this character and advance to the next one.
+  void NextChar();
+
+  // Read a new buffer from the input.
+  void Refresh();
+
+  inline void RecordTo(std::string* target);
+  inline void StopRecording();
+
+  // Called when the current character is the first character of a new
+  // token (not including whitespace or comments).
+  inline void StartToken();
+  // Called when the current character is the first character after the
+  // end of the last token.  After this returns, current_.text will
+  // contain all text consumed since StartToken() was called.
+  inline void EndToken();
+
+  // Convenience method to add an error at the current line and column.
+  void AddError(const std::string& message) {
+    error_collector_->AddError(line_, column_, message);
+  }
+
+  // -----------------------------------------------------------------
+  // The following four methods are used to consume tokens of specific
+  // types.  They are actually used to consume all characters *after*
+  // the first, since the calling function consumes the first character
+  // in order to decide what kind of token is being read.
+
+  // Read and consume a string, ending when the given delimiter is
+  // consumed.
+  void ConsumeString(char delimiter);
+
+  // Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
+  // depending on what was read.  This needs to know if the first
+  // character was a zero in order to correctly recognize hex and octal
+  // numbers.
+  // It also needs to know if the first character was a . to parse floating
+  // point correctly.
+  TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
+
+  // Consume the rest of a line.
+  void ConsumeLineComment(std::string* content);
+  // Consume until "*/".
+  void ConsumeBlockComment(std::string* content);
+
+  enum NextCommentStatus {
+    // Started a line comment.
+    LINE_COMMENT,
+
+    // Started a block comment.
+    BLOCK_COMMENT,
+
+    // Consumed a slash, then realized it wasn't a comment.  current_ has
+    // been filled in with a slash token.  The caller should return it.
+    SLASH_NOT_COMMENT,
+
+    // We do not appear to be starting a comment here.
+    NO_COMMENT
+  };
+
+  // If we're at the start of a new comment, consume it and return what kind
+  // of comment it is.
+  NextCommentStatus TryConsumeCommentStart();
+
+  // If we're looking at a TYPE_WHITESPACE token and `report_whitespace_` is
+  // true, consume it and return true.
+  bool TryConsumeWhitespace();
+
+  // If we're looking at a TYPE_NEWLINE token and `report_newlines_` is true,
+  // consume it and return true.
+  bool TryConsumeNewline();
+
+  // -----------------------------------------------------------------
+  // These helper methods make the parsing code more readable.  The
+  // "character classes" referred to are defined at the top of the .cc file.
+  // Basically it is a C++ class with one method:
+  //   static bool InClass(char c);
+  // The method returns true if c is a member of this "class", like "Letter"
+  // or "Digit".
+
+  // Returns true if the current character is of the given character
+  // class, but does not consume anything.
+  template <typename CharacterClass>
+  inline bool LookingAt();
+
+  // If the current character is in the given class, consume it and return
+  // true.  Otherwise return false.
+  // e.g. TryConsumeOne<Letter>()
+  template <typename CharacterClass>
+  inline bool TryConsumeOne();
+
+  // Like above, but try to consume the specific character indicated.
+  inline bool TryConsume(char c);
+
+  // Consume zero or more of the given character class.
+  template <typename CharacterClass>
+  inline void ConsumeZeroOrMore();
+
+  // Consume one or more of the given character class or log the given
+  // error message.
+  // e.g. ConsumeOneOrMore<Digit>("Expected digits.");
+  template <typename CharacterClass>
+  inline void ConsumeOneOrMore(const char* error);
+};
+
+// inline methods ====================================================
+inline const Tokenizer::Token& Tokenizer::current() { return current_; }
+
+inline const Tokenizer::Token& Tokenizer::previous() { return previous_; }
+
+inline void Tokenizer::ParseString(const std::string& text,
+                                   std::string* output) {
+  output->clear();
+  ParseStringAppend(text, output);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
new file mode 100644
index 0000000..16ba940
--- /dev/null
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -0,0 +1,1175 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/io/tokenizer.h>
+
+#include <limits.h>
+#include <math.h>
+
+#include <vector>
+
+#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/io/zero_copy_stream_impl.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace {
+
+// ===================================================================
+// Data-Driven Test Infrastructure
+
+// TODO(kenton):  This is copied from coded_stream_unittest.  This is
+//   temporary until these features are integrated into gTest itself.
+
+// TEST_1D and TEST_2D are macros I'd eventually like to see added to
+// gTest.  These macros can be used to declare tests which should be
+// run multiple times, once for each item in some input array.  TEST_1D
+// tests all cases in a single input array.  TEST_2D tests all
+// combinations of cases from two arrays.  The arrays must be statically
+// defined such that the GOOGLE_ARRAYSIZE() macro works on them.  Example:
+//
+// int kCases[] = {1, 2, 3, 4}
+// TEST_1D(MyFixture, MyTest, kCases) {
+//   EXPECT_GT(kCases_case, 0);
+// }
+//
+// This test iterates through the numbers 1, 2, 3, and 4 and tests that
+// they are all grater than zero.  In case of failure, the exact case
+// which failed will be printed.  The case type must be printable using
+// ostream::operator<<.
+
+#define TEST_1D(FIXTURE, NAME, CASES)                             \
+  class FIXTURE##_##NAME##_DD : public FIXTURE {                  \
+   protected:                                                     \
+    template <typename CaseType>                                  \
+    void DoSingleCase(const CaseType& CASES##_case);              \
+  };                                                              \
+                                                                  \
+  TEST_F(FIXTURE##_##NAME##_DD, NAME) {                           \
+    for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES); i++) {                  \
+      SCOPED_TRACE(testing::Message()                             \
+                   << #CASES " case #" << i << ": " << CASES[i]); \
+      DoSingleCase(CASES[i]);                                     \
+    }                                                             \
+  }                                                               \
+                                                                  \
+  template <typename CaseType>                                    \
+  void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType& CASES##_case)
+
+#define TEST_2D(FIXTURE, NAME, CASES1, CASES2)                              \
+  class FIXTURE##_##NAME##_DD : public FIXTURE {                            \
+   protected:                                                               \
+    template <typename CaseType1, typename CaseType2>                       \
+    void DoSingleCase(const CaseType1& CASES1##_case,                       \
+                      const CaseType2& CASES2##_case);                      \
+  };                                                                        \
+                                                                            \
+  TEST_F(FIXTURE##_##NAME##_DD, NAME) {                                     \
+    for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES1); i++) {                           \
+      for (int j = 0; j < GOOGLE_ARRAYSIZE(CASES2); j++) {                         \
+        SCOPED_TRACE(testing::Message()                                     \
+                     << #CASES1 " case #" << i << ": " << CASES1[i] << ", " \
+                     << #CASES2 " case #" << j << ": " << CASES2[j]);       \
+        DoSingleCase(CASES1[i], CASES2[j]);                                 \
+      }                                                                     \
+    }                                                                       \
+  }                                                                         \
+                                                                            \
+  template <typename CaseType1, typename CaseType2>                         \
+  void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType1& CASES1##_case,  \
+                                           const CaseType2& CASES2##_case)
+
+// -------------------------------------------------------------------
+
+// An input stream that is basically like an ArrayInputStream but sometimes
+// returns empty buffers, just to throw us off.
+class TestInputStream : public ZeroCopyInputStream {
+ public:
+  TestInputStream(const void* data, int size, int block_size)
+      : array_stream_(data, size, block_size), counter_(0) {}
+  ~TestInputStream() {}
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override {
+    // We'll return empty buffers starting with the first buffer, and every
+    // 3 and 5 buffers after that.
+    if (counter_ % 3 == 0 || counter_ % 5 == 0) {
+      *data = NULL;
+      *size = 0;
+      ++counter_;
+      return true;
+    } else {
+      ++counter_;
+      return array_stream_.Next(data, size);
+    }
+  }
+
+  void BackUp(int count) override { return array_stream_.BackUp(count); }
+  bool Skip(int count) override { return array_stream_.Skip(count); }
+  int64_t ByteCount() const override { return array_stream_.ByteCount(); }
+
+ private:
+  ArrayInputStream array_stream_;
+  int counter_;
+};
+
+// -------------------------------------------------------------------
+
+// An error collector which simply concatenates all its errors into a big
+// block of text which can be checked.
+class TestErrorCollector : public ErrorCollector {
+ public:
+  TestErrorCollector() {}
+  ~TestErrorCollector() {}
+
+  std::string text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(int line, int column, const std::string& message) {
+    strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line, column, message);
+  }
+};
+
+// -------------------------------------------------------------------
+
+// We test each operation over a variety of block sizes to insure that
+// we test cases where reads cross buffer boundaries as well as cases
+// where they don't.  This is sort of a brute-force approach to this,
+// but it's easy to write and easy to understand.
+const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
+
+class TokenizerTest : public testing::Test {
+ protected:
+  // For easy testing.
+  uint64_t ParseInteger(const std::string& text) {
+    uint64_t result;
+    EXPECT_TRUE(Tokenizer::ParseInteger(text, kuint64max, &result))
+        << "'" << text << "'";
+    return result;
+  }
+};
+
+// ===================================================================
+
+// These tests causes gcc 3.3.5 (and earlier?) to give the cryptic error:
+//   "sorry, unimplemented: `method_call_expr' not supported by dump_expr"
+#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
+
+// In each test case, the entire input text should parse as a single token
+// of the given type.
+struct SimpleTokenCase {
+  std::string input;
+  Tokenizer::TokenType type;
+};
+
+inline std::ostream& operator<<(std::ostream& out,
+                                const SimpleTokenCase& test_case) {
+  return out << CEscape(test_case.input);
+}
+
+SimpleTokenCase kSimpleTokenCases[] = {
+    // Test identifiers.
+    {"hello", Tokenizer::TYPE_IDENTIFIER},
+
+    // Test integers.
+    {"123", Tokenizer::TYPE_INTEGER},
+    {"0xab6", Tokenizer::TYPE_INTEGER},
+    {"0XAB6", Tokenizer::TYPE_INTEGER},
+    {"0X1234567", Tokenizer::TYPE_INTEGER},
+    {"0x89abcdef", Tokenizer::TYPE_INTEGER},
+    {"0x89ABCDEF", Tokenizer::TYPE_INTEGER},
+    {"01234567", Tokenizer::TYPE_INTEGER},
+
+    // Test floats.
+    {"123.45", Tokenizer::TYPE_FLOAT},
+    {"1.", Tokenizer::TYPE_FLOAT},
+    {"1e3", Tokenizer::TYPE_FLOAT},
+    {"1E3", Tokenizer::TYPE_FLOAT},
+    {"1e-3", Tokenizer::TYPE_FLOAT},
+    {"1e+3", Tokenizer::TYPE_FLOAT},
+    {"1.e3", Tokenizer::TYPE_FLOAT},
+    {"1.2e3", Tokenizer::TYPE_FLOAT},
+    {".1", Tokenizer::TYPE_FLOAT},
+    {".1e3", Tokenizer::TYPE_FLOAT},
+    {".1e-3", Tokenizer::TYPE_FLOAT},
+    {".1e+3", Tokenizer::TYPE_FLOAT},
+
+    // Test strings.
+    {"'hello'", Tokenizer::TYPE_STRING},
+    {"\"foo\"", Tokenizer::TYPE_STRING},
+    {"'a\"b'", Tokenizer::TYPE_STRING},
+    {"\"a'b\"", Tokenizer::TYPE_STRING},
+    {"'a\\'b'", Tokenizer::TYPE_STRING},
+    {"\"a\\\"b\"", Tokenizer::TYPE_STRING},
+    {"'\\xf'", Tokenizer::TYPE_STRING},
+    {"'\\0'", Tokenizer::TYPE_STRING},
+
+    // Test symbols.
+    {"+", Tokenizer::TYPE_SYMBOL},
+    {".", Tokenizer::TYPE_SYMBOL},
+};
+
+TEST_2D(TokenizerTest, SimpleTokens, kSimpleTokenCases, kBlockSizes) {
+  // Set up the tokenizer.
+  TestInputStream input(kSimpleTokenCases_case.input.data(),
+                        kSimpleTokenCases_case.input.size(), kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+
+  // Before Next() is called, the initial token should always be TYPE_START.
+  EXPECT_EQ(Tokenizer::TYPE_START, tokenizer.current().type);
+  EXPECT_EQ("", tokenizer.current().text);
+  EXPECT_EQ(0, tokenizer.current().line);
+  EXPECT_EQ(0, tokenizer.current().column);
+  EXPECT_EQ(0, tokenizer.current().end_column);
+
+  // Parse the token.
+  ASSERT_TRUE(tokenizer.Next());
+
+  // Check that it has the right type.
+  EXPECT_EQ(kSimpleTokenCases_case.type, tokenizer.current().type);
+  // Check that it contains the complete input text.
+  EXPECT_EQ(kSimpleTokenCases_case.input, tokenizer.current().text);
+  // Check that it is located at the beginning of the input
+  EXPECT_EQ(0, tokenizer.current().line);
+  EXPECT_EQ(0, tokenizer.current().column);
+  EXPECT_EQ(kSimpleTokenCases_case.input.size(),
+            tokenizer.current().end_column);
+
+  // There should be no more input.
+  EXPECT_FALSE(tokenizer.Next());
+
+  // After Next() returns false, the token should have type TYPE_END.
+  EXPECT_EQ(Tokenizer::TYPE_END, tokenizer.current().type);
+  EXPECT_EQ("", tokenizer.current().text);
+  EXPECT_EQ(0, tokenizer.current().line);
+  EXPECT_EQ(kSimpleTokenCases_case.input.size(), tokenizer.current().column);
+  EXPECT_EQ(kSimpleTokenCases_case.input.size(),
+            tokenizer.current().end_column);
+
+  // There should be no errors.
+  EXPECT_TRUE(error_collector.text_.empty());
+}
+
+TEST_1D(TokenizerTest, FloatSuffix, kBlockSizes) {
+  // Test the "allow_f_after_float" option.
+
+  // Set up the tokenizer.
+  const char* text = "1f 2.5f 6e3f 7F";
+  TestInputStream input(text, strlen(text), kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+  tokenizer.set_allow_f_after_float(true);
+
+  // Advance through tokens and check that they are parsed as expected.
+  ASSERT_TRUE(tokenizer.Next());
+  EXPECT_EQ(tokenizer.current().text, "1f");
+  EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
+  ASSERT_TRUE(tokenizer.Next());
+  EXPECT_EQ(tokenizer.current().text, "2.5f");
+  EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
+  ASSERT_TRUE(tokenizer.Next());
+  EXPECT_EQ(tokenizer.current().text, "6e3f");
+  EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
+  ASSERT_TRUE(tokenizer.Next());
+  EXPECT_EQ(tokenizer.current().text, "7F");
+  EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
+
+  // There should be no more input.
+  EXPECT_FALSE(tokenizer.Next());
+  // There should be no errors.
+  EXPECT_TRUE(error_collector.text_.empty());
+}
+
+SimpleTokenCase kWhitespaceTokenCases[] = {
+    {" ", Tokenizer::TYPE_WHITESPACE},
+    {"    ", Tokenizer::TYPE_WHITESPACE},
+    {"\t", Tokenizer::TYPE_WHITESPACE},
+    {"\v", Tokenizer::TYPE_WHITESPACE},
+    {"\t ", Tokenizer::TYPE_WHITESPACE},
+    {"\v\t", Tokenizer::TYPE_WHITESPACE},
+    {"   \t\r", Tokenizer::TYPE_WHITESPACE},
+    // Newlines:
+    {"\n", Tokenizer::TYPE_NEWLINE},
+};
+
+TEST_2D(TokenizerTest, Whitespace, kWhitespaceTokenCases, kBlockSizes) {
+  {
+    TestInputStream input(kWhitespaceTokenCases_case.input.data(),
+                          kWhitespaceTokenCases_case.input.size(),
+                          kBlockSizes_case);
+    TestErrorCollector error_collector;
+    Tokenizer tokenizer(&input, &error_collector);
+
+    EXPECT_FALSE(tokenizer.Next());
+  }
+  {
+    TestInputStream input(kWhitespaceTokenCases_case.input.data(),
+                          kWhitespaceTokenCases_case.input.size(),
+                          kBlockSizes_case);
+    TestErrorCollector error_collector;
+    Tokenizer tokenizer(&input, &error_collector);
+    tokenizer.set_report_whitespace(true);
+    tokenizer.set_report_newlines(true);
+
+    ASSERT_TRUE(tokenizer.Next());
+    EXPECT_EQ(tokenizer.current().text, kWhitespaceTokenCases_case.input);
+    EXPECT_EQ(tokenizer.current().type, kWhitespaceTokenCases_case.type);
+
+    EXPECT_FALSE(tokenizer.Next());
+  }
+}
+
+#endif
+
+// -------------------------------------------------------------------
+
+// In each case, the input is parsed to produce a list of tokens.  The
+// last token in "output" must have type TYPE_END.
+struct MultiTokenCase {
+  std::string input;
+  std::vector<Tokenizer::Token> output;
+};
+
+inline std::ostream& operator<<(std::ostream& out,
+                                const MultiTokenCase& test_case) {
+  return out << CEscape(test_case.input);
+}
+
+MultiTokenCase kMultiTokenCases[] = {
+    // Test empty input.
+    {"",
+     {
+         {Tokenizer::TYPE_END, "", 0, 0, 0},
+     }},
+
+    // Test all token types at the same time.
+    {"foo 1 1.2 + 'bar'",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_INTEGER, "1", 0, 4, 5},
+         {Tokenizer::TYPE_FLOAT, "1.2", 0, 6, 9},
+         {Tokenizer::TYPE_SYMBOL, "+", 0, 10, 11},
+         {Tokenizer::TYPE_STRING, "'bar'", 0, 12, 17},
+         {Tokenizer::TYPE_END, "", 0, 17, 17},
+     }},
+
+    // Test that consecutive symbols are parsed as separate tokens.
+    {"!@+%",
+     {
+         {Tokenizer::TYPE_SYMBOL, "!", 0, 0, 1},
+         {Tokenizer::TYPE_SYMBOL, "@", 0, 1, 2},
+         {Tokenizer::TYPE_SYMBOL, "+", 0, 2, 3},
+         {Tokenizer::TYPE_SYMBOL, "%", 0, 3, 4},
+         {Tokenizer::TYPE_END, "", 0, 4, 4},
+     }},
+
+    // Test that newlines affect line numbers correctly.
+    {"foo bar\nrab oof",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_IDENTIFIER, "bar", 0, 4, 7},
+         {Tokenizer::TYPE_IDENTIFIER, "rab", 1, 0, 3},
+         {Tokenizer::TYPE_IDENTIFIER, "oof", 1, 4, 7},
+         {Tokenizer::TYPE_END, "", 1, 7, 7},
+     }},
+
+    // Test that tabs affect column numbers correctly.
+    {"foo\tbar  \tbaz",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_IDENTIFIER, "bar", 0, 8, 11},
+         {Tokenizer::TYPE_IDENTIFIER, "baz", 0, 16, 19},
+         {Tokenizer::TYPE_END, "", 0, 19, 19},
+     }},
+
+    // Test that tabs in string literals affect column numbers correctly.
+    {"\"foo\tbar\" baz",
+     {
+         {Tokenizer::TYPE_STRING, "\"foo\tbar\"", 0, 0, 12},
+         {Tokenizer::TYPE_IDENTIFIER, "baz", 0, 13, 16},
+         {Tokenizer::TYPE_END, "", 0, 16, 16},
+     }},
+
+    // Test that line comments are ignored.
+    {"foo // This is a comment\n"
+     "bar // This is another comment",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_IDENTIFIER, "bar", 1, 0, 3},
+         {Tokenizer::TYPE_END, "", 1, 30, 30},
+     }},
+
+    // Test that block comments are ignored.
+    {"foo /* This is a block comment */ bar",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_IDENTIFIER, "bar", 0, 34, 37},
+         {Tokenizer::TYPE_END, "", 0, 37, 37},
+     }},
+
+    // Test that sh-style comments are not ignored by default.
+    {"foo # bar\n"
+     "baz",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_SYMBOL, "#", 0, 4, 5},
+         {Tokenizer::TYPE_IDENTIFIER, "bar", 0, 6, 9},
+         {Tokenizer::TYPE_IDENTIFIER, "baz", 1, 0, 3},
+         {Tokenizer::TYPE_END, "", 1, 3, 3},
+     }},
+
+    // Test all whitespace chars
+    {"foo\n\t\r\v\fbar",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_IDENTIFIER, "bar", 1, 11, 14},
+         {Tokenizer::TYPE_END, "", 1, 14, 14},
+     }},
+};
+
+TEST_2D(TokenizerTest, MultipleTokens, kMultiTokenCases, kBlockSizes) {
+  // Set up the tokenizer.
+  TestInputStream input(kMultiTokenCases_case.input.data(),
+                        kMultiTokenCases_case.input.size(), kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+
+  // Before Next() is called, the initial token should always be TYPE_START.
+  EXPECT_EQ(Tokenizer::TYPE_START, tokenizer.current().type);
+  EXPECT_EQ("", tokenizer.current().text);
+  EXPECT_EQ(0, tokenizer.current().line);
+  EXPECT_EQ(0, tokenizer.current().column);
+  EXPECT_EQ(0, tokenizer.current().end_column);
+
+  // Loop through all expected tokens.
+  int i = 0;
+  Tokenizer::Token token;
+  do {
+    token = kMultiTokenCases_case.output[i++];
+
+    SCOPED_TRACE(testing::Message() << "Token #" << i << ": " << token.text);
+
+    Tokenizer::Token previous = tokenizer.current();
+
+    // Next() should only return false when it hits the end token.
+    if (token.type != Tokenizer::TYPE_END) {
+      ASSERT_TRUE(tokenizer.Next());
+    } else {
+      ASSERT_FALSE(tokenizer.Next());
+    }
+
+    // Check that the previous token is set correctly.
+    EXPECT_EQ(previous.type, tokenizer.previous().type);
+    EXPECT_EQ(previous.text, tokenizer.previous().text);
+    EXPECT_EQ(previous.line, tokenizer.previous().line);
+    EXPECT_EQ(previous.column, tokenizer.previous().column);
+    EXPECT_EQ(previous.end_column, tokenizer.previous().end_column);
+
+    // Check that the token matches the expected one.
+    EXPECT_EQ(token.type, tokenizer.current().type);
+    EXPECT_EQ(token.text, tokenizer.current().text);
+    EXPECT_EQ(token.line, tokenizer.current().line);
+    EXPECT_EQ(token.column, tokenizer.current().column);
+    EXPECT_EQ(token.end_column, tokenizer.current().end_column);
+
+  } while (token.type != Tokenizer::TYPE_END);
+
+  // There should be no errors.
+  EXPECT_TRUE(error_collector.text_.empty());
+}
+
+MultiTokenCase kMultiWhitespaceTokenCases[] = {
+    // Test all token types at the same time.
+    {"foo 1 \t1.2  \n   +\v'bar'",
+     {
+         {Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0, 3},
+         {Tokenizer::TYPE_WHITESPACE, " ", 0, 3, 4},
+         {Tokenizer::TYPE_INTEGER, "1", 0, 4, 5},
+         {Tokenizer::TYPE_WHITESPACE, " \t", 0, 5, 8},
+         {Tokenizer::TYPE_FLOAT, "1.2", 0, 8, 11},
+         {Tokenizer::TYPE_WHITESPACE, "  ", 0, 11, 13},
+         {Tokenizer::TYPE_NEWLINE, "\n", 0, 13, 0},
+         {Tokenizer::TYPE_WHITESPACE, "   ", 1, 0, 3},
+         {Tokenizer::TYPE_SYMBOL, "+", 1, 3, 4},
+         {Tokenizer::TYPE_WHITESPACE, "\v", 1, 4, 5},
+         {Tokenizer::TYPE_STRING, "'bar'", 1, 5, 10},
+         {Tokenizer::TYPE_END, "", 1, 10, 10},
+     }},
+
+};
+
+TEST_2D(TokenizerTest, MultipleWhitespaceTokens, kMultiWhitespaceTokenCases,
+        kBlockSizes) {
+  // Set up the tokenizer.
+  TestInputStream input(kMultiWhitespaceTokenCases_case.input.data(),
+                        kMultiWhitespaceTokenCases_case.input.size(),
+                        kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+  tokenizer.set_report_whitespace(true);
+  tokenizer.set_report_newlines(true);
+
+  // Before Next() is called, the initial token should always be TYPE_START.
+  EXPECT_EQ(Tokenizer::TYPE_START, tokenizer.current().type);
+  EXPECT_EQ("", tokenizer.current().text);
+  EXPECT_EQ(0, tokenizer.current().line);
+  EXPECT_EQ(0, tokenizer.current().column);
+  EXPECT_EQ(0, tokenizer.current().end_column);
+
+  // Loop through all expected tokens.
+  int i = 0;
+  Tokenizer::Token token;
+  do {
+    token = kMultiWhitespaceTokenCases_case.output[i++];
+
+    SCOPED_TRACE(testing::Message() << "Token #" << i << ": " << token.text);
+
+    Tokenizer::Token previous = tokenizer.current();
+
+    // Next() should only return false when it hits the end token.
+    if (token.type != Tokenizer::TYPE_END) {
+      ASSERT_TRUE(tokenizer.Next());
+    } else {
+      ASSERT_FALSE(tokenizer.Next());
+    }
+
+    // Check that the previous token is set correctly.
+    EXPECT_EQ(previous.type, tokenizer.previous().type);
+    EXPECT_EQ(previous.text, tokenizer.previous().text);
+    EXPECT_EQ(previous.line, tokenizer.previous().line);
+    EXPECT_EQ(previous.column, tokenizer.previous().column);
+    EXPECT_EQ(previous.end_column, tokenizer.previous().end_column);
+
+    // Check that the token matches the expected one.
+    EXPECT_EQ(token.type, tokenizer.current().type);
+    EXPECT_EQ(token.text, tokenizer.current().text);
+    EXPECT_EQ(token.line, tokenizer.current().line);
+    EXPECT_EQ(token.column, tokenizer.current().column);
+    EXPECT_EQ(token.end_column, tokenizer.current().end_column);
+
+  } while (token.type != Tokenizer::TYPE_END);
+
+  // There should be no errors.
+  EXPECT_TRUE(error_collector.text_.empty());
+}
+
+// This test causes gcc 3.3.5 (and earlier?) to give the cryptic error:
+//   "sorry, unimplemented: `method_call_expr' not supported by dump_expr"
+#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
+
+TEST_1D(TokenizerTest, ShCommentStyle, kBlockSizes) {
+  // Test the "comment_style" option.
+
+  const char* text =
+      "foo # bar\n"
+      "baz // qux\n"
+      "corge /* grault */\n"
+      "garply";
+  const char* const kTokens[] = {"foo",  // "# bar" is ignored
+                                 "baz", "/",      "/", "qux", "corge", "/",
+                                 "*",   "grault", "*", "/",   "garply"};
+
+  // Set up the tokenizer.
+  TestInputStream input(text, strlen(text), kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+  tokenizer.set_comment_style(Tokenizer::SH_COMMENT_STYLE);
+
+  // Advance through tokens and check that they are parsed as expected.
+  for (int i = 0; i < GOOGLE_ARRAYSIZE(kTokens); i++) {
+    EXPECT_TRUE(tokenizer.Next());
+    EXPECT_EQ(tokenizer.current().text, kTokens[i]);
+  }
+
+  // There should be no more input.
+  EXPECT_FALSE(tokenizer.Next());
+  // There should be no errors.
+  EXPECT_TRUE(error_collector.text_.empty());
+}
+
+#endif
+
+// -------------------------------------------------------------------
+
+// In each case, the input is expected to have two tokens named "prev" and
+// "next" with comments in between.
+struct DocCommentCase {
+  std::string input;
+
+  const char* prev_trailing_comments;
+  const char* detached_comments[10];
+  const char* next_leading_comments;
+};
+
+inline std::ostream& operator<<(std::ostream& out,
+                                const DocCommentCase& test_case) {
+  return out << CEscape(test_case.input);
+}
+
+DocCommentCase kDocCommentCases[] = {
+    {"prev next",
+
+     "",
+     {},
+     ""},
+
+    {"prev /* ignored */ next",
+
+     "",
+     {},
+     ""},
+
+    {"prev // trailing comment\n"
+     "next",
+
+     " trailing comment\n",
+     {},
+     ""},
+
+    {"prev\n"
+     "// leading comment\n"
+     "// line 2\n"
+     "next",
+
+     "",
+     {},
+     " leading comment\n"
+     " line 2\n"},
+
+    {"prev\n"
+     "// trailing comment\n"
+     "// line 2\n"
+     "\n"
+     "next",
+
+     " trailing comment\n"
+     " line 2\n",
+     {},
+     ""},
+
+    {"prev // trailing comment\n"
+     "// leading comment\n"
+     "// line 2\n"
+     "next",
+
+     " trailing comment\n",
+     {},
+     " leading comment\n"
+     " line 2\n"},
+
+    {"prev /* trailing block comment */\n"
+     "/* leading block comment\n"
+     " * line 2\n"
+     " * line 3 */"
+     "next",
+
+     " trailing block comment ",
+     {},
+     " leading block comment\n"
+     " line 2\n"
+     " line 3 "},
+
+    {"prev\n"
+     "/* trailing block comment\n"
+     " * line 2\n"
+     " * line 3\n"
+     " */\n"
+     "/* leading block comment\n"
+     " * line 2\n"
+     " * line 3 */"
+     "next",
+
+     " trailing block comment\n"
+     " line 2\n"
+     " line 3\n",
+     {},
+     " leading block comment\n"
+     " line 2\n"
+     " line 3 "},
+
+    {"prev\n"
+     "// trailing comment\n"
+     "\n"
+     "// detached comment\n"
+     "// line 2\n"
+     "\n"
+     "// second detached comment\n"
+     "/* third detached comment\n"
+     " * line 2 */\n"
+     "// leading comment\n"
+     "next",
+
+     " trailing comment\n",
+     {" detached comment\n"
+      " line 2\n",
+      " second detached comment\n",
+      " third detached comment\n"
+      " line 2 "},
+     " leading comment\n"},
+
+    {"prev /**/\n"
+     "\n"
+     "// detached comment\n"
+     "\n"
+     "// leading comment\n"
+     "next",
+
+     "",
+     {" detached comment\n"},
+     " leading comment\n"},
+
+    {"prev /**/\n"
+     "// leading comment\n"
+     "next",
+
+     "",
+     {},
+     " leading comment\n"},
+};
+
+TEST_2D(TokenizerTest, DocComments, kDocCommentCases, kBlockSizes) {
+  // Set up the tokenizer.
+  TestInputStream input(kDocCommentCases_case.input.data(),
+                        kDocCommentCases_case.input.size(), kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+
+  // Set up a second tokenizer where we'll pass all NULLs to NextWithComments().
+  TestInputStream input2(kDocCommentCases_case.input.data(),
+                         kDocCommentCases_case.input.size(), kBlockSizes_case);
+  Tokenizer tokenizer2(&input2, &error_collector);
+
+  tokenizer.Next();
+  tokenizer2.Next();
+
+  EXPECT_EQ("prev", tokenizer.current().text);
+  EXPECT_EQ("prev", tokenizer2.current().text);
+
+  std::string prev_trailing_comments;
+  std::vector<std::string> detached_comments;
+  std::string next_leading_comments;
+  tokenizer.NextWithComments(&prev_trailing_comments, &detached_comments,
+                             &next_leading_comments);
+  tokenizer2.NextWithComments(NULL, NULL, NULL);
+  EXPECT_EQ("next", tokenizer.current().text);
+  EXPECT_EQ("next", tokenizer2.current().text);
+
+  EXPECT_EQ(kDocCommentCases_case.prev_trailing_comments,
+            prev_trailing_comments);
+
+  for (int i = 0; i < detached_comments.size(); i++) {
+    ASSERT_LT(i, GOOGLE_ARRAYSIZE(kDocCommentCases));
+    ASSERT_TRUE(kDocCommentCases_case.detached_comments[i] != NULL);
+    EXPECT_EQ(kDocCommentCases_case.detached_comments[i], detached_comments[i]);
+  }
+
+  // Verify that we matched all the detached comments.
+  EXPECT_EQ(NULL,
+            kDocCommentCases_case.detached_comments[detached_comments.size()]);
+
+  EXPECT_EQ(kDocCommentCases_case.next_leading_comments, next_leading_comments);
+}
+
+// -------------------------------------------------------------------
+
+// Test parse helpers.
+// TODO(b/225783758): Add a fuzz test for this.
+TEST_F(TokenizerTest, ParseInteger) {
+  EXPECT_EQ(0, ParseInteger("0"));
+  EXPECT_EQ(123, ParseInteger("123"));
+  EXPECT_EQ(0xabcdef12u, ParseInteger("0xabcdef12"));
+  EXPECT_EQ(0xabcdef12u, ParseInteger("0xABCDEF12"));
+  EXPECT_EQ(kuint64max, ParseInteger("0xFFFFFFFFFFFFFFFF"));
+  EXPECT_EQ(01234567, ParseInteger("01234567"));
+  EXPECT_EQ(0X123, ParseInteger("0X123"));
+
+  // Test invalid integers that may still be tokenized as integers.
+  EXPECT_EQ(0, ParseInteger("0x"));
+
+  uint64_t i;
+
+  // Test invalid integers that will never be tokenized as integers.
+  EXPECT_FALSE(Tokenizer::ParseInteger("zxy", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("1.2", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("08", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("0xg", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("-1", kuint64max, &i));
+
+  // Test overflows.
+  EXPECT_TRUE(Tokenizer::ParseInteger("0", 0, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("1", 0, &i));
+  EXPECT_TRUE(Tokenizer::ParseInteger("1", 1, &i));
+  EXPECT_TRUE(Tokenizer::ParseInteger("12345", 12345, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("12346", 12345, &i));
+  EXPECT_TRUE(Tokenizer::ParseInteger("0xFFFFFFFFFFFFFFFF", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("0x10000000000000000", kuint64max, &i));
+
+  // Test near the limits of signed parsing (values in kint64max +/- 1600)
+  for (int64_t offset = -1600; offset <= 1600; ++offset) {
+    // We make sure to perform an unsigned addition so that we avoid signed
+    // overflow, which would be undefined behavior.
+    uint64_t i = 0x7FFFFFFFFFFFFFFFu + static_cast<uint64_t>(offset);
+    char decimal[32];
+    snprintf(decimal, 32, "%llu", static_cast<unsigned long long>(i));
+    if (offset > 0) {
+      uint64_t parsed = -1;
+      EXPECT_FALSE(Tokenizer::ParseInteger(decimal, kint64max, &parsed))
+          << decimal << "=>" << parsed;
+    } else {
+      uint64_t parsed = -1;
+      EXPECT_TRUE(Tokenizer::ParseInteger(decimal, kint64max, &parsed))
+          << decimal << "=>" << parsed;
+      EXPECT_EQ(parsed, i);
+    }
+    char octal[32];
+    snprintf(octal, 32, "0%llo", static_cast<unsigned long long>(i));
+    if (offset > 0) {
+      uint64_t parsed = -1;
+      EXPECT_FALSE(Tokenizer::ParseInteger(octal, kint64max, &parsed))
+          << octal << "=>" << parsed;
+    } else {
+      uint64_t parsed = -1;
+      EXPECT_TRUE(Tokenizer::ParseInteger(octal, kint64max, &parsed))
+          << octal << "=>" << parsed;
+      EXPECT_EQ(parsed, i);
+    }
+    char hex[32];
+    snprintf(hex, 32, "0x%llx", static_cast<unsigned long long>(i));
+    if (offset > 0) {
+      uint64_t parsed = -1;
+      EXPECT_FALSE(Tokenizer::ParseInteger(hex, kint64max, &parsed))
+          << hex << "=>" << parsed;
+    } else {
+      uint64_t parsed = -1;
+      EXPECT_TRUE(Tokenizer::ParseInteger(hex, kint64max, &parsed)) << hex;
+      EXPECT_EQ(parsed, i);
+    }
+    // EXPECT_NE(offset, -237);
+  }
+
+  // Test near the limits of unsigned parsing (values in kuint64max +/- 1600)
+  // By definition, values greater than kuint64max cannot be held in a uint64_t
+  // variable, so printing them is a little tricky; fortunately all but the
+  // last four digits are known, so we can hard-code them in the printf string,
+  // and we only need to format the last 4.
+  for (int64_t offset = -1600; offset <= 1600; ++offset) {
+    {
+      uint64_t i = 18446744073709551615u + offset;
+      char decimal[32];
+      snprintf(decimal, 32, "1844674407370955%04llu",
+               static_cast<unsigned long long>(1615 + offset));
+      if (offset > 0) {
+        uint64_t parsed = -1;
+        EXPECT_FALSE(Tokenizer::ParseInteger(decimal, kuint64max, &parsed))
+            << decimal << "=>" << parsed;
+      } else {
+        uint64_t parsed = -1;
+        EXPECT_TRUE(Tokenizer::ParseInteger(decimal, kuint64max, &parsed))
+            << decimal;
+        EXPECT_EQ(parsed, i);
+      }
+    }
+    {
+      uint64_t i = 01777777777777777777777u + offset;
+      if (offset > 0) {
+        char octal[32];
+        snprintf(octal, 32, "0200000000000000000%04llo",
+                 static_cast<unsigned long long>(offset - 1));
+        uint64_t parsed = -1;
+        EXPECT_FALSE(Tokenizer::ParseInteger(octal, kuint64max, &parsed))
+            << octal << "=>" << parsed;
+      } else {
+        char octal[32];
+        snprintf(octal, 32, "0%llo", static_cast<unsigned long long>(i));
+        uint64_t parsed = -1;
+        EXPECT_TRUE(Tokenizer::ParseInteger(octal, kuint64max, &parsed))
+            << octal;
+        EXPECT_EQ(parsed, i);
+      }
+    }
+    {
+      uint64_t ui = 0xffffffffffffffffu + offset;
+      char hex[32];
+      if (offset > 0) {
+        snprintf(hex, 32, "0x1000000000000%04llx",
+                 static_cast<unsigned long long>(offset - 1));
+        uint64_t parsed = -1;
+        EXPECT_FALSE(Tokenizer::ParseInteger(hex, kuint64max, &parsed))
+            << hex << "=>" << parsed;
+      } else {
+        snprintf(hex, 32, "0x%llx", static_cast<unsigned long long>(ui));
+        uint64_t parsed = -1;
+        EXPECT_TRUE(Tokenizer::ParseInteger(hex, kuint64max, &parsed)) << hex;
+        EXPECT_EQ(parsed, ui);
+      }
+    }
+  }
+}
+
+TEST_F(TokenizerTest, ParseFloat) {
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1."));
+  EXPECT_DOUBLE_EQ(1e3, Tokenizer::ParseFloat("1e3"));
+  EXPECT_DOUBLE_EQ(1e3, Tokenizer::ParseFloat("1E3"));
+  EXPECT_DOUBLE_EQ(1.5e3, Tokenizer::ParseFloat("1.5e3"));
+  EXPECT_DOUBLE_EQ(.1, Tokenizer::ParseFloat(".1"));
+  EXPECT_DOUBLE_EQ(.25, Tokenizer::ParseFloat(".25"));
+  EXPECT_DOUBLE_EQ(.1e3, Tokenizer::ParseFloat(".1e3"));
+  EXPECT_DOUBLE_EQ(.25e3, Tokenizer::ParseFloat(".25e3"));
+  EXPECT_DOUBLE_EQ(.1e+3, Tokenizer::ParseFloat(".1e+3"));
+  EXPECT_DOUBLE_EQ(.1e-3, Tokenizer::ParseFloat(".1e-3"));
+  EXPECT_DOUBLE_EQ(5, Tokenizer::ParseFloat("5"));
+  EXPECT_DOUBLE_EQ(6e-12, Tokenizer::ParseFloat("6e-12"));
+  EXPECT_DOUBLE_EQ(1.2, Tokenizer::ParseFloat("1.2"));
+  EXPECT_DOUBLE_EQ(1.e2, Tokenizer::ParseFloat("1.e2"));
+
+  // Test invalid integers that may still be tokenized as integers.
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1e"));
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1e-"));
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1.e"));
+
+  // Test 'f' suffix.
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1f"));
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1.0f"));
+  EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1F"));
+
+  // These should parse successfully even though they are out of range.
+  // Overflows become infinity and underflows become zero.
+  EXPECT_EQ(0.0, Tokenizer::ParseFloat("1e-9999999999999999999999999999"));
+  EXPECT_EQ(HUGE_VAL, Tokenizer::ParseFloat("1e+9999999999999999999999999999"));
+
+#ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet
+  // Test invalid integers that will never be tokenized as integers.
+  EXPECT_DEBUG_DEATH(
+      Tokenizer::ParseFloat("zxy"),
+      "passed text that could not have been tokenized as a float");
+  EXPECT_DEBUG_DEATH(
+      Tokenizer::ParseFloat("1-e0"),
+      "passed text that could not have been tokenized as a float");
+  EXPECT_DEBUG_DEATH(
+      Tokenizer::ParseFloat("-1.0"),
+      "passed text that could not have been tokenized as a float");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST_F(TokenizerTest, ParseString) {
+  std::string output;
+  Tokenizer::ParseString("'hello'", &output);
+  EXPECT_EQ("hello", output);
+  Tokenizer::ParseString("\"blah\\nblah2\"", &output);
+  EXPECT_EQ("blah\nblah2", output);
+  Tokenizer::ParseString("'\\1x\\1\\123\\739\\52\\334n\\3'", &output);
+  EXPECT_EQ("\1x\1\123\739\52\334n\3", output);
+  Tokenizer::ParseString("'\\x20\\x4'", &output);
+  EXPECT_EQ("\x20\x4", output);
+
+  // Test invalid strings that may still be tokenized as strings.
+  Tokenizer::ParseString("\"\\a\\l\\v\\t", &output);  // \l is invalid
+  EXPECT_EQ("\a?\v\t", output);
+  Tokenizer::ParseString("'", &output);
+  EXPECT_EQ("", output);
+  Tokenizer::ParseString("'\\", &output);
+  EXPECT_EQ("\\", output);
+
+  // Experiment with Unicode escapes. Here are one-, two- and three-byte Unicode
+  // characters.
+  Tokenizer::ParseString("'\\u0024\\u00a2\\u20ac\\U00024b62XX'", &output);
+  EXPECT_EQ("$¢€𤭢XX", output);
+  // Same thing encoded using UTF16.
+  Tokenizer::ParseString("'\\u0024\\u00a2\\u20ac\\ud852\\udf62XX'", &output);
+  EXPECT_EQ("$¢€𤭢XX", output);
+  // Here's some broken UTF16; there's a head surrogate with no tail surrogate.
+  // We just output this as if it were UTF8; it's not a defined code point, but
+  // it has a defined encoding.
+  Tokenizer::ParseString("'\\ud852XX'", &output);
+  EXPECT_EQ("\xed\xa1\x92XX", output);
+  // Malformed escape: Demons may fly out of the nose.
+  Tokenizer::ParseString("'\\u0'", &output);
+  EXPECT_EQ("u0", output);
+  // Beyond the range of valid UTF-32 code units.
+  Tokenizer::ParseString("'\\U00110000\\U00200000\\UFFFFFFFF'", &output);
+  EXPECT_EQ("\\U00110000\\U00200000\\Uffffffff", output);
+
+  // Test invalid strings that will never be tokenized as strings.
+#ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet
+  EXPECT_DEBUG_DEATH(
+      Tokenizer::ParseString("", &output),
+      "passed text that could not have been tokenized as a string");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST_F(TokenizerTest, ParseStringAppend) {
+  // Check that ParseString and ParseStringAppend differ.
+  std::string output("stuff+");
+  Tokenizer::ParseStringAppend("'hello'", &output);
+  EXPECT_EQ("stuff+hello", output);
+  Tokenizer::ParseString("'hello'", &output);
+  EXPECT_EQ("hello", output);
+}
+
+// -------------------------------------------------------------------
+
+// Each case parses some input text, ignoring the tokens produced, and
+// checks that the error output matches what is expected.
+struct ErrorCase {
+  std::string input;
+  bool recoverable;  // True if the tokenizer should be able to recover and
+                     // parse more tokens after seeing this error.  Cases
+                     // for which this is true must end with "foo" as
+                     // the last token, which the test will check for.
+  const char* errors;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const ErrorCase& test_case) {
+  return out << CEscape(test_case.input);
+}
+
+ErrorCase kErrorCases[] = {
+    // 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, "0:4: Unexpected end of string.\n"},
+    {"'bar\nfoo", true, "0:4: String literals cannot cross line boundaries.\n"},
+    {"'\\u01' foo", true,
+     "0:5: Expected four hex digits for \\u escape sequence.\n"},
+    {"'\\u01' foo", true,
+     "0:5: Expected four hex digits for \\u escape sequence.\n"},
+    {"'\\uXYZ' foo", true,
+     "0:3: Expected four hex digits for \\u escape sequence.\n"},
+
+    // Integer errors.
+    {"123foo", true, "0:3: Need space between number and identifier.\n"},
+
+    // Hex/octal errors.
+    {"0x foo", true, "0:2: \"0x\" must be followed by hex digits.\n"},
+    {"0541823 foo", true,
+     "0:4: Numbers starting with leading zero must be in octal.\n"},
+    {"0x123z foo", true, "0:5: Need space between number and identifier.\n"},
+    {"0x123.4 foo", true, "0:5: Hex and octal numbers must be integers.\n"},
+    {"0123.4 foo", true, "0:4: Hex and octal numbers must be integers.\n"},
+
+    // Float errors.
+    {"1e foo", true, "0:2: \"e\" must be followed by exponent.\n"},
+    {"1e- foo", true, "0:3: \"e\" must be followed by exponent.\n"},
+    {"1.2.3 foo", true,
+     "0:3: Already saw decimal point or exponent; can't have another one.\n"},
+    {"1e2.3 foo", true,
+     "0:3: Already saw decimal point or exponent; can't have another one.\n"},
+    {"a.1 foo", true,
+     "0:1: Need space between identifier and decimal point.\n"},
+    // allow_f_after_float not enabled, so this should be an error.
+    {"1.0f foo", true, "0:3: Need space between number and identifier.\n"},
+
+    // Block comment errors.
+    {"/*", false,
+     "0:2: End-of-file inside block comment.\n"
+     "0:0:   Comment started here.\n"},
+    {"/*/*/ foo", true,
+     "0:3: \"/*\" inside block comment.  Block comments cannot be nested.\n"},
+
+    // Control characters.  Multiple consecutive control characters should only
+    // produce one error.
+    {"\b foo", true, "0:0: Invalid control characters encountered in text.\n"},
+    {"\b\b foo", true,
+     "0:0: Invalid control characters encountered in text.\n"},
+
+    // Check that control characters at end of input don't result in an
+    // infinite loop.
+    {"\b", false, "0:0: Invalid control characters encountered in text.\n"},
+
+    // Check recovery from '\0'.  We have to explicitly specify the length of
+    // these strings because otherwise the string constructor will just call
+    // strlen() which will see the first '\0' and think that is the end of the
+    // string.
+    {std::string("\0foo", 4), true,
+     "0:0: Invalid control characters encountered in text.\n"},
+    {std::string("\0\0foo", 5), true,
+     "0:0: Invalid control characters encountered in text.\n"},
+
+    // Check error from high order bits set
+    {"\300foo", true, "0:0: Interpreting non ascii codepoint 192.\n"},
+};
+
+TEST_2D(TokenizerTest, Errors, kErrorCases, kBlockSizes) {
+  // Set up the tokenizer.
+  TestInputStream input(kErrorCases_case.input.data(),
+                        kErrorCases_case.input.size(), kBlockSizes_case);
+  TestErrorCollector error_collector;
+  Tokenizer tokenizer(&input, &error_collector);
+
+  // Ignore all input, except remember if the last token was "foo".
+  bool last_was_foo = false;
+  while (tokenizer.Next()) {
+    last_was_foo = tokenizer.current().text == "foo";
+  }
+
+  // Check that the errors match what was expected.
+  EXPECT_EQ(kErrorCases_case.errors, error_collector.text_);
+
+  // If the error was recoverable, make sure we saw "foo" after it.
+  if (kErrorCases_case.recoverable) {
+    EXPECT_TRUE(last_was_foo);
+  }
+}
+
+// -------------------------------------------------------------------
+
+TEST_1D(TokenizerTest, BackUpOnDestruction, kBlockSizes) {
+  std::string text = "foo bar";
+  TestInputStream input(text.data(), text.size(), kBlockSizes_case);
+
+  // Create a tokenizer, read one token, then destroy it.
+  {
+    TestErrorCollector error_collector;
+    Tokenizer tokenizer(&input, &error_collector);
+
+    tokenizer.Next();
+  }
+
+  // Only "foo" should have been read.
+  EXPECT_EQ(strlen("foo"), input.ByteCount());
+}
+
+
+}  // namespace
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/zero_copy_stream.cc b/src/google/protobuf/io/zero_copy_stream.cc
new file mode 100644
index 0000000..f81555e
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream.cc
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/io/zero_copy_stream.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+
+bool ZeroCopyOutputStream::WriteAliasedRaw(const void* /* data */,
+                                           int /* size */) {
+  GOOGLE_LOG(FATAL) << "This ZeroCopyOutputStream doesn't support aliasing. "
+                "Reaching here usually means a ZeroCopyOutputStream "
+                "implementation bug.";
+  return false;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/zero_copy_stream.h b/src/google/protobuf/io/zero_copy_stream.h
new file mode 100644
index 0000000..2041cbf
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream.h
@@ -0,0 +1,260 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 the ZeroCopyInputStream and ZeroCopyOutputStream
+// interfaces, which represent abstract I/O streams to and from which
+// protocol buffers can be read and written.  For a few simple
+// implementations of these interfaces, see zero_copy_stream_impl.h.
+//
+// These interfaces are different from classic I/O streams in that they
+// try to minimize the amount of data copying that needs to be done.
+// To accomplish this, responsibility for allocating buffers is moved to
+// the stream object, rather than being the responsibility of the caller.
+// So, the stream can return a buffer which actually points directly into
+// the final data structure where the bytes are to be stored, and the caller
+// can interact directly with that buffer, eliminating an intermediate copy
+// operation.
+//
+// As an example, consider the common case in which you are reading bytes
+// from an array that is already in memory (or perhaps an mmap()ed file).
+// With classic I/O streams, you would do something like:
+//   char buffer[BUFFER_SIZE];
+//   input->Read(buffer, BUFFER_SIZE);
+//   DoSomething(buffer, BUFFER_SIZE);
+// Then, the stream basically just calls memcpy() to copy the data from
+// the array into your buffer.  With a ZeroCopyInputStream, you would do
+// this instead:
+//   const void* buffer;
+//   int size;
+//   input->Next(&buffer, &size);
+//   DoSomething(buffer, size);
+// Here, no copy is performed.  The input stream returns a pointer directly
+// into the backing array, and the caller ends up reading directly from it.
+//
+// If you want to be able to read the old-fashion way, you can create
+// a CodedInputStream or CodedOutputStream wrapping these objects and use
+// their ReadRaw()/WriteRaw() methods.  These will, of course, add a copy
+// step, but Coded*Stream will handle buffering so at least it will be
+// reasonably efficient.
+//
+// ZeroCopyInputStream example:
+//   // Read in a file and print its contents to stdout.
+//   int fd = open("myfile", O_RDONLY);
+//   ZeroCopyInputStream* input = new FileInputStream(fd);
+//
+//   const void* buffer;
+//   int size;
+//   while (input->Next(&buffer, &size)) {
+//     cout.write(buffer, size);
+//   }
+//
+//   delete input;
+//   close(fd);
+//
+// ZeroCopyOutputStream example:
+//   // Copy the contents of "infile" to "outfile", using plain read() for
+//   // "infile" but a ZeroCopyOutputStream for "outfile".
+//   int infd = open("infile", O_RDONLY);
+//   int outfd = open("outfile", O_WRONLY);
+//   ZeroCopyOutputStream* output = new FileOutputStream(outfd);
+//
+//   void* buffer;
+//   int size;
+//   while (output->Next(&buffer, &size)) {
+//     int bytes = read(infd, buffer, size);
+//     if (bytes < size) {
+//       // Reached EOF.
+//       output->BackUp(size - bytes);
+//       break;
+//     }
+//   }
+//
+//   delete output;
+//   close(infd);
+//   close(outfd);
+
+#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
+
+
+#include <google/protobuf/stubs/common.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// Defined in this file.
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+
+// Abstract interface similar to an input stream but designed to minimize
+// copying.
+class PROTOBUF_EXPORT ZeroCopyInputStream {
+ public:
+  ZeroCopyInputStream() {}
+  virtual ~ZeroCopyInputStream() {}
+
+  // Obtains a chunk of data from the stream.
+  //
+  // Preconditions:
+  // * "size" and "data" are not NULL.
+  //
+  // Postconditions:
+  // * If the returned value is false, there is no more data to return or
+  //   an error occurred.  All errors are permanent.
+  // * Otherwise, "size" points to the actual number of bytes read and "data"
+  //   points to a pointer to a buffer containing these bytes.
+  // * Ownership of this buffer remains with the stream, and the buffer
+  //   remains valid only until some other method of the stream is called
+  //   or the stream is destroyed.
+  // * It is legal for the returned buffer to have zero size, as long
+  //   as repeatedly calling Next() eventually yields a buffer with non-zero
+  //   size.
+  virtual bool Next(const void** data, int* size) = 0;
+
+  // Backs up a number of bytes, so that the next call to Next() returns
+  // data again that was already returned by the last call to Next().  This
+  // is useful when writing procedures that are only supposed to read up
+  // to a certain point in the input, then return.  If Next() returns a
+  // buffer that goes beyond what you wanted to read, you can use BackUp()
+  // to return to the point where you intended to finish.
+  //
+  // This method can be called with `count = 0` to finalize (flush) any
+  // previously returned buffer. For example, a file output stream can
+  // flush buffers returned from a previous call to Next() upon such
+  // BackUp(0) invocations. ZeroCopyOutputStream callers should always
+  // invoke BackUp() after a final Next() call, even if there is no
+  // excess buffer data to be backed up to indicate a flush point.
+  //
+  // Preconditions:
+  // * The last method called must have been Next().
+  // * count must be less than or equal to the size of the last buffer
+  //   returned by Next().
+  //
+  // Postconditions:
+  // * The last "count" bytes of the last buffer returned by Next() will be
+  //   pushed back into the stream.  Subsequent calls to Next() will return
+  //   the same data again before producing new data.
+  virtual void BackUp(int count) = 0;
+
+  // Skips a number of bytes.  Returns false if the end of the stream is
+  // reached or some input error occurred.  In the end-of-stream case, the
+  // stream is advanced to the end of the stream (so ByteCount() will return
+  // the total size of the stream).
+  virtual bool Skip(int count) = 0;
+
+  // Returns the total number of bytes read since this object was created.
+  virtual int64_t ByteCount() const = 0;
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream);
+};
+
+// Abstract interface similar to an output stream but designed to minimize
+// copying.
+class PROTOBUF_EXPORT ZeroCopyOutputStream {
+ public:
+  ZeroCopyOutputStream() {}
+  virtual ~ZeroCopyOutputStream() {}
+
+  // Obtains a buffer into which data can be written.  Any data written
+  // into this buffer will eventually (maybe instantly, maybe later on)
+  // be written to the output.
+  //
+  // Preconditions:
+  // * "size" and "data" are not NULL.
+  //
+  // Postconditions:
+  // * If the returned value is false, an error occurred.  All errors are
+  //   permanent.
+  // * Otherwise, "size" points to the actual number of bytes in the buffer
+  //   and "data" points to the buffer.
+  // * Ownership of this buffer remains with the stream, and the buffer
+  //   remains valid only until some other method of the stream is called
+  //   or the stream is destroyed.
+  // * Any data which the caller stores in this buffer will eventually be
+  //   written to the output (unless BackUp() is called).
+  // * It is legal for the returned buffer to have zero size, as long
+  //   as repeatedly calling Next() eventually yields a buffer with non-zero
+  //   size.
+  virtual bool Next(void** data, int* size) = 0;
+
+  // Backs up a number of bytes, so that the end of the last buffer returned
+  // by Next() is not actually written.  This is needed when you finish
+  // writing all the data you want to write, but the last buffer was bigger
+  // than you needed.  You don't want to write a bunch of garbage after the
+  // end of your data, so you use BackUp() to back up.
+  //
+  // Preconditions:
+  // * The last method called must have been Next().
+  // * count must be less than or equal to the size of the last buffer
+  //   returned by Next().
+  // * The caller must not have written anything to the last "count" bytes
+  //   of that buffer.
+  //
+  // Postconditions:
+  // * The last "count" bytes of the last buffer returned by Next() will be
+  //   ignored.
+  virtual void BackUp(int count) = 0;
+
+  // Returns the total number of bytes written since this object was created.
+  virtual int64_t ByteCount() const = 0;
+
+  // Write a given chunk of data to the output.  Some output streams may
+  // implement this in a way that avoids copying. Check AllowsAliasing() before
+  // calling WriteAliasedRaw(). It will GOOGLE_CHECK fail if WriteAliasedRaw() is
+  // called on a stream that does not allow aliasing.
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  virtual bool WriteAliasedRaw(const void* data, int size);
+  virtual bool AllowsAliasing() const { return false; }
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
+};
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
new file mode 100644
index 0000000..c66bc86
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -0,0 +1,372 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 _MSC_VER
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <algorithm>
+#include <iostream>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+#ifdef _WIN32
+// Win32 lseek is broken:  If invoked on a non-seekable file descriptor, its
+// return value is undefined.  We re-define it to always produce an error.
+#define lseek(fd, offset, origin) ((off_t)-1)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::open;
+using google::protobuf::io::win32::read;
+using google::protobuf::io::win32::write;
+#endif
+
+namespace {
+
+// EINTR sucks.
+int close_no_eintr(int fd) {
+  int result;
+  do {
+    result = close(fd);
+  } while (result < 0 && errno == EINTR);
+  return result;
+}
+
+}  // namespace
+
+// ===================================================================
+
+FileInputStream::FileInputStream(int file_descriptor, int block_size)
+    : copying_input_(file_descriptor), impl_(&copying_input_, block_size) {}
+
+bool FileInputStream::Close() { return copying_input_.Close(); }
+
+bool FileInputStream::Next(const void** data, int* size) {
+  return impl_.Next(data, size);
+}
+
+void FileInputStream::BackUp(int count) { impl_.BackUp(count); }
+
+bool FileInputStream::Skip(int count) { return impl_.Skip(count); }
+
+int64_t FileInputStream::ByteCount() const { return impl_.ByteCount(); }
+
+FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
+    int file_descriptor)
+    : file_(file_descriptor),
+      close_on_delete_(false),
+      is_closed_(false),
+      errno_(0),
+      previous_seek_failed_(false) {
+#ifndef _WIN32
+  int flags = fcntl(file_, F_GETFL);
+  flags &= ~O_NONBLOCK;
+  fcntl(file_, F_SETFL, flags);
+#endif
+}
+
+FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
+  if (close_on_delete_) {
+    if (!Close()) {
+      GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
+    }
+  }
+}
+
+bool FileInputStream::CopyingFileInputStream::Close() {
+  GOOGLE_CHECK(!is_closed_);
+
+  is_closed_ = true;
+  if (close_no_eintr(file_) != 0) {
+    // The docs on close() do not specify whether a file descriptor is still
+    // open after close() fails with EIO.  However, the glibc source code
+    // seems to indicate that it is not.
+    errno_ = errno;
+    return false;
+  }
+
+  return true;
+}
+
+int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
+  GOOGLE_CHECK(!is_closed_);
+
+  int result;
+  do {
+    result = read(file_, buffer, size);
+  } while (result < 0 && errno == EINTR);
+
+  if (result < 0) {
+    // Read error (not EOF).
+    errno_ = errno;
+  }
+
+  return result;
+}
+
+int FileInputStream::CopyingFileInputStream::Skip(int count) {
+  GOOGLE_CHECK(!is_closed_);
+
+  if (!previous_seek_failed_ && lseek(file_, count, SEEK_CUR) != (off_t)-1) {
+    // Seek succeeded.
+    return count;
+  } else {
+    // Failed to seek.
+
+    // Note to self:  Don't seek again.  This file descriptor doesn't
+    // support it.
+    previous_seek_failed_ = true;
+
+    // Use the default implementation.
+    return CopyingInputStream::Skip(count);
+  }
+}
+
+// ===================================================================
+
+FileOutputStream::FileOutputStream(int file_descriptor, int /*block_size*/)
+    : CopyingOutputStreamAdaptor(&copying_output_),
+      copying_output_(file_descriptor) {}
+
+bool FileOutputStream::Close() {
+  bool flush_succeeded = Flush();
+  return copying_output_.Close() && flush_succeeded;
+}
+
+FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
+    int file_descriptor)
+    : file_(file_descriptor),
+      close_on_delete_(false),
+      is_closed_(false),
+      errno_(0) {}
+
+FileOutputStream::~FileOutputStream() { Flush(); }
+
+FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
+  if (close_on_delete_) {
+    if (!Close()) {
+      GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
+    }
+  }
+}
+
+bool FileOutputStream::CopyingFileOutputStream::Close() {
+  GOOGLE_CHECK(!is_closed_);
+
+  is_closed_ = true;
+  if (close_no_eintr(file_) != 0) {
+    // The docs on close() do not specify whether a file descriptor is still
+    // open after close() fails with EIO.  However, the glibc source code
+    // seems to indicate that it is not.
+    errno_ = errno;
+    return false;
+  }
+
+  return true;
+}
+
+bool FileOutputStream::CopyingFileOutputStream::Write(const void* buffer,
+                                                      int size) {
+  GOOGLE_CHECK(!is_closed_);
+  int total_written = 0;
+
+  const uint8_t* buffer_base = reinterpret_cast<const uint8_t*>(buffer);
+
+  while (total_written < size) {
+    int bytes;
+    do {
+      bytes = write(file_, buffer_base + total_written, size - total_written);
+    } while (bytes < 0 && errno == EINTR);
+
+    if (bytes <= 0) {
+      // Write error.
+
+      // FIXME(kenton):  According to the man page, if write() returns zero,
+      //   there was no error; write() simply did not write anything.  It's
+      //   unclear under what circumstances this might happen, but presumably
+      //   errno won't be set in this case.  I am confused as to how such an
+      //   event should be handled.  For now I'm treating it as an error, since
+      //   retrying seems like it could lead to an infinite loop.  I suspect
+      //   this never actually happens anyway.
+
+      if (bytes < 0) {
+        errno_ = errno;
+      }
+      return false;
+    }
+    total_written += bytes;
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+IstreamInputStream::IstreamInputStream(std::istream* input, int block_size)
+    : copying_input_(input), impl_(&copying_input_, block_size) {}
+
+bool IstreamInputStream::Next(const void** data, int* size) {
+  return impl_.Next(data, size);
+}
+
+void IstreamInputStream::BackUp(int count) { impl_.BackUp(count); }
+
+bool IstreamInputStream::Skip(int count) { return impl_.Skip(count); }
+
+int64_t IstreamInputStream::ByteCount() const { return impl_.ByteCount(); }
+
+IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
+    std::istream* input)
+    : input_(input) {}
+
+IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
+
+int IstreamInputStream::CopyingIstreamInputStream::Read(void* buffer,
+                                                        int size) {
+  input_->read(reinterpret_cast<char*>(buffer), size);
+  int result = input_->gcount();
+  if (result == 0 && input_->fail() && !input_->eof()) {
+    return -1;
+  }
+  return result;
+}
+
+// ===================================================================
+
+OstreamOutputStream::OstreamOutputStream(std::ostream* output, int block_size)
+    : copying_output_(output), impl_(&copying_output_, block_size) {}
+
+OstreamOutputStream::~OstreamOutputStream() { impl_.Flush(); }
+
+bool OstreamOutputStream::Next(void** data, int* size) {
+  return impl_.Next(data, size);
+}
+
+void OstreamOutputStream::BackUp(int count) { impl_.BackUp(count); }
+
+int64_t OstreamOutputStream::ByteCount() const { return impl_.ByteCount(); }
+
+OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
+    std::ostream* output)
+    : output_(output) {}
+
+OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
+}
+
+bool OstreamOutputStream::CopyingOstreamOutputStream::Write(const void* buffer,
+                                                            int size) {
+  output_->write(reinterpret_cast<const char*>(buffer), size);
+  return output_->good();
+}
+
+// ===================================================================
+
+ConcatenatingInputStream::ConcatenatingInputStream(
+    ZeroCopyInputStream* const streams[], int count)
+    : streams_(streams), stream_count_(count), bytes_retired_(0) {
+}
+
+bool ConcatenatingInputStream::Next(const void** data, int* size) {
+  while (stream_count_ > 0) {
+    if (streams_[0]->Next(data, size)) return true;
+
+    // That stream is done.  Advance to the next one.
+    bytes_retired_ += streams_[0]->ByteCount();
+    ++streams_;
+    --stream_count_;
+  }
+
+  // No more streams.
+  return false;
+}
+
+void ConcatenatingInputStream::BackUp(int count) {
+  if (stream_count_ > 0) {
+    streams_[0]->BackUp(count);
+  } else {
+    GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next().";
+  }
+}
+
+bool ConcatenatingInputStream::Skip(int count) {
+  while (stream_count_ > 0) {
+    // Assume that ByteCount() can be used to find out how much we actually
+    // skipped when Skip() fails.
+    int64_t target_byte_count = streams_[0]->ByteCount() + count;
+    if (streams_[0]->Skip(count)) return true;
+
+    // Hit the end of the stream.  Figure out how many more bytes we still have
+    // to skip.
+    int64_t final_byte_count = streams_[0]->ByteCount();
+    GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
+    count = target_byte_count - final_byte_count;
+
+    // That stream is done.  Advance to the next one.
+    bytes_retired_ += final_byte_count;
+    ++streams_;
+    --stream_count_;
+  }
+
+  return false;
+}
+
+int64_t ConcatenatingInputStream::ByteCount() const {
+  if (stream_count_ == 0) {
+    return bytes_retired_;
+  } else {
+    return bytes_retired_ + streams_[0]->ByteCount();
+  }
+}
+
+
+// ===================================================================
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h
new file mode 100644
index 0000000..a385992
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_impl.h
@@ -0,0 +1,336 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 common implementations of the interfaces defined in
+// zero_copy_stream.h which are only included in the full (non-lite)
+// protobuf library.  These implementations include Unix file descriptors
+// and C++ iostreams.  See also:  zero_copy_stream_impl_lite.h
+
+#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
+
+
+#include <iosfwd>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// ===================================================================
+
+// A ZeroCopyInputStream which reads from a file descriptor.
+//
+// FileInputStream is preferred over using an ifstream with IstreamInputStream.
+// The latter will introduce an extra layer of buffering, harming performance.
+// Also, it's conceivable that FileInputStream could someday be enhanced
+// to use zero-copy file descriptors on OSs which support them.
+class PROTOBUF_EXPORT FileInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Creates a stream that reads from the given Unix file descriptor.
+  // If a block_size is given, it specifies the number of bytes that
+  // should be read and returned with each call to Next().  Otherwise,
+  // a reasonable default is used.
+  explicit FileInputStream(int file_descriptor, int block_size = -1);
+
+  // Flushes any buffers and closes the underlying file.  Returns false if
+  // an error occurs during the process; use GetErrno() to examine the error.
+  // Even if an error occurs, the file descriptor is closed when this returns.
+  bool Close();
+
+  // By default, the file descriptor is not closed when the stream is
+  // destroyed.  Call SetCloseOnDelete(true) to change that.  WARNING:
+  // This leaves no way for the caller to detect if close() fails.  If
+  // detecting close() errors is important to you, you should arrange
+  // to close the descriptor yourself.
+  void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); }
+
+  // If an I/O error has occurred on this file descriptor, this is the
+  // errno from that error.  Otherwise, this is zero.  Once an error
+  // occurs, the stream is broken and all subsequent operations will
+  // fail.
+  int GetErrno() const { return copying_input_.GetErrno(); }
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  class PROTOBUF_EXPORT CopyingFileInputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingInputStream {
+   public:
+    CopyingFileInputStream(int file_descriptor);
+    ~CopyingFileInputStream() override;
+
+    bool Close();
+    void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
+    int GetErrno() const { return errno_; }
+
+    // implements CopyingInputStream ---------------------------------
+    int Read(void* buffer, int size) override;
+    int Skip(int count) override;
+
+   private:
+    // The file descriptor.
+    const int file_;
+    bool close_on_delete_;
+    bool is_closed_;
+
+    // The errno of the I/O error, if one has occurred.  Otherwise, zero.
+    int errno_;
+
+    // Did we try to seek once and fail?  If so, we assume this file descriptor
+    // doesn't support seeking and won't try again.
+    bool previous_seek_failed_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream);
+  };
+
+  CopyingFileInputStream copying_input_;
+  CopyingInputStreamAdaptor impl_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream which writes to a file descriptor.
+//
+// FileOutputStream is preferred over using an ofstream with
+// OstreamOutputStream.  The latter will introduce an extra layer of buffering,
+// harming performance.  Also, it's conceivable that FileOutputStream could
+// someday be enhanced to use zero-copy file descriptors on OSs which
+// support them.
+class PROTOBUF_EXPORT FileOutputStream PROTOBUF_FUTURE_FINAL
+    : public CopyingOutputStreamAdaptor {
+ public:
+  // Creates a stream that writes to the given Unix file descriptor.
+  // If a block_size is given, it specifies the size of the buffers
+  // that should be returned by Next().  Otherwise, a reasonable default
+  // is used.
+  explicit FileOutputStream(int file_descriptor, int block_size = -1);
+
+  ~FileOutputStream() override;
+
+  // Flushes any buffers and closes the underlying file.  Returns false if
+  // an error occurs during the process; use GetErrno() to examine the error.
+  // Even if an error occurs, the file descriptor is closed when this returns.
+  bool Close();
+
+  // By default, the file descriptor is not closed when the stream is
+  // destroyed.  Call SetCloseOnDelete(true) to change that.  WARNING:
+  // This leaves no way for the caller to detect if close() fails.  If
+  // detecting close() errors is important to you, you should arrange
+  // to close the descriptor yourself.
+  void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); }
+
+  // If an I/O error has occurred on this file descriptor, this is the
+  // errno from that error.  Otherwise, this is zero.  Once an error
+  // occurs, the stream is broken and all subsequent operations will
+  // fail.
+  int GetErrno() const { return copying_output_.GetErrno(); }
+
+ private:
+  class PROTOBUF_EXPORT CopyingFileOutputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingOutputStream {
+   public:
+    CopyingFileOutputStream(int file_descriptor);
+    ~CopyingFileOutputStream() override;
+
+    bool Close();
+    void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
+    int GetErrno() const { return errno_; }
+
+    // implements CopyingOutputStream --------------------------------
+    bool Write(const void* buffer, int size) override;
+
+   private:
+    // The file descriptor.
+    const int file_;
+    bool close_on_delete_;
+    bool is_closed_;
+
+    // The errno of the I/O error, if one has occurred.  Otherwise, zero.
+    int errno_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream);
+  };
+
+  CopyingFileOutputStream copying_output_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which reads from a C++ istream.
+//
+// Note that for reading files (or anything represented by a file descriptor),
+// FileInputStream is more efficient.
+class PROTOBUF_EXPORT IstreamInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Creates a stream that reads from the given C++ istream.
+  // If a block_size is given, it specifies the number of bytes that
+  // should be read and returned with each call to Next().  Otherwise,
+  // a reasonable default is used.
+  explicit IstreamInputStream(std::istream* stream, int block_size = -1);
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  class PROTOBUF_EXPORT CopyingIstreamInputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingInputStream {
+   public:
+    CopyingIstreamInputStream(std::istream* input);
+    ~CopyingIstreamInputStream() override;
+
+    // implements CopyingInputStream ---------------------------------
+    int Read(void* buffer, int size) override;
+    // (We use the default implementation of Skip().)
+
+   private:
+    // The stream.
+    std::istream* input_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream);
+  };
+
+  CopyingIstreamInputStream copying_input_;
+  CopyingInputStreamAdaptor impl_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream which writes to a C++ ostream.
+//
+// Note that for writing files (or anything represented by a file descriptor),
+// FileOutputStream is more efficient.
+class PROTOBUF_EXPORT OstreamOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Creates a stream that writes to the given C++ ostream.
+  // If a block_size is given, it specifies the size of the buffers
+  // that should be returned by Next().  Otherwise, a reasonable default
+  // is used.
+  explicit OstreamOutputStream(std::ostream* stream, int block_size = -1);
+  ~OstreamOutputStream() override;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  class PROTOBUF_EXPORT CopyingOstreamOutputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingOutputStream {
+   public:
+    CopyingOstreamOutputStream(std::ostream* output);
+    ~CopyingOstreamOutputStream() override;
+
+    // implements CopyingOutputStream --------------------------------
+    bool Write(const void* buffer, int size) override;
+
+   private:
+    // The stream.
+    std::ostream* output_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream);
+  };
+
+  CopyingOstreamOutputStream copying_output_;
+  CopyingOutputStreamAdaptor impl_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which reads from several other streams in sequence.
+// ConcatenatingInputStream is unable to distinguish between end-of-stream
+// and read errors in the underlying streams, so it assumes any errors mean
+// end-of-stream.  So, if the underlying streams fail for any other reason,
+// ConcatenatingInputStream may do odd things.  It is suggested that you do
+// not use ConcatenatingInputStream on streams that might produce read errors
+// other than end-of-stream.
+class PROTOBUF_EXPORT ConcatenatingInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // All streams passed in as well as the array itself must remain valid
+  // until the ConcatenatingInputStream is destroyed.
+  ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count);
+  ~ConcatenatingInputStream() override = default;
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+
+ private:
+  // As streams are retired, streams_ is incremented and count_ is
+  // decremented.
+  ZeroCopyInputStream* const* streams_;
+  int stream_count_;
+  int64_t bytes_retired_;  // Bytes read from previous streams.
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
+};
+
+// ===================================================================
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_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
new file mode 100644
index 0000000..b3dfd84
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -0,0 +1,470 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/io/zero_copy_stream_impl_lite.h>
+
+#include <algorithm>
+#include <limits>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+namespace {
+
+// Default block size for Copying{In,Out}putStreamAdaptor.
+static const int kDefaultBlockSize = 8192;
+
+}  // namespace
+
+// ===================================================================
+
+ArrayInputStream::ArrayInputStream(const void* data, int size, int block_size)
+    : data_(reinterpret_cast<const uint8_t*>(data)),
+      size_(size),
+      block_size_(block_size > 0 ? block_size : size),
+      position_(0),
+      last_returned_size_(0) {}
+
+bool ArrayInputStream::Next(const void** data, int* size) {
+  if (position_ < size_) {
+    last_returned_size_ = std::min(block_size_, size_ - position_);
+    *data = data_ + position_;
+    *size = last_returned_size_;
+    position_ += last_returned_size_;
+    return true;
+  } else {
+    // We're at the end of the array.
+    last_returned_size_ = 0;  // Don't let caller back up.
+    return false;
+  }
+}
+
+void ArrayInputStream::BackUp(int count) {
+  GOOGLE_CHECK_GT(last_returned_size_, 0)
+      << "BackUp() can only be called after a successful Next().";
+  GOOGLE_CHECK_LE(count, last_returned_size_);
+  GOOGLE_CHECK_GE(count, 0);
+  position_ -= count;
+  last_returned_size_ = 0;  // Don't let caller back up further.
+}
+
+bool ArrayInputStream::Skip(int count) {
+  GOOGLE_CHECK_GE(count, 0);
+  last_returned_size_ = 0;  // Don't let caller back up.
+  if (count > size_ - position_) {
+    position_ = size_;
+    return false;
+  } else {
+    position_ += count;
+    return true;
+  }
+}
+
+int64_t ArrayInputStream::ByteCount() const { return position_; }
+
+
+// ===================================================================
+
+ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
+    : data_(reinterpret_cast<uint8_t*>(data)),
+      size_(size),
+      block_size_(block_size > 0 ? block_size : size),
+      position_(0),
+      last_returned_size_(0) {}
+
+bool ArrayOutputStream::Next(void** data, int* size) {
+  if (position_ < size_) {
+    last_returned_size_ = std::min(block_size_, size_ - position_);
+    *data = data_ + position_;
+    *size = last_returned_size_;
+    position_ += last_returned_size_;
+    return true;
+  } else {
+    // We're at the end of the array.
+    last_returned_size_ = 0;  // Don't let caller back up.
+    return false;
+  }
+}
+
+void ArrayOutputStream::BackUp(int count) {
+  GOOGLE_CHECK_LE(count, last_returned_size_)
+      << "BackUp() can not exceed the size of the last Next() call.";
+  GOOGLE_CHECK_GE(count, 0);
+  position_ -= count;
+  last_returned_size_ -= count;
+}
+
+int64_t ArrayOutputStream::ByteCount() const { return position_; }
+
+// ===================================================================
+
+StringOutputStream::StringOutputStream(std::string* target) : target_(target) {}
+
+bool StringOutputStream::Next(void** data, int* size) {
+  GOOGLE_CHECK(target_ != NULL);
+  size_t old_size = target_->size();
+
+  // Grow the string.
+  size_t new_size;
+  if (old_size < target_->capacity()) {
+    // Resize the string to match its capacity, since we can get away
+    // without a memory allocation this way.
+    new_size = target_->capacity();
+  } else {
+    // Size has reached capacity, try to double it.
+    new_size = old_size * 2;
+  }
+  // Avoid integer overflow in returned '*size'.
+  new_size = std::min(new_size, old_size + std::numeric_limits<int>::max());
+  // Increase the size, also make sure that it is at least kMinimumSize.
+  STLStringResizeUninitialized(
+      target_,
+      std::max(new_size,
+               kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
+
+  *data = mutable_string_data(target_) + old_size;
+  *size = target_->size() - old_size;
+  return true;
+}
+
+void StringOutputStream::BackUp(int count) {
+  GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK(target_ != NULL);
+  GOOGLE_CHECK_LE(static_cast<size_t>(count), target_->size());
+  target_->resize(target_->size() - count);
+}
+
+int64_t StringOutputStream::ByteCount() const {
+  GOOGLE_CHECK(target_ != NULL);
+  return target_->size();
+}
+
+// ===================================================================
+
+int CopyingInputStream::Skip(int count) {
+  char junk[4096];
+  int skipped = 0;
+  while (skipped < count) {
+    int bytes = Read(junk, std::min(count - skipped,
+                                    implicit_cast<int>(sizeof(junk))));
+    if (bytes <= 0) {
+      // EOF or read error.
+      return skipped;
+    }
+    skipped += bytes;
+  }
+  return skipped;
+}
+
+CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
+    CopyingInputStream* copying_stream, int block_size)
+    : copying_stream_(copying_stream),
+      owns_copying_stream_(false),
+      failed_(false),
+      position_(0),
+      buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
+      buffer_used_(0),
+      backup_bytes_(0) {}
+
+CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
+  if (owns_copying_stream_) {
+    delete copying_stream_;
+  }
+}
+
+bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
+  if (failed_) {
+    // Already failed on a previous read.
+    return false;
+  }
+
+  AllocateBufferIfNeeded();
+
+  if (backup_bytes_ > 0) {
+    // We have data left over from a previous BackUp(), so just return that.
+    *data = buffer_.get() + buffer_used_ - backup_bytes_;
+    *size = backup_bytes_;
+    backup_bytes_ = 0;
+    return true;
+  }
+
+  // Read new data into the buffer.
+  buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
+  if (buffer_used_ <= 0) {
+    // EOF or read error.  We don't need the buffer anymore.
+    if (buffer_used_ < 0) {
+      // Read error (not EOF).
+      failed_ = true;
+    }
+    FreeBuffer();
+    return false;
+  }
+  position_ += buffer_used_;
+
+  *size = buffer_used_;
+  *data = buffer_.get();
+  return true;
+}
+
+void CopyingInputStreamAdaptor::BackUp(int count) {
+  GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
+      << " BackUp() can only be called after Next().";
+  GOOGLE_CHECK_LE(count, buffer_used_)
+      << " Can't back up over more bytes than were returned by the last call"
+         " to Next().";
+  GOOGLE_CHECK_GE(count, 0) << " Parameter to BackUp() can't be negative.";
+
+  backup_bytes_ = count;
+}
+
+bool CopyingInputStreamAdaptor::Skip(int count) {
+  GOOGLE_CHECK_GE(count, 0);
+
+  if (failed_) {
+    // Already failed on a previous read.
+    return false;
+  }
+
+  // First skip any bytes left over from a previous BackUp().
+  if (backup_bytes_ >= count) {
+    // We have more data left over than we're trying to skip.  Just chop it.
+    backup_bytes_ -= count;
+    return true;
+  }
+
+  count -= backup_bytes_;
+  backup_bytes_ = 0;
+
+  int skipped = copying_stream_->Skip(count);
+  position_ += skipped;
+  return skipped == count;
+}
+
+int64_t CopyingInputStreamAdaptor::ByteCount() const {
+  return position_ - backup_bytes_;
+}
+
+void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
+  if (buffer_.get() == NULL) {
+    buffer_.reset(new uint8_t[buffer_size_]);
+  }
+}
+
+void CopyingInputStreamAdaptor::FreeBuffer() {
+  GOOGLE_CHECK_EQ(backup_bytes_, 0);
+  buffer_used_ = 0;
+  buffer_.reset();
+}
+
+// ===================================================================
+
+CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
+    CopyingOutputStream* copying_stream, int block_size)
+    : copying_stream_(copying_stream),
+      owns_copying_stream_(false),
+      failed_(false),
+      position_(0),
+      buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
+      buffer_used_(0) {}
+
+CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
+  WriteBuffer();
+  if (owns_copying_stream_) {
+    delete copying_stream_;
+  }
+}
+
+bool CopyingOutputStreamAdaptor::Flush() { return WriteBuffer(); }
+
+bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
+  if (buffer_used_ == buffer_size_) {
+    if (!WriteBuffer()) return false;
+  }
+
+  AllocateBufferIfNeeded();
+
+  *data = buffer_.get() + buffer_used_;
+  *size = buffer_size_ - buffer_used_;
+  buffer_used_ = buffer_size_;
+  return true;
+}
+
+void CopyingOutputStreamAdaptor::BackUp(int count) {
+  if (count == 0) {
+    Flush();
+    return;
+  }
+  GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
+      << " BackUp() can only be called after Next().";
+  GOOGLE_CHECK_LE(count, buffer_used_)
+      << " Can't back up over more bytes than were returned by the last call"
+         " to Next().";
+
+  buffer_used_ -= count;
+}
+
+int64_t CopyingOutputStreamAdaptor::ByteCount() const {
+  return position_ + buffer_used_;
+}
+
+bool CopyingOutputStreamAdaptor::WriteAliasedRaw(const void* data, int size) {
+  if (size >= buffer_size_) {
+    if (!Flush() || !copying_stream_->Write(data, size)) {
+      return false;
+    }
+    GOOGLE_DCHECK_EQ(buffer_used_, 0);
+    position_ += size;
+    return true;
+  }
+
+  void* out;
+  int out_size;
+  while (true) {
+    if (!Next(&out, &out_size)) {
+      return false;
+    }
+
+    if (size <= out_size) {
+      std::memcpy(out, data, size);
+      BackUp(out_size - size);
+      return true;
+    }
+
+    std::memcpy(out, data, out_size);
+    data = static_cast<const char*>(data) + out_size;
+    size -= out_size;
+  }
+  return true;
+}
+
+
+bool CopyingOutputStreamAdaptor::WriteBuffer() {
+  if (failed_) {
+    // Already failed on a previous write.
+    return false;
+  }
+
+  if (buffer_used_ == 0) return true;
+
+  if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
+    position_ += buffer_used_;
+    buffer_used_ = 0;
+    return true;
+  } else {
+    failed_ = true;
+    FreeBuffer();
+    return false;
+  }
+}
+
+void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
+  if (buffer_ == NULL) {
+    buffer_.reset(new uint8_t[buffer_size_]);
+  }
+}
+
+void CopyingOutputStreamAdaptor::FreeBuffer() {
+  buffer_used_ = 0;
+  buffer_.reset();
+}
+
+// ===================================================================
+
+LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
+                                         int64_t limit)
+    : input_(input), limit_(limit) {
+  prior_bytes_read_ = input_->ByteCount();
+}
+
+LimitingInputStream::~LimitingInputStream() {
+  // If we overshot the limit, back up.
+  if (limit_ < 0) input_->BackUp(-limit_);
+}
+
+bool LimitingInputStream::Next(const void** data, int* size) {
+  if (limit_ <= 0) return false;
+  if (!input_->Next(data, size)) return false;
+
+  limit_ -= *size;
+  if (limit_ < 0) {
+    // We overshot the limit.  Reduce *size to hide the rest of the buffer.
+    *size += limit_;
+  }
+  return true;
+}
+
+void LimitingInputStream::BackUp(int count) {
+  if (limit_ < 0) {
+    input_->BackUp(count - limit_);
+    limit_ = count;
+  } else {
+    input_->BackUp(count);
+    limit_ += count;
+  }
+}
+
+bool LimitingInputStream::Skip(int count) {
+  if (count > limit_) {
+    if (limit_ < 0) return false;
+    input_->Skip(limit_);
+    limit_ = 0;
+    return false;
+  } else {
+    if (!input_->Skip(count)) return false;
+    limit_ -= count;
+    return true;
+  }
+}
+
+int64_t LimitingInputStream::ByteCount() const {
+  if (limit_ < 0) {
+    return input_->ByteCount() + limit_ - prior_bytes_read_;
+  } else {
+    return input_->ByteCount() - prior_bytes_read_;
+  }
+}
+
+
+// ===================================================================
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
new file mode 100644
index 0000000..cbda328
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains common implementations of the interfaces defined in
+// zero_copy_stream.h which are included in the "lite" protobuf library.
+// These implementations cover I/O on raw arrays and strings, as well as
+// adaptors which make it easy to implement streams based on traditional
+// streams.  Of course, many users will probably want to write their own
+// implementations of these interfaces specific to the particular I/O
+// abstractions they prefer to use, but these should cover the most common
+// cases.
+
+#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
+
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// ===================================================================
+
+// A ZeroCopyInputStream backed by an in-memory array of bytes.
+class PROTOBUF_EXPORT ArrayInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Create an InputStream that returns the bytes pointed to by "data".
+  // "data" remains the property of the caller but must remain valid until
+  // the stream is destroyed.  If a block_size is given, calls to Next()
+  // will return data blocks no larger than the given size.  Otherwise, the
+  // first call to Next() returns the entire array.  block_size is mainly
+  // useful for testing; in production you would probably never want to set
+  // it.
+  ArrayInputStream(const void* data, int size, int block_size = -1);
+  ~ArrayInputStream() override = default;
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+
+ private:
+  const uint8_t* const data_;  // The byte array.
+  const int size_;           // Total size of the array.
+  const int block_size_;     // How many bytes to return at a time.
+
+  int position_;
+  int last_returned_size_;  // How many bytes we returned last time Next()
+                            // was called (used for error checking only).
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream backed by an in-memory array of bytes.
+class PROTOBUF_EXPORT ArrayOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Create an OutputStream that writes to the bytes pointed to by "data".
+  // "data" remains the property of the caller but must remain valid until
+  // the stream is destroyed.  If a block_size is given, calls to Next()
+  // will return data blocks no larger than the given size.  Otherwise, the
+  // first call to Next() returns the entire array.  block_size is mainly
+  // useful for testing; in production you would probably never want to set
+  // it.
+  ArrayOutputStream(void* data, int size, int block_size = -1);
+  ~ArrayOutputStream() override = default;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  uint8_t* const data_;     // The byte array.
+  const int size_;        // Total size of the array.
+  const int block_size_;  // How many bytes to return at a time.
+
+  int position_;
+  int last_returned_size_;  // How many bytes we returned last time Next()
+                            // was called (used for error checking only).
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream which appends bytes to a string.
+class PROTOBUF_EXPORT StringOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Create a StringOutputStream which appends bytes to the given string.
+  // The string remains property of the caller, but it is mutated in arbitrary
+  // ways and MUST NOT be accessed in any way until you're done with the
+  // stream. Either be sure there's no further usage, or (safest) destroy the
+  // stream before using the contents.
+  //
+  // Hint:  If you call target->reserve(n) before creating the stream,
+  //   the first call to Next() will return at least n bytes of buffer
+  //   space.
+  explicit StringOutputStream(std::string* target);
+  ~StringOutputStream() override = default;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  static constexpr size_t kMinimumSize = 16;
+
+  std::string* target_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
+};
+
+// Note:  There is no StringInputStream.  Instead, just create an
+// ArrayInputStream as follows:
+//   ArrayInputStream input(str.data(), str.size());
+
+// ===================================================================
+
+// A generic traditional input stream interface.
+//
+// Lots of traditional input streams (e.g. file descriptors, C stdio
+// streams, and C++ iostreams) expose an interface where every read
+// involves copying bytes into a buffer.  If you want to take such an
+// interface and make a ZeroCopyInputStream based on it, simply implement
+// CopyingInputStream and then use CopyingInputStreamAdaptor.
+//
+// CopyingInputStream implementations should avoid buffering if possible.
+// CopyingInputStreamAdaptor does its own buffering and will read data
+// in large blocks.
+class PROTOBUF_EXPORT CopyingInputStream {
+ public:
+  virtual ~CopyingInputStream() {}
+
+  // Reads up to "size" bytes into the given buffer.  Returns the number of
+  // bytes read.  Read() waits until at least one byte is available, or
+  // returns zero if no bytes will ever become available (EOF), or -1 if a
+  // permanent read error occurred.
+  virtual int Read(void* buffer, int size) = 0;
+
+  // Skips the next "count" bytes of input.  Returns the number of bytes
+  // actually skipped.  This will always be exactly equal to "count" unless
+  // EOF was reached or a permanent read error occurred.
+  //
+  // The default implementation just repeatedly calls Read() into a scratch
+  // buffer.
+  virtual int Skip(int count);
+};
+
+// A ZeroCopyInputStream which reads from a CopyingInputStream.  This is
+// useful for implementing ZeroCopyInputStreams that read from traditional
+// streams.  Note that this class is not really zero-copy.
+//
+// If you want to read from file descriptors or C++ istreams, this is
+// already implemented for you:  use FileInputStream or IstreamInputStream
+// respectively.
+class PROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
+ public:
+  // Creates a stream that reads from the given CopyingInputStream.
+  // If a block_size is given, it specifies the number of bytes that
+  // should be read and returned with each call to Next().  Otherwise,
+  // a reasonable default is used.  The caller retains ownership of
+  // copying_stream unless SetOwnsCopyingStream(true) is called.
+  explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream,
+                                     int block_size = -1);
+  ~CopyingInputStreamAdaptor() override;
+
+  // Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to
+  // delete the underlying CopyingInputStream when it is destroyed.
+  void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  // Insures that buffer_ is not NULL.
+  void AllocateBufferIfNeeded();
+  // Frees the buffer and resets buffer_used_.
+  void FreeBuffer();
+
+  // The underlying copying stream.
+  CopyingInputStream* copying_stream_;
+  bool owns_copying_stream_;
+
+  // True if we have seen a permanent error from the underlying stream.
+  bool failed_;
+
+  // The current position of copying_stream_, relative to the point where
+  // we started reading.
+  int64_t position_;
+
+  // 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_.
+  std::unique_ptr<uint8_t[]> buffer_;
+  const int buffer_size_;
+
+  // Number of valid bytes currently in the buffer (i.e. the size last
+  // returned by Next()).  0 <= buffer_used_ <= buffer_size_.
+  int buffer_used_;
+
+  // Number of bytes in the buffer which were backed up over by a call to
+  // BackUp().  These need to be returned again.
+  // 0 <= backup_bytes_ <= buffer_used_
+  int backup_bytes_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor);
+};
+
+// ===================================================================
+
+// A generic traditional output stream interface.
+//
+// Lots of traditional output streams (e.g. file descriptors, C stdio
+// streams, and C++ iostreams) expose an interface where every write
+// involves copying bytes from a buffer.  If you want to take such an
+// interface and make a ZeroCopyOutputStream based on it, simply implement
+// CopyingOutputStream and then use CopyingOutputStreamAdaptor.
+//
+// CopyingOutputStream implementations should avoid buffering if possible.
+// CopyingOutputStreamAdaptor does its own buffering and will write data
+// in large blocks.
+class PROTOBUF_EXPORT CopyingOutputStream {
+ public:
+  virtual ~CopyingOutputStream() {}
+
+  // Writes "size" bytes from the given buffer to the output.  Returns true
+  // if successful, false on a write error.
+  virtual bool Write(const void* buffer, int size) = 0;
+};
+
+// A ZeroCopyOutputStream which writes to a CopyingOutputStream.  This is
+// useful for implementing ZeroCopyOutputStreams that write to traditional
+// streams.  Note that this class is not really zero-copy.
+//
+// If you want to write to file descriptors or C++ ostreams, this is
+// already implemented for you:  use FileOutputStream or OstreamOutputStream
+// respectively.
+class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
+ public:
+  // Creates a stream that writes to the given Unix file descriptor.
+  // If a block_size is given, it specifies the size of the buffers
+  // that should be returned by Next().  Otherwise, a reasonable default
+  // is used.
+  explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream,
+                                      int block_size = -1);
+  ~CopyingOutputStreamAdaptor() override;
+
+  // Writes all pending data to the underlying stream.  Returns false if a
+  // write error occurred on the underlying stream.  (The underlying
+  // stream itself is not necessarily flushed.)
+  bool Flush();
+
+  // Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to
+  // delete the underlying CopyingOutputStream when it is destroyed.
+  void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+  bool WriteAliasedRaw(const void* data, int size) override;
+  bool AllowsAliasing() const override { return true; }
+
+ private:
+  // Write the current buffer, if it is present.
+  bool WriteBuffer();
+  // Insures that buffer_ is not NULL.
+  void AllocateBufferIfNeeded();
+  // Frees the buffer.
+  void FreeBuffer();
+
+  // The underlying copying stream.
+  CopyingOutputStream* copying_stream_;
+  bool owns_copying_stream_;
+
+  // True if we have seen a permanent error from the underlying stream.
+  bool failed_;
+
+  // The current position of copying_stream_, relative to the point where
+  // we started writing.
+  int64_t position_;
+
+  // 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_.
+  std::unique_ptr<uint8_t[]> buffer_;
+  const int buffer_size_;
+
+  // Number of valid bytes currently in the buffer (i.e. the size last
+  // returned by Next()).  When BackUp() is called, we just reduce this.
+  // 0 <= buffer_used_ <= buffer_size_.
+  int buffer_used_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which wraps some other stream and limits it to
+// a particular byte count.
+class PROTOBUF_EXPORT LimitingInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  LimitingInputStream(ZeroCopyInputStream* input, int64_t limit);
+  ~LimitingInputStream() override;
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+
+ private:
+  ZeroCopyInputStream* input_;
+  int64_t limit_;  // Decreases as we go, becomes negative if we overshoot.
+  int64_t prior_bytes_read_;  // Bytes read on underlying stream at construction
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
+};
+
+
+// ===================================================================
+
+// mutable_string_data() and as_string_data() are workarounds to improve
+// the performance of writing new data to an existing string.  Unfortunately
+// the methods provided by the string class are suboptimal, and using memcpy()
+// is mildly annoying because it requires its pointer args to be non-NULL even
+// if we ask it to copy 0 bytes.  Furthermore, string_as_array() has the
+// property that it always returns NULL if its arg is the empty string, exactly
+// what we want to avoid if we're using it in conjunction with memcpy()!
+// With C++11, the desired memcpy() boils down to memcpy(..., &(*s)[0], size),
+// where s is a string*.  Without C++11, &(*s)[0] is not guaranteed to be safe,
+// so we use string_as_array(), and live with the extra logic that tests whether
+// *s is empty.
+
+// Return a pointer to mutable characters underlying the given string.  The
+// return value is valid until the next time the string is resized.  We
+// trust the caller to treat the return value as an array of length s->size().
+inline char* mutable_string_data(std::string* s) {
+  // This should be simpler & faster than string_as_array() because the latter
+  // is guaranteed to return NULL when *s is empty, so it has to check for that.
+  return &(*s)[0];
+}
+
+// as_string_data(s) is equivalent to
+//  ({ char* p = mutable_string_data(s); make_pair(p, p != NULL); })
+// Sometimes it's faster: in some scenarios p cannot be NULL, and then the
+// code can avoid that check.
+inline std::pair<char*, bool> as_string_data(std::string* s) {
+  char* p = mutable_string_data(s);
+  return std::make_pair(p, true);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc
new file mode 100644
index 0000000..d4e5b54
--- /dev/null
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -0,0 +1,1088 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Testing strategy:  For each type of I/O (array, string, file, etc.) we
+// create an output stream and write some data to it, then create a
+// corresponding input stream to read the same data back and expect it to
+// match.  When the data is written, it is written in several small chunks
+// of varying sizes, with a BackUp() after each chunk.  It is read back
+// similarly, but with chunks separated at different points.  The whole
+// process is run with a variety of block sizes for both the input and
+// the output.
+//
+// TODO(kenton):  Rewrite this test to bring it up to the standards of all
+//   the other proto2 tests.  May want to wait for gTest to implement
+//   "parametized tests" so that one set of tests can be used on all the
+//   implementations.
+
+#include <chrono>
+#include <thread>
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <sstream>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#if HAVE_ZLIB
+#include <google/protobuf/io/gzip_stream.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace {
+
+#ifdef _WIN32
+#define pipe(fds) _pipe(fds, 4096, O_BINARY)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::mkdir;
+using google::protobuf::io::win32::open;
+#endif
+
+#ifndef O_BINARY
+#ifdef _O_BINARY
+#define O_BINARY _O_BINARY
+#else
+#define O_BINARY 0  // If this isn't defined, the platform doesn't need it.
+#endif
+#endif
+
+class IoTest : public testing::Test {
+ protected:
+  // Test helpers.
+
+  // Helper to write an array of data to an output stream.
+  bool WriteToOutput(ZeroCopyOutputStream* output, const void* data, int size);
+  // Helper to read a fixed-length array of data from an input stream.
+  int ReadFromInput(ZeroCopyInputStream* input, void* data, int size);
+  // Write a string to the output stream.
+  void WriteString(ZeroCopyOutputStream* output, const std::string& str);
+  // Read a number of bytes equal to the size of the given string and checks
+  // that it matches the string.
+  void ReadString(ZeroCopyInputStream* input, const std::string& str);
+  // Writes some text to the output stream in a particular order.  Returns
+  // the number of bytes written, in case the caller needs that to set up an
+  // input stream.
+  int WriteStuff(ZeroCopyOutputStream* output);
+  // Reads text from an input stream and expects it to match what
+  // WriteStuff() writes.
+  void ReadStuff(ZeroCopyInputStream* input, bool read_eof = true);
+
+  // Similar to WriteStuff, but performs more sophisticated testing.
+  int WriteStuffLarge(ZeroCopyOutputStream* output);
+  // Reads and tests a stream that should have been written to
+  // via WriteStuffLarge().
+  void ReadStuffLarge(ZeroCopyInputStream* input);
+
+#if HAVE_ZLIB
+  std::string Compress(const std::string& data,
+                       const GzipOutputStream::Options& options);
+  std::string Uncompress(const std::string& data);
+#endif
+
+  static const int kBlockSizes[];
+  static const int kBlockSizeCount;
+};
+
+const int IoTest::kBlockSizes[] = {-1, 1, 2, 5, 7, 10, 23, 64};
+const int IoTest::kBlockSizeCount = GOOGLE_ARRAYSIZE(IoTest::kBlockSizes);
+
+bool IoTest::WriteToOutput(ZeroCopyOutputStream* output, const void* data,
+                           int size) {
+  const uint8* in = reinterpret_cast<const uint8*>(data);
+  int in_size = size;
+
+  void* out;
+  int out_size;
+
+  while (true) {
+    if (!output->Next(&out, &out_size)) {
+      return false;
+    }
+    EXPECT_GT(out_size, 0);
+
+    if (in_size <= out_size) {
+      memcpy(out, in, in_size);
+      output->BackUp(out_size - in_size);
+      return true;
+    }
+
+    memcpy(out, in, out_size);
+    in += out_size;
+    in_size -= out_size;
+  }
+}
+
+#define MAX_REPEATED_ZEROS 100
+
+int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) {
+  uint8* out = reinterpret_cast<uint8*>(data);
+  int out_size = size;
+
+  const void* in;
+  int in_size = 0;
+
+  int repeated_zeros = 0;
+
+  while (true) {
+    if (!input->Next(&in, &in_size)) {
+      return size - out_size;
+    }
+    EXPECT_GT(in_size, -1);
+    if (in_size == 0) {
+      repeated_zeros++;
+    } else {
+      repeated_zeros = 0;
+    }
+    EXPECT_LT(repeated_zeros, MAX_REPEATED_ZEROS);
+
+    if (out_size <= in_size) {
+      memcpy(out, in, out_size);
+      if (in_size > out_size) {
+        input->BackUp(in_size - out_size);
+      }
+      return size;  // Copied all of it.
+    }
+
+    memcpy(out, in, in_size);
+    out += in_size;
+    out_size -= in_size;
+  }
+}
+
+void IoTest::WriteString(ZeroCopyOutputStream* output, const std::string& str) {
+  EXPECT_TRUE(WriteToOutput(output, str.c_str(), str.size()));
+}
+
+void IoTest::ReadString(ZeroCopyInputStream* input, const std::string& str) {
+  std::unique_ptr<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());
+}
+
+int IoTest::WriteStuff(ZeroCopyOutputStream* output) {
+  WriteString(output, "Hello world!\n");
+  WriteString(output, "Some te");
+  WriteString(output, "xt.  Blah blah.");
+  WriteString(output, "abcdefg");
+  WriteString(output, "01234567890123456789");
+  WriteString(output, "foobar");
+
+  EXPECT_EQ(output->ByteCount(), 68);
+
+  int result = output->ByteCount();
+  return result;
+}
+
+// Reads text from an input stream and expects it to match what WriteStuff()
+// writes.
+void IoTest::ReadStuff(ZeroCopyInputStream* input, bool read_eof) {
+  ReadString(input, "Hello world!\n");
+  ReadString(input, "Some text.  ");
+  ReadString(input, "Blah ");
+  ReadString(input, "blah.");
+  ReadString(input, "abcdefg");
+  EXPECT_TRUE(input->Skip(20));
+  ReadString(input, "foo");
+  ReadString(input, "bar");
+
+  EXPECT_EQ(input->ByteCount(), 68);
+
+  if (read_eof) {
+    uint8 byte;
+    EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
+  }
+}
+
+int IoTest::WriteStuffLarge(ZeroCopyOutputStream* output) {
+  WriteString(output, "Hello world!\n");
+  WriteString(output, "Some te");
+  WriteString(output, "xt.  Blah blah.");
+  WriteString(output, std::string(100000, 'x'));  // A very long string
+  WriteString(output, std::string(100000, 'y'));  // A very long string
+  WriteString(output, "01234567890123456789");
+
+  EXPECT_EQ(output->ByteCount(), 200055);
+
+  int result = output->ByteCount();
+  return result;
+}
+
+// Reads text from an input stream and expects it to match what WriteStuff()
+// writes.
+void IoTest::ReadStuffLarge(ZeroCopyInputStream* input) {
+  ReadString(input, "Hello world!\nSome text.  ");
+  EXPECT_TRUE(input->Skip(5));
+  ReadString(input, "blah.");
+  EXPECT_TRUE(input->Skip(100000 - 10));
+  ReadString(input, std::string(10, 'x') + std::string(100000 - 20000, 'y'));
+  EXPECT_TRUE(input->Skip(20000 - 10));
+  ReadString(input, "yyyyyyyyyy01234567890123456789");
+
+  EXPECT_EQ(input->ByteCount(), 200055);
+
+  uint8 byte;
+  EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
+}
+
+// ===================================================================
+
+TEST_F(IoTest, ArrayIo) {
+  const int kBufferSize = 256;
+  uint8 buffer[kBufferSize];
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      int size;
+      {
+        ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
+        size = WriteStuff(&output);
+      }
+      {
+        ArrayInputStream input(buffer, size, kBlockSizes[j]);
+        ReadStuff(&input);
+      }
+    }
+  }
+}
+
+TEST_F(IoTest, TwoSessionWrite) {
+  // Test that two concatenated write sessions read correctly
+
+  static const char* strA = "0123456789";
+  static const char* strB = "WhirledPeas";
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+  char* temp_buffer = new char[40];
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      ArrayOutputStream* output =
+          new ArrayOutputStream(buffer, kBufferSize, kBlockSizes[i]);
+      CodedOutputStream* coded_output = new CodedOutputStream(output);
+      coded_output->WriteVarint32(strlen(strA));
+      coded_output->WriteRaw(strA, strlen(strA));
+      delete coded_output;  // flush
+      int64 pos = output->ByteCount();
+      delete output;
+      output = new ArrayOutputStream(buffer + pos, kBufferSize - pos,
+                                     kBlockSizes[i]);
+      coded_output = new CodedOutputStream(output);
+      coded_output->WriteVarint32(strlen(strB));
+      coded_output->WriteRaw(strB, strlen(strB));
+      delete coded_output;  // flush
+      int64 size = pos + output->ByteCount();
+      delete output;
+
+      ArrayInputStream* input =
+          new ArrayInputStream(buffer, size, kBlockSizes[j]);
+      CodedInputStream* coded_input = new CodedInputStream(input);
+      uint32 insize;
+      EXPECT_TRUE(coded_input->ReadVarint32(&insize));
+      EXPECT_EQ(strlen(strA), insize);
+      EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
+      EXPECT_EQ(0, memcmp(temp_buffer, strA, insize));
+
+      EXPECT_TRUE(coded_input->ReadVarint32(&insize));
+      EXPECT_EQ(strlen(strB), insize);
+      EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
+      EXPECT_EQ(0, memcmp(temp_buffer, strB, insize));
+
+      delete coded_input;
+      delete input;
+    }
+  }
+
+  delete[] temp_buffer;
+  delete[] buffer;
+}
+
+#if HAVE_ZLIB
+TEST_F(IoTest, GzipIo) {
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      for (int z = 0; z < kBlockSizeCount; z++) {
+        int gzip_buffer_size = kBlockSizes[z];
+        int size;
+        {
+          ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
+          GzipOutputStream::Options options;
+          options.format = GzipOutputStream::GZIP;
+          if (gzip_buffer_size != -1) {
+            options.buffer_size = gzip_buffer_size;
+          }
+          GzipOutputStream gzout(&output, options);
+          WriteStuff(&gzout);
+          gzout.Close();
+          size = output.ByteCount();
+        }
+        {
+          ArrayInputStream input(buffer, size, kBlockSizes[j]);
+          GzipInputStream gzin(&input, GzipInputStream::GZIP, gzip_buffer_size);
+          ReadStuff(&gzin);
+        }
+      }
+    }
+  }
+  delete[] buffer;
+}
+
+TEST_F(IoTest, GzipIoWithFlush) {
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+  // We start with i = 4 as we want a block size > 6. With block size <= 6
+  // Flush() fills up the entire 2K buffer with flush markers and the test
+  // fails. See documentation for Flush() for more detail.
+  for (int i = 4; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      for (int z = 0; z < kBlockSizeCount; z++) {
+        int gzip_buffer_size = kBlockSizes[z];
+        int size;
+        {
+          ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
+          GzipOutputStream::Options options;
+          options.format = GzipOutputStream::GZIP;
+          if (gzip_buffer_size != -1) {
+            options.buffer_size = gzip_buffer_size;
+          }
+          GzipOutputStream gzout(&output, options);
+          WriteStuff(&gzout);
+          EXPECT_TRUE(gzout.Flush());
+          gzout.Close();
+          size = output.ByteCount();
+        }
+        {
+          ArrayInputStream input(buffer, size, kBlockSizes[j]);
+          GzipInputStream gzin(&input, GzipInputStream::GZIP, gzip_buffer_size);
+          ReadStuff(&gzin);
+        }
+      }
+    }
+  }
+  delete[] buffer;
+}
+
+TEST_F(IoTest, GzipIoContiguousFlushes) {
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+
+  int block_size = kBlockSizes[4];
+  int gzip_buffer_size = block_size;
+  int size;
+
+  ArrayOutputStream output(buffer, kBufferSize, block_size);
+  GzipOutputStream::Options options;
+  options.format = GzipOutputStream::GZIP;
+  if (gzip_buffer_size != -1) {
+    options.buffer_size = gzip_buffer_size;
+  }
+  GzipOutputStream gzout(&output, options);
+  WriteStuff(&gzout);
+  EXPECT_TRUE(gzout.Flush());
+  EXPECT_TRUE(gzout.Flush());
+  gzout.Close();
+  size = output.ByteCount();
+
+  ArrayInputStream input(buffer, size, block_size);
+  GzipInputStream gzin(&input, GzipInputStream::GZIP, gzip_buffer_size);
+  ReadStuff(&gzin);
+
+  delete[] buffer;
+}
+
+TEST_F(IoTest, GzipIoReadAfterFlush) {
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+
+  int block_size = kBlockSizes[4];
+  int gzip_buffer_size = block_size;
+  int size;
+  ArrayOutputStream output(buffer, kBufferSize, block_size);
+  GzipOutputStream::Options options;
+  options.format = GzipOutputStream::GZIP;
+  if (gzip_buffer_size != -1) {
+    options.buffer_size = gzip_buffer_size;
+  }
+
+  GzipOutputStream gzout(&output, options);
+  WriteStuff(&gzout);
+  EXPECT_TRUE(gzout.Flush());
+  size = output.ByteCount();
+
+  ArrayInputStream input(buffer, size, block_size);
+  GzipInputStream gzin(&input, GzipInputStream::GZIP, gzip_buffer_size);
+  ReadStuff(&gzin);
+
+  gzout.Close();
+
+  delete[] buffer;
+}
+
+TEST_F(IoTest, ZlibIo) {
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      for (int z = 0; z < kBlockSizeCount; z++) {
+        int gzip_buffer_size = kBlockSizes[z];
+        int size;
+        {
+          ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
+          GzipOutputStream::Options options;
+          options.format = GzipOutputStream::ZLIB;
+          if (gzip_buffer_size != -1) {
+            options.buffer_size = gzip_buffer_size;
+          }
+          GzipOutputStream gzout(&output, options);
+          WriteStuff(&gzout);
+          gzout.Close();
+          size = output.ByteCount();
+        }
+        {
+          ArrayInputStream input(buffer, size, kBlockSizes[j]);
+          GzipInputStream gzin(&input, GzipInputStream::ZLIB, gzip_buffer_size);
+          ReadStuff(&gzin);
+        }
+      }
+    }
+  }
+  delete[] buffer;
+}
+
+TEST_F(IoTest, ZlibIoInputAutodetect) {
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+  int size;
+  {
+    ArrayOutputStream output(buffer, kBufferSize);
+    GzipOutputStream::Options options;
+    options.format = GzipOutputStream::ZLIB;
+    GzipOutputStream gzout(&output, options);
+    WriteStuff(&gzout);
+    gzout.Close();
+    size = output.ByteCount();
+  }
+  {
+    ArrayInputStream input(buffer, size);
+    GzipInputStream gzin(&input, GzipInputStream::AUTO);
+    ReadStuff(&gzin);
+  }
+  {
+    ArrayOutputStream output(buffer, kBufferSize);
+    GzipOutputStream::Options options;
+    options.format = GzipOutputStream::GZIP;
+    GzipOutputStream gzout(&output, options);
+    WriteStuff(&gzout);
+    gzout.Close();
+    size = output.ByteCount();
+  }
+  {
+    ArrayInputStream input(buffer, size);
+    GzipInputStream gzin(&input, GzipInputStream::AUTO);
+    ReadStuff(&gzin);
+  }
+  delete[] buffer;
+}
+
+std::string IoTest::Compress(const std::string& data,
+                             const GzipOutputStream::Options& options) {
+  std::string result;
+  {
+    StringOutputStream output(&result);
+    GzipOutputStream gzout(&output, options);
+    WriteToOutput(&gzout, data.data(), data.size());
+  }
+  return result;
+}
+
+std::string IoTest::Uncompress(const std::string& data) {
+  std::string result;
+  {
+    ArrayInputStream input(data.data(), data.size());
+    GzipInputStream gzin(&input);
+    const void* buffer;
+    int size;
+    while (gzin.Next(&buffer, &size)) {
+      result.append(reinterpret_cast<const char*>(buffer), size);
+    }
+  }
+  return result;
+}
+
+TEST_F(IoTest, CompressionOptions) {
+  // Some ad-hoc testing of compression options.
+
+  std::string golden_filename =
+      TestUtil::GetTestDataPath("net/proto2/internal/testdata/golden_message");
+  std::string golden;
+  GOOGLE_CHECK_OK(File::GetContents(golden_filename, &golden, true));
+
+  GzipOutputStream::Options options;
+  std::string gzip_compressed = Compress(golden, options);
+
+  options.compression_level = 0;
+  std::string not_compressed = Compress(golden, options);
+
+  // Try zlib compression for fun.
+  options = GzipOutputStream::Options();
+  options.format = GzipOutputStream::ZLIB;
+  std::string zlib_compressed = Compress(golden, options);
+
+  // Uncompressed should be bigger than the original since it should have some
+  // sort of header.
+  EXPECT_GT(not_compressed.size(), golden.size());
+
+  // Higher compression levels should result in smaller sizes.
+  EXPECT_LT(zlib_compressed.size(), not_compressed.size());
+
+  // ZLIB format should differ from GZIP format.
+  EXPECT_TRUE(zlib_compressed != gzip_compressed);
+
+  // Everything should decompress correctly.
+  EXPECT_TRUE(Uncompress(not_compressed) == golden);
+  EXPECT_TRUE(Uncompress(gzip_compressed) == golden);
+  EXPECT_TRUE(Uncompress(zlib_compressed) == golden);
+}
+
+TEST_F(IoTest, TwoSessionWriteGzip) {
+  // Test that two concatenated gzip streams can be read correctly
+
+  static const char* strA = "0123456789";
+  static const char* strB = "QuickBrownFox";
+  const int kBufferSize = 2 * 1024;
+  uint8* buffer = new uint8[kBufferSize];
+  char* temp_buffer = new char[40];
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      ArrayOutputStream* output =
+          new ArrayOutputStream(buffer, kBufferSize, kBlockSizes[i]);
+      GzipOutputStream* gzout = new GzipOutputStream(output);
+      CodedOutputStream* coded_output = new CodedOutputStream(gzout);
+      int32 outlen = strlen(strA) + 1;
+      coded_output->WriteVarint32(outlen);
+      coded_output->WriteRaw(strA, outlen);
+      delete coded_output;  // flush
+      delete gzout;         // flush
+      int64 pos = output->ByteCount();
+      delete output;
+      output = new ArrayOutputStream(buffer + pos, kBufferSize - pos,
+                                     kBlockSizes[i]);
+      gzout = new GzipOutputStream(output);
+      coded_output = new CodedOutputStream(gzout);
+      outlen = strlen(strB) + 1;
+      coded_output->WriteVarint32(outlen);
+      coded_output->WriteRaw(strB, outlen);
+      delete coded_output;  // flush
+      delete gzout;         // flush
+      int64 size = pos + output->ByteCount();
+      delete output;
+
+      ArrayInputStream* input =
+          new ArrayInputStream(buffer, size, kBlockSizes[j]);
+      GzipInputStream* gzin = new GzipInputStream(input);
+      CodedInputStream* coded_input = new CodedInputStream(gzin);
+      uint32 insize;
+      EXPECT_TRUE(coded_input->ReadVarint32(&insize));
+      EXPECT_EQ(strlen(strA) + 1, insize);
+      EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
+      EXPECT_EQ(0, memcmp(temp_buffer, strA, insize))
+          << "strA=" << strA << " in=" << temp_buffer;
+
+      EXPECT_TRUE(coded_input->ReadVarint32(&insize));
+      EXPECT_EQ(strlen(strB) + 1, insize);
+      EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
+      EXPECT_EQ(0, memcmp(temp_buffer, strB, insize))
+          << " out_block_size=" << kBlockSizes[i]
+          << " in_block_size=" << kBlockSizes[j] << " pos=" << pos
+          << " size=" << size << " strB=" << strB << " in=" << temp_buffer;
+
+      delete coded_input;
+      delete gzin;
+      delete input;
+    }
+  }
+
+  delete[] temp_buffer;
+  delete[] buffer;
+}
+
+TEST_F(IoTest, GzipInputByteCountAfterClosed) {
+  std::string golden = "abcdefghijklmnopqrstuvwxyz";
+  std::string compressed = Compress(golden, GzipOutputStream::Options());
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    ArrayInputStream arr_input(compressed.data(), compressed.size(),
+                               kBlockSizes[i]);
+    GzipInputStream gz_input(&arr_input);
+    const void* buffer;
+    int size;
+    while (gz_input.Next(&buffer, &size)) {
+      EXPECT_LE(gz_input.ByteCount(), golden.size());
+    }
+    EXPECT_EQ(golden.size(), gz_input.ByteCount());
+  }
+}
+
+TEST_F(IoTest, GzipInputByteCountAfterClosedConcatenatedStreams) {
+  std::string golden1 = "abcdefghijklmnopqrstuvwxyz";
+  std::string golden2 = "the quick brown fox jumps over the lazy dog";
+  const size_t total_size = golden1.size() + golden2.size();
+  std::string compressed = Compress(golden1, GzipOutputStream::Options()) +
+                           Compress(golden2, GzipOutputStream::Options());
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    ArrayInputStream arr_input(compressed.data(), compressed.size(),
+                               kBlockSizes[i]);
+    GzipInputStream gz_input(&arr_input);
+    const void* buffer;
+    int size;
+    while (gz_input.Next(&buffer, &size)) {
+      EXPECT_LE(gz_input.ByteCount(), total_size);
+    }
+    EXPECT_EQ(total_size, gz_input.ByteCount());
+  }
+}
+#endif
+
+// There is no string input, only string output.  Also, it doesn't support
+// explicit block sizes.  So, we'll only run one test and we'll use
+// ArrayInput to read back the results.
+TEST_F(IoTest, StringIo) {
+  std::string str;
+  {
+    StringOutputStream output(&str);
+    WriteStuff(&output);
+  }
+  {
+    ArrayInputStream input(str.data(), str.size());
+    ReadStuff(&input);
+  }
+}
+
+// Verifies that outputs up to kint32max can be created.
+TEST_F(IoTest, LargeOutput) {
+  std::string str;
+  StringOutputStream output(&str);
+  void* unused_data;
+  int size;
+  // Repeatedly calling Next should eventually grow the buffer to kint32max.
+  do {
+    EXPECT_TRUE(output.Next(&unused_data, &size));
+  } while (str.size() < std::numeric_limits<int>::max());
+  // Further increases should be possible.
+  output.Next(&unused_data, &size);
+  EXPECT_GT(size, 0);
+}
+
+
+// To test files, we create a temporary file, write, read, truncate, repeat.
+TEST_F(IoTest, FileIo) {
+  std::string filename = TestTempDir() + "/zero_copy_stream_test_file";
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      // Make a temporary file.
+      int file =
+          open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
+      ASSERT_GE(file, 0);
+
+      {
+        FileOutputStream output(file, kBlockSizes[i]);
+        WriteStuff(&output);
+        EXPECT_EQ(0, output.GetErrno());
+      }
+
+      // Rewind.
+      ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
+
+      {
+        FileInputStream input(file, kBlockSizes[j]);
+        ReadStuff(&input);
+        EXPECT_EQ(0, input.GetErrno());
+      }
+
+      close(file);
+    }
+  }
+}
+
+#ifndef _WIN32
+// This tests the FileInputStream with a non blocking file. It opens a pipe in
+// non blocking mode, then starts reading it. The writing thread starts writing
+// 100ms after that.
+TEST_F(IoTest, NonBlockingFileIo) {
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      int fd[2];
+      // On Linux we could use pipe2 to make the pipe non-blocking in one step,
+      // but we instead use pipe and fcntl because pipe2 is not available on
+      // Mac OS.
+      ASSERT_EQ(pipe(fd), 0);
+      ASSERT_EQ(fcntl(fd[0], F_SETFL, O_NONBLOCK), 0);
+      ASSERT_EQ(fcntl(fd[1], F_SETFL, O_NONBLOCK), 0);
+
+      std::mutex go_write;
+      go_write.lock();
+
+      bool done_reading = false;
+
+      std::thread write_thread([this, fd, &go_write, i]() {
+        go_write.lock();
+        go_write.unlock();
+        FileOutputStream output(fd[1], kBlockSizes[i]);
+        WriteStuff(&output);
+        EXPECT_EQ(0, output.GetErrno());
+      });
+
+      std::thread read_thread([this, fd, &done_reading, j]() {
+        FileInputStream input(fd[0], kBlockSizes[j]);
+        ReadStuff(&input, false /* read_eof */);
+        done_reading = true;
+        close(fd[0]);
+        close(fd[1]);
+        EXPECT_EQ(0, input.GetErrno());
+      });
+
+      // Sleeping is not necessary but makes the next expectation relevant: the
+      // reading thread waits for the data to be available before returning.
+      std::this_thread::sleep_for(std::chrono::milliseconds(100));
+      EXPECT_FALSE(done_reading);
+      go_write.unlock();
+      write_thread.join();
+      read_thread.join();
+      EXPECT_TRUE(done_reading);
+    }
+  }
+}
+
+TEST_F(IoTest, BlockingFileIoWithTimeout) {
+  int fd[2];
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, fd), 0);
+    struct timeval tv {
+      .tv_sec = 0, .tv_usec = 5000
+    };
+    ASSERT_EQ(setsockopt(fd[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), 0);
+    FileInputStream input(fd[0], kBlockSizes[i]);
+    uint8 byte;
+    EXPECT_EQ(ReadFromInput(&input, &byte, 1), 0);
+    EXPECT_EQ(EAGAIN, input.GetErrno());
+  }
+}
+#endif
+
+#if HAVE_ZLIB
+TEST_F(IoTest, GzipFileIo) {
+  std::string filename = TestTempDir() + "/zero_copy_stream_test_file";
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      // Make a temporary file.
+      int file =
+          open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
+      ASSERT_GE(file, 0);
+      {
+        FileOutputStream output(file, kBlockSizes[i]);
+        GzipOutputStream gzout(&output);
+        WriteStuffLarge(&gzout);
+        gzout.Close();
+        output.Flush();
+        EXPECT_EQ(0, output.GetErrno());
+      }
+
+      // Rewind.
+      ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
+
+      {
+        FileInputStream input(file, kBlockSizes[j]);
+        GzipInputStream gzin(&input);
+        ReadStuffLarge(&gzin);
+        EXPECT_EQ(0, input.GetErrno());
+      }
+
+      close(file);
+    }
+  }
+}
+#endif
+
+// MSVC raises various debugging exceptions if we try to use a file
+// descriptor of -1, defeating our tests below.  This class will disable
+// these debug assertions while in scope.
+class MsvcDebugDisabler {
+ public:
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+  MsvcDebugDisabler() {
+    old_handler_ = _set_invalid_parameter_handler(MyHandler);
+    old_mode_ = _CrtSetReportMode(_CRT_ASSERT, 0);
+  }
+  ~MsvcDebugDisabler() {
+    old_handler_ = _set_invalid_parameter_handler(old_handler_);
+    old_mode_ = _CrtSetReportMode(_CRT_ASSERT, old_mode_);
+  }
+
+  static void MyHandler(const wchar_t* expr, const wchar_t* func,
+                        const wchar_t* file, unsigned int line,
+                        uintptr_t pReserved) {
+    // do nothing
+  }
+
+  _invalid_parameter_handler old_handler_;
+  int old_mode_;
+#else
+  // Dummy constructor and destructor to ensure that GCC doesn't complain
+  // that debug_disabler is an unused variable.
+  MsvcDebugDisabler() {}
+  ~MsvcDebugDisabler() {}
+#endif
+};
+
+// Test that FileInputStreams report errors correctly.
+TEST_F(IoTest, FileReadError) {
+  MsvcDebugDisabler debug_disabler;
+
+  // -1 = invalid file descriptor.
+  FileInputStream input(-1);
+
+  const void* buffer;
+  int size;
+  EXPECT_FALSE(input.Next(&buffer, &size));
+  EXPECT_EQ(EBADF, input.GetErrno());
+}
+
+// Test that FileOutputStreams report errors correctly.
+TEST_F(IoTest, FileWriteError) {
+  MsvcDebugDisabler debug_disabler;
+
+  // -1 = invalid file descriptor.
+  FileOutputStream input(-1);
+
+  void* buffer;
+  int size;
+
+  // The first call to Next() succeeds because it doesn't have anything to
+  // write yet.
+  EXPECT_TRUE(input.Next(&buffer, &size));
+
+  // Second call fails.
+  EXPECT_FALSE(input.Next(&buffer, &size));
+
+  EXPECT_EQ(EBADF, input.GetErrno());
+}
+
+// Pipes are not seekable, so File{Input,Output}Stream ends up doing some
+// different things to handle them.  We'll test by writing to a pipe and
+// reading back from it.
+TEST_F(IoTest, PipeIo) {
+  int files[2];
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      // Need to create a new pipe each time because ReadStuff() expects
+      // to see EOF at the end.
+      ASSERT_EQ(pipe(files), 0);
+
+      {
+        FileOutputStream output(files[1], kBlockSizes[i]);
+        WriteStuff(&output);
+        EXPECT_EQ(0, output.GetErrno());
+      }
+      close(files[1]);  // Send EOF.
+
+      {
+        FileInputStream input(files[0], kBlockSizes[j]);
+        ReadStuff(&input);
+        EXPECT_EQ(0, input.GetErrno());
+      }
+      close(files[0]);
+    }
+  }
+}
+
+// Test using C++ iostreams.
+TEST_F(IoTest, IostreamIo) {
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      {
+        std::stringstream stream;
+
+        {
+          OstreamOutputStream output(&stream, kBlockSizes[i]);
+          WriteStuff(&output);
+          EXPECT_FALSE(stream.fail());
+        }
+
+        {
+          IstreamInputStream input(&stream, kBlockSizes[j]);
+          ReadStuff(&input);
+          EXPECT_TRUE(stream.eof());
+        }
+      }
+
+      {
+        std::stringstream stream;
+
+        {
+          OstreamOutputStream output(&stream, kBlockSizes[i]);
+          WriteStuffLarge(&output);
+          EXPECT_FALSE(stream.fail());
+        }
+
+        {
+          IstreamInputStream input(&stream, kBlockSizes[j]);
+          ReadStuffLarge(&input);
+          EXPECT_TRUE(stream.eof());
+        }
+      }
+    }
+  }
+}
+
+// To test ConcatenatingInputStream, we create several ArrayInputStreams
+// covering a buffer and then concatenate them.
+TEST_F(IoTest, ConcatenatingInputStream) {
+  const int kBufferSize = 256;
+  uint8 buffer[kBufferSize];
+
+  // Fill the buffer.
+  ArrayOutputStream output(buffer, kBufferSize);
+  WriteStuff(&output);
+
+  // Now split it up into multiple streams of varying sizes.
+  ASSERT_EQ(68, output.ByteCount());  // Test depends on this.
+  ArrayInputStream input1(buffer, 12);
+  ArrayInputStream input2(buffer + 12, 7);
+  ArrayInputStream input3(buffer + 19, 6);
+  ArrayInputStream input4(buffer + 25, 15);
+  ArrayInputStream input5(buffer + 40, 0);
+  // Note:  We want to make sure we have a stream boundary somewhere between
+  // bytes 42 and 62, which is the range that it Skip()ed by ReadStuff().  This
+  // tests that a bug that existed in the original code for Skip() is fixed.
+  ArrayInputStream input6(buffer + 40, 10);
+  ArrayInputStream input7(buffer + 50, 18);  // Total = 68 bytes.
+
+  ZeroCopyInputStream* streams[] = {&input1, &input2, &input3, &input4,
+                                    &input5, &input6, &input7};
+
+  // Create the concatenating stream and read.
+  ConcatenatingInputStream input(streams, GOOGLE_ARRAYSIZE(streams));
+  ReadStuff(&input);
+}
+
+// To test LimitingInputStream, we write our golden text to a buffer, then
+// create an ArrayInputStream that contains the whole buffer (not just the
+// bytes written), then use a LimitingInputStream to limit it just to the
+// bytes written.
+TEST_F(IoTest, LimitingInputStream) {
+  const int kBufferSize = 256;
+  uint8 buffer[kBufferSize];
+
+  // Fill the buffer.
+  ArrayOutputStream output(buffer, kBufferSize);
+  WriteStuff(&output);
+
+  // Set up input.
+  ArrayInputStream array_input(buffer, kBufferSize);
+  LimitingInputStream input(&array_input, output.ByteCount());
+
+  ReadStuff(&input);
+}
+
+// Checks that ByteCount works correctly for LimitingInputStreams where the
+// underlying stream has already been read.
+TEST_F(IoTest, LimitingInputStreamByteCount) {
+  const int kHalfBufferSize = 128;
+  const int kBufferSize = kHalfBufferSize * 2;
+  uint8 buffer[kBufferSize];
+
+  // Set up input. Only allow half to be read at once.
+  ArrayInputStream array_input(buffer, kBufferSize, kHalfBufferSize);
+  const void* data;
+  int size;
+  EXPECT_TRUE(array_input.Next(&data, &size));
+  EXPECT_EQ(kHalfBufferSize, array_input.ByteCount());
+  // kHalfBufferSize - 1 to test limiting logic as well.
+  LimitingInputStream input(&array_input, kHalfBufferSize - 1);
+  EXPECT_EQ(0, input.ByteCount());
+  EXPECT_TRUE(input.Next(&data, &size));
+  EXPECT_EQ(kHalfBufferSize - 1, input.ByteCount());
+}
+
+// Check that a zero-size array doesn't confuse the code.
+TEST(ZeroSizeArray, Input) {
+  ArrayInputStream input(NULL, 0);
+  const void* data;
+  int size;
+  EXPECT_FALSE(input.Next(&data, &size));
+}
+
+TEST(ZeroSizeArray, Output) {
+  ArrayOutputStream output(NULL, 0);
+  void* data;
+  int size;
+  EXPECT_FALSE(output.Next(&data, &size));
+}
+
+}  // namespace
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/lite_arena_unittest.cc b/src/google/protobuf/lite_arena_unittest.cc
new file mode 100644
index 0000000..d68c6c9
--- /dev/null
+++ b/src/google/protobuf/lite_arena_unittest.cc
@@ -0,0 +1,90 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_lite_test_util.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+class LiteArenaTest : public testing::Test {
+ protected:
+  LiteArenaTest() {
+    ArenaOptions options;
+    options.start_block_size = 128 * 1024;
+    options.max_block_size = 128 * 1024;
+    arena_.reset(new Arena(options));
+    // Trigger the allocation of the first arena block, so that further use of
+    // the arena will not require any heap allocations.
+    Arena::CreateArray<char>(arena_.get(), 1);
+  }
+
+  std::unique_ptr<Arena> arena_;
+};
+
+TEST_F(LiteArenaTest, MapNoHeapAllocation) {
+  std::string data;
+  data.reserve(128 * 1024);
+
+  {
+    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in
+    // Map.
+    // internal::NoHeapChecker no_heap;
+
+    protobuf_unittest::TestArenaMapLite* from =
+        Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(arena_.get());
+    MapLiteTestUtil::SetArenaMapFields(from);
+    from->SerializeToString(&data);
+
+    protobuf_unittest::TestArenaMapLite* to =
+        Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(arena_.get());
+    to->ParseFromString(data);
+    MapLiteTestUtil::ExpectArenaMapFieldsSet(*to);
+  }
+}
+
+TEST_F(LiteArenaTest, UnknownFieldMemLeak) {
+  protobuf_unittest::ForeignMessageArenaLite* message =
+      Arena::CreateMessage<protobuf_unittest::ForeignMessageArenaLite>(
+          arena_.get());
+  std::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
new file mode 100644
index 0000000..583d325
--- /dev/null
+++ b/src/google/protobuf/lite_unittest.cc
@@ -0,0 +1,1333 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <climits>
+#include <iostream>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/map_lite_unittest.pb.h>
+#include <google/protobuf/unittest_lite.pb.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arena_test_util.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/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/map_lite_test_util.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/test_util_lite.h>
+#include <google/protobuf/wire_format_lite.h>
+
+namespace google {
+namespace protobuf {
+
+// Helper methods to test parsing merge behavior.
+void ExpectMessageMerged(const unittest::TestAllTypesLite& message) {
+  EXPECT_EQ(message.optional_int32(), 3);
+  EXPECT_EQ(message.optional_int64(), 2);
+  EXPECT_EQ(message.optional_string(), "hello");
+}
+
+void AssignParsingMergeMessages(unittest::TestAllTypesLite* msg1,
+                                unittest::TestAllTypesLite* msg2,
+                                unittest::TestAllTypesLite* msg3) {
+  msg1->set_optional_int32(1);
+  msg2->set_optional_int64(2);
+  msg3->set_optional_int32(3);
+  msg3->set_optional_string("hello");
+}
+
+void SetAllTypesInEmptyMessageUnknownFields(
+    unittest::TestEmptyMessageLite* empty_message) {
+  protobuf_unittest::TestAllTypesLite message;
+  TestUtilLite::ExpectClear(message);
+  TestUtilLite::SetAllFields(&message);
+  std::string data = message.SerializeAsString();
+  empty_message->ParseFromString(data);
+}
+
+void SetSomeTypesInEmptyMessageUnknownFields(
+    unittest::TestEmptyMessageLite* empty_message) {
+  protobuf_unittest::TestAllTypesLite message;
+  TestUtilLite::ExpectClear(message);
+  message.set_optional_int32(101);
+  message.set_optional_int64(102);
+  message.set_optional_uint32(103);
+  message.set_optional_uint64(104);
+  std::string data = message.SerializeAsString();
+  empty_message->ParseFromString(data);
+}
+
+
+TEST(ParseVarintTest, Varint32) {
+  auto test_value = [](uint32_t value, int varint_length) {
+    uint8_t buffer[10];
+    uint8_t* p = io::CodedOutputStream::WriteVarint32ToArray(value, buffer);
+    ASSERT_EQ(p - buffer, varint_length) << "Value = " << value;
+
+    const char* cbuffer = reinterpret_cast<const char*>(buffer);
+    uint32_t parsed = ~value;
+    const char* r = internal::VarintParse(cbuffer, &parsed);
+    ASSERT_EQ(r - cbuffer, varint_length) << "Value = " << value;
+    ASSERT_EQ(parsed, value);
+  };
+
+  uint32_t base = 73;  // 1001011b
+  for (int varint_length = 1; varint_length <= 5; ++varint_length) {
+    uint32_t values[] = {
+        base - 73, base - 72, base, base + 126 - 73, base + 126 - 72,
+    };
+    for (uint32_t value : values) {
+      test_value(value, varint_length);
+    }
+    base = (base << 7) + 73;
+  }
+
+  test_value(std::numeric_limits<uint32_t>::max(), 5);
+}
+
+TEST(ParseVarintTest, Varint64) {
+  auto test_value = [](uint64_t value, int varint_length) {
+    uint8_t buffer[10];
+    uint8_t* p = io::CodedOutputStream::WriteVarint64ToArray(value, buffer);
+    ASSERT_EQ(p - buffer, varint_length) << "Value = " << value;
+
+    const char* cbuffer = reinterpret_cast<const char*>(buffer);
+    uint64_t parsed = ~value;
+    const char* r = internal::VarintParse(cbuffer, &parsed);
+    ASSERT_EQ(r - cbuffer, varint_length) << "Value = " << value;
+    ASSERT_EQ(parsed, value);
+  };
+
+  uint64_t base = 73;  // 1001011b
+  for (int varint_length = 1; varint_length <= 10; ++varint_length) {
+    uint64_t values[] = {
+        base - 73, base - 72, base, base + 126 - 73, base + 126 - 72,
+    };
+    for (uint64_t value : values) {
+      test_value(value, varint_length);
+    }
+    base = (base << 7) + 73;
+  }
+
+  test_value(std::numeric_limits<uint64_t>::max(), 10);
+}
+
+TEST(Lite, AllLite1) {
+  std::string data;
+
+  {
+    protobuf_unittest::TestAllTypesLite message, message2, message3;
+    TestUtilLite::ExpectClear(message);
+    TestUtilLite::SetAllFields(&message);
+    message2.CopyFrom(message);
+    data = message.SerializeAsString();
+    message3.ParseFromString(data);
+    TestUtilLite::ExpectAllFieldsSet(message);
+    TestUtilLite::ExpectAllFieldsSet(message2);
+    TestUtilLite::ExpectAllFieldsSet(message3);
+    TestUtilLite::ModifyRepeatedFields(&message);
+    TestUtilLite::ExpectRepeatedFieldsModified(message);
+    message.Clear();
+    TestUtilLite::ExpectClear(message);
+  }
+}
+
+TEST(Lite, AllLite2) {
+  std::string data;
+  {
+    protobuf_unittest::TestAllExtensionsLite message, message2, message3;
+    TestUtilLite::ExpectExtensionsClear(message);
+    TestUtilLite::SetAllExtensions(&message);
+    message2.CopyFrom(message);
+    std::string extensions_data = message.SerializeAsString();
+    message3.ParseFromString(extensions_data);
+    TestUtilLite::ExpectAllExtensionsSet(message);
+    TestUtilLite::ExpectAllExtensionsSet(message2);
+    TestUtilLite::ExpectAllExtensionsSet(message3);
+    TestUtilLite::ModifyRepeatedExtensions(&message);
+    TestUtilLite::ExpectRepeatedExtensionsModified(message);
+    message.Clear();
+    TestUtilLite::ExpectExtensionsClear(message);
+  }
+}
+
+TEST(Lite, AllLite3) {
+  std::string data, packed_data;
+
+  {
+    protobuf_unittest::TestPackedTypesLite message, message2, message3;
+    TestUtilLite::ExpectPackedClear(message);
+    TestUtilLite::SetPackedFields(&message);
+    message2.CopyFrom(message);
+    packed_data = message.SerializeAsString();
+    message3.ParseFromString(packed_data);
+    TestUtilLite::ExpectPackedFieldsSet(message);
+    TestUtilLite::ExpectPackedFieldsSet(message2);
+    TestUtilLite::ExpectPackedFieldsSet(message3);
+    TestUtilLite::ModifyPackedFields(&message);
+    TestUtilLite::ExpectPackedFieldsModified(message);
+    message.Clear();
+    TestUtilLite::ExpectPackedClear(message);
+  }
+
+  {
+    protobuf_unittest::TestPackedExtensionsLite message, message2, message3;
+    TestUtilLite::ExpectPackedExtensionsClear(message);
+    TestUtilLite::SetPackedExtensions(&message);
+    message2.CopyFrom(message);
+    std::string packed_extensions_data = message.SerializeAsString();
+    EXPECT_EQ(packed_extensions_data, packed_data);
+    message3.ParseFromString(packed_extensions_data);
+    TestUtilLite::ExpectPackedExtensionsSet(message);
+    TestUtilLite::ExpectPackedExtensionsSet(message2);
+    TestUtilLite::ExpectPackedExtensionsSet(message3);
+    TestUtilLite::ModifyPackedExtensions(&message);
+    TestUtilLite::ExpectPackedExtensionsModified(message);
+    message.Clear();
+    TestUtilLite::ExpectPackedExtensionsClear(message);
+  }
+}
+
+TEST(Lite, AllLite5) {
+  std::string data;
+
+  {
+    // Test that if an optional or required message/group field appears multiple
+    // times in the input, they need to be merged.
+    unittest::TestParsingMergeLite::RepeatedFieldsGenerator generator;
+    unittest::TestAllTypesLite* msg1;
+    unittest::TestAllTypesLite* msg2;
+    unittest::TestAllTypesLite* msg3;
+
+#define ASSIGN_REPEATED_FIELD(FIELD) \
+  msg1 = generator.add_##FIELD();    \
+  msg2 = generator.add_##FIELD();    \
+  msg3 = generator.add_##FIELD();    \
+  AssignParsingMergeMessages(msg1, msg2, msg3)
+
+    ASSIGN_REPEATED_FIELD(field1);
+    ASSIGN_REPEATED_FIELD(field2);
+    ASSIGN_REPEATED_FIELD(field3);
+    ASSIGN_REPEATED_FIELD(ext1);
+    ASSIGN_REPEATED_FIELD(ext2);
+
+#undef ASSIGN_REPEATED_FIELD
+#define ASSIGN_REPEATED_GROUP(FIELD)                \
+  msg1 = generator.add_##FIELD()->mutable_field1(); \
+  msg2 = generator.add_##FIELD()->mutable_field1(); \
+  msg3 = generator.add_##FIELD()->mutable_field1(); \
+  AssignParsingMergeMessages(msg1, msg2, msg3)
+
+    ASSIGN_REPEATED_GROUP(group1);
+    ASSIGN_REPEATED_GROUP(group2);
+
+#undef ASSIGN_REPEATED_GROUP
+
+    std::string buffer;
+    generator.SerializeToString(&buffer);
+    unittest::TestParsingMergeLite parsing_merge;
+    parsing_merge.ParseFromString(buffer);
+
+    // Required and optional fields should be merged.
+    ExpectMessageMerged(parsing_merge.required_all_types());
+    ExpectMessageMerged(parsing_merge.optional_all_types());
+    ExpectMessageMerged(
+        parsing_merge.optionalgroup().optional_group_all_types());
+    ExpectMessageMerged(parsing_merge.GetExtension(
+        unittest::TestParsingMergeLite::optional_ext));
+
+    // Repeated fields should not be merged.
+    EXPECT_EQ(parsing_merge.repeated_all_types_size(), 3);
+    EXPECT_EQ(parsing_merge.repeatedgroup_size(), 3);
+    EXPECT_EQ(parsing_merge.ExtensionSize(
+                  unittest::TestParsingMergeLite::repeated_ext),
+              3);
+  }
+}
+
+TEST(Lite, AllLite6) {
+  std::string data;
+
+  // Test unknown fields support for lite messages.
+  {
+    protobuf_unittest::TestAllTypesLite message, message2;
+    protobuf_unittest::TestEmptyMessageLite empty_message;
+    TestUtilLite::ExpectClear(message);
+    TestUtilLite::SetAllFields(&message);
+    data = message.SerializeAsString();
+    ASSERT_TRUE(empty_message.ParseFromString(data));
+    data.clear();
+    data = empty_message.SerializeAsString();
+    EXPECT_TRUE(message2.ParseFromString(data));
+    data = message2.SerializeAsString();
+    TestUtilLite::ExpectAllFieldsSet(message2);
+    message.Clear();
+    TestUtilLite::ExpectClear(message);
+  }
+}
+
+TEST(Lite, AllLite7) {
+  std::string data;
+
+  {
+    protobuf_unittest::TestAllExtensionsLite message, message2;
+    protobuf_unittest::TestEmptyMessageLite empty_message;
+    TestUtilLite::ExpectExtensionsClear(message);
+    TestUtilLite::SetAllExtensions(&message);
+    data = message.SerializeAsString();
+    empty_message.ParseFromString(data);
+    data.clear();
+    data = empty_message.SerializeAsString();
+    message2.ParseFromString(data);
+    data = message2.SerializeAsString();
+    TestUtilLite::ExpectAllExtensionsSet(message2);
+    message.Clear();
+    TestUtilLite::ExpectExtensionsClear(message);
+  }
+}
+
+TEST(Lite, AllLite8) {
+  std::string data;
+
+  {
+    protobuf_unittest::TestPackedTypesLite message, message2;
+    protobuf_unittest::TestEmptyMessageLite empty_message;
+    TestUtilLite::ExpectPackedClear(message);
+    TestUtilLite::SetPackedFields(&message);
+    data = message.SerializeAsString();
+    empty_message.ParseFromString(data);
+    data.clear();
+    data = empty_message.SerializeAsString();
+    message2.ParseFromString(data);
+    data = message2.SerializeAsString();
+    TestUtilLite::ExpectPackedFieldsSet(message2);
+    message.Clear();
+    TestUtilLite::ExpectPackedClear(message);
+  }
+}
+
+TEST(Lite, AllLite9) {
+  std::string data;
+
+  {
+    protobuf_unittest::TestPackedExtensionsLite message, message2;
+    protobuf_unittest::TestEmptyMessageLite empty_message;
+    TestUtilLite::ExpectPackedExtensionsClear(message);
+    TestUtilLite::SetPackedExtensions(&message);
+    data = message.SerializeAsString();
+    empty_message.ParseFromString(data);
+    data.clear();
+    data = empty_message.SerializeAsString();
+    message2.ParseFromString(data);
+    data = message2.SerializeAsString();
+    TestUtilLite::ExpectPackedExtensionsSet(message2);
+    message.Clear();
+    TestUtilLite::ExpectPackedExtensionsClear(message);
+  }
+}
+
+TEST(Lite, AllLite10) {
+  std::string data;
+
+  {
+    // Test Unknown fields swap
+    protobuf_unittest::TestEmptyMessageLite empty_message, empty_message2;
+    SetAllTypesInEmptyMessageUnknownFields(&empty_message);
+    SetSomeTypesInEmptyMessageUnknownFields(&empty_message2);
+    data = empty_message.SerializeAsString();
+    std::string data2 = empty_message2.SerializeAsString();
+    empty_message.Swap(&empty_message2);
+    EXPECT_EQ(data, empty_message2.SerializeAsString());
+    EXPECT_EQ(data2, empty_message.SerializeAsString());
+  }
+}
+
+TEST(Lite, AllLite11) {
+  std::string data;
+
+  {
+    // Test unknown fields swap with self
+    protobuf_unittest::TestEmptyMessageLite empty_message;
+    SetAllTypesInEmptyMessageUnknownFields(&empty_message);
+    data = empty_message.SerializeAsString();
+    empty_message.Swap(&empty_message);
+    EXPECT_EQ(data, empty_message.SerializeAsString());
+  }
+}
+
+TEST(Lite, AllLite12) {
+  std::string data;
+
+  {
+    // Test MergeFrom with unknown fields
+    protobuf_unittest::TestAllTypesLite message, message2;
+    protobuf_unittest::TestEmptyMessageLite empty_message, empty_message2;
+    message.set_optional_int32(101);
+    message.add_repeated_int32(201);
+    message.set_optional_nested_enum(unittest::TestAllTypesLite::BAZ);
+    message2.set_optional_int64(102);
+    message2.add_repeated_int64(202);
+    message2.set_optional_foreign_enum(unittest::FOREIGN_LITE_BAZ);
+
+    data = message.SerializeAsString();
+    empty_message.ParseFromString(data);
+    data = message2.SerializeAsString();
+    empty_message2.ParseFromString(data);
+    message.MergeFrom(message2);
+    empty_message.MergeFrom(empty_message2);
+
+    data = empty_message.SerializeAsString();
+    message2.ParseFromString(data);
+    // We do not compare the serialized output of a normal message and a lite
+    // message because the order of fields do not match. We convert lite message
+    // back into normal message, then compare.
+    EXPECT_EQ(message.SerializeAsString(), message2.SerializeAsString());
+  }
+}
+
+TEST(Lite, AllLite13) {
+  std::string data;
+
+  {
+    // Test unknown enum value
+    protobuf_unittest::TestAllTypesLite message;
+    std::string buffer;
+    {
+      io::StringOutputStream output_stream(&buffer);
+      io::CodedOutputStream coded_output(&output_stream);
+      internal::WireFormatLite::WriteTag(
+          protobuf_unittest::TestAllTypesLite::kOptionalNestedEnumFieldNumber,
+          internal::WireFormatLite::WIRETYPE_VARINT, &coded_output);
+      coded_output.WriteVarint32(10);
+      internal::WireFormatLite::WriteTag(
+          protobuf_unittest::TestAllTypesLite::kRepeatedNestedEnumFieldNumber,
+          internal::WireFormatLite::WIRETYPE_VARINT, &coded_output);
+      coded_output.WriteVarint32(20);
+    }
+    message.ParseFromString(buffer);
+    data = message.SerializeAsString();
+    EXPECT_EQ(data, buffer);
+  }
+}
+
+TEST(Lite, AllLite14) {
+  std::string data;
+
+  {
+    // Test Clear with unknown fields
+    protobuf_unittest::TestEmptyMessageLite empty_message;
+    SetAllTypesInEmptyMessageUnknownFields(&empty_message);
+    empty_message.Clear();
+    EXPECT_EQ(0, empty_message.unknown_fields().size());
+  }
+}
+
+// Tests for map lite =============================================
+
+TEST(Lite, AllLite15) {
+  std::string data;
+
+  {
+    // Accessors
+    protobuf_unittest::TestMapLite message;
+
+    MapLiteTestUtil::SetMapFields(&message);
+    MapLiteTestUtil::ExpectMapFieldsSet(message);
+
+    MapLiteTestUtil::ModifyMapFields(&message);
+    MapLiteTestUtil::ExpectMapFieldsModified(message);
+  }
+}
+
+TEST(Lite, AllLite16) {
+  std::string data;
+
+  {
+    // SetMapFieldsInitialized
+    protobuf_unittest::TestMapLite message;
+
+    MapLiteTestUtil::SetMapFieldsInitialized(&message);
+    MapLiteTestUtil::ExpectMapFieldsSetInitialized(message);
+  }
+}
+
+TEST(Lite, AllLite17) {
+  std::string data;
+
+  {
+    // Clear
+    protobuf_unittest::TestMapLite message;
+
+    MapLiteTestUtil::SetMapFields(&message);
+    message.Clear();
+    MapLiteTestUtil::ExpectClear(message);
+  }
+}
+
+TEST(Lite, AllLite18) {
+  std::string data;
+
+  {
+    // ClearMessageMap
+    protobuf_unittest::TestMessageMapLite message;
+
+    // Creates a TestAllTypes with default value
+    TestUtilLite::ExpectClear((*message.mutable_map_int32_message())[0]);
+  }
+}
+
+TEST(Lite, AllLite19) {
+  std::string data;
+
+  {
+    // CopyFrom
+    protobuf_unittest::TestMapLite message1, message2;
+
+    MapLiteTestUtil::SetMapFields(&message1);
+    message2.CopyFrom(message1);
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+
+    // Copying from self should be a no-op.
+    message2.CopyFrom(message2);
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+}
+
+TEST(Lite, AllLite20) {
+  std::string data;
+
+  {
+    // 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));
+  }
+}
+
+TEST(Lite, AllLite21) {
+  std::string data;
+
+  {
+    // SwapWithEmpty
+    protobuf_unittest::TestMapLite message1, message2;
+
+    MapLiteTestUtil::SetMapFields(&message1);
+    MapLiteTestUtil::ExpectMapFieldsSet(message1);
+    MapLiteTestUtil::ExpectClear(message2);
+
+    message1.Swap(&message2);
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+    MapLiteTestUtil::ExpectClear(message1);
+  }
+}
+
+TEST(Lite, AllLite22) {
+  std::string data;
+
+  {
+    // SwapWithSelf
+    protobuf_unittest::TestMapLite message;
+
+    MapLiteTestUtil::SetMapFields(&message);
+    MapLiteTestUtil::ExpectMapFieldsSet(message);
+
+    message.Swap(&message);
+    MapLiteTestUtil::ExpectMapFieldsSet(message);
+  }
+}
+
+TEST(Lite, AllLite23) {
+  std::string data;
+
+  {
+    // SwapWithOther
+    protobuf_unittest::TestMapLite message1, message2;
+
+    MapLiteTestUtil::SetMapFields(&message1);
+    MapLiteTestUtil::SetMapFields(&message2);
+    MapLiteTestUtil::ModifyMapFields(&message2);
+
+    message1.Swap(&message2);
+    MapLiteTestUtil::ExpectMapFieldsModified(message1);
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+}
+
+TEST(Lite, AllLite24) {
+  std::string data;
+
+  {
+    // CopyConstructor
+    protobuf_unittest::TestMapLite message1;
+    MapLiteTestUtil::SetMapFields(&message1);
+
+    protobuf_unittest::TestMapLite message2(message1);
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+}
+
+TEST(Lite, AllLite25) {
+  std::string data;
+
+  {
+    // CopyAssignmentOperator
+    protobuf_unittest::TestMapLite message1;
+    MapLiteTestUtil::SetMapFields(&message1);
+
+    protobuf_unittest::TestMapLite message2;
+    message2 = message1;
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+
+    // Make sure that self-assignment does something sane.
+    message2.operator=(message2);
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+}
+
+TEST(Lite, AllLite26) {
+  std::string data;
+
+  {
+    // NonEmptyMergeFrom
+    protobuf_unittest::TestMapLite message1, message2;
+
+    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);
+    MapLiteTestUtil::ExpectMapFieldsSet(message1);
+  }
+}
+
+TEST(Lite, AllLite27) {
+  std::string data;
+
+  {
+    // 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(Lite, AllLite28) {
+  std::string data;
+
+  {
+    // Test the generated SerializeWithCachedSizesToArray()
+    protobuf_unittest::TestMapLite message1, message2;
+    std::string data;
+    MapLiteTestUtil::SetMapFields(&message1);
+    size_t size = message1.ByteSizeLong();
+    data.resize(size);
+    ::uint8_t* start =
+        reinterpret_cast<::uint8_t*>(::google::protobuf::string_as_array(&data));
+    ::uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+}
+
+TEST(Lite, AllLite29) {
+  std::string data;
+
+  {
+    // Test the generated SerializeWithCachedSizes()
+    protobuf_unittest::TestMapLite message1, message2;
+    MapLiteTestUtil::SetMapFields(&message1);
+    size_t size = message1.ByteSizeLong();
+    std::string data;
+    data.resize(size);
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+      io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+    EXPECT_TRUE(message2.ParseFromString(data));
+    MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+}
+
+
+TEST(Lite, AllLite32) {
+  std::string data;
+
+  {
+    // 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;
+    std::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());
+    ASSERT_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));
+    ASSERT_EQ(1, from.known_map_field().size());
+    EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE,
+              from.known_map_field().at(0));
+    ASSERT_EQ(1, from.unknown_map_field().size());
+    EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE,
+              from.unknown_map_field().at(0));
+  }
+}
+
+TEST(Lite, AllLite33) {
+  std::string data;
+
+  {
+    // StandardWireFormat
+    protobuf_unittest::TestMapLite message;
+    std::string data = "\x0A\x04\x08\x01\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(1));
+  }
+}
+
+TEST(Lite, AllLite34) {
+  std::string data;
+
+  {
+    // UnorderedWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // put value before key in wire format
+    std::string data = "\x0A\x04\x10\x01\x08\x02";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    ASSERT_NE(message.map_int32_int32().find(2),
+              message.map_int32_int32().end());
+    EXPECT_EQ(1, message.map_int32_int32().at(2));
+  }
+}
+
+TEST(Lite, AllLite35) {
+  std::string data;
+
+  {
+    // DuplicatedKeyWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Two key fields in wire format
+    std::string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(2));
+  }
+}
+
+TEST(Lite, AllLite36) {
+  std::string data;
+
+  {
+    // DuplicatedValueWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Two value fields in wire format
+    std::string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(2, message.map_int32_int32().at(1));
+  }
+}
+
+TEST(Lite, AllLite37) {
+  std::string data;
+
+  {
+    // MissedKeyWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // No key field in wire format
+    std::string data = "\x0A\x02\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    ASSERT_NE(message.map_int32_int32().find(0),
+              message.map_int32_int32().end());
+    EXPECT_EQ(1, message.map_int32_int32().at(0));
+  }
+}
+
+TEST(Lite, AllLite38) {
+  std::string data;
+
+  {
+    // MissedValueWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // No value field in wire format
+    std::string data = "\x0A\x02\x08\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    ASSERT_NE(message.map_int32_int32().find(1),
+              message.map_int32_int32().end());
+    EXPECT_EQ(0, message.map_int32_int32().at(1));
+  }
+}
+
+TEST(Lite, AllLite39) {
+  std::string data;
+
+  {
+    // UnknownFieldWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Unknown field in wire format
+    std::string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    ASSERT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(3, message.map_int32_int32().at(2));
+  }
+}
+
+TEST(Lite, AllLite40) {
+  std::string data;
+
+  {
+    // CorruptedWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // corrupted data in wire format
+    std::string data = "\x0A\x06\x08\x02\x11\x03";
+
+    EXPECT_FALSE(message.ParseFromString(data));
+  }
+}
+
+TEST(Lite, AllLite41) {
+  std::string 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());
+  }
+}
+
+TEST(Lite, AllLite42) {
+  std::string data;
+
+  {
+    // Check that adding more values to enum does not corrupt message
+    // when passed through an old client.
+    protobuf_unittest::V2MessageLite v2_message;
+    v2_message.set_int_field(800);
+    // Set enum field to the value not understood by the old client.
+    v2_message.set_enum_field(protobuf_unittest::V2_SECOND);
+    std::string v2_bytes = v2_message.SerializeAsString();
+
+    protobuf_unittest::V1MessageLite v1_message;
+    v1_message.ParseFromString(v2_bytes);
+    EXPECT_TRUE(v1_message.IsInitialized());
+    EXPECT_EQ(v1_message.int_field(), v2_message.int_field());
+    // V1 client does not understand V2_SECOND value, so it discards it and
+    // uses default value instead.
+    EXPECT_EQ(v1_message.enum_field(), protobuf_unittest::V1_FIRST);
+
+    // However, when re-serialized, it should preserve enum value.
+    std::string v1_bytes = v1_message.SerializeAsString();
+
+    protobuf_unittest::V2MessageLite same_v2_message;
+    same_v2_message.ParseFromString(v1_bytes);
+
+    EXPECT_EQ(v2_message.int_field(), same_v2_message.int_field());
+    EXPECT_EQ(v2_message.enum_field(), same_v2_message.enum_field());
+  }
+}
+
+// Test that when parsing a oneof, we can successfully clear whatever already
+// happened to be stored in the oneof.
+TEST(Lite, AllLite43) {
+  protobuf_unittest::TestOneofParsingLite message1;
+
+  message1.set_oneof_int32(17);
+  std::string serialized;
+  EXPECT_TRUE(message1.SerializeToString(&serialized));
+
+  // Submessage
+  {
+    protobuf_unittest::TestOneofParsingLite message2;
+    message2.mutable_oneof_submessage();
+    io::CodedInputStream input_stream(
+        reinterpret_cast<const ::uint8_t*>(serialized.data()),
+        serialized.size());
+    EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
+    EXPECT_EQ(17, message2.oneof_int32());
+  }
+
+  // String
+  {
+    protobuf_unittest::TestOneofParsingLite message2;
+    message2.set_oneof_string("string");
+    io::CodedInputStream input_stream(
+        reinterpret_cast<const ::uint8_t*>(serialized.data()),
+        serialized.size());
+    EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
+    EXPECT_EQ(17, message2.oneof_int32());
+  }
+
+  // Bytes
+  {
+    protobuf_unittest::TestOneofParsingLite message2;
+    message2.set_oneof_bytes("bytes");
+    io::CodedInputStream input_stream(
+        reinterpret_cast<const ::uint8_t*>(serialized.data()),
+        serialized.size());
+    EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
+    EXPECT_EQ(17, message2.oneof_int32());
+  }
+}
+
+// Verify that we can successfully parse fields of various types within oneof
+// fields. We also verify that we can parse the same data twice into the same
+// message.
+TEST(Lite, AllLite44) {
+  // Int32
+  {
+    protobuf_unittest::TestOneofParsingLite original;
+    original.set_oneof_int32(17);
+    std::string serialized;
+    EXPECT_TRUE(original.SerializeToString(&serialized));
+    protobuf_unittest::TestOneofParsingLite parsed;
+    for (int i = 0; i < 2; ++i) {
+      io::CodedInputStream input_stream(
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
+          serialized.size());
+      EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
+      EXPECT_EQ(17, parsed.oneof_int32());
+    }
+  }
+
+  // Submessage
+  {
+    protobuf_unittest::TestOneofParsingLite original;
+    original.mutable_oneof_submessage()->set_optional_int32(5);
+    std::string serialized;
+    EXPECT_TRUE(original.SerializeToString(&serialized));
+    protobuf_unittest::TestOneofParsingLite parsed;
+    for (int i = 0; i < 2; ++i) {
+      io::CodedInputStream input_stream(
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
+          serialized.size());
+      EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
+      EXPECT_EQ(5, parsed.oneof_submessage().optional_int32());
+    }
+  }
+
+  // String
+  {
+    protobuf_unittest::TestOneofParsingLite original;
+    original.set_oneof_string("string");
+    std::string serialized;
+    EXPECT_TRUE(original.SerializeToString(&serialized));
+    protobuf_unittest::TestOneofParsingLite parsed;
+    for (int i = 0; i < 2; ++i) {
+      io::CodedInputStream input_stream(
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
+          serialized.size());
+      EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
+      EXPECT_EQ("string", parsed.oneof_string());
+    }
+  }
+
+  // Bytes
+  {
+    protobuf_unittest::TestOneofParsingLite original;
+    original.set_oneof_bytes("bytes");
+    std::string serialized;
+    EXPECT_TRUE(original.SerializeToString(&serialized));
+    protobuf_unittest::TestOneofParsingLite parsed;
+    for (int i = 0; i < 2; ++i) {
+      io::CodedInputStream input_stream(
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
+          serialized.size());
+      EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
+      EXPECT_EQ("bytes", parsed.oneof_bytes());
+    }
+  }
+
+  // Enum
+  {
+    protobuf_unittest::TestOneofParsingLite original;
+    original.set_oneof_enum(protobuf_unittest::V2_SECOND);
+    std::string serialized;
+    EXPECT_TRUE(original.SerializeToString(&serialized));
+    protobuf_unittest::TestOneofParsingLite parsed;
+    for (int i = 0; i < 2; ++i) {
+      io::CodedInputStream input_stream(
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
+          serialized.size());
+      EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
+      EXPECT_EQ(protobuf_unittest::V2_SECOND, parsed.oneof_enum());
+    }
+  }
+
+  std::cout << "PASS" << std::endl;
+}
+
+TEST(Lite, AllLite45) {
+  // Test unknown fields are not discarded upon parsing.
+  std::string data = "\20\1";  // varint 1 with field number 2
+
+  protobuf_unittest::ForeignMessageLite a;
+  EXPECT_TRUE(a.ParseFromString(data));
+  io::CodedInputStream input_stream(
+      reinterpret_cast<const ::uint8_t*>(data.data()), data.size());
+  EXPECT_TRUE(a.MergePartialFromCodedStream(&input_stream));
+
+  std::string serialized = a.SerializeAsString();
+  EXPECT_EQ(serialized.substr(0, 2), data);
+  EXPECT_EQ(serialized.substr(2), data);
+}
+
+// The following two tests check for wire compatibility between packed and
+// unpacked repeated fields. There used to be a bug in the generated parsing
+// code that caused us to calculate the highest possible tag number without
+// taking into account that a repeated field might not be in the packed (or
+// unpacked) state we expect. These tests specifically check for that issue by
+// making sure we can parse repeated fields when the tag is higher than we would
+// expect.
+TEST(Lite, AllLite46) {
+  protobuf_unittest::PackedInt32 packed;
+  packed.add_repeated_int32(42);
+  std::string serialized;
+  ASSERT_TRUE(packed.SerializeToString(&serialized));
+
+  protobuf_unittest::NonPackedInt32 non_packed;
+  ASSERT_TRUE(non_packed.ParseFromString(serialized));
+  ASSERT_EQ(1, non_packed.repeated_int32_size());
+  EXPECT_EQ(42, non_packed.repeated_int32(0));
+}
+
+TEST(Lite, AllLite47) {
+  protobuf_unittest::NonPackedFixed32 non_packed;
+  non_packed.add_repeated_fixed32(42);
+  std::string serialized;
+  ASSERT_TRUE(non_packed.SerializeToString(&serialized));
+
+  protobuf_unittest::PackedFixed32 packed;
+  ASSERT_TRUE(packed.ParseFromString(serialized));
+  ASSERT_EQ(1, packed.repeated_fixed32_size());
+  EXPECT_EQ(42, packed.repeated_fixed32(0));
+}
+
+TEST(Lite, MapCrash) {
+  // See b/113635730
+  Arena arena;
+  auto msg = Arena::CreateMessage<protobuf_unittest::TestMapLite>(&arena);
+  // Payload for the map<string, Enum> with a enum varint that's longer >
+  // 10 bytes. This causes a parse fail and a subsequent delete. field 16
+  // (map<int32, MapEnumLite>) tag = 128+2 = \202 \1
+  //   13 long \15
+  //   int32 key = 1  (\10 \1)
+  //   MapEnumLite value = too long varint (parse error)
+  EXPECT_FALSE(msg->ParseFromString(
+      "\202\1\15\10\1\200\200\200\200\200\200\200\200\200\200\1"));
+}
+
+TEST(Lite, CorrectEnding) {
+  protobuf_unittest::TestAllTypesLite msg;
+  {
+    // All proto wireformat parsers should act the same on parsing data in as
+    // much as it concerns the parsing, ie. not the interpretation of the data.
+    // TestAllTypesLite is not a group inside another message. So in practice
+    // will not encounter an end-group tag. However the parser should behave
+    // like any wire format parser should.
+    static const char kWireFormat[] = "\204\1";
+    io::CodedInputStream cis(reinterpret_cast<const uint8_t*>(kWireFormat), 2);
+    // The old CodedInputStream parser got an optimization (ReadTagNoLastTag)
+    // for non-group messages (like TestAllTypesLite) which made it not accept
+    // end-group. This is not a real big deal, but I think going forward its
+    // good to have all parse loops behave 'exactly' the same.
+    EXPECT_TRUE(msg.MergePartialFromCodedStream(&cis));
+    EXPECT_FALSE(cis.ConsumedEntireMessage());
+    EXPECT_TRUE(cis.LastTagWas(132));
+  }
+  {
+    // This is an incomplete end-group tag. This should be a genuine parse
+    // failure.
+    static const char kWireFormat[] = "\214";
+    io::CodedInputStream cis(reinterpret_cast<const uint8_t*>(kWireFormat), 1);
+    // Unfortunately the old parser detects a parse error in ReadTag and returns
+    // 0 (as it states 0 is an invalid tag). However 0 is not an invalid tag
+    // as it can be used to terminate the stream, so this returns true.
+    EXPECT_FALSE(msg.MergePartialFromCodedStream(&cis));
+  }
+}
+
+TEST(Lite, DebugString) {
+  protobuf_unittest::TestAllTypesLite message1, message2;
+  EXPECT_TRUE(HasPrefixString(message1.DebugString(), "MessageLite at 0x"));
+  EXPECT_TRUE(HasPrefixString(message2.DebugString(), "MessageLite at 0x"));
+
+  // DebugString() and ShortDebugString() are the same for now.
+  EXPECT_EQ(message1.DebugString(), message1.ShortDebugString());
+
+  // Even identical lite protos should have different DebugString() output. Part
+  // of the reason for including the memory address is so that we get some
+  // non-determinism, which should make it easier for us to change the output
+  // later without breaking any code.
+  EXPECT_NE(message1.DebugString(), message2.DebugString());
+}
+
+TEST(Lite, EnumValueToName) {
+  EXPECT_EQ("FOREIGN_LITE_FOO", protobuf_unittest::ForeignEnumLite_Name(
+                                    protobuf_unittest::FOREIGN_LITE_FOO));
+  EXPECT_EQ("FOREIGN_LITE_BAR", protobuf_unittest::ForeignEnumLite_Name(
+                                    protobuf_unittest::FOREIGN_LITE_BAR));
+  EXPECT_EQ("FOREIGN_LITE_BAZ", protobuf_unittest::ForeignEnumLite_Name(
+                                    protobuf_unittest::FOREIGN_LITE_BAZ));
+  EXPECT_EQ("", protobuf_unittest::ForeignEnumLite_Name(0));
+  EXPECT_EQ("", protobuf_unittest::ForeignEnumLite_Name(999));
+}
+
+TEST(Lite, NestedEnumValueToName) {
+  EXPECT_EQ("FOO", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
+                       protobuf_unittest::TestAllTypesLite::FOO));
+  EXPECT_EQ("BAR", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
+                       protobuf_unittest::TestAllTypesLite::BAR));
+  EXPECT_EQ("BAZ", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
+                       protobuf_unittest::TestAllTypesLite::BAZ));
+  EXPECT_EQ("", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(0));
+  EXPECT_EQ("", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(999));
+}
+
+TEST(Lite, EnumNameToValue) {
+  protobuf_unittest::ForeignEnumLite value;
+
+  ASSERT_TRUE(
+      protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_FOO", &value));
+  EXPECT_EQ(protobuf_unittest::FOREIGN_LITE_FOO, value);
+
+  ASSERT_TRUE(
+      protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_BAR", &value));
+  EXPECT_EQ(protobuf_unittest::FOREIGN_LITE_BAR, value);
+
+  ASSERT_TRUE(
+      protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_BAZ", &value));
+  EXPECT_EQ(protobuf_unittest::FOREIGN_LITE_BAZ, value);
+
+  // Non-existent values
+  EXPECT_FALSE(protobuf_unittest::ForeignEnumLite_Parse("E", &value));
+  EXPECT_FALSE(
+      protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_C", &value));
+  EXPECT_FALSE(protobuf_unittest::ForeignEnumLite_Parse("G", &value));
+}
+
+TEST(Lite, NestedEnumNameToValue) {
+  protobuf_unittest::TestAllTypesLite::NestedEnum value;
+
+  ASSERT_TRUE(
+      protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("FOO", &value));
+  EXPECT_EQ(protobuf_unittest::TestAllTypesLite::FOO, value);
+
+  ASSERT_TRUE(
+      protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("BAR", &value));
+  EXPECT_EQ(protobuf_unittest::TestAllTypesLite::BAR, value);
+
+  ASSERT_TRUE(
+      protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("BAZ", &value));
+  EXPECT_EQ(protobuf_unittest::TestAllTypesLite::BAZ, value);
+
+  // Non-existent values
+  EXPECT_FALSE(
+      protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("A", &value));
+  EXPECT_FALSE(
+      protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("C", &value));
+  EXPECT_FALSE(
+      protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("G", &value));
+}
+
+TEST(Lite, AliasedEnum) {
+  // Enums with allow_alias = true can have multiple entries with the same
+  // value.
+  EXPECT_EQ("FOO1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
+                        protobuf_unittest::DupEnum::FOO1));
+  EXPECT_EQ("FOO1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
+                        protobuf_unittest::DupEnum::FOO2));
+  EXPECT_EQ("BAR1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
+                        protobuf_unittest::DupEnum::BAR1));
+  EXPECT_EQ("BAR1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
+                        protobuf_unittest::DupEnum::BAR2));
+  EXPECT_EQ("BAZ", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
+                       protobuf_unittest::DupEnum::BAZ));
+  EXPECT_EQ("", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(999));
+
+  protobuf_unittest::DupEnum::TestEnumWithDupValueLite value;
+  ASSERT_TRUE(
+      protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Parse("FOO1", &value));
+  EXPECT_EQ(protobuf_unittest::DupEnum::FOO1, value);
+
+  value = static_cast<protobuf_unittest::DupEnum::TestEnumWithDupValueLite>(0);
+  ASSERT_TRUE(
+      protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Parse("FOO2", &value));
+  EXPECT_EQ(protobuf_unittest::DupEnum::FOO2, value);
+}
+
+
+TEST(Lite, CodedInputStreamRollback) {
+  {
+    protobuf_unittest::TestAllTypesLite m;
+    m.set_optional_bytes(std::string(30, 'a'));
+    std::string serialized = m.SerializeAsString();
+    serialized += '\014';
+    serialized += std::string(3, ' ');
+    io::ArrayInputStream is(serialized.data(), serialized.size(),
+                            serialized.size() - 6);
+    {
+      io::CodedInputStream cis(&is);
+      m.Clear();
+      m.MergePartialFromCodedStream(&cis);
+      EXPECT_TRUE(cis.LastTagWas(12));
+      EXPECT_FALSE(cis.ConsumedEntireMessage());
+      // Should leave is with 3 spaces;
+    }
+    const void* data;
+    int size;
+    ASSERT_TRUE(is.Next(&data, &size));
+    ASSERT_EQ(size, 3);
+    EXPECT_EQ(memcmp(data, "   ", 3), 0);
+  }
+  {
+    protobuf_unittest::TestPackedTypesLite m;
+    constexpr int kCount = 30;
+    for (int i = 0; i < kCount; i++) m.add_packed_fixed32(i);
+    std::string serialized = m.SerializeAsString();
+    serialized += '\014';
+    serialized += std::string(3, ' ');
+    // Buffer breaks in middle of a fixed32.
+    io::ArrayInputStream is(serialized.data(), serialized.size(),
+                            serialized.size() - 7);
+    {
+      io::CodedInputStream cis(&is);
+      m.Clear();
+      m.MergePartialFromCodedStream(&cis);
+      EXPECT_TRUE(cis.LastTagWas(12));
+      EXPECT_FALSE(cis.ConsumedEntireMessage());
+      // Should leave is with 3 spaces;
+    }
+    ASSERT_EQ(m.packed_fixed32_size(), kCount);
+    for (int i = 0; i < kCount; i++) EXPECT_EQ(m.packed_fixed32(i), i);
+    const void* data;
+    int size;
+    ASSERT_TRUE(is.Next(&data, &size));
+    ASSERT_EQ(size, 3);
+    EXPECT_EQ(memcmp(data, "   ", 3), 0);
+  }
+  {
+    protobuf_unittest::TestPackedTypesLite m;
+    constexpr int kCount = 30;
+    // Make sure we output 2 byte varints
+    for (int i = 0; i < kCount; i++) m.add_packed_fixed32(128 + i);
+    std::string serialized = m.SerializeAsString();
+    serialized += '\014';
+    serialized += std::string(3, ' ');
+    // Buffer breaks in middle of a 2 byte varint.
+    io::ArrayInputStream is(serialized.data(), serialized.size(),
+                            serialized.size() - 5);
+    {
+      io::CodedInputStream cis(&is);
+      m.Clear();
+      m.MergePartialFromCodedStream(&cis);
+      EXPECT_TRUE(cis.LastTagWas(12));
+      EXPECT_FALSE(cis.ConsumedEntireMessage());
+      // Should leave is with 3 spaces;
+    }
+    ASSERT_EQ(m.packed_fixed32_size(), kCount);
+    for (int i = 0; i < kCount; i++) EXPECT_EQ(m.packed_fixed32(i), i + 128);
+    const void* data;
+    int size;
+    ASSERT_TRUE(is.Next(&data, &size));
+    ASSERT_EQ(size, 3);
+    EXPECT_EQ(memcmp(data, "   ", 3), 0);
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map.cc b/src/google/protobuf/map.cc
new file mode 100644
index 0000000..d60a9a2
--- /dev/null
+++ b/src/google/protobuf/map.cc
@@ -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.
+
+#include <google/protobuf/map.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void* const kGlobalEmptyTable[kGlobalEmptyTableSize] = {nullptr};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
new file mode 100644
index 0000000..008c192
--- /dev/null
+++ b/src/google/protobuf/map.h
@@ -0,0 +1,1448 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 the map container and its helpers to support protobuf maps.
+//
+// The Map and MapIterator types are provided by this header file.
+// Please avoid using other types defined here, unless they are public
+// types within Map or MapIterator, such as Map::value_type.
+
+#ifndef GOOGLE_PROTOBUF_MAP_H__
+#define GOOGLE_PROTOBUF_MAP_H__
+
+
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <limits>  // To support Visual Studio 2008
+#include <map>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#if defined(__cpp_lib_string_view)
+#include <string_view>
+#endif  // defined(__cpp_lib_string_view)
+
+#if !defined(GOOGLE_PROTOBUF_NO_RDTSC) && defined(__APPLE__)
+#include <mach/mach_time.h>
+#endif
+
+#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/port.h>
+#include <google/protobuf/stubs/hash.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+template <typename Key, typename T>
+class Map;
+
+class MapIterator;
+
+template <typename Enum>
+struct is_proto_enum;
+
+namespace internal {
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+class MapFieldLite;
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+class MapField;
+
+template <typename Key, typename T>
+class TypeDefinedMapFieldBase;
+
+class DynamicMapField;
+
+class GeneratedMessageReflection;
+
+// re-implement std::allocator to use arena allocator for memory allocation.
+// Used for Map implementation. Users should not use this class
+// directly.
+template <typename U>
+class MapAllocator {
+ public:
+  using value_type = U;
+  using pointer = value_type*;
+  using const_pointer = const value_type*;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  constexpr MapAllocator() : arena_(nullptr) {}
+  explicit constexpr MapAllocator(Arena* arena) : arena_(arena) {}
+  template <typename X>
+  MapAllocator(const MapAllocator<X>& allocator)  // NOLINT(runtime/explicit)
+      : arena_(allocator.arena()) {}
+
+  // MapAllocator does not support alignments beyond 8. Technically we should
+  // support up to std::max_align_t, but this fails with ubsan and tcmalloc
+  // debug allocation logic which assume 8 as default alignment.
+  static_assert(alignof(value_type) <= 8, "");
+
+  pointer allocate(size_type n, const void* /* hint */ = nullptr) {
+    // If arena is not given, malloc needs to be called which doesn't
+    // construct element object.
+    if (arena_ == nullptr) {
+      return static_cast<pointer>(::operator new(n * sizeof(value_type)));
+    } else {
+      return reinterpret_cast<pointer>(
+          Arena::CreateArray<uint8_t>(arena_, n * sizeof(value_type)));
+    }
+  }
+
+  void deallocate(pointer p, size_type n) {
+    if (arena_ == nullptr) {
+      internal::SizedDelete(p, n * sizeof(value_type));
+    }
+  }
+
+#if !defined(GOOGLE_PROTOBUF_OS_APPLE) && !defined(GOOGLE_PROTOBUF_OS_NACL) && \
+    !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN)
+  template <class NodeType, class... Args>
+  void construct(NodeType* p, Args&&... args) {
+    // Clang 3.6 doesn't compile static casting to void* directly. (Issue
+    // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall
+    // not cast away constness". So first the maybe const pointer is casted to
+    // const void* and after the const void* is const casted.
+    new (const_cast<void*>(static_cast<const void*>(p)))
+        NodeType(std::forward<Args>(args)...);
+  }
+
+  template <class NodeType>
+  void destroy(NodeType* p) {
+    p->~NodeType();
+  }
+#else
+  void construct(pointer p, const_reference t) { new (p) value_type(t); }
+
+  void destroy(pointer p) { p->~value_type(); }
+#endif
+
+  template <typename X>
+  struct rebind {
+    using other = MapAllocator<X>;
+  };
+
+  template <typename X>
+  bool operator==(const MapAllocator<X>& other) const {
+    return arena_ == other.arena_;
+  }
+
+  template <typename X>
+  bool operator!=(const MapAllocator<X>& other) const {
+    return arena_ != other.arena_;
+  }
+
+  // To support Visual Studio 2008
+  size_type max_size() const {
+    // parentheses around (std::...:max) prevents macro warning of max()
+    return (std::numeric_limits<size_type>::max)();
+  }
+
+  // To support gcc-4.4, which does not properly
+  // support templated friend classes
+  Arena* arena() const { return arena_; }
+
+ private:
+  using DestructorSkippable_ = void;
+  Arena* arena_;
+};
+
+template <typename T>
+using KeyForTree =
+    typename std::conditional<std::is_scalar<T>::value, T,
+                              std::reference_wrapper<const T>>::type;
+
+// Default case: Not transparent.
+// We use std::hash<key_type>/std::less<key_type> and all the lookup functions
+// only accept `key_type`.
+template <typename key_type>
+struct TransparentSupport {
+  using hash = std::hash<key_type>;
+  using less = std::less<key_type>;
+
+  static bool Equals(const key_type& a, const key_type& b) { return a == b; }
+
+  template <typename K>
+  using key_arg = key_type;
+};
+
+#if defined(__cpp_lib_string_view)
+// If std::string_view is available, we add transparent support for std::string
+// keys. We use std::hash<std::string_view> as it supports the input types we
+// care about. The lookup functions accept arbitrary `K`. This will include any
+// key type that is convertible to std::string_view.
+template <>
+struct TransparentSupport<std::string> {
+  static std::string_view ImplicitConvert(std::string_view str) { return str; }
+  // If the element is not convertible to std::string_view, try to convert to
+  // std::string first.
+  // The template makes this overload lose resolution when both have the same
+  // rank otherwise.
+  template <typename = void>
+  static std::string_view ImplicitConvert(const std::string& str) {
+    return str;
+  }
+
+  struct hash : private std::hash<std::string_view> {
+    using is_transparent = void;
+
+    template <typename T>
+    size_t operator()(const T& str) const {
+      return base()(ImplicitConvert(str));
+    }
+
+   private:
+    const std::hash<std::string_view>& base() const { return *this; }
+  };
+  struct less {
+    using is_transparent = void;
+
+    template <typename T, typename U>
+    bool operator()(const T& t, const U& u) const {
+      return ImplicitConvert(t) < ImplicitConvert(u);
+    }
+  };
+
+  template <typename T, typename U>
+  static bool Equals(const T& t, const U& u) {
+    return ImplicitConvert(t) == ImplicitConvert(u);
+  }
+
+  template <typename K>
+  using key_arg = K;
+};
+#endif  // defined(__cpp_lib_string_view)
+
+template <typename Key>
+using TreeForMap =
+    std::map<KeyForTree<Key>, void*, typename TransparentSupport<Key>::less,
+             MapAllocator<std::pair<const KeyForTree<Key>, void*>>>;
+
+inline bool TableEntryIsEmpty(void* const* table, size_t b) {
+  return table[b] == nullptr;
+}
+inline bool TableEntryIsNonEmptyList(void* const* table, size_t b) {
+  return table[b] != nullptr && table[b] != table[b ^ 1];
+}
+inline bool TableEntryIsTree(void* const* table, size_t b) {
+  return !TableEntryIsEmpty(table, b) && !TableEntryIsNonEmptyList(table, b);
+}
+inline bool TableEntryIsList(void* const* table, size_t b) {
+  return !TableEntryIsTree(table, b);
+}
+
+// This captures all numeric types.
+inline size_t MapValueSpaceUsedExcludingSelfLong(bool) { return 0; }
+inline size_t MapValueSpaceUsedExcludingSelfLong(const std::string& str) {
+  return StringSpaceUsedExcludingSelfLong(str);
+}
+template <typename T,
+          typename = decltype(std::declval<const T&>().SpaceUsedLong())>
+size_t MapValueSpaceUsedExcludingSelfLong(const T& message) {
+  return message.SpaceUsedLong() - sizeof(T);
+}
+
+constexpr size_t kGlobalEmptyTableSize = 1;
+PROTOBUF_EXPORT extern void* const kGlobalEmptyTable[kGlobalEmptyTableSize];
+
+// Space used for the table, trees, and nodes.
+// Does not include the indirect space used. Eg the data of a std::string.
+template <typename Key>
+PROTOBUF_NOINLINE size_t SpaceUsedInTable(void** table, size_t num_buckets,
+                                          size_t num_elements,
+                                          size_t sizeof_node) {
+  size_t size = 0;
+  // The size of the table.
+  size += sizeof(void*) * num_buckets;
+  // All the nodes.
+  size += sizeof_node * num_elements;
+  // For each tree, count the overhead of the those nodes.
+  // Two buckets at a time because we only care about trees.
+  for (size_t b = 0; b < num_buckets; b += 2) {
+    if (internal::TableEntryIsTree(table, b)) {
+      using Tree = TreeForMap<Key>;
+      Tree* tree = static_cast<Tree*>(table[b]);
+      // Estimated cost of the red-black tree nodes, 3 pointers plus a
+      // bool (plus alignment, so 4 pointers).
+      size += tree->size() *
+              (sizeof(typename Tree::value_type) + sizeof(void*) * 4);
+    }
+  }
+  return size;
+}
+
+template <typename Map,
+          typename = typename std::enable_if<
+              !std::is_scalar<typename Map::key_type>::value ||
+              !std::is_scalar<typename Map::mapped_type>::value>::type>
+size_t SpaceUsedInValues(const Map* map) {
+  size_t size = 0;
+  for (const auto& v : *map) {
+    size += internal::MapValueSpaceUsedExcludingSelfLong(v.first) +
+            internal::MapValueSpaceUsedExcludingSelfLong(v.second);
+  }
+  return size;
+}
+
+inline size_t SpaceUsedInValues(const void*) { return 0; }
+
+}  // namespace internal
+
+// This is the class for Map's internal value_type. Instead of using
+// std::pair as value_type, we use this class which provides us more control of
+// its process of construction and destruction.
+template <typename Key, typename T>
+struct PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG MapPair {
+  using first_type = const Key;
+  using second_type = T;
+
+  MapPair(const Key& other_first, const T& other_second)
+      : first(other_first), second(other_second) {}
+  explicit MapPair(const Key& other_first) : first(other_first), second() {}
+  explicit MapPair(Key&& other_first)
+      : first(std::move(other_first)), second() {}
+  MapPair(const MapPair& other) : first(other.first), second(other.second) {}
+
+  ~MapPair() {}
+
+  // Implicitly convertible to std::pair of compatible types.
+  template <typename T1, typename T2>
+  operator std::pair<T1, T2>() const {  // NOLINT(runtime/explicit)
+    return std::pair<T1, T2>(first, second);
+  }
+
+  const Key first;
+  T second;
+
+ private:
+  friend class Arena;
+  friend class Map<Key, T>;
+};
+
+// Map is an associative container type used to store protobuf map
+// fields.  Each Map instance may or may not use a different hash function, a
+// different iteration order, and so on.  E.g., please don't examine
+// implementation details to decide if the following would work:
+//  Map<int, int> m0, m1;
+//  m0[0] = m1[0] = m0[1] = m1[1] = 0;
+//  assert(m0.begin()->first == m1.begin()->first);  // Bug!
+//
+// Map's interface is similar to std::unordered_map, except that Map is not
+// designed to play well with exceptions.
+template <typename Key, typename T>
+class Map {
+ public:
+  using key_type = Key;
+  using mapped_type = T;
+  using value_type = MapPair<Key, T>;
+
+  using pointer = value_type*;
+  using const_pointer = const value_type*;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+
+  using size_type = size_t;
+  using hasher = typename internal::TransparentSupport<Key>::hash;
+
+  constexpr Map() : elements_(nullptr) {}
+  explicit Map(Arena* arena) : elements_(arena) {}
+
+  Map(const Map& other) : Map() { insert(other.begin(), other.end()); }
+
+  Map(Map&& other) noexcept : Map() {
+    if (other.arena() != nullptr) {
+      *this = other;
+    } else {
+      swap(other);
+    }
+  }
+
+  Map& operator=(Map&& other) noexcept {
+    if (this != &other) {
+      if (arena() != other.arena()) {
+        *this = other;
+      } else {
+        swap(other);
+      }
+    }
+    return *this;
+  }
+
+  template <class InputIt>
+  Map(const InputIt& first, const InputIt& last) : Map() {
+    insert(first, last);
+  }
+
+  ~Map() {}
+
+ private:
+  using Allocator = internal::MapAllocator<void*>;
+
+  // InnerMap is a generic hash-based map.  It doesn't contain any
+  // protocol-buffer-specific logic.  It is a chaining hash map with the
+  // additional feature that some buckets can be converted to use an ordered
+  // container.  This ensures O(lg n) bounds on find, insert, and erase, while
+  // avoiding the overheads of ordered containers most of the time.
+  //
+  // The implementation doesn't need the full generality of unordered_map,
+  // and it doesn't have it.  More bells and whistles can be added as needed.
+  // Some implementation details:
+  // 1. The hash function has type hasher and the equality function
+  //    equal_to<Key>.  We inherit from hasher to save space
+  //    (empty-base-class optimization).
+  // 2. The number of buckets is a power of two.
+  // 3. Buckets are converted to trees in pairs: if we convert bucket b then
+  //    buckets b and b^1 will share a tree.  Invariant: buckets b and b^1 have
+  //    the same non-null value iff they are sharing a tree.  (An alternative
+  //    implementation strategy would be to have a tag bit per bucket.)
+  // 4. As is typical for hash_map and such, the Keys and Values are always
+  //    stored in linked list nodes.  Pointers to elements are never invalidated
+  //    until the element is deleted.
+  // 5. The trees' payload type is pointer to linked-list node.  Tree-converting
+  //    a bucket doesn't copy Key-Value pairs.
+  // 6. Once we've tree-converted a bucket, it is never converted back. However,
+  //    the items a tree contains may wind up assigned to trees or lists upon a
+  //    rehash.
+  // 7. The code requires no C++ features from C++14 or later.
+  // 8. Mutations to a map do not invalidate the map's iterators, pointers to
+  //    elements, or references to elements.
+  // 9. Except for erase(iterator), any non-const method can reorder iterators.
+  // 10. InnerMap uses KeyForTree<Key> when using the Tree representation, which
+  //    is either `Key`, if Key is a scalar, or `reference_wrapper<const Key>`
+  //    otherwise. This avoids unnecessary copies of string keys, for example.
+  class InnerMap : private hasher {
+   public:
+    explicit constexpr InnerMap(Arena* arena)
+        : hasher(),
+          num_elements_(0),
+          num_buckets_(internal::kGlobalEmptyTableSize),
+          seed_(0),
+          index_of_first_non_null_(internal::kGlobalEmptyTableSize),
+          table_(const_cast<void**>(internal::kGlobalEmptyTable)),
+          alloc_(arena) {}
+
+    ~InnerMap() {
+      if (alloc_.arena() == nullptr &&
+          num_buckets_ != internal::kGlobalEmptyTableSize) {
+        clear();
+        Dealloc<void*>(table_, num_buckets_);
+      }
+    }
+
+   private:
+    enum { kMinTableSize = 8 };
+
+    // Linked-list nodes, as one would expect for a chaining hash table.
+    struct Node {
+      value_type kv;
+      Node* next;
+    };
+
+    // Trees. The payload type is a copy of Key, so that we can query the tree
+    // with Keys that are not in any particular data structure.
+    // The value is a void* pointing to Node. We use void* instead of Node* to
+    // avoid code bloat. That way there is only one instantiation of the tree
+    // class per key type.
+    using Tree = internal::TreeForMap<Key>;
+    using TreeIterator = typename Tree::iterator;
+
+    static Node* NodeFromTreeIterator(TreeIterator it) {
+      return static_cast<Node*>(it->second);
+    }
+
+    // iterator and const_iterator are instantiations of iterator_base.
+    template <typename KeyValueType>
+    class iterator_base {
+     public:
+      using reference = KeyValueType&;
+      using pointer = KeyValueType*;
+
+      // Invariants:
+      // node_ is always correct. This is handy because the most common
+      // operations are operator* and operator-> and they only use node_.
+      // When node_ is set to a non-null value, all the other non-const fields
+      // are updated to be correct also, but those fields can become stale
+      // if the underlying map is modified.  When those fields are needed they
+      // are rechecked, and updated if necessary.
+      iterator_base() : node_(nullptr), m_(nullptr), bucket_index_(0) {}
+
+      explicit iterator_base(const InnerMap* m) : m_(m) {
+        SearchFrom(m->index_of_first_non_null_);
+      }
+
+      // Any iterator_base can convert to any other.  This is overkill, and we
+      // rely on the enclosing class to use it wisely.  The standard "iterator
+      // can convert to const_iterator" is OK but the reverse direction is not.
+      template <typename U>
+      explicit iterator_base(const iterator_base<U>& it)
+          : node_(it.node_), m_(it.m_), bucket_index_(it.bucket_index_) {}
+
+      iterator_base(Node* n, const InnerMap* m, size_type index)
+          : node_(n), m_(m), bucket_index_(index) {}
+
+      iterator_base(TreeIterator tree_it, const InnerMap* m, size_type index)
+          : node_(NodeFromTreeIterator(tree_it)), m_(m), bucket_index_(index) {
+        // Invariant: iterators that use buckets with trees have an even
+        // bucket_index_.
+        GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0u);
+      }
+
+      // Advance through buckets, looking for the first that isn't empty.
+      // If nothing non-empty is found then leave node_ == nullptr.
+      void SearchFrom(size_type start_bucket) {
+        GOOGLE_DCHECK(m_->index_of_first_non_null_ == m_->num_buckets_ ||
+               m_->table_[m_->index_of_first_non_null_] != nullptr);
+        node_ = nullptr;
+        for (bucket_index_ = start_bucket; bucket_index_ < m_->num_buckets_;
+             bucket_index_++) {
+          if (m_->TableEntryIsNonEmptyList(bucket_index_)) {
+            node_ = static_cast<Node*>(m_->table_[bucket_index_]);
+            break;
+          } else if (m_->TableEntryIsTree(bucket_index_)) {
+            Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
+            GOOGLE_DCHECK(!tree->empty());
+            node_ = NodeFromTreeIterator(tree->begin());
+            break;
+          }
+        }
+      }
+
+      reference operator*() const { return node_->kv; }
+      pointer operator->() const { return &(operator*()); }
+
+      friend bool operator==(const iterator_base& a, const iterator_base& b) {
+        return a.node_ == b.node_;
+      }
+      friend bool operator!=(const iterator_base& a, const iterator_base& b) {
+        return a.node_ != b.node_;
+      }
+
+      iterator_base& operator++() {
+        if (node_->next == nullptr) {
+          TreeIterator tree_it;
+          const bool is_list = revalidate_if_necessary(&tree_it);
+          if (is_list) {
+            SearchFrom(bucket_index_ + 1);
+          } else {
+            GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0u);
+            Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
+            if (++tree_it == tree->end()) {
+              SearchFrom(bucket_index_ + 2);
+            } else {
+              node_ = NodeFromTreeIterator(tree_it);
+            }
+          }
+        } else {
+          node_ = node_->next;
+        }
+        return *this;
+      }
+
+      iterator_base operator++(int /* unused */) {
+        iterator_base tmp = *this;
+        ++*this;
+        return tmp;
+      }
+
+      // Assumes node_ and m_ are correct and non-null, but other fields may be
+      // stale.  Fix them as needed.  Then return true iff node_ points to a
+      // Node in a list.  If false is returned then *it is modified to be
+      // a valid iterator for node_.
+      bool revalidate_if_necessary(TreeIterator* it) {
+        GOOGLE_DCHECK(node_ != nullptr && m_ != nullptr);
+        // Force bucket_index_ to be in range.
+        bucket_index_ &= (m_->num_buckets_ - 1);
+        // Common case: the bucket we think is relevant points to node_.
+        if (m_->table_[bucket_index_] == static_cast<void*>(node_)) return true;
+        // Less common: the bucket is a linked list with node_ somewhere in it,
+        // but not at the head.
+        if (m_->TableEntryIsNonEmptyList(bucket_index_)) {
+          Node* l = static_cast<Node*>(m_->table_[bucket_index_]);
+          while ((l = l->next) != nullptr) {
+            if (l == node_) {
+              return true;
+            }
+          }
+        }
+        // Well, bucket_index_ still might be correct, but probably
+        // not.  Revalidate just to be sure.  This case is rare enough that we
+        // don't worry about potential optimizations, such as having a custom
+        // find-like method that compares Node* instead of the key.
+        iterator_base i(m_->find(node_->kv.first, it));
+        bucket_index_ = i.bucket_index_;
+        return m_->TableEntryIsList(bucket_index_);
+      }
+
+      Node* node_;
+      const InnerMap* m_;
+      size_type bucket_index_;
+    };
+
+   public:
+    using iterator = iterator_base<value_type>;
+    using const_iterator = iterator_base<const value_type>;
+
+    Arena* arena() const { return alloc_.arena(); }
+
+    void Swap(InnerMap* other) {
+      std::swap(num_elements_, other->num_elements_);
+      std::swap(num_buckets_, other->num_buckets_);
+      std::swap(seed_, other->seed_);
+      std::swap(index_of_first_non_null_, other->index_of_first_non_null_);
+      std::swap(table_, other->table_);
+      std::swap(alloc_, other->alloc_);
+    }
+
+    iterator begin() { return iterator(this); }
+    iterator end() { return iterator(); }
+    const_iterator begin() const { return const_iterator(this); }
+    const_iterator end() const { return const_iterator(); }
+
+    void clear() {
+      for (size_type b = 0; b < num_buckets_; b++) {
+        if (TableEntryIsNonEmptyList(b)) {
+          Node* node = static_cast<Node*>(table_[b]);
+          table_[b] = nullptr;
+          do {
+            Node* next = node->next;
+            DestroyNode(node);
+            node = next;
+          } while (node != nullptr);
+        } else if (TableEntryIsTree(b)) {
+          Tree* tree = static_cast<Tree*>(table_[b]);
+          GOOGLE_DCHECK(table_[b] == table_[b + 1] && (b & 1) == 0);
+          table_[b] = table_[b + 1] = nullptr;
+          typename Tree::iterator tree_it = tree->begin();
+          do {
+            Node* node = NodeFromTreeIterator(tree_it);
+            typename Tree::iterator next = tree_it;
+            ++next;
+            tree->erase(tree_it);
+            DestroyNode(node);
+            tree_it = next;
+          } while (tree_it != tree->end());
+          DestroyTree(tree);
+          b++;
+        }
+      }
+      num_elements_ = 0;
+      index_of_first_non_null_ = num_buckets_;
+    }
+
+    const hasher& hash_function() const { return *this; }
+
+    static size_type max_size() {
+      return static_cast<size_type>(1) << (sizeof(void**) >= 8 ? 60 : 28);
+    }
+    size_type size() const { return num_elements_; }
+    bool empty() const { return size() == 0; }
+
+    template <typename K>
+    iterator find(const K& k) {
+      return iterator(FindHelper(k).first);
+    }
+
+    template <typename K>
+    const_iterator find(const K& k) const {
+      return FindHelper(k).first;
+    }
+
+    // Inserts a new element into the container if there is no element with the
+    // key in the container.
+    // The new element is:
+    //  (1) Constructed in-place with the given args, if mapped_type is not
+    //      arena constructible.
+    //  (2) Constructed in-place with the arena and then assigned with a
+    //      mapped_type temporary constructed with the given args, otherwise.
+    template <typename K, typename... Args>
+    std::pair<iterator, bool> try_emplace(K&& k, Args&&... args) {
+      return ArenaAwareTryEmplace(Arena::is_arena_constructable<mapped_type>(),
+                                  std::forward<K>(k),
+                                  std::forward<Args>(args)...);
+    }
+
+    // Inserts the key into the map, if not present. In that case, the value
+    // will be value initialized.
+    template <typename K>
+    std::pair<iterator, bool> insert(K&& k) {
+      return try_emplace(std::forward<K>(k));
+    }
+
+    template <typename K>
+    value_type& operator[](K&& k) {
+      return *try_emplace(std::forward<K>(k)).first;
+    }
+
+    void erase(iterator it) {
+      GOOGLE_DCHECK_EQ(it.m_, this);
+      typename Tree::iterator tree_it;
+      const bool is_list = it.revalidate_if_necessary(&tree_it);
+      size_type b = it.bucket_index_;
+      Node* const item = it.node_;
+      if (is_list) {
+        GOOGLE_DCHECK(TableEntryIsNonEmptyList(b));
+        Node* head = static_cast<Node*>(table_[b]);
+        head = EraseFromLinkedList(item, head);
+        table_[b] = static_cast<void*>(head);
+      } else {
+        GOOGLE_DCHECK(TableEntryIsTree(b));
+        Tree* tree = static_cast<Tree*>(table_[b]);
+        tree->erase(tree_it);
+        if (tree->empty()) {
+          // Force b to be the minimum of b and b ^ 1.  This is important
+          // only because we want index_of_first_non_null_ to be correct.
+          b &= ~static_cast<size_type>(1);
+          DestroyTree(tree);
+          table_[b] = table_[b + 1] = nullptr;
+        }
+      }
+      DestroyNode(item);
+      --num_elements_;
+      if (PROTOBUF_PREDICT_FALSE(b == index_of_first_non_null_)) {
+        while (index_of_first_non_null_ < num_buckets_ &&
+               table_[index_of_first_non_null_] == nullptr) {
+          ++index_of_first_non_null_;
+        }
+      }
+    }
+
+    size_t SpaceUsedInternal() const {
+      return internal::SpaceUsedInTable<Key>(table_, num_buckets_,
+                                             num_elements_, sizeof(Node));
+    }
+
+   private:
+    template <typename K, typename... Args>
+    std::pair<iterator, bool> TryEmplaceInternal(K&& k, Args&&... args) {
+      std::pair<const_iterator, size_type> p = FindHelper(k);
+      // Case 1: key was already present.
+      if (p.first.node_ != nullptr)
+        return std::make_pair(iterator(p.first), false);
+      // Case 2: insert.
+      if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
+        p = FindHelper(k);
+      }
+      const size_type b = p.second;  // bucket number
+      // If K is not key_type, make the conversion to key_type explicit.
+      using TypeToInit = typename std::conditional<
+          std::is_same<typename std::decay<K>::type, key_type>::value, K&&,
+          key_type>::type;
+      Node* node = Alloc<Node>(1);
+      // Even when arena is nullptr, CreateInArenaStorage is still used to
+      // ensure the arena of submessage will be consistent. Otherwise,
+      // submessage may have its own arena when message-owned arena is enabled.
+      // Note: This only works if `Key` is not arena constructible.
+      Arena::CreateInArenaStorage(const_cast<Key*>(&node->kv.first),
+                                  alloc_.arena(),
+                                  static_cast<TypeToInit>(std::forward<K>(k)));
+      // Note: if `T` is arena constructible, `Args` needs to be empty.
+      Arena::CreateInArenaStorage(&node->kv.second, alloc_.arena(),
+                                  std::forward<Args>(args)...);
+
+      iterator result = InsertUnique(b, node);
+      ++num_elements_;
+      return std::make_pair(result, true);
+    }
+
+    // A helper function to perform an assignment of `mapped_type`.
+    // If the first argument is true, then it is a regular assignment.
+    // Otherwise, we first create a temporary and then perform an assignment.
+    template <typename V>
+    static void AssignMapped(std::true_type, mapped_type& mapped, V&& v) {
+      mapped = std::forward<V>(v);
+    }
+    template <typename... Args>
+    static void AssignMapped(std::false_type, mapped_type& mapped,
+                             Args&&... args) {
+      mapped = mapped_type(std::forward<Args>(args)...);
+    }
+
+    // Case 1: `mapped_type` is arena constructible. A temporary object is
+    // created and then (if `Args` are not empty) assigned to a mapped value
+    // that was created with the arena.
+    template <typename K>
+    std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k) {
+      // case 1.1: "default" constructed (e.g. from arena only).
+      return TryEmplaceInternal(std::forward<K>(k));
+    }
+    template <typename K, typename... Args>
+    std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k,
+                                                   Args&&... args) {
+      // case 1.2: "default" constructed + copy/move assignment
+      auto p = TryEmplaceInternal(std::forward<K>(k));
+      if (p.second) {
+        AssignMapped(std::is_same<void(typename std::decay<Args>::type...),
+                                  void(mapped_type)>(),
+                     p.first->second, std::forward<Args>(args)...);
+      }
+      return p;
+    }
+    // Case 2: `mapped_type` is not arena constructible. Using in-place
+    // construction.
+    template <typename... Args>
+    std::pair<iterator, bool> ArenaAwareTryEmplace(std::false_type,
+                                                   Args&&... args) {
+      return TryEmplaceInternal(std::forward<Args>(args)...);
+    }
+
+    const_iterator find(const Key& k, TreeIterator* it) const {
+      return FindHelper(k, it).first;
+    }
+    template <typename K>
+    std::pair<const_iterator, size_type> FindHelper(const K& k) const {
+      return FindHelper(k, nullptr);
+    }
+    template <typename K>
+    std::pair<const_iterator, size_type> FindHelper(const K& k,
+                                                    TreeIterator* it) const {
+      size_type b = BucketNumber(k);
+      if (TableEntryIsNonEmptyList(b)) {
+        Node* node = static_cast<Node*>(table_[b]);
+        do {
+          if (internal::TransparentSupport<Key>::Equals(node->kv.first, k)) {
+            return std::make_pair(const_iterator(node, this, b), b);
+          } else {
+            node = node->next;
+          }
+        } while (node != nullptr);
+      } else if (TableEntryIsTree(b)) {
+        GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]);
+        b &= ~static_cast<size_t>(1);
+        Tree* tree = static_cast<Tree*>(table_[b]);
+        auto tree_it = tree->find(k);
+        if (tree_it != tree->end()) {
+          if (it != nullptr) *it = tree_it;
+          return std::make_pair(const_iterator(tree_it, this, b), b);
+        }
+      }
+      return std::make_pair(end(), b);
+    }
+
+    // Insert the given Node in bucket b.  If that would make bucket b too big,
+    // and bucket b is not a tree, create a tree for buckets b and b^1 to share.
+    // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct
+    // bucket.  num_elements_ is not modified.
+    iterator InsertUnique(size_type b, Node* node) {
+      GOOGLE_DCHECK(index_of_first_non_null_ == num_buckets_ ||
+             table_[index_of_first_non_null_] != nullptr);
+      // In practice, the code that led to this point may have already
+      // determined whether we are inserting into an empty list, a short list,
+      // or whatever.  But it's probably cheap enough to recompute that here;
+      // it's likely that we're inserting into an empty or short list.
+      iterator result;
+      GOOGLE_DCHECK(find(node->kv.first) == end());
+      if (TableEntryIsEmpty(b)) {
+        result = InsertUniqueInList(b, node);
+      } else if (TableEntryIsNonEmptyList(b)) {
+        if (PROTOBUF_PREDICT_FALSE(TableEntryIsTooLong(b))) {
+          TreeConvert(b);
+          result = InsertUniqueInTree(b, node);
+          GOOGLE_DCHECK_EQ(result.bucket_index_, b & ~static_cast<size_type>(1));
+        } else {
+          // Insert into a pre-existing list.  This case cannot modify
+          // index_of_first_non_null_, so we skip the code to update it.
+          return InsertUniqueInList(b, node);
+        }
+      } else {
+        // Insert into a pre-existing tree.  This case cannot modify
+        // index_of_first_non_null_, so we skip the code to update it.
+        return InsertUniqueInTree(b, node);
+      }
+      // parentheses around (std::min) prevents macro expansion of min(...)
+      index_of_first_non_null_ =
+          (std::min)(index_of_first_non_null_, result.bucket_index_);
+      return result;
+    }
+
+    // Returns whether we should insert after the head of the list. For
+    // non-optimized builds, we randomly decide whether to insert right at the
+    // head of the list or just after the head. This helps add a little bit of
+    // non-determinism to the map ordering.
+    bool ShouldInsertAfterHead(void* node) {
+#ifdef NDEBUG
+      (void)node;
+      return false;
+#else
+      // Doing modulo with a prime mixes the bits more.
+      return (reinterpret_cast<uintptr_t>(node) ^ seed_) % 13 > 6;
+#endif
+    }
+
+    // Helper for InsertUnique.  Handles the case where bucket b is a
+    // not-too-long linked list.
+    iterator InsertUniqueInList(size_type b, Node* node) {
+      if (table_[b] != nullptr && ShouldInsertAfterHead(node)) {
+        Node* first = static_cast<Node*>(table_[b]);
+        node->next = first->next;
+        first->next = node;
+        return iterator(node, this, b);
+      }
+
+      node->next = static_cast<Node*>(table_[b]);
+      table_[b] = static_cast<void*>(node);
+      return iterator(node, this, b);
+    }
+
+    // Helper for InsertUnique.  Handles the case where bucket b points to a
+    // Tree.
+    iterator InsertUniqueInTree(size_type b, Node* node) {
+      GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]);
+      // Maintain the invariant that node->next is null for all Nodes in Trees.
+      node->next = nullptr;
+      return iterator(
+          static_cast<Tree*>(table_[b])->insert({node->kv.first, node}).first,
+          this, b & ~static_cast<size_t>(1));
+    }
+
+    // Returns whether it did resize.  Currently this is only used when
+    // num_elements_ increases, though it could be used in other situations.
+    // It checks for load too low as well as load too high: because any number
+    // of erases can occur between inserts, the load could be as low as 0 here.
+    // Resizing to a lower size is not always helpful, but failing to do so can
+    // destroy the expected big-O bounds for some operations. By having the
+    // policy that sometimes we resize down as well as up, clients can easily
+    // keep O(size()) = O(number of buckets) if they want that.
+    bool ResizeIfLoadIsOutOfRange(size_type new_size) {
+      const size_type kMaxMapLoadTimes16 = 12;  // controls RAM vs CPU tradeoff
+      const size_type hi_cutoff = num_buckets_ * kMaxMapLoadTimes16 / 16;
+      const size_type lo_cutoff = hi_cutoff / 4;
+      // We don't care how many elements are in trees.  If a lot are,
+      // we may resize even though there are many empty buckets.  In
+      // practice, this seems fine.
+      if (PROTOBUF_PREDICT_FALSE(new_size >= hi_cutoff)) {
+        if (num_buckets_ <= max_size() / 2) {
+          Resize(num_buckets_ * 2);
+          return true;
+        }
+      } else if (PROTOBUF_PREDICT_FALSE(new_size <= lo_cutoff &&
+                                        num_buckets_ > kMinTableSize)) {
+        size_type lg2_of_size_reduction_factor = 1;
+        // It's possible we want to shrink a lot here... size() could even be 0.
+        // So, estimate how much to shrink by making sure we don't shrink so
+        // much that we would need to grow the table after a few inserts.
+        const size_type hypothetical_size = new_size * 5 / 4 + 1;
+        while ((hypothetical_size << lg2_of_size_reduction_factor) <
+               hi_cutoff) {
+          ++lg2_of_size_reduction_factor;
+        }
+        size_type new_num_buckets = std::max<size_type>(
+            kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor);
+        if (new_num_buckets != num_buckets_) {
+          Resize(new_num_buckets);
+          return true;
+        }
+      }
+      return false;
+    }
+
+    // Resize to the given number of buckets.
+    void Resize(size_t new_num_buckets) {
+      if (num_buckets_ == internal::kGlobalEmptyTableSize) {
+        // This is the global empty array.
+        // Just overwrite with a new one. No need to transfer or free anything.
+        num_buckets_ = index_of_first_non_null_ = kMinTableSize;
+        table_ = CreateEmptyTable(num_buckets_);
+        seed_ = Seed();
+        return;
+      }
+
+      GOOGLE_DCHECK_GE(new_num_buckets, kMinTableSize);
+      void** const old_table = table_;
+      const size_type old_table_size = num_buckets_;
+      num_buckets_ = new_num_buckets;
+      table_ = CreateEmptyTable(num_buckets_);
+      const size_type start = index_of_first_non_null_;
+      index_of_first_non_null_ = num_buckets_;
+      for (size_type i = start; i < old_table_size; i++) {
+        if (internal::TableEntryIsNonEmptyList(old_table, i)) {
+          TransferList(old_table, i);
+        } else if (internal::TableEntryIsTree(old_table, i)) {
+          TransferTree(old_table, i++);
+        }
+      }
+      Dealloc<void*>(old_table, old_table_size);
+    }
+
+    void TransferList(void* const* table, size_type index) {
+      Node* node = static_cast<Node*>(table[index]);
+      do {
+        Node* next = node->next;
+        InsertUnique(BucketNumber(node->kv.first), node);
+        node = next;
+      } while (node != nullptr);
+    }
+
+    void TransferTree(void* const* table, size_type index) {
+      Tree* tree = static_cast<Tree*>(table[index]);
+      typename Tree::iterator tree_it = tree->begin();
+      do {
+        InsertUnique(BucketNumber(std::cref(tree_it->first).get()),
+                     NodeFromTreeIterator(tree_it));
+      } while (++tree_it != tree->end());
+      DestroyTree(tree);
+    }
+
+    Node* EraseFromLinkedList(Node* item, Node* head) {
+      if (head == item) {
+        return head->next;
+      } else {
+        head->next = EraseFromLinkedList(item, head->next);
+        return head;
+      }
+    }
+
+    bool TableEntryIsEmpty(size_type b) const {
+      return internal::TableEntryIsEmpty(table_, b);
+    }
+    bool TableEntryIsNonEmptyList(size_type b) const {
+      return internal::TableEntryIsNonEmptyList(table_, b);
+    }
+    bool TableEntryIsTree(size_type b) const {
+      return internal::TableEntryIsTree(table_, b);
+    }
+    bool TableEntryIsList(size_type b) const {
+      return internal::TableEntryIsList(table_, b);
+    }
+
+    void TreeConvert(size_type b) {
+      GOOGLE_DCHECK(!TableEntryIsTree(b) && !TableEntryIsTree(b ^ 1));
+      Tree* tree =
+          Arena::Create<Tree>(alloc_.arena(), typename Tree::key_compare(),
+                              typename Tree::allocator_type(alloc_));
+      size_type count = CopyListToTree(b, tree) + CopyListToTree(b ^ 1, tree);
+      GOOGLE_DCHECK_EQ(count, tree->size());
+      table_[b] = table_[b ^ 1] = static_cast<void*>(tree);
+    }
+
+    // Copy a linked list in the given bucket to a tree.
+    // Returns the number of things it copied.
+    size_type CopyListToTree(size_type b, Tree* tree) {
+      size_type count = 0;
+      Node* node = static_cast<Node*>(table_[b]);
+      while (node != nullptr) {
+        tree->insert({node->kv.first, node});
+        ++count;
+        Node* next = node->next;
+        node->next = nullptr;
+        node = next;
+      }
+      return count;
+    }
+
+    // Return whether table_[b] is a linked list that seems awfully long.
+    // Requires table_[b] to point to a non-empty linked list.
+    bool TableEntryIsTooLong(size_type b) {
+      const size_type kMaxLength = 8;
+      size_type count = 0;
+      Node* node = static_cast<Node*>(table_[b]);
+      do {
+        ++count;
+        node = node->next;
+      } while (node != nullptr);
+      // Invariant: no linked list ever is more than kMaxLength in length.
+      GOOGLE_DCHECK_LE(count, kMaxLength);
+      return count >= kMaxLength;
+    }
+
+    template <typename K>
+    size_type BucketNumber(const K& k) const {
+      // We xor the hash value against the random seed so that we effectively
+      // have a random hash function.
+      uint64_t h = hash_function()(k) ^ seed_;
+
+      // We use the multiplication method to determine the bucket number from
+      // the hash value. The constant kPhi (suggested by Knuth) is roughly
+      // (sqrt(5) - 1) / 2 * 2^64.
+      constexpr uint64_t kPhi = uint64_t{0x9e3779b97f4a7c15};
+      return ((kPhi * h) >> 32) & (num_buckets_ - 1);
+    }
+
+    // Return a power of two no less than max(kMinTableSize, n).
+    // Assumes either n < kMinTableSize or n is a power of two.
+    size_type TableSize(size_type n) {
+      return n < static_cast<size_type>(kMinTableSize)
+                 ? static_cast<size_type>(kMinTableSize)
+                 : n;
+    }
+
+    // Use alloc_ to allocate an array of n objects of type U.
+    template <typename U>
+    U* Alloc(size_type n) {
+      using alloc_type = typename Allocator::template rebind<U>::other;
+      return alloc_type(alloc_).allocate(n);
+    }
+
+    // Use alloc_ to deallocate an array of n objects of type U.
+    template <typename U>
+    void Dealloc(U* t, size_type n) {
+      using alloc_type = typename Allocator::template rebind<U>::other;
+      alloc_type(alloc_).deallocate(t, n);
+    }
+
+    void DestroyNode(Node* node) {
+      if (alloc_.arena() == nullptr) {
+        delete node;
+      }
+    }
+
+    void DestroyTree(Tree* tree) {
+      if (alloc_.arena() == nullptr) {
+        delete tree;
+      }
+    }
+
+    void** CreateEmptyTable(size_type n) {
+      GOOGLE_DCHECK(n >= kMinTableSize);
+      GOOGLE_DCHECK_EQ(n & (n - 1), 0u);
+      void** result = Alloc<void*>(n);
+      memset(result, 0, n * sizeof(result[0]));
+      return result;
+    }
+
+    // Return a randomish value.
+    size_type Seed() const {
+      // We get a little bit of randomness from the address of the map. The
+      // lower bits are not very random, due to alignment, so we discard them
+      // and shift the higher bits into their place.
+      size_type s = reinterpret_cast<uintptr_t>(this) >> 4;
+#if !defined(GOOGLE_PROTOBUF_NO_RDTSC)
+#if defined(__APPLE__)
+      // Use a commpage-based fast time function on Apple environments (MacOS,
+      // iOS, tvOS, watchOS, etc).
+      s += mach_absolute_time();
+#elif defined(__x86_64__) && defined(__GNUC__)
+      uint32_t hi, lo;
+      asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+      s += ((static_cast<uint64_t>(hi) << 32) | lo);
+#elif defined(__aarch64__) && defined(__GNUC__)
+      // There is no rdtsc on ARMv8. CNTVCT_EL0 is the virtual counter of the
+      // system timer. It runs at a different frequency than the CPU's, but is
+      // the best source of time-based entropy we get.
+      uint64_t virtual_timer_value;
+      asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
+      s += virtual_timer_value;
+#endif
+#endif  // !defined(GOOGLE_PROTOBUF_NO_RDTSC)
+      return s;
+    }
+
+    friend class Arena;
+    using InternalArenaConstructable_ = void;
+    using DestructorSkippable_ = void;
+
+    size_type num_elements_;
+    size_type num_buckets_;
+    size_type seed_;
+    size_type index_of_first_non_null_;
+    void** table_;  // an array with num_buckets_ entries
+    Allocator alloc_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap);
+  };  // end of class InnerMap
+
+  template <typename LookupKey>
+  using key_arg = typename internal::TransparentSupport<
+      key_type>::template key_arg<LookupKey>;
+
+ public:
+  // Iterators
+  class const_iterator {
+    using InnerIt = typename InnerMap::const_iterator;
+
+   public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = typename Map::value_type;
+    using difference_type = ptrdiff_t;
+    using pointer = const value_type*;
+    using reference = const value_type&;
+
+    const_iterator() {}
+    explicit const_iterator(const InnerIt& it) : it_(it) {}
+
+    const_reference operator*() const { return *it_; }
+    const_pointer operator->() const { return &(operator*()); }
+
+    const_iterator& operator++() {
+      ++it_;
+      return *this;
+    }
+    const_iterator operator++(int) { return const_iterator(it_++); }
+
+    friend bool operator==(const const_iterator& a, const const_iterator& b) {
+      return a.it_ == b.it_;
+    }
+    friend bool operator!=(const const_iterator& a, const const_iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    InnerIt it_;
+  };
+
+  class iterator {
+    using InnerIt = typename InnerMap::iterator;
+
+   public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = typename Map::value_type;
+    using difference_type = ptrdiff_t;
+    using pointer = value_type*;
+    using reference = value_type&;
+
+    iterator() {}
+    explicit iterator(const InnerIt& it) : it_(it) {}
+
+    reference operator*() const { return *it_; }
+    pointer operator->() const { return &(operator*()); }
+
+    iterator& operator++() {
+      ++it_;
+      return *this;
+    }
+    iterator operator++(int) { return iterator(it_++); }
+
+    // Allow implicit conversion to const_iterator.
+    operator const_iterator() const {  // NOLINT(runtime/explicit)
+      return const_iterator(typename InnerMap::const_iterator(it_));
+    }
+
+    friend bool operator==(const iterator& a, const iterator& b) {
+      return a.it_ == b.it_;
+    }
+    friend bool operator!=(const iterator& a, const iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    friend class Map;
+
+    InnerIt it_;
+  };
+
+  iterator begin() { return iterator(elements_.begin()); }
+  iterator end() { return iterator(elements_.end()); }
+  const_iterator begin() const { return const_iterator(elements_.begin()); }
+  const_iterator end() const { return const_iterator(elements_.end()); }
+  const_iterator cbegin() const { return begin(); }
+  const_iterator cend() const { return end(); }
+
+  // Capacity
+  size_type size() const { return elements_.size(); }
+  bool empty() const { return size() == 0; }
+
+  // Element access
+  template <typename K = key_type>
+  T& operator[](const key_arg<K>& key) {
+    return elements_[key].second;
+  }
+  template <
+      typename K = key_type,
+      // Disable for integral types to reduce code bloat.
+      typename = typename std::enable_if<!std::is_integral<K>::value>::type>
+  T& operator[](key_arg<K>&& key) {
+    return elements_[std::forward<K>(key)].second;
+  }
+
+  template <typename K = key_type>
+  const T& at(const key_arg<K>& key) const {
+    const_iterator it = find(key);
+    GOOGLE_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
+    return it->second;
+  }
+
+  template <typename K = key_type>
+  T& at(const key_arg<K>& key) {
+    iterator it = find(key);
+    GOOGLE_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
+    return it->second;
+  }
+
+  // Lookup
+  template <typename K = key_type>
+  size_type count(const key_arg<K>& key) const {
+    return find(key) == end() ? 0 : 1;
+  }
+
+  template <typename K = key_type>
+  const_iterator find(const key_arg<K>& key) const {
+    return const_iterator(elements_.find(key));
+  }
+  template <typename K = key_type>
+  iterator find(const key_arg<K>& key) {
+    return iterator(elements_.find(key));
+  }
+
+  template <typename K = key_type>
+  bool contains(const key_arg<K>& key) const {
+    return find(key) != end();
+  }
+
+  template <typename K = key_type>
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_arg<K>& key) const {
+    const_iterator it = find(key);
+    if (it == end()) {
+      return std::pair<const_iterator, const_iterator>(it, it);
+    } else {
+      const_iterator begin = it++;
+      return std::pair<const_iterator, const_iterator>(begin, it);
+    }
+  }
+
+  template <typename K = key_type>
+  std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
+    iterator it = find(key);
+    if (it == end()) {
+      return std::pair<iterator, iterator>(it, it);
+    } else {
+      iterator begin = it++;
+      return std::pair<iterator, iterator>(begin, it);
+    }
+  }
+
+  // insert
+  template <typename K, typename... Args>
+  std::pair<iterator, bool> try_emplace(K&& k, Args&&... args) {
+    auto p =
+        elements_.try_emplace(std::forward<K>(k), std::forward<Args>(args)...);
+    return std::pair<iterator, bool>(iterator(p.first), p.second);
+  }
+  std::pair<iterator, bool> insert(const value_type& value) {
+    return try_emplace(value.first, value.second);
+  }
+  std::pair<iterator, bool> insert(value_type&& value) {
+    return try_emplace(value.first, std::move(value.second));
+  }
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    return insert(value_type(std::forward<Args>(args)...));
+  }
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (; first != last; ++first) {
+      try_emplace(first->first, first->second);
+    }
+  }
+  void insert(std::initializer_list<value_type> values) {
+    insert(values.begin(), values.end());
+  }
+
+  // Erase and clear
+  template <typename K = key_type>
+  size_type erase(const key_arg<K>& key) {
+    iterator it = find(key);
+    if (it == end()) {
+      return 0;
+    } else {
+      erase(it);
+      return 1;
+    }
+  }
+  iterator erase(iterator pos) {
+    iterator i = pos++;
+    elements_.erase(i.it_);
+    return pos;
+  }
+  void erase(iterator first, iterator last) {
+    while (first != last) {
+      first = erase(first);
+    }
+  }
+  void clear() { elements_.clear(); }
+
+  // Assign
+  Map& operator=(const Map& other) {
+    if (this != &other) {
+      clear();
+      insert(other.begin(), other.end());
+    }
+    return *this;
+  }
+
+  void swap(Map& other) {
+    if (arena() == other.arena()) {
+      InternalSwap(other);
+    } else {
+      // TODO(zuguang): optimize this. The temporary copy can be allocated
+      // in the same arena as the other message, and the "other = copy" can
+      // be replaced with the fast-path swap above.
+      Map copy = *this;
+      *this = other;
+      other = copy;
+    }
+  }
+
+  void InternalSwap(Map& other) { elements_.Swap(&other.elements_); }
+
+  // Access to hasher.  Currently this returns a copy, but it may
+  // be modified to return a const reference in the future.
+  hasher hash_function() const { return elements_.hash_function(); }
+
+  size_t SpaceUsedExcludingSelfLong() const {
+    if (empty()) return 0;
+    return elements_.SpaceUsedInternal() + internal::SpaceUsedInValues(this);
+  }
+
+ private:
+  Arena* arena() const { return elements_.arena(); }
+  InnerMap elements_;
+
+  friend class Arena;
+  using InternalArenaConstructable_ = void;
+  using DestructorSkippable_ = void;
+  template <typename Derived, typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type>
+  friend class internal::MapFieldLite;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_H__
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
new file mode 100644
index 0000000..536dec9
--- /dev/null
+++ b/src/google/protobuf/map_entry.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_H__
+
+#include <google/protobuf/port.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class Arena;
+namespace internal {
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapField;
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// MapEntry is the returned google::protobuf::Message when calling AddMessage of
+// google::protobuf::Reflection. In order to let it work with generated message
+// reflection, its in-memory type is the same as generated message with the same
+// fields. However, in order to decide the in-memory type of key/value, we need
+// to know both their cpp type in generated api and proto type. In
+// implementation, all in-memory types have related wire format functions to
+// support except ArenaStringPtr. Therefore, we need to define another type with
+// supporting wire format functions. Since this type is only used as return type
+// of MapEntry accessors, it's named MapEntry accessor type.
+//
+// cpp type:               the type visible to users in public API.
+// proto type:             WireFormatLite::FieldType of the field.
+// in-memory type:         type of the data member used to stored this field.
+// MapEntry accessor type: type used in MapEntry getters/mutators to access the
+//                         field.
+//
+// cpp type | proto type  | in-memory type | MapEntry accessor type
+// int32_t    TYPE_INT32    int32_t          int32_t
+// int32_t    TYPE_FIXED32  int32_t          int32_t
+// 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.
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntry : public MapEntryImpl<Derived, Message, Key, Value,
+                                     kKeyFieldType, kValueFieldType> {
+ public:
+  constexpr MapEntry() {}
+  explicit MapEntry(Arena* arena)
+      : MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
+                     kValueFieldType>(arena) {}
+  ~MapEntry() override {
+    Message::_internal_metadata_.template Delete<UnknownFieldSet>();
+  }
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+
+  typedef typename MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
+                                kValueFieldType>::KeyTypeHandler KeyTypeHandler;
+  typedef
+      typename MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
+                            kValueFieldType>::ValueTypeHandler ValueTypeHandler;
+  size_t SpaceUsedLong() const override {
+    size_t size = sizeof(Derived);
+    size += KeyTypeHandler::SpaceUsedInMapEntryLong(this->key_);
+    size += ValueTypeHandler::SpaceUsedInMapEntryLong(this->value_);
+    return size;
+  }
+
+ private:
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+  template <typename C, typename K, typename V,
+            WireFormatLite::FieldType k_wire_type, WireFormatLite::FieldType>
+  friend class internal::MapField;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_ENTRY_H__
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
new file mode 100644
index 0000000..6b08cd9
--- /dev/null
+++ b/src/google/protobuf/map_entry_lite.h
@@ -0,0 +1,563 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntry;
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapFieldLite;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// MoveHelper::Move is used to set *dest.  It copies *src, or moves it (in
+// the C++11 sense), or swaps it. *src is left in a sane state for
+// subsequent destruction, but shouldn't be used for anything.
+template <bool is_enum, bool is_message, bool is_stringlike, typename T>
+struct MoveHelper {  // primitives
+  static void Move(T* src, T* dest) { *dest = *src; }
+};
+
+template <bool is_message, bool is_stringlike, typename T>
+struct MoveHelper<true, is_message, is_stringlike, T> {  // enums
+  static void Move(T* src, T* dest) { *dest = *src; }
+  // T is an enum here, so allow conversions to and from int.
+  static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
+  static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
+};
+
+template <bool is_stringlike, typename T>
+struct MoveHelper<false, true, is_stringlike, T> {  // messages
+  static void Move(T* src, T* dest) { dest->Swap(src); }
+};
+
+template <typename T>
+struct MoveHelper<false, false, true, T> {  // strings and similar
+  static void Move(T* src, T* dest) {
+    *dest = std::move(*src);
+  }
+};
+
+// MapEntryImpl is used to implement parsing and serialization of map entries.
+// It uses Curious Recursive Template Pattern (CRTP) to provide the type of
+// the eventual code to the template code.
+template <typename Derived, typename Base, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntryImpl : public Base {
+ public:
+  typedef MapEntryFuncs<Key, Value, kKeyFieldType, kValueFieldType> Funcs;
+
+ protected:
+  // Provide utilities to parse/serialize key/value.  Provide utilities to
+  // manipulate internal stored type.
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+
+  // Define internal memory layout. Strings and messages are stored as
+  // pointers, while other types are stored as values.
+  typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
+  typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
+
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type
+  // which will replace Enum with int.
+  typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
+  typedef
+      typename ValueTypeHandler::MapEntryAccessorType ValueMapEntryAccessorType;
+
+  // Constants for field number.
+  static const int kKeyFieldNumber = 1;
+  static const int kValueFieldNumber = 2;
+
+  // Constants for field tag.
+  static const uint8_t kKeyTag =
+      GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType);
+  static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kValueFieldNumber, ValueTypeHandler::kWireType);
+  static const size_t kTagSize = 1;
+
+ public:
+  // Work-around for a compiler bug (see repeated_field.h).
+  typedef void MapEntryHasMergeTypeTrait;
+  typedef Derived EntryType;
+  typedef Key EntryKeyType;
+  typedef Value EntryValueType;
+  static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
+  static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
+
+  constexpr MapEntryImpl()
+      : key_(KeyTypeHandler::Constinit()),
+        value_(ValueTypeHandler::Constinit()),
+        _has_bits_{} {}
+
+  explicit MapEntryImpl(Arena* arena)
+      : Base(arena),
+        key_(KeyTypeHandler::Constinit()),
+        value_(ValueTypeHandler::Constinit()),
+        _has_bits_{} {}
+
+  ~MapEntryImpl() override {
+    if (Base::GetArenaForAllocation() != nullptr) return;
+    KeyTypeHandler::DeleteNoArena(key_);
+    ValueTypeHandler::DeleteNoArena(value_);
+  }
+
+  // accessors ======================================================
+
+  virtual inline const KeyMapEntryAccessorType& key() const {
+    return KeyTypeHandler::GetExternalReference(key_);
+  }
+  virtual inline const ValueMapEntryAccessorType& value() const {
+    return ValueTypeHandler::DefaultIfNotInitialized(value_);
+  }
+  inline KeyMapEntryAccessorType* mutable_key() {
+    set_has_key();
+    return KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
+  }
+  inline ValueMapEntryAccessorType* mutable_value() {
+    set_has_value();
+    return ValueTypeHandler::EnsureMutable(&value_,
+                                           Base::GetArenaForAllocation());
+  }
+
+  // implements MessageLite =========================================
+
+  // MapEntryImpl is for implementation only and this function isn't called
+  // anywhere. Just provide a fake implementation here for MessageLite.
+  std::string GetTypeName() const override { return ""; }
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) override {
+    MergeFromInternal(*::google::protobuf::internal::DownCast<const Derived*>(&other));
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
+    while (!ctx->Done(&ptr)) {
+      uint32_t tag;
+      ptr = ReadTag(ptr, &tag);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (tag == kKeyTag) {
+        set_has_key();
+        KeyMapEntryAccessorType* key = mutable_key();
+        ptr = KeyTypeHandler::Read(ptr, ctx, key);
+        if (!Derived::ValidateKey(key)) return nullptr;
+      } else if (tag == kValueTag) {
+        set_has_value();
+        ValueMapEntryAccessorType* value = mutable_value();
+        ptr = ValueTypeHandler::Read(ptr, ctx, value);
+        if (!Derived::ValidateValue(value)) return nullptr;
+      } else {
+        if (tag == 0 || WireFormatLite::GetTagWireType(tag) ==
+                            WireFormatLite::WIRETYPE_END_GROUP) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        ptr = UnknownFieldParse(tag, static_cast<std::string*>(nullptr), ptr,
+                                ctx);
+      }
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+    return ptr;
+  }
+
+  size_t ByteSizeLong() const override {
+    size_t size = 0;
+    size += kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key()));
+    size += kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value()));
+    return size;
+  }
+
+  ::uint8_t* _InternalSerialize(
+      ::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
+  }
+
+  // Don't override SerializeWithCachedSizesToArray.  Use MessageLite's.
+
+  int GetCachedSize() const override {
+    int size = 0;
+    size += has_key() ? static_cast<int>(kTagSize) +
+                            KeyTypeHandler::GetCachedSize(key())
+                      : 0;
+    size += has_value() ? static_cast<int>(kTagSize) +
+                              ValueTypeHandler::GetCachedSize(value())
+                        : 0;
+    return size;
+  }
+
+  bool IsInitialized() const override {
+    return ValueTypeHandler::IsInitialized(value_);
+  }
+
+  Base* New(Arena* arena) const override {
+    Derived* entry = Arena::CreateMessage<Derived>(arena);
+    return entry;
+  }
+
+ protected:
+  // We can't declare this function directly here as it would hide the other
+  // overload (const Message&).
+  void MergeFromInternal(const MapEntryImpl& from) {
+    if (from._has_bits_[0]) {
+      if (from.has_key()) {
+        KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
+        KeyTypeHandler::Merge(from.key(), &key_, Base::GetArenaForAllocation());
+        set_has_key();
+      }
+      if (from.has_value()) {
+        ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation());
+        ValueTypeHandler::Merge(from.value(), &value_,
+                                Base::GetArenaForAllocation());
+        set_has_value();
+      }
+    }
+  }
+
+ public:
+  void Clear() override {
+    KeyTypeHandler::Clear(&key_, Base::GetArenaForAllocation());
+    ValueTypeHandler::Clear(&value_, Base::GetArenaForAllocation());
+    clear_has_key();
+    clear_has_value();
+  }
+
+  // Parsing using MergePartialFromCodedStream, above, is not as
+  // efficient as it could be.  This helper class provides a speedier way.
+  template <typename MapField, typename Map>
+  class Parser {
+   public:
+    explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
+    ~Parser() {
+      if (entry_ != nullptr && entry_->GetArenaForAllocation() == nullptr)
+        delete entry_;
+    }
+
+    const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+      if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) {
+        ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_);
+        if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateKey(&key_))) {
+          return nullptr;
+        }
+        if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kValueTag)) {
+          typename Map::size_type map_size = map_->size();
+          value_ptr_ = &(*map_)[key_];
+          if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
+            using T =
+                typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type;
+            ptr = ValueTypeHandler::Read(ptr + 1, ctx,
+                                         reinterpret_cast<T>(value_ptr_));
+            if (PROTOBUF_PREDICT_FALSE(!ptr ||
+                                       !Derived::ValidateValue(value_ptr_))) {
+              map_->erase(key_);  // Failure! Undo insertion.
+              return nullptr;
+            }
+            if (PROTOBUF_PREDICT_TRUE(ctx->Done(&ptr))) return ptr;
+            if (!ptr) return nullptr;
+            NewEntry();
+            ValueMover::Move(value_ptr_, entry_->mutable_value());
+            map_->erase(key_);
+            goto move_key;
+          }
+        } else {
+          if (!ptr) return nullptr;
+        }
+        NewEntry();
+      move_key:
+        KeyMover::Move(&key_, entry_->mutable_key());
+      } else {
+        if (!ptr) return nullptr;
+        NewEntry();
+      }
+      ptr = entry_->_InternalParse(ptr, ctx);
+      if (ptr) UseKeyAndValueFromEntry();
+      return ptr;
+    }
+
+    template <typename UnknownType>
+    const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
+                                        bool (*is_valid)(int),
+                                        uint32_t field_num,
+                                        InternalMetadata* metadata) {
+      auto entry = NewEntry();
+      ptr = entry->_InternalParse(ptr, ctx);
+      if (!ptr) return nullptr;
+      if (is_valid(entry->value())) {
+        UseKeyAndValueFromEntry();
+      } else {
+        WriteLengthDelimited(field_num, entry->SerializeAsString(),
+                             metadata->mutable_unknown_fields<UnknownType>());
+      }
+      return ptr;
+    }
+
+    MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); }
+
+    const Key& key() const { return key_; }
+    const Value& value() const { return *value_ptr_; }
+
+    const Key& entry_key() const { return entry_->key(); }
+    const Value& entry_value() const { return entry_->value(); }
+
+   private:
+    void UseKeyAndValueFromEntry() {
+      // Update key_ in case we need it later (because key() is called).
+      // This is potentially inefficient, especially if the key is
+      // expensive to copy (e.g., a long string), but this is a cold
+      // path, so it's not a big deal.
+      key_ = entry_->key();
+      value_ptr_ = &(*map_)[key_];
+      ValueMover::Move(entry_->mutable_value(), value_ptr_);
+    }
+
+    // After reading a key and value successfully, and inserting that data
+    // into map_, we are not at the end of the input.  This is unusual, but
+    // allowed by the spec.
+    bool ReadBeyondKeyValuePair(io::CodedInputStream* input) PROTOBUF_COLD {
+      NewEntry();
+      ValueMover::Move(value_ptr_, entry_->mutable_value());
+      map_->erase(key_);
+      KeyMover::Move(&key_, entry_->mutable_key());
+      const bool result = entry_->MergePartialFromCodedStream(input);
+      if (result) UseKeyAndValueFromEntry();
+      return result;
+    }
+
+    typedef MoveHelper<KeyTypeHandler::kIsEnum, KeyTypeHandler::kIsMessage,
+                       KeyTypeHandler::kWireType ==
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                       Key>
+        KeyMover;
+    typedef MoveHelper<ValueTypeHandler::kIsEnum, ValueTypeHandler::kIsMessage,
+                       ValueTypeHandler::kWireType ==
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                       Value>
+        ValueMover;
+
+    MapField* const mf_;
+    Map* const map_;
+    Key key_;
+    Value* value_ptr_;
+    MapEntryImpl* entry_ = nullptr;
+  };
+
+ protected:
+  void set_has_key() { _has_bits_[0] |= 0x00000001u; }
+  bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
+  void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
+  void set_has_value() { _has_bits_[0] |= 0x00000002u; }
+  bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
+  void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
+
+ public:
+  inline Arena* GetArena() const { return Base::GetArena(); }
+
+ protected:  // Needed for constructing tables
+  KeyOnMemory key_;
+  ValueOnMemory value_;
+  uint32_t _has_bits_[1];
+
+ private:
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  template <typename C, typename K, typename V, WireFormatLite::FieldType,
+            WireFormatLite::FieldType>
+  friend class internal::MapEntry;
+  template <typename C, typename K, typename V, WireFormatLite::FieldType,
+            WireFormatLite::FieldType>
+  friend class internal::MapFieldLite;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl);
+};
+
+template <typename T, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntryLite : public MapEntryImpl<T, MessageLite, Key, Value,
+                                         kKeyFieldType, kValueFieldType> {
+ public:
+  typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
+                       kValueFieldType>
+      SuperType;
+  constexpr MapEntryLite() {}
+  explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
+  ~MapEntryLite() override {
+    MessageLite::_internal_metadata_.template Delete<std::string>();
+  }
+  void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
+};
+
+// Helpers for deterministic serialization =============================
+
+// Iterator base for MapSorterFlat and MapSorterPtr.
+template <typename storage_type>
+struct MapSorterIt {
+  storage_type* ptr;
+  MapSorterIt(storage_type* ptr) : ptr(ptr) {}
+  bool operator==(const MapSorterIt& other) const { return ptr == other.ptr; }
+  bool operator!=(const MapSorterIt& other) const { return !(*this == other); }
+  MapSorterIt& operator++() { ++ptr; return *this; }
+  MapSorterIt operator++(int) { auto other = *this; ++ptr; return other; }
+  MapSorterIt operator+(int v) { return MapSorterIt{ptr + v}; }
+};
+
+// MapSorterFlat stores keys inline with pointers to map entries, so that
+// keys can be compared without indirection. This type is used for maps with
+// keys that are not strings.
+template <typename MapT>
+class MapSorterFlat {
+ public:
+  using value_type = typename MapT::value_type;
+  using storage_type = std::pair<typename MapT::key_type, const value_type*>;
+
+  // This const_iterator dereferenes to the map entry stored in the sorting
+  // array pairs. This is the same interface as the Map::const_iterator type,
+  // and allows generated code to use the same loop body with either form:
+  //   for (const auto& entry : map) { ... }
+  //   for (const auto& entry : MapSorterFlat(map)) { ... }
+  struct const_iterator : public MapSorterIt<storage_type> {
+    using pointer = const typename MapT::value_type*;
+    using reference = const typename MapT::value_type&;
+    using MapSorterIt<storage_type>::MapSorterIt;
+
+    pointer operator->() const { return this->ptr->second; }
+    reference operator*() const { return *this->operator->(); }
+  };
+
+  explicit MapSorterFlat(const MapT& m)
+      : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
+    if (!size_) return;
+    storage_type* it = &items_[0];
+    for (const auto& entry : m) {
+      *it++ = {entry.first, &entry};
+    }
+    std::sort(&items_[0], &items_[size_],
+              [](const storage_type& a, const storage_type& b) {
+                return a.first < b.first;
+              });
+  }
+  size_t size() const { return size_; }
+  const_iterator begin() const { return {items_.get()}; }
+  const_iterator end() const { return {items_.get() + size_}; }
+
+ private:
+  size_t size_;
+  std::unique_ptr<storage_type[]> items_;
+};
+
+// MapSorterPtr stores and sorts pointers to map entries. This type is used for
+// maps with keys that are strings.
+template <typename MapT>
+class MapSorterPtr {
+ public:
+  using value_type = typename MapT::value_type;
+  using storage_type = const typename MapT::value_type*;
+
+  // This const_iterator dereferenes the map entry pointer stored in the sorting
+  // array. This is the same interface as the Map::const_iterator type, and
+  // allows generated code to use the same loop body with either form:
+  //   for (const auto& entry : map) { ... }
+  //   for (const auto& entry : MapSorterPtr(map)) { ... }
+  struct const_iterator : public MapSorterIt<storage_type> {
+    using pointer = const typename MapT::value_type*;
+    using reference = const typename MapT::value_type&;
+    using MapSorterIt<storage_type>::MapSorterIt;
+
+    pointer operator->() const { return *this->ptr; }
+    reference operator*() const { return *this->operator->(); }
+  };
+
+  explicit MapSorterPtr(const MapT& m)
+      : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
+    if (!size_) return;
+    storage_type* it = &items_[0];
+    for (const auto& entry : m) {
+      *it++ = &entry;
+    }
+    std::sort(&items_[0], &items_[size_],
+              [](const storage_type& a, const storage_type& b) {
+                return a->first < b->first;
+              });
+  }
+  size_t size() const { return size_; }
+  const_iterator begin() const { return {items_.get()}; }
+  const_iterator end() const { return {items_.get() + size_}; }
+
+ private:
+  size_t size_;
+  std::unique_ptr<storage_type[]> items_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
new file mode 100644
index 0000000..ed662df
--- /dev/null
+++ b/src/google/protobuf/map_field.cc
@@ -0,0 +1,654 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/map_field.h>
+
+#include <vector>
+
+#include <google/protobuf/map_field_inl.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void MapFieldBase::Destruct() {
+  if (arena_ == nullptr) {
+    delete repeated_field_;
+  }
+  repeated_field_ = nullptr;
+}
+
+const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
+  ConstAccess();
+  SyncRepeatedFieldWithMap();
+  return *reinterpret_cast<RepeatedPtrFieldBase*>(repeated_field_);
+}
+
+RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() {
+  MutableAccess();
+  SyncRepeatedFieldWithMap();
+  SetRepeatedDirty();
+  return reinterpret_cast<RepeatedPtrFieldBase*>(repeated_field_);
+}
+
+void MapFieldBase::SwapState(MapFieldBase* other) {
+  // a relaxed swap of the atomic
+  auto other_state = other->state_.load(std::memory_order_relaxed);
+  auto this_state = state_.load(std::memory_order_relaxed);
+  other->state_.store(this_state, std::memory_order_relaxed);
+  state_.store(other_state, std::memory_order_relaxed);
+}
+
+void SwapRepeatedPtrToNull(RepeatedPtrField<Message>** from,
+                           RepeatedPtrField<Message>** to, Arena* from_arena,
+                           Arena* to_arena) {
+  GOOGLE_DCHECK(*from != nullptr);
+  GOOGLE_DCHECK(*to == nullptr);
+  *to = Arena::CreateMessage<RepeatedPtrField<Message> >(to_arena);
+  **to = std::move(**from);
+  if (from_arena == nullptr) {
+    delete *from;
+  }
+  *from = nullptr;
+}
+
+void MapFieldBase::Swap(MapFieldBase* other) {
+  if (arena_ == other->arena_) {
+    InternalSwap(other);
+    return;
+  }
+  if (repeated_field_ != nullptr || other->repeated_field_ != nullptr) {
+    if (repeated_field_ == nullptr) {
+      SwapRepeatedPtrToNull(&other->repeated_field_, &repeated_field_,
+                            other->arena_, arena_);
+    } else if (other->repeated_field_ == nullptr) {
+      SwapRepeatedPtrToNull(&repeated_field_, &other->repeated_field_, arena_,
+                            other->arena_);
+    } else {
+      repeated_field_->Swap(other->repeated_field_);
+    }
+  }
+  SwapState(other);
+}
+
+void MapFieldBase::UnsafeShallowSwap(MapFieldBase* other) {
+  GOOGLE_DCHECK_EQ(arena_, other->arena_);
+  InternalSwap(other);
+}
+
+void MapFieldBase::InternalSwap(MapFieldBase* other) {
+  std::swap(arena_, other->arena_);
+  std::swap(repeated_field_, other->repeated_field_);
+  SwapState(other);
+}
+
+size_t MapFieldBase::SpaceUsedExcludingSelfLong() const {
+  ConstAccess();
+  mutex_.Lock();
+  size_t size = SpaceUsedExcludingSelfNoLock();
+  mutex_.Unlock();
+  ConstAccess();
+  return size;
+}
+
+size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
+  if (repeated_field_ != nullptr) {
+    return repeated_field_->SpaceUsedExcludingSelfLong();
+  } else {
+    return 0;
+  }
+}
+
+bool MapFieldBase::IsMapValid() const {
+  ConstAccess();
+  // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
+  // executed before state_ is checked.
+  int state = state_.load(std::memory_order_acquire);
+  return state != STATE_MODIFIED_REPEATED;
+}
+
+bool MapFieldBase::IsRepeatedFieldValid() const {
+  ConstAccess();
+  int state = state_.load(std::memory_order_acquire);
+  return state != STATE_MODIFIED_MAP;
+}
+
+void MapFieldBase::SetMapDirty() {
+  MutableAccess();
+  // These are called by (non-const) mutator functions. So by our API it's the
+  // callers responsibility to have these calls properly ordered.
+  state_.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
+}
+
+void MapFieldBase::SetRepeatedDirty() {
+  MutableAccess();
+  // These are called by (non-const) mutator functions. So by our API it's the
+  // callers responsibility to have these calls properly ordered.
+  state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
+}
+
+void MapFieldBase::SyncRepeatedFieldWithMap() const {
+  ConstAccess();
+  // acquire here matches with release below to ensure that we can only see a
+  // value of CLEAN after all previous changes have been synced.
+  switch (state_.load(std::memory_order_acquire)) {
+    case 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_.load(std::memory_order_relaxed) == STATE_MODIFIED_MAP) {
+        SyncRepeatedFieldWithMapNoLock();
+        state_.store(CLEAN, std::memory_order_release);
+      }
+      mutex_.Unlock();
+      ConstAccess();
+      break;
+    case CLEAN:
+      mutex_.Lock();
+      // Double check state
+      if (state_.load(std::memory_order_relaxed) == CLEAN) {
+        if (repeated_field_ == nullptr) {
+          repeated_field_ =
+              Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
+        }
+        state_.store(CLEAN, std::memory_order_release);
+      }
+      mutex_.Unlock();
+      ConstAccess();
+      break;
+    default:
+      break;
+  }
+}
+
+void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
+  if (repeated_field_ == nullptr) {
+    repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
+  }
+}
+
+void MapFieldBase::SyncMapWithRepeatedField() const {
+  ConstAccess();
+  // acquire here matches with release below to ensure that we can only see a
+  // value of CLEAN after all previous changes have been synced.
+  if (state_.load(std::memory_order_acquire) == 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_.load(std::memory_order_relaxed) == STATE_MODIFIED_REPEATED) {
+      SyncMapWithRepeatedFieldNoLock();
+      state_.store(CLEAN, std::memory_order_release);
+    }
+    mutex_.Unlock();
+    ConstAccess();
+  }
+}
+
+// ------------------DynamicMapField------------------
+DynamicMapField::DynamicMapField(const Message* default_entry)
+    : default_entry_(default_entry) {}
+
+DynamicMapField::DynamicMapField(const Message* default_entry, Arena* arena)
+    : TypeDefinedMapFieldBase<MapKey, MapValueRef>(arena),
+      map_(arena),
+      default_entry_(default_entry) {}
+
+DynamicMapField::~DynamicMapField() {
+  if (arena_ == nullptr) {
+    // DynamicMapField owns map values. Need to delete them before clearing the
+    // map.
+    for (auto& kv : map_) {
+      kv.second.DeleteData();
+    }
+    map_.clear();
+  }
+  Destruct();
+}
+
+int DynamicMapField::size() const { return GetMap().size(); }
+
+void DynamicMapField::Clear() {
+  Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
+  if (MapFieldBase::arena_ == nullptr) {
+    for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
+         iter != map->end(); ++iter) {
+      iter->second.DeleteData();
+    }
+  }
+
+  map->clear();
+
+  if (MapFieldBase::repeated_field_ != nullptr) {
+    MapFieldBase::repeated_field_->Clear();
+  }
+  // Data in map and repeated field are both empty, but we can't set status
+  // CLEAN which will invalidate previous reference to map.
+  MapFieldBase::SetMapDirty();
+}
+
+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();
+}
+
+void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
+  const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
+  map_val->SetType(val_des->cpp_type());
+  // Allocate memory for the MapValueRef, and initialize to
+  // default value.
+  switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                 \
+    TYPE* value = Arena::Create<TYPE>(MapFieldBase::arena_); \
+    map_val->SetValue(value);                                \
+    break;                                                   \
+  }
+    HANDLE_TYPE(INT32, int32_t);
+    HANDLE_TYPE(INT64, int64_t);
+    HANDLE_TYPE(UINT32, uint32_t);
+    HANDLE_TYPE(UINT64, uint64_t);
+    HANDLE_TYPE(DOUBLE, double);
+    HANDLE_TYPE(FLOAT, float);
+    HANDLE_TYPE(BOOL, bool);
+    HANDLE_TYPE(STRING, std::string);
+    HANDLE_TYPE(ENUM, int32_t);
+#undef HANDLE_TYPE
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      const Message& message =
+          default_entry_->GetReflection()->GetMessage(*default_entry_, val_des);
+      Message* value = message.New(MapFieldBase::arena_);
+      map_val->SetValue(value);
+      break;
+    }
+  }
+}
+
+bool DynamicMapField::InsertOrLookupMapValue(const MapKey& map_key,
+                                             MapValueRef* val) {
+  // Always use mutable map because users may change the map value by
+  // MapValueRef.
+  Map<MapKey, MapValueRef>* map = MutableMap();
+  Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
+  if (iter == map->end()) {
+    MapValueRef& map_val = map_[map_key];
+    AllocateMapValue(&map_val);
+    val->CopyFrom(map_val);
+    return true;
+  }
+  // map_key is already in the map. Make sure (*map)[map_key] is not called.
+  // [] may reorder the map and iterators.
+  val->CopyFrom(iter->second);
+  return false;
+}
+
+bool DynamicMapField::LookupMapValue(const MapKey& map_key,
+                                     MapValueConstRef* val) const {
+  const Map<MapKey, MapValueRef>& map = GetMap();
+  Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key);
+  if (iter == map.end()) {
+    return false;
+  }
+  // map_key is already in the map. Make sure (*map)[map_key] is not called.
+  // [] may reorder the map and iterators.
+  val->CopyFrom(iter->second);
+  return true;
+}
+
+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();
+  if (MapFieldBase::arena_ == nullptr) {
+    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::MergeFrom(const MapFieldBase& other) {
+  GOOGLE_DCHECK(IsMapValid() && other.IsMapValid());
+  Map<MapKey, MapValueRef>* map = MutableMap();
+  const DynamicMapField& other_field =
+      reinterpret_cast<const DynamicMapField&>(other);
+  for (Map<MapKey, MapValueRef>::const_iterator other_it =
+           other_field.map_.begin();
+       other_it != other_field.map_.end(); ++other_it) {
+    Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first);
+    MapValueRef* map_val;
+    if (iter == map->end()) {
+      map_val = &map_[other_it->first];
+      AllocateMapValue(map_val);
+    } else {
+      map_val = &iter->second;
+    }
+
+    // Copy map value
+    const FieldDescriptor* field_descriptor =
+        default_entry_->GetDescriptor()->map_value();
+    switch (field_descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32: {
+        map_val->SetInt32Value(other_it->second.GetInt32Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+        map_val->SetInt64Value(other_it->second.GetInt64Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        map_val->SetUInt32Value(other_it->second.GetUInt32Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        map_val->SetUInt64Value(other_it->second.GetUInt64Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_FLOAT: {
+        map_val->SetFloatValue(other_it->second.GetFloatValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_DOUBLE: {
+        map_val->SetDoubleValue(other_it->second.GetDoubleValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_BOOL: {
+        map_val->SetBoolValue(other_it->second.GetBoolValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+        map_val->SetStringValue(other_it->second.GetStringValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        map_val->SetEnumValue(other_it->second.GetEnumValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        map_val->MutableMessageValue()->CopyFrom(
+            other_it->second.GetMessageValue());
+        break;
+      }
+    }
+  }
+}
+
+void DynamicMapField::Swap(MapFieldBase* other) {
+  DynamicMapField* other_field = down_cast<DynamicMapField*>(other);
+  std::swap(this->MapFieldBase::repeated_field_, other_field->repeated_field_);
+  map_.swap(other_field->map_);
+  // a relaxed swap of the atomic
+  auto other_state = other_field->state_.load(std::memory_order_relaxed);
+  auto this_state = this->MapFieldBase::state_.load(std::memory_order_relaxed);
+  other_field->state_.store(this_state, std::memory_order_relaxed);
+  this->MapFieldBase::state_.store(other_state, std::memory_order_relaxed);
+}
+
+void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const {
+  const Reflection* reflection = default_entry_->GetReflection();
+  const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
+  const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
+  if (MapFieldBase::repeated_field_ == nullptr) {
+    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::arena_);
+    MapFieldBase::repeated_field_->AddAllocated(new_entry);
+    const MapKey& map_key = it->first;
+    switch (key_des->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        reflection->SetString(new_entry, key_des, map_key.GetStringValue());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        reflection->SetBool(new_entry, key_des, map_key.GetBoolValue());
+        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;
+    }
+    const MapValueRef& map_val = it->second;
+    switch (val_des->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        reflection->SetString(new_entry, val_des, map_val.GetStringValue());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        reflection->SetBool(new_entry, val_des, map_val.GetBoolValue());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue());
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue());
+        break;
+      case 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()->map_key();
+  const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
+  // DynamicMapField owns map values. Need to delete them before clearing
+  // the map.
+  if (MapFieldBase::arena_ == nullptr) {
+    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 type will be set later.
+    MapKey map_key;
+    switch (key_des->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        map_key.SetStringValue(reflection->GetString(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        map_key.SetInt64Value(reflection->GetInt64(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        map_key.SetInt32Value(reflection->GetInt32(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        map_key.SetUInt64Value(reflection->GetUInt64(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        map_key.SetUInt32Value(reflection->GetUInt32(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        map_key.SetBoolValue(reflection->GetBool(*it, key_des));
+        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;
+    }
+
+    if (MapFieldBase::arena_ == nullptr) {
+      // Remove existing map value with same key.
+      Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
+      if (iter != map->end()) {
+        iter->second.DeleteData();
+      }
+    }
+
+    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 FieldDescriptor::CPPTYPE_##CPPTYPE: {                 \
+    TYPE* value = Arena::Create<TYPE>(MapFieldBase::arena_); \
+    *value = reflection->Get##METHOD(*it, val_des);          \
+    map_val.SetValue(value);                                 \
+    break;                                                   \
+  }
+      HANDLE_TYPE(INT32, int32_t, Int32);
+      HANDLE_TYPE(INT64, int64_t, Int64);
+      HANDLE_TYPE(UINT32, uint32_t, UInt32);
+      HANDLE_TYPE(UINT64, uint64_t, UInt64);
+      HANDLE_TYPE(DOUBLE, double, Double);
+      HANDLE_TYPE(FLOAT, float, Float);
+      HANDLE_TYPE(BOOL, bool, Bool);
+      HANDLE_TYPE(STRING, std::string, String);
+      HANDLE_TYPE(ENUM, int32_t, EnumValue);
+#undef HANDLE_TYPE
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        const Message& message = reflection->GetMessage(*it, val_des);
+        Message* value = message.New(MapFieldBase::arena_);
+        value->CopyFrom(message);
+        map_val.SetValue(value);
+        break;
+      }
+    }
+  }
+}
+
+size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
+  size_t size = 0;
+  if (MapFieldBase::repeated_field_ != nullptr) {
+    size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelfLong();
+  }
+  size += sizeof(map_);
+  size_t 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() == FieldDescriptor::CPPTYPE_STRING) {
+      size += sizeof(std::string) * map_size;
+    }
+    // Add the allocated space in MapValueRef.
+    switch (it->second.type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
+    size += sizeof(TYPE) * map_size;         \
+    break;                                   \
+  }
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, std::string);
+      HANDLE_TYPE(ENUM, int32_t);
+#undef HANDLE_TYPE
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        while (it != map_.end()) {
+          const Message& message = it->second.GetMessageValue();
+          size += message.GetReflection()->SpaceUsedLong(message);
+          ++it;
+        }
+        break;
+      }
+    }
+  }
+  return size;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
new file mode 100644
index 0000000..287d58f
--- /dev/null
+++ b/src/google/protobuf/map_field.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_H__
+
+#include <atomic>
+#include <functional>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_entry.h>
+#include <google/protobuf/map_field_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class DynamicMessage;
+class MapIterator;
+
+// Microsoft compiler complains about non-virtual destructor,
+// even when the destructor is private.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4265)
+#endif  // _MSC_VER
+
+#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 PROTOBUF_EXPORT MapKey {
+ public:
+  MapKey() : type_() {}
+  MapKey(const MapKey& other) : type_() { CopyFrom(other); }
+
+  MapKey& operator=(const MapKey& other) {
+    CopyFrom(other);
+    return *this;
+  }
+
+  ~MapKey() {
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_.Destruct();
+    }
+  }
+
+  FieldDescriptor::CppType type() const {
+    if (type_ == FieldDescriptor::CppType()) {
+      GOOGLE_LOG(FATAL) << "Protocol Buffer map usage error:\n"
+                 << "MapKey::type MapKey is not initialized. "
+                 << "Call set methods to initialize MapKey.";
+    }
+    return type_;
+  }
+
+  void SetInt64Value(int64_t value) {
+    SetType(FieldDescriptor::CPPTYPE_INT64);
+    val_.int64_value_ = value;
+  }
+  void SetUInt64Value(uint64_t value) {
+    SetType(FieldDescriptor::CPPTYPE_UINT64);
+    val_.uint64_value_ = value;
+  }
+  void SetInt32Value(int32_t value) {
+    SetType(FieldDescriptor::CPPTYPE_INT32);
+    val_.int32_value_ = value;
+  }
+  void SetUInt32Value(uint32_t value) {
+    SetType(FieldDescriptor::CPPTYPE_UINT32);
+    val_.uint32_value_ = value;
+  }
+  void SetBoolValue(bool value) {
+    SetType(FieldDescriptor::CPPTYPE_BOOL);
+    val_.bool_value_ = value;
+  }
+  void SetStringValue(std::string val) {
+    SetType(FieldDescriptor::CPPTYPE_STRING);
+    *val_.string_value_.get_mutable() = std::move(val);
+  }
+
+  int64_t GetInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapKey::GetInt64Value");
+    return val_.int64_value_;
+  }
+  uint64_t GetUInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapKey::GetUInt64Value");
+    return val_.uint64_value_;
+  }
+  int32_t GetInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapKey::GetInt32Value");
+    return val_.int32_value_;
+  }
+  uint32_t 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 std::string& GetStringValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, "MapKey::GetStringValue");
+    return val_.string_value_.get();
+  }
+
+  bool operator<(const MapKey& other) const {
+    if (type_ != other.type_) {
+      // We could define a total order that handles this case, but
+      // there currently no need.  So, for now, fail.
+      GOOGLE_LOG(FATAL) << "Unsupported: type mismatch";
+    }
+    switch (type()) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        return false;
+      case FieldDescriptor::CPPTYPE_STRING:
+        return val_.string_value_.get() < other.val_.string_value_.get();
+      case FieldDescriptor::CPPTYPE_INT64:
+        return val_.int64_value_ < other.val_.int64_value_;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return val_.int32_value_ < other.val_.int32_value_;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return val_.uint64_value_ < other.val_.uint64_value_;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return val_.uint32_value_ < other.val_.uint32_value_;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return val_.bool_value_ < other.val_.bool_value_;
+    }
+    return false;
+  }
+
+  bool operator==(const MapKey& other) const {
+    if (type_ != other.type_) {
+      // To be consistent with operator<, we don't allow this either.
+      GOOGLE_LOG(FATAL) << "Unsupported: type mismatch";
+    }
+    switch (type()) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        return val_.string_value_.get() == other.val_.string_value_.get();
+      case FieldDescriptor::CPPTYPE_INT64:
+        return val_.int64_value_ == other.val_.int64_value_;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return val_.int32_value_ == other.val_.int32_value_;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return val_.uint64_value_ == other.val_.uint64_value_;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return val_.uint32_value_ == other.val_.uint32_value_;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return val_.bool_value_ == other.val_.bool_value_;
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return false;
+  }
+
+  void CopyFrom(const MapKey& other) {
+    SetType(other.type());
+    switch (type_) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        *val_.string_value_.get_mutable() = other.val_.string_value_.get();
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        val_.int64_value_ = other.val_.int64_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        val_.int32_value_ = other.val_.int32_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        val_.uint64_value_ = other.val_.uint64_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        val_.uint32_value_ = other.val_.uint32_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        val_.bool_value_ = other.val_.bool_value_;
+        break;
+    }
+  }
+
+ private:
+  template <typename K, typename V>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class ::PROTOBUF_NAMESPACE_ID::MapIterator;
+  friend class internal::DynamicMapField;
+
+  union KeyValue {
+    KeyValue() {}
+    internal::ExplicitlyConstructed<std::string> string_value_;
+    int64_t int64_value_;
+    int32_t int32_value_;
+    uint64_t uint64_value_;
+    uint32_t uint32_value_;
+    bool bool_value_;
+  } val_;
+
+  void SetType(FieldDescriptor::CppType type) {
+    if (type_ == type) return;
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_.Destruct();
+    }
+    type_ = type;
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_.DefaultConstruct();
+    }
+  }
+
+  // type_ is 0 or a valid FieldDescriptor::CppType.
+  // Use "CppType()" to indicate zero.
+  FieldDescriptor::CppType type_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+namespace std {
+template <>
+struct hash<::PROTOBUF_NAMESPACE_ID::MapKey> {
+  size_t operator()(const ::PROTOBUF_NAMESPACE_ID::MapKey& map_key) const {
+    switch (map_key.type()) {
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_DOUBLE:
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_FLOAT:
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_ENUM:
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_STRING:
+        return hash<std::string>()(map_key.GetStringValue());
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_INT64: {
+        auto value = map_key.GetInt64Value();
+        return hash<decltype(value)>()(value);
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_INT32: {
+        auto value = map_key.GetInt32Value();
+        return hash<decltype(value)>()(map_key.GetInt32Value());
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_UINT64: {
+        auto value = map_key.GetUInt64Value();
+        return hash<decltype(value)>()(map_key.GetUInt64Value());
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_UINT32: {
+        auto value = map_key.GetUInt32Value();
+        return hash<decltype(value)>()(map_key.GetUInt32Value());
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_BOOL: {
+        return hash<bool>()(map_key.GetBoolValue());
+      }
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
+  }
+  bool operator()(const ::PROTOBUF_NAMESPACE_ID::MapKey& map_key1,
+                  const ::PROTOBUF_NAMESPACE_ID::MapKey& map_key2) const {
+    return map_key1 < map_key2;
+  }
+};
+}  // namespace std
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class ContendedMapCleanTest;
+class GeneratedMessageReflection;
+class MapFieldAccessor;
+
+// This class provides access to map field using reflection, which is the same
+// as those provided for RepeatedPtrField<Message>. It is used for internal
+// reflection implementation only. Users should never use this directly.
+class PROTOBUF_EXPORT MapFieldBase {
+ public:
+  MapFieldBase()
+      : arena_(nullptr), repeated_field_(nullptr), state_(STATE_MODIFIED_MAP) {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // Except in MSVC, where we can't have a constinit mutex.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr MapFieldBase(ConstantInitialized)
+      : arena_(nullptr),
+        repeated_field_(nullptr),
+        mutex_(GOOGLE_PROTOBUF_LINKER_INITIALIZED),
+        state_(STATE_MODIFIED_MAP) {}
+  explicit MapFieldBase(Arena* arena)
+      : arena_(arena), repeated_field_(nullptr), state_(STATE_MODIFIED_MAP) {}
+
+ protected:
+  ~MapFieldBase() {  // "protected" stops users from deleting a `MapFieldBase *`
+    GOOGLE_DCHECK(repeated_field_ == nullptr);
+  }
+  void Destruct();
+
+ public:
+  // Returns reference to internal repeated field. Data written using
+  // Map's api prior to calling this function is guarantted to be
+  // included in repeated field.
+  const RepeatedPtrFieldBase& GetRepeatedField() const;
+
+  // Like above. Returns mutable pointer to the internal repeated field.
+  RepeatedPtrFieldBase* MutableRepeatedField();
+
+  // Pure virtual map APIs for Map Reflection.
+  virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
+  virtual bool InsertOrLookupMapValue(const MapKey& map_key,
+                                      MapValueRef* val) = 0;
+  virtual bool LookupMapValue(const MapKey& map_key,
+                              MapValueConstRef* val) const = 0;
+  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
+
+  // Returns whether changes to the map are reflected in the repeated field.
+  bool IsRepeatedFieldValid() const;
+  // Insures operations after won't get executed before calling this.
+  bool IsMapValid() const;
+  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;
+  virtual void MergeFrom(const MapFieldBase& other) = 0;
+  virtual void Swap(MapFieldBase* other);
+  virtual void UnsafeShallowSwap(MapFieldBase* other);
+  // Sync Map with repeated field and returns the size of map.
+  virtual int size() const = 0;
+  virtual void Clear() = 0;
+
+  // Returns the number of bytes used by the repeated field, excluding
+  // sizeof(*this)
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+ protected:
+  // Gets the size of space used by map field.
+  virtual size_t SpaceUsedExcludingSelfNoLock() const;
+
+  // Synchronizes the content in Map to RepeatedPtrField if there is any change
+  // to Map after last synchronization.
+  void SyncRepeatedFieldWithMap() const;
+  virtual void SyncRepeatedFieldWithMapNoLock() const;
+
+  // Synchronizes the content in RepeatedPtrField to Map if there is any change
+  // to RepeatedPtrField after last synchronization.
+  void SyncMapWithRepeatedField() const;
+  virtual void SyncMapWithRepeatedFieldNoLock() const {}
+
+  // Tells MapFieldBase that there is new change to Map.
+  void SetMapDirty();
+
+  // Tells MapFieldBase that there is new change to RepeatedPtrField.
+  void SetRepeatedDirty();
+
+  // Provides derived class the access to repeated field.
+  void* MutableRepeatedPtrField() const;
+
+  void InternalSwap(MapFieldBase* other);
+
+  // Support thread sanitizer (tsan) by making const / mutable races
+  // more apparent.  If one thread calls MutableAccess() while another
+  // thread calls either ConstAccess() or MutableAccess(), on the same
+  // MapFieldBase-derived object, and there is no synchronization going
+  // on between them, tsan will alert.
+#if defined(__SANITIZE_THREAD__) || defined(THREAD_SANITIZER)
+  void ConstAccess() const { GOOGLE_CHECK_EQ(seq1_, seq2_); }
+  void MutableAccess() {
+    if (seq1_ & 1) {
+      seq2_ = ++seq1_;
+    } else {
+      seq1_ = ++seq2_;
+    }
+  }
+  unsigned int seq1_ = 0, seq2_ = 0;
+#else
+  void ConstAccess() const {}
+  void MutableAccess() {}
+#endif
+  enum State {
+    STATE_MODIFIED_MAP = 0,       // map has newly added data that has not been
+                                  // synchronized to repeated field
+    STATE_MODIFIED_REPEATED = 1,  // repeated field has newly added data that
+                                  // has not been synchronized to map
+    CLEAN = 2,                    // data in map and repeated field are same
+  };
+
+  Arena* arena_;
+  mutable RepeatedPtrField<Message>* repeated_field_;
+
+  mutable internal::WrappedMutex
+      mutex_;  // The thread to synchronize map and repeated field
+               // needs to get lock first;
+  mutable std::atomic<State> state_;
+
+ private:
+  friend class ContendedMapCleanTest;
+  friend class GeneratedMessageReflection;
+  friend class MapFieldAccessor;
+  friend class ::PROTOBUF_NAMESPACE_ID::Reflection;
+  friend class ::PROTOBUF_NAMESPACE_ID::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 ::PROTOBUF_NAMESPACE_ID::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;
+
+  // Swaps state_ with another MapFieldBase
+  void SwapState(MapFieldBase* other);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldBase);
+};
+
+// This class provides common Map Reflection implementations for generated
+// message and dynamic message.
+template <typename Key, typename T>
+class TypeDefinedMapFieldBase : public MapFieldBase {
+ public:
+  TypeDefinedMapFieldBase() {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr TypeDefinedMapFieldBase(ConstantInitialized tag)
+      : MapFieldBase(tag) {}
+  explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {}
+  TypeDefinedMapFieldBase(ArenaInitialized, Arena* arena)
+      : TypeDefinedMapFieldBase(arena) {}
+
+ protected:
+  ~TypeDefinedMapFieldBase() {}
+  using MapFieldBase::Destruct;
+
+ public:
+  void MapBegin(MapIterator* map_iter) const override;
+  void MapEnd(MapIterator* map_iter) const override;
+  bool EqualIterator(const MapIterator& a, const MapIterator& b) const override;
+
+  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 override;
+  void DeleteIterator(MapIterator* map_iter) const override;
+  void CopyIterator(MapIterator* this_iteratorm,
+                    const MapIterator& that_iterator) const override;
+  void IncreaseIterator(MapIterator* map_iter) const override;
+
+  virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeDefinedMapFieldBase);
+};
+
+// This class provides access to map field using generated api. It is used for
+// internal generated message implementation only. Users should never use this
+// directly.
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapField : public TypeDefinedMapFieldBase<Key, T> {
+  // 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 Derived EntryType;
+
+  // Define abbreviation for parent MapFieldLite
+  typedef MapFieldLite<Derived, Key, T, kKeyFieldType, kValueFieldType>
+      MapFieldLiteType;
+
+  // Enum needs to be handled differently from other types because it has
+  // different exposed type in Map's api and repeated field's api. For
+  // details see the comment in the implementation of
+  // SyncMapWithRepeatedFieldNoLock.
+  static constexpr bool kIsValueEnum = ValueTypeHandler::kIsEnum;
+  typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
+
+ public:
+  typedef Map<Key, T> MapType;
+
+  MapField() : impl_() {}
+  virtual ~MapField() {}  // Destruct() must already have been called!
+  void Destruct() {
+    impl_.Destruct();
+    TypeDefinedMapFieldBase<Key, T>::Destruct();
+  }
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr MapField(ConstantInitialized tag)
+      : TypeDefinedMapFieldBase<Key, T>(tag), impl_() {}
+  explicit MapField(Arena* arena)
+      : TypeDefinedMapFieldBase<Key, T>(arena), impl_(arena) {}
+  MapField(ArenaInitialized, Arena* arena) : MapField(arena) {}
+
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const override;
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
+  bool LookupMapValue(const MapKey& map_key,
+                      MapValueConstRef* val) const override;
+  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
+  bool DeleteMapValue(const MapKey& map_key) override;
+
+  const Map<Key, T>& GetMap() const override {
+    MapFieldBase::SyncMapWithRepeatedField();
+    return impl_.GetMap();
+  }
+
+  Map<Key, T>* MutableMap() override {
+    MapFieldBase::SyncMapWithRepeatedField();
+    Map<Key, T>* result = impl_.MutableMap();
+    MapFieldBase::SetMapDirty();
+    return result;
+  }
+
+  int size() const override;
+  void Clear() override;
+  void MergeFrom(const MapFieldBase& other) override;
+  void Swap(MapFieldBase* other) override;
+  void UnsafeShallowSwap(MapFieldBase* other) override;
+  void InternalSwap(MapField* other);
+
+  // Used in the implementation of parsing. Caller should take the ownership iff
+  // arena_ is nullptr.
+  EntryType* NewEntry() const { return impl_.NewEntry(); }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return impl_._InternalParse(ptr, ctx);
+  }
+  template <typename UnknownType>
+  const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
+                                      bool (*is_valid)(int), uint32_t field_num,
+                                      InternalMetadata* metadata) {
+    return impl_.template ParseWithEnumValidation<UnknownType>(
+        ptr, ctx, is_valid, field_num, metadata);
+  }
+
+ private:
+  MapFieldLiteType impl_;
+
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+
+  // Implements MapFieldBase
+  void SyncRepeatedFieldWithMapNoLock() const override;
+  void SyncMapWithRepeatedFieldNoLock() const override;
+  size_t SpaceUsedExcludingSelfNoLock() const override;
+
+  void SetMapIteratorValue(MapIterator* map_iter) const override;
+
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+  friend class MapFieldStateTest;  // For testing, it needs raw access to impl_
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapField);
+};
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+bool AllAreInitialized(
+    const MapField<Derived, Key, T, key_wire_type, value_wire_type>& field) {
+  const auto& t = field.GetMap();
+  for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
+       ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+template <typename T, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryToMapField<
+    MapEntry<T, Key, Value, kKeyFieldType, kValueFieldType>> {
+  typedef MapField<T, Key, Value, kKeyFieldType, kValueFieldType> MapFieldType;
+};
+
+class PROTOBUF_EXPORT DynamicMapField
+    : public TypeDefinedMapFieldBase<MapKey, MapValueRef> {
+ public:
+  explicit DynamicMapField(const Message* default_entry);
+  DynamicMapField(const Message* default_entry, Arena* arena);
+  virtual ~DynamicMapField();
+
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const override;
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
+  bool LookupMapValue(const MapKey& map_key,
+                      MapValueConstRef* val) const override;
+  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
+  bool DeleteMapValue(const MapKey& map_key) override;
+  void MergeFrom(const MapFieldBase& other) override;
+  void Swap(MapFieldBase* other) override;
+  void UnsafeShallowSwap(MapFieldBase* other) override { Swap(other); }
+
+  const Map<MapKey, MapValueRef>& GetMap() const override;
+  Map<MapKey, MapValueRef>* MutableMap() override;
+
+  int size() const override;
+  void Clear() override;
+
+ private:
+  Map<MapKey, MapValueRef> map_;
+  const Message* default_entry_;
+
+  void AllocateMapValue(MapValueRef* map_val);
+
+  // Implements MapFieldBase
+  void SyncRepeatedFieldWithMapNoLock() const override;
+  void SyncMapWithRepeatedFieldNoLock() const override;
+  size_t SpaceUsedExcludingSelfNoLock() const override;
+  void SetMapIteratorValue(MapIterator* map_iter) const override;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMapField);
+};
+
+}  // namespace internal
+
+// MapValueConstRef points to a map value. Users can NOT modify
+// the map value.
+class PROTOBUF_EXPORT MapValueConstRef {
+ public:
+  MapValueConstRef() : data_(nullptr), type_() {}
+
+  int64_t GetInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64,
+               "MapValueConstRef::GetInt64Value");
+    return *reinterpret_cast<int64_t*>(data_);
+  }
+  uint64_t GetUInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64,
+               "MapValueConstRef::GetUInt64Value");
+    return *reinterpret_cast<uint64_t*>(data_);
+  }
+  int32_t GetInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32,
+               "MapValueConstRef::GetInt32Value");
+    return *reinterpret_cast<int32_t*>(data_);
+  }
+  uint32_t GetUInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
+               "MapValueConstRef::GetUInt32Value");
+    return *reinterpret_cast<uint32_t*>(data_);
+  }
+  bool GetBoolValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueConstRef::GetBoolValue");
+    return *reinterpret_cast<bool*>(data_);
+  }
+  int GetEnumValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, "MapValueConstRef::GetEnumValue");
+    return *reinterpret_cast<int*>(data_);
+  }
+  const std::string& GetStringValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING,
+               "MapValueConstRef::GetStringValue");
+    return *reinterpret_cast<std::string*>(data_);
+  }
+  float GetFloatValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT,
+               "MapValueConstRef::GetFloatValue");
+    return *reinterpret_cast<float*>(data_);
+  }
+  double GetDoubleValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE,
+               "MapValueConstRef::GetDoubleValue");
+    return *reinterpret_cast<double*>(data_);
+  }
+
+  const Message& GetMessageValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE,
+               "MapValueConstRef::GetMessageValue");
+    return *reinterpret_cast<Message*>(data_);
+  }
+
+ protected:
+  // data_ point to a map value. MapValueConstRef does not
+  // own this value.
+  void* data_;
+  // type_ is 0 or a valid FieldDescriptor::CppType.
+  // Use "CppType()" to indicate zero.
+  FieldDescriptor::CppType type_;
+
+  FieldDescriptor::CppType type() const {
+    if (type_ == FieldDescriptor::CppType() || data_ == nullptr) {
+      GOOGLE_LOG(FATAL)
+          << "Protocol Buffer map usage error:\n"
+          << "MapValueConstRef::type MapValueConstRef is not initialized.";
+    }
+    return type_;
+  }
+
+ private:
+  template <typename Derived, typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type>
+  friend class internal::MapField;
+  template <typename K, typename V>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class ::PROTOBUF_NAMESPACE_ID::MapIterator;
+  friend class Reflection;
+  friend class internal::DynamicMapField;
+
+  void SetType(FieldDescriptor::CppType type) { type_ = type; }
+  void SetValue(const void* val) { data_ = const_cast<void*>(val); }
+  void CopyFrom(const MapValueConstRef& other) {
+    type_ = other.type_;
+    data_ = other.data_;
+  }
+};
+
+// MapValueRef points to a map value. Users are able to modify
+// the map value.
+class PROTOBUF_EXPORT MapValueRef final : public MapValueConstRef {
+ public:
+  MapValueRef() {}
+
+  void SetInt64Value(int64_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapValueRef::SetInt64Value");
+    *reinterpret_cast<int64_t*>(data_) = value;
+  }
+  void SetUInt64Value(uint64_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapValueRef::SetUInt64Value");
+    *reinterpret_cast<uint64_t*>(data_) = value;
+  }
+  void SetInt32Value(int32_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapValueRef::SetInt32Value");
+    *reinterpret_cast<int32_t*>(data_) = value;
+  }
+  void SetUInt32Value(uint32_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapValueRef::SetUInt32Value");
+    *reinterpret_cast<uint32_t*>(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 std::string& value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, "MapValueRef::SetStringValue");
+    *reinterpret_cast<std::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;
+  }
+
+  Message* MutableMessageValue() {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE,
+               "MapValueRef::MutableMessageValue");
+    return reinterpret_cast<Message*>(data_);
+  }
+
+ private:
+  friend class internal::DynamicMapField;
+
+  // Only used in DynamicMapField
+  void DeleteData() {
+    switch (type_) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
+    delete reinterpret_cast<TYPE*>(data_);   \
+    break;                                   \
+  }
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, std::string);
+      HANDLE_TYPE(ENUM, int32_t);
+      HANDLE_TYPE(MESSAGE, Message);
+#undef HANDLE_TYPE
+    }
+  }
+};
+
+#undef TYPE_CHECK
+
+class PROTOBUF_EXPORT MapIterator {
+ public:
+  MapIterator(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    map_ = reflection->MutableMapData(message, field);
+    key_.SetType(field->message_type()->map_key()->cpp_type());
+    value_.SetType(field->message_type()->map_value()->cpp_type());
+    map_->InitializeIterator(this);
+  }
+  MapIterator(const MapIterator& other) {
+    map_ = other.map_;
+    map_->InitializeIterator(this);
+    map_->CopyIterator(this, other);
+  }
+  ~MapIterator() { map_->DeleteIterator(this); }
+  MapIterator& operator=(const MapIterator& other) {
+    map_ = other.map_;
+    map_->CopyIterator(this, other);
+    return *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 Derived, typename Key, typename T,
+            internal::WireFormatLite::FieldType kKeyFieldType,
+            internal::WireFormatLite::FieldType kValueFieldType>
+  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
+
+#ifdef _MSC_VER
+#pragma warning(pop)  // restore warning C4265
+#endif                // _MSC_VER
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_H__
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
new file mode 100644
index 0000000..7c4c232
--- /dev/null
+++ b/src/google/protobuf/map_field_inl.h
@@ -0,0 +1,375 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+
+#include <memory>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_type_handler.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// UnwrapMapKey template
+template <typename T>
+T UnwrapMapKey(const MapKey& map_key);
+template <>
+inline int32_t UnwrapMapKey<int32_t>(const MapKey& map_key) {
+  return map_key.GetInt32Value();
+}
+template <>
+inline uint32_t UnwrapMapKey<uint32_t>(const MapKey& map_key) {
+  return map_key.GetUInt32Value();
+}
+template <>
+inline int64_t UnwrapMapKey<int64_t>(const MapKey& map_key) {
+  return map_key.GetInt64Value();
+}
+template <>
+inline uint64_t UnwrapMapKey<uint64_t>(const MapKey& map_key) {
+  return map_key.GetUInt64Value();
+}
+template <>
+inline bool UnwrapMapKey<bool>(const MapKey& map_key) {
+  return map_key.GetBoolValue();
+}
+template <>
+inline std::string UnwrapMapKey<std::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_t>(MapKey* map_key, const int32_t& value) {
+  map_key->SetInt32Value(value);
+}
+template <>
+inline void SetMapKey<uint32_t>(MapKey* map_key, const uint32_t& value) {
+  map_key->SetUInt32Value(value);
+}
+template <>
+inline void SetMapKey<int64_t>(MapKey* map_key, const int64_t& value) {
+  map_key->SetInt64Value(value);
+}
+template <>
+inline void SetMapKey<uint64_t>(MapKey* map_key, const uint64_t& value) {
+  map_key->SetUInt64Value(value);
+}
+template <>
+inline void SetMapKey<bool>(MapKey* map_key, const bool& value) {
+  map_key->SetBoolValue(value);
+}
+template <>
+inline void SetMapKey<std::string>(MapKey* map_key, const std::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_ != nullptr);
+}
+
+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 Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+int MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::size() const {
+  MapFieldBase::SyncMapWithRepeatedField();
+  return static_cast<int>(impl_.GetMap().size());
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::Clear() {
+  if (this->MapFieldBase::repeated_field_ != nullptr) {
+    RepeatedPtrField<EntryType>* repeated_field =
+        reinterpret_cast<RepeatedPtrField<EntryType>*>(
+            this->MapFieldBase::repeated_field_);
+    repeated_field->Clear();
+  }
+
+  impl_.MutableMap()->clear();
+  // Data in map and repeated field are both empty, but we can't set status
+  // CLEAN. Because clear is a generated API, we cannot invalidate previous
+  // reference to map.
+  MapFieldBase::SetMapDirty();
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::SetMapIteratorValue(MapIterator* map_iter)
+    const {
+  const Map<Key, T>& map = impl_.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 Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::ContainsMapKey(
+    const MapKey& map_key) const {
+  const Map<Key, T>& map = impl_.GetMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::const_iterator iter = map.find(key);
+  return iter != map.end();
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::InsertOrLookupMapValue(const MapKey& map_key,
+                                                       MapValueRef* val) {
+  // Always use mutable map because users may change the map value by
+  // MapValueRef.
+  Map<Key, T>* map = MutableMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::iterator iter = map->find(key);
+  if (map->end() == iter) {
+    val->SetValue(&((*map)[key]));
+    return true;
+  }
+  // Key is already in the map. Make sure (*map)[key] is not called.
+  // [] may reorder the map and iterators.
+  val->SetValue(&(iter->second));
+  return false;
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::LookupMapValue(
+    const MapKey& map_key, MapValueConstRef* val) const {
+  const Map<Key, T>& map = GetMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::const_iterator iter = map.find(key);
+  if (map.end() == iter) {
+    return false;
+  }
+  // Key is already in the map. Make sure (*map)[key] is not called.
+  // [] may reorder the map and iterators.
+  val->SetValue(&(iter->second));
+  return true;
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::DeleteMapValue(
+    const MapKey& map_key) {
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  return MutableMap()->erase(key);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::MergeFrom(
+    const MapFieldBase& other) {
+  MapFieldBase::SyncMapWithRepeatedField();
+  const MapField& other_field = static_cast<const MapField&>(other);
+  other_field.SyncMapWithRepeatedField();
+  impl_.MergeFrom(other_field.impl_);
+  MapFieldBase::SetMapDirty();
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::Swap(
+    MapFieldBase* other) {
+  MapFieldBase::Swap(other);
+  MapField* other_field = down_cast<MapField*>(other);
+  impl_.Swap(&other_field->impl_);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::UnsafeShallowSwap(MapFieldBase* other) {
+  InternalSwap(down_cast<MapField*>(other));
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::InternalSwap(
+    MapField* other) {
+  MapFieldBase::InternalSwap(other);
+  impl_.InternalSwap(&other->impl_);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::SyncRepeatedFieldWithMapNoLock() const {
+  if (this->MapFieldBase::repeated_field_ == nullptr) {
+    this->MapFieldBase::repeated_field_ =
+        Arena::CreateMessage<RepeatedPtrField<Message> >(
+            this->MapFieldBase::arena_);
+  }
+  const Map<Key, T>& map = impl_.GetMap();
+  RepeatedPtrField<EntryType>* repeated_field =
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          this->MapFieldBase::repeated_field_);
+
+  repeated_field->Clear();
+
+  // The only way we can get at this point is through reflection and the
+  // only way we can get the reflection object is by having called GetReflection
+  // on the encompassing field. So that type must have existed and hence we
+  // know that this MapEntry default_type has also already been constructed.
+  // So it's safe to just call internal_default_instance().
+  const Message* default_entry = Derived::internal_default_instance();
+  for (typename Map<Key, T>::const_iterator it = map.begin(); it != map.end();
+       ++it) {
+    EntryType* new_entry =
+        down_cast<EntryType*>(default_entry->New(this->MapFieldBase::arena_));
+    repeated_field->AddAllocated(new_entry);
+    (*new_entry->mutable_key()) = it->first;
+    (*new_entry->mutable_value()) = it->second;
+  }
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::SyncMapWithRepeatedFieldNoLock() const {
+  Map<Key, T>* map = const_cast<MapField*>(this)->impl_.MutableMap();
+  RepeatedPtrField<EntryType>* repeated_field =
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          this->MapFieldBase::repeated_field_);
+  GOOGLE_CHECK(this->MapFieldBase::repeated_field_ != nullptr);
+  map->clear();
+  for (typename RepeatedPtrField<EntryType>::iterator it =
+           repeated_field->begin();
+       it != repeated_field->end(); ++it) {
+    // Cast is needed because Map's api and internal storage is different when
+    // value is enum. For enum, we cannot cast an int to enum. Thus, we have to
+    // copy value. For other types, they have same exposed api type and internal
+    // stored type. We should not introduce value copy for them. We achieve this
+    // by casting to value for enum while casting to reference for other types.
+    (*map)[it->key()] = static_cast<CastValueType>(it->value());
+  }
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+size_t MapField<Derived, Key, T, kKeyFieldType,
+                kValueFieldType>::SpaceUsedExcludingSelfNoLock() const {
+  size_t size = 0;
+  if (this->MapFieldBase::repeated_field_ != nullptr) {
+    size += this->MapFieldBase::repeated_field_->SpaceUsedExcludingSelfLong();
+  }
+  size += impl_.GetMap().SpaceUsedExcludingSelfLong();
+
+  return size;
+}
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
new file mode 100644
index 0000000..53bf7a0
--- /dev/null
+++ b/src/google/protobuf/map_field_lite.h
@@ -0,0 +1,209 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+
+#include <type_traits>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#ifndef NDEBUG
+void MapFieldLiteNotDestructed(void* map_field_lite);
+#endif
+
+// This class provides access to map field using generated api. It is used for
+// internal generated message implementation only. Users should never use this
+// directly.
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+class MapFieldLite {
+  // Define message type for internal repeated field.
+  typedef Derived EntryType;
+
+ public:
+  typedef Map<Key, T> MapType;
+
+  constexpr MapFieldLite() : map_() {}
+  explicit MapFieldLite(Arena* arena) : map_(arena) {}
+  MapFieldLite(ArenaInitialized, Arena* arena) : MapFieldLite(arena) {}
+
+#ifdef NDEBUG
+  void Destruct() { map_.~Map(); }
+  ~MapFieldLite() {}
+#else
+  void Destruct() {
+    // We want to destruct the map in such a way that we can verify
+    // that we've done that, but also be sure that we've deallocated
+    // everything (as opposed to leaving an allocation behind with no
+    // data in it, as would happen if a vector was resize'd to zero.
+    // Map::Swap with an empty map accomplishes that.
+    decltype(map_) swapped_map(map_.arena());
+    map_.InternalSwap(swapped_map);
+  }
+  ~MapFieldLite() {
+    if (map_.arena() == nullptr && !map_.empty()) {
+      MapFieldLiteNotDestructed(this);
+    }
+  }
+#endif
+  // Accessors
+  const Map<Key, T>& GetMap() const { return map_; }
+  Map<Key, T>* MutableMap() { return &map_; }
+
+  // Convenient methods for generated message implementation.
+  int size() const { return static_cast<int>(map_.size()); }
+  void Clear() { return map_.clear(); }
+  void MergeFrom(const MapFieldLite& other) {
+    for (typename Map<Key, T>::const_iterator it = other.map_.begin();
+         it != other.map_.end(); ++it) {
+      map_[it->first] = it->second;
+    }
+  }
+  void Swap(MapFieldLite* other) { map_.swap(other->map_); }
+  void InternalSwap(MapFieldLite* other) { map_.InternalSwap(other->map_); }
+
+  // Used in the implementation of parsing. Caller should take the ownership iff
+  // arena_ is nullptr.
+  EntryType* NewEntry() const {
+    return Arena::CreateMessage<EntryType>(map_.arena());
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
+    return parser._InternalParse(ptr, ctx);
+  }
+
+  template <typename UnknownType>
+  const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
+                                      bool (*is_valid)(int), uint32_t field_num,
+                                      InternalMetadata* metadata) {
+    typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
+    return parser.template ParseWithEnumValidation<UnknownType>(
+        ptr, ctx, is_valid, field_num, metadata);
+  }
+
+ private:
+  typedef void DestructorSkippable_;
+
+  // map_ is inside an anonymous union so we can explicitly control its
+  // destruction
+  union {
+    Map<Key, T> map_;
+  };
+
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+};
+
+template <typename UnknownType, typename T>
+struct EnumParseWrapper {
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return map_field->template ParseWithEnumValidation<UnknownType>(
+        ptr, ctx, is_valid, field_num, metadata);
+  }
+  T* map_field;
+  bool (*is_valid)(int);
+  uint32_t field_num;
+  InternalMetadata* metadata;
+};
+
+// Helper function because the typenames of maps are horrendous to print. This
+// leverages compiler type deduction, to keep all type data out of the
+// generated code
+template <typename UnknownType, typename T>
+EnumParseWrapper<UnknownType, T> InitEnumParseWrapper(
+    T* map_field, bool (*is_valid)(int), uint32_t field_num,
+    InternalMetadata* metadata) {
+  return EnumParseWrapper<UnknownType, T>{map_field, is_valid, field_num,
+                                          metadata};
+}
+
+// True if IsInitialized() is true for value field in all elements of t. T is
+// expected to be message.  It's useful to have this helper here to keep the
+// protobuf compiler from ever having to emit loops in IsInitialized() methods.
+// We want the C++ compiler to inline this or not as it sees fit.
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+bool AllAreInitialized(const MapFieldLite<Derived, Key, T, key_wire_type,
+                                          value_wire_type>& field) {
+  const auto& t = field.GetMap();
+  for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
+       ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+template <typename MEntry>
+struct MapEntryToMapField : MapEntryToMapField<typename MEntry::SuperType> {};
+
+template <typename T, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryToMapField<
+    MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType>> {
+  typedef MapFieldLite<
+      MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType>, Key, Value,
+      kKeyFieldType, kValueFieldType>
+      MapFieldType;
+};
+
+#ifndef NDEBUG
+inline PROTOBUF_NOINLINE void MapFieldLiteNotDestructed(void* map_field_lite) {
+  bool proper_destruct = false;
+  GOOGLE_CHECK(proper_destruct) << map_field_lite;
+}
+#endif
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
new file mode 100644
index 0000000..1659c95
--- /dev/null
+++ b/src/google/protobuf/map_field_test.cc
@@ -0,0 +1,538 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include <memory>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_test_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+using unittest::TestAllTypes;
+
+// ArenaHolder from map_test_util.h works fine for fields other than map
+// fields.  For map fields, the Destruct() call must be made before the
+// actual destructor is called.
+template <typename MapType>
+struct ArenaDestructor : ArenaHolder<MapType> {
+  using ArenaHolder<MapType>::ArenaHolder;
+  ~ArenaDestructor() { ArenaHolder<MapType>::get()->Destruct(); }
+};
+
+class MapFieldBaseStub : public MapFieldBase {
+ public:
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  MapFieldBaseStub() {}
+  virtual ~MapFieldBaseStub() { MapFieldBase::Destruct(); }
+  explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
+  // Get underlined repeated field without synchronizing map.
+  RepeatedPtrField<Message>* InternalRepeatedField() { return repeated_field_; }
+  bool IsMapClean() {
+    return state_.load(std::memory_order_relaxed) != STATE_MODIFIED_MAP;
+  }
+  bool IsRepeatedClean() {
+    return state_.load(std::memory_order_relaxed) != STATE_MODIFIED_REPEATED;
+  }
+  void SetMapDirty() {
+    state_.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
+  }
+  void SetRepeatedDirty() {
+    state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
+  }
+  bool ContainsMapKey(const MapKey& map_key) const override { return false; }
+  bool InsertOrLookupMapValue(const MapKey& map_key,
+                              MapValueRef* val) override {
+    return false;
+  }
+  bool LookupMapValue(const MapKey& map_key,
+                      MapValueConstRef* val) const override {
+    return false;
+  }
+  bool DeleteMapValue(const MapKey& map_key) override { return false; }
+  bool EqualIterator(const MapIterator& a,
+                     const MapIterator& b) const override {
+    return false;
+  }
+  int size() const override { return 0; }
+  void Clear() override {}
+  void MapBegin(MapIterator* map_iter) const override {}
+  void MapEnd(MapIterator* map_iter) const override {}
+  void MergeFrom(const MapFieldBase& other) override {}
+  void Swap(MapFieldBase* other) override {}
+  void InitializeIterator(MapIterator* map_iter) const override {}
+  void DeleteIterator(MapIterator* map_iter) const override {}
+  void CopyIterator(MapIterator* this_iterator,
+                    const MapIterator& other_iterator) const override {}
+  void IncreaseIterator(MapIterator* map_iter) const override {}
+
+  Arena* GetArenaForInternalRepeatedField() {
+    auto* repeated_field = MutableRepeatedField();
+    return repeated_field->GetArena();
+  }
+};
+
+class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> {
+ protected:
+  typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
+  typedef MapField<EntryType, int32_t, int32_t, WireFormatLite::TYPE_INT32,
+                   WireFormatLite::TYPE_INT32>
+      MapFieldType;
+
+  MapFieldBasePrimitiveTest()
+      : arena_(GetParam() ? new Arena() : nullptr),
+        map_field_(arena_.get()),
+        map_field_base_(map_field_.get()) {
+    // Get descriptors
+    map_descriptor_ = unittest::TestMap::descriptor()
+                          ->FindFieldByName("map_int32_int32")
+                          ->message_type();
+    key_descriptor_ = map_descriptor_->map_key();
+    value_descriptor_ = map_descriptor_->map_value();
+
+    // Build map field
+    map_field_base_ = map_field_.get();
+    map_ = map_field_->MutableMap();
+    initial_value_map_[0] = 100;
+    initial_value_map_[1] = 101;
+    map_->insert(initial_value_map_.begin(), initial_value_map_.end());
+    EXPECT_EQ(2, map_->size());
+  }
+
+  std::unique_ptr<Arena> arena_;
+  ArenaDestructor<MapFieldType> map_field_;
+  MapFieldBase* map_field_base_;
+  Map<int32_t, int32_t>* map_;
+  const Descriptor* map_descriptor_;
+  const FieldDescriptor* key_descriptor_;
+  const FieldDescriptor* value_descriptor_;
+  std::map<int32_t, int32_t>
+      initial_value_map_;  // copy of initial values inserted
+};
+
+INSTANTIATE_TEST_SUITE_P(MapFieldBasePrimitiveTestInstance,
+                         MapFieldBasePrimitiveTest,
+                         testing::Values(true, false));
+
+TEST_P(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
+  EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
+}
+
+TEST_P(MapFieldBasePrimitiveTest, GetRepeatedField) {
+  const RepeatedPtrField<Message>& repeated =
+      reinterpret_cast<const RepeatedPtrField<Message>&>(
+          map_field_base_->GetRepeatedField());
+  EXPECT_EQ(2, repeated.size());
+  for (int i = 0; i < repeated.size(); i++) {
+    const Message& message = repeated.Get(i);
+    int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+    int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+    EXPECT_EQ(value, initial_value_map_[key]);
+  }
+}
+
+TEST_P(MapFieldBasePrimitiveTest, MutableRepeatedField) {
+  RepeatedPtrField<Message>* repeated =
+      reinterpret_cast<RepeatedPtrField<Message>*>(
+          map_field_base_->MutableRepeatedField());
+  EXPECT_EQ(2, repeated->size());
+  for (int i = 0; i < repeated->size(); i++) {
+    const Message& message = repeated->Get(i);
+    int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+    int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+    EXPECT_EQ(value, initial_value_map_[key]);
+  }
+}
+
+TEST_P(MapFieldBasePrimitiveTest, Arena) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  {
+    // TODO(liujisi): Re-write the test to ensure the memory for the map and
+    // repeated fields are allocated from arenas.
+    // NoHeapChecker no_heap;
+
+    MapFieldType* map_field = Arena::CreateMessage<MapFieldType>(&arena);
+
+    // Set content in map
+    (*map_field->MutableMap())[100] = 101;
+
+    // Trigger conversion to repeated field.
+    map_field->GetRepeatedField();
+  }
+
+  {
+    // TODO(liujisi): Re-write the test to ensure the memory for the map and
+    // repeated fields are allocated from arenas.
+    // NoHeapChecker no_heap;
+
+    MapFieldBaseStub* map_field =
+        Arena::CreateMessage<MapFieldBaseStub>(&arena);
+
+    // Trigger conversion to repeated field.
+    EXPECT_TRUE(map_field->MutableRepeatedField() != nullptr);
+
+    EXPECT_EQ(map_field->GetArenaForInternalRepeatedField(), &arena);
+  }
+}
+
+TEST_P(MapFieldBasePrimitiveTest, EnforceNoArena) {
+  std::unique_ptr<MapFieldBaseStub> map_field(
+      Arena::CreateMessage<MapFieldBaseStub>(nullptr));
+  EXPECT_EQ(map_field->GetArenaForInternalRepeatedField(), nullptr);
+}
+
+namespace {
+enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
+}  // anonymous namespace
+
+class MapFieldStateTest
+    : public testing::TestWithParam<std::tuple<State, bool>> {
+ protected:
+  typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
+  typedef MapField<EntryType, int32_t, int32_t, WireFormatLite::TYPE_INT32,
+                   WireFormatLite::TYPE_INT32>
+      MapFieldType;
+  MapFieldStateTest()
+      : arena_(std::get<1>(GetParam()) ? new Arena() : nullptr),
+        map_field_(arena_.get()),
+        map_field_base_(map_field_.get()),
+        state_(std::get<0>(GetParam())) {
+    // Build map field
+    Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
+    switch (state_) {
+      case CLEAN:
+        AddOneStillClean(map_field_.get());
+        break;
+      case MAP_DIRTY:
+        MakeMapDirty(map_field_.get());
+        break;
+      case REPEATED_DIRTY:
+        MakeRepeatedDirty(map_field_.get());
+        break;
+      default:
+        break;
+    }
+  }
+
+  void AddOneStillClean(MapFieldType* map_field) {
+    MapFieldBase* map_field_base = map_field;
+    Map<int32_t, int32_t>* map = map_field->MutableMap();
+    (*map)[0] = 0;
+    map_field_base->GetRepeatedField();
+    Expect(map_field, CLEAN, 1, 1, false);
+  }
+
+  void MakeMapDirty(MapFieldType* map_field) {
+    Map<int32_t, int32_t>* map = map_field->MutableMap();
+    (*map)[0] = 0;
+    Expect(map_field, MAP_DIRTY, 1, 0, true);
+  }
+
+  void MakeRepeatedDirty(MapFieldType* map_field) {
+    MakeMapDirty(map_field);
+    MapFieldBase* map_field_base = map_field;
+    map_field_base->MutableRepeatedField();
+    // We use MutableMap on impl_ because we don't want to disturb the syncing
+    Map<int32_t, int32_t>* map = map_field->impl_.MutableMap();
+    map->clear();
+
+    Expect(map_field, REPEATED_DIRTY, 0, 1, false);
+  }
+
+  void Expect(MapFieldType* map_field, State state, int map_size,
+              int repeated_size, bool is_repeated_null) {
+    MapFieldBase* map_field_base = map_field;
+    MapFieldBaseStub* stub =
+        reinterpret_cast<MapFieldBaseStub*>(map_field_base);
+
+    // We use MutableMap on impl_ because we don't want to disturb the syncing
+    Map<int32_t, int32_t>* map = map_field->impl_.MutableMap();
+    RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
+
+    switch (state) {
+      case MAP_DIRTY:
+        EXPECT_FALSE(stub->IsMapClean());
+        EXPECT_TRUE(stub->IsRepeatedClean());
+        break;
+      case REPEATED_DIRTY:
+        EXPECT_TRUE(stub->IsMapClean());
+        EXPECT_FALSE(stub->IsRepeatedClean());
+        break;
+      case CLEAN:
+        EXPECT_TRUE(stub->IsMapClean());
+        EXPECT_TRUE(stub->IsRepeatedClean());
+        break;
+      default:
+        FAIL();
+    }
+
+    EXPECT_EQ(map_size, map->size());
+    if (is_repeated_null) {
+      EXPECT_TRUE(repeated_field == nullptr);
+    } else {
+      if (repeated_field == nullptr) {
+        EXPECT_EQ(repeated_size, 0);
+      } else {
+        EXPECT_EQ(repeated_size, repeated_field->size());
+      }
+    }
+  }
+
+  std::unique_ptr<Arena> arena_;
+  ArenaDestructor<MapFieldType> map_field_;
+  MapFieldBase* map_field_base_;
+  State state_;
+};
+
+INSTANTIATE_TEST_SUITE_P(MapFieldStateTestInstance, MapFieldStateTest,
+                         testing::Combine(testing::Values(CLEAN, MAP_DIRTY,
+                                                          REPEATED_DIRTY),
+                                          testing::Values(true, false)));
+
+TEST_P(MapFieldStateTest, GetMap) {
+  map_field_->GetMap();
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), CLEAN, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+}
+
+TEST_P(MapFieldStateTest, MutableMap) {
+  map_field_->MutableMap();
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+}
+
+TEST_P(MapFieldStateTest, MergeFromClean) {
+  ArenaDestructor<MapFieldType> other(arena_.get());
+  AddOneStillClean(other.get());
+
+  map_field_->MergeFrom(*other);
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+
+  Expect(other.get(), CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, MergeFromMapDirty) {
+  ArenaDestructor<MapFieldType> other(arena_.get());
+  MakeMapDirty(other.get());
+
+  map_field_->MergeFrom(*other);
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+
+  Expect(other.get(), MAP_DIRTY, 1, 0, true);
+}
+
+TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
+  ArenaDestructor<MapFieldType> other(arena_.get());
+  MakeRepeatedDirty(other.get());
+
+  map_field_->MergeFrom(*other);
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+
+  Expect(other.get(), CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, SwapClean) {
+  ArenaDestructor<MapFieldType> other(arena_.get());
+  AddOneStillClean(other.get());
+
+  map_field_->Swap(other.get());
+
+  Expect(map_field_.get(), CLEAN, 1, 1, false);
+
+  switch (state_) {
+    case CLEAN:
+      Expect(other.get(), CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(other.get(), MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(other.get(), REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, SwapMapDirty) {
+  ArenaDestructor<MapFieldType> other(arena_.get());
+  MakeMapDirty(other.get());
+
+  map_field_->Swap(other.get());
+
+  Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+
+  switch (state_) {
+    case CLEAN:
+      Expect(other.get(), CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(other.get(), MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(other.get(), REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
+  ArenaDestructor<MapFieldType> other(arena_.get());
+  MakeRepeatedDirty(other.get());
+
+  map_field_->Swap(other.get());
+
+  Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+
+  switch (state_) {
+    case CLEAN:
+      Expect(other.get(), CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(other.get(), MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(other.get(), REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, Clear) {
+  map_field_->Clear();
+
+  Expect(map_field_.get(), MAP_DIRTY, 0, 0, false);
+}
+
+TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
+  map_field_base_->SpaceUsedExcludingSelf();
+
+  switch (state_) {
+    case CLEAN:
+      Expect(map_field_.get(), CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, GetMapField) {
+  map_field_base_->GetRepeatedField();
+
+  if (state_ != REPEATED_DIRTY) {
+    Expect(map_field_.get(), CLEAN, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+  }
+}
+
+TEST_P(MapFieldStateTest, MutableMapField) {
+  map_field_base_->MutableRepeatedField();
+
+  if (state_ != REPEATED_DIRTY) {
+    Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+  }
+}
+
+class MyMapField
+    : public MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32_t,
+                      int32_t, internal::WireFormatLite::TYPE_INT32,
+                      internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapField()
+      : MyMapField::MapField(internal::ConstantInitialized{}) {}
+};
+
+TEST(MapFieldTest, ConstInit) {
+  // This tests that `MapField` and all its base classes can be constant
+  // initialized.
+  PROTOBUF_CONSTINIT static MyMapField field;  // NOLINT
+  EXPECT_EQ(field.size(), 0);
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_lite_test_util.cc b/src/google/protobuf/map_lite_test_util.cc
new file mode 100644
index 0000000..121f267
--- /dev/null
+++ b/src/google/protobuf/map_lite_test_util.cc
@@ -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.
+
+#include <google/protobuf/map_lite_test_util.h>
+
+#include <google/protobuf/map_lite_unittest.pb.h>
+#include <google/protobuf/map_test_util_impl.h>
+
+namespace google {
+namespace protobuf {
+
+void MapLiteTestUtil::SetMapFields(unittest::TestMapLite* message) {
+  MapTestUtilImpl::SetMapFields<unittest::MapEnumLite,
+                                unittest::MAP_ENUM_BAR_LITE,
+                                unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::SetArenaMapFields(unittest::TestArenaMapLite* message) {
+  MapTestUtilImpl::SetArenaMapFields<unittest::MapEnumLite,
+                                     unittest::MAP_ENUM_BAR_LITE,
+                                     unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::SetMapFieldsInitialized(unittest::TestMapLite* message) {
+  MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+void MapLiteTestUtil::ModifyMapFields(unittest::TestMapLite* message) {
+  MapTestUtilImpl::ModifyMapFields<unittest::MapEnumLite,
+                                   unittest::MAP_ENUM_FOO_LITE>(message);
+}
+
+void MapLiteTestUtil::ExpectClear(const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectClear(message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsSet(const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectMapFieldsSet<unittest::MapEnumLite,
+                                      unittest::MAP_ENUM_BAR_LITE,
+                                      unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::ExpectArenaMapFieldsSet(
+    const unittest::TestArenaMapLite& message) {
+  MapTestUtilImpl::ExpectArenaMapFieldsSet<unittest::MapEnumLite,
+                                           unittest::MAP_ENUM_BAR_LITE,
+                                           unittest::MAP_ENUM_BAZ_LITE>(
+      message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsSetInitialized(
+    const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectMapFieldsSetInitialized<unittest::MapEnumLite,
+                                                 unittest::MAP_ENUM_FOO_LITE>(
+      message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsModified(
+    const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectMapFieldsModified<unittest::MapEnumLite,
+                                           unittest::MAP_ENUM_BAR_LITE,
+                                           unittest::MAP_ENUM_FOO_LITE>(
+      message);
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h
new file mode 100644
index 0000000..573de7b
--- /dev/null
+++ b/src/google/protobuf/map_lite_test_util.h
@@ -0,0 +1,80 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
+
+#include <google/protobuf/map_lite_unittest.pb.h>
+
+namespace google {
+namespace protobuf {
+
+class MapLiteTestUtil {
+ public:
+  // Set every field in the TestMapLite message to a unique value.
+  static void SetMapFields(protobuf_unittest::TestMapLite* message);
+
+  // Set every field in the TestArenaMapLite message to a unique value.
+  static void SetArenaMapFields(protobuf_unittest::TestArenaMapLite* message);
+
+  // Set every field in the message to a default value.
+  static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  static void ModifyMapFields(protobuf_unittest::TestMapLite* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  static void ExpectMapFieldsSet(const protobuf_unittest::TestMapLite& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMapLite.
+  static void ExpectArenaMapFieldsSet(
+      const protobuf_unittest::TestArenaMapLite& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  static void ExpectMapFieldsSetInitialized(
+      const protobuf_unittest::TestMapLite& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  static void ExpectMapFieldsModified(
+      const protobuf_unittest::TestMapLite& message);
+
+  // Check that all fields are empty.
+  static void ExpectClear(const protobuf_unittest::TestMapLite& message);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto
new file mode 100644
index 0000000..7f10431
--- /dev/null
+++ b/src/google/protobuf/map_lite_unittest.proto
@@ -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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest_lite.proto";
+
+option cc_enable_arenas = true;
+option optimize_for = LITE_RUNTIME;
+
+message TestMapLite {
+  map<int32, int32> map_int32_int32 = 1;
+  map<int64, int64> map_int64_int64 = 2;
+  map<uint32, uint32> map_uint32_uint32 = 3;
+  map<uint64, uint64> map_uint64_uint64 = 4;
+  map<sint32, sint32> map_sint32_sint32 = 5;
+  map<sint64, sint64> map_sint64_sint64 = 6;
+  map<fixed32, fixed32> map_fixed32_fixed32 = 7;
+  map<fixed64, fixed64> map_fixed64_fixed64 = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32, float> map_int32_float = 11;
+  map<int32, double> map_int32_double = 12;
+  map<bool, bool> map_bool_bool = 13;
+  map<string, string> map_string_string = 14;
+  map<int32, bytes> map_int32_bytes = 15;
+  map<int32, MapEnumLite> map_int32_enum = 16;
+  map<int32, ForeignMessageLite> map_int32_foreign_message = 17;
+  map<int32, int32> teboring = 18;
+}
+
+message TestArenaMapLite {
+  map<int32, int32> map_int32_int32 = 1;
+  map<int64, int64> map_int64_int64 = 2;
+  map<uint32, uint32> map_uint32_uint32 = 3;
+  map<uint64, uint64> map_uint64_uint64 = 4;
+  map<sint32, sint32> map_sint32_sint32 = 5;
+  map<sint64, sint64> map_sint64_sint64 = 6;
+  map<fixed32, fixed32> map_fixed32_fixed32 = 7;
+  map<fixed64, fixed64> map_fixed64_fixed64 = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32, float> map_int32_float = 11;
+  map<int32, double> map_int32_double = 12;
+  map<bool, bool> map_bool_bool = 13;
+  map<string, string> map_string_string = 14;
+  map<int32, bytes> map_int32_bytes = 15;
+  map<int32, MapEnumLite> map_int32_enum = 16;
+  map<int32, ForeignMessageArenaLite> map_int32_foreign_message = 17;
+}
+
+// Test embedded message with required fields
+message TestRequiredMessageMapLite {
+  map<int32, TestRequiredLite> map_field = 1;
+}
+
+message TestEnumMapLite {
+  map<int32, Proto2MapEnumLite> known_map_field = 101;
+  map<int32, Proto2MapEnumLite> unknown_map_field = 102;
+}
+
+message TestEnumMapPlusExtraLite {
+  map<int32, Proto2MapEnumPlusExtraLite> known_map_field = 101;
+  map<int32, Proto2MapEnumPlusExtraLite> unknown_map_field = 102;
+}
+
+message TestMessageMapLite {
+  map<int32, TestAllTypesLite> map_int32_message = 1;
+}
+
+enum Proto2MapEnumLite {
+  PROTO2_MAP_ENUM_FOO_LITE = 0;
+  PROTO2_MAP_ENUM_BAR_LITE = 1;
+  PROTO2_MAP_ENUM_BAZ_LITE = 2;
+}
+
+enum Proto2MapEnumPlusExtraLite {
+  E_PROTO2_MAP_ENUM_FOO_LITE = 0;
+  E_PROTO2_MAP_ENUM_BAR_LITE = 1;
+  E_PROTO2_MAP_ENUM_BAZ_LITE = 2;
+  E_PROTO2_MAP_ENUM_EXTRA_LITE = 3;
+}
+
+enum MapEnumLite {
+  MAP_ENUM_FOO_LITE = 0;
+  MAP_ENUM_BAR_LITE = 1;
+  MAP_ENUM_BAZ_LITE = 2;
+}
+
+message TestRequiredLite {
+  required int32 a = 1;
+  required int32 b = 2;
+  required int32 c = 3;
+
+  extend TestAllExtensionsLite {
+    optional TestRequiredLite single = 1000;
+  }
+}
+
+message ForeignMessageArenaLite {
+  optional int32 c = 1;
+}
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
new file mode 100644
index 0000000..20d58f9
--- /dev/null
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -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.
+
+syntax = "proto2";
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest_import.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+enum Proto2MapEnum {
+  PROTO2_MAP_ENUM_FOO   = 0;
+  PROTO2_MAP_ENUM_BAR   = 1;
+  PROTO2_MAP_ENUM_BAZ   = 2;
+}
+
+enum Proto2MapEnumPlusExtra {
+  E_PROTO2_MAP_ENUM_FOO   = 0;
+  E_PROTO2_MAP_ENUM_BAR   = 1;
+  E_PROTO2_MAP_ENUM_BAZ   = 2;
+  E_PROTO2_MAP_ENUM_EXTRA = 3;
+}
+
+message TestEnumMap {
+  map<int32, Proto2MapEnum> known_map_field = 101;
+  map<int32, Proto2MapEnum> unknown_map_field = 102;
+}
+
+message TestEnumMapPlusExtra {
+  map<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
+  map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
+}
+
+message TestImportEnumMap {
+  map<int32, protobuf_unittest_import.ImportEnumForMap> import_enum_amp = 1;
+}
+
+message TestIntIntMap {
+  map<int32, int32> m = 1;
+}
+
+// Test all key types: string, plus the non-floating-point scalars.
+message TestMaps {
+  map<int32, TestIntIntMap> m_int32 = 1;
+  map<int64, TestIntIntMap> m_int64 = 2;
+  map<uint32, TestIntIntMap> m_uint32 = 3;
+  map<uint64, TestIntIntMap> m_uint64 = 4;
+  map<sint32, TestIntIntMap> m_sint32 = 5;
+  map<sint64, TestIntIntMap> m_sint64 = 6;
+  map<fixed32, TestIntIntMap> m_fixed32 = 7;
+  map<fixed64, TestIntIntMap> m_fixed64 = 8;
+  map<sfixed32, TestIntIntMap> m_sfixed32 = 9;
+  map<sfixed64, TestIntIntMap> m_sfixed64 = 10;
+  map<bool, TestIntIntMap> m_bool = 11;
+  map<string, TestIntIntMap> m_string = 12;
+}
+
+// Test maps in submessages.
+message TestSubmessageMaps {
+  optional TestMaps m = 1;
+}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
new file mode 100644
index 0000000..f7c024c
--- /dev/null
+++ b/src/google/protobuf/map_test.cc
@@ -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.
+
+#include <google/protobuf/map_proto2_unittest.pb.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/reflection_tester.h>
+#include <google/protobuf/test_util2.h>
+
+
+#define BRIDGE_UNITTEST ::google::protobuf::bridge_unittest
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+#define UNITTEST_PACKAGE_NAME "protobuf_unittest"
+
+// Must include after defining UNITTEST, etc.
+// clang-format off
+#include <google/protobuf/test_util.inc>
+#include <google/protobuf/map_test_util.inc>
+#include <google/protobuf/map_test.inc>
+// clang-format on
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+
+struct AlignedAsDefault {
+  int x;
+};
+struct alignas(8) AlignedAs8 {
+  int x;
+};
+
+template <typename Aligned, bool on_arena = false>
+void MapTest_Aligned() {
+  Arena arena;
+  constexpr size_t align_mask = alignof(Aligned) - 1;
+  Map<int, Aligned> map(on_arena ? &arena : nullptr);
+  map.insert({1, Aligned{}});
+  auto it = map.find(1);
+  ASSERT_NE(it, map.end());
+  ASSERT_EQ(reinterpret_cast<intptr_t>(&it->second) & align_mask, 0);
+  map.clear();
+}
+
+TEST(MapTest, Aligned) { MapTest_Aligned<AlignedAsDefault>(); }
+TEST(MapTest, AlignedOnArena) { MapTest_Aligned<AlignedAsDefault, true>(); }
+TEST(MapTest, Aligned8) { MapTest_Aligned<AlignedAs8>(); }
+TEST(MapTest, Aligned8OnArena) { MapTest_Aligned<AlignedAs8, true>(); }
+
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc
new file mode 100644
index 0000000..18a7bfb
--- /dev/null
+++ b/src/google/protobuf/map_test.inc
@@ -0,0 +1,4071 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A hack to include windows.h first, which ensures the GetMessage macro can
+// be undefined when we include <google/protobuf/stubs/common.h>
+#if defined(_MSC_VER)
+#define _WINSOCKAPI_  // to avoid re-definition in WinSock2.h
+#define NOMINMAX      // to avoid defining min/max macros
+#include <windows.h>
+#endif  // _WIN32
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <random>
+#include <set>
+#include <sstream>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/util/time_util.h>
+#include <google/protobuf/wire_format.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+using UNITTEST::ForeignMessage;
+using UNITTEST::TestAllTypes;
+using UNITTEST::TestMap;
+using UNITTEST::TestRecursiveMapMessage;
+
+namespace internal {
+
+void MapTestForceDeterministic() {
+  io::CodedOutputStream::SetDefaultSerializationDeterministic();
+}
+
+namespace {
+
+// Map API Test =====================================================
+
+class MapImplTest : public ::testing::Test {
+ protected:
+  MapImplTest()
+      : map_ptr_(new Map<int32_t, int32_t>()),
+        map_(*map_ptr_),
+        const_map_(*map_ptr_) {
+    EXPECT_TRUE(map_.empty());
+    EXPECT_EQ(0, map_.size());
+  }
+
+  void ExpectSingleElement(int32_t key, int32_t value) {
+    EXPECT_FALSE(map_.empty());
+    EXPECT_EQ(1, map_.size());
+    ExpectElement(key, value);
+  }
+
+  void ExpectElements(const std::map<int32_t, int32_t>& map) {
+    EXPECT_FALSE(map_.empty());
+    EXPECT_EQ(map.size(), map_.size());
+    for (std::map<int32_t, int32_t>::const_iterator it = map.begin();
+         it != map.end(); ++it) {
+      ExpectElement(it->first, it->second);
+    }
+  }
+
+  void ExpectElement(int32_t key, int32_t value) {
+    // Test map size is correct.
+    EXPECT_EQ(value, map_[key]);
+    EXPECT_EQ(1, map_.count(key));
+    EXPECT_TRUE(map_.contains(key));
+
+    // Check mutable at and find work correctly.
+    EXPECT_EQ(value, map_.at(key));
+    Map<int32_t, int32_t>::iterator it = map_.find(key);
+
+    // iterator dereferenceable
+    EXPECT_EQ(key, (*it).first);
+    EXPECT_EQ(value, (*it).second);
+    EXPECT_EQ(key, it->first);
+    EXPECT_EQ(value, it->second);
+
+    // iterator mutable
+    ((*it).second) = value + 1;
+    EXPECT_EQ(value + 1, map_[key]);
+    ((*it).second) = value;
+    EXPECT_EQ(value, map_[key]);
+
+    it->second = value + 1;
+    EXPECT_EQ(value + 1, map_[key]);
+    it->second = value;
+    EXPECT_EQ(value, map_[key]);
+
+    // copy constructor
+    Map<int32_t, int32_t>::iterator it_copy = it;
+    EXPECT_EQ(key, it_copy->first);
+    EXPECT_EQ(value, it_copy->second);
+
+    // Immutable API ================================================
+
+    // Check immutable at and find work correctly.
+    EXPECT_EQ(value, const_map_.at(key));
+    Map<int32_t, int32_t>::const_iterator const_it = const_map_.find(key);
+
+    // iterator dereferenceable
+    EXPECT_EQ(key, (*const_it).first);
+    EXPECT_EQ(value, (*const_it).second);
+    EXPECT_EQ(key, const_it->first);
+    EXPECT_EQ(value, const_it->second);
+
+    // copy constructor
+    Map<int32_t, int32_t>::const_iterator const_it_copy = const_it;
+    EXPECT_EQ(key, const_it_copy->first);
+    EXPECT_EQ(value, const_it_copy->second);
+  }
+
+  std::unique_ptr<Map<int32_t, int32_t>> map_ptr_;
+  Map<int32_t, int32_t>& map_;
+  const Map<int32_t, int32_t>& const_map_;
+};
+
+TEST_F(MapImplTest, OperatorBracket) {
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  EXPECT_EQ(0, map_[key]);
+
+  map_[key] = value1;
+  ExpectSingleElement(key, value1);
+
+  map_[key] = value2;
+  ExpectSingleElement(key, value2);
+}
+
+struct MoveTestKey {
+  MoveTestKey(int data, int* copies) : data(data), copies(copies) {}
+
+  MoveTestKey(const MoveTestKey& other)
+      : data(other.data), copies(other.copies) {
+    ++*copies;
+  }
+
+  MoveTestKey(MoveTestKey&& other) noexcept
+      : data(other.data), copies(other.copies) {}
+
+  friend bool operator==(const MoveTestKey& lhs, const MoveTestKey& rhs) {
+    return lhs.data == rhs.data;
+  }
+  friend bool operator<(const MoveTestKey& lhs, const MoveTestKey& rhs) {
+    return lhs.data < rhs.data;
+  }
+
+  int data;
+  int* copies;
+};
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace std {
+
+template <>  // NOLINT
+struct hash<google::protobuf::internal::MoveTestKey> {
+  size_t operator()(const google::protobuf::internal::MoveTestKey& key) const {
+    return hash<int>{}(key.data);
+  }
+};
+}  // namespace std
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST_F(MapImplTest, OperatorBracketRValue) {
+  Arena arena;
+  for (Arena* arena_to_use : {&arena, static_cast<Arena*>(nullptr)}) {
+    int copies = 0;
+    Map<MoveTestKey, int> map(arena_to_use);
+    MoveTestKey key1(1, &copies);
+    EXPECT_EQ(copies, 0);
+    map[key1] = 0;
+    EXPECT_EQ(copies, 1);
+    map[MoveTestKey(2, &copies)] = 2;
+    EXPECT_EQ(copies, 1);
+  }
+}
+
+TEST_F(MapImplTest, OperatorBracketNonExist) {
+  int32_t key = 0;
+  int32_t default_value = 0;
+
+  EXPECT_EQ(default_value, map_[key]);
+  ExpectSingleElement(key, default_value);
+}
+
+TEST_F(MapImplTest, MutableAt) {
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  map_[key] = value1;
+  ExpectSingleElement(key, value1);
+
+  map_.at(key) = value2;
+  ExpectSingleElement(key, value2);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST_F(MapImplTest, MutableAtNonExistDeathTest) {
+  EXPECT_DEATH(map_.at(0), "");
+}
+
+TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) {
+  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"
+      "MapValue[Const]*Ref::type MapValue[Const]*Ref is not initialized.");
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST_F(MapImplTest, MapKeyAssignment) {
+  MapKey from, to;
+  from.SetStringValue("abc");
+  to = from;
+  EXPECT_EQ("abc", to.GetStringValue());
+}
+
+TEST_F(MapImplTest, CountNonExist) { EXPECT_EQ(0, map_.count(0)); }
+
+TEST_F(MapImplTest, ContainNotExist) { EXPECT_FALSE(map_.contains(0)); }
+
+TEST_F(MapImplTest, ImmutableContainNotExist) {
+  EXPECT_FALSE(const_map_.contains(0));
+}
+
+TEST_F(MapImplTest, MutableFindNonExist) {
+  EXPECT_TRUE(map_.end() == map_.find(0));
+}
+
+TEST_F(MapImplTest, ImmutableFindNonExist) {
+  EXPECT_TRUE(const_map_.end() == const_map_.find(0));
+}
+
+TEST_F(MapImplTest, ConstEnd) {
+  EXPECT_TRUE(const_map_.end() == const_map_.cend());
+}
+
+TEST_F(MapImplTest, GetReferenceFromIterator) {
+  for (int i = 0; i < 10; i++) {
+    map_[i] = i;
+  }
+
+  for (Map<int32_t, int32_t>::const_iterator it = map_.cbegin();
+       it != map_.cend();) {
+    Map<int32_t, int32_t>::const_reference entry = *it++;
+    EXPECT_EQ(entry.first, entry.second);
+  }
+
+  for (Map<int32_t, int32_t>::const_iterator it = const_map_.begin();
+       it != const_map_.end();) {
+    Map<int32_t, int32_t>::const_reference entry = *it++;
+    EXPECT_EQ(entry.first, entry.second);
+  }
+
+  for (Map<int32_t, int32_t>::iterator it = map_.begin(); it != map_.end();) {
+    Map<int32_t, int32_t>::reference entry = *it++;
+    EXPECT_EQ(entry.first + 1, ++entry.second);
+  }
+}
+
+TEST_F(MapImplTest, IteratorBasic) {
+  map_[0] = 0;
+
+  // Default constructible (per forward iterator requirements).
+  Map<int, int>::const_iterator cit;
+  Map<int, int>::iterator it;
+
+  it = map_.begin();
+  cit = it;  // Converts to const_iterator
+
+  // Can compare between them.
+  EXPECT_TRUE(it == cit);
+  EXPECT_FALSE(cit != it);
+
+  // Pre increment.
+  EXPECT_FALSE(it == ++cit);
+
+  // Post increment.
+  EXPECT_FALSE(it++ == cit);
+  EXPECT_TRUE(it == cit);
+}
+
+template <typename Iterator>
+static int64_t median(Iterator i0, Iterator i1) {
+  std::vector<int64_t> v(i0, i1);
+  std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
+  return v[v.size() / 2];
+}
+
+static int64_t Now() {
+  return util::TimeUtil::TimestampToNanoseconds(
+      util::TimeUtil::GetCurrentTime());
+}
+
+// Arbitrary odd integers for creating test data.
+static int k0 = 812398771;
+static int k1 = 1312938717;
+static int k2 = 1321555333;
+
+// A naive begin() implementation will cause begin() to get slower and slower
+// if one erases elements at the "front" of the hash map, and we'd like to
+// avoid that, as std::unordered_map does.
+TEST_F(MapImplTest, BeginIsFast) {
+  if (true) return;  // TODO(gpike): make this less flaky and re-enable it.
+  Map<int32_t, int32_t> map;
+  const int kTestSize = 250000;
+  // Create a random-looking map of size n.  Use non-negative integer keys.
+  uint32_t frog = 123983;
+  int last_key = 0;
+  int counter = 0;
+  while (map.size() < kTestSize) {
+    frog *= static_cast<uint32_t>(k0);
+    frog ^= frog >> 17;
+    frog += counter++;
+    last_key =
+        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
+    GOOGLE_DCHECK_GE(last_key, 0);
+    map[last_key] = last_key ^ 1;
+  }
+  std::vector<int64_t> times;
+  // We're going to do map.erase(map.begin()) over and over again.  But,
+  // just in case one iteration is fast compared to the granularity of
+  // our time keeping, we measure kChunkSize iterations per outer-loop iter.
+  const int kChunkSize = 1000;
+  GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0);
+  do {
+    const int64_t start = Now();
+    for (int i = 0; i < kChunkSize; i++) {
+      map.erase(map.begin());
+    }
+    const int64_t end = Now();
+    if (end > start) {
+      times.push_back(end - start);
+    }
+  } while (!map.empty());
+  if (times.size() < .99 * kTestSize / kChunkSize) {
+    GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time";
+    return;
+  }
+  int64_t x0 = median(times.begin(), times.begin() + 9);
+  int64_t x1 = median(times.begin() + times.size() - 9, times.end());
+  GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1;
+  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
+  // And we'll probably time out and never get here.  So, this test is
+  // intentionally loose: we check that x0 and x1 are within a factor of 8.
+  EXPECT_GE(x1, x0 / 8);
+  EXPECT_GE(x0, x1 / 8);
+}
+
+// Try to create kTestSize keys that will land in just a few buckets, and
+// time the insertions, to get a rough estimate of whether an O(n^2) worst case
+// was triggered.  This test is a hacky, but probably better than nothing.
+TEST_F(MapImplTest, HashFlood) {
+  const int kTestSize = 1024;  // must be a power of 2
+  std::set<int> s;
+  for (int i = 0; s.size() < kTestSize; i++) {
+    if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) {
+      s.insert(i);
+    }
+  }
+  // Create hash table with kTestSize entries that hash flood a table with
+  // 1024 (or 512 or 2048 or ...) entries.  This assumes that map_ uses powers
+  // of 2 for table sizes, and that it's sufficient to "flood" with respect to
+  // the low bits of the output of map_.hash_function().
+  std::vector<int64_t> times;
+  std::set<int>::iterator it = s.begin();
+  int count = 0;
+  do {
+    const int64_t start = Now();
+    map_[*it] = 0;
+    const int64_t end = Now();
+    if (end > start) {
+      times.push_back(end - start);
+    }
+    ++count;
+    ++it;
+  } while (it != s.end());
+  if (times.size() < .99 * count) return;
+  int64_t x0 = median(times.begin(), times.begin() + 9);
+  int64_t x1 = median(times.begin() + times.size() - 9, times.end());
+  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
+  // But we want to allow O(n log n).  A factor of 20 should be generous enough.
+  EXPECT_LE(x1, x0 * 20);
+}
+
+TEST_F(MapImplTest, CopyIteratorStressTest) {
+  std::vector<Map<int32_t, int32_t>::iterator> v;
+  const int kIters = 1e5;
+  for (uint32_t i = 0; i < kIters; i++) {
+    int32_t key = (3 + i * (5 + i * (-8 + i * (62 + i)))) & 0x77777777;
+    map_[key] = i;
+    v.push_back(map_.find(key));
+  }
+  for (std::vector<Map<int32_t, int32_t>::iterator>::const_iterator it =
+           v.begin();
+       it != v.end(); it++) {
+    Map<int32_t, int32_t>::iterator i = *it;
+    ASSERT_EQ(i->first, (*it)->first);
+    ASSERT_EQ(i->second, (*it)->second);
+  }
+}
+
+template <typename T, typename U>
+static void TestValidityForAllKeysExcept(int key_to_avoid, const T& check_map,
+                                         const U& map) {
+  typedef typename U::value_type value_type;  // a key-value pair
+  for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) {
+    const int key = it->first;
+    if (key == key_to_avoid) continue;
+    // All iterators relevant to this key, whether old (from check_map) or new,
+    // must point to the same memory.  So, test pointer equality here.
+    const value_type* check_val = &*check_map.find(key)->second;
+    EXPECT_EQ(check_val, &*it);
+    EXPECT_EQ(check_val, &*map.find(key));
+  }
+}
+
+// EXPECT i0 and i1 to be the same.  Advancing them should have the same effect,
+// too.
+template <typename Iter>
+static void TestEqualIterators(Iter i0, Iter i1, Iter end) {
+  const int kMaxAdvance = 10;
+  for (int i = 0; i < kMaxAdvance; i++) {
+    EXPECT_EQ(i0 == end, i1 == end);
+    if (i0 == end) return;
+    EXPECT_EQ(&*i0, &*i1) << "iter " << i;
+    ++i0;
+    ++i1;
+  }
+}
+
+template <typename IteratorType>
+static void TestOldVersusNewIterator(int skip, Map<int, int>* m) {
+  const int initial_size = m->size();
+  IteratorType it = m->begin();
+  for (int i = 0; i < skip && it != m->end(); it++, i++) {
+  }
+  if (it == m->end()) return;
+  const IteratorType old = it;
+  GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first;
+  const int target_size =
+      initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4;
+  for (int i = 0; m->size() <= target_size; i++) {
+    (*m)[i] = 0;
+  }
+  // Iterator 'old' should still work just fine despite the growth of *m.
+  const IteratorType after_growth = m->find(old->first);
+  TestEqualIterators<IteratorType>(old, after_growth, m->end());
+
+  // Now shrink the number of elements.  Do this with a mix of erases and
+  // inserts to increase the chance that the hashtable will resize to a lower
+  // number of buckets.  (But, in any case, the test is still useful.)
+  for (int i = 0; i < 2 * (target_size - initial_size); i++) {
+    if (i != old->first) {
+      m->erase(i);
+    }
+    if (((i ^ m->begin()->first) & 15) == 0) {
+      (*m)[i * 342] = i;
+    }
+  }
+  // Now, the table has grown and shrunk; test again.
+  TestEqualIterators<IteratorType>(old, m->find(old->first), m->end());
+  TestEqualIterators<IteratorType>(old, after_growth, m->end());
+}
+
+// Create and test an n-element Map, with emphasis on iterator correctness.
+static void StressTestIterators(int n) {
+  GOOGLE_LOG(INFO) << "StressTestIterators " << n;
+  GOOGLE_CHECK_GT(n, 0);
+  // Create a random-looking map of size n.  Use non-negative integer keys.
+  Map<int, int> m;
+  uint32_t frog = 123987 + n;
+  int last_key = 0;
+  int counter = 0;
+  while (m.size() < n) {
+    frog *= static_cast<uint32_t>(k0);
+    frog ^= frog >> 17;
+    frog += counter++;
+    last_key =
+        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
+    GOOGLE_DCHECK_GE(last_key, 0);
+    m[last_key] = last_key ^ 1;
+  }
+  // Test it.
+  ASSERT_EQ(n, m.size());
+  // Create maps of pointers and iterators.
+  // These should remain valid even if we modify m.
+  std::unordered_map<int, Map<int, int>::value_type*> mp(n);
+  std::unordered_map<int, Map<int, int>::iterator> mi(n);
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
+    mp[it->first] = &*it;
+    mi[it->first] = it;
+  }
+  ASSERT_EQ(m.size(), mi.size());
+  ASSERT_EQ(m.size(), mp.size());
+  m.erase(last_key);
+  ASSERT_EQ(n - 1, m.size());
+  TestValidityForAllKeysExcept(last_key, mp, m);
+  TestValidityForAllKeysExcept(last_key, mi, m);
+
+  m[last_key] = 0;
+  ASSERT_EQ(n, m.size());
+  // Test old iterator vs new iterator, with table modification in between.
+  TestOldVersusNewIterator<Map<int, int>::const_iterator>(n % 3, &m);
+  TestOldVersusNewIterator<Map<int, int>::iterator>(n % (1 + (n / 40)), &m);
+  // Finally, ensure erase(iterator) doesn't reorder anything, because that is
+  // what its documentation says.
+  m[last_key] = m[last_key ^ 999] = 0;
+  std::vector<Map<int, int>::iterator> v;
+  v.reserve(m.size());
+  int position_of_last_key = 0;
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
+    if (it->first == last_key) {
+      position_of_last_key = v.size();
+    }
+    v.push_back(it);
+  }
+  ASSERT_EQ(m.size(), v.size());
+  const Map<int, int>::iterator erase_result = m.erase(m.find(last_key));
+  int index = 0;
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it, ++index) {
+    if (index == position_of_last_key) {
+      EXPECT_EQ(&*erase_result, &*v[++index]);
+    }
+    ASSERT_EQ(&*it, &*v[index]);
+  }
+}
+
+TEST_F(MapImplTest, IteratorInvalidation) {
+  // Create a set of pseudo-random sizes to test.
+#ifndef NDEBUG
+  const int kMaxSizeToTest = 100 * 1000;
+#else
+  const int kMaxSizeToTest = 1000 * 1000;
+#endif
+  std::set<int> s;
+  int n = kMaxSizeToTest;
+  unsigned int frog = k1 + n;
+  while (n > 1 && s.size() < 25) {
+    s.insert(n);
+    n = static_cast<int>(n * 100 / (101.0 + (frog & 63)));
+    frog *= k2;
+    frog ^= frog >> 17;
+  }
+  // Ensure we test a few small sizes.
+  s.insert(1);
+  s.insert(2);
+  s.insert(3);
+  // Now, the real work.
+  for (std::set<int>::iterator i = s.begin(); i != s.end(); ++i) {
+    StressTestIterators(*i);
+  }
+}
+
+// Test that erase() revalidates iterators.
+TEST_F(MapImplTest, EraseRevalidates) {
+  map_[3] = map_[13] = map_[20] = 0;
+  const int initial_size = map_.size();
+  EXPECT_EQ(3, initial_size);
+  std::vector<Map<int, int>::iterator> v;
+  for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) {
+    v.push_back(it);
+  }
+  EXPECT_EQ(initial_size, v.size());
+  for (int i = 0; map_.size() <= initial_size * 20; i++) {
+    map_[i] = 0;
+  }
+  const int larger_size = map_.size();
+  // We've greatly increased the size of the map, so it is highly likely that
+  // the following will corrupt m if erase() doesn't properly revalidate
+  // iterators passed to it.  Finishing this routine without crashing indicates
+  // success.
+  for (int i = 0; i < v.size(); i++) {
+    map_.erase(v[i]);
+  }
+  EXPECT_EQ(larger_size - v.size(), map_.size());
+}
+
+template <typename T>
+bool IsConstHelper(T& /*t*/) {  // NOLINT. We want to catch non-const refs here.
+  return false;
+}
+template <typename T>
+bool IsConstHelper(const T& /*t*/) {
+  return true;
+}
+
+TEST_F(MapImplTest, IteratorConstness) {
+  map_[0] = 0;
+  EXPECT_TRUE(IsConstHelper(*map_.cbegin()));
+  EXPECT_TRUE(IsConstHelper(*const_map_.begin()));
+  EXPECT_FALSE(IsConstHelper(*map_.begin()));
+}
+
+bool IsForwardIteratorHelper(std::forward_iterator_tag /*tag*/) { return true; }
+
+TEST_F(MapImplTest, IteratorCategory) {
+  EXPECT_TRUE(IsForwardIteratorHelper(
+      std::iterator_traits<Map<int, int>::iterator>::iterator_category()));
+  EXPECT_TRUE(IsForwardIteratorHelper(
+      std::iterator_traits<
+          Map<int, int>::const_iterator>::iterator_category()));
+}
+
+TEST_F(MapImplTest, InsertSingleLValue) {
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  // Insert a non-existing key.
+  Map<int32_t, int32_t>::value_type v1(key, value1);
+  std::pair<Map<int32_t, int32_t>::iterator, bool> result1 = map_.insert(v1);
+  ExpectSingleElement(key, value1);
+
+  Map<int32_t, int32_t>::iterator it1 = result1.first;
+  EXPECT_EQ(key, it1->first);
+  EXPECT_EQ(value1, it1->second);
+  EXPECT_TRUE(result1.second);
+
+  // Insert an existing key.
+  Map<int32_t, int32_t>::value_type v2(key, value2);
+  std::pair<Map<int32_t, int32_t>::iterator, bool> result2 = map_.insert(v2);
+  ExpectSingleElement(key, value1);
+
+  Map<int32_t, int32_t>::iterator it2 = result2.first;
+  EXPECT_TRUE(it1 == it2);
+  EXPECT_FALSE(result2.second);
+}
+
+TEST_F(MapImplTest, InsertSingleRValue) {
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  // Insert a non-existing key.
+  std::pair<Map<int32_t, int32_t>::iterator, bool> result1 =
+      map_.insert(Map<int32_t, int32_t>::value_type(key, value1));
+  ExpectSingleElement(key, value1);
+
+  Map<int32_t, int32_t>::iterator it1 = result1.first;
+  EXPECT_EQ(key, it1->first);
+  EXPECT_EQ(value1, it1->second);
+  EXPECT_TRUE(result1.second);
+
+  // Insert an existing key.
+  std::pair<Map<int32_t, int32_t>::iterator, bool> result2 =
+      map_.insert(Map<int32_t, int32_t>::value_type(key, value2));
+  ExpectSingleElement(key, value1);
+
+  Map<int32_t, int32_t>::iterator it2 = result2.first;
+  EXPECT_TRUE(it1 == it2);
+  EXPECT_FALSE(result2.second);
+}
+
+TEST_F(MapImplTest, TryEmplace) {
+  using ::testing::Pair;
+  using ::testing::UnorderedElementsAre;
+
+  Map<int32_t, std::string> m;
+
+  m.try_emplace(1, "one");
+  EXPECT_EQ(m.size(), 1);
+
+  const int32_t key = 42;
+  m.try_emplace(key, 3, 'a');
+  m.try_emplace(2, std::string("two"));
+  EXPECT_THAT(
+      m, UnorderedElementsAre(Pair(1, "one"), Pair(2, "two"), Pair(42, "aaa")));
+}
+
+TEST_F(MapImplTest, Emplace) {
+  using ::testing::Pair;
+  using ::testing::UnorderedElementsAre;
+
+  Map<int32_t, std::string> m;
+
+  m.emplace(1, "one");
+  EXPECT_EQ(m.size(), 1);
+
+  const int32_t key = 42;
+  m.emplace(key, "aaa");
+  m.emplace(2, std::string("two"));
+  EXPECT_THAT(
+      m, UnorderedElementsAre(Pair(1, "one"), Pair(2, "two"), Pair(42, "aaa")));
+}
+
+struct CountedInstance {
+  CountedInstance() { ++num_created; }
+  CountedInstance(const CountedInstance&) : CountedInstance() {}
+  CountedInstance(CountedInstance&&) : CountedInstance() {}
+
+  CountedInstance& operator=(const CountedInstance&) {
+    ++num_assigned;
+    return *this;
+  }
+
+  explicit CountedInstance(int x) : CountedInstance() {}
+
+  static int num_created;
+  static int num_assigned;
+};
+
+int CountedInstance::num_created = 0;
+int CountedInstance::num_assigned = 0;
+
+TEST_F(MapImplTest, TryEmplaceExisting) {
+  Map<int32_t, CountedInstance> m;
+
+  m.try_emplace(1, 1);
+  ASSERT_EQ(m.size(), 1);
+
+  CountedInstance::num_created = 0;
+  CountedInstance::num_assigned = 0;
+  m.try_emplace(1, 123);
+  EXPECT_EQ(m.size(), 1);
+  EXPECT_EQ(CountedInstance::num_created, 0);
+  EXPECT_EQ(CountedInstance::num_assigned, 0);
+}
+
+struct ArenaConstructible {
+  using InternalArenaConstructable_ = void;
+  using DestructorSkippable_ = void;
+
+  ArenaConstructible() = default;
+  ArenaConstructible(const ArenaConstructible&) = default;
+  ArenaConstructible(Arena*) : ArenaConstructible() {}
+
+  ArenaConstructible& operator=(const ArenaConstructible&) = default;
+
+  explicit ArenaConstructible(int) : ArenaConstructible() {}
+
+  Arena* arena() const { return nullptr; }
+
+  CountedInstance unused;
+};
+
+TEST_F(MapImplTest, TryEmplaceArenaConstructible) {
+  ASSERT_TRUE(Arena::is_arena_constructable<ArenaConstructible>::value);
+
+  ArenaConstructible v1, v2;
+
+  Map<int32_t, ArenaConstructible> m;
+
+  // "default" construction
+  CountedInstance::num_created = 0;
+  CountedInstance::num_assigned = 0;
+  m.try_emplace(1);
+  EXPECT_EQ(m.size(), 1);
+  EXPECT_EQ(CountedInstance::num_created, 1);
+  EXPECT_EQ(CountedInstance::num_assigned, 0);
+
+  // "default" construction + copy assignment
+  CountedInstance::num_created = 0;
+  CountedInstance::num_assigned = 0;
+  m.try_emplace(2, v1);
+  EXPECT_EQ(m.size(), 2);
+  EXPECT_EQ(CountedInstance::num_created, 1);
+  EXPECT_EQ(CountedInstance::num_assigned, 1);
+
+  // "default" construction + move assignment
+  CountedInstance::num_created = 0;
+  CountedInstance::num_assigned = 0;
+  m.try_emplace(3, std::move(v2));
+  EXPECT_EQ(m.size(), 3);
+  EXPECT_EQ(CountedInstance::num_created, 1);
+  EXPECT_EQ(CountedInstance::num_assigned, 1);
+
+  // "default" construction + in-place temporary + move assignment
+  CountedInstance::num_created = 0;
+  CountedInstance::num_assigned = 0;
+  m.try_emplace(4, 239);
+  EXPECT_EQ(m.size(), 4);
+  EXPECT_EQ(CountedInstance::num_created, 2);
+  EXPECT_EQ(CountedInstance::num_assigned, 1);
+}
+
+TEST_F(MapImplTest, TryEmplaceExistingArenaConstructible) {
+  ASSERT_TRUE(Arena::is_arena_constructable<ArenaConstructible>::value);
+
+  Map<int32_t, ArenaConstructible> m;
+
+  m.try_emplace(1, 1);
+  ASSERT_EQ(m.size(), 1);
+
+  CountedInstance::num_created = 0;
+  CountedInstance::num_assigned = 0;
+  m.try_emplace(1, 123);
+  EXPECT_EQ(m.size(), 1);
+  EXPECT_EQ(CountedInstance::num_created, 0);
+  EXPECT_EQ(CountedInstance::num_assigned, 0);
+}
+
+TEST_F(MapImplTest, EmplaceSingle) {
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  // Emplace a non-existing key.
+  auto result1 = map_.emplace(key, value1);
+  ExpectSingleElement(key, value1);
+
+  Map<int32_t, int32_t>::iterator it1 = result1.first;
+  EXPECT_EQ(key, it1->first);
+  EXPECT_EQ(value1, it1->second);
+  EXPECT_TRUE(result1.second);
+
+  // Emplace an existing key.
+  auto result2 = map_.emplace(key, value2);
+  ExpectSingleElement(key, value1);
+
+  Map<int32_t, int32_t>::iterator it2 = result2.first;
+  EXPECT_TRUE(it1 == it2);
+  EXPECT_FALSE(result2.second);
+}
+
+TEST_F(MapImplTest, InsertByIterator) {
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1a = 100;
+  int32_t value1b = 101;
+  int32_t value2a = 200;
+  int32_t value2b = 201;
+
+  std::map<int32_t, int32_t> map1;
+  map1[key1] = value1a;
+  map1[key2] = value2a;
+
+  map_.insert(map1.begin(), map1.end());
+  ExpectElements(map1);
+
+  std::map<int32_t, int32_t> map2;
+  map2[key1] = value1b;
+  map2[key2] = value2b;
+
+  map_.insert(map2.begin(), map2.end());
+  ExpectElements(map1);
+}
+
+TEST_F(MapImplTest, InsertByInitializerList) {
+  map_.insert({{1, 100}, {2, 200}});
+  ExpectElements({{1, 100}, {2, 200}});
+
+  map_.insert({{2, 201}, {3, 301}});
+  ExpectElements({{1, 100}, {2, 200}, {3, 301}});
+}
+
+TEST_F(MapImplTest, EraseSingleByKey) {
+  int32_t key = 0;
+  int32_t value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  // Erase an existing key.
+  EXPECT_EQ(1, map_.erase(key));
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+
+  // Erase a non-existing key.
+  EXPECT_EQ(0, map_.erase(key));
+}
+
+TEST_F(MapImplTest, EraseMutipleByKey) {
+  // erase in one specific order to trigger corner cases
+  for (int i = 0; i < 5; i++) {
+    map_[i] = i;
+  }
+
+  map_.erase(0);
+  EXPECT_EQ(4, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(0));
+
+  map_.erase(1);
+  EXPECT_EQ(3, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(1));
+
+  map_.erase(3);
+  EXPECT_EQ(2, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(3));
+
+  map_.erase(4);
+  EXPECT_EQ(1, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(4));
+
+  map_.erase(2);
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(2));
+}
+
+TEST_F(MapImplTest, EraseSingleByIterator) {
+  int32_t key = 0;
+  int32_t value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  Map<int32_t, int32_t>::iterator it = map_.find(key);
+  map_.erase(it);
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, ValidIteratorAfterErase) {
+  for (int i = 0; i < 10; i++) {
+    map_[i] = i;
+  }
+
+  int count = 0;
+
+  for (Map<int32_t, int32_t>::iterator it = map_.begin(); it != map_.end();) {
+    count++;
+    if (it->first % 2 == 1) {
+      map_.erase(it++);
+    } else {
+      ++it;
+    }
+  }
+
+  EXPECT_EQ(10, count);
+  EXPECT_EQ(5, map_.size());
+}
+
+TEST_F(MapImplTest, EraseByIterator) {
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  std::map<int32_t, int32_t> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  map_.insert(map.begin(), map.end());
+  ExpectElements(map);
+
+  map_.erase(map_.begin(), map_.end());
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key1));
+  EXPECT_TRUE(map_.end() == map_.find(key2));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, Clear) {
+  int32_t key = 0;
+  int32_t value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  map_.clear();
+
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+static void CopyConstructorHelper(Arena* arena, Map<int32_t, int32_t>* m) {
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  std::map<int32_t, int32_t> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  m->insert(map.begin(), map.end());
+
+  Map<int32_t, int32_t> other(*m);
+
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_F(MapImplTest, CopyConstructorWithArena) {
+  Arena a;
+  CopyConstructorHelper(&a, &map_);
+}
+
+TEST_F(MapImplTest, CopyConstructorWithoutArena) {
+  CopyConstructorHelper(nullptr, &map_);
+}
+
+TEST_F(MapImplTest, IterConstructor) {
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  std::map<int32_t, int32_t> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  Map<int32_t, int32_t> 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_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
+
+  std::map<int32_t, int32_t> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  map_.insert(map.begin(), map.end());
+
+  Map<int32_t, int32_t> other;
+  int32_t key_other = 123;
+  int32_t value_other = 321;
+  other[key_other] = value_other;
+  EXPECT_EQ(1, other.size());
+
+  other = map_;
+
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+  EXPECT_TRUE(other.find(key_other) == other.end());
+
+  // Self assign
+  other = *&other;  // Avoid -Wself-assign.
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_F(MapImplTest, Rehash) {
+  const int test_size = 50;
+  std::map<int32_t, int32_t> reference_map;
+  for (int i = 0; i < test_size; i++) {
+    reference_map[i] = i;
+  }
+  for (int i = 0; i < test_size; i++) {
+    map_[i] = reference_map[i];
+    EXPECT_EQ(reference_map[i], map_[i]);
+  }
+  for (int i = 0; i < test_size; i++) {
+    map_.erase(i);
+    EXPECT_TRUE(map_.end() == map_.find(i));
+  }
+  EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(MapImplTest, EqualRange) {
+  int key = 100, key_missing = 101;
+  map_[key] = 100;
+
+  std::pair<Map<int32_t, int32_t>::iterator, Map<int32_t, int32_t>::iterator>
+      range = map_.equal_range(key);
+  EXPECT_TRUE(map_.find(key) == range.first);
+  EXPECT_TRUE(++map_.find(key) == range.second);
+
+  range = map_.equal_range(key_missing);
+  EXPECT_TRUE(map_.end() == range.first);
+  EXPECT_TRUE(map_.end() == range.second);
+
+  std::pair<Map<int32_t, int32_t>::const_iterator,
+            Map<int32_t, int32_t>::const_iterator>
+      const_range = const_map_.equal_range(key);
+  EXPECT_TRUE(const_map_.find(key) == const_range.first);
+  EXPECT_TRUE(++const_map_.find(key) == const_range.second);
+
+  const_range = const_map_.equal_range(key_missing);
+  EXPECT_TRUE(const_map_.end() == const_range.first);
+  EXPECT_TRUE(const_map_.end() == const_range.second);
+}
+
+TEST_F(MapImplTest, ConvertToStdMap) {
+  map_[100] = 101;
+  std::map<int32_t, int32_t> std_map(map_.begin(), map_.end());
+  EXPECT_EQ(1, std_map.size());
+  EXPECT_EQ(101, std_map[100]);
+}
+
+TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
+  map_[100] = 101;
+  std::vector<std::pair<int32_t, int32_t>> std_vec(map_.begin(), map_.end());
+  EXPECT_EQ(1, std_vec.size());
+  EXPECT_EQ(100, std_vec[0].first);
+  EXPECT_EQ(101, std_vec[0].second);
+}
+
+TEST_F(MapImplTest, SwapBasic) {
+  Map<int32_t, int32_t> another;
+  map_[9398] = 41999;
+  another[9398] = 41999;
+  another[8070] = 42056;
+  another.swap(map_);
+  EXPECT_THAT(another,
+              testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
+                                                  testing::Pair(9398, 41999)));
+}
+
+TEST_F(MapImplTest, SwapArena) {
+  Arena arena1, arena2;
+  Map<int32_t, int32_t> m1(&arena1);
+  Map<int32_t, int32_t> m2(&arena2);
+  map_[9398] = 41999;
+  m1[9398] = 41999;
+  m1[8070] = 42056;
+  m2[10244] = 10247;
+  m2[8070] = 42056;
+  m1.swap(map_);
+  EXPECT_THAT(m1, testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
+                                                  testing::Pair(9398, 41999)));
+  m2.swap(m1);
+  EXPECT_THAT(m1, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
+                                                testing::Pair(10244, 10247)));
+  EXPECT_THAT(m2, testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
+}
+
+TEST_F(MapImplTest, SwapFieldArenaReflection) {
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  Arena arena;
+
+  {
+    // Tests filled lfs and empty rhs.
+    TestMap rhs;
+
+    {
+      // Use local_arena to allocate lhs to trigger use-after-free error.
+      Arena local_arena;
+      auto* lhs = Arena::CreateMessage<TestMap>(&local_arena);
+      const auto* reflection = lhs->GetReflection();
+      std::vector<const FieldDescriptor*> fields;
+
+      reflection_tester.SetMapFieldsViaReflection(lhs);
+      reflection->ListFields(*lhs, &fields);
+
+      reflection->SwapFields(lhs, &rhs, fields);
+
+      reflection_tester.ExpectClearViaReflection(*lhs);
+    }
+
+    reflection_tester.ExpectMapFieldsSetViaReflection(rhs);
+  }
+}
+
+TEST_F(MapImplTest, CopyAssignMapIterator) {
+  TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  MapIterator it1 = reflection_tester.MapBegin(&message, "map_int32_int32");
+  MapIterator it2 = reflection_tester.MapEnd(&message, "map_int32_int32");
+  it2 = it1;
+  EXPECT_EQ(it1.GetKey().GetInt32Value(), it2.GetKey().GetInt32Value());
+}
+
+TEST_F(MapImplTest, SpaceUsed) {
+  constexpr size_t kMinCap = 8;
+
+  Map<int32_t, int32_t> m;
+  // An newly constructed map should have no space used.
+  EXPECT_EQ(m.SpaceUsedExcludingSelfLong(), 0);
+
+  size_t capacity = kMinCap;
+  for (int i = 0; i < 100; ++i) {
+    m[i];
+    static constexpr double kMaxLoadFactor = .75;
+    if (m.size() >= capacity * kMaxLoadFactor) {
+      capacity *= 2;
+    }
+    EXPECT_EQ(
+        m.SpaceUsedExcludingSelfLong(),
+        sizeof(void*) * capacity +
+            m.size() * sizeof(std::pair<std::pair<int32_t, int32_t>, void*>));
+  }
+
+  // Test string, and non-scalar keys.
+  Map<std::string, int32_t> m2;
+  std::string str = "Some arbitrarily large string";
+  m2[str] = 1;
+  EXPECT_EQ(m2.SpaceUsedExcludingSelfLong(),
+            sizeof(void*) * kMinCap +
+                sizeof(std::pair<std::pair<std::string, int32_t>, void*>) +
+                internal::StringSpaceUsedExcludingSelfLong(str));
+
+  // Test messages, and non-scalar values.
+  Map<int32_t, TestAllTypes> m3;
+  m3[0].set_optional_string(str);
+  EXPECT_EQ(m3.SpaceUsedExcludingSelfLong(),
+            sizeof(void*) * kMinCap +
+                sizeof(std::pair<std::pair<int32_t, TestAllTypes>, void*>) +
+                m3[0].SpaceUsedLong() - sizeof(m3[0]));
+}
+
+// Attempts to verify that a map with keys a and b has a random ordering. This
+// function returns true if it succeeds in observing both possible orderings.
+bool MapOrderingIsRandom(int a, int b) {
+  bool saw_a_first = false;
+  bool saw_b_first = false;
+  std::vector<Map<int32_t, int32_t>> v(50);
+  for (int i = 0; i < 50; ++i) {
+    Map<int32_t, int32_t>& m = v[i];
+    m[a] = 0;
+    m[b] = 0;
+    int32_t first_element = m.begin()->first;
+    if (first_element == a) saw_a_first = true;
+    if (first_element == b) saw_b_first = true;
+    if (saw_a_first && saw_b_first) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// This test verifies that the iteration order is reasonably random even for
+// small maps.
+TEST_F(MapImplTest, RandomOrdering) {
+  for (int i = 0; i < 10; ++i) {
+    for (int j = i + 1; j < 10; ++j) {
+      EXPECT_TRUE(MapOrderingIsRandom(i, j))
+          << "Map with keys " << i << " and " << j
+          << " has deterministic ordering";
+    }
+  }
+}
+
+template <typename Key>
+void TestTransparent(const Key& key, const Key& miss_key) {
+  Map<std::string, int> m;
+  const auto& cm = m;
+
+  m.insert({"ABC", 1});
+
+  const auto abc_it = m.begin();
+
+  m.insert({"DEF", 2});
+
+  using testing::Pair;
+  using testing::UnorderedElementsAre;
+
+  EXPECT_EQ(m.at(key), 1);
+  EXPECT_EQ(cm.at(key), 1);
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  EXPECT_DEATH(m.at(miss_key), "");
+  EXPECT_DEATH(cm.at(miss_key), "");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+  EXPECT_EQ(m.count(key), 1);
+  EXPECT_EQ(cm.count(key), 1);
+  EXPECT_EQ(m.count(miss_key), 0);
+  EXPECT_EQ(cm.count(miss_key), 0);
+
+  EXPECT_EQ(m.find(key), abc_it);
+  EXPECT_EQ(cm.find(key), abc_it);
+  EXPECT_EQ(m.find(miss_key), m.end());
+  EXPECT_EQ(cm.find(miss_key), cm.end());
+
+  EXPECT_TRUE(m.contains(key));
+  EXPECT_TRUE(cm.contains(key));
+  EXPECT_FALSE(m.contains(miss_key));
+  EXPECT_FALSE(cm.contains(miss_key));
+
+  EXPECT_THAT(m.equal_range(key), Pair(abc_it, std::next(abc_it)));
+  EXPECT_THAT(cm.equal_range(key), Pair(abc_it, std::next(abc_it)));
+  EXPECT_THAT(m.equal_range(miss_key), Pair(m.end(), m.end()));
+  EXPECT_THAT(cm.equal_range(miss_key), Pair(m.end(), m.end()));
+
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
+  EXPECT_EQ(m.erase(key), 1);
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
+  EXPECT_EQ(m.erase(key), 0);
+  EXPECT_EQ(m.erase(miss_key), 0);
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
+
+  m[key];
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 0), Pair("DEF", 2)));
+  m[key] = 1;
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
+}
+
+TEST_F(MapImplTest, TransparentLookupForString) {
+  TestTransparent("ABC", "LKJ");
+  TestTransparent(std::string("ABC"), std::string("LKJ"));
+#if defined(__cpp_lib_string_view)
+  TestTransparent(std::string_view("ABC"), std::string_view("LKJ"));
+#endif  // defined(__cpp_lib_string_view)
+
+  // std::reference_wrapper
+  std::string abc = "ABC", lkj = "LKJ";
+  TestTransparent(std::ref(abc), std::ref(lkj));
+  TestTransparent(std::cref(abc), std::cref(lkj));
+}
+
+TEST_F(MapImplTest, ConstInit) {
+  PROTOBUF_CONSTINIT static Map<int, int> map;  // NOLINT
+  EXPECT_TRUE(map.empty());
+}
+
+// Map Field Reflection Test ========================================
+
+static int Func(int i, int j) { return i * j; }
+
+static std::string StrFunc(int i, int j) { return StrCat(Func(i, j)); }
+
+static int Int(const std::string& value) {
+  int result = 0;
+  std::istringstream(value) >> result;
+  return result;
+}
+
+}  // namespace
+
+// This class is a friend, so no anonymous namespace.
+class MapFieldReflectionTest : public testing::Test {
+ protected:
+  typedef FieldDescriptor FD;
+
+  int MapSize(const Reflection* reflection, const FieldDescriptor* field,
+              const Message& message) {
+    return reflection->MapSize(message, field);
+  }
+};
+
+namespace {
+
+TEST_F(MapFieldReflectionTest, RegularFields) {
+  TestMap message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  Map<int32_t, int32_t>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32_t, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<std::string, std::string>* map_string_string =
+      message.mutable_map_string_string();
+  Map<int32_t, ForeignMessage>* map_int32_foreign_message =
+      message.mutable_map_int32_foreign_message();
+
+  for (int i = 0; i < 10; ++i) {
+    (*map_int32_int32)[i] = Func(i, 1);
+    (*map_int32_double)[i] = Func(i, 2);
+    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  const FieldDescriptor* fd_map_int32_in32_key =
+      fd_map_int32_int32->message_type()->map_key();
+  const FieldDescriptor* fd_map_int32_in32_value =
+      fd_map_int32_int32->message_type()->map_value();
+  const FieldDescriptor* fd_map_int32_double_key =
+      fd_map_int32_double->message_type()->map_key();
+  const FieldDescriptor* fd_map_int32_double_value =
+      fd_map_int32_double->message_type()->map_value();
+  const FieldDescriptor* fd_map_string_string_key =
+      fd_map_string_string->message_type()->map_key();
+  const FieldDescriptor* fd_map_string_string_value =
+      fd_map_string_string->message_type()->map_value();
+  const FieldDescriptor* fd_map_int32_foreign_message_key =
+      fd_map_int32_foreign_message->message_type()->map_key();
+  const FieldDescriptor* fd_map_int32_foreign_message_value =
+      fd_map_int32_foreign_message->message_type()->map_value();
+
+  // Get RepeatedPtrField objects for all fields of interest.
+  const RepeatedPtrField<Message>& mf_int32_int32 =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_int32);
+  const RepeatedPtrField<Message>& mf_int32_double =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_double);
+  const RepeatedPtrField<Message>& mf_string_string =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_string_string);
+  const RepeatedPtrField<Message>& mf_int32_foreign_message =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_foreign_message);
+
+  // Get mutable RepeatedPtrField objects for all fields of interest.
+  RepeatedPtrField<Message>* mmf_int32_int32 =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_int32);
+  RepeatedPtrField<Message>* mmf_int32_double =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_double);
+  RepeatedPtrField<Message>* mmf_string_string =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_string_string);
+  RepeatedPtrField<Message>* mmf_int32_foreign_message =
+      refl->MutableRepeatedPtrField<Message>(&message,
+                                             fd_map_int32_foreign_message);
+
+  // Make sure we can do gets through the RepeatedPtrField objects.
+  for (int i = 0; i < 10; ++i) {
+    {
+      // Check gets through const objects.
+      const Message& message_int32_int32 = mf_int32_int32.Get(i);
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double = mf_int32_double.Get(i);
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string = mf_string_string.Get(i);
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message = mf_int32_foreign_message.Get(i);
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+
+    {
+      // Check gets through mutable objects.
+      const Message& message_int32_int32 = mmf_int32_int32->Get(i);
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double = mmf_int32_double->Get(i);
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string = mmf_string_string->Get(i);
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message = mmf_int32_foreign_message->Get(i);
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+  }
+
+  // Do sets through the RepeatedPtrField objects.
+  for (int i = 0; i < 10; i++) {
+    {
+      Message* message_int32_int32 = mmf_int32_int32->Mutable(i);
+      int32_t key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
+          *message_int32_int32, fd_map_int32_in32_key);
+      message_int32_int32->GetReflection()->SetInt32(message_int32_int32,
+                                                     fd_map_int32_in32_value,
+                                                     Func(key_int32_int32, -1));
+
+      Message* message_int32_double = mmf_int32_double->Mutable(i);
+      int32_t key_int32_double =
+          message_int32_double->GetReflection()->GetInt32(
+              *message_int32_double, fd_map_int32_double_key);
+      message_int32_double->GetReflection()->SetDouble(
+          message_int32_double, fd_map_int32_double_value,
+          Func(key_int32_double, -2));
+
+      Message* message_string_string = mmf_string_string->Mutable(i);
+      std::string key_string_string =
+          message_string_string->GetReflection()->GetString(
+              *message_string_string, fd_map_string_string_key);
+      message_string_string->GetReflection()->SetString(
+          message_string_string, fd_map_string_string_value,
+          StrFunc(Int(key_string_string), -5));
+
+      Message* message_int32_message = mmf_int32_foreign_message->Mutable(i);
+      int32_t key_int32_message =
+          message_int32_message->GetReflection()->GetInt32(
+              *message_int32_message, fd_map_int32_foreign_message_key);
+      ForeignMessage* value_int32_message = down_cast<ForeignMessage*>(
+          message_int32_message->GetReflection()->MutableMessage(
+              message_int32_message, fd_map_int32_foreign_message_value));
+      value_int32_message->set_c(Func(key_int32_message, -6));
+    }
+  }
+
+  // Check gets through mutable objects.
+  for (int i = 0; i < 10; i++) {
+    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+  }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+  TestMap message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  Map<int32_t, int32_t>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32_t, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<std::string, std::string>* map_string_string =
+      message.mutable_map_string_string();
+  Map<int32_t, ForeignMessage>* map_int32_foreign_message =
+      message.mutable_map_int32_foreign_message();
+
+  for (int i = 0; i < 10; ++i) {
+    (*map_int32_int32)[i] = Func(i, 1);
+    (*map_int32_double)[i] = Func(i, 2);
+    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  const FieldDescriptor* fd_map_int32_in32_key =
+      fd_map_int32_int32->message_type()->map_key();
+  const FieldDescriptor* fd_map_int32_in32_value =
+      fd_map_int32_int32->message_type()->map_value();
+  const FieldDescriptor* fd_map_int32_double_key =
+      fd_map_int32_double->message_type()->map_key();
+  const FieldDescriptor* fd_map_int32_double_value =
+      fd_map_int32_double->message_type()->map_value();
+  const FieldDescriptor* fd_map_string_string_key =
+      fd_map_string_string->message_type()->map_key();
+  const FieldDescriptor* fd_map_string_string_value =
+      fd_map_string_string->message_type()->map_value();
+  const FieldDescriptor* fd_map_int32_foreign_message_key =
+      fd_map_int32_foreign_message->message_type()->map_key();
+  const FieldDescriptor* fd_map_int32_foreign_message_value =
+      fd_map_int32_foreign_message->message_type()->map_value();
+
+  // Get RepeatedFieldRef objects for all fields of interest.
+  const RepeatedFieldRef<Message> mf_int32_int32 =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_int32);
+  const RepeatedFieldRef<Message> mf_int32_double =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_double);
+  const RepeatedFieldRef<Message> mf_string_string =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_string_string);
+  const RepeatedFieldRef<Message> mf_int32_foreign_message =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_foreign_message);
+
+  // Get mutable RepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_int32);
+  const MutableRepeatedFieldRef<Message> mmf_int32_double =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_double);
+  const MutableRepeatedFieldRef<Message> mmf_string_string =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_string_string);
+  const MutableRepeatedFieldRef<Message> mmf_int32_foreign_message =
+      refl->GetMutableRepeatedFieldRef<Message>(&message,
+                                                fd_map_int32_foreign_message);
+
+  // Get entry default instances
+  std::unique_ptr<Message> entry_int32_int32(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_int32->message_type())
+          ->New(message.GetArena()));
+  std::unique_ptr<Message> entry_int32_double(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_double->message_type())
+          ->New(message.GetArena()));
+  std::unique_ptr<Message> entry_string_string(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_string_string->message_type())
+          ->New(message.GetArena()));
+  std::unique_ptr<Message> entry_int32_foreign_message(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_foreign_message->message_type())
+          ->New(message.GetArena()));
+
+  EXPECT_EQ(10, mf_int32_int32.size());
+  EXPECT_EQ(10, mmf_int32_int32.size());
+  EXPECT_EQ(10, mf_int32_double.size());
+  EXPECT_EQ(10, mmf_int32_double.size());
+  EXPECT_EQ(10, mf_string_string.size());
+  EXPECT_EQ(10, mmf_string_string.size());
+  EXPECT_EQ(10, mf_int32_foreign_message.size());
+  EXPECT_EQ(10, mmf_int32_foreign_message.size());
+
+  EXPECT_FALSE(mf_int32_int32.empty());
+  EXPECT_FALSE(mmf_int32_int32.empty());
+  EXPECT_FALSE(mf_int32_double.empty());
+  EXPECT_FALSE(mmf_int32_double.empty());
+  EXPECT_FALSE(mf_string_string.empty());
+  EXPECT_FALSE(mmf_string_string.empty());
+  EXPECT_FALSE(mf_int32_foreign_message.empty());
+  EXPECT_FALSE(mmf_int32_foreign_message.empty());
+
+  // Make sure we can do gets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; ++i) {
+    {
+      // Check gets through const objects.
+      const Message& message_int32_int32 =
+          mf_int32_int32.Get(i, entry_int32_int32.get());
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double =
+          mf_int32_double.Get(i, entry_int32_double.get());
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string =
+          mf_string_string.Get(i, entry_string_string.get());
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message =
+          mf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+
+    {
+      // Check gets through mutable objects.
+      const Message& message_int32_int32 =
+          mmf_int32_int32.Get(i, entry_int32_int32.get());
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double =
+          mmf_int32_double.Get(i, entry_int32_double.get());
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string =
+          mmf_string_string.Get(i, entry_string_string.get());
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message =
+          mmf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+  }
+
+  // Make sure we can do sets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; i++) {
+    const Message& message_int32_int32 =
+        mmf_int32_int32.Get(i, entry_int32_int32.get());
+    int key = message_int32_int32.GetReflection()->GetInt32(
+        message_int32_int32, fd_map_int32_in32_key);
+
+    entry_int32_int32->GetReflection()->SetInt32(
+        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+        key);
+    entry_int32_int32->GetReflection()->SetInt32(
+        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+        Func(key, -1));
+    entry_int32_double->GetReflection()->SetInt32(
+        entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+        key);
+    entry_int32_double->GetReflection()->SetDouble(
+        entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+        Func(key, -2));
+    entry_string_string->GetReflection()->SetString(
+        entry_string_string.get(),
+        fd_map_string_string->message_type()->field(0), StrFunc(key, 1));
+    entry_string_string->GetReflection()->SetString(
+        entry_string_string.get(),
+        fd_map_string_string->message_type()->field(1), StrFunc(key, -5));
+    entry_int32_foreign_message->GetReflection()->SetInt32(
+        entry_int32_foreign_message.get(),
+        fd_map_int32_foreign_message->message_type()->field(0), key);
+    Message* value_message =
+        entry_int32_foreign_message->GetReflection()->MutableMessage(
+            entry_int32_foreign_message.get(),
+            fd_map_int32_foreign_message->message_type()->field(1));
+    value_message->GetReflection()->SetInt32(
+        value_message, value_message->GetDescriptor()->FindFieldByName("c"),
+        Func(key, -6));
+
+    mmf_int32_int32.Set(i, *entry_int32_int32);
+    mmf_int32_double.Set(i, *entry_int32_double);
+    mmf_string_string.Set(i, *entry_string_string);
+    mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+  }
+
+  // Test iterators.
+  {
+    int index = 0;
+    std::unordered_map<int32_t, int32_t> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_int32_int32.begin();
+         it != mf_int32_int32.end(); ++it) {
+      const Message& message = *it;
+      int32_t key =
+          message.GetReflection()->GetInt32(message, fd_map_int32_in32_key);
+      int32_t value =
+          message.GetReflection()->GetInt32(message, fd_map_int32_in32_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::unordered_map<int32_t, int32_t>::const_iterator it =
+             result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_int32().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::unordered_map<int32_t, double> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_int32_double.begin();
+         it != mf_int32_double.end(); ++it) {
+      const Message& message = *it;
+      int32_t key =
+          message.GetReflection()->GetInt32(message, fd_map_int32_double_key);
+      double value = message.GetReflection()->GetDouble(
+          message, fd_map_int32_double_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::unordered_map<int32_t, double>::const_iterator it =
+             result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_double().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::unordered_map<std::string, std::string> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_string_string.begin();
+         it != mf_string_string.end(); ++it) {
+      const Message& message = *it;
+      std::string key =
+          message.GetReflection()->GetString(message, fd_map_string_string_key);
+      std::string value = message.GetReflection()->GetString(
+          message, fd_map_string_string_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::unordered_map<std::string, std::string>::const_iterator it =
+             result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_string_string().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::map<int32_t, ForeignMessage> result;
+    for (RepeatedFieldRef<Message>::iterator it =
+             mf_int32_foreign_message.begin();
+         it != mf_int32_foreign_message.end(); ++it) {
+      const Message& message = *it;
+      int32_t key = message.GetReflection()->GetInt32(
+          message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& sub_message =
+          down_cast<const ForeignMessage&>(message.GetReflection()->GetMessage(
+              message, fd_map_int32_foreign_message_value));
+      result[key].MergeFrom(sub_message);
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::map<int32_t, ForeignMessage>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_foreign_message().at(it->first).c(),
+                it->second.c());
+    }
+  }
+
+  // Test MutableRepeatedFieldRef::Add()
+  entry_int32_int32->GetReflection()->SetInt32(
+      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+      4321);
+  entry_int32_int32->GetReflection()->SetInt32(
+      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+      1234);
+  mmf_int32_int32.Add(*entry_int32_int32);
+  EXPECT_EQ(1234, message.map_int32_int32().at(4321));
+
+  entry_int32_double->GetReflection()->SetInt32(
+      entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+      4321);
+  entry_int32_double->GetReflection()->SetDouble(
+      entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+      1234.0);
+  mmf_int32_double.Add(*entry_int32_double);
+  EXPECT_EQ(1234.0, message.map_int32_double().at(4321));
+
+  entry_string_string->GetReflection()->SetString(
+      entry_string_string.get(), fd_map_string_string->message_type()->field(0),
+      "4321");
+  entry_string_string->GetReflection()->SetString(
+      entry_string_string.get(), fd_map_string_string->message_type()->field(1),
+      "1234");
+  mmf_string_string.Add(*entry_string_string);
+  EXPECT_EQ("1234", message.map_string_string().at("4321"));
+
+  entry_int32_foreign_message->GetReflection()->SetInt32(
+      entry_int32_foreign_message.get(),
+      fd_map_int32_foreign_message->message_type()->field(0), 4321);
+  Message* value_message =
+      entry_int32_foreign_message->GetReflection()->MutableMessage(
+          entry_int32_foreign_message.get(),
+          fd_map_int32_foreign_message->message_type()->field(1));
+  ForeignMessage foreign_message;
+  foreign_message.set_c(1234);
+  value_message->CopyFrom(foreign_message);
+
+  mmf_int32_foreign_message.Add(*entry_int32_foreign_message);
+  EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c());
+
+  // Test Reflection::AddAllocatedMessage
+  Message* free_entry_string_string =
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_string_string->message_type())
+          ->New();
+  entry_string_string->GetReflection()->SetString(
+      free_entry_string_string, fd_map_string_string->message_type()->field(0),
+      "4321");
+  entry_string_string->GetReflection()->SetString(
+      free_entry_string_string, fd_map_string_string->message_type()->field(1),
+      "1234");
+  refl->AddAllocatedMessage(&message, fd_map_string_string,
+                            free_entry_string_string);
+
+  // Test MutableRepeatedFieldRef::RemoveLast()
+  mmf_int32_int32.RemoveLast();
+  mmf_int32_double.RemoveLast();
+  mmf_string_string.RemoveLast();
+  mmf_int32_foreign_message.RemoveLast();
+  EXPECT_EQ(10, message.map_int32_int32().size());
+  EXPECT_EQ(10, message.map_int32_double().size());
+  EXPECT_EQ(11, message.map_string_string().size());
+  EXPECT_EQ(10, message.map_int32_foreign_message().size());
+
+  // Test MutableRepeatedFieldRef::SwapElements()
+  {
+    const Message& message0a = mmf_int32_int32.Get(0, entry_int32_int32.get());
+    int32_t int32_value0a =
+        message0a.GetReflection()->GetInt32(message0a, fd_map_int32_in32_value);
+    const Message& message9a = mmf_int32_int32.Get(9, entry_int32_int32.get());
+    int32_t int32_value9a =
+        message9a.GetReflection()->GetInt32(message9a, fd_map_int32_in32_value);
+
+    mmf_int32_int32.SwapElements(0, 9);
+
+    const Message& message0b = mmf_int32_int32.Get(0, entry_int32_int32.get());
+    int32_t int32_value0b =
+        message0b.GetReflection()->GetInt32(message0b, fd_map_int32_in32_value);
+    const Message& message9b = mmf_int32_int32.Get(9, entry_int32_int32.get());
+    int32_t int32_value9b =
+        message9b.GetReflection()->GetInt32(message9b, fd_map_int32_in32_value);
+
+    EXPECT_EQ(int32_value9a, int32_value0b);
+    EXPECT_EQ(int32_value0a, int32_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_int32_double.Get(0, entry_int32_double.get());
+    double double_value0a = message0a.GetReflection()->GetDouble(
+        message0a, fd_map_int32_double_value);
+    const Message& message9a =
+        mmf_int32_double.Get(9, entry_int32_double.get());
+    double double_value9a = message9a.GetReflection()->GetDouble(
+        message9a, fd_map_int32_double_value);
+
+    mmf_int32_double.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_int32_double.Get(0, entry_int32_double.get());
+    double double_value0b = message0b.GetReflection()->GetDouble(
+        message0b, fd_map_int32_double_value);
+    const Message& message9b =
+        mmf_int32_double.Get(9, entry_int32_double.get());
+    double double_value9b = message9b.GetReflection()->GetDouble(
+        message9b, fd_map_int32_double_value);
+
+    EXPECT_EQ(double_value9a, double_value0b);
+    EXPECT_EQ(double_value0a, double_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_string_string.Get(0, entry_string_string.get());
+    std::string string_value0a = message0a.GetReflection()->GetString(
+        message0a, fd_map_string_string_value);
+    const Message& message9a =
+        mmf_string_string.Get(9, entry_string_string.get());
+    std::string string_value9a = message9a.GetReflection()->GetString(
+        message9a, fd_map_string_string_value);
+
+    mmf_string_string.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_string_string.Get(0, entry_string_string.get());
+    std::string string_value0b = message0b.GetReflection()->GetString(
+        message0b, fd_map_string_string_value);
+    const Message& message9b =
+        mmf_string_string.Get(9, entry_string_string.get());
+    std::string string_value9b = message9b.GetReflection()->GetString(
+        message9b, fd_map_string_string_value);
+
+    EXPECT_EQ(string_value9a, string_value0b);
+    EXPECT_EQ(string_value0a, string_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message0a =
+        down_cast<const ForeignMessage&>(message0a.GetReflection()->GetMessage(
+            message0a, fd_map_int32_foreign_message_value));
+    int32_t int32_value0a = sub_message0a.c();
+    const Message& message9a =
+        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message9a =
+        down_cast<const ForeignMessage&>(message9a.GetReflection()->GetMessage(
+            message9a, fd_map_int32_foreign_message_value));
+    int32_t int32_value9a = sub_message9a.c();
+
+    mmf_int32_foreign_message.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message0b =
+        down_cast<const ForeignMessage&>(message0b.GetReflection()->GetMessage(
+            message0b, fd_map_int32_foreign_message_value));
+    int32_t int32_value0b = sub_message0b.c();
+    const Message& message9b =
+        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message9b =
+        down_cast<const ForeignMessage&>(message9b.GetReflection()->GetMessage(
+            message9b, fd_map_int32_foreign_message_value));
+    int32_t int32_value9b = sub_message9b.c();
+
+    EXPECT_EQ(int32_value9a, int32_value0b);
+    EXPECT_EQ(int32_value0a, int32_value9b);
+  }
+
+  // TODO(b/181148674): After supporting arena agnostic delete or let map entry
+  // handle heap allocation, this could be removed.
+  if (message.GetArena() != nullptr) {
+    entry_int32_int32.release();
+    entry_int32_double.release();
+    entry_string_string.release();
+    entry_int32_foreign_message.release();
+  }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+  // Set-up message content.
+  TestMap m0, m1, m2;
+  for (int i = 0; i < 10; ++i) {
+    (*m0.mutable_map_int32_int32())[i] = Func(i, 1);
+    (*m0.mutable_map_int32_double())[i] = Func(i, 2);
+    (*m0.mutable_map_string_string())[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*m0.mutable_map_int32_foreign_message())[i].set_c(Func(i, 6));
+    (*m1.mutable_map_int32_int32())[i + 10] = Func(i, 11);
+    (*m1.mutable_map_int32_double())[i + 10] = Func(i, 12);
+    (*m1.mutable_map_string_string())[StrFunc(i + 10, 1)] = StrFunc(i, 15);
+    (*m1.mutable_map_int32_foreign_message())[i + 10].set_c(Func(i, 16));
+    (*m2.mutable_map_int32_int32())[i + 20] = Func(i, 21);
+    (*m2.mutable_map_int32_double())[i + 20] = Func(i, 22);
+    (*m2.mutable_map_string_string())[StrFunc(i + 20, 1)] = StrFunc(i, 25);
+    (*m2.mutable_map_int32_foreign_message())[i + 20].set_c(Func(i, 26));
+  }
+
+  const Reflection* refl = m0.GetReflection();
+  const Descriptor* desc = m0.GetDescriptor();
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_int32_int32);
+  const MutableRepeatedFieldRef<Message> mmf_int32_double =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_int32_double);
+  const MutableRepeatedFieldRef<Message> mmf_string_string =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_string_string);
+  const MutableRepeatedFieldRef<Message> mmf_int32_foreign_message =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0,
+                                                fd_map_int32_foreign_message);
+
+  // Test MutableRepeatedRef::CopyFrom
+  mmf_int32_int32.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_int32));
+  mmf_int32_double.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_double));
+  mmf_string_string.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_string_string));
+  mmf_int32_foreign_message.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_foreign_message));
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 11), m0.map_int32_int32().at(i + 10));
+    EXPECT_EQ(Func(i, 12), m0.map_int32_double().at(i + 10));
+    EXPECT_EQ(StrFunc(i, 15), m0.map_string_string().at(StrFunc(i + 10, 1)));
+    EXPECT_EQ(Func(i, 16), m0.map_int32_foreign_message().at(i + 10).c());
+  }
+
+  // Test MutableRepeatedRef::MergeFrom
+  mmf_int32_int32.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_int32));
+  mmf_int32_double.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_double));
+  mmf_string_string.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_string_string));
+  mmf_int32_foreign_message.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_foreign_message));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+  }
+
+  // Test MutableRepeatedRef::Swap
+  // Swap between m0 and m2.
+  mmf_int32_int32.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_int32_int32));
+  mmf_int32_double.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_int32_double));
+  mmf_string_string.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_string_string));
+  mmf_int32_foreign_message.Swap(refl->GetMutableRepeatedFieldRef<Message>(
+      &m2, fd_map_int32_foreign_message));
+  for (int i = 0; i < 10; ++i) {
+    // Check the content of m0.
+    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+
+    // Check the content of m2.
+    EXPECT_EQ(Func(i, 11), m2.map_int32_int32().at(i + 10));
+    EXPECT_EQ(Func(i, 12), m2.map_int32_double().at(i + 10));
+    EXPECT_EQ(StrFunc(i, 15), m2.map_string_string().at(StrFunc(i + 10, 1)));
+    EXPECT_EQ(Func(i, 16), m2.map_int32_foreign_message().at(i + 10).c());
+    EXPECT_EQ(Func(i, 21), m2.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m2.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m2.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m2.map_int32_foreign_message().at(i + 20).c());
+  }
+
+  // TODO(teboring): add test for duplicated key
+}
+
+TEST_F(MapFieldReflectionTest, MapSizeWithDuplicatedKey) {
+  // Dynamic Message
+  {
+    DynamicMessageFactory factory;
+    std::unique_ptr<Message> message(
+        factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+    const Reflection* reflection = message->GetReflection();
+    const FieldDescriptor* field =
+        UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+
+    Message* entry1 = reflection->AddMessage(message.get(), field);
+    Message* entry2 = reflection->AddMessage(message.get(), field);
+
+    const Reflection* entry_reflection = entry1->GetReflection();
+    const FieldDescriptor* key_field = entry1->GetDescriptor()->map_key();
+    entry_reflection->SetInt32(entry1, key_field, 1);
+    entry_reflection->SetInt32(entry2, key_field, 1);
+
+    EXPECT_EQ(2, reflection->FieldSize(*message, field));
+    EXPECT_EQ(1, MapSize(reflection, field, *message));
+    EXPECT_EQ(2, reflection->FieldSize(*message, field));
+  }
+
+  // Generated Message
+  {
+    UNITTEST::TestMap message;
+    const Reflection* reflection = message.GetReflection();
+    const FieldDescriptor* field =
+        message.GetDescriptor()->FindFieldByName("map_int32_int32");
+
+    Message* entry1 = reflection->AddMessage(&message, field);
+    Message* entry2 = reflection->AddMessage(&message, field);
+
+    const Reflection* entry_reflection = entry1->GetReflection();
+    const FieldDescriptor* key_field = entry1->GetDescriptor()->map_key();
+    entry_reflection->SetInt32(entry1, key_field, 1);
+    entry_reflection->SetInt32(entry2, key_field, 1);
+
+    EXPECT_EQ(2, reflection->FieldSize(message, field));
+    EXPECT_EQ(1, MapSize(reflection, field, message));
+  }
+}
+
+TEST_F(MapFieldReflectionTest, UninitializedEntry) {
+  UNITTEST::TestRequiredMessageMap message;
+  const Reflection* reflection = message.GetReflection();
+  const FieldDescriptor* field =
+      message.GetDescriptor()->FindFieldByName("map_field");
+  auto entry = reflection->AddMessage(&message, field);
+  EXPECT_FALSE(entry->IsInitialized());
+  EXPECT_FALSE(message.IsInitialized());
+}
+
+class MyMapEntry
+    : public internal::MapEntry<MyMapEntry, ::int32_t, ::int32_t,
+                                internal::WireFormatLite::TYPE_INT32,
+                                internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapEntry() {}
+  MyMapEntry(Arena*) { std::abort(); }
+  Metadata GetMetadata() const override { std::abort(); }
+  static bool ValidateKey(void*) { return true; }
+  static bool ValidateValue(void*) { return true; }
+};
+
+class MyMapEntryLite
+    : public internal::MapEntryLite<MyMapEntryLite, ::int32_t, ::int32_t,
+                                    internal::WireFormatLite::TYPE_INT32,
+                                    internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapEntryLite() {}
+  explicit MyMapEntryLite(Arena*) { std::abort(); }
+  static bool ValidateKey(void*) { return true; }
+  static bool ValidateValue(void*) { return true; }
+};
+
+TEST(MapEntryTest, ConstInit) {
+  // This verifies that `MapEntry`, `MapEntryLite` and `MapEntryImpl` can be
+  // constant initialized.
+  PROTOBUF_CONSTINIT static MyMapEntry entry{};
+  EXPECT_NE(entry.SpaceUsed(), 0);
+
+  PROTOBUF_CONSTINIT static MyMapEntryLite entry_lite{};  // NOLINT
+  EXPECT_TRUE(entry_lite.IsInitialized());
+}
+
+// Generated Message Test ===========================================
+
+TEST(GeneratedMapFieldTest, Accessors) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  MapTestUtil::ModifyMapFields(&message);
+  MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFieldsInitialized(&message);
+  MapTestUtil::ExpectMapFieldsSetInitialized(message);
+}
+
+TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) {
+  UNITTEST::TestEnumMap message;
+  EXPECT_EQ(UNITTEST::PROTO2_MAP_ENUM_FOO,
+            (*message.mutable_known_map_field())[0]);
+}
+
+TEST(GeneratedMapFieldTest, Clear) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  message.Clear();
+  MapTestUtil::ExpectClear(message);
+}
+
+TEST(GeneratedMapFieldTest, ClearMessageMap) {
+  UNITTEST::TestMessageMap message;
+
+  // Creates a TestAllTypes with default value
+  TestUtil::ExpectClear((*message.mutable_map_int32_message())[0]);
+}
+
+TEST(GeneratedMapFieldTest, CopyFrom) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  message2.CopyFrom(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  message2.CopyFrom(message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromMessageMap) {
+  UNITTEST::TestMessageMap message1, message2;
+
+  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+  message1.CopyFrom(message2);
+
+  // Checks repeated field is overwritten.
+  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+TEST(GeneratedMapFieldTest, SwapWithEmpty) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::ExpectMapFieldsSet(message1);
+  MapTestUtil::ExpectClear(message2);
+
+  message1.Swap(&message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+  MapTestUtil::ExpectClear(message1);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithSelf) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  message.Swap(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithOther) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+  MapTestUtil::ModifyMapFields(&message2);
+
+  message1.Swap(&message2);
+  MapTestUtil::ExpectMapFieldsModified(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyConstructor) {
+  UNITTEST::TestMap message1;
+  MapTestUtil::SetMapFields(&message1);
+
+  UNITTEST::TestMap message2(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyAssignmentOperator) {
+  UNITTEST::TestMap message1;
+  MapTestUtil::SetMapFields(&message1);
+
+  UNITTEST::TestMap message2;
+  message2 = message1;
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Make sure that self-assignment does something sane.
+  message2.operator=(message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || PROTOBUF_RTTI
+TEST(GeneratedMapFieldTest, UpcastCopyFrom) {
+  // Test the CopyFrom method that takes in the generic const Message&
+  // parameter.
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  const Message* source = implicit_cast<const Message*>(&message1);
+  message2.CopyFrom(*source);
+
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+#endif
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) {
+  // Test copying from a DynamicMessage, which must fall back to using
+  // reflection.
+  UNITTEST::TestMap message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessageMapReflection) {
+  UNITTEST::TestMap message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageMergeFromDynamicMessage) {
+  // Construct two dynamic message and sets via map reflection.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+
+  // message2 is created by same factory.
+  std::unique_ptr<Message> message2;
+  message2.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
+
+  // message3 is created by different factory.
+  DynamicMessageFactory factory3;
+  std::unique_ptr<Message> message3;
+  message3.reset(factory3.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message3.get());
+
+  message2->MergeFrom(*message1);
+  message3->MergeFrom(*message1);
+
+  // Test MergeFrom does not sync to repeated fields and
+  // there is no duplicate keys in text format.
+  std::string output1, output2, output3;
+  TextFormat::PrintToString(*message1, &output1);
+  TextFormat::PrintToString(*message2, &output2);
+  TextFormat::PrintToString(*message3, &output3);
+  EXPECT_EQ(output1, output2);
+  EXPECT_EQ(output1, output3);
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
+  // Test copying to a DynamicMessage, which must fall back to using reflection.
+  UNITTEST::TestMap message2;
+  MapTestUtil::SetMapFields(&message2);
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  message1->MergeFrom(message2);
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFromMapReflection) {
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  UNITTEST::TestMap message2;
+  reflection_tester.SetMapFieldsViaMapReflection(&message2);
+
+  // Construct a dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_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;
+  std::unique_ptr<Message> message;
+  message.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  // This field will test merging into an empty spot.
+  (*message2.mutable_map_int32_int32())[1] = 1;
+  message1.mutable_map_int32_int32()->erase(1);
+
+  // This tests overwriting.
+  (*message2.mutable_map_int32_double())[1] = 1;
+  (*message1.mutable_map_int32_double())[1] = 2;
+
+  message1.MergeFrom(message2);
+  MapTestUtil::ExpectMapFieldsSet(message1);
+
+  // Test reflection MergeFrom does not sync to repeated field
+  // and there is no duplicated keys.
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+
+  message2.MergeFrom(message1);
+
+  std::string output1, output2;
+  TextFormat::PrintToString(message1, &output1);
+  TextFormat::PrintToString(message2, &output2);
+  EXPECT_EQ(output1, output2);
+}
+
+TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
+  UNITTEST::TestMessageMap message1, message2;
+
+  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+  message1.MergeFrom(message2);
+
+  // Checks repeated field is overwritten.
+  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+// Test the generated SerializeWithCachedSizesToArray()
+TEST(GeneratedMapFieldTest, SerializationToArray) {
+  UNITTEST::TestMap message1, message2;
+  std::string data;
+  MapTestUtil::SetMapFields(&message1);
+  size_t size = message1.ByteSizeLong();
+  data.resize(size);
+  uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
+  EXPECT_EQ(size, end - start);
+  EXPECT_TRUE(message2.ParseFromString(data));
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+// Test the generated SerializeWithCachedSizes()
+TEST(GeneratedMapFieldTest, SerializationToStream) {
+  UNITTEST::TestMap message1, message2;
+  MapTestUtil::SetMapFields(&message1);
+  size_t size = message1.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  {
+    // Allow the output stream to buffer only one byte at a time.
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message1.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_TRUE(message2.ParseFromString(data));
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, ParseFailsIfMalformed) {
+  UNITTEST::TestMapSubmessage o, p;
+  auto m = o.mutable_test_map()->mutable_map_int32_foreign_message();
+  (*m)[0].set_c(-1);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+
+TEST(GeneratedMapFieldTest, SameTypeMaps) {
+  const Descriptor* map1 = UNITTEST::TestSameTypeMap::descriptor()
+                               ->FindFieldByName("map1")
+                               ->message_type();
+  const Descriptor* map2 = UNITTEST::TestSameTypeMap::descriptor()
+                               ->FindFieldByName("map2")
+                               ->message_type();
+
+  const Message* map1_entry =
+      MessageFactory::generated_factory()->GetPrototype(map1);
+  const Message* map2_entry =
+      MessageFactory::generated_factory()->GetPrototype(map2);
+
+  EXPECT_EQ(map1, map1_entry->GetDescriptor());
+  EXPECT_EQ(map2, map2_entry->GetDescriptor());
+}
+
+TEST(GeneratedMapFieldTest, Proto2UnknownEnum) {
+  UNITTEST::TestEnumMapPlusExtra from;
+  (*from.mutable_known_map_field())[0] = UNITTEST::E_PROTO2_MAP_ENUM_FOO;
+  (*from.mutable_unknown_map_field())[0] = UNITTEST::E_PROTO2_MAP_ENUM_EXTRA;
+  std::string data;
+  from.SerializeToString(&data);
+
+  UNITTEST::TestEnumMap to;
+  EXPECT_TRUE(to.ParseFromString(data));
+  EXPECT_EQ(0, to.unknown_map_field().size());
+  const UnknownFieldSet& unknown_field_set =
+      to.GetReflection()->GetUnknownFields(to);
+  EXPECT_EQ(1, unknown_field_set.field_count());
+  EXPECT_EQ(1, to.known_map_field().size());
+  EXPECT_EQ(UNITTEST::PROTO2_MAP_ENUM_FOO, to.known_map_field().at(0));
+
+  data.clear();
+  from.Clear();
+  to.SerializeToString(&data);
+  EXPECT_TRUE(from.ParseFromString(data));
+  EXPECT_EQ(0, from.GetReflection()->GetUnknownFields(from).field_count());
+  EXPECT_EQ(1, from.known_map_field().size());
+  EXPECT_EQ(UNITTEST::E_PROTO2_MAP_ENUM_FOO, from.known_map_field().at(0));
+  EXPECT_EQ(1, from.unknown_map_field().size());
+  EXPECT_EQ(UNITTEST::E_PROTO2_MAP_ENUM_EXTRA, from.unknown_map_field().at(0));
+}
+
+TEST(GeneratedMapFieldTest, StandardWireFormat) {
+  UNITTEST::TestMap message;
+  std::string data = "\x0A\x04\x08\x01\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, UnorderedWireFormat) {
+  UNITTEST::TestMap message;
+
+  // put value before key in wire format
+  std::string data = "\x0A\x04\x10\x01\x08\x02";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  ASSERT_NE(message.map_int32_int32().find(2), message.map_int32_int32().end());
+  EXPECT_EQ(1, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) {
+  UNITTEST::TestMap message;
+
+  // Two key fields in wire format
+  std::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));
+
+  // A similar test, but with a map from int to a message type.
+  // Again, we want to be sure that the "second one wins" when
+  // there are two separate entries with the same key.
+  const int key = 99;
+  UNITTEST::TestRequiredMessageMap map_message;
+  UNITTEST::TestRequired with_dummy4;
+  with_dummy4.set_a(0);
+  with_dummy4.set_b(0);
+  with_dummy4.set_c(0);
+  with_dummy4.set_dummy4(11);
+  (*map_message.mutable_map_field())[key] = with_dummy4;
+  std::string s = map_message.SerializeAsString();
+  UNITTEST::TestRequired with_dummy5;
+  with_dummy5.set_a(0);
+  with_dummy5.set_b(0);
+  with_dummy5.set_c(0);
+  with_dummy5.set_dummy5(12);
+  (*map_message.mutable_map_field())[key] = with_dummy5;
+  std::string both = s + map_message.SerializeAsString();
+  // We don't expect a merge now.  The "second one wins."
+  ASSERT_TRUE(map_message.ParseFromString(both));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.c());
+  EXPECT_FALSE(map_message.map_field().find(key)->second.has_dummy4());
+  ASSERT_TRUE(map_message.map_field().find(key)->second.has_dummy5());
+  EXPECT_EQ(12, map_message.map_field().find(key)->second.dummy5());
+}
+
+// Exhaustive combinations of keys, values, and junk in any order.
+// This re-tests some of the things tested above, but if it fails
+// it's more work to determine what went wrong, so it isn't necessarily
+// bad that we have the simpler tests too.
+TEST(GeneratedMapFieldTest, KeysValuesUnknownsWireFormat) {
+  UNITTEST::TestMap message;
+  const int kMaxNumKeysAndValuesAndJunk = 4;
+  const char kKeyTag = 0x08;
+  const char kValueTag = 0x10;
+  const char kJunkTag = 0x20;
+  for (int items = 0; items <= kMaxNumKeysAndValuesAndJunk; items++) {
+    std::string data = "\x0A";
+    // Encode length of what will follow.
+    data.push_back(items * 2);
+    static const int kBitsOfIPerItem = 4;
+    static const int mask = (1 << kBitsOfIPerItem) - 1;
+    // Each iteration of the following is a test.  It uses i as bit vector
+    // encoding the keys and values to put in the wire format.
+    for (int i = 0; i < (1 << (items * kBitsOfIPerItem)); i++) {
+      std::string wire_format = data;
+      int expected_key = 0;
+      int expected_value = 0;
+      for (int k = i, j = 0; j < items; j++, k >>= kBitsOfIPerItem) {
+        bool is_key = k & 0x1;
+        bool is_value = !is_key && (k & 0x2);
+        wire_format.push_back(is_key ? kKeyTag
+                                     : is_value ? kValueTag : kJunkTag);
+        char c = static_cast<char>(k & mask) >> 2;  // One char after the tag.
+        wire_format.push_back(c);
+        if (is_key) expected_key = static_cast<int>(c);
+        if (is_value) expected_value = static_cast<int>(c);
+        bool res = message.ParseFromString(wire_format);
+        bool expect_success = true;
+        // Unfortunately the old map parser accepts malformed input, the new
+        // parser accepts only correct input.
+        if (j != items - 1) expect_success = false;
+        if (expect_success) {
+          ASSERT_TRUE(res);
+          ASSERT_EQ(1, message.map_int32_int32().size());
+          ASSERT_EQ(expected_key, message.map_int32_int32().begin()->first);
+          ASSERT_EQ(expected_value, message.map_int32_int32().begin()->second);
+        } else {
+          ASSERT_FALSE(res);
+        }
+      }
+    }
+  }
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
+  UNITTEST::TestMap message;
+
+  // Two value fields in wire format
+  std::string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedKeyWireFormat) {
+  UNITTEST::TestMap message;
+
+  // No key field in wire format
+  std::string data = "\x0A\x02\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  ASSERT_NE(message.map_int32_int32().find(0), message.map_int32_int32().end());
+  EXPECT_EQ(1, message.map_int32_int32().at(0));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueWireFormat) {
+  UNITTEST::TestMap message;
+
+  // No value field in wire format
+  std::string data = "\x0A\x02\x08\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  ASSERT_NE(message.map_int32_int32().find(1), message.map_int32_int32().end());
+  EXPECT_EQ(0, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueTextFormat) {
+  UNITTEST::TestMap message;
+
+  // No value field in text format
+  std::string text =
+      "map_int32_foreign_message {\n"
+      "  key: 1234567890\n"
+      "}";
+
+  EXPECT_TRUE(TextFormat::ParseFromString(text, &message));
+  EXPECT_EQ(1, message.map_int32_foreign_message().size());
+  EXPECT_EQ(11, message.ByteSizeLong());
+}
+
+TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) {
+  UNITTEST::TestMap message;
+
+  // Unknown field in wire format
+  std::string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(3, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, CorruptedWireFormat) {
+  UNITTEST::TestMap message;
+
+  // corrupted data in wire format
+  std::string data = "\x0A\x06\x08\x02\x11\x03";
+
+  EXPECT_FALSE(message.ParseFromString(data));
+}
+
+TEST(GeneratedMapFieldTest, IsInitialized) {
+  UNITTEST::TestRequiredMessageMap map_message;
+
+  // Add an uninitialized message.
+  (*map_message.mutable_map_field())[0];
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  // Initialize uninitialized message
+  (*map_message.mutable_map_field())[0].set_a(0);
+  (*map_message.mutable_map_field())[0].set_b(0);
+  (*map_message.mutable_map_field())[0].set_c(0);
+  EXPECT_TRUE(map_message.IsInitialized());
+}
+
+TEST(GeneratedMapFieldTest, SpaceUsed) {
+  UNITTEST::TestRequiredMessageMap map_message;
+  const size_t initial = map_message.SpaceUsed();
+  const size_t space_used_message = UNITTEST::TestRequired().SpaceUsed();
+
+  auto& m = *map_message.mutable_map_field();
+  constexpr int kNumValues = 100;
+  for (int i = 0; i < kNumValues; ++i) {
+    m[i];
+  }
+
+  // The exact value will depend on internal state, like collisions,
+  // so we can't predict it. But we can predict a lower bound.
+  size_t lower_bound =
+      initial + kNumValues * (space_used_message + sizeof(int32_t) +
+                              /* Node::next */ sizeof(void*) +
+                              /* table entry */ sizeof(void*));
+
+  EXPECT_LE(lower_bound, map_message.SpaceUsed());
+}
+
+TEST(GeneratedMapFieldTest, MessagesMustMerge) {
+  UNITTEST::TestRequiredMessageMap map_message;
+
+  UNITTEST::TestRequired with_dummy4;
+  with_dummy4.set_a(97);
+  with_dummy4.set_b(91);
+  with_dummy4.set_dummy4(98);
+  EXPECT_FALSE(with_dummy4.IsInitialized());
+  (*map_message.mutable_map_field())[0] = with_dummy4;
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  UNITTEST::TestRequired with_dummy5;
+  with_dummy5.set_b(0);
+  with_dummy5.set_c(33);
+  with_dummy5.set_dummy5(99);
+  EXPECT_FALSE(with_dummy5.IsInitialized());
+  (*map_message.mutable_map_field())[0] = with_dummy5;
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  // The wire format of MapEntry is straightforward (*) and can be manually
+  // constructed to force merging of two uninitialized messages that would
+  // result in an initialized message.
+  //
+  // (*) http://google3/net/proto2/internal/map_test.cc?l=2433&rcl=310012028
+  std::string dummy4_s = with_dummy4.SerializePartialAsString();
+  std::string dummy5_s = with_dummy5.SerializePartialAsString();
+  int payload_size = dummy4_s.size() + dummy5_s.size();
+  // Makes sure the payload size fits into one byte.
+  ASSERT_LT(payload_size, 128);
+
+  std::string s(6, 0);
+  char* p = &s[0];
+  *p++ = WireFormatLite::MakeTag(1, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+  // Length: 2B for key tag & val and 2B for val tag and length of the following
+  // payload.
+  *p++ = 4 + payload_size;
+  *p++ = WireFormatLite::MakeTag(1, WireFormatLite::WIRETYPE_VARINT);
+  *p++ = 0;
+  *p++ = WireFormatLite::MakeTag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+  *p++ = payload_size;
+  StrAppend(&s, dummy4_s, dummy5_s);
+
+  // Test key then value then value.
+  int key = 0;
+  ASSERT_TRUE(map_message.ParseFromString(s));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+
+  // Test key then value then value then key.
+  s.push_back(s[2]);  // Copy the key's tag.
+  key = 19;
+  s.push_back(key);  // Second key is 19 instead of 0.
+  s[1] += 2;         // Adjust encoded size.
+  ASSERT_TRUE(map_message.ParseFromString(s));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+}
+
+// Generated Message Reflection Test ================================
+
+TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(&message);
+
+  EXPECT_LT(0, message.GetReflection()->SpaceUsedLong(message));
+}
+
+TEST(GeneratedMapFieldReflectionTest, Accessors) {
+  // Set every field to a unique value then go back and check all those
+  // values.
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+
+  reflection_tester.ModifyMapFieldsViaReflection(&message);
+  MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Swap) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  const Reflection* reflection = message1.GetReflection();
+  reflection->Swap(&message1, &message2);
+
+  MapTestUtil::ExpectClear(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapWithBothSet) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+  MapTestUtil::ModifyMapFields(&message2);
+
+  const Reflection* reflection = message1.GetReflection();
+  reflection->Swap(&message1, &message2);
+
+  MapTestUtil::ExpectMapFieldsModified(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapFields) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message2);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1.GetReflection();
+  reflection->ListFields(message2, &fields);
+  reflection->SwapFields(&message1, &message2, fields);
+
+  MapTestUtil::ExpectMapFieldsSet(message1);
+  MapTestUtil::ExpectClear(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ClearField) {
+  UNITTEST::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.ClearMapFieldsViaReflection(&message);
+  reflection_tester.ExpectClearViaReflection(message);
+  reflection_tester.ExpectClearViaReflectionIterator(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, RemoveLast) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapsSize(message, 2);
+  std::vector<const Message*> expected_entries =
+      MapTestUtil::GetMapEntries(message, 0);
+
+  reflection_tester.RemoveLastMapsViaReflection(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 1);
+  std::vector<const Message*> remained_entries =
+      MapTestUtil::GetMapEntries(message, 0);
+  EXPECT_TRUE(expected_entries == remained_entries);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ReleaseLast) {
+  UNITTEST::TestMap message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  MapReflectionTester reflection_tester(descriptor);
+
+  MapTestUtil::SetMapFields(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 2);
+
+  reflection_tester.ReleaseLastMapsViaReflection(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 1);
+
+  // Now test that we actually release the right message.
+  message.Clear();
+  MapTestUtil::SetMapFields(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 2);
+  std::vector<const Message*> expect_last =
+      MapTestUtil::GetMapEntries(message, 1);
+  std::vector<const Message*> release_last =
+      MapTestUtil::GetMapEntriesFromRelease(&message);
+  MapTestUtil::ExpectMapsSize(message, 1);
+  EXPECT_TRUE(expect_last == release_last);
+  for (std::vector<const Message*>::iterator it = release_last.begin();
+       it != release_last.end(); ++it) {
+    delete *it;
+  }
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapElements) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+
+  MapTestUtil::SetMapFields(&message);
+
+  // Get pointers of map entries at their original position
+  std::vector<const Message*> entries0 = MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1 = MapTestUtil::GetMapEntries(message, 1);
+
+  // Swap the first time.
+  reflection_tester.SwapMapsViaReflection(&message);
+
+  // Get pointer of map entry after swap once.
+  std::vector<const Message*> entries0_once =
+      MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1_once =
+      MapTestUtil::GetMapEntries(message, 1);
+
+  // Test map entries are swapped.
+  MapTestUtil::ExpectMapsSize(message, 2);
+  EXPECT_TRUE(entries0 == entries1_once);
+  EXPECT_TRUE(entries1 == entries0_once);
+
+  // Swap the second time.
+  reflection_tester.SwapMapsViaReflection(&message);
+
+  // Get pointer of map entry after swap once.
+  std::vector<const Message*> entries0_twice =
+      MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1_twice =
+      MapTestUtil::GetMapEntries(message, 1);
+
+  // Test map entries are swapped back.
+  MapTestUtil::ExpectMapsSize(message, 2);
+  EXPECT_TRUE(entries0 == entries0_twice);
+  EXPECT_TRUE(entries1 == entries1_twice);
+}
+
+TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, EmbedProto2Message) {
+  UNITTEST::TestMessageMap message;
+
+  const FieldDescriptor* map_field =
+      UNITTEST::TestMessageMap::descriptor()->FindFieldByName(
+          "map_int32_message");
+  const FieldDescriptor* value = map_field->message_type()->map_value();
+
+  Message* entry_message =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_EQ(
+      &entry_message->GetReflection()->GetMessage(*entry_message, value),
+      reinterpret_cast<const Message*>(&TestAllTypes::default_instance()));
+
+  Message* proto2_message =
+      entry_message->GetReflection()->MutableMessage(entry_message, value);
+  EXPECT_EQ(UNITTEST::TestAllTypes::descriptor(),
+            proto2_message->GetDescriptor());
+  ASSERT_EQ(1, message.map_int32_message().size());
+}
+
+TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) {
+  UNITTEST::TestMap message;
+  const FieldDescriptor* map_field =
+      UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* key = map_field->message_type()->map_key();
+  const FieldDescriptor* value = map_field->message_type()->map_value();
+
+  Message* entry_message1 =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+  EXPECT_FALSE(
+      entry_message1->GetReflection()->HasField(*entry_message1, value));
+
+  Message* entry_message2 =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_FALSE(entry_message2->GetReflection()->HasField(*entry_message2, key));
+  EXPECT_FALSE(
+      entry_message2->GetReflection()->HasField(*entry_message2, value));
+
+  entry_message1->MergeFrom(*entry_message2);
+  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+  EXPECT_FALSE(
+      entry_message1->GetReflection()->HasField(*entry_message1, value));
+}
+
+TEST(GeneratedMapFieldReflectionTest, MapEntryClear) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) {
+  UNITTEST::TestEnumMap message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  const FieldDescriptor* field_descriptor =
+      descriptor->FindFieldByName("known_map_field");
+  const FieldDescriptor* value_descriptor =
+      field_descriptor->message_type()->map_value();
+  Message* sub_message =
+      message.GetReflection()->AddMessage(&message, field_descriptor);
+  EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message,
+                                                          value_descriptor));
+}
+
+// Map Reflection API Test =========================================
+
+TEST(GeneratedMapFieldReflectionTest, SetViaMapReflection) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+}
+
+// Dynamic Message Test =============================================
+
+class MapFieldInDynamicMessageTest : public testing::Test {
+ protected:
+  const DescriptorPool* pool_;
+  DynamicMessageFactory factory_;
+  const Descriptor* map_descriptor_;
+  const Descriptor* recursive_map_descriptor_;
+  const Message* map_prototype_;
+
+  MapFieldInDynamicMessageTest()
+      : pool_(DescriptorPool::generated_pool()), factory_(pool_) {}
+
+  void SetUp() override {
+    map_descriptor_ = pool_->FindMessageTypeByName(
+        std::string(UNITTEST_PACKAGE_NAME) + ".TestMap");
+    recursive_map_descriptor_ = pool_->FindMessageTypeByName(
+        std::string(UNITTEST_PACKAGE_NAME) + ".TestRecursiveMapMessage");
+    ASSERT_TRUE(map_descriptor_ != nullptr);
+    ASSERT_TRUE(recursive_map_descriptor_ != nullptr);
+    map_prototype_ = factory_.GetPrototype(map_descriptor_);
+  }
+};
+
+TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
+  // Check that all fields have independent offsets by setting each
+  // one to a unique value then checking that they all still have those
+  // unique values (i.e. they don't stomp each other).
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
+  // Check that map fields work properly.
+  std::unique_ptr<Message> message(map_prototype_->New());
+
+  // Check set functions.
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
+  // Test that SpaceUsedLong() works properly
+
+  // Since we share the implementation with generated messages, we don't need
+  // to test very much here.  Just make sure it appears to be working.
+
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+
+  int initial_space_used = message->SpaceUsedLong();
+
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  EXPECT_LT(initial_space_used, message->SpaceUsedLong());
+}
+
+TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) {
+  TestRecursiveMapMessage from;
+  (*from.mutable_a())[""];
+  std::string data = from.SerializeAsString();
+  std::unique_ptr<Message> to(
+      factory_.GetPrototype(recursive_map_descriptor_)->New());
+  ASSERT_TRUE(to->ParseFromString(data));
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapValueReferernceValidAfterSerialize) {
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+
+  // Get value reference before serialization, so that we know the value is from
+  // map.
+  MapKey map_key;
+  MapValueRef map_val;
+  map_key.SetInt32Value(0);
+  reflection_tester.GetMapValueViaMapReflection(
+      message.get(), "map_int32_foreign_message", map_key, &map_val);
+  Message* submsg = map_val.MutableMessageValue();
+
+  // In previous implementation, calling SerializeToString will cause syncing
+  // from map to repeated field, which will invalidate the submsg we previously
+  // got.
+  std::string data;
+  message->SerializeToString(&data);
+
+  const Reflection* submsg_reflection = submsg->GetReflection();
+  const Descriptor* submsg_desc = submsg->GetDescriptor();
+  const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
+  submsg_reflection->SetInt32(submsg, submsg_field, 128);
+
+  message->SerializeToString(&data);
+  TestMap to;
+  to.ParseFromString(data);
+  EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapEntryReferernceValidAfterSerialize) {
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+
+  // Get map entry before serialization, so that we know the it is from
+  // repeated field.
+  Message* map_entry = reflection_tester.GetMapEntryViaReflection(
+      message.get(), "map_int32_foreign_message", 0);
+  const Reflection* map_entry_reflection = map_entry->GetReflection();
+  const Descriptor* map_entry_desc = map_entry->GetDescriptor();
+  const FieldDescriptor* value_field = map_entry_desc->map_value();
+  Message* submsg =
+      map_entry_reflection->MutableMessage(map_entry, value_field);
+
+  // In previous implementation, calling SerializeToString will cause syncing
+  // from repeated field to map, which will invalidate the map_entry we
+  // previously got.
+  std::string data;
+  message->SerializeToString(&data);
+
+  const Reflection* submsg_reflection = submsg->GetReflection();
+  const Descriptor* submsg_desc = submsg->GetDescriptor();
+  const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
+  submsg_reflection->SetInt32(submsg, submsg_field, 128);
+
+  message->SerializeToString(&data);
+  TestMap to;
+  to.ParseFromString(data);
+  EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
+}
+
+// ReflectionOps Test ===============================================
+
+TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapCopy) {
+  UNITTEST::TestMap message, message2;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Copy(message, &message2);
+
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  ReflectionOps::Copy(message2, &message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MergeMap) {
+  // Note:  Copy is implemented in terms of Merge() so technically the Copy
+  //   test already tested most of this.
+
+  UNITTEST::TestMap message, message2;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Merge(message2, &message);
+
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, ClearMap) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Clear(&message);
+
+  MapTestUtil::ExpectClear(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapDiscardUnknownFields) {
+  UNITTEST::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+
+  // Set some unknown fields in message.
+  message.GetReflection()->MutableUnknownFields(&message)->AddVarint(123456,
+                                                                     654321);
+
+  // Discard them.
+  ReflectionOps::DiscardUnknownFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  EXPECT_EQ(0,
+            message.GetReflection()->GetUnknownFields(message).field_count());
+}
+
+TEST(ReflectionOpsForMapFieldTest, IsInitialized) {
+  UNITTEST::TestRequiredMessageMap map_message;
+
+  // Add an uninitialized message.
+  (*map_message.mutable_map_field())[0];
+  EXPECT_FALSE(ReflectionOps::IsInitialized(map_message));
+
+  // 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(ReflectionOps::IsInitialized(map_message));
+}
+
+// Wire Format Test =================================================
+
+TEST(WireFormatForMapFieldTest, ParseMap) {
+  UNITTEST::TestMap source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  MapTestUtil::SetMapFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(WireFormatForMapFieldTest, MapByteSize) {
+  UNITTEST::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatForMapFieldTest, SerializeMap) {
+  UNITTEST::TestMap message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  MapTestUtil::SetMapFields(&message);
+
+  // Serialize using the generated code.
+  {
+    message.ByteSizeLong();
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    size_t size = WireFormat::ByteSize(message);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatForMapFieldTest, SerializeMapDynamicMessage) {
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> dynamic_message;
+  dynamic_message.reset(
+      factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
+
+  UNITTEST::TestMap generated_message;
+  MapTestUtil::SetMapFields(&generated_message);
+  MapTestUtil::ExpectMapFieldsSet(generated_message);
+
+  std::string generated_data;
+  std::string dynamic_data;
+
+  // Serialize.
+  generated_message.SerializeToString(&generated_data);
+  dynamic_message->SerializeToString(&dynamic_data);
+
+  // Because map serialization doesn't guarantee order, we just compare
+  // serialized size here. This is enough to tell dynamic message doesn't miss
+  // anything in serialization.
+  EXPECT_TRUE(dynamic_data.size() == generated_data.size());
+}
+
+TEST(WireFormatForMapFieldTest, MapByteSizeDynamicMessage) {
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> dynamic_message;
+  dynamic_message.reset(
+      factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
+  std::string expected_serialized_data;
+  dynamic_message->SerializeToString(&expected_serialized_data);
+  int expected_size = expected_serialized_data.size();
+  EXPECT_EQ(dynamic_message->ByteSizeLong(), expected_size);
+  TestMap expected_message;
+  expected_message.ParseFromString(expected_serialized_data);
+
+  std::unique_ptr<Message> message2;
+  message2.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
+
+  const FieldDescriptor* field =
+      UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+  const Reflection* reflection = dynamic_message->GetReflection();
+
+  // Force the map field to mark with STATE_MODIFIED_REPEATED
+  reflection->RemoveLast(dynamic_message.get(), field);
+  dynamic_message->MergeFrom(*message2);
+  dynamic_message->MergeFrom(*message2);
+  // The map field is marked as STATE_MODIFIED_REPEATED, ByteSizeLong() will use
+  // repeated field which have duplicate keys to calculate.
+  size_t duplicate_size = dynamic_message->ByteSizeLong();
+  EXPECT_TRUE(duplicate_size > expected_size);
+  std::string duplicate_serialized_data;
+  dynamic_message->SerializeToString(&duplicate_serialized_data);
+  EXPECT_EQ(dynamic_message->ByteSizeLong(), duplicate_serialized_data.size());
+
+  // Force the map field to mark with map CLEAN
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_int32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_int32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int64_int64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_uint32_uint32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_uint64_uint64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sint32_sint32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sint64_sint64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_fixed32_fixed32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_fixed64_fixed64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sfixed32_sfixed32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sfixed64_sfixed64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_float"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_double"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_bool_bool"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_string_string"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_bytes"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_enum"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(*dynamic_message, "map_int32_foreign_message"), 2);
+  // The map field is marked as CLEAN, ByteSizeLong() will use map which do not
+  // have duplicate keys to calculate.
+  int size = dynamic_message->ByteSizeLong();
+  EXPECT_EQ(expected_size, size);
+
+  // Protobuf used to have a bug for serialize when map it marked CLEAN. It used
+  // repeated field to calculate ByteSizeLong but use map to serialize the real
+  // data, thus the ByteSizeLong may bigger than real serialized size. A crash
+  // might be happen at SerializeToString(). Or an "unexpected end group"
+  // warning was raised at parse back if user use SerializeWithCachedSizes()
+  // which avoids size check at serialize.
+  std::string serialized_data;
+  dynamic_message->SerializeToString(&serialized_data);
+  EXPECT_TRUE(dynamic_message->ParseFromString(serialized_data));
+}
+
+TEST(WireFormatForMapFieldTest, MapParseHelpers) {
+  std::string data;
+
+  {
+    // Set up.
+    UNITTEST::TestMap message;
+    MapTestUtil::SetMapFields(&message);
+    message.SerializeToString(&data);
+  }
+
+  {
+    // Test ParseFromString.
+    UNITTEST::TestMap message;
+    EXPECT_TRUE(message.ParseFromString(data));
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromIstream.
+    UNITTEST::TestMap message;
+    std::stringstream stream(data);
+    EXPECT_TRUE(message.ParseFromIstream(&stream));
+    EXPECT_TRUE(stream.eof());
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromBoundedZeroCopyStream.
+    std::string data_with_junk(data);
+    data_with_junk.append("some junk on the end");
+    io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
+    UNITTEST::TestMap message;
+    EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
+    // EOF is reached before the expected number of bytes.
+    io::ArrayInputStream stream(data.data(), data.size());
+    UNITTEST::TestAllTypes message;
+    EXPECT_FALSE(
+        message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
+  }
+}
+
+// Deterministic Serialization Test ==========================================
+
+template <typename T>
+static std::string DeterministicSerializationWithSerializePartialToCodedStream(
+    const T& t) {
+  const size_t size = t.ByteSizeLong();
+  std::string result(size, '\0');
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
+  io::CodedOutputStream output_stream(&array_stream);
+  output_stream.SetSerializationDeterministic(true);
+  t.SerializePartialToCodedStream(&output_stream);
+  EXPECT_FALSE(output_stream.HadError());
+  EXPECT_EQ(size, output_stream.ByteCount());
+  return result;
+}
+
+template <typename T>
+static std::string DeterministicSerializationWithSerializeToCodedStream(
+    const T& t) {
+  const size_t size = t.ByteSizeLong();
+  std::string result(size, '\0');
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
+  io::CodedOutputStream output_stream(&array_stream);
+  output_stream.SetSerializationDeterministic(true);
+  t.SerializeToCodedStream(&output_stream);
+  EXPECT_FALSE(output_stream.HadError());
+  EXPECT_EQ(size, output_stream.ByteCount());
+  return result;
+}
+
+template <typename T>
+static std::string DeterministicSerialization(const T& t) {
+  const size_t size = t.ByteSizeLong();
+  std::string result(size, '\0');
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
+  {
+    io::CodedOutputStream output_stream(&array_stream);
+    output_stream.SetSerializationDeterministic(true);
+    t.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_EQ(result, DeterministicSerializationWithSerializeToCodedStream(t));
+  EXPECT_EQ(result,
+            DeterministicSerializationWithSerializePartialToCodedStream(t));
+  return result;
+}
+
+// Helper for MapSerializationTest.  Return a 7-bit ASCII string.
+static std::string ConstructKey(uint64_t n) {
+  std::string s(n % static_cast<uint64_t>(9), '\0');
+  if (s.empty()) {
+    return StrCat(n);
+  } else {
+    while (n != 0) {
+      s[n % s.size()] = (n >> 10) & 0x7f;
+      n /= 888;
+    }
+    return s;
+  }
+}
+
+TEST(MapSerializationTest, Deterministic) {
+  const int kIters = 25;
+  UNITTEST::TestMaps t;
+  UNITTEST::TestIntIntMap inner;
+  (*inner.mutable_m())[0] = (*inner.mutable_m())[10] =
+      (*inner.mutable_m())[-200] = 0;
+  uint64_t frog = 9;
+  const uint64_t multiplier = 0xa29cd16f;
+  for (int i = 0; i < kIters; i++) {
+    const int32_t i32 = static_cast<int32_t>(frog & 0xffffffff);
+    const uint32_t u32 = static_cast<uint32_t>(i32) * 91919;
+    const int64_t i64 = static_cast<int64_t>(frog);
+    const uint64_t u64 = frog * static_cast<uint64_t>(187321);
+    const bool b = i32 > 0;
+    const std::string s = ConstructKey(frog);
+    (*inner.mutable_m())[i] = i32;
+    (*t.mutable_m_int32())[i32] = (*t.mutable_m_sint32())[i32] =
+        (*t.mutable_m_sfixed32())[i32] = inner;
+    (*t.mutable_m_uint32())[u32] = (*t.mutable_m_fixed32())[u32] = inner;
+    (*t.mutable_m_int64())[i64] = (*t.mutable_m_sint64())[i64] =
+        (*t.mutable_m_sfixed64())[i64] = inner;
+    (*t.mutable_m_uint64())[u64] = (*t.mutable_m_fixed64())[u64] = inner;
+    (*t.mutable_m_bool())[b] = inner;
+    (*t.mutable_m_string())[s] = inner;
+    (*t.mutable_m_string())[s + std::string(
+                                    1 << (u32 % static_cast<uint32_t>(9)), b)] =
+        inner;
+    inner.mutable_m()->erase(i);
+    frog = frog * multiplier + i;
+    frog ^= (frog >> 41);
+  }
+
+  // Verifies if two consecutive calls to deterministic serialization produce
+  // the same bytes. Deterministic serialization means the same serialization
+  // bytes in the same binary.
+  const std::string s1 = DeterministicSerialization(t);
+  const std::string s2 = DeterministicSerialization(t);
+  EXPECT_EQ(s1, s2);
+
+  UNITTEST::TestMaps u;
+  EXPECT_TRUE(u.ParseFromString(s1));
+  EXPECT_TRUE(util::MessageDifferencer::Equals(u, t));
+}
+
+TEST(MapSerializationTest, DeterministicSubmessage) {
+  UNITTEST::TestSubmessageMaps p;
+  UNITTEST::TestMaps t;
+  const std::string filename = "golden_message_maps";
+  std::string golden;
+  GOOGLE_CHECK_OK(File::GetContents(
+      TestUtil::GetTestDataPath("net/proto2/internal/testdata/" + filename),
+      &golden, true));
+  t.ParseFromString(golden);
+  *(p.mutable_m()) = t;
+  std::vector<std::string> v;
+  // Use multiple attempts to increase the chance of a failure if something is
+  // buggy.  For example, each separate copy of a map might use a different
+  // randomly-chosen hash function.
+  const int kAttempts = 10;
+  for (int i = 0; i < kAttempts; i++) {
+    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
+    UNITTEST::TestSubmessageMaps q(p);
+    ASSERT_EQ(DeterministicSerialization(q), DeterministicSerialization(p));
+  }
+}
+
+// Text Format Test =================================================
+
+TEST(TextFormatMapTest, SerializeAndParse) {
+  UNITTEST::TestMap source;
+  UNITTEST::TestMap dest;
+  MapTestUtil::SetMapFields(&source);
+  std::string output;
+
+  // Test compact ASCII
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+  TextFormat::Parser parser;
+  EXPECT_TRUE(parser.ParseFromString(output, &dest));
+  MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(TextFormatMapTest, DynamicMessage) {
+  TestMap prototype;
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message(
+      factory.GetPrototype(prototype.GetDescriptor())->New());
+  MapReflectionTester tester(message->GetDescriptor());
+  tester.SetMapFieldsViaReflection(message.get());
+
+  std::string expected_text;
+  GOOGLE_CHECK_OK(
+      File::GetContents(TestUtil::GetTestDataPath("net/proto2/internal/"
+                                                  "testdata/map_test_data.txt"),
+                        &expected_text, true));
+
+  CleanStringLineEndings(&expected_text, false);
+  std::string actual_text;
+  TextFormat::PrintToString(*message, &actual_text);
+  EXPECT_EQ(actual_text, expected_text);
+}
+
+TEST(TextFormatMapTest, Sorted) {
+  UNITTEST::TestMap message;
+  MapReflectionTester tester(message.GetDescriptor());
+  tester.SetMapFieldsViaReflection(&message);
+
+  std::string expected_text;
+  GOOGLE_CHECK_OK(
+      File::GetContents(TestUtil::GetTestDataPath("net/proto2/internal/"
+                                                  "testdata/map_test_data.txt"),
+                        &expected_text, true));
+
+  CleanStringLineEndings(&expected_text, false);
+  TextFormat::Printer printer;
+  std::string actual_text;
+  printer.PrintToString(message, &actual_text);
+  EXPECT_EQ(actual_text, expected_text);
+
+  // Test again on the reverse order.
+  UNITTEST::TestMap message2;
+  tester.SetMapFieldsViaReflection(&message2);
+  tester.SwapMapsViaReflection(&message2);
+  printer.PrintToString(message2, &actual_text);
+  EXPECT_EQ(actual_text, expected_text);
+}
+
+TEST(TextFormatMapTest, ParseCorruptedString) {
+  std::string serialized_message;
+  GOOGLE_CHECK_OK(
+      File::GetContents(TestUtil::GetTestDataPath(
+                            "net/proto2/internal/testdata/golden_message_maps"),
+                        &serialized_message, true));
+  UNITTEST::TestMaps message;
+  GOOGLE_CHECK(message.ParseFromString(serialized_message));
+  TestParseCorruptedString<UNITTEST::TestMaps, true>(message);
+  TestParseCorruptedString<UNITTEST::TestMaps, false>(message);
+}
+
+// Previously, serializing to text format will disable iterator from generated
+// API. Now, the iterator can be still used even after serializing to text
+// format.
+TEST(TextFormatMapTest, NoDisableIterator) {
+  UNITTEST::TestMap source;
+  (*source.mutable_map_int32_int32())[1] = 1;
+
+  // Get iterator.
+  Map<int32_t, int32_t>::iterator iter =
+      source.mutable_map_int32_int32()->find(1);
+
+  // Serialize message to text format, which will invalidate the previous
+  // iterator previously.
+  std::string output;
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+
+  // Modify map via the iterator (invalidated in previous implementation.).
+  iter->second = 2;
+
+  // In previous implementation, the new change won't be reflected in text
+  // format, because the previous iterator has been invalidated.
+  output.clear();
+  printer.PrintToString(source, &output);
+  std::string expected =
+      "map_int32_int32 {\n"
+      "  key: 1\n"
+      "  value: 2\n"
+      "}\n";
+  EXPECT_EQ(output, expected);
+}
+
+// Previously, serializing to text format will disable iterator from reflection
+// API.
+TEST(TextFormatMapTest, NoDisableReflectionIterator) {
+  UNITTEST::TestMap source;
+  (*source.mutable_map_int32_int32())[1] = 1;
+
+  // Get iterator. This will also sync internal repeated field with map inside
+  // of MapField.
+  const Reflection* reflection = source.GetReflection();
+  const FieldDescriptor* field_desc =
+      source.GetDescriptor()->FindFieldByName("map_int32_int32");
+  RepeatedPtrField<Message>* map_field =
+      reflection->MutableRepeatedPtrField<Message>(&source, field_desc);
+  RepeatedPtrField<Message>::iterator iter = map_field->begin();
+
+  // Serialize message to text format, which will invalidate the previous
+  // iterator previously.
+  std::string output;
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+
+  // Modify map via the iterator (invalidated in previous implementation.).
+  const Reflection* map_entry_reflection = iter->GetReflection();
+  const FieldDescriptor* value_field_desc = iter->GetDescriptor()->map_value();
+  map_entry_reflection->SetInt32(&(*iter), value_field_desc, 2);
+  GOOGLE_LOG(INFO) << iter->DebugString();
+
+  // In previous implementation, the new change won't be reflected in text
+  // format, because the previous iterator has been invalidated.
+  output.clear();
+  printer.PrintToString(source, &output);
+  std::string expected =
+      "map_int32_int32 {\n"
+      "  key: 1\n"
+      "  value: 2\n"
+      "}\n";
+  EXPECT_EQ(output, expected);
+}
+
+// arena support =================================================
+TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+  std::string data;
+  data.reserve(128 * 1024);
+
+  {
+    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map.
+    // NoHeapChecker no_heap;
+
+    UNITTEST::TestArenaMap* from =
+        Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+    MapTestUtil::SetArenaMapFields(from);
+    from->SerializeToString(&data);
+
+    UNITTEST::TestArenaMap* to =
+        Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+    to->ParseFromString(data);
+    MapTestUtil::ExpectArenaMapFieldsSet(*to);
+  }
+}
+
+TEST(ArenaTest, SubmessageOnSameArena) {
+  Arena arena;
+  for (Arena* arena_to_use : {&arena, static_cast<Arena*>(nullptr)}) {
+    ArenaHolder<UNITTEST::TestArenaMap> m(arena_to_use);
+    auto* subm = &(*m->mutable_map_int32_foreign_message())[0];
+    EXPECT_EQ(subm->GetArena(), arena_to_use);
+  }
+}
+
+// Use text format parsing and serializing to test reflection api.
+TEST(ArenaTest, ReflectionInTextFormat) {
+  Arena arena;
+  std::string data;
+
+  TextFormat::Printer printer;
+  TextFormat::Parser parser;
+
+  UNITTEST::TestArenaMap* from =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+  UNITTEST::TestArenaMap* to =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+
+  MapTestUtil::SetArenaMapFields(from);
+  printer.PrintToString(*from, &data);
+
+  EXPECT_TRUE(parser.ParseFromString(data, to));
+  MapTestUtil::ExpectArenaMapFieldsSet(*to);
+}
+
+// Make sure the memory allocated for string in map is deallocated.
+TEST(ArenaTest, StringMapNoLeak) {
+  Arena arena;
+  UNITTEST::TestArenaMap* message =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+  std::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 == nullptr);
+}
+
+TEST(ArenaTest, IsInitialized) {
+  // Allocate a large initial polluted block.
+  std::vector<char> arena_block(128 * 1024);
+  std::fill(arena_block.begin(), arena_block.end(), '\xff');
+
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  UNITTEST::TestArenaMap* message =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+  EXPECT_EQ(0, (*message->mutable_map_int32_int32())[0]);
+}
+
+TEST(ArenaTest, DynamicMapFieldOnArena) {
+  Arena arena;
+  UNITTEST::TestMap message2;
+
+  DynamicMessageFactory factory;
+  Message* message1 =
+      factory.GetPrototype(UNITTEST::TestMap::descriptor())->New(&arena);
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(message1);
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1);
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(ArenaTest, DynamicMapFieldOnArenaMemoryLeak) {
+  auto* desc = UNITTEST::TestMap::descriptor();
+  auto* field = desc->FindFieldByName("map_int32_int32");
+
+  Arena arena;
+  DynamicMessageFactory factory;
+  auto* message = factory.GetPrototype(desc)->New(&arena);
+  auto* reflection = message->GetReflection();
+  reflection->AddMessage(message, field);
+
+  // Force internal syncing, which initializes the mutex.
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  int size = reflection_tester.MapSize(*message, "map_int32_int32");
+  EXPECT_EQ(size, 1);
+}
+
+TEST(MoveTest, MoveConstructorWorks) {
+  Map<int32_t, TestAllTypes> original_map;
+  original_map[42].mutable_optional_nested_message()->set_bb(42);
+  original_map[43].mutable_optional_nested_message()->set_bb(43);
+  const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
+  const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
+
+  Map<int32_t, TestAllTypes> moved_to_map(std::move(original_map));
+  EXPECT_TRUE(original_map.empty());
+  EXPECT_EQ(2, moved_to_map.size());
+  EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
+  EXPECT_EQ(43, moved_to_map[43].optional_nested_message().bb());
+  // This test takes advantage of the fact that pointers are swapped, so there
+  // should be pointer stability.
+  EXPECT_EQ(nested_msg42_ptr, &moved_to_map[42].optional_nested_message());
+  EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
+}
+
+TEST(MoveTest, MoveAssignmentWorks) {
+  Map<int32_t, TestAllTypes> original_map;
+  original_map[42].mutable_optional_nested_message()->set_bb(42);
+  original_map[43].mutable_optional_nested_message()->set_bb(43);
+  const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
+  const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
+
+  Map<int32_t, TestAllTypes> moved_to_map = std::move(original_map);
+  EXPECT_TRUE(original_map.empty());
+  EXPECT_EQ(2, moved_to_map.size());
+  EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
+  EXPECT_EQ(43, moved_to_map[43].optional_nested_message().bb());
+  // This test takes advantage of the fact that pointers are swapped, so there
+  // should be pointer stability.
+  EXPECT_EQ(nested_msg42_ptr, &moved_to_map[42].optional_nested_message());
+  EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
new file mode 100644
index 0000000..f3215db
--- /dev/null
+++ b/src/google/protobuf/map_test_util.h
@@ -0,0 +1,46 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
+
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/reflection_tester.h>
+
+#define UNITTEST ::protobuf_unittest
+#define BRIDGE_UNITTEST ::google::protobuf::bridge_unittest
+
+// Must be included after defining UNITTEST, etc.
+#include <google/protobuf/map_test_util.inc>
+
+#undef UNITTEST
+#undef BRIDGE_UNITTEST
+
+#endif  // GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_test_util.inc b/src/google/protobuf/map_test_util.inc
new file mode 100644
index 0000000..5b12c76
--- /dev/null
+++ b/src/google/protobuf/map_test_util.inc
@@ -0,0 +1,271 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/map_test_util_impl.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+
+class MapTestUtil {
+ public:
+  // Set every field in the TestMap message to a unique value.
+  static void SetMapFields(UNITTEST::TestMap* message);
+
+  // Set every field in the TestArenaMap message to a unique value.
+  static void SetArenaMapFields(UNITTEST::TestArenaMap* message);
+
+  // Set every field in the message to a default value.
+  static void SetMapFieldsInitialized(UNITTEST::TestMap* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  static void ModifyMapFields(UNITTEST::TestMap* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  static void ExpectMapFieldsSet(const UNITTEST::TestMap& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMap.
+  static void ExpectArenaMapFieldsSet(const UNITTEST::TestArenaMap& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  static void ExpectMapFieldsSetInitialized(const UNITTEST::TestMap& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  static void ExpectMapFieldsModified(const UNITTEST::TestMap& message);
+
+  // Check that all fields are empty.
+  static void ExpectClear(const UNITTEST::TestMap& message);
+
+  // Check that all map fields have the given size.
+  static void ExpectMapsSize(const UNITTEST::TestMap& message, int size);
+
+  // Get pointers of map entries at given index.
+  static std::vector<const Message*> GetMapEntries(
+      const UNITTEST::TestMap& message, int index);
+
+  // Get pointers of map entries from release.
+  static std::vector<const Message*> GetMapEntriesFromRelease(
+      UNITTEST::TestMap* message);
+};
+
+inline void MapTestUtil::SetMapFields(UNITTEST::TestMap* message) {
+  MapTestUtilImpl::SetMapFields<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR,
+                                UNITTEST::MAP_ENUM_BAZ>(message);
+}
+
+inline void MapTestUtil::SetArenaMapFields(UNITTEST::TestArenaMap* message) {
+  MapTestUtilImpl::SetArenaMapFields<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR,
+                                     UNITTEST::MAP_ENUM_BAZ>(message);
+}
+
+inline void MapTestUtil::SetMapFieldsInitialized(UNITTEST::TestMap* message) {
+  MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+inline void MapTestUtil::ModifyMapFields(UNITTEST::TestMap* message) {
+  MapTestUtilImpl::ModifyMapFields<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_FOO>(
+      message);
+}
+
+inline void MapTestUtil::ExpectClear(const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectClear(message);
+}
+
+inline void MapTestUtil::ExpectMapFieldsSet(const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsSet<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR,
+                                      UNITTEST::MAP_ENUM_BAZ>(message);
+}
+
+inline void MapTestUtil::ExpectArenaMapFieldsSet(
+    const UNITTEST::TestArenaMap& message) {
+  MapTestUtilImpl::ExpectArenaMapFieldsSet<
+      UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR, UNITTEST::MAP_ENUM_BAZ>(
+      message);
+}
+
+inline void MapTestUtil::ExpectMapFieldsSetInitialized(
+    const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsSetInitialized<UNITTEST::MapEnum,
+                                                 UNITTEST::MAP_ENUM_FOO>(
+      message);
+}
+
+inline void MapTestUtil::ExpectMapFieldsModified(
+    const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsModified<
+      UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR, UNITTEST::MAP_ENUM_FOO>(
+      message);
+}
+
+inline void MapTestUtil::ExpectMapsSize(const UNITTEST::TestMap& message,
+                                        int size) {
+  const Descriptor* descriptor = message.GetDescriptor();
+
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int32_int32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int64_int64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_uint32_uint32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_uint64_uint64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sint32_sint32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sint64_sint64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int32_float")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_int32_double")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_bool_bool")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_string_string")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int32_bytes")));
+  EXPECT_EQ(
+      size,
+      message.GetReflection()->FieldSize(
+          message, descriptor->FindFieldByName("map_int32_foreign_message")));
+}
+
+inline std::vector<const Message*> MapTestUtil::GetMapEntries(
+    const UNITTEST::TestMap& message, int index) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  std::vector<const Message*> result;
+
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_int32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int64_int64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_uint32_uint32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_uint64_uint64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sint32_sint32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sint64_sint64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_fixed32_fixed32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_fixed64_fixed64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sfixed32_sfixed32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sfixed64_sfixed64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_float"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_double"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_bool_bool"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_string_string"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_bytes"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_enum"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_foreign_message"),
+      index));
+
+  return result;
+}
+
+inline std::vector<const Message*> MapTestUtil::GetMapEntriesFromRelease(
+    UNITTEST::TestMap* message) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  std::vector<const Message*> result;
+
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_int32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int64_int64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_uint32_uint32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_uint64_uint64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sint32_sint32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sint64_sint64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_float")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_double")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_bool_bool")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_string_string")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_bytes")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_enum")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_foreign_message")));
+
+  return result;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h
new file mode 100644
index 0000000..655aec8
--- /dev/null
+++ b/src/google/protobuf/map_test_util_impl.h
@@ -0,0 +1,476 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
+#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <gtest/gtest.h>
+
+
+namespace protobuf_unittest {}  // namespace protobuf_unittest
+
+namespace google {
+namespace protobuf {
+
+namespace unittest = ::protobuf_unittest;
+
+class MapTestUtilImpl {
+ public:
+  // Set every field in the TestMap message to a unique value.
+  template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+            typename MapMessage>
+  static void SetMapFields(MapMessage* message);
+
+  // Set every field in the TestArenaMap message to a unique value.
+  template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+            typename MapMessage>
+  static void SetArenaMapFields(MapMessage* message);
+
+  // Set every field in the message to a default value.
+  template <typename MapMessage>
+  static void SetMapFieldsInitialized(MapMessage* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  template <typename EnumType, EnumType enum_value, typename MapMessage>
+  static void ModifyMapFields(MapMessage* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+            typename MapMessage>
+  static void ExpectMapFieldsSet(const MapMessage& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMap.
+  template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+            typename MapMessage>
+  static void ExpectArenaMapFieldsSet(const MapMessage& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  template <typename EnumType, EnumType enum_value, typename MapMessage>
+  static void ExpectMapFieldsSetInitialized(const MapMessage& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+            typename MapMessage>
+  static void ExpectMapFieldsModified(const MapMessage& message);
+
+  // Check that all fields are empty.
+  template <typename MapMessage>
+  static void ExpectClear(const MapMessage& message);
+
+  // // Check that all map fields have the given size.
+  // template <typename MapMessage>
+  // static void ExpectMapsSize(const MapMessage& message, int size);
+
+  // // Get pointers of map entries at given index.
+  // static std::vector<const Message*> GetMapEntries(
+  //     const MapMessage& message, int index);
+
+  // // Get pointers of map entries from release.
+  // static std::vector<const Message*> GetMapEntriesFromRelease(
+  //     MapMessage* message);
+};
+
+template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+          typename MapMessage>
+void MapTestUtilImpl::SetMapFields(MapMessage* message) {
+  // Add first element.
+  (*message->mutable_map_int32_int32())[0] = 0;
+  (*message->mutable_map_int64_int64())[0] = 0;
+  (*message->mutable_map_uint32_uint32())[0] = 0;
+  (*message->mutable_map_uint64_uint64())[0] = 0;
+  (*message->mutable_map_sint32_sint32())[0] = 0;
+  (*message->mutable_map_sint64_sint64())[0] = 0;
+  (*message->mutable_map_fixed32_fixed32())[0] = 0;
+  (*message->mutable_map_fixed64_fixed64())[0] = 0;
+  (*message->mutable_map_sfixed32_sfixed32())[0] = 0;
+  (*message->mutable_map_sfixed64_sfixed64())[0] = 0;
+  (*message->mutable_map_int32_float())[0] = 0.0;
+  (*message->mutable_map_int32_double())[0] = 0.0;
+  (*message->mutable_map_bool_bool())[0] = false;
+  (*message->mutable_map_string_string())["0"] = "0";
+  (*message->mutable_map_int32_bytes())[0] = "0";
+  (*message->mutable_map_int32_enum())[0] = enum_value0;
+  (*message->mutable_map_int32_foreign_message())[0].set_c(0);
+
+  // Add second element
+  (*message->mutable_map_int32_int32())[1] = 1;
+  (*message->mutable_map_int64_int64())[1] = 1;
+  (*message->mutable_map_uint32_uint32())[1] = 1;
+  (*message->mutable_map_uint64_uint64())[1] = 1;
+  (*message->mutable_map_sint32_sint32())[1] = 1;
+  (*message->mutable_map_sint64_sint64())[1] = 1;
+  (*message->mutable_map_fixed32_fixed32())[1] = 1;
+  (*message->mutable_map_fixed64_fixed64())[1] = 1;
+  (*message->mutable_map_sfixed32_sfixed32())[1] = 1;
+  (*message->mutable_map_sfixed64_sfixed64())[1] = 1;
+  (*message->mutable_map_int32_float())[1] = 1.0;
+  (*message->mutable_map_int32_double())[1] = 1.0;
+  (*message->mutable_map_bool_bool())[1] = true;
+  (*message->mutable_map_string_string())["1"] = "1";
+  (*message->mutable_map_int32_bytes())[1] = "1";
+  (*message->mutable_map_int32_enum())[1] = enum_value1;
+  (*message->mutable_map_int32_foreign_message())[1].set_c(1);
+}
+
+template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+          typename MapMessage>
+void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) {
+  // Add first element.
+  (*message->mutable_map_int32_int32())[0] = 0;
+  (*message->mutable_map_int64_int64())[0] = 0;
+  (*message->mutable_map_uint32_uint32())[0] = 0;
+  (*message->mutable_map_uint64_uint64())[0] = 0;
+  (*message->mutable_map_sint32_sint32())[0] = 0;
+  (*message->mutable_map_sint64_sint64())[0] = 0;
+  (*message->mutable_map_fixed32_fixed32())[0] = 0;
+  (*message->mutable_map_fixed64_fixed64())[0] = 0;
+  (*message->mutable_map_sfixed32_sfixed32())[0] = 0;
+  (*message->mutable_map_sfixed64_sfixed64())[0] = 0;
+  (*message->mutable_map_int32_float())[0] = 0.0;
+  (*message->mutable_map_int32_double())[0] = 0.0;
+  (*message->mutable_map_bool_bool())[0] = false;
+  (*message->mutable_map_string_string())["0"] = "0";
+  (*message->mutable_map_int32_bytes())[0] = "0";
+  (*message->mutable_map_int32_enum())[0] = enum_value0;
+  (*message->mutable_map_int32_foreign_message())[0].set_c(0);
+
+  // Add second element
+  (*message->mutable_map_int32_int32())[1] = 1;
+  (*message->mutable_map_int64_int64())[1] = 1;
+  (*message->mutable_map_uint32_uint32())[1] = 1;
+  (*message->mutable_map_uint64_uint64())[1] = 1;
+  (*message->mutable_map_sint32_sint32())[1] = 1;
+  (*message->mutable_map_sint64_sint64())[1] = 1;
+  (*message->mutable_map_fixed32_fixed32())[1] = 1;
+  (*message->mutable_map_fixed64_fixed64())[1] = 1;
+  (*message->mutable_map_sfixed32_sfixed32())[1] = 1;
+  (*message->mutable_map_sfixed64_sfixed64())[1] = 1;
+  (*message->mutable_map_int32_float())[1] = 1.0;
+  (*message->mutable_map_int32_double())[1] = 1.0;
+  (*message->mutable_map_bool_bool())[1] = true;
+  (*message->mutable_map_string_string())["1"] = "1";
+  (*message->mutable_map_int32_bytes())[1] = "1";
+  (*message->mutable_map_int32_enum())[1] = enum_value1;
+  (*message->mutable_map_int32_foreign_message())[1].set_c(1);
+}
+
+template <typename MapMessage>
+void MapTestUtilImpl::SetMapFieldsInitialized(MapMessage* message) {
+  // Add first element using bracket operator, which should assign default
+  // value automatically.
+  (*message->mutable_map_int32_int32())[0];
+  (*message->mutable_map_int64_int64())[0];
+  (*message->mutable_map_uint32_uint32())[0];
+  (*message->mutable_map_uint64_uint64())[0];
+  (*message->mutable_map_sint32_sint32())[0];
+  (*message->mutable_map_sint64_sint64())[0];
+  (*message->mutable_map_fixed32_fixed32())[0];
+  (*message->mutable_map_fixed64_fixed64())[0];
+  (*message->mutable_map_sfixed32_sfixed32())[0];
+  (*message->mutable_map_sfixed64_sfixed64())[0];
+  (*message->mutable_map_int32_float())[0];
+  (*message->mutable_map_int32_double())[0];
+  (*message->mutable_map_bool_bool())[0];
+  (*message->mutable_map_string_string())["0"];
+  (*message->mutable_map_int32_bytes())[0];
+  (*message->mutable_map_int32_enum())[0];
+  (*message->mutable_map_int32_foreign_message())[0];
+}
+
+template <typename EnumType, EnumType enum_value, typename MapMessage>
+void MapTestUtilImpl::ModifyMapFields(MapMessage* message) {
+  (*message->mutable_map_int32_int32())[1] = 2;
+  (*message->mutable_map_int64_int64())[1] = 2;
+  (*message->mutable_map_uint32_uint32())[1] = 2;
+  (*message->mutable_map_uint64_uint64())[1] = 2;
+  (*message->mutable_map_sint32_sint32())[1] = 2;
+  (*message->mutable_map_sint64_sint64())[1] = 2;
+  (*message->mutable_map_fixed32_fixed32())[1] = 2;
+  (*message->mutable_map_fixed64_fixed64())[1] = 2;
+  (*message->mutable_map_sfixed32_sfixed32())[1] = 2;
+  (*message->mutable_map_sfixed64_sfixed64())[1] = 2;
+  (*message->mutable_map_int32_float())[1] = 2.0;
+  (*message->mutable_map_int32_double())[1] = 2.0;
+  (*message->mutable_map_bool_bool())[1] = false;
+  (*message->mutable_map_string_string())["1"] = "2";
+  (*message->mutable_map_int32_bytes())[1] = "2";
+  (*message->mutable_map_int32_enum())[1] = enum_value;
+  (*message->mutable_map_int32_foreign_message())[1].set_c(2);
+}
+
+template <typename MapMessage>
+void MapTestUtilImpl::ExpectClear(const MapMessage& message) {
+  EXPECT_EQ(0, message.map_int32_int32().size());
+  EXPECT_EQ(0, message.map_int64_int64().size());
+  EXPECT_EQ(0, message.map_uint32_uint32().size());
+  EXPECT_EQ(0, message.map_uint64_uint64().size());
+  EXPECT_EQ(0, message.map_sint32_sint32().size());
+  EXPECT_EQ(0, message.map_sint64_sint64().size());
+  EXPECT_EQ(0, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(0, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(0, message.map_int32_float().size());
+  EXPECT_EQ(0, message.map_int32_double().size());
+  EXPECT_EQ(0, message.map_bool_bool().size());
+  EXPECT_EQ(0, message.map_string_string().size());
+  EXPECT_EQ(0, message.map_int32_bytes().size());
+  EXPECT_EQ(0, message.map_int32_enum().size());
+  EXPECT_EQ(0, message.map_int32_foreign_message().size());
+}
+
+template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+          typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsSet(const MapMessage& message) {
+  ASSERT_EQ(2, message.map_int32_int32().size());
+  ASSERT_EQ(2, message.map_int64_int64().size());
+  ASSERT_EQ(2, message.map_uint32_uint32().size());
+  ASSERT_EQ(2, message.map_uint64_uint64().size());
+  ASSERT_EQ(2, message.map_sint32_sint32().size());
+  ASSERT_EQ(2, message.map_sint64_sint64().size());
+  ASSERT_EQ(2, message.map_fixed32_fixed32().size());
+  ASSERT_EQ(2, message.map_fixed64_fixed64().size());
+  ASSERT_EQ(2, message.map_sfixed32_sfixed32().size());
+  ASSERT_EQ(2, message.map_sfixed64_sfixed64().size());
+  ASSERT_EQ(2, message.map_int32_float().size());
+  ASSERT_EQ(2, message.map_int32_double().size());
+  ASSERT_EQ(2, message.map_bool_bool().size());
+  ASSERT_EQ(2, message.map_string_string().size());
+  ASSERT_EQ(2, message.map_int32_bytes().size());
+  ASSERT_EQ(2, message.map_int32_enum().size());
+  ASSERT_EQ(2, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("0", message.map_string_string().at("0"));
+  EXPECT_EQ("0", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+  EXPECT_EQ(1, message.map_int64_int64().at(1));
+  EXPECT_EQ(1, message.map_uint32_uint32().at(1));
+  EXPECT_EQ(1, message.map_uint64_uint64().at(1));
+  EXPECT_EQ(1, message.map_sint32_sint32().at(1));
+  EXPECT_EQ(1, message.map_sint64_sint64().at(1));
+  EXPECT_EQ(1, message.map_fixed32_fixed32().at(1));
+  EXPECT_EQ(1, message.map_fixed64_fixed64().at(1));
+  EXPECT_EQ(1, message.map_sfixed32_sfixed32().at(1));
+  EXPECT_EQ(1, message.map_sfixed64_sfixed64().at(1));
+  EXPECT_EQ(1, message.map_int32_float().at(1));
+  EXPECT_EQ(1, message.map_int32_double().at(1));
+  EXPECT_EQ(true, message.map_bool_bool().at(1));
+  EXPECT_EQ("1", message.map_string_string().at("1"));
+  EXPECT_EQ("1", message.map_int32_bytes().at(1));
+  EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+  EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c());
+}
+
+template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+          typename MapMessage>
+void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) {
+  EXPECT_EQ(2, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int64_int64().size());
+  EXPECT_EQ(2, message.map_uint32_uint32().size());
+  EXPECT_EQ(2, message.map_uint64_uint64().size());
+  EXPECT_EQ(2, message.map_sint32_sint32().size());
+  EXPECT_EQ(2, message.map_sint64_sint64().size());
+  EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(2, message.map_int32_float().size());
+  EXPECT_EQ(2, message.map_int32_double().size());
+  EXPECT_EQ(2, message.map_bool_bool().size());
+  EXPECT_EQ(2, message.map_string_string().size());
+  EXPECT_EQ(2, message.map_int32_bytes().size());
+  EXPECT_EQ(2, message.map_int32_enum().size());
+  EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("0", message.map_string_string().at("0"));
+  EXPECT_EQ("0", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+  EXPECT_EQ(1, message.map_int64_int64().at(1));
+  EXPECT_EQ(1, message.map_uint32_uint32().at(1));
+  EXPECT_EQ(1, message.map_uint64_uint64().at(1));
+  EXPECT_EQ(1, message.map_sint32_sint32().at(1));
+  EXPECT_EQ(1, message.map_sint64_sint64().at(1));
+  EXPECT_EQ(1, message.map_fixed32_fixed32().at(1));
+  EXPECT_EQ(1, message.map_fixed64_fixed64().at(1));
+  EXPECT_EQ(1, message.map_sfixed32_sfixed32().at(1));
+  EXPECT_EQ(1, message.map_sfixed64_sfixed64().at(1));
+  EXPECT_EQ(1, message.map_int32_float().at(1));
+  EXPECT_EQ(1, message.map_int32_double().at(1));
+  EXPECT_EQ(true, message.map_bool_bool().at(1));
+  EXPECT_EQ("1", message.map_string_string().at("1"));
+  EXPECT_EQ("1", message.map_int32_bytes().at(1));
+  EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+  EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c());
+}
+
+template <typename EnumType, EnumType enum_value, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsSetInitialized(const MapMessage& message) {
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int64_int64().size());
+  EXPECT_EQ(1, message.map_uint32_uint32().size());
+  EXPECT_EQ(1, message.map_uint64_uint64().size());
+  EXPECT_EQ(1, message.map_sint32_sint32().size());
+  EXPECT_EQ(1, message.map_sint64_sint64().size());
+  EXPECT_EQ(1, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(1, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(1, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(1, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(1, message.map_int32_float().size());
+  EXPECT_EQ(1, message.map_int32_double().size());
+  EXPECT_EQ(1, message.map_bool_bool().size());
+  EXPECT_EQ(1, message.map_string_string().size());
+  EXPECT_EQ(1, message.map_int32_bytes().size());
+  EXPECT_EQ(1, message.map_int32_enum().size());
+  EXPECT_EQ(1, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("", message.map_string_string().at("0"));
+  EXPECT_EQ("", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).ByteSizeLong());
+}
+
+template <typename EnumType, EnumType enum_value0, EnumType enum_value1,
+          typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsModified(const MapMessage& message) {
+  // ModifyMapFields only sets the second element of each field.  In addition to
+  // verifying this, we also verify that the first element and size were *not*
+  // modified.
+  EXPECT_EQ(2, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int64_int64().size());
+  EXPECT_EQ(2, message.map_uint32_uint32().size());
+  EXPECT_EQ(2, message.map_uint64_uint64().size());
+  EXPECT_EQ(2, message.map_sint32_sint32().size());
+  EXPECT_EQ(2, message.map_sint64_sint64().size());
+  EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(2, message.map_int32_float().size());
+  EXPECT_EQ(2, message.map_int32_double().size());
+  EXPECT_EQ(2, message.map_bool_bool().size());
+  EXPECT_EQ(2, message.map_string_string().size());
+  EXPECT_EQ(2, message.map_int32_bytes().size());
+  EXPECT_EQ(2, message.map_int32_enum().size());
+  EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("0", message.map_string_string().at("0"));
+  EXPECT_EQ("0", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(2, message.map_int32_int32().at(1));
+  EXPECT_EQ(2, message.map_int64_int64().at(1));
+  EXPECT_EQ(2, message.map_uint32_uint32().at(1));
+  EXPECT_EQ(2, message.map_uint64_uint64().at(1));
+  EXPECT_EQ(2, message.map_sint32_sint32().at(1));
+  EXPECT_EQ(2, message.map_sint64_sint64().at(1));
+  EXPECT_EQ(2, message.map_fixed32_fixed32().at(1));
+  EXPECT_EQ(2, message.map_fixed64_fixed64().at(1));
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().at(1));
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().at(1));
+  EXPECT_EQ(2, message.map_int32_float().at(1));
+  EXPECT_EQ(2, message.map_int32_double().at(1));
+  EXPECT_EQ(false, message.map_bool_bool().at(1));
+  EXPECT_EQ("2", message.map_string_string().at("1"));
+  EXPECT_EQ("2", message.map_int32_bytes().at(1));
+  EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+  EXPECT_EQ(2, message.map_int32_foreign_message().at(1).c());
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
new file mode 100644
index 0000000..c210c63
--- /dev/null
+++ b/src/google/protobuf/map_type_handler.h
@@ -0,0 +1,736 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
+#define GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Used for compile time type selection. MapIf::type will be TrueType if Flag is
+// true and FalseType otherwise.
+template <bool Flag, typename TrueType, typename FalseType>
+struct MapIf;
+
+template <typename TrueType, typename FalseType>
+struct MapIf<true, TrueType, FalseType> {
+  typedef TrueType type;
+};
+
+template <typename TrueType, typename FalseType>
+struct MapIf<false, TrueType, FalseType> {
+  typedef FalseType type;
+};
+
+template <typename Type, bool is_arena_constructable>
+class MapArenaMessageCreator {
+ public:
+  // Use arena to create message if Type is arena constructable. Otherwise,
+  // create the message on heap.
+  static inline Type* CreateMessage(Arena* arena);
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, true> {
+ public:
+  static inline Type* CreateMessage(Arena* arena) {
+    return Arena::CreateMessage<Type>(arena);
+  }
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, false> {
+ public:
+  static inline Type* CreateMessage(Arena* arena) {
+    return Arena::Create<Type>(arena);
+  }
+};
+
+// Define constants for given wire field type
+template <WireFormatLite::FieldType field_type, typename Type>
+class MapWireFieldTypeTraits {};
+
+#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum)   \
+  template <typename Type>                                                 \
+  class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> {   \
+   public:                                                                 \
+    static const bool kIsMessage = IsMessage;                              \
+    static const bool kIsEnum = IsEnum;                                    \
+    typedef typename MapIf<kIsMessage, Type*, CType>::type TypeOnMemory;   \
+    typedef typename MapIf<kIsEnum, int, Type>::type MapEntryAccessorType; \
+    static const WireFormatLite::WireType kWireType =                      \
+        WireFormatLite::WIRETYPE_##WireFormatType;                         \
+  };
+
+TYPE_TRAITS(MESSAGE, Type, LENGTH_DELIMITED, true, false)
+TYPE_TRAITS(STRING, ArenaStringPtr, LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(BYTES, ArenaStringPtr, LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(INT64, int64_t, VARINT, false, false)
+TYPE_TRAITS(UINT64, uint64_t, VARINT, false, false)
+TYPE_TRAITS(INT32, int32_t, VARINT, false, false)
+TYPE_TRAITS(UINT32, uint32_t, VARINT, false, false)
+TYPE_TRAITS(SINT64, int64_t, VARINT, false, false)
+TYPE_TRAITS(SINT32, int32_t, VARINT, false, false)
+TYPE_TRAITS(ENUM, int, VARINT, false, true)
+TYPE_TRAITS(DOUBLE, double, FIXED64, false, false)
+TYPE_TRAITS(FLOAT, float, FIXED32, false, false)
+TYPE_TRAITS(FIXED64, uint64_t, FIXED64, false, false)
+TYPE_TRAITS(FIXED32, uint32_t, FIXED32, false, false)
+TYPE_TRAITS(SFIXED64, int64_t, FIXED64, false, false)
+TYPE_TRAITS(SFIXED32, int32_t, FIXED32, false, false)
+TYPE_TRAITS(BOOL, bool, VARINT, false, false)
+
+#undef TYPE_TRAITS
+
+template <WireFormatLite::FieldType field_type, typename Type>
+class MapTypeHandler {};
+
+template <typename Type>
+class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
+ public:
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type which will
+  // replace Enum with int.
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+                                          Type>::MapEntryAccessorType
+      MapEntryAccessorType;
+  // Internal stored type in MapEntryLite for given wire field type.
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+                                          Type>::TypeOnMemory TypeOnMemory;
+  // Corresponding wire type for field type.
+  static constexpr WireFormatLite::WireType kWireType =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType;
+  // Whether wire type is for message.
+  static constexpr bool kIsMessage =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage;
+  // Whether wire type is for enum.
+  static constexpr bool kIsEnum =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsEnum;
+
+  // Functions used in parsing and serialization. ===================
+  static inline size_t ByteSize(const MapEntryAccessorType& value);
+  static inline int GetCachedSize(const MapEntryAccessorType& value);
+  static inline bool Read(io::CodedInputStream* input,
+                          MapEntryAccessorType* value);
+  static inline const char* Read(const char* ptr, ParseContext* ctx,
+                                 MapEntryAccessorType* value);
+
+  static inline uint8_t* Write(int field, const MapEntryAccessorType& value,
+                               uint8_t* ptr, io::EpsCopyOutputStream* stream);
+
+  // 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 constexpr TypeOnMemory Constinit();
+
+  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 size_t SpaceUsedInMapEntryLong(const Type* value);
+  // Return default instance if value is not initialized when calling const
+  // reference accessor.
+  static inline const Type& DefaultIfNotInitialized(const Type* value);
+  // Check if all required fields have values set.
+  static inline bool IsInitialized(Type* value);
+};
+
+#define MAP_HANDLER(FieldType)                                                 \
+  template <typename Type>                                                     \
+  class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> {               \
+   public:                                                                     \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,  \
+                                            Type>::MapEntryAccessorType        \
+        MapEntryAccessorType;                                                  \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,  \
+                                            Type>::TypeOnMemory TypeOnMemory;  \
+    static const WireFormatLite::WireType kWireType =                          \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kWireType;                               \
+    static const bool kIsMessage =                                             \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kIsMessage;                              \
+    static const bool kIsEnum =                                                \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kIsEnum;                                 \
+    static inline int ByteSize(const MapEntryAccessorType& value);             \
+    static inline int GetCachedSize(const MapEntryAccessorType& value);        \
+    static inline bool Read(io::CodedInputStream* input,                       \
+                            MapEntryAccessorType* value);                      \
+    static inline const char* Read(const char* begin, ParseContext* ctx,       \
+                                   MapEntryAccessorType* value);               \
+    static inline uint8_t* Write(int field, const MapEntryAccessorType& value, \
+                                 uint8_t* ptr,                                 \
+                                 io::EpsCopyOutputStream* stream);             \
+    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 size_t SpaceUsedInMapEntryLong(const TypeOnMemory& value);   \
+    static inline const MapEntryAccessorType& DefaultIfNotInitialized(         \
+        const TypeOnMemory& value);                                            \
+    static inline bool IsInitialized(const TypeOnMemory& value);               \
+    static void DeleteNoArena(TypeOnMemory& value);                            \
+    static constexpr TypeOnMemory Constinit();                                 \
+    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 size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::ByteSize(
+    const MapEntryAccessorType& value) {
+  return WireFormatLite::MessageSizeNoVirtual(value);
+}
+
+#define GOOGLE_PROTOBUF_BYTE_SIZE(FieldType, DeclaredType)                     \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
+      const MapEntryAccessorType& value) {                                     \
+    return static_cast<int>(WireFormatLite::DeclaredType##Size(value));        \
+  }
+
+GOOGLE_PROTOBUF_BYTE_SIZE(STRING, String)
+GOOGLE_PROTOBUF_BYTE_SIZE(BYTES, Bytes)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT64, Int64)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT64, UInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT32, Int32)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT32, UInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT64, SInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT32, SInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(ENUM, Enum)
+
+#undef GOOGLE_PROTOBUF_BYTE_SIZE
+
+#define FIXED_BYTE_SIZE(FieldType, DeclaredType)                               \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
+      const MapEntryAccessorType& /* value */) {                               \
+    return WireFormatLite::k##DeclaredType##Size;                              \
+  }
+
+FIXED_BYTE_SIZE(DOUBLE, Double)
+FIXED_BYTE_SIZE(FLOAT, Float)
+FIXED_BYTE_SIZE(FIXED64, Fixed64)
+FIXED_BYTE_SIZE(FIXED32, Fixed32)
+FIXED_BYTE_SIZE(SFIXED64, SFixed64)
+FIXED_BYTE_SIZE(SFIXED32, SFixed32)
+FIXED_BYTE_SIZE(BOOL, Bool)
+
+#undef FIXED_BYTE_SIZE
+
+template <typename Type>
+inline int MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetCachedSize(
+    const MapEntryAccessorType& value) {
+  return static_cast<int>(WireFormatLite::LengthDelimitedSize(
+      static_cast<size_t>(value.GetCachedSize())));
+}
+
+#define GET_CACHED_SIZE(FieldType, DeclaredType)                         \
+  template <typename Type>                                               \
+  inline int                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
+      const MapEntryAccessorType& value) {                               \
+    return static_cast<int>(WireFormatLite::DeclaredType##Size(value));  \
+  }
+
+GET_CACHED_SIZE(STRING, String)
+GET_CACHED_SIZE(BYTES, Bytes)
+GET_CACHED_SIZE(INT64, Int64)
+GET_CACHED_SIZE(UINT64, UInt64)
+GET_CACHED_SIZE(INT32, Int32)
+GET_CACHED_SIZE(UINT32, UInt32)
+GET_CACHED_SIZE(SINT64, SInt64)
+GET_CACHED_SIZE(SINT32, SInt32)
+GET_CACHED_SIZE(ENUM, Enum)
+
+#undef GET_CACHED_SIZE
+
+#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType)                   \
+  template <typename Type>                                               \
+  inline int                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
+      const MapEntryAccessorType& /* value */) {                         \
+    return WireFormatLite::k##DeclaredType##Size;                        \
+  }
+
+GET_FIXED_CACHED_SIZE(DOUBLE, Double)
+GET_FIXED_CACHED_SIZE(FLOAT, Float)
+GET_FIXED_CACHED_SIZE(FIXED64, Fixed64)
+GET_FIXED_CACHED_SIZE(FIXED32, Fixed32)
+GET_FIXED_CACHED_SIZE(SFIXED64, SFixed64)
+GET_FIXED_CACHED_SIZE(SFIXED32, SFixed32)
+GET_FIXED_CACHED_SIZE(BOOL, Bool)
+
+#undef GET_FIXED_CACHED_SIZE
+
+template <typename Type>
+inline uint8_t* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
+    int field, const MapEntryAccessorType& value, uint8_t* ptr,
+    io::EpsCopyOutputStream* stream) {
+  ptr = stream->EnsureSpace(ptr);
+  return WireFormatLite::InternalWriteMessage(
+      field, value, value.GetCachedSize(), ptr, stream);
+}
+
+#define WRITE_METHOD(FieldType, DeclaredType)                     \
+  template <typename Type>                                        \
+  inline uint8_t*                                                 \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(  \
+      int field, const MapEntryAccessorType& value, uint8_t* ptr, \
+      io::EpsCopyOutputStream* stream) {                          \
+    ptr = stream->EnsureSpace(ptr);                               \
+    return stream->Write##DeclaredType(field, value, ptr);        \
+  }
+
+WRITE_METHOD(STRING, String)
+WRITE_METHOD(BYTES, Bytes)
+
+#undef WRITE_METHOD
+#define WRITE_METHOD(FieldType, DeclaredType)                               \
+  template <typename Type>                                                  \
+  inline uint8_t*                                                           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(            \
+      int field, const MapEntryAccessorType& value, uint8_t* ptr,           \
+      io::EpsCopyOutputStream* stream) {                                    \
+    ptr = stream->EnsureSpace(ptr);                                         \
+    return WireFormatLite::Write##DeclaredType##ToArray(field, value, ptr); \
+  }
+
+WRITE_METHOD(INT64, Int64)
+WRITE_METHOD(UINT64, UInt64)
+WRITE_METHOD(INT32, Int32)
+WRITE_METHOD(UINT32, UInt32)
+WRITE_METHOD(SINT64, SInt64)
+WRITE_METHOD(SINT32, SInt32)
+WRITE_METHOD(ENUM, Enum)
+WRITE_METHOD(DOUBLE, Double)
+WRITE_METHOD(FLOAT, Float)
+WRITE_METHOD(FIXED64, Fixed64)
+WRITE_METHOD(FIXED32, Fixed32)
+WRITE_METHOD(SFIXED64, SFixed64)
+WRITE_METHOD(SFIXED32, SFixed32)
+WRITE_METHOD(BOOL, Bool)
+
+#undef WRITE_METHOD
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadMessageNoVirtual(input, value);
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadString(input, value);
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadBytes(input, value);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  return ctx->ParseMessage(value, ptr);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ctx->ReadString(ptr, size, value);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ctx->ReadString(ptr, size, value);
+}
+
+inline const char* ReadINT64(const char* ptr, int64_t* value) {
+  return VarintParse(ptr, reinterpret_cast<uint64_t*>(value));
+}
+inline const char* ReadUINT64(const char* ptr, uint64_t* value) {
+  return VarintParse(ptr, value);
+}
+inline const char* ReadINT32(const char* ptr, int32_t* value) {
+  return VarintParse(ptr, reinterpret_cast<uint32_t*>(value));
+}
+inline const char* ReadUINT32(const char* ptr, uint32_t* value) {
+  return VarintParse(ptr, value);
+}
+inline const char* ReadSINT64(const char* ptr, int64_t* value) {
+  *value = ReadVarintZigZag64(&ptr);
+  return ptr;
+}
+inline const char* ReadSINT32(const char* ptr, int32_t* value) {
+  *value = ReadVarintZigZag32(&ptr);
+  return ptr;
+}
+template <typename E>
+inline const char* ReadENUM(const char* ptr, E* value) {
+  *value = static_cast<E>(ReadVarint32(&ptr));
+  return ptr;
+}
+inline const char* ReadBOOL(const char* ptr, bool* value) {
+  *value = static_cast<bool>(ReadVarint32(&ptr));
+  return ptr;
+}
+
+template <typename F>
+inline const char* ReadUnaligned(const char* ptr, F* value) {
+  *value = UnalignedLoad<F>(ptr);
+  return ptr + sizeof(F);
+}
+inline const char* ReadFLOAT(const char* ptr, float* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadDOUBLE(const char* ptr, double* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadFIXED64(const char* ptr, uint64_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadFIXED32(const char* ptr, uint32_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadSFIXED64(const char* ptr, int64_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadSFIXED32(const char* ptr, int32_t* value) {
+  return ReadUnaligned(ptr, 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);                                                      \
+  }                                                                         \
+  template <typename Type>                                                  \
+  const char* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
+      const char* begin, ParseContext* ctx, MapEntryAccessorType* value) {  \
+    (void)ctx;                                                              \
+    return Read##FieldType(begin, value);                                   \
+  }
+
+READ_METHOD(INT64)
+READ_METHOD(UINT64)
+READ_METHOD(INT32)
+READ_METHOD(UINT32)
+READ_METHOD(SINT64)
+READ_METHOD(SINT32)
+READ_METHOD(ENUM)
+READ_METHOD(DOUBLE)
+READ_METHOD(FLOAT)
+READ_METHOD(FIXED64)
+READ_METHOD(FIXED32)
+READ_METHOD(SFIXED64)
+READ_METHOD(SFIXED32)
+READ_METHOD(BOOL)
+
+#undef READ_METHOD
+
+// Definition for message handler
+
+template <typename Type>
+inline const Type&
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetExternalReference(
+    const Type* value) {
+  return *value;
+}
+
+template <typename Type>
+inline size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                             Type>::SpaceUsedInMapEntryLong(const Type* value) {
+  return value->SpaceUsedLong();
+}
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Clear(
+    Type** value, Arena* /* arena */) {
+  if (*value != nullptr) (*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>
+constexpr auto MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Constinit()
+    -> TypeOnMemory {
+  return nullptr;
+}
+
+template <typename Type>
+inline Type* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::EnsureMutable(
+    Type** value, Arena* arena) {
+  if (*value == nullptr) {
+    *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) {
+  return value != nullptr ? *value : *Type::internal_default_instance();
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::IsInitialized(
+    Type* value) {
+  return value ? value->IsInitialized() : false;
+}
+
+// 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();                                                       \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline size_t                                                               \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                            \
+                 Type>::SpaceUsedInMapEntryLong(const TypeOnMemory& value) {  \
+    return sizeof(value);                                                     \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear(  \
+      TypeOnMemory* value, Arena* /* arena */) {                              \
+    value->ClearToEmpty();                                                    \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge(  \
+      const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) {     \
+    to->Set(from, arena);                                                     \
+  }                                                                           \
+  template <typename Type>                                                    \
+  void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena( \
+      TypeOnMemory& value) {                                                  \
+    value.Destroy();                                                          \
+  }                                                                           \
+  template <typename Type>                                                    \
+  constexpr auto                                                              \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Constinit()         \
+      ->TypeOnMemory {                                                        \
+    return TypeOnMemory(&internal::fixed_address_empty_string,                \
+                        ConstantInitialized{});                               \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,            \
+                                 Type>::MapEntryAccessorType*                 \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable(      \
+      TypeOnMemory* value, Arena* arena) {                                    \
+    return value->Mutable(arena);                                             \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,      \
+                                       Type>::MapEntryAccessorType&           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                            \
+                 Type>::DefaultIfNotInitialized(const TypeOnMemory& value) {  \
+    return value.Get();                                                       \
+  }                                                                           \
+  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 size_t MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::     \
+      SpaceUsedInMapEntryLong(const TypeOnMemory& /* value */) {             \
+    return 0;                                                                \
+  }                                                                          \
+  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>::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>                                                   \
+  constexpr auto                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Constinit()        \
+      ->TypeOnMemory {                                                       \
+    return 0;                                                                \
+  }                                                                          \
+  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) { \
+    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
+
+// Functions for operating on a map entry using type handlers.
+//
+// Does not contain any representation (this class is not intended to be
+// instantiated).
+template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryFuncs {
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+  enum : int {
+    kKeyFieldNumber = 1,
+    kValueFieldNumber = 2
+  };
+
+  static uint8_t* InternalSerialize(int field_number, const Key& key,
+                                    const Value& value, uint8_t* ptr,
+                                    io::EpsCopyOutputStream* stream) {
+    ptr = stream->EnsureSpace(ptr);
+    ptr = WireFormatLite::WriteTagToArray(
+        field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
+    ptr = io::CodedOutputStream::WriteVarint32ToArray(GetCachedSize(key, value),
+                                                      ptr);
+
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key, ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value, ptr, stream);
+  }
+
+  static size_t ByteSizeLong(const Key& key, const Value& value) {
+    // Tags for key and value will both be one byte (field numbers 1 and 2).
+    size_t inner_length =
+        2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
+    return inner_length + io::CodedOutputStream::VarintSize32(
+                              static_cast<uint32_t>(inner_length));
+  }
+
+  static int GetCachedSize(const Key& key, const Value& value) {
+    // Tags for key and value will both be one byte (field numbers 1 and 2).
+    return 2 + KeyTypeHandler::GetCachedSize(key) +
+           ValueTypeHandler::GetCachedSize(value);
+  }
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto
new file mode 100644
index 0000000..263ef61
--- /dev/null
+++ b/src/google/protobuf/map_unittest.proto
@@ -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.
+
+syntax = "proto3";
+
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Tests maps.
+message TestMap {
+  map<int32, int32> map_int32_int32 = 1;
+  map<int64, int64> map_int64_int64 = 2;
+  map<uint32, uint32> map_uint32_uint32 = 3;
+  map<uint64, uint64> map_uint64_uint64 = 4;
+  map<sint32, sint32> map_sint32_sint32 = 5;
+  map<sint64, sint64> map_sint64_sint64 = 6;
+  map<fixed32, fixed32> map_fixed32_fixed32 = 7;
+  map<fixed64, fixed64> map_fixed64_fixed64 = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32, float> map_int32_float = 11;
+  map<int32, double> map_int32_double = 12;
+  map<bool, bool> map_bool_bool = 13;
+  map<string, string> map_string_string = 14;
+  map<int32, bytes> map_int32_bytes = 15;
+  map<int32, MapEnum> map_int32_enum = 16;
+  map<int32, ForeignMessage> map_int32_foreign_message = 17;
+  map<string, ForeignMessage> map_string_foreign_message = 18;
+  map<int32, TestAllTypes> map_int32_all_types = 19;
+}
+
+message TestMapSubmessage {
+  TestMap test_map = 1;
+}
+
+message TestMessageMap {
+  map<int32, TestAllTypes> map_int32_message = 1;
+}
+
+// Two map fields share the same entry default instance.
+message TestSameTypeMap {
+  map<int32, int32> map1 = 1;
+  map<int32, int32> map2 = 2;
+}
+
+
+enum MapEnum {
+  MAP_ENUM_FOO = 0;
+  MAP_ENUM_BAR = 1;
+  MAP_ENUM_BAZ = 2;
+}
+
+// Test embedded message with required fields
+message TestRequiredMessageMap {
+  map<int32, TestRequired> map_field = 1;
+}
+
+message TestArenaMap {
+  map<int32, int32> map_int32_int32 = 1;
+  map<int64, int64> map_int64_int64 = 2;
+  map<uint32, uint32> map_uint32_uint32 = 3;
+  map<uint64, uint64> map_uint64_uint64 = 4;
+  map<sint32, sint32> map_sint32_sint32 = 5;
+  map<sint64, sint64> map_sint64_sint64 = 6;
+  map<fixed32, fixed32> map_fixed32_fixed32 = 7;
+  map<fixed64, fixed64> map_fixed64_fixed64 = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32, float> map_int32_float = 11;
+  map<int32, double> map_int32_double = 12;
+  map<bool, bool> map_bool_bool = 13;
+  map<string, string> map_string_string = 14;
+  map<int32, bytes> map_int32_bytes = 15;
+  map<int32, MapEnum> map_int32_enum = 16;
+  map<int32, ForeignMessage> map_int32_foreign_message = 17;
+}
+
+// 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/message.cc b/src/google/protobuf/message.cc
new file mode 100644
index 0000000..6cdc6c8
--- /dev/null
+++ b/src/google/protobuf/message.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/message.h>
+
+#include <iostream>
+#include <stack>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/casts.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.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/reflection_internal.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+// TODO(gerbens) make this factorized better. This should not have to hop
+// to reflection. Currently uses GeneratedMessageReflection and thus is
+// defined in generated_message_reflection.cc
+void RegisterFileLevelMetadata(const DescriptorTable* descriptor_table);
+
+}  // namespace internal
+
+using internal::ReflectionOps;
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+void Message::MergeFrom(const Message& from) {
+  auto* class_to = GetClassData();
+  auto* class_from = from.GetClassData();
+  auto* merge_to_from = class_to ? class_to->merge_to_from : nullptr;
+  if (class_to == nullptr || class_to != class_from) {
+    merge_to_from = [](Message& to, const Message& from) {
+      ReflectionOps::Merge(from, &to);
+    };
+  }
+  merge_to_from(*this, from);
+}
+
+void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
+  MergeFrom(*down_cast<const Message*>(&other));
+}
+
+void Message::CopyFrom(const Message& from) {
+  if (&from == this) return;
+
+  auto* class_to = GetClassData();
+  auto* class_from = from.GetClassData();
+  auto* copy_to_from = class_to ? class_to->copy_to_from : nullptr;
+
+  if (class_to == nullptr || class_to != class_from) {
+    const Descriptor* descriptor = GetDescriptor();
+    GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
+        << ": Tried to copy from a message with a different type. "
+           "to: "
+        << descriptor->full_name()
+        << ", "
+           "from: "
+        << from.GetDescriptor()->full_name();
+    copy_to_from = [](Message& to, const Message& from) {
+      ReflectionOps::Copy(from, &to);
+    };
+  }
+  copy_to_from(*this, from);
+}
+
+void Message::CopyWithSourceCheck(Message& to, const Message& from) {
+#ifndef NDEBUG
+  FailIfCopyFromDescendant(to, from);
+#endif
+  to.Clear();
+  to.GetClassData()->merge_to_from(to, from);
+}
+
+void Message::FailIfCopyFromDescendant(Message& to, const Message& from) {
+  auto* arena = to.GetArenaForAllocation();
+  bool same_message_owned_arena = to.GetOwningArena() == nullptr &&
+                                  arena != nullptr &&
+                                  arena == from.GetOwningArena();
+  GOOGLE_CHECK(!same_message_owned_arena && !internal::IsDescendant(to, from))
+      << "Source of CopyFrom cannot be a descendant of the target.";
+}
+
+std::string Message::GetTypeName() const {
+  return GetDescriptor()->full_name();
+}
+
+void Message::Clear() { ReflectionOps::Clear(this); }
+
+bool Message::IsInitialized() const {
+  return ReflectionOps::IsInitialized(*this);
+}
+
+void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
+  return ReflectionOps::FindInitializationErrors(*this, "", errors);
+}
+
+std::string Message::InitializationErrorString() const {
+  std::vector<std::string> errors;
+  FindInitializationErrors(&errors);
+  return Join(errors, ", ");
+}
+
+void Message::CheckInitialized() const {
+  GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
+                         << "\" is missing required fields: "
+                         << InitializationErrorString();
+}
+
+void Message::DiscardUnknownFields() {
+  return ReflectionOps::DiscardUnknownFields(this);
+}
+
+const char* Message::_InternalParse(const char* ptr,
+                                    internal::ParseContext* ctx) {
+  return WireFormat::_InternalParse(this, ptr, ctx);
+}
+
+uint8_t* Message::_InternalSerialize(uint8_t* target,
+                                     io::EpsCopyOutputStream* stream) const {
+  return WireFormat::_InternalSerialize(*this, target, stream);
+}
+
+size_t Message::ByteSizeLong() const {
+  size_t size = WireFormat::ByteSize(*this);
+  SetCachedSize(internal::ToCachedSize(size));
+  return size;
+}
+
+void Message::SetCachedSize(int /* size */) const {
+  GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
+             << "\" implements neither SetCachedSize() nor ByteSize().  "
+                "Must implement one or the other.";
+}
+
+size_t Message::ComputeUnknownFieldsSize(
+    size_t total_size, internal::CachedSize* cached_size) const {
+  total_size += WireFormat::ComputeUnknownFieldsSize(
+      _internal_metadata_.unknown_fields<UnknownFieldSet>(
+          UnknownFieldSet::default_instance));
+  cached_size->Set(internal::ToCachedSize(total_size));
+  return total_size;
+}
+
+size_t Message::MaybeComputeUnknownFieldsSize(
+    size_t total_size, internal::CachedSize* cached_size) const {
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ComputeUnknownFieldsSize(total_size, cached_size);
+  }
+  cached_size->Set(internal::ToCachedSize(total_size));
+  return total_size;
+}
+
+size_t Message::SpaceUsedLong() const {
+  return GetReflection()->SpaceUsedLong(*this);
+}
+
+uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
+  return salt;
+}
+
+// =============================================================================
+// MessageFactory
+
+MessageFactory::~MessageFactory() {}
+
+namespace {
+
+
+#define HASH_MAP std::unordered_map
+#define STR_HASH_FXN hash<::google::protobuf::StringPiece>
+
+
+class GeneratedMessageFactory final : public MessageFactory {
+ public:
+  static GeneratedMessageFactory* singleton();
+
+  void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
+  void RegisterType(const Descriptor* descriptor, const Message* prototype);
+
+  // implements MessageFactory ---------------------------------------
+  const Message* GetPrototype(const Descriptor* type) override;
+
+ private:
+  // Only written at static init time, so does not require locking.
+  HASH_MAP<StringPiece, const google::protobuf::internal::DescriptorTable*,
+           STR_HASH_FXN>
+      file_map_;
+
+  internal::WrappedMutex mutex_;
+  // Initialized lazily, so requires locking.
+  std::unordered_map<const Descriptor*, const Message*> type_map_;
+};
+
+GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
+  static auto instance =
+      internal::OnShutdownDelete(new GeneratedMessageFactory);
+  return instance;
+}
+
+void GeneratedMessageFactory::RegisterFile(
+    const google::protobuf::internal::DescriptorTable* table) {
+  if (!InsertIfNotPresent(&file_map_, table->filename, table)) {
+    GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
+  }
+}
+
+void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
+                                           const Message* prototype) {
+  GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
+      << "Tried to register a non-generated type with the generated "
+         "type registry.";
+
+  // This should only be called as a result of calling a file registration
+  // function during GetPrototype(), in which case we already have locked
+  // the mutex.
+  mutex_.AssertHeld();
+  if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
+    GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
+  }
+}
+
+
+const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
+  {
+    ReaderMutexLock lock(&mutex_);
+    const Message* result = FindPtrOrNull(type_map_, type);
+    if (result != nullptr) return result;
+  }
+
+  // If the type is not in the generated pool, then we can't possibly handle
+  // it.
+  if (type->file()->pool() != DescriptorPool::generated_pool()) return nullptr;
+
+  // Apparently the file hasn't been registered yet.  Let's do that now.
+  const internal::DescriptorTable* registration_data =
+      FindPtrOrNull(file_map_, type->file()->name().c_str());
+  if (registration_data == nullptr) {
+    GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
+                   "registered: "
+                << type->file()->name();
+    return nullptr;
+  }
+
+  WriterMutexLock lock(&mutex_);
+
+  // Check if another thread preempted us.
+  const Message* result = FindPtrOrNull(type_map_, type);
+  if (result == nullptr) {
+    // Nope.  OK, register everything.
+    internal::RegisterFileLevelMetadata(registration_data);
+    // Should be here now.
+    result = FindPtrOrNull(type_map_, type);
+  }
+
+  if (result == nullptr) {
+    GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
+                << "registered: " << type->full_name();
+  }
+
+  return result;
+}
+
+}  // namespace
+
+MessageFactory* MessageFactory::generated_factory() {
+  return GeneratedMessageFactory::singleton();
+}
+
+void MessageFactory::InternalRegisterGeneratedFile(
+    const google::protobuf::internal::DescriptorTable* table) {
+  GeneratedMessageFactory::singleton()->RegisterFile(table);
+}
+
+void MessageFactory::InternalRegisterGeneratedMessage(
+    const Descriptor* descriptor, const Message* prototype) {
+  GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
+}
+
+
+namespace {
+template <typename T>
+T* GetSingleton() {
+  static T singleton;
+  return &singleton;
+}
+}  // namespace
+
+const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK(field->is_repeated());
+  switch (field->cpp_type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
+  case FieldDescriptor::CPPTYPE_##TYPE:   \
+    return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
+    HANDLE_PRIMITIVE_TYPE(INT32, int32_t)
+    HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t)
+    HANDLE_PRIMITIVE_TYPE(INT64, int64_t)
+    HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t)
+    HANDLE_PRIMITIVE_TYPE(FLOAT, float)
+    HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
+    HANDLE_PRIMITIVE_TYPE(BOOL, bool)
+    HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
+#undef HANDLE_PRIMITIVE_TYPE
+    case FieldDescriptor::CPPTYPE_STRING:
+      switch (field->options().ctype()) {
+        default:
+        case FieldOptions::STRING:
+          return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
+      }
+      break;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      if (field->is_map()) {
+        return GetSingleton<internal::MapFieldAccessor>();
+      } else {
+        return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
+      }
+  }
+  GOOGLE_LOG(FATAL) << "Should not reach here.";
+  return nullptr;
+}
+
+namespace internal {
+template <>
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
+// #240
+PROTOBUF_NOINLINE
+#endif
+    Message*
+    GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
+                                                  Arena* arena) {
+  return prototype->New(arena);
+}
+template <>
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
+// #240
+PROTOBUF_NOINLINE
+#endif
+    Arena*
+    GenericTypeHandler<Message>::GetOwningArena(Message* value) {
+  return value->GetOwningArena();
+}
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
new file mode 100644
index 0000000..39ec154
--- /dev/null
+++ b/src/google/protobuf/message.h
@@ -0,0 +1,1497 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Defines Message, the abstract interface implemented by non-lite
+// protocol message objects.  Although it's possible to implement this
+// interface manually, most users will use the protocol compiler to
+// generate implementations.
+//
+// Example usage:
+//
+// Say you have a message defined as:
+//
+//   message Foo {
+//     optional string text = 1;
+//     repeated int32 numbers = 2;
+//   }
+//
+// Then, if you used the protocol compiler to generate a class from the above
+// definition, you could use it like so:
+//
+//   std::string data;  // Will store a serialized version of the message.
+//
+//   {
+//     // Create a message and serialize it.
+//     Foo foo;
+//     foo.set_text("Hello World!");
+//     foo.add_numbers(1);
+//     foo.add_numbers(5);
+//     foo.add_numbers(42);
+//
+//     foo.SerializeToString(&data);
+//   }
+//
+//   {
+//     // Parse the serialized message and check that it contains the
+//     // correct data.
+//     Foo foo;
+//     foo.ParseFromString(data);
+//
+//     assert(foo.text() == "Hello World!");
+//     assert(foo.numbers_size() == 3);
+//     assert(foo.numbers(0) == 1);
+//     assert(foo.numbers(1) == 5);
+//     assert(foo.numbers(2) == 42);
+//   }
+//
+//   {
+//     // Same as the last block, but do it dynamically via the Message
+//     // reflection interface.
+//     Message* foo = new Foo;
+//     const Descriptor* descriptor = foo->GetDescriptor();
+//
+//     // Get the descriptors for the fields we're interested in and verify
+//     // their types.
+//     const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
+//     assert(text_field != nullptr);
+//     assert(text_field->type() == FieldDescriptor::TYPE_STRING);
+//     assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
+//     const FieldDescriptor* numbers_field = descriptor->
+//                                            FindFieldByName("numbers");
+//     assert(numbers_field != nullptr);
+//     assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
+//     assert(numbers_field->label() == FieldDescriptor::LABEL_REPEATED);
+//
+//     // Parse the message.
+//     foo->ParseFromString(data);
+//
+//     // 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);
+//
+//     delete foo;
+//   }
+
+#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
+#define GOOGLE_PROTOBUF_MESSAGE_H__
+
+
+#include <iosfwd>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map.h>  // TODO(b/211442718): cleanup
+#include <google/protobuf/message_lite.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Message;
+class Reflection;
+class MessageFactory;
+
+// Defined in other files.
+class AssignDescriptorsHelper;
+class DynamicMessageFactory;
+class GeneratedMessageReflectionTestHelper;
+class MapKey;
+class MapValueConstRef;
+class MapValueRef;
+class MapIterator;
+class MapReflectionTester;
+
+namespace internal {
+struct DescriptorTable;
+class MapFieldBase;
+class SwapFieldHelper;
+class CachedSize;
+}  // namespace internal
+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
+}  // namespace io
+namespace python {
+class MapReflectionFriend;  // scalar_map_container.h
+class MessageReflectionFriend;
+}  // namespace python
+namespace expr {
+class CelMapReflectionFriend;  // field_backed_map_impl.cc
+}
+
+namespace internal {
+class MapFieldPrinterHelper;  // text_format.cc
+}
+namespace util {
+class MessageDifferencer;
+}
+
+
+namespace internal {
+class ReflectionAccessor;      // message.cc
+class ReflectionOps;           // reflection_ops.h
+class MapKeySorter;            // wire_format.cc
+class WireFormat;              // wire_format.h
+class MapFieldReflectionTest;  // map_test.cc
+}  // namespace internal
+
+template <typename T>
+class RepeatedField;  // repeated_field.h
+
+template <typename T>
+class RepeatedPtrField;  // repeated_field.h
+
+// A container to hold message metadata.
+struct Metadata {
+  const Descriptor* descriptor;
+  const Reflection* reflection;
+};
+
+namespace internal {
+template <class To>
+inline To* GetPointerAtOffset(Message* message, uint32_t offset) {
+  return reinterpret_cast<To*>(reinterpret_cast<char*>(message) + offset);
+}
+
+template <class To>
+const To* GetConstPointerAtOffset(const Message* message, uint32_t offset) {
+  return reinterpret_cast<const To*>(reinterpret_cast<const char*>(message) +
+                                     offset);
+}
+
+template <class To>
+const To& GetConstRefAtOffset(const Message& message, uint32_t offset) {
+  return *GetConstPointerAtOffset<To>(&message, offset);
+}
+
+bool CreateUnknownEnumValues(const FieldDescriptor* field);
+
+// Returns true if "message" is a descendant of "root".
+PROTOBUF_EXPORT bool IsDescendant(Message& root, const Message& message);
+}  // namespace internal
+
+// Abstract interface for protocol messages.
+//
+// See also MessageLite, which contains most every-day operations.  Message
+// adds descriptors and reflection on top of that.
+//
+// The methods of this class that are virtual but not pure-virtual have
+// default implementations based on reflection.  Message classes which are
+// optimized for speed will want to override these with faster implementations,
+// but classes optimized for code size may be happy with keeping them.  See
+// the optimize_for option in descriptor.proto.
+//
+// Users must not derive from this class. Only the protocol compiler and
+// the internal library are allowed to create subclasses.
+class PROTOBUF_EXPORT Message : public MessageLite {
+ public:
+  constexpr Message() {}
+
+  // Basic Operations ------------------------------------------------
+
+  // Construct a new instance of the same type.  Ownership is passed to the
+  // caller.  (This is also defined in MessageLite, but is defined again here
+  // for return-type covariance.)
+  Message* New() const { return New(nullptr); }
+
+  // Construct a new instance on the arena. Ownership is passed to the caller
+  // if arena is a nullptr.
+  Message* New(Arena* arena) const override = 0;
+
+  // Make this message into a copy of the given message.  The given message
+  // must have the same descriptor, but need not necessarily be the same class.
+  // By default this is just implemented as "Clear(); MergeFrom(from);".
+  void CopyFrom(const Message& from);
+
+  // Merge the fields from the given message into this message.  Singular
+  // fields will be overwritten, if specified in from, except for embedded
+  // messages which will be merged.  Repeated fields will be concatenated.
+  // The given message must be of the same type as this message (i.e. the
+  // exact same class).
+  virtual void MergeFrom(const Message& from);
+
+  // Verifies that IsInitialized() returns true.  GOOGLE_CHECK-fails otherwise, with
+  // a nice error message.
+  void CheckInitialized() const;
+
+  // Slowly build a list of all required fields that are not set.
+  // This is much, much slower than IsInitialized() as it is implemented
+  // purely via reflection.  Generally, you should not call this unless you
+  // have already determined that an error exists by calling IsInitialized().
+  void FindInitializationErrors(std::vector<std::string>* errors) const;
+
+  // Like FindInitializationErrors, but joins all the strings, delimited by
+  // commas, and returns them.
+  std::string InitializationErrorString() const override;
+
+  // Clears all unknown fields from this message and all embedded messages.
+  // Normally, if unknown tag numbers are encountered when parsing a message,
+  // the tag and value are stored in the message's UnknownFieldSet and
+  // then written back out when the message is serialized.  This allows servers
+  // which simply route messages to other servers to pass through messages
+  // that have new field definitions which they don't yet know about.  However,
+  // this behavior can have security implications.  To avoid it, call this
+  // method after parsing.
+  //
+  // See Reflection::GetUnknownFields() for more on unknown fields.
+  void DiscardUnknownFields();
+
+  // 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 size_t SpaceUsedLong() const;
+
+  PROTOBUF_DEPRECATED_MSG("Please use SpaceUsedLong() instead")
+  int SpaceUsed() const { return internal::ToIntSize(SpaceUsedLong()); }
+
+  // Debugging & Testing----------------------------------------------
+
+  // Generates a human-readable form of this message for debugging purposes.
+  // Note that the format and content of a debug string is not guaranteed, may
+  // change without notice, and should not be depended on. Code that does
+  // anything except display a string to assist in debugging should use
+  // TextFormat instead.
+  std::string DebugString() const;
+  // Like DebugString(), but with less whitespace.
+  std::string ShortDebugString() const;
+  // Like DebugString(), but do not escape UTF-8 byte sequences.
+  std::string Utf8DebugString() const;
+  // Convenience function useful in GDB.  Prints DebugString() to stdout.
+  void PrintDebugString() const;
+
+  // Reflection-based methods ----------------------------------------
+  // These methods are pure-virtual in MessageLite, but Message provides
+  // reflection-based default implementations.
+
+  std::string GetTypeName() const override;
+  void Clear() override;
+
+  // Returns whether all required fields have been set. Note that required
+  // fields no longer exist starting in proto3.
+  bool IsInitialized() const override;
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) override;
+  // Reflective parser
+  const char* _InternalParse(const char* ptr,
+                             internal::ParseContext* ctx) override;
+  size_t ByteSizeLong() const override;
+  uint8_t* _InternalSerialize(uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const override;
+
+ private:
+  // This is called only by the default implementation of ByteSize(), to
+  // update the cached size.  If you override ByteSize(), you do not need
+  // to override this.  If you do not override ByteSize(), you MUST override
+  // this; the default implementation will crash.
+  //
+  // The method is private because subclasses should never call it; only
+  // override it.  Yes, C++ lets you do that.  Crazy, huh?
+  virtual void SetCachedSize(int size) const;
+
+ public:
+  // Introspection ---------------------------------------------------
+
+
+  // Get a non-owning pointer to a Descriptor for this message's type.  This
+  // describes what fields the message contains, the types of those fields, etc.
+  // This object remains property of the Message.
+  const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; }
+
+  // Get a non-owning pointer to the Reflection interface for this Message,
+  // which can be used to read and modify the fields of the Message dynamically
+  // (in other words, without knowing the message type at compile time).  This
+  // object remains property of the Message.
+  const Reflection* GetReflection() const { return GetMetadata().reflection; }
+
+ protected:
+  // Get a struct containing the metadata for the Message, which is used in turn
+  // to implement GetDescriptor() and GetReflection() above.
+  virtual Metadata GetMetadata() const = 0;
+
+  struct ClassData {
+    // Note: The order of arguments (to, then from) is chosen so that the ABI
+    // of this function is the same as the CopyFrom method.  That is, the
+    // hidden "this" parameter comes first.
+    void (*copy_to_from)(Message& to, const Message& from_msg);
+    void (*merge_to_from)(Message& to, const Message& from_msg);
+  };
+  // GetClassData() returns a pointer to a ClassData struct which
+  // exists in global memory and is unique to each subclass.  This uniqueness
+  // property is used in order to quickly determine whether two messages are
+  // of the same type.
+  // TODO(jorg): change to pure virtual
+  virtual const ClassData* GetClassData() const { return nullptr; }
+
+  // CopyWithSourceCheck calls Clear() and then MergeFrom(), and in debug
+  // builds, checks that calling Clear() on the destination message doesn't
+  // alter the source.  It assumes the messages are known to be of the same
+  // type, and thus uses GetClassData().
+  static void CopyWithSourceCheck(Message& to, const Message& from);
+
+  // Fail if "from" is a descendant of "to" as such copy is not allowed.
+  static void FailIfCopyFromDescendant(Message& to, const Message& from);
+
+  inline explicit Message(Arena* arena, bool is_message_owned = false)
+      : MessageLite(arena, is_message_owned) {}
+  size_t ComputeUnknownFieldsSize(size_t total_size,
+                                  internal::CachedSize* cached_size) const;
+  size_t MaybeComputeUnknownFieldsSize(size_t total_size,
+                                       internal::CachedSize* cached_size) const;
+
+
+ protected:
+  static uint64_t GetInvariantPerBuild(uint64_t salt);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
+};
+
+namespace internal {
+// Forward-declare interfaces used to implement RepeatedFieldRef.
+// These are protobuf internals that users shouldn't care about.
+class RepeatedFieldAccessor;
+}  // namespace internal
+
+// Forward-declare RepeatedFieldRef templates. The second type parameter is
+// used for SFINAE tricks. Users should ignore it.
+template <typename T, typename Enable = void>
+class RepeatedFieldRef;
+
+template <typename T, typename Enable = void>
+class MutableRepeatedFieldRef;
+
+// This interface contains methods that can be used to dynamically access
+// and modify the fields of a protocol message.  Their semantics are
+// similar to the accessors the protocol compiler generates.
+//
+// To get the Reflection for a given Message, call Message::GetReflection().
+//
+// This interface is separate from Message only for efficiency reasons;
+// the vast majority of implementations of Message will share the same
+// implementation of Reflection (GeneratedMessageReflection,
+// defined in generated_message.h), and all Messages of a particular class
+// should share the same Reflection object (though you should not rely on
+// the latter fact).
+//
+// There are several ways that these methods can be used incorrectly.  For
+// example, any of the following conditions will lead to undefined
+// results (probably assertion failures):
+// - The FieldDescriptor is not a field of this message type.
+// - The method called is not appropriate for the field's type.  For
+//   each field type in FieldDescriptor::TYPE_*, there is only one
+//   Get*() method, one Set*() method, and one Add*() method that is
+//   valid for that type.  It should be obvious which (except maybe
+//   for TYPE_BYTES, which are represented using strings in C++).
+// - A Get*() or Set*() method for singular fields is called on a repeated
+//   field.
+// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated
+//   field.
+// - The Message object passed to any method is not of the right type for
+//   this Reflection object (i.e. message.GetReflection() != reflection).
+//
+// You might wonder why there is not any abstract representation for a field
+// of arbitrary type.  E.g., why isn't there just a "GetField()" method that
+// returns "const Field&", where "Field" is some class with accessors like
+// "GetInt32Value()".  The problem is that someone would have to deal with
+// allocating these Field objects.  For generated message classes, having to
+// allocate space for an additional object to wrap every field would at least
+// double the message's memory footprint, probably worse.  Allocating the
+// objects on-demand, on the other hand, would be expensive and prone to
+// memory leaks.  So, instead we ended up with this flat interface.
+class PROTOBUF_EXPORT Reflection final {
+ public:
+  // Get the UnknownFieldSet for the message.  This contains fields which
+  // were seen when the Message was parsed but were not recognized according
+  // to the Message's definition.
+  const UnknownFieldSet& GetUnknownFields(const Message& message) const;
+  // Get a mutable pointer to the UnknownFieldSet for the message.  This
+  // contains fields which were seen when the Message was parsed but were not
+  // recognized according to the Message's definition.
+  UnknownFieldSet* MutableUnknownFields(Message* message) const;
+
+  // Estimate the amount of memory used by the message object.
+  size_t SpaceUsedLong(const Message& message) const;
+
+  PROTOBUF_DEPRECATED_MSG("Please use SpaceUsedLong() instead")
+  int SpaceUsed(const Message& message) const {
+    return internal::ToIntSize(SpaceUsedLong(message));
+  }
+
+  // Check if the given non-repeated field is set.
+  bool HasField(const Message& message, const FieldDescriptor* field) const;
+
+  // Get the number of elements of a repeated field.
+  int FieldSize(const Message& message, const FieldDescriptor* field) const;
+
+  // Clear the value of a field, so that HasField() returns false or
+  // FieldSize() returns zero.
+  void ClearField(Message* message, const FieldDescriptor* field) const;
+
+  // Check if the oneof is set. Returns true if any field in oneof
+  // is set, false otherwise.
+  bool HasOneof(const Message& message,
+                const OneofDescriptor* oneof_descriptor) const;
+
+  void ClearOneof(Message* message,
+                  const OneofDescriptor* oneof_descriptor) const;
+
+  // Returns the field descriptor if the oneof is set. nullptr otherwise.
+  const FieldDescriptor* GetOneofFieldDescriptor(
+      const Message& message, const OneofDescriptor* oneof_descriptor) const;
+
+  // Removes the last element of a repeated field.
+  // We don't provide a way to remove any element other than the last
+  // because it invites inefficient use, such as O(n^2) filtering loops
+  // that should have been O(n).  If you want to remove an element other
+  // than the last, the best way to do it is to re-arrange the elements
+  // (using Swap()) so that the one you want removed is at the end, then
+  // call RemoveLast().
+  void RemoveLast(Message* message, const FieldDescriptor* field) const;
+  // Removes the last element of a repeated message field, and returns the
+  // pointer to the caller.  Caller takes ownership of the returned pointer.
+  PROTOBUF_NODISCARD Message* ReleaseLast(Message* message,
+                                          const FieldDescriptor* field) const;
+
+  // Similar to ReleaseLast() without internal safety and ownershp checks. This
+  // method should only be used when the objects are on the same arena or paired
+  // with a call to `UnsafeArenaAddAllocatedMessage`.
+  Message* UnsafeArenaReleaseLast(Message* message,
+                                  const FieldDescriptor* field) const;
+
+  // Swap the complete contents of two messages.
+  void Swap(Message* message1, Message* message2) const;
+
+  // Swap fields listed in fields vector of two messages.
+  void SwapFields(Message* message1, Message* message2,
+                  const std::vector<const FieldDescriptor*>& fields) const;
+
+  // Swap two elements of a repeated field.
+  void SwapElements(Message* message, const FieldDescriptor* field, int index1,
+                    int index2) const;
+
+  // Swap without internal safety and ownership checks. This method should only
+  // be used when the objects are on the same arena.
+  void UnsafeArenaSwap(Message* lhs, Message* rhs) const;
+
+  // SwapFields without internal safety and ownership checks. This method should
+  // only be used when the objects are on the same arena.
+  void UnsafeArenaSwapFields(
+      Message* lhs, Message* rhs,
+      const std::vector<const FieldDescriptor*>& fields) const;
+
+  // List all fields of the message which are currently set, except for unknown
+  // fields, but including extension known to the parser (i.e. compiled in).
+  // Singular fields will only be listed if HasField(field) would return true
+  // and repeated fields will only be listed if FieldSize(field) would return
+  // non-zero.  Fields (both normal fields and extension fields) will be listed
+  // ordered by field number.
+  // Use Reflection::GetUnknownFields() or message.unknown_fields() to also get
+  // access to fields/extensions unknown to the parser.
+  void ListFields(const Message& message,
+                  std::vector<const FieldDescriptor*>* output) const;
+
+  // Singular field getters ------------------------------------------
+  // These get the value of a non-repeated field.  They return the default
+  // value for fields that aren't set.
+
+  int32_t GetInt32(const Message& message, const FieldDescriptor* field) const;
+  int64_t GetInt64(const Message& message, const FieldDescriptor* field) const;
+  uint32_t GetUInt32(const Message& message,
+                     const FieldDescriptor* field) const;
+  uint64_t GetUInt64(const Message& message,
+                     const FieldDescriptor* field) const;
+  float GetFloat(const Message& message, const FieldDescriptor* field) const;
+  double GetDouble(const Message& message, const FieldDescriptor* field) const;
+  bool GetBool(const Message& message, const FieldDescriptor* field) const;
+  std::string GetString(const Message& message,
+                        const FieldDescriptor* field) const;
+  const EnumValueDescriptor* GetEnum(const Message& message,
+                                     const FieldDescriptor* field) const;
+
+  // GetEnumValue() returns an enum field's value as an integer rather than
+  // an EnumValueDescriptor*. If the integer value does not correspond to a
+  // known value descriptor, a new value descriptor is created. (Such a value
+  // will only be present when the new unknown-enum-value semantics are enabled
+  // for a message.)
+  int GetEnumValue(const Message& message, const FieldDescriptor* field) const;
+
+  // See MutableMessage() for the meaning of the "factory" parameter.
+  const Message& GetMessage(const Message& message,
+                            const FieldDescriptor* field,
+                            MessageFactory* factory = nullptr) const;
+
+  // Get a string value without copying, if possible.
+  //
+  // GetString() necessarily returns a copy of the string.  This can be
+  // inefficient when the std::string is already stored in a std::string object
+  // in the underlying message.  GetStringReference() will return a reference to
+  // the underlying std::string in this case.  Otherwise, it will copy the
+  // string into *scratch and return that.
+  //
+  // Note:  It is perfectly reasonable and useful to write code like:
+  //     str = reflection->GetStringReference(message, field, &str);
+  //   This line would ensure that only one copy of the string is made
+  //   regardless of the field's underlying representation.  When initializing
+  //   a newly-constructed string, though, it's just as fast and more
+  //   readable to use code like:
+  //     std::string str = reflection->GetString(message, field);
+  const std::string& GetStringReference(const Message& message,
+                                        const FieldDescriptor* field,
+                                        std::string* scratch) const;
+
+
+  // Singular field mutators -----------------------------------------
+  // These mutate the value of a non-repeated field.
+
+  void SetInt32(Message* message, const FieldDescriptor* field,
+                int32_t value) const;
+  void SetInt64(Message* message, const FieldDescriptor* field,
+                int64_t value) const;
+  void SetUInt32(Message* message, const FieldDescriptor* field,
+                 uint32_t value) const;
+  void SetUInt64(Message* message, const FieldDescriptor* field,
+                 uint64_t value) const;
+  void SetFloat(Message* message, const FieldDescriptor* field,
+                float value) const;
+  void SetDouble(Message* message, const FieldDescriptor* field,
+                 double value) const;
+  void SetBool(Message* message, const FieldDescriptor* field,
+               bool value) const;
+  void SetString(Message* message, const FieldDescriptor* field,
+                 std::string value) const;
+  void SetEnum(Message* message, const FieldDescriptor* field,
+               const EnumValueDescriptor* value) const;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // For proto3 this is just setting the enum field to the value specified, for
+  // proto2 it's more complicated. If value is a known enum value the field is
+  // set as usual. If the value is unknown then it is added to the unknown field
+  // set. Note this matches the behavior of parsing unknown enum values.
+  // If multiple calls with unknown values happen than they are all added to the
+  // unknown field set in order of the calls.
+  void SetEnumValue(Message* message, const FieldDescriptor* field,
+                    int value) const;
+
+  // Get a mutable pointer to a field with a message type.  If a MessageFactory
+  // is provided, it will be used to construct instances of the sub-message;
+  // otherwise, the default factory is used.  If the field is an extension that
+  // does not live in the same pool as the containing message's descriptor (e.g.
+  // it lives in an overlay pool), then a MessageFactory must be provided.
+  // If you have no idea what that meant, then you probably don't need to worry
+  // about it (don't provide a MessageFactory).  WARNING:  If the
+  // FieldDescriptor is for a compiled-in extension, then
+  // factory->GetPrototype(field->message_type()) MUST return an instance of
+  // the compiled-in class for this type, NOT DynamicMessage.
+  Message* MutableMessage(Message* message, const FieldDescriptor* field,
+                          MessageFactory* factory = nullptr) const;
+
+  // Replaces the message specified by 'field' with the already-allocated object
+  // sub_message, passing ownership to the message.  If the field contained a
+  // message, that message is deleted.  If sub_message is nullptr, the field is
+  // cleared.
+  void SetAllocatedMessage(Message* message, Message* sub_message,
+                           const FieldDescriptor* field) const;
+
+  // Similar to `SetAllocatedMessage`, but omits all internal safety and
+  // ownership checks.  This method should only be used when the objects are on
+  // the same arena or paired with a call to `UnsafeArenaReleaseMessage`.
+  void UnsafeArenaSetAllocatedMessage(Message* message, Message* sub_message,
+                                      const FieldDescriptor* field) const;
+
+  // Releases the message specified by 'field' and returns the pointer,
+  // ReleaseMessage() will return the message the message object if it exists.
+  // Otherwise, it may or may not return nullptr.  In any case, if the return
+  // value is non-null, the caller takes ownership of the pointer.
+  // If the field existed (HasField() is true), then the returned pointer will
+  // be the same as the pointer returned by MutableMessage().
+  // This function has the same effect as ClearField().
+  PROTOBUF_NODISCARD Message* ReleaseMessage(
+      Message* message, const FieldDescriptor* field,
+      MessageFactory* factory = nullptr) const;
+
+  // Similar to `ReleaseMessage`, but omits all internal safety and ownership
+  // checks.  This method should only be used when the objects are on the same
+  // arena or paired with a call to `UnsafeArenaSetAllocatedMessage`.
+  Message* UnsafeArenaReleaseMessage(Message* message,
+                                     const FieldDescriptor* field,
+                                     MessageFactory* factory = nullptr) const;
+
+
+  // Repeated field getters ------------------------------------------
+  // These get the value of one element of a repeated field.
+
+  int32_t GetRepeatedInt32(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  int64_t GetRepeatedInt64(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  uint32_t GetRepeatedUInt32(const Message& message,
+                             const FieldDescriptor* field, int index) const;
+  uint64_t GetRepeatedUInt64(const Message& message,
+                             const FieldDescriptor* field, int index) const;
+  float GetRepeatedFloat(const Message& message, const FieldDescriptor* field,
+                         int index) const;
+  double GetRepeatedDouble(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  bool GetRepeatedBool(const Message& message, const FieldDescriptor* field,
+                       int index) const;
+  std::string GetRepeatedString(const Message& message,
+                                const FieldDescriptor* field, int index) const;
+  const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
+                                             const FieldDescriptor* field,
+                                             int index) const;
+  // GetRepeatedEnumValue() returns an enum field's value as an integer rather
+  // than an EnumValueDescriptor*. If the integer value does not correspond to a
+  // known value descriptor, a new value descriptor is created. (Such a value
+  // will only be present when the new unknown-enum-value semantics are enabled
+  // for a message.)
+  int GetRepeatedEnumValue(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  const Message& GetRepeatedMessage(const Message& message,
+                                    const FieldDescriptor* field,
+                                    int index) const;
+
+  // See GetStringReference(), above.
+  const std::string& GetRepeatedStringReference(const Message& message,
+                                                const FieldDescriptor* field,
+                                                int index,
+                                                std::string* scratch) const;
+
+
+  // Repeated field mutators -----------------------------------------
+  // These mutate the value of one element of a repeated field.
+
+  void SetRepeatedInt32(Message* message, const FieldDescriptor* field,
+                        int index, int32_t value) const;
+  void SetRepeatedInt64(Message* message, const FieldDescriptor* field,
+                        int index, int64_t value) const;
+  void SetRepeatedUInt32(Message* message, const FieldDescriptor* field,
+                         int index, uint32_t value) const;
+  void SetRepeatedUInt64(Message* message, const FieldDescriptor* field,
+                         int index, uint64_t value) const;
+  void SetRepeatedFloat(Message* message, const FieldDescriptor* field,
+                        int index, float value) const;
+  void SetRepeatedDouble(Message* message, const FieldDescriptor* field,
+                         int index, double value) const;
+  void SetRepeatedBool(Message* message, const FieldDescriptor* field,
+                       int index, bool value) const;
+  void SetRepeatedString(Message* message, const FieldDescriptor* field,
+                         int index, std::string value) const;
+  void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
+                       int index, const EnumValueDescriptor* value) const;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // For proto3 this is just setting the enum field to the value specified, for
+  // proto2 it's more complicated. If value is a known enum value the field is
+  // set as usual. If the value is unknown then it is added to the unknown field
+  // set. Note this matches the behavior of parsing unknown enum values.
+  // If multiple calls with unknown values happen than they are all added to the
+  // unknown field set in order of the calls.
+  void SetRepeatedEnumValue(Message* message, const FieldDescriptor* field,
+                            int index, int value) const;
+  // Get a mutable pointer to an element of a repeated field with a message
+  // type.
+  Message* MutableRepeatedMessage(Message* message,
+                                  const FieldDescriptor* field,
+                                  int index) const;
+
+
+  // Repeated field adders -------------------------------------------
+  // These add an element to a repeated field.
+
+  void AddInt32(Message* message, const FieldDescriptor* field,
+                int32_t value) const;
+  void AddInt64(Message* message, const FieldDescriptor* field,
+                int64_t value) const;
+  void AddUInt32(Message* message, const FieldDescriptor* field,
+                 uint32_t value) const;
+  void AddUInt64(Message* message, const FieldDescriptor* field,
+                 uint64_t value) const;
+  void AddFloat(Message* message, const FieldDescriptor* field,
+                float value) const;
+  void AddDouble(Message* message, const FieldDescriptor* field,
+                 double value) const;
+  void AddBool(Message* message, const FieldDescriptor* field,
+               bool value) const;
+  void AddString(Message* message, const FieldDescriptor* field,
+                 std::string value) const;
+  void AddEnum(Message* message, const FieldDescriptor* field,
+               const EnumValueDescriptor* value) const;
+  // Add an integer value to a repeated enum field rather than
+  // EnumValueDescriptor. For proto3 this is just setting the enum field to the
+  // value specified, for proto2 it's more complicated. If value is a known enum
+  // value the field is set as usual. If the value is unknown then it is added
+  // to the unknown field set. Note this matches the behavior of parsing unknown
+  // enum values. If multiple calls with unknown values happen than they are all
+  // added to the unknown field set in order of the calls.
+  void AddEnumValue(Message* message, const FieldDescriptor* field,
+                    int value) const;
+  // See MutableMessage() for comments on the "factory" parameter.
+  Message* AddMessage(Message* message, const FieldDescriptor* field,
+                      MessageFactory* factory = nullptr) const;
+
+  // Appends an already-allocated object 'new_entry' to the repeated field
+  // specified by 'field' passing ownership to the message.
+  void AddAllocatedMessage(Message* message, const FieldDescriptor* field,
+                           Message* new_entry) const;
+
+  // Similar to AddAllocatedMessage() without internal safety and ownership
+  // checks. This method should only be used when the objects are on the same
+  // arena or paired with a call to `UnsafeArenaReleaseLast`.
+  void UnsafeArenaAddAllocatedMessage(Message* message,
+                                      const FieldDescriptor* field,
+                                      Message* new_entry) const;
+
+
+  // Get a RepeatedFieldRef object that can be used to read the underlying
+  // repeated field. The type parameter T must be set according to the
+  // field's cpp type. The following table shows the mapping from cpp type
+  // to acceptable T.
+  //
+  //   field->cpp_type()      T
+  //   CPPTYPE_INT32        int32_t
+  //   CPPTYPE_UINT32       uint32_t
+  //   CPPTYPE_INT64        int64_t
+  //   CPPTYPE_UINT64       uint64_t
+  //   CPPTYPE_DOUBLE       double
+  //   CPPTYPE_FLOAT        float
+  //   CPPTYPE_BOOL         bool
+  //   CPPTYPE_ENUM         generated enum type or int32_t
+  //   CPPTYPE_STRING       std::string
+  //   CPPTYPE_MESSAGE      generated message type or google::protobuf::Message
+  //
+  // A RepeatedFieldRef object can be copied and the resulted object will point
+  // to the same repeated field in the same message. The object can be used as
+  // long as the message is not destroyed.
+  //
+  // Note that to use this method users need to include the header file
+  // "reflection.h" (which defines the RepeatedFieldRef class templates).
+  template <typename T>
+  RepeatedFieldRef<T> GetRepeatedFieldRef(const Message& message,
+                                          const FieldDescriptor* field) const;
+
+  // Like GetRepeatedFieldRef() but return an object that can also be used
+  // manipulate the underlying repeated field.
+  template <typename T>
+  MutableRepeatedFieldRef<T> GetMutableRepeatedFieldRef(
+      Message* message, const FieldDescriptor* field) const;
+
+  // DEPRECATED. Please use Get(Mutable)RepeatedFieldRef() for repeated field
+  // access. The following repeated field accessors will be removed in the
+  // future.
+  //
+  // Repeated field accessors  -------------------------------------------------
+  // The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular
+  // access to the data in a RepeatedField.  The methods below provide aggregate
+  // access by exposing the RepeatedField object itself with the Message.
+  // Applying these templates to inappropriate types will lead to an undefined
+  // reference at link time (e.g. GetRepeatedField<***double>), or possibly a
+  // template matching error at compile time (e.g. GetRepeatedPtrField<File>).
+  //
+  // Usage example: my_doubs = refl->GetRepeatedField<double>(msg, fd);
+
+  // DEPRECATED. Please use GetRepeatedFieldRef().
+  //
+  // for T = Cord and all protobuf scalar types except enums.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetRepeatedFieldRef() instead")
+  const RepeatedField<T>& GetRepeatedField(const Message& msg,
+                                           const FieldDescriptor* d) const {
+    return GetRepeatedFieldInternal<T>(msg, d);
+  }
+
+  // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+  //
+  // for T = Cord and all protobuf scalar types except enums.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetMutableRepeatedFieldRef() instead")
+  RepeatedField<T>* MutableRepeatedField(Message* msg,
+                                         const FieldDescriptor* d) const {
+    return MutableRepeatedFieldInternal<T>(msg, d);
+  }
+
+  // DEPRECATED. Please use GetRepeatedFieldRef().
+  //
+  // for T = std::string, google::protobuf::internal::StringPieceField
+  //         google::protobuf::Message & descendants.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetRepeatedFieldRef() instead")
+  const RepeatedPtrField<T>& GetRepeatedPtrField(
+      const Message& msg, const FieldDescriptor* d) const {
+    return GetRepeatedPtrFieldInternal<T>(msg, d);
+  }
+
+  // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+  //
+  // for T = std::string, google::protobuf::internal::StringPieceField
+  //         google::protobuf::Message & descendants.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetMutableRepeatedFieldRef() instead")
+  RepeatedPtrField<T>* MutableRepeatedPtrField(Message* msg,
+                                               const FieldDescriptor* d) const {
+    return MutableRepeatedPtrFieldInternal<T>(msg, d);
+  }
+
+  // Extensions ----------------------------------------------------------------
+
+  // Try to find an extension of this message type by fully-qualified field
+  // name.  Returns nullptr if no extension is known for this name or number.
+  const FieldDescriptor* FindKnownExtensionByName(
+      const std::string& name) const;
+
+  // Try to find an extension of this message type by field number.
+  // Returns nullptr if no extension is known for this name or number.
+  const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
+
+  // Feature Flags -------------------------------------------------------------
+
+  // Does this message support storing arbitrary integer values in enum fields?
+  // If |true|, GetEnumValue/SetEnumValue and associated repeated-field versions
+  // take arbitrary integer values, and the legacy GetEnum() getter will
+  // dynamically create an EnumValueDescriptor for any integer value without
+  // one. If |false|, setting an unknown enum value via the integer-based
+  // setters results in undefined behavior (in practice, GOOGLE_DCHECK-fails).
+  //
+  // Generic code that uses reflection to handle messages with enum fields
+  // should check this flag before using the integer-based setter, and either
+  // downgrade to a compatible value or use the UnknownFieldSet if not. For
+  // example:
+  //
+  //   int new_value = GetValueFromApplicationLogic();
+  //   if (reflection->SupportsUnknownEnumValues()) {
+  //     reflection->SetEnumValue(message, field, new_value);
+  //   } else {
+  //     if (field_descriptor->enum_type()->
+  //             FindValueByNumber(new_value) != nullptr) {
+  //       reflection->SetEnumValue(message, field, new_value);
+  //     } else if (emit_unknown_enum_values) {
+  //       reflection->MutableUnknownFields(message)->AddVarint(
+  //           field->number(), new_value);
+  //     } else {
+  //       // convert value to a compatible/default value.
+  //       new_value = CompatibleDowngrade(new_value);
+  //       reflection->SetEnumValue(message, field, new_value);
+  //     }
+  //   }
+  bool SupportsUnknownEnumValues() const;
+
+  // Returns the MessageFactory associated with this message.  This can be
+  // useful for determining if a message is a generated message or not, for
+  // example:
+  //   if (message->GetReflection()->GetMessageFactory() ==
+  //       google::protobuf::MessageFactory::generated_factory()) {
+  //     // This is a generated message.
+  //   }
+  // It can also be used to create more messages of this type, though
+  // Message::New() is an easier way to accomplish this.
+  MessageFactory* GetMessageFactory() const;
+
+ private:
+  template <typename T>
+  const RepeatedField<T>& GetRepeatedFieldInternal(
+      const Message& message, const FieldDescriptor* field) const;
+  template <typename T>
+  RepeatedField<T>* MutableRepeatedFieldInternal(
+      Message* message, const FieldDescriptor* field) const;
+  template <typename T>
+  const RepeatedPtrField<T>& GetRepeatedPtrFieldInternal(
+      const Message& message, const FieldDescriptor* field) const;
+  template <typename T>
+  RepeatedPtrField<T>* MutableRepeatedPtrFieldInternal(
+      Message* message, const FieldDescriptor* field) const;
+  // Obtain a pointer to a Repeated Field Structure and do some type checking:
+  //   on field->cpp_type(),
+  //   on field->field_option().ctype() (if ctype >= 0)
+  //   of field->message_type() (if message_type != nullptr).
+  // We use 2 routine rather than 4 (const vs mutable) x (scalar vs pointer).
+  void* MutableRawRepeatedField(Message* message, const FieldDescriptor* field,
+                                FieldDescriptor::CppType, int ctype,
+                                const Descriptor* message_type) const;
+
+  const void* GetRawRepeatedField(const Message& message,
+                                  const FieldDescriptor* field,
+                                  FieldDescriptor::CppType cpptype, int ctype,
+                                  const Descriptor* message_type) const;
+
+  // The following methods are used to implement (Mutable)RepeatedFieldRef.
+  // A Ref object will store a raw pointer to the repeated field data (obtained
+  // from RepeatedFieldData()) and a pointer to a Accessor (obtained from
+  // RepeatedFieldAccessor) which will be used to access the raw data.
+
+  // Returns a raw pointer to the repeated field
+  //
+  // "cpp_type" and "message_type" are deduced from the type parameter T passed
+  // to Get(Mutable)RepeatedFieldRef. If T is a generated message type,
+  // "message_type" should be set to its descriptor. Otherwise "message_type"
+  // should be set to nullptr. 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.
+  void* RepeatedFieldData(Message* message, const FieldDescriptor* field,
+                          FieldDescriptor::CppType cpp_type,
+                          const Descriptor* message_type) const;
+
+  // The returned pointer should point to a singleton instance which implements
+  // the RepeatedFieldAccessor interface.
+  const internal::RepeatedFieldAccessor* RepeatedFieldAccessor(
+      const FieldDescriptor* field) const;
+
+  // Lists all fields of the message which are currently set, except for unknown
+  // fields and stripped fields. See ListFields for details.
+  void ListFieldsOmitStripped(
+      const Message& message,
+      std::vector<const FieldDescriptor*>* output) const;
+
+  bool IsMessageStripped(const Descriptor* descriptor) const {
+    return schema_.IsMessageStripped(descriptor);
+  }
+
+  friend class TextFormat;
+
+  void ListFieldsMayFailOnStripped(
+      const Message& message, bool should_fail,
+      std::vector<const FieldDescriptor*>* output) const;
+
+  // Returns true if the message field is backed by a LazyField.
+  //
+  // A message field may be backed by a LazyField without the user annotation
+  // ([lazy = true]). While the user-annotated LazyField is lazily verified on
+  // first touch (i.e. failure on access rather than parsing if the LazyField is
+  // not initialized), the inferred LazyField is eagerly verified to avoid lazy
+  // parsing error at the cost of lower efficiency. When reflecting a message
+  // field, use this API instead of checking field->options().lazy().
+  bool IsLazyField(const FieldDescriptor* field) const {
+    return IsLazilyVerifiedLazyField(field) ||
+           IsEagerlyVerifiedLazyField(field);
+  }
+
+  // Returns true if the field is lazy extension. It is meant to allow python
+  // reparse lazy field until b/157559327 is fixed.
+  bool IsLazyExtension(const Message& message,
+                       const FieldDescriptor* field) const;
+
+  bool IsLazilyVerifiedLazyField(const FieldDescriptor* field) const;
+  bool IsEagerlyVerifiedLazyField(const FieldDescriptor* field) const;
+
+  friend class FastReflectionMessageMutator;
+  friend bool internal::IsDescendant(Message& root, const Message& message);
+
+  const Descriptor* const descriptor_;
+  const internal::ReflectionSchema schema_;
+  const DescriptorPool* const descriptor_pool_;
+  MessageFactory* const message_factory_;
+
+  // Last non weak field index. This is an optimization when most weak fields
+  // are at the end of the containing message. If a message proto doesn't
+  // contain weak fields, then this field equals descriptor_->field_count().
+  int last_non_weak_field_index_;
+
+  template <typename T, typename Enable>
+  friend class RepeatedFieldRef;
+  template <typename T, typename Enable>
+  friend class MutableRepeatedFieldRef;
+  friend class ::PROTOBUF_NAMESPACE_ID::MessageLayoutInspector;
+  friend class ::PROTOBUF_NAMESPACE_ID::AssignDescriptorsHelper;
+  friend class DynamicMessageFactory;
+  friend class GeneratedMessageReflectionTestHelper;
+  friend class python::MapReflectionFriend;
+  friend class python::MessageReflectionFriend;
+  friend class util::MessageDifferencer;
+#define GOOGLE_PROTOBUF_HAS_CEL_MAP_REFLECTION_FRIEND
+  friend class expr::CelMapReflectionFriend;
+  friend class internal::MapFieldReflectionTest;
+  friend class internal::MapKeySorter;
+  friend class internal::WireFormat;
+  friend class internal::ReflectionOps;
+  friend class internal::SwapFieldHelper;
+  // Needed for implementing text format for map.
+  friend class internal::MapFieldPrinterHelper;
+
+  Reflection(const Descriptor* descriptor,
+             const internal::ReflectionSchema& schema,
+             const DescriptorPool* pool, MessageFactory* factory);
+
+  // 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;
+  // Returns true if key is in map. Returns false if key is not in map field.
+  bool ContainsMapKey(const Message& message, const FieldDescriptor* field,
+                      const MapKey& key) const;
+
+  // 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 returns true. Users are able to modify the
+  // map value by MapValueRef.
+  bool InsertOrLookupMapValue(Message* message, const FieldDescriptor* field,
+                              const MapKey& key, MapValueRef* val) const;
+
+  // If key is in map field: Saves the value pointer to val and returns true.
+  // Returns false if key is not in map field. Users are NOT able to modify
+  // the value by MapValueConstRef.
+  bool LookupMapValue(const Message& message, const FieldDescriptor* field,
+                      const MapKey& key, MapValueConstRef* val) const;
+  bool LookupMapValue(const Message&, const FieldDescriptor*, const MapKey&,
+                      MapValueRef*) const = delete;
+
+  // Delete and returns true if key is in the map field. Returns false
+  // otherwise.
+  bool DeleteMapValue(Message* message, const FieldDescriptor* field,
+                      const MapKey& key) const;
+
+  // 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.
+  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.
+  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.
+  int MapSize(const Message& message, const FieldDescriptor* field) const;
+
+  // Help method for MapIterator.
+  friend class MapIterator;
+  friend class WireFormatForMapFieldTest;
+  internal::MapFieldBase* MutableMapData(Message* message,
+                                         const FieldDescriptor* field) const;
+
+  const internal::MapFieldBase* GetMapData(const Message& message,
+                                           const FieldDescriptor* field) const;
+
+  template <class T>
+  const T& GetRawNonOneof(const Message& message,
+                          const FieldDescriptor* field) const;
+  template <class T>
+  T* MutableRawNonOneof(Message* message, const FieldDescriptor* field) const;
+
+  template <typename Type>
+  const Type& GetRaw(const Message& message,
+                     const FieldDescriptor* field) const;
+  template <typename Type>
+  inline Type* MutableRaw(Message* message, const FieldDescriptor* field) const;
+  template <typename Type>
+  const Type& DefaultRaw(const FieldDescriptor* field) const;
+
+  const Message* GetDefaultMessageInstance(const FieldDescriptor* field) const;
+
+  inline const uint32_t* GetHasBits(const Message& message) const;
+  inline uint32_t* MutableHasBits(Message* message) const;
+  inline uint32_t GetOneofCase(const Message& message,
+                               const OneofDescriptor* oneof_descriptor) const;
+  inline uint32_t* MutableOneofCase(
+      Message* message, const OneofDescriptor* oneof_descriptor) const;
+  inline bool HasExtensionSet(const Message& /* message */) const {
+    return schema_.HasExtensionSet();
+  }
+  const internal::ExtensionSet& GetExtensionSet(const Message& message) const;
+  internal::ExtensionSet* MutableExtensionSet(Message* message) const;
+
+  const internal::InternalMetadata& GetInternalMetadata(
+      const Message& message) const;
+
+  internal::InternalMetadata* MutableInternalMetadata(Message* message) const;
+
+  inline bool IsInlined(const FieldDescriptor* field) const;
+
+  inline bool HasBit(const Message& message,
+                     const FieldDescriptor* field) const;
+  inline void SetBit(Message* message, const FieldDescriptor* field) const;
+  inline void ClearBit(Message* message, const FieldDescriptor* field) const;
+  inline void SwapBit(Message* message1, Message* message2,
+                      const FieldDescriptor* field) const;
+
+  inline const uint32_t* GetInlinedStringDonatedArray(
+      const Message& message) const;
+  inline uint32_t* MutableInlinedStringDonatedArray(Message* message) const;
+  inline bool IsInlinedStringDonated(const Message& message,
+                                     const FieldDescriptor* field) const;
+  inline void SwapInlinedStringDonated(Message* lhs, Message* rhs,
+                                       const FieldDescriptor* field) const;
+
+  // Shallow-swap fields listed in fields vector of two messages. It is the
+  // caller's responsibility to make sure shallow swap is safe.
+  void UnsafeShallowSwapFields(
+      Message* message1, Message* message2,
+      const std::vector<const FieldDescriptor*>& fields) const;
+
+  // This function only swaps the field. Should swap corresponding has_bit
+  // before or after using this function.
+  void SwapField(Message* message1, Message* message2,
+                 const FieldDescriptor* field) const;
+
+  // Unsafe but shallow version of SwapField.
+  void UnsafeShallowSwapField(Message* message1, Message* message2,
+                              const FieldDescriptor* field) const;
+
+  template <bool unsafe_shallow_swap>
+  void SwapFieldsImpl(Message* message1, Message* message2,
+                      const std::vector<const FieldDescriptor*>& fields) const;
+
+  template <bool unsafe_shallow_swap>
+  void SwapOneofField(Message* lhs, Message* rhs,
+                      const OneofDescriptor* oneof_descriptor) const;
+
+  inline bool HasOneofField(const Message& message,
+                            const FieldDescriptor* field) const;
+  inline void SetOneofCase(Message* message,
+                           const FieldDescriptor* field) const;
+  inline void ClearOneofField(Message* message,
+                              const FieldDescriptor* field) const;
+
+  template <typename Type>
+  inline const Type& GetField(const Message& message,
+                              const FieldDescriptor* field) const;
+  template <typename Type>
+  inline void SetField(Message* message, const FieldDescriptor* field,
+                       const Type& value) const;
+  template <typename Type>
+  inline Type* MutableField(Message* message,
+                            const FieldDescriptor* field) const;
+  template <typename Type>
+  inline const Type& GetRepeatedField(const Message& message,
+                                      const FieldDescriptor* field,
+                                      int index) const;
+  template <typename Type>
+  inline const Type& GetRepeatedPtrField(const Message& message,
+                                         const FieldDescriptor* field,
+                                         int index) const;
+  template <typename Type>
+  inline void SetRepeatedField(Message* message, const FieldDescriptor* field,
+                               int index, Type value) const;
+  template <typename Type>
+  inline Type* MutableRepeatedField(Message* message,
+                                    const FieldDescriptor* field,
+                                    int index) const;
+  template <typename Type>
+  inline void AddField(Message* message, const FieldDescriptor* field,
+                       const Type& value) const;
+  template <typename Type>
+  inline Type* AddField(Message* message, const FieldDescriptor* field) const;
+
+  int GetExtensionNumberOrDie(const Descriptor* type) const;
+
+  // Internal versions of EnumValue API perform no checking. Called after checks
+  // by public methods.
+  void SetEnumValueInternal(Message* message, const FieldDescriptor* field,
+                            int value) const;
+  void SetRepeatedEnumValueInternal(Message* message,
+                                    const FieldDescriptor* field, int index,
+                                    int value) const;
+  void AddEnumValueInternal(Message* message, const FieldDescriptor* field,
+                            int value) const;
+
+  friend inline  // inline so nobody can call this function.
+      void
+      RegisterAllTypesInternal(const Metadata* file_level_metadata, int size);
+  friend inline const char* ParseLenDelim(int field_number,
+                                          const FieldDescriptor* field,
+                                          Message* msg,
+                                          const Reflection* reflection,
+                                          const char* ptr,
+                                          internal::ParseContext* ctx);
+  friend inline const char* ParsePackedField(const FieldDescriptor* field,
+                                             Message* msg,
+                                             const Reflection* reflection,
+                                             const char* ptr,
+                                             internal::ParseContext* ctx);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
+};
+
+// Abstract interface for a factory for message objects.
+class PROTOBUF_EXPORT MessageFactory {
+ public:
+  inline MessageFactory() {}
+  virtual ~MessageFactory();
+
+  // Given a Descriptor, gets or constructs the default (prototype) Message
+  // of that type.  You can then call that message's New() method to construct
+  // a mutable message of that type.
+  //
+  // Calling this method twice with the same Descriptor returns the same
+  // object.  The returned object remains property of the factory.  Also, any
+  // objects created by calling the prototype's New() method share some data
+  // with the prototype, so these must be destroyed before the MessageFactory
+  // is destroyed.
+  //
+  // The given descriptor must outlive the returned message, and hence must
+  // outlive the MessageFactory.
+  //
+  // Some implementations do not support all types.  GetPrototype() will
+  // return nullptr if the descriptor passed in is not supported.
+  //
+  // This method may or may not be thread-safe depending on the implementation.
+  // Each implementation should document its own degree thread-safety.
+  virtual const Message* GetPrototype(const Descriptor* type) = 0;
+
+  // Gets a MessageFactory which supports all generated, compiled-in messages.
+  // In other words, for any compiled-in type FooMessage, the following is true:
+  //   MessageFactory::generated_factory()->GetPrototype(
+  //     FooMessage::descriptor()) == FooMessage::default_instance()
+  // This factory supports all types which are found in
+  // DescriptorPool::generated_pool().  If given a descriptor from any other
+  // pool, GetPrototype() will return nullptr.  (You can also check if a
+  // descriptor is for a generated message by checking if
+  // descriptor->file()->pool() == DescriptorPool::generated_pool().)
+  //
+  // This factory is 100% thread-safe; calling GetPrototype() does not modify
+  // any shared data.
+  //
+  // This factory is a singleton.  The caller must not delete the object.
+  static MessageFactory* generated_factory();
+
+  // For internal use only:  Registers a .proto file at static initialization
+  // time, to be placed in generated_factory.  The first time GetPrototype()
+  // is called with a descriptor from this file, |register_messages| will be
+  // called, with the file name as the parameter.  It must call
+  // InternalRegisterGeneratedMessage() (below) to register each message type
+  // in the file.  This strange mechanism is necessary because descriptors are
+  // built lazily, so we can't register types by their descriptor until we
+  // know that the descriptor exists.  |filename| must be a permanent string.
+  static void InternalRegisterGeneratedFile(
+      const google::protobuf::internal::DescriptorTable* table);
+
+  // For internal use only:  Registers a message type.  Called only by the
+  // functions which are registered with InternalRegisterGeneratedFile(),
+  // above.
+  static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
+                                               const Message* prototype);
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
+};
+
+#define DECLARE_GET_REPEATED_FIELD(TYPE)                           \
+  template <>                                                      \
+  PROTOBUF_EXPORT const RepeatedField<TYPE>&                       \
+  Reflection::GetRepeatedFieldInternal<TYPE>(                      \
+      const Message& message, const FieldDescriptor* field) const; \
+                                                                   \
+  template <>                                                      \
+  PROTOBUF_EXPORT RepeatedField<TYPE>*                             \
+  Reflection::MutableRepeatedFieldInternal<TYPE>(                  \
+      Message * message, const FieldDescriptor* field) const;
+
+DECLARE_GET_REPEATED_FIELD(int32_t)
+DECLARE_GET_REPEATED_FIELD(int64_t)
+DECLARE_GET_REPEATED_FIELD(uint32_t)
+DECLARE_GET_REPEATED_FIELD(uint64_t)
+DECLARE_GET_REPEATED_FIELD(float)
+DECLARE_GET_REPEATED_FIELD(double)
+DECLARE_GET_REPEATED_FIELD(bool)
+
+#undef DECLARE_GET_REPEATED_FIELD
+
+// Tries to downcast this message to a generated message type.  Returns nullptr
+// if this class is not an instance of T.  This works even if RTTI is disabled.
+//
+// This also has the effect of creating a strong reference to T that will
+// prevent the linker from stripping it out at link time.  This can be important
+// if you are using a DynamicMessageFactory that delegates to the generated
+// factory.
+template <typename T>
+const 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*>(nullptr);
+  (void)unused;
+
+#if PROTOBUF_RTTI
+  return dynamic_cast<const T*>(from);
+#else
+  bool ok = from != nullptr &&
+            T::default_instance().GetReflection() == from->GetReflection();
+  return ok ? down_cast<const T*>(from) : nullptr;
+#endif
+}
+
+template <typename T>
+T* DynamicCastToGenerated(Message* from) {
+  const Message* message_const = from;
+  return const_cast<T*>(DynamicCastToGenerated<T>(message_const));
+}
+
+// Call this function to ensure that this message's reflection is linked into
+// the binary:
+//
+//   google::protobuf::LinkMessageReflection<pkg::FooMessage>();
+//
+// This will ensure that the following lookup will succeed:
+//
+//   DescriptorPool::generated_pool()->FindMessageTypeByName("pkg.FooMessage");
+//
+// As a side-effect, it will also guarantee that anything else from the same
+// .proto file will also be available for lookup in the generated pool.
+//
+// This function does not actually register the message, so it does not need
+// to be called before the lookup.  However it does need to occur in a function
+// that cannot be stripped from the binary (ie. it must be reachable from main).
+//
+// Best practice is to call this function as close as possible to where the
+// reflection is actually needed.  This function is very cheap to call, so you
+// should not need to worry about its runtime overhead except in the tightest
+// of loops (on x86-64 it compiles into two "mov" instructions).
+template <typename T>
+void LinkMessageReflection() {
+  internal::StrongReference(T::default_instance);
+}
+
+// =============================================================================
+// Implementation details for {Get,Mutable}RawRepeatedPtrField.  We provide
+// specializations for <std::string>, <StringPieceField> and <Message> and
+// handle everything else with the default template which will match any type
+// having a method with signature "static const google::protobuf::Descriptor*
+// descriptor()". Such a type presumably is a descendant of google::protobuf::Message.
+
+template <>
+inline const RepeatedPtrField<std::string>&
+Reflection::GetRepeatedPtrFieldInternal<std::string>(
+    const Message& message, const FieldDescriptor* field) const {
+  return *static_cast<RepeatedPtrField<std::string>*>(
+      MutableRawRepeatedString(const_cast<Message*>(&message), field, true));
+}
+
+template <>
+inline RepeatedPtrField<std::string>*
+Reflection::MutableRepeatedPtrFieldInternal<std::string>(
+    Message* message, const FieldDescriptor* field) const {
+  return static_cast<RepeatedPtrField<std::string>*>(
+      MutableRawRepeatedString(message, field, true));
+}
+
+
+// -----
+
+template <>
+inline const RepeatedPtrField<Message>& Reflection::GetRepeatedPtrFieldInternal(
+    const Message& message, const FieldDescriptor* field) const {
+  return *static_cast<const RepeatedPtrField<Message>*>(GetRawRepeatedField(
+      message, field, FieldDescriptor::CPPTYPE_MESSAGE, -1, nullptr));
+}
+
+template <>
+inline RepeatedPtrField<Message>* Reflection::MutableRepeatedPtrFieldInternal(
+    Message* message, const FieldDescriptor* field) const {
+  return static_cast<RepeatedPtrField<Message>*>(MutableRawRepeatedField(
+      message, field, FieldDescriptor::CPPTYPE_MESSAGE, -1, nullptr));
+}
+
+template <typename PB>
+inline const RepeatedPtrField<PB>& Reflection::GetRepeatedPtrFieldInternal(
+    const Message& message, const FieldDescriptor* field) const {
+  return *static_cast<const RepeatedPtrField<PB>*>(
+      GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE, -1,
+                          PB::default_instance().GetDescriptor()));
+}
+
+template <typename PB>
+inline RepeatedPtrField<PB>* Reflection::MutableRepeatedPtrFieldInternal(
+    Message* message, const FieldDescriptor* field) const {
+  return static_cast<RepeatedPtrField<PB>*>(
+      MutableRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE,
+                              -1, PB::default_instance().GetDescriptor()));
+}
+
+template <typename Type>
+const Type& Reflection::DefaultRaw(const FieldDescriptor* field) const {
+  return *reinterpret_cast<const Type*>(schema_.GetFieldDefault(field));
+}
+
+uint32_t Reflection::GetOneofCase(
+    const Message& message, const OneofDescriptor* oneof_descriptor) const {
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  return internal::GetConstRefAtOffset<uint32_t>(
+      message, schema_.GetOneofCaseOffset(oneof_descriptor));
+}
+
+bool Reflection::HasOneofField(const Message& message,
+                               const FieldDescriptor* field) const {
+  return (GetOneofCase(message, field->containing_oneof()) ==
+          static_cast<uint32_t>(field->number()));
+}
+
+template <typename Type>
+const Type& Reflection::GetRaw(const Message& message,
+                               const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!schema_.InRealOneof(field) || HasOneofField(message, field))
+      << "Field = " << field->full_name();
+  return internal::GetConstRefAtOffset<Type>(message,
+                                             schema_.GetFieldOffset(field));
+}
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MESSAGE_H__
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
new file mode 100644
index 0000000..da66c19
--- /dev/null
+++ b/src/google/protobuf/message_lite.cc
@@ -0,0 +1,602 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Authors: wink@google.com (Wink Saville),
+//          kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/message_lite.h>
+
+#include <climits>
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/parse_context.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/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/mutex.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+std::string MessageLite::InitializationErrorString() const {
+  return "(cannot determine missing fields for lite message)";
+}
+
+std::string MessageLite::DebugString() const {
+  std::uintptr_t address = reinterpret_cast<std::uintptr_t>(this);
+  return StrCat("MessageLite at 0x", strings::Hex(address));
+}
+
+namespace {
+
+// When serializing, we first compute the byte size, then serialize the message.
+// If serialization produces a different number of bytes than expected, we
+// call this function, which crashes.  The problem could be due to a bug in the
+// protobuf implementation but is more likely caused by concurrent modification
+// of the message.  This function attempts to distinguish between the two and
+// provide a useful error message.
+void ByteSizeConsistencyError(size_t byte_size_before_serialization,
+                              size_t byte_size_after_serialization,
+                              size_t bytes_produced_by_serialization,
+                              const MessageLite& message) {
+  GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
+      << message.GetTypeName()
+      << " was modified concurrently during serialization.";
+  GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
+      << "Byte size calculation and serialization were inconsistent.  This "
+         "may indicate a bug in protocol buffers or it may be caused by "
+         "concurrent modification of "
+      << message.GetTypeName() << ".";
+  GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
+}
+
+std::string InitializationErrorMessage(const char* action,
+                                       const MessageLite& message) {
+  // Note:  We want to avoid depending on strutil in the lite library, otherwise
+  //   we'd use:
+  //
+  // return strings::Substitute(
+  //   "Can't $0 message of type \"$1\" because it is missing required "
+  //   "fields: $2",
+  //   action, message.GetTypeName(),
+  //   message.InitializationErrorString());
+
+  std::string result;
+  result += "Can't ";
+  result += action;
+  result += " message of type \"";
+  result += message.GetTypeName();
+  result += "\" because it is missing required fields: ";
+  result += message.InitializationErrorString();
+  return result;
+}
+
+inline StringPiece as_string_view(const void* data, int size) {
+  return StringPiece(static_cast<const char*>(data), size);
+}
+
+// Returns true of all required fields are present / have values.
+inline bool CheckFieldPresence(const internal::ParseContext& ctx,
+                               const MessageLite& msg,
+                               MessageLite::ParseFlags parse_flags) {
+  (void)ctx;  // Parameter is used by Google-internal code.
+  if (PROTOBUF_PREDICT_FALSE((parse_flags & MessageLite::kMergePartial) != 0)) {
+    return true;
+  }
+  return msg.IsInitializedWithErrors();
+}
+
+}  // namespace
+
+void MessageLite::LogInitializationErrorMessage() const {
+  GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *this);
+}
+
+namespace internal {
+
+template <bool aliasing>
+bool MergeFromImpl(StringPiece input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input);
+  ptr = msg->_InternalParse(ptr, &ctx);
+  // ctx has an explicit limit set (length of string_view).
+  if (PROTOBUF_PREDICT_TRUE(ptr && ctx.EndedAtLimit())) {
+    return CheckFieldPresence(ctx, *msg, parse_flags);
+  }
+  return false;
+}
+
+template <bool aliasing>
+bool MergeFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input);
+  ptr = msg->_InternalParse(ptr, &ctx);
+  // ctx has no explicit limit (hence we end on end of stream)
+  if (PROTOBUF_PREDICT_TRUE(ptr && ctx.EndedAtEndOfStream())) {
+    return CheckFieldPresence(ctx, *msg, parse_flags);
+  }
+  return false;
+}
+
+template <bool aliasing>
+bool MergeFromImpl(BoundedZCIS input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input.zcis, input.limit);
+  ptr = msg->_InternalParse(ptr, &ctx);
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
+  ctx.BackUp(ptr);
+  if (PROTOBUF_PREDICT_TRUE(ctx.EndedAtLimit())) {
+    return CheckFieldPresence(ctx, *msg, parse_flags);
+  }
+  return false;
+}
+
+template bool MergeFromImpl<false>(StringPiece input, MessageLite* msg,
+                                   MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<true>(StringPiece input, MessageLite* msg,
+                                  MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<false>(io::ZeroCopyInputStream* input,
+                                   MessageLite* msg,
+                                   MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<true>(io::ZeroCopyInputStream* input,
+                                  MessageLite* msg,
+                                  MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<false>(BoundedZCIS input, MessageLite* msg,
+                                   MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<true>(BoundedZCIS input, MessageLite* msg,
+                                  MessageLite::ParseFlags parse_flags);
+
+}  // namespace internal
+
+class ZeroCopyCodedInputStream : public io::ZeroCopyInputStream {
+ public:
+  ZeroCopyCodedInputStream(io::CodedInputStream* cis) : cis_(cis) {}
+  bool Next(const void** data, int* size) final {
+    if (!cis_->GetDirectBufferPointer(data, size)) return false;
+    cis_->Skip(*size);
+    return true;
+  }
+  void BackUp(int count) final { cis_->Advance(-count); }
+  bool Skip(int count) final { return cis_->Skip(count); }
+  int64_t ByteCount() const final { return 0; }
+
+  bool aliasing_enabled() { return cis_->aliasing_enabled_; }
+
+ private:
+  io::CodedInputStream* cis_;
+};
+
+bool MessageLite::MergeFromImpl(io::CodedInputStream* input,
+                                MessageLite::ParseFlags parse_flags) {
+  ZeroCopyCodedInputStream zcis(input);
+  const char* ptr;
+  internal::ParseContext ctx(input->RecursionBudget(), zcis.aliasing_enabled(),
+                             &ptr, &zcis);
+  // MergePartialFromCodedStream allows terminating the wireformat by 0 or
+  // end-group tag. Leaving it up to the caller to verify correct ending by
+  // calling LastTagWas on input. We need to maintain this behavior.
+  ctx.TrackCorrectEnding();
+  ctx.data().pool = input->GetExtensionPool();
+  ctx.data().factory = input->GetExtensionFactory();
+  ptr = _InternalParse(ptr, &ctx);
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
+  ctx.BackUp(ptr);
+  if (!ctx.EndedAtEndOfStream()) {
+    GOOGLE_DCHECK_NE(ctx.LastTag(), 1);  // We can't end on a pushed limit.
+    if (ctx.IsExceedingLimit(ptr)) return false;
+    input->SetLastTag(ctx.LastTag());
+  } else {
+    input->SetConsumed();
+  }
+  return CheckFieldPresence(ctx, *this, parse_flags);
+}
+
+bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
+  return MergeFromImpl(input, kMergePartial);
+}
+
+bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
+  return MergeFromImpl(input, kMerge);
+}
+
+bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
+  Clear();
+  return MergeFromImpl(input, kParse);
+}
+
+bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
+  Clear();
+  return MergeFromImpl(input, kParsePartial);
+}
+
+bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+  return ParseFrom<kParse>(input);
+}
+
+bool MessageLite::ParsePartialFromZeroCopyStream(
+    io::ZeroCopyInputStream* input) {
+  return ParseFrom<kParsePartial>(input);
+}
+
+bool MessageLite::ParseFromFileDescriptor(int file_descriptor) {
+  io::FileInputStream input(file_descriptor);
+  return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool MessageLite::ParsePartialFromFileDescriptor(int file_descriptor) {
+  io::FileInputStream input(file_descriptor);
+  return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool MessageLite::ParseFromIstream(std::istream* input) {
+  io::IstreamInputStream zero_copy_input(input);
+  return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+bool MessageLite::ParsePartialFromIstream(std::istream* input) {
+  io::IstreamInputStream zero_copy_input(input);
+  return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+bool MessageLite::MergePartialFromBoundedZeroCopyStream(
+    io::ZeroCopyInputStream* input, int size) {
+  return ParseFrom<kMergePartial>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                                 int size) {
+  return ParseFrom<kMerge>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                                 int size) {
+  return ParseFrom<kParse>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
+    io::ZeroCopyInputStream* input, int size) {
+  return ParseFrom<kParsePartial>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::ParseFromString(ConstStringParam data) {
+  return ParseFrom<kParse>(data);
+}
+
+bool MessageLite::ParsePartialFromString(ConstStringParam data) {
+  return ParseFrom<kParsePartial>(data);
+}
+
+bool MessageLite::ParseFromArray(const void* data, int size) {
+  return ParseFrom<kParse>(as_string_view(data, size));
+}
+
+bool MessageLite::ParsePartialFromArray(const void* data, int size) {
+  return ParseFrom<kParsePartial>(as_string_view(data, size));
+}
+
+bool MessageLite::MergeFromString(ConstStringParam data) {
+  return ParseFrom<kMerge>(data);
+}
+
+
+// ===================================================================
+
+inline uint8_t* SerializeToArrayImpl(const MessageLite& msg, uint8_t* target,
+                                     int size) {
+  constexpr bool debug = false;
+  if (debug) {
+    // Force serialization to a stream with a block size of 1, which forces
+    // all writes to the stream to cross buffers triggering all fallback paths
+    // in the unittests when serializing to string / array.
+    io::ArrayOutputStream stream(target, size, 1);
+    uint8_t* ptr;
+    io::EpsCopyOutputStream out(
+        &stream, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
+        &ptr);
+    ptr = msg._InternalSerialize(ptr, &out);
+    out.Trim(ptr);
+    GOOGLE_DCHECK(!out.HadError() && stream.ByteCount() == size);
+    return target + size;
+  } else {
+    io::EpsCopyOutputStream out(
+        target, size,
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    auto res = msg._InternalSerialize(target, &out);
+    GOOGLE_DCHECK(target + size == res);
+    return res;
+  }
+}
+
+uint8_t* MessageLite::SerializeWithCachedSizesToArray(uint8_t* target) const {
+  // We only optimize this when using optimize_for = SPEED.  In other cases
+  // we just use the CodedOutputStream path.
+  return SerializeToArrayImpl(*this, target, GetCachedSize());
+}
+
+bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToCodedStream(output);
+}
+
+bool MessageLite::SerializePartialToCodedStream(
+    io::CodedOutputStream* output) const {
+  const size_t size = ByteSizeLong();  // Force size to be cached.
+  if (size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << size;
+    return false;
+  }
+
+  int original_byte_count = output->ByteCount();
+  SerializeWithCachedSizes(output);
+  if (output->HadError()) {
+    return false;
+  }
+  int final_byte_count = output->ByteCount();
+
+  if (final_byte_count - original_byte_count != static_cast<int64_t>(size)) {
+    ByteSizeConsistencyError(size, ByteSizeLong(),
+                             final_byte_count - original_byte_count, *this);
+  }
+
+  return true;
+}
+
+bool MessageLite::SerializeToZeroCopyStream(
+    io::ZeroCopyOutputStream* output) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToZeroCopyStream(output);
+}
+
+bool MessageLite::SerializePartialToZeroCopyStream(
+    io::ZeroCopyOutputStream* output) const {
+  const size_t size = ByteSizeLong();  // Force size to be cached.
+  if (size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << size;
+    return false;
+  }
+
+  uint8_t* target;
+  io::EpsCopyOutputStream stream(
+      output, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
+      &target);
+  target = _InternalSerialize(target, &stream);
+  stream.Trim(target);
+  if (stream.HadError()) return false;
+  return true;
+}
+
+bool MessageLite::SerializeToFileDescriptor(int file_descriptor) const {
+  io::FileOutputStream output(file_descriptor);
+  return SerializeToZeroCopyStream(&output) && output.Flush();
+}
+
+bool MessageLite::SerializePartialToFileDescriptor(int file_descriptor) const {
+  io::FileOutputStream output(file_descriptor);
+  return SerializePartialToZeroCopyStream(&output) && output.Flush();
+}
+
+bool MessageLite::SerializeToOstream(std::ostream* output) const {
+  {
+    io::OstreamOutputStream zero_copy_output(output);
+    if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
+  }
+  return output->good();
+}
+
+bool MessageLite::SerializePartialToOstream(std::ostream* output) const {
+  io::OstreamOutputStream zero_copy_output(output);
+  return SerializePartialToZeroCopyStream(&zero_copy_output);
+}
+
+bool MessageLite::AppendToString(std::string* output) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return AppendPartialToString(output);
+}
+
+bool MessageLite::AppendPartialToString(std::string* output) const {
+  size_t old_size = output->size();
+  size_t byte_size = ByteSizeLong();
+  if (byte_size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << byte_size;
+    return false;
+  }
+
+  STLStringResizeUninitializedAmortized(output, old_size + byte_size);
+  uint8_t* start =
+      reinterpret_cast<uint8_t*>(io::mutable_string_data(output) + old_size);
+  SerializeToArrayImpl(*this, start, byte_size);
+  return true;
+}
+
+bool MessageLite::SerializeToString(std::string* output) const {
+  output->clear();
+  return AppendToString(output);
+}
+
+bool MessageLite::SerializePartialToString(std::string* output) const {
+  output->clear();
+  return AppendPartialToString(output);
+}
+
+bool MessageLite::SerializeToArray(void* data, int size) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToArray(data, size);
+}
+
+bool MessageLite::SerializePartialToArray(void* data, int size) const {
+  const size_t byte_size = ByteSizeLong();
+  if (byte_size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << byte_size;
+    return false;
+  }
+  if (size < static_cast<int64_t>(byte_size)) return false;
+  uint8_t* start = reinterpret_cast<uint8_t*>(data);
+  SerializeToArrayImpl(*this, start, byte_size);
+  return true;
+}
+
+std::string MessageLite::SerializeAsString() const {
+  // If the compiler implements the (Named) Return Value Optimization,
+  // 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.
+  std::string output;
+  if (!AppendToString(&output)) output.clear();
+  return output;
+}
+
+std::string MessageLite::SerializePartialAsString() const {
+  std::string output;
+  if (!AppendPartialToString(&output)) output.clear();
+  return output;
+}
+
+
+namespace internal {
+
+MessageLite* NewFromPrototypeHelper(const MessageLite* prototype,
+                                    Arena* arena) {
+  return prototype->New(arena);
+}
+template <>
+void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
+                                            MessageLite* to) {
+  to->CheckTypeAndMergeFrom(from);
+}
+template <>
+void GenericTypeHandler<std::string>::Merge(const std::string& from,
+                                            std::string* to) {
+  *to = from;
+}
+
+// Non-inline implementations of InternalMetadata destructor
+// This is moved out of the header because the GOOGLE_DCHECK produces a lot of code.
+void InternalMetadata::CheckedDestruct() {
+  if (HasMessageOwnedArenaTag()) {
+    GOOGLE_DCHECK(!HasUnknownFieldsTag());
+    delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
+  }
+}
+
+// Non-inline variants of std::string specializations for
+// various InternalMetadata routines.
+template <>
+void InternalMetadata::DoClear<std::string>() {
+  mutable_unknown_fields<std::string>()->clear();
+}
+
+template <>
+void InternalMetadata::DoMergeFrom<std::string>(const std::string& other) {
+  mutable_unknown_fields<std::string>()->append(other);
+}
+
+template <>
+void InternalMetadata::DoSwap<std::string>(std::string* other) {
+  mutable_unknown_fields<std::string>()->swap(*other);
+}
+
+}  // namespace internal
+
+
+// ===================================================================
+// Shutdown support.
+
+namespace internal {
+
+struct ShutdownData {
+  ~ShutdownData() {
+    std::reverse(functions.begin(), functions.end());
+    for (auto pair : functions) pair.first(pair.second);
+  }
+
+  static ShutdownData* get() {
+    static auto* data = new ShutdownData;
+    return data;
+  }
+
+  std::vector<std::pair<void (*)(const void*), const void*>> functions;
+  Mutex mutex;
+};
+
+static void RunZeroArgFunc(const void* arg) {
+  void (*func)() = reinterpret_cast<void (*)()>(const_cast<void*>(arg));
+  func();
+}
+
+void OnShutdown(void (*func)()) {
+  OnShutdownRun(RunZeroArgFunc, reinterpret_cast<void*>(func));
+}
+
+void OnShutdownRun(void (*f)(const void*), const void* arg) {
+  auto shutdown_data = ShutdownData::get();
+  MutexLock lock(&shutdown_data->mutex);
+  shutdown_data->functions.push_back(std::make_pair(f, arg));
+}
+
+}  // namespace internal
+
+void ShutdownProtobufLibrary() {
+  // This function should be called only once, but accepts multiple calls.
+  static bool is_shutdown = false;
+  if (!is_shutdown) {
+    delete internal::ShutdownData::get();
+    is_shutdown = true;
+  }
+}
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
new file mode 100644
index 0000000..950ae1a
--- /dev/null
+++ b/src/google/protobuf/message_lite.h
@@ -0,0 +1,591 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Authors: wink@google.com (Wink Saville),
+//          kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Defines MessageLite, the abstract interface implemented by all (lite
+// and non-lite) protocol message objects.
+
+#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__
+#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
+
+
+#include <climits>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/explicitly_constructed.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/stubs/hash.h>  // TODO(b/211442718): cleanup
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+template <typename T>
+class RepeatedPtrField;
+
+class FastReflectionMessageMutator;
+class FastReflectionStringSetter;
+class Reflection;
+
+namespace io {
+
+class CodedInputStream;
+class CodedOutputStream;
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+
+}  // namespace io
+namespace internal {
+
+class SwapFieldHelper;
+
+// See parse_context.h for explanation
+class ParseContext;
+
+class ExtensionSet;
+class LazyField;
+class RepeatedPtrFieldBase;
+class TcParser;
+class WireFormatLite;
+class WeakFieldMap;
+
+template <typename Type>
+class GenericTypeHandler;  // defined in repeated_field.h
+
+// We compute sizes as size_t but cache them as int.  This function converts a
+// computed size to a cached size.  Since we don't proceed with serialization
+// if the total size was > INT_MAX, it is not important what this function
+// returns for inputs > INT_MAX.  However this case should not error or
+// GOOGLE_CHECK-fail, because the full size_t resolution is still returned from
+// ByteSizeLong() and checked against INT_MAX; we can catch the overflow
+// there.
+inline int ToCachedSize(size_t size) { return static_cast<int>(size); }
+
+// We mainly calculate sizes in terms of size_t, but some functions that
+// compute sizes return "int".  These int sizes are expected to always be
+// positive. This function is more efficient than casting an int to size_t
+// directly on 64-bit platforms because it avoids making the compiler emit a
+// sign extending instruction, which we don't want and don't want to pay for.
+inline size_t FromIntSize(int size) {
+  // Convert to unsigned before widening so sign extension is not necessary.
+  return static_cast<unsigned int>(size);
+}
+
+// For cases where a legacy function returns an integer size.  We GOOGLE_DCHECK()
+// that the conversion will fit within an integer; if this is false then we
+// are losing information.
+inline int ToIntSize(size_t size) {
+  GOOGLE_DCHECK_LE(size, static_cast<size_t>(INT_MAX));
+  return static_cast<int>(size);
+}
+
+// Default empty string object. Don't use this directly. Instead, call
+// GetEmptyString() to get the reference. This empty string is aligned with a
+// minimum alignment of 8 bytes to match the requirement of ArenaStringPtr.
+PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
+    fixed_address_empty_string;
+
+
+PROTOBUF_EXPORT constexpr const std::string& GetEmptyStringAlreadyInited() {
+  return fixed_address_empty_string.get();
+}
+
+PROTOBUF_EXPORT size_t StringSpaceUsedExcludingSelfLong(const std::string& str);
+
+}  // namespace internal
+
+// Interface to light weight protocol messages.
+//
+// This interface is implemented by all protocol message objects.  Non-lite
+// messages additionally implement the Message interface, which is a
+// subclass of MessageLite.  Use MessageLite instead when you only need
+// the subset of features which it supports -- namely, nothing that uses
+// descriptors or reflection.  You can instruct the protocol compiler
+// to generate classes which implement only MessageLite, not the full
+// Message interface, by adding the following line to the .proto file:
+//
+//   option optimize_for = LITE_RUNTIME;
+//
+// This is particularly useful on resource-constrained systems where
+// the full protocol buffers runtime library is too big.
+//
+// Note that on non-constrained systems (e.g. servers) when you need
+// to link in lots of protocol definitions, a better way to reduce
+// total code footprint is to use optimize_for = CODE_SIZE.  This
+// will make the generated code smaller while still supporting all the
+// same features (at the expense of speed).  optimize_for = LITE_RUNTIME
+// is best when you only have a small number of message types linked
+// into your binary, in which case the size of the protocol buffers
+// runtime itself is the biggest problem.
+//
+// Users must not derive from this class. Only the protocol compiler and
+// the internal library are allowed to create subclasses.
+class PROTOBUF_EXPORT MessageLite {
+ public:
+  constexpr MessageLite() {}
+  virtual ~MessageLite() = default;
+
+  // Basic Operations ------------------------------------------------
+
+  // Get the name of this message type, e.g. "foo.bar.BazProto".
+  virtual std::string GetTypeName() const = 0;
+
+  // Construct a new instance of the same type.  Ownership is passed to the
+  // caller.
+  MessageLite* New() const { return New(nullptr); }
+
+  // Construct a new instance on the arena. Ownership is passed to the caller
+  // if arena is a nullptr.
+  virtual MessageLite* New(Arena* arena) const = 0;
+
+  // Returns user-owned arena; nullptr if it's message owned.
+  Arena* GetArena() const { return _internal_metadata_.user_arena(); }
+
+  // Clear all fields of the message and set them to their default values.
+  // Clear() assumes that any memory allocated to hold parts of the message
+  // will likely be needed again, so the memory used may not be freed.
+  // To ensure that all memory used by a Message is freed, you must delete it.
+  virtual void Clear() = 0;
+
+  // Quickly check if all required fields have values set.
+  virtual bool IsInitialized() const = 0;
+
+  // This is not implemented for Lite messages -- it just returns "(cannot
+  // determine missing fields for lite message)".  However, it is implemented
+  // for full messages.  See message.h.
+  virtual std::string InitializationErrorString() const;
+
+  // If |other| is the exact same class as this, calls MergeFrom(). Otherwise,
+  // results are undefined (probably crash).
+  virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0;
+
+  // These methods return a human-readable summary of the message. Note that
+  // since the MessageLite interface does not support reflection, there is very
+  // little information that these methods can provide. They are shadowed by
+  // methods of the same name on the Message interface which provide much more
+  // information. The methods here are intended primarily to facilitate code
+  // reuse for logic that needs to interoperate with both full and lite protos.
+  //
+  // The format of the returned string is subject to change, so please do not
+  // assume it will remain stable over time.
+  std::string DebugString() const;
+  std::string ShortDebugString() const { return DebugString(); }
+  // MessageLite::DebugString is already Utf8 Safe. This is to add compatibility
+  // with Message.
+  std::string Utf8DebugString() const { return DebugString(); }
+
+  // Parsing ---------------------------------------------------------
+  // Methods for parsing in protocol buffer format.  Most of these are
+  // just simple wrappers around MergeFromCodedStream().  Clear() will be
+  // called before merging the input.
+
+  // Fill the message with a protocol buffer parsed from the given input
+  // stream. Returns false on a read error or if the input is in the wrong
+  // format.  A successful return does not indicate the entire input is
+  // consumed, ensure you call ConsumedEntireMessage() to check that if
+  // applicable.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromCodedStream(
+      io::CodedInputStream* input);
+  // Like ParseFromCodedStream(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromCodedStream(
+      io::CodedInputStream* input);
+  // Read a protocol buffer from the given zero-copy input stream.  If
+  // successful, the entire input will be consumed.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromZeroCopyStream(
+      io::ZeroCopyInputStream* input);
+  // Like ParseFromZeroCopyStream(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromZeroCopyStream(
+      io::ZeroCopyInputStream* input);
+  // Parse a protocol buffer from a file descriptor.  If successful, the entire
+  // input will be consumed.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromFileDescriptor(
+      int file_descriptor);
+  // Like ParseFromFileDescriptor(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromFileDescriptor(
+      int file_descriptor);
+  // Parse a protocol buffer from a C++ istream.  If successful, the entire
+  // input will be consumed.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromIstream(std::istream* input);
+  // Like ParseFromIstream(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromIstream(
+      std::istream* input);
+  // Read a protocol buffer from the given zero-copy input stream, expecting
+  // the message to be exactly "size" bytes long.  If successful, exactly
+  // this many bytes will have been consumed from the input.
+  bool MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                             int size);
+  // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+  // missing required fields.
+  bool MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromBoundedZeroCopyStream(
+      io::ZeroCopyInputStream* input, int size);
+  // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+  // missing required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromBoundedZeroCopyStream(
+      io::ZeroCopyInputStream* input, int size);
+  // Parses a protocol buffer contained in a string. Returns true on success.
+  // This function takes a string in the (non-human-readable) binary wire
+  // format, matching the encoding output by MessageLite::SerializeToString().
+  // If you'd like to convert a human-readable string into a protocol buffer
+  // object, see google::protobuf::TextFormat::ParseFromString().
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromString(ConstStringParam data);
+  // Like ParseFromString(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromString(
+      ConstStringParam data);
+  // Parse a protocol buffer contained in an array of bytes.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromArray(const void* data,
+                                                       int size);
+  // Like ParseFromArray(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromArray(const void* data,
+                                                              int size);
+
+
+  // Reads a protocol buffer from the stream and merges it into this
+  // Message.  Singular fields read from the what is
+  // already in the Message and repeated fields are appended to those
+  // already present.
+  //
+  // It is the responsibility of the caller to call input->LastTagWas()
+  // (for groups) or input->ConsumedEntireMessage() (for non-groups) after
+  // this returns to verify that the message's end was delimited correctly.
+  //
+  // ParseFromCodedStream() is implemented as Clear() followed by
+  // MergeFromCodedStream().
+  bool MergeFromCodedStream(io::CodedInputStream* input);
+
+  // Like MergeFromCodedStream(), but succeeds even if required fields are
+  // missing in the input.
+  //
+  // MergeFromCodedStream() is just implemented as MergePartialFromCodedStream()
+  // followed by IsInitialized().
+  bool MergePartialFromCodedStream(io::CodedInputStream* input);
+
+  // Merge a protocol buffer contained in a string.
+  bool MergeFromString(ConstStringParam data);
+
+
+  // Serialization ---------------------------------------------------
+  // Methods for serializing in protocol buffer format.  Most of these
+  // are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
+
+  // Write a protocol buffer of this message to the given output.  Returns
+  // false on a write error.  If the message is missing required fields,
+  // this may GOOGLE_CHECK-fail.
+  bool SerializeToCodedStream(io::CodedOutputStream* output) const;
+  // Like SerializeToCodedStream(), but allows missing required fields.
+  bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;
+  // Write the message to the given zero-copy output stream.  All required
+  // fields must be set.
+  bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
+  // Like SerializeToZeroCopyStream(), but allows missing required fields.
+  bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
+  // Serialize the message and store it in the given string.  All required
+  // fields must be set.
+  bool SerializeToString(std::string* output) const;
+  // Like SerializeToString(), but allows missing required fields.
+  bool SerializePartialToString(std::string* output) const;
+  // Serialize the message and store it in the given byte array.  All required
+  // fields must be set.
+  bool SerializeToArray(void* data, int size) const;
+  // Like SerializeToArray(), but allows missing required fields.
+  bool SerializePartialToArray(void* data, int size) const;
+
+  // Make a string encoding the message. Is equivalent to calling
+  // SerializeToString() on a string and using that.  Returns the empty
+  // string if SerializeToString() would have returned an error.
+  // Note: If you intend to generate many such strings, you may
+  // reduce heap fragmentation by instead re-using the same string
+  // object with calls to SerializeToString().
+  std::string SerializeAsString() const;
+  // Like SerializeAsString(), but allows missing required fields.
+  std::string SerializePartialAsString() const;
+
+  // Serialize the message and write it to the given file descriptor.  All
+  // required fields must be set.
+  bool SerializeToFileDescriptor(int file_descriptor) const;
+  // Like SerializeToFileDescriptor(), but allows missing required fields.
+  bool SerializePartialToFileDescriptor(int file_descriptor) const;
+  // Serialize the message and write it to the given C++ ostream.  All
+  // required fields must be set.
+  bool SerializeToOstream(std::ostream* output) const;
+  // Like SerializeToOstream(), but allows missing required fields.
+  bool SerializePartialToOstream(std::ostream* output) const;
+
+  // Like SerializeToString(), but appends to the data to the string's
+  // existing contents.  All required fields must be set.
+  bool AppendToString(std::string* output) const;
+  // Like AppendToString(), but allows missing required fields.
+  bool AppendPartialToString(std::string* output) const;
+
+
+  // Computes the serialized size of the message.  This recursively calls
+  // ByteSizeLong() on all embedded messages.
+  //
+  // ByteSizeLong() is generally linear in the number of fields defined for the
+  // proto.
+  virtual size_t ByteSizeLong() const = 0;
+
+  // Legacy ByteSize() API.
+  PROTOBUF_DEPRECATED_MSG("Please use ByteSizeLong() instead")
+  int ByteSize() const { return internal::ToIntSize(ByteSizeLong()); }
+
+  // Serializes the message without recomputing the size.  The message must not
+  // have changed since the last call to ByteSize(), and the value returned by
+  // ByteSize must be non-negative.  Otherwise the results are undefined.
+  void SerializeWithCachedSizes(io::CodedOutputStream* output) const {
+    output->SetCur(_InternalSerialize(output->Cur(), output->EpsCopy()));
+  }
+
+  // Functions below here are not part of the public interface.  It isn't
+  // enforced, but they should be treated as private, and will be private
+  // at some future time.  Unfortunately the implementation of the "friend"
+  // keyword in GCC is broken at the moment, but we expect it will be fixed.
+
+  // Like SerializeWithCachedSizes, but writes directly to *target, returning
+  // a pointer to the byte immediately after the last byte written.  "target"
+  // must point at a byte array of at least ByteSize() bytes.  Whether to use
+  // deterministic serialization, e.g., maps in sorted order, is determined by
+  // CodedOutputStream::IsDefaultSerializationDeterministic().
+  uint8_t* SerializeWithCachedSizesToArray(uint8_t* target) const;
+
+  // Returns the result of the last call to ByteSize().  An embedded message's
+  // size is needed both to serialize it (because embedded messages are
+  // length-delimited) and to compute the outer message's size.  Caching
+  // the size avoids computing it multiple times.
+  //
+  // ByteSize() does not automatically use the cached size when available
+  // because this would require invalidating it every time the message was
+  // modified, which would be too hard and expensive.  (E.g. if a deeply-nested
+  // sub-message is changed, all of its parents' cached sizes would need to be
+  // invalidated, which is too much work for an otherwise inlined setter
+  // method.)
+  virtual int GetCachedSize() const = 0;
+
+  virtual const char* _InternalParse(const char* /*ptr*/,
+                                     internal::ParseContext* /*ctx*/) {
+    return nullptr;
+  }
+
+  virtual void OnDemandRegisterArenaDtor(Arena* /*arena*/) {}
+
+ protected:
+  template <typename T>
+  static T* CreateMaybeMessage(Arena* arena) {
+    return Arena::CreateMaybeMessage<T>(arena);
+  }
+
+  inline explicit MessageLite(Arena* arena, bool is_message_owned = false)
+      : _internal_metadata_(arena, is_message_owned) {}
+
+  // Returns the arena, if any, that directly owns this message and its internal
+  // memory (Arena::Own is different in that the arena doesn't directly own the
+  // internal memory). This method is used in proto's implementation for
+  // swapping, moving and setting allocated, for deciding whether the ownership
+  // of this message or its internal memory could be changed.
+  Arena* GetOwningArena() const { return _internal_metadata_.owning_arena(); }
+
+  // Returns the arena, used for allocating internal objects(e.g., child
+  // messages, etc), or owning incoming objects (e.g., set allocated).
+  Arena* GetArenaForAllocation() const { return _internal_metadata_.arena(); }
+
+  // Returns true if this message is enabled for message-owned arena (MOA)
+  // trials. No lite messages are eligible for MOA.
+  static bool InMoaTrial() { return false; }
+
+  internal::InternalMetadata _internal_metadata_;
+
+ public:
+  enum ParseFlags {
+    kMerge = 0,
+    kParse = 1,
+    kMergePartial = 2,
+    kParsePartial = 3,
+    kMergeWithAliasing = 4,
+    kParseWithAliasing = 5,
+    kMergePartialWithAliasing = 6,
+    kParsePartialWithAliasing = 7
+  };
+
+  template <ParseFlags flags, typename T>
+  bool ParseFrom(const T& input);
+
+  // Fast path when conditions match (ie. non-deterministic)
+  //  uint8_t* _InternalSerialize(uint8_t* ptr) const;
+  virtual uint8_t* _InternalSerialize(
+      uint8_t* ptr, io::EpsCopyOutputStream* stream) const = 0;
+
+  // Identical to IsInitialized() except that it logs an error message.
+  bool IsInitializedWithErrors() const {
+    if (IsInitialized()) return true;
+    LogInitializationErrorMessage();
+    return false;
+  }
+
+ private:
+  friend class FastReflectionMessageMutator;
+  friend class FastReflectionStringSetter;
+  friend class Message;
+  friend class Reflection;
+  friend class internal::ExtensionSet;
+  friend class internal::LazyField;
+  friend class internal::SwapFieldHelper;
+  friend class internal::TcParser;
+  friend class internal::WeakFieldMap;
+  friend class internal::WireFormatLite;
+
+  template <typename Type>
+  friend class Arena::InternalHelper;
+  template <typename Type>
+  friend class internal::GenericTypeHandler;
+
+  void LogInitializationErrorMessage() const;
+
+  bool MergeFromImpl(io::CodedInputStream* input, ParseFlags parse_flags);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
+};
+
+namespace internal {
+
+template <bool alias>
+bool MergeFromImpl(StringPiece input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<false>(StringPiece input,
+                                          MessageLite* msg,
+                                          MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<true>(StringPiece input,
+                                         MessageLite* msg,
+                                         MessageLite::ParseFlags parse_flags);
+
+template <bool alias>
+bool MergeFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<false>(io::ZeroCopyInputStream* input,
+                                          MessageLite* msg,
+                                          MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<true>(io::ZeroCopyInputStream* input,
+                                         MessageLite* msg,
+                                         MessageLite::ParseFlags parse_flags);
+
+struct BoundedZCIS {
+  io::ZeroCopyInputStream* zcis;
+  int limit;
+};
+
+template <bool alias>
+bool MergeFromImpl(BoundedZCIS input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<false>(BoundedZCIS input, MessageLite* msg,
+                                          MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<true>(BoundedZCIS input, MessageLite* msg,
+                                         MessageLite::ParseFlags parse_flags);
+
+template <typename T>
+struct SourceWrapper;
+
+template <bool alias, typename T>
+bool MergeFromImpl(const SourceWrapper<T>& input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  return input.template MergeInto<alias>(msg, parse_flags);
+}
+
+}  // namespace internal
+
+template <MessageLite::ParseFlags flags, typename T>
+bool MessageLite::ParseFrom(const T& input) {
+  if (flags & kParse) Clear();
+  constexpr bool alias = (flags & kMergeWithAliasing) != 0;
+  return internal::MergeFromImpl<alias>(input, this, flags);
+}
+
+// ===================================================================
+// Shutdown support.
+
+
+// Shut down the entire protocol buffers library, deleting all static-duration
+// objects allocated by the library or by generated .pb.cc files.
+//
+// There are two reasons you might want to call this:
+// * You use a draconian definition of "memory leak" in which you expect
+//   every single malloc() to have a corresponding free(), even for objects
+//   which live until program exit.
+// * You are writing a dynamically-loaded library which needs to clean up
+//   after itself when the library is unloaded.
+//
+// It is safe to call this multiple times.  However, it is not safe to use
+// any other part of the protocol buffers library after
+// ShutdownProtobufLibrary() has been called. Furthermore this call is not
+// thread safe, user needs to synchronize multiple calls.
+PROTOBUF_EXPORT void ShutdownProtobufLibrary();
+
+namespace internal {
+
+// Register a function to be called when ShutdownProtocolBuffers() is called.
+PROTOBUF_EXPORT void OnShutdown(void (*func)());
+// Run an arbitrary function on an arg
+PROTOBUF_EXPORT void OnShutdownRun(void (*f)(const void*), const void* arg);
+
+template <typename T>
+T* OnShutdownDelete(T* p) {
+  OnShutdownRun([](const void* pp) { delete static_cast<const T*>(pp); }, p);
+  return p;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MESSAGE_LITE_H__
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
new file mode 100644
index 0000000..f71f60c
--- /dev/null
+++ b/src/google/protobuf/message_unittest.cc
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/unittest.pb.h>
+
+#define MESSAGE_TEST_NAME MessageTest
+#define MESSAGE_FACTORY_TEST_NAME MessageFactoryTest
+#define UNITTEST_PACKAGE_NAME "protobuf_unittest"
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+
+// Must include after the above macros.
+// clang-format off
+#include <google/protobuf/test_util.inc>
+#include <google/protobuf/message_unittest.inc>
+#include <google/protobuf/arena.h>
+// clang-format on
diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc
new file mode 100644
index 0000000..fa2bbbf
--- /dev/null
+++ b/src/google/protobuf/message_unittest.inc
@@ -0,0 +1,1131 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 needs to be included as .inc as it depends on certain macros being
+// defined prior to its inclusion.
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cmath>
+#include <limits>
+
+#include <google/protobuf/message.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <fstream>
+#include <sstream>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/generated_message_reflection.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/test_util2.h>
+
+
+namespace google {
+namespace protobuf {
+
+#if defined(_WIN32)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::open;
+#endif
+
+#ifndef O_BINARY
+#ifdef _O_BINARY
+#define O_BINARY _O_BINARY
+#else
+#define O_BINARY 0  // If this isn't defined, the platform doesn't need it.
+#endif
+#endif
+
+TEST(MESSAGE_TEST_NAME, SerializeHelpers) {
+  // TODO(kenton):  Test more helpers?  They're all two-liners so it seems
+  //   like a waste of time.
+
+  UNITTEST::TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+  std::stringstream stream;
+
+  std::string str1("foo");
+  std::string str2("bar");
+
+  EXPECT_TRUE(message.SerializeToString(&str1));
+  EXPECT_TRUE(message.AppendToString(&str2));
+  EXPECT_TRUE(message.SerializeToOstream(&stream));
+
+  EXPECT_EQ(str1.size() + 3, str2.size());
+  EXPECT_EQ("bar", str2.substr(0, 3));
+  // Don't use EXPECT_EQ because we don't want to dump raw binary data to
+  // stdout.
+  EXPECT_TRUE(str2.substr(3) == str1);
+
+  // GCC gives some sort of error if we try to just do stream.str() == str1.
+  std::string temp = stream.str();
+  EXPECT_TRUE(temp == str1);
+
+  EXPECT_TRUE(message.SerializeAsString() == str1);
+
+}
+
+TEST(MESSAGE_TEST_NAME, SerializeToBrokenOstream) {
+  std::ofstream out;
+  UNITTEST::TestAllTypes message;
+  message.set_optional_int32(123);
+
+  EXPECT_FALSE(message.SerializeToOstream(&out));
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFromFileDescriptor) {
+  std::string filename =
+      TestUtil::GetTestDataPath("net/proto2/internal/testdata/golden_message");
+  int file = open(filename.c_str(), O_RDONLY | O_BINARY);
+  ASSERT_GE(file, 0);
+
+  UNITTEST::TestAllTypes message;
+  EXPECT_TRUE(message.ParseFromFileDescriptor(file));
+  TestUtil::ExpectAllFieldsSet(message);
+
+  EXPECT_GE(close(file), 0);
+}
+
+TEST(MESSAGE_TEST_NAME, ParsePackedFromFileDescriptor) {
+  std::string filename = TestUtil::GetTestDataPath(
+      "net/proto2/internal/testdata/golden_packed_fields_message");
+  int file = open(filename.c_str(), O_RDONLY | O_BINARY);
+  ASSERT_GE(file, 0);
+
+  UNITTEST::TestPackedTypes message;
+  EXPECT_TRUE(message.ParseFromFileDescriptor(file));
+  TestUtil::ExpectPackedFieldsSet(message);
+
+  EXPECT_GE(close(file), 0);
+}
+
+TEST(MESSAGE_TEST_NAME, ParseHelpers) {
+  // TODO(kenton):  Test more helpers?  They're all two-liners so it seems
+  //   like a waste of time.
+  std::string data;
+
+  {
+    // Set up.
+    UNITTEST::TestAllTypes message;
+    TestUtil::SetAllFields(&message);
+    message.SerializeToString(&data);
+  }
+
+  {
+    // Test ParseFromString.
+    UNITTEST::TestAllTypes message;
+    EXPECT_TRUE(message.ParseFromString(data));
+    TestUtil::ExpectAllFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromIstream.
+    UNITTEST::TestAllTypes message;
+    std::stringstream stream(data);
+    EXPECT_TRUE(message.ParseFromIstream(&stream));
+    EXPECT_TRUE(stream.eof());
+    TestUtil::ExpectAllFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromBoundedZeroCopyStream.
+    std::string data_with_junk(data);
+    data_with_junk.append("some junk on the end");
+    io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
+    UNITTEST::TestAllTypes message;
+    EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+    TestUtil::ExpectAllFieldsSet(message);
+  }
+
+  {
+    // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
+    // EOF is reached before the expected number of bytes.
+    io::ArrayInputStream stream(data.data(), data.size());
+    UNITTEST::TestAllTypes message;
+    EXPECT_FALSE(
+        message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
+  }
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfNotInitialized) {
+  UNITTEST::TestRequired message;
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog log;
+    EXPECT_FALSE(message.ParseFromString(""));
+    errors = log.GetMessages(ERROR);
+  }
+
+  ASSERT_EQ(1, errors.size());
+  EXPECT_EQ(
+      "Can't parse message of type \"" + std::string(UNITTEST_PACKAGE_NAME) +
+          ".TestRequired\" because it is missing required fields: a, b, c",
+      errors[0]);
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfSubmessageNotInitialized) {
+  UNITTEST::TestRequiredForeign source, message;
+  source.mutable_optional_message()->set_dummy2(100);
+  std::string serialized = source.SerializePartialAsString();
+
+  EXPECT_TRUE(message.ParsePartialFromString(serialized));
+  EXPECT_FALSE(message.IsInitialized());
+
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    EXPECT_FALSE(message.ParseFromString(source.SerializePartialAsString()));
+    errors = log.GetMessages(ERROR);
+  }
+
+  EXPECT_THAT(
+      errors,
+      testing::ElementsAre(
+          "Can't parse message of type \"" +
+          std::string(UNITTEST_PACKAGE_NAME) +
+          ".TestRequiredForeign\" because it is missing required fields: "
+          "optional_message.a, optional_message.b, optional_message.c"));
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfExtensionNotInitialized) {
+  UNITTEST::TestChildExtension source, message;
+  auto* r = source.mutable_optional_extension()->MutableExtension(
+      UNITTEST::TestRequired::single);
+  r->set_dummy2(100);
+  std::string serialized = source.SerializePartialAsString();
+
+  EXPECT_TRUE(message.ParsePartialFromString(serialized));
+  EXPECT_FALSE(message.IsInitialized());
+
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    EXPECT_FALSE(message.ParseFromString(source.SerializePartialAsString()));
+    errors = log.GetMessages(ERROR);
+  }
+
+  EXPECT_THAT(errors,
+              testing::ElementsAre(strings::Substitute(
+                  "Can't parse message of type \"$0.TestChildExtension\" "
+                  "because it is missing required fields: "
+                  "optional_extension.($0.TestRequired.single).a, "
+                  "optional_extension.($0.TestRequired.single).b, "
+                  "optional_extension.($0.TestRequired.single).c",
+                  UNITTEST_PACKAGE_NAME)));
+}
+
+TEST(MESSAGE_TEST_NAME, MergeFromUninitialized) {
+  UNITTEST::TestNestedRequiredForeign o, p, q;
+  UNITTEST::TestNestedRequiredForeign* child = o.mutable_child();
+  constexpr int kDepth = 2;
+  for (int i = 0; i < kDepth; i++) {
+    child->set_dummy(i);
+    child = child->mutable_child();
+  }
+  UNITTEST::TestRequiredForeign* payload = child->mutable_payload();
+  payload->mutable_optional_message()->set_a(1);
+  payload->mutable_optional_message()->set_dummy2(100);
+  payload->mutable_optional_message()->set_dummy4(200);
+  ASSERT_TRUE(p.ParsePartialFromString(o.SerializePartialAsString()));
+
+  q.mutable_child()->set_dummy(500);
+  q = p;
+  q.ParsePartialFromString(q.SerializePartialAsString());
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(q, o.SerializePartialAsString()));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(q, p.SerializePartialAsString()));
+}
+
+TEST(MESSAGE_TEST_NAME, ExplicitLazyExceedRecursionLimit) {
+  UNITTEST::NestedTestAllTypes original, parsed;
+  // Build proto with recursion depth of 3.
+  original.mutable_lazy_child()
+      ->mutable_child()
+      ->mutable_payload()
+      ->set_optional_int32(-1);
+  std::string serialized;
+  EXPECT_TRUE(original.SerializeToString(&serialized));
+
+  // User annotated LazyField ([lazy = true]) is eagerly verified and should
+  // catch the recursion limit violation.
+  io::ArrayInputStream array_stream(serialized.data(), serialized.size());
+  io::CodedInputStream input_stream(&array_stream);
+  input_stream.SetRecursionLimit(2);
+  EXPECT_FALSE(parsed.ParseFromCodedStream(&input_stream));
+
+  // Lazy read results in parsing error which can be verified by not having
+  // expected value.
+  EXPECT_NE(parsed.lazy_child().child().payload().optional_int32(), -1);
+}
+
+TEST(MESSAGE_TEST_NAME, NestedExplicitLazyExceedRecursionLimit) {
+  UNITTEST::NestedTestAllTypes original, parsed;
+  // Build proto with recursion depth of 5, with nested annotated LazyField.
+  original.mutable_lazy_child()
+      ->mutable_child()
+      ->mutable_lazy_child()
+      ->mutable_child()
+      ->mutable_payload()
+      ->set_optional_int32(-1);
+  std::string serialized;
+  EXPECT_TRUE(original.SerializeToString(&serialized));
+
+  // User annotated LazyField ([lazy = true]) is eagerly verified and should
+  // catch the recursion limit violation.
+  io::ArrayInputStream array_stream(serialized.data(), serialized.size());
+  io::CodedInputStream input_stream(&array_stream);
+  input_stream.SetRecursionLimit(4);
+  EXPECT_FALSE(parsed.ParseFromCodedStream(&input_stream));
+
+  // Lazy read results in parsing error which can be verified by not having
+  // expected value.
+  EXPECT_NE(parsed.lazy_child()
+                .child()
+                .lazy_child()
+                .child()
+                .payload()
+                .optional_int32(),
+            -1);
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfSubmessageTruncated) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 5;
+  auto* child = o.mutable_child();
+  for (int i = 0; i < kDepth; i++) {
+    child = child->mutable_child();
+  }
+  TestUtil::SetAllFields(child->mutable_payload());
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  constexpr int kMaxTruncate = 50;
+  ASSERT_GT(serialized.size(), kMaxTruncate);
+
+  for (int i = 1; i < kMaxTruncate; i += 3) {
+    EXPECT_FALSE(
+        p.ParseFromString(serialized.substr(0, serialized.size() - i)));
+  }
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfWireMalformed) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 5;
+  auto* child = o.mutable_child();
+  for (int i = 0; i < kDepth; i++) {
+    child = child->mutable_child();
+  }
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  child->mutable_payload()->set_optional_int32(-1);
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfOneofWireMalformed) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 5;
+  auto* child = o.mutable_child();
+  for (int i = 0; i < kDepth; i++) {
+    child = child->mutable_child();
+  }
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  child->mutable_payload()->mutable_oneof_nested_message()->set_bb(-1);
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsIfExtensionWireMalformed) {
+  UNITTEST::TestChildExtension o, p;
+  auto* m = o.mutable_optional_extension()->MutableExtension(
+      UNITTEST::optional_nested_message_extension);
+
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  m->set_bb(-1);
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME, UninitializedAndMalformed) {
+  UNITTEST::TestRequiredForeign o, p1, p2;
+  o.mutable_optional_message()->set_a(-1);
+
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  std::string serialized;
+  EXPECT_TRUE(o.SerializePartialToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p1.ParsePartialFromString(serialized));
+  EXPECT_FALSE(p1.IsInitialized());
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p2.ParseFromString(serialized));
+  EXPECT_FALSE(p2.IsInitialized());
+}
+
+inline UNITTEST::NestedTestAllTypes InitNestedProto(int depth) {
+  UNITTEST::NestedTestAllTypes p;
+  auto* child = p.mutable_child();
+  for (int i = 0; i < depth; i++) {
+    child->mutable_payload()->set_optional_int32(i);
+    child = child->mutable_child();
+  }
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  child->mutable_payload()->set_optional_int32(-1);
+  return p;
+}
+
+// Parsing proto must not access beyond the bound.
+TEST(MESSAGE_TEST_NAME, ParseStrictlyBoundedStream) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 2;
+  o = InitNestedProto(kDepth);
+  TestUtil::SetAllFields(o.mutable_child()->mutable_payload());
+  o.mutable_child()->mutable_child()->mutable_payload()->set_optional_string(
+      std::string(1024, 'a'));
+
+  std::string data;
+  EXPECT_TRUE(o.SerializeToString(&data));
+
+  TestUtil::BoundedArrayInputStream stream(data.data(), data.size());
+  EXPECT_TRUE(p.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+  TestUtil::ExpectAllFieldsSet(p.child().payload());
+}
+
+TEST(MESSAGE_TEST_NAME, AllSetMethodsOnStringField) {
+  UNITTEST::TestAllTypes msg;
+
+
+  msg.set_optional_string("Asciiz");
+  EXPECT_EQ(msg.optional_string(), "Asciiz");
+
+  msg.set_optional_string("Length delimited", 6);
+  EXPECT_EQ(msg.optional_string(), "Length");
+
+  std::string value = "std::string value 1";
+  msg.set_optional_string(value);
+  EXPECT_EQ(msg.optional_string(), "std::string value 1");
+
+  value = "std::string value 2";
+  msg.set_optional_string(std::cref(value));
+  EXPECT_EQ(msg.optional_string(), "std::string value 2");
+
+  value = "std::string value 3";
+  msg.set_optional_string(std::move(value));
+  EXPECT_EQ(msg.optional_string(), "std::string value 3");
+}
+
+TEST(MESSAGE_TEST_NAME, SuccessAfterParsingFailure) {
+  UNITTEST::NestedTestAllTypes o, p, q;
+  constexpr int kDepth = 5;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+
+  // Subsequent serialization should be parsed correctly.
+  EXPECT_TRUE(q.ParseFromString(p.SerializeAsString()));
+}
+
+TEST(MESSAGE_TEST_NAME, ExceedRecursionLimit) {
+  UNITTEST::NestedTestAllTypes o, p;
+  const int kDepth = io::CodedInputStream::GetDefaultRecursionLimit() + 10;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Recursion level deeper than the default.
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME, SupportCustomRecursionLimitRead) {
+  UNITTEST::NestedTestAllTypes o, p;
+  const int kDepth = io::CodedInputStream::GetDefaultRecursionLimit() + 10;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should pass with custom limit + reads.
+  io::ArrayInputStream raw_input(serialized.data(), serialized.size());
+  io::CodedInputStream input(&raw_input);
+  input.SetRecursionLimit(kDepth + 10);
+  EXPECT_TRUE(p.ParseFromCodedStream(&input));
+
+  EXPECT_EQ(p.child().payload().optional_int32(), 0);
+  EXPECT_EQ(p.child().child().payload().optional_int32(), 1);
+
+  // Verify p serializes successfully (survives VerifyConsistency).
+  std::string result;
+  EXPECT_TRUE(p.SerializeToString(&result));
+}
+
+TEST(MESSAGE_TEST_NAME, SupportCustomRecursionLimitWrite) {
+  UNITTEST::NestedTestAllTypes o, p;
+  const int kDepth = io::CodedInputStream::GetDefaultRecursionLimit() + 10;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should pass with custom limit + writes.
+  io::ArrayInputStream raw_input(serialized.data(), serialized.size());
+  io::CodedInputStream input(&raw_input);
+  input.SetRecursionLimit(kDepth + 10);
+  EXPECT_TRUE(p.ParseFromCodedStream(&input));
+
+  EXPECT_EQ(p.mutable_child()->mutable_payload()->optional_int32(), 0);
+  EXPECT_EQ(
+      p.mutable_child()->mutable_child()->mutable_payload()->optional_int32(),
+      1);
+}
+
+// While deep recursion is never guaranteed, this test aims to catch potential
+// issues with very deep recursion.
+TEST(MESSAGE_TEST_NAME, SupportDeepRecursionLimit) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 1000;
+  auto* child = o.mutable_child();
+  for (int i = 0; i < kDepth; i++) {
+    child = child->mutable_child();
+  }
+  child->mutable_payload()->set_optional_int32(100);
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  io::ArrayInputStream raw_input(serialized.data(), serialized.size());
+  io::CodedInputStream input(&raw_input);
+  input.SetRecursionLimit(1100);
+  EXPECT_TRUE(p.ParseFromCodedStream(&input));
+}
+
+TEST(MESSAGE_TEST_NAME, Swap) {
+  UNITTEST::NestedTestAllTypes o;
+  constexpr int kDepth = 5;
+  auto* child = o.mutable_child();
+  for (int i = 0; i < kDepth; i++) {
+    child = child->mutable_child();
+  }
+  TestUtil::SetAllFields(child->mutable_payload());
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  {
+    Arena arena;
+    UNITTEST::NestedTestAllTypes* p1 =
+        Arena::CreateMessage<UNITTEST::NestedTestAllTypes>(&arena);
+
+    // Should parse correctly.
+    EXPECT_TRUE(p1->ParseFromString(serialized));
+
+    UNITTEST::NestedTestAllTypes* p2 =
+        Arena::CreateMessage<UNITTEST::NestedTestAllTypes>(&arena);
+
+    p1->Swap(p2);
+
+    EXPECT_EQ(o.SerializeAsString(), p2->SerializeAsString());
+  }
+}
+
+TEST(MESSAGE_TEST_NAME, BypassInitializationCheckOnParse) {
+  UNITTEST::TestRequired message;
+  io::ArrayInputStream raw_input(nullptr, 0);
+  io::CodedInputStream input(&raw_input);
+  EXPECT_TRUE(message.MergePartialFromCodedStream(&input));
+}
+
+TEST(MESSAGE_TEST_NAME, InitializationErrorString) {
+  UNITTEST::TestRequired message;
+  EXPECT_EQ("a, b, c", message.InitializationErrorString());
+}
+
+TEST(MESSAGE_TEST_NAME, DynamicCastToGenerated) {
+  UNITTEST::TestAllTypes test_all_types;
+
+  Message* test_all_types_pointer = &test_all_types;
+  EXPECT_EQ(&test_all_types, DynamicCastToGenerated<UNITTEST::TestAllTypes>(
+                                 test_all_types_pointer));
+  EXPECT_EQ(nullptr, DynamicCastToGenerated<UNITTEST::TestRequired>(
+                         test_all_types_pointer));
+
+  const Message* test_all_types_pointer_const = &test_all_types;
+  EXPECT_EQ(&test_all_types,
+            DynamicCastToGenerated<const UNITTEST::TestAllTypes>(
+                test_all_types_pointer_const));
+  EXPECT_EQ(nullptr, DynamicCastToGenerated<const UNITTEST::TestRequired>(
+                         test_all_types_pointer_const));
+
+  Message* test_all_types_pointer_nullptr = nullptr;
+  EXPECT_EQ(nullptr, DynamicCastToGenerated<UNITTEST::TestAllTypes>(
+                         test_all_types_pointer_nullptr));
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet.
+
+TEST(MESSAGE_TEST_NAME, SerializeFailsIfNotInitialized) {
+  UNITTEST::TestRequired message;
+  std::string data;
+  EXPECT_DEBUG_DEATH(EXPECT_TRUE(message.SerializeToString(&data)),
+                     "Can't serialize message of type \"" +
+                         std::string(UNITTEST_PACKAGE_NAME) +
+                         ".TestRequired\" because "
+                         "it is missing required fields: a, b, c");
+}
+
+TEST(MESSAGE_TEST_NAME, CheckInitialized) {
+  UNITTEST::TestRequired message;
+  EXPECT_DEATH(message.CheckInitialized(),
+               "Message of type \"" + std::string(UNITTEST_PACKAGE_NAME) +
+                   ".TestRequired\" is missing required "
+                   "fields: a, b, c");
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+namespace {
+// An input stream that repeats a std::string's content for a number of times.
+// It helps us create a really large input without consuming too much memory.
+// Used to test the parsing behavior when the input size exceeds 2G or close to
+// it.
+class RepeatedInputStream : public io::ZeroCopyInputStream {
+ public:
+  RepeatedInputStream(const std::string& data, size_t count)
+      : data_(data), count_(count), position_(0), total_byte_count_(0) {}
+
+  bool Next(const void** data, int* size) override {
+    if (position_ == data_.size()) {
+      if (--count_ == 0) {
+        return false;
+      }
+      position_ = 0;
+    }
+    *data = &data_[position_];
+    *size = static_cast<int>(data_.size() - position_);
+    position_ = data_.size();
+    total_byte_count_ += *size;
+    return true;
+  }
+
+  void BackUp(int count) override {
+    position_ -= static_cast<size_t>(count);
+    total_byte_count_ -= count;
+  }
+
+  bool Skip(int count) override {
+    while (count > 0) {
+      const void* data;
+      int size;
+      if (!Next(&data, &size)) {
+        break;
+      }
+      if (size >= count) {
+        BackUp(size - count);
+        return true;
+      } else {
+        count -= size;
+      }
+    }
+    return false;
+  }
+
+  int64_t ByteCount() const override { return total_byte_count_; }
+
+ private:
+  std::string data_;
+  size_t count_;     // The number of strings that haven't been consumed.
+  size_t position_;  // Position in the std::string for the next read.
+  int64_t total_byte_count_;
+};
+}  // namespace
+
+TEST(MESSAGE_TEST_NAME, TestParseMessagesCloseTo2G) {
+  constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
+
+  // Create a message with a large std::string field.
+  std::string value = std::string(64 * 1024 * 1024, 'x');
+  UNITTEST::TestAllTypes message;
+  message.set_optional_string(value);
+
+  // Repeat this message in the input stream to make the total input size
+  // close to 2G.
+  std::string data = message.SerializeAsString();
+  size_t count = static_cast<size_t>(kint32max) / data.size();
+  RepeatedInputStream input(data, count);
+
+  // The parsing should succeed.
+  UNITTEST::TestAllTypes result;
+  EXPECT_TRUE(result.ParseFromZeroCopyStream(&input));
+
+  // When there are multiple occurrences of a singular field, the last one
+  // should win.
+  EXPECT_EQ(value, result.optional_string());
+}
+
+TEST(MESSAGE_TEST_NAME, TestParseMessagesOver2G) {
+  constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
+
+  // Create a message with a large std::string field.
+  std::string value = std::string(64 * 1024 * 1024, 'x');
+  UNITTEST::TestAllTypes message;
+  message.set_optional_string(value);
+
+  // Repeat this message in the input stream to make the total input size
+  // larger than 2G.
+  std::string data = message.SerializeAsString();
+  size_t count = static_cast<size_t>(kint32max) / data.size() + 1;
+  RepeatedInputStream input(data, count);
+
+  // The parsing should fail.
+  UNITTEST::TestAllTypes result;
+  EXPECT_FALSE(result.ParseFromZeroCopyStream(&input));
+}
+
+TEST(MESSAGE_TEST_NAME, BypassInitializationCheckOnSerialize) {
+  UNITTEST::TestRequired message;
+  io::ArrayOutputStream raw_output(nullptr, 0);
+  io::CodedOutputStream output(&raw_output);
+  EXPECT_TRUE(message.SerializePartialToCodedStream(&output));
+}
+
+TEST(MESSAGE_TEST_NAME, FindInitializationErrors) {
+  UNITTEST::TestRequired message;
+  std::vector<std::string> errors;
+  message.FindInitializationErrors(&errors);
+  ASSERT_EQ(3, errors.size());
+  EXPECT_EQ("a", errors[0]);
+  EXPECT_EQ("b", errors[1]);
+  EXPECT_EQ("c", errors[2]);
+}
+
+TEST(MESSAGE_TEST_NAME, ReleaseMustUseResult) {
+  UNITTEST::TestAllTypes message;
+  auto* f = new UNITTEST::ForeignMessage();
+  f->set_c(1000);
+  message.set_allocated_optional_foreign_message(f);
+  auto* mf = message.mutable_optional_foreign_message();
+  EXPECT_EQ(mf, f);
+  std::unique_ptr<UNITTEST::ForeignMessage> rf(
+      message.release_optional_foreign_message());
+  EXPECT_NE(rf.get(), nullptr);
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailsOnInvalidMessageEnd) {
+  UNITTEST::TestAllTypes message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromArray("", 0));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromArray("\0", 1));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromArray("\200", 1));
+
+  // The byte is an endgroup tag, but we aren't parsing a group.
+  EXPECT_FALSE(message.ParseFromArray("\014", 1));
+}
+
+// Regression test for b/23630858
+TEST(MESSAGE_TEST_NAME, MessageIsStillValidAfterParseFails) {
+  UNITTEST::TestAllTypes message;
+
+  // 9 0xFFs for the "optional_uint64" field.
+  std::string invalid_data = "\x20\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
+
+  EXPECT_FALSE(message.ParseFromString(invalid_data));
+  message.Clear();
+  EXPECT_EQ(0, message.optional_uint64());
+
+  // invalid data for field "optional_string". Length prefix is 1 but no
+  // payload.
+  std::string invalid_string_data = "\x72\x01";
+  {
+    Arena arena;
+    UNITTEST::TestAllTypes* arena_message =
+        Arena::CreateMessage<UNITTEST::TestAllTypes>(&arena);
+    EXPECT_FALSE(arena_message->ParseFromString(invalid_string_data));
+    arena_message->Clear();
+    EXPECT_EQ("", arena_message->optional_string());
+  }
+}
+
+
+namespace {
+
+void ExpectMessageMerged(const UNITTEST::TestAllTypes& message) {
+  EXPECT_EQ(3, message.optional_int32());
+  EXPECT_EQ(2, message.optional_int64());
+  EXPECT_EQ("hello", message.optional_string());
+}
+
+void AssignParsingMergeMessages(UNITTEST::TestAllTypes* msg1,
+                                UNITTEST::TestAllTypes* msg2,
+                                UNITTEST::TestAllTypes* msg3) {
+  msg1->set_optional_int32(1);
+  msg2->set_optional_int64(2);
+  msg3->set_optional_int32(3);
+  msg3->set_optional_string("hello");
+}
+
+}  // namespace
+
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+TEST(MESSAGE_TEST_NAME, ParsingMerge) {
+  UNITTEST::TestParsingMerge::RepeatedFieldsGenerator generator;
+  UNITTEST::TestAllTypes* msg1;
+  UNITTEST::TestAllTypes* msg2;
+  UNITTEST::TestAllTypes* msg3;
+
+#define ASSIGN_REPEATED_FIELD(FIELD) \
+  msg1 = generator.add_##FIELD();    \
+  msg2 = generator.add_##FIELD();    \
+  msg3 = generator.add_##FIELD();    \
+  AssignParsingMergeMessages(msg1, msg2, msg3)
+
+  ASSIGN_REPEATED_FIELD(field1);
+  ASSIGN_REPEATED_FIELD(field2);
+  ASSIGN_REPEATED_FIELD(field3);
+  ASSIGN_REPEATED_FIELD(ext1);
+  ASSIGN_REPEATED_FIELD(ext2);
+
+#undef ASSIGN_REPEATED_FIELD
+#define ASSIGN_REPEATED_GROUP(FIELD)                \
+  msg1 = generator.add_##FIELD()->mutable_field1(); \
+  msg2 = generator.add_##FIELD()->mutable_field1(); \
+  msg3 = generator.add_##FIELD()->mutable_field1(); \
+  AssignParsingMergeMessages(msg1, msg2, msg3)
+
+  ASSIGN_REPEATED_GROUP(group1);
+  ASSIGN_REPEATED_GROUP(group2);
+
+#undef ASSIGN_REPEATED_GROUP
+
+  std::string buffer;
+  generator.SerializeToString(&buffer);
+  UNITTEST::TestParsingMerge parsing_merge;
+  parsing_merge.ParseFromString(buffer);
+
+  // Required and optional fields should be merged.
+  ExpectMessageMerged(parsing_merge.required_all_types());
+  ExpectMessageMerged(parsing_merge.optional_all_types());
+  ExpectMessageMerged(parsing_merge.optionalgroup().optional_group_all_types());
+  ExpectMessageMerged(
+      parsing_merge.GetExtension(UNITTEST::TestParsingMerge::optional_ext));
+
+  // Repeated fields should not be merged.
+  EXPECT_EQ(3, parsing_merge.repeated_all_types_size());
+  EXPECT_EQ(3, parsing_merge.repeatedgroup_size());
+  EXPECT_EQ(
+      3, parsing_merge.ExtensionSize(UNITTEST::TestParsingMerge::repeated_ext));
+}
+
+TEST(MESSAGE_TEST_NAME, MergeFrom) {
+  UNITTEST::TestAllTypes source, dest;
+
+  // Optional fields
+  source.set_optional_int32(1);  // only source
+  source.set_optional_int64(2);  // both source and dest
+  dest.set_optional_int64(3);
+  dest.set_optional_uint32(4);  // only dest
+
+  // Optional fields with defaults
+  source.set_default_int32(13);  // only source
+  source.set_default_int64(14);  // both source and dest
+  dest.set_default_int64(15);
+  dest.set_default_uint32(16);  // only dest
+
+  // Repeated fields
+  source.add_repeated_int32(5);  // only source
+  source.add_repeated_int32(6);
+  source.add_repeated_int64(7);  // both source and dest
+  source.add_repeated_int64(8);
+  dest.add_repeated_int64(9);
+  dest.add_repeated_int64(10);
+  dest.add_repeated_uint32(11);  // only dest
+  dest.add_repeated_uint32(12);
+
+  dest.MergeFrom(source);
+
+  // Optional fields: source overwrites dest if source is specified
+  EXPECT_EQ(1, dest.optional_int32());   // only source: use source
+  EXPECT_EQ(2, dest.optional_int64());   // source and dest: use source
+  EXPECT_EQ(4, dest.optional_uint32());  // only dest: use dest
+  EXPECT_EQ(0, dest.optional_uint64());  // neither: use default
+
+  // Optional fields with defaults
+  EXPECT_EQ(13, dest.default_int32());   // only source: use source
+  EXPECT_EQ(14, dest.default_int64());   // source and dest: use source
+  EXPECT_EQ(16, dest.default_uint32());  // only dest: use dest
+  EXPECT_EQ(44, dest.default_uint64());  // neither: use default
+
+  // Repeated fields: concatenate source onto the end of dest
+  ASSERT_EQ(2, dest.repeated_int32_size());
+  EXPECT_EQ(5, dest.repeated_int32(0));
+  EXPECT_EQ(6, dest.repeated_int32(1));
+  ASSERT_EQ(4, dest.repeated_int64_size());
+  EXPECT_EQ(9, dest.repeated_int64(0));
+  EXPECT_EQ(10, dest.repeated_int64(1));
+  EXPECT_EQ(7, dest.repeated_int64(2));
+  EXPECT_EQ(8, dest.repeated_int64(3));
+  ASSERT_EQ(2, dest.repeated_uint32_size());
+  EXPECT_EQ(11, dest.repeated_uint32(0));
+  EXPECT_EQ(12, dest.repeated_uint32(1));
+  ASSERT_EQ(0, dest.repeated_uint64_size());
+}
+
+TEST(MESSAGE_TEST_NAME, IsInitialized) {
+  UNITTEST::TestIsInitialized msg;
+  EXPECT_TRUE(msg.IsInitialized());
+  UNITTEST::TestIsInitialized::SubMessage* sub_message =
+      msg.mutable_sub_message();
+  EXPECT_TRUE(msg.IsInitialized());
+  UNITTEST::TestIsInitialized::SubMessage::SubGroup* sub_group =
+      sub_message->mutable_subgroup();
+  EXPECT_FALSE(msg.IsInitialized());
+  sub_group->set_i(1);
+  EXPECT_TRUE(msg.IsInitialized());
+}
+
+TEST(MESSAGE_TEST_NAME, IsInitializedSplitBytestream) {
+  UNITTEST::TestRequired ab, c;
+  ab.set_a(1);
+  ab.set_b(2);
+  c.set_c(3);
+
+  // The protobuf represented by the concatenated string has all required
+  // fields (a,b,c) set.
+  std::string bytes =
+      ab.SerializePartialAsString() + c.SerializePartialAsString();
+
+  UNITTEST::TestRequired concatenated;
+  EXPECT_TRUE(concatenated.ParsePartialFromString(bytes));
+  EXPECT_TRUE(concatenated.IsInitialized());
+
+  UNITTEST::TestRequiredForeign fab, fc;
+  fab.mutable_optional_message()->set_a(1);
+  fab.mutable_optional_message()->set_b(2);
+  fc.mutable_optional_message()->set_c(3);
+
+  bytes =
+      fab.SerializePartialAsString() + fc.SerializePartialAsString();
+
+  UNITTEST::TestRequiredForeign fconcatenated;
+  EXPECT_TRUE(fconcatenated.ParsePartialFromString(bytes));
+  EXPECT_TRUE(fconcatenated.IsInitialized());
+}
+
+TEST(MESSAGE_FACTORY_TEST_NAME, GeneratedFactoryLookup) {
+  EXPECT_EQ(MessageFactory::generated_factory()->GetPrototype(
+                UNITTEST::TestAllTypes::descriptor()),
+            &UNITTEST::TestAllTypes::default_instance());
+}
+
+TEST(MESSAGE_FACTORY_TEST_NAME, GeneratedFactoryUnknownType) {
+  // Construct a new descriptor.
+  DescriptorPool pool;
+  FileDescriptorProto file;
+  file.set_name("foo.proto");
+  file.add_message_type()->set_name("Foo");
+  const Descriptor* descriptor = pool.BuildFile(file)->message_type(0);
+
+  // Trying to construct it should return nullptr.
+  EXPECT_TRUE(MessageFactory::generated_factory()->GetPrototype(descriptor) ==
+              nullptr);
+}
+
+TEST(MESSAGE_TEST_NAME, MOMIParserEdgeCases) {
+  {
+    UNITTEST::TestAllTypes msg;
+    // Parser ends in last 16 bytes of buffer due to a 0.
+    std::string data;
+    // 12 bytes of data
+    for (int i = 0; i < 4; i++) data += "\370\1\1";
+    // 13 byte is terminator
+    data += '\0';  // Terminator
+    // followed by the rest of the stream
+    // space is ascii 32 so no end group
+    data += std::string(30, ' ');
+    io::ArrayInputStream zcis(data.data(), data.size(), 17);
+    io::CodedInputStream cis(&zcis);
+    EXPECT_TRUE(msg.MergePartialFromCodedStream(&cis));
+    EXPECT_EQ(cis.CurrentPosition(), 3 * 4 + 1);
+  }
+  {
+    // Parser ends in last 16 bytes of buffer due to a end-group.
+    // Must use a message that is a group. Otherwise ending on a group end is
+    // a failure.
+    UNITTEST::TestAllTypes::OptionalGroup msg;
+    std::string data;
+    for (int i = 0; i < 3; i++) data += "\370\1\1";
+    data += '\14';  // Octal end-group tag 12 (1 * 8 + 4(
+    data += std::string(30, ' ');
+    io::ArrayInputStream zcis(data.data(), data.size(), 17);
+    io::CodedInputStream cis(&zcis);
+    EXPECT_TRUE(msg.MergePartialFromCodedStream(&cis));
+    EXPECT_EQ(cis.CurrentPosition(), 3 * 3 + 1);
+    EXPECT_TRUE(cis.LastTagWas(12));
+  }
+  {
+    // Parser ends in last 16 bytes of buffer due to a end-group. But is inside
+    // a length delimited field.
+    // a failure.
+    UNITTEST::TestAllTypes::OptionalGroup msg;
+    std::string data;
+    data += "\22\3foo";
+    data += '\14';  // Octal end-group tag 12 (1 * 8 + 4(
+    data += std::string(30, ' ');
+    io::ArrayInputStream zcis(data.data(), data.size(), 17);
+    io::CodedInputStream cis(&zcis);
+    EXPECT_TRUE(msg.MergePartialFromCodedStream(&cis));
+    EXPECT_EQ(cis.CurrentPosition(), 6);
+    EXPECT_TRUE(cis.LastTagWas(12));
+  }
+  {
+    // Parser fails when ending on 0 if from ZeroCopyInputStream
+    UNITTEST::TestAllTypes msg;
+    std::string data;
+    // 12 bytes of data
+    for (int i = 0; i < 4; i++) data += "\370\1\1";
+    // 13 byte is terminator
+    data += '\0';  // Terminator
+    data += std::string(30, ' ');
+    io::ArrayInputStream zcis(data.data(), data.size(), 17);
+    EXPECT_FALSE(msg.ParsePartialFromZeroCopyStream(&zcis));
+  }
+}
+
+
+TEST(MESSAGE_TEST_NAME, CheckSerializationWhenInterleavedExtensions) {
+  UNITTEST::TestExtensionRangeSerialize in_message;
+
+  in_message.set_foo_one(1);
+  in_message.set_foo_two(2);
+  in_message.set_foo_three(3);
+  in_message.set_foo_four(4);
+
+  in_message.SetExtension(UNITTEST::TestExtensionRangeSerialize::bar_one, 1);
+  in_message.SetExtension(UNITTEST::TestExtensionRangeSerialize::bar_two, 2);
+  in_message.SetExtension(UNITTEST::TestExtensionRangeSerialize::bar_three, 3);
+  in_message.SetExtension(UNITTEST::TestExtensionRangeSerialize::bar_four, 4);
+  in_message.SetExtension(UNITTEST::TestExtensionRangeSerialize::bar_five, 5);
+
+  std::string buffer;
+  in_message.SerializeToString(&buffer);
+
+  UNITTEST::TestExtensionRangeSerialize out_message;
+  out_message.ParseFromString(buffer);
+
+  EXPECT_EQ(1, out_message.foo_one());
+  EXPECT_EQ(2, out_message.foo_two());
+  EXPECT_EQ(3, out_message.foo_three());
+  EXPECT_EQ(4, out_message.foo_four());
+
+  EXPECT_EQ(1, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_one));
+  EXPECT_EQ(2, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_two));
+  EXPECT_EQ(3, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_three));
+  EXPECT_EQ(4, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_four));
+  EXPECT_EQ(5, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_five));
+}
+
+TEST(MESSAGE_TEST_NAME, PreservesFloatingPointNegative0) {
+  UNITTEST::TestAllTypes in_message;
+  in_message.set_optional_float(-0.0f);
+  in_message.set_optional_double(-0.0);
+  std::string serialized;
+  EXPECT_TRUE(in_message.SerializeToString(&serialized));
+  UNITTEST::TestAllTypes out_message;
+  EXPECT_TRUE(out_message.ParseFromString(serialized));
+  EXPECT_EQ(in_message.optional_float(), out_message.optional_float());
+  EXPECT_EQ(std::signbit(in_message.optional_float()),
+            std::signbit(out_message.optional_float()));
+  EXPECT_EQ(in_message.optional_double(), out_message.optional_double());
+  EXPECT_EQ(std::signbit(in_message.optional_double()),
+            std::signbit(out_message.optional_double()));
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h
new file mode 100644
index 0000000..4e89648
--- /dev/null
+++ b/src/google/protobuf/metadata.h
@@ -0,0 +1,36 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_METADATA_H__
+#define GOOGLE_PROTOBUF_METADATA_H__
+
+// TODO(b/151117630): Remove this file and all instances where it gets imported.
+
+#endif  // GOOGLE_PROTOBUF_METADATA_H__
diff --git a/src/google/protobuf/metadata_lite.h b/src/google/protobuf/metadata_lite.h
new file mode 100644
index 0000000..0c31517
--- /dev/null
+++ b/src/google/protobuf/metadata_lite.h
@@ -0,0 +1,316 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_METADATA_LITE_H__
+#define GOOGLE_PROTOBUF_METADATA_LITE_H__
+
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This is the representation for messages that support arena allocation. It
+// uses a tagged pointer to either store the owning Arena pointer, if there are
+// no unknown fields, or a pointer to a block of memory with both the owning
+// Arena pointer and the UnknownFieldSet, if there are unknown fields. Besides,
+// it also uses the tag to distinguish whether the owning Arena pointer is also
+// used by sub-structure allocation. This optimization allows for
+// "zero-overhead" storage of the Arena pointer, relative to the above baseline
+// implementation.
+//
+// The tagged pointer uses the least two significant bits to disambiguate cases.
+// It uses bit 0 == 0 to indicate an arena pointer and bit 0 == 1 to indicate a
+// UFS+Arena-container pointer. Besides it uses bit 1 == 0 to indicate arena
+// allocation and bit 1 == 1 to indicate heap allocation.
+class PROTOBUF_EXPORT InternalMetadata {
+ public:
+  constexpr InternalMetadata() : ptr_(0) {}
+  explicit InternalMetadata(Arena* arena, bool is_message_owned = false) {
+    SetArena(arena, is_message_owned);
+  }
+
+  void SetArena(Arena* arena, bool is_message_owned) {
+    ptr_ = is_message_owned
+               ? reinterpret_cast<intptr_t>(arena) | kMessageOwnedArenaTagMask
+               : reinterpret_cast<intptr_t>(arena);
+    GOOGLE_DCHECK(!is_message_owned || arena != nullptr);
+  }
+
+  // To keep the ABI identical between debug and non-debug builds,
+  // the destructor is always defined here even though it may delegate
+  // to a non-inline private method.
+  // (see https://github.com/protocolbuffers/protobuf/issues/9947)
+  ~InternalMetadata() {
+#if defined(NDEBUG) || defined(_MSC_VER)
+    if (HasMessageOwnedArenaTag()) {
+      delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
+    }
+#else
+    CheckedDestruct();
+#endif
+  }
+
+  template <typename T>
+  void Delete() {
+    // Note that Delete<> should be called not more than once.
+    if (have_unknown_fields()) {
+      DeleteOutOfLineHelper<T>();
+    }
+  }
+
+  // DeleteReturnArena will delete the unknown fields only if they weren't
+  // allocated on an arena.  Then it updates the flags so that if you call
+  // have_unknown_fields(), it will return false.  Finally, it returns the
+  // current value of arena().  It is designed to be used as part of a
+  // Message class's destructor call, so that when control eventually gets
+  // to ~InternalMetadata(), we don't need to check for have_unknown_fields()
+  // again.
+  template <typename T>
+  Arena* DeleteReturnArena() {
+    if (have_unknown_fields()) {
+      return DeleteOutOfLineHelper<T>();
+    } else {
+      return PtrValue<Arena>();
+    }
+  }
+
+  PROTOBUF_NDEBUG_INLINE Arena* owning_arena() const {
+    return HasMessageOwnedArenaTag() ? nullptr : arena();
+  }
+
+  PROTOBUF_NDEBUG_INLINE Arena* user_arena() const {
+    Arena* a = arena();
+    return a && !a->IsMessageOwned() ? a : nullptr;
+  }
+
+  PROTOBUF_NDEBUG_INLINE Arena* arena() const {
+    if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
+      return PtrValue<ContainerBase>()->arena;
+    } else {
+      return PtrValue<Arena>();
+    }
+  }
+
+  PROTOBUF_NDEBUG_INLINE bool have_unknown_fields() const {
+    return HasUnknownFieldsTag();
+  }
+
+  PROTOBUF_NDEBUG_INLINE void* raw_arena_ptr() const {
+    return reinterpret_cast<void*>(ptr_);
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE const T& unknown_fields(
+      const T& (*default_instance)()) const {
+    if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
+      return PtrValue<Container<T>>()->unknown_fields;
+    } else {
+      return default_instance();
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE T* mutable_unknown_fields() {
+    if (PROTOBUF_PREDICT_TRUE(have_unknown_fields())) {
+      return &PtrValue<Container<T>>()->unknown_fields;
+    } else {
+      return mutable_unknown_fields_slow<T>();
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE void Swap(InternalMetadata* other) {
+    // Semantics here are that we swap only the unknown fields, not the arena
+    // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
+    // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
+    // different states (direct arena pointer vs. container with UFS) so we
+    // cannot simply swap ptr_ and then restore the arena pointers. We reuse
+    // UFS's swap implementation instead.
+    if (have_unknown_fields() || other->have_unknown_fields()) {
+      DoSwap<T>(other->mutable_unknown_fields<T>());
+    }
+  }
+
+  PROTOBUF_NDEBUG_INLINE void InternalSwap(InternalMetadata* other) {
+    std::swap(ptr_, other->ptr_);
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE void MergeFrom(const InternalMetadata& other) {
+    if (other.have_unknown_fields()) {
+      DoMergeFrom<T>(other.unknown_fields<T>(nullptr));
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE void Clear() {
+    if (have_unknown_fields()) {
+      DoClear<T>();
+    }
+  }
+
+ private:
+  intptr_t ptr_;
+
+  // Tagged pointer implementation.
+  static constexpr intptr_t kUnknownFieldsTagMask = 1;
+  static constexpr intptr_t kMessageOwnedArenaTagMask = 2;
+  static constexpr intptr_t kPtrTagMask =
+      kUnknownFieldsTagMask | kMessageOwnedArenaTagMask;
+  static constexpr intptr_t kPtrValueMask = ~kPtrTagMask;
+
+  // Accessors for pointer tag and pointer value.
+  PROTOBUF_ALWAYS_INLINE bool HasUnknownFieldsTag() const {
+    return ptr_ & kUnknownFieldsTagMask;
+  }
+  PROTOBUF_ALWAYS_INLINE bool HasMessageOwnedArenaTag() const {
+    return ptr_ & kMessageOwnedArenaTagMask;
+  }
+
+  template <typename U>
+  U* PtrValue() const {
+    return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
+  }
+
+  // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
+  struct ContainerBase {
+    Arena* arena;
+  };
+
+  template <typename T>
+  struct Container : public ContainerBase {
+    T unknown_fields;
+  };
+
+  template <typename T>
+  PROTOBUF_NOINLINE Arena* DeleteOutOfLineHelper() {
+    if (auto* a = arena()) {
+      // Subtle: we want to preserve the message-owned arena flag, while at the
+      // same time replacing the pointer to Container<T> with a pointer to the
+      // arena.
+      intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
+      ptr_ = reinterpret_cast<intptr_t>(a) | message_owned_arena_tag;
+      return a;
+    } else {
+      delete PtrValue<Container<T>>();
+      ptr_ = 0;
+      return nullptr;
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() {
+    Arena* my_arena = arena();
+    Container<T>* container = Arena::Create<Container<T>>(my_arena);
+    intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
+    // Two-step assignment works around a bug in clang's static analyzer:
+    // https://bugs.llvm.org/show_bug.cgi?id=34198.
+    ptr_ = reinterpret_cast<intptr_t>(container);
+    ptr_ |= kUnknownFieldsTagMask | message_owned_arena_tag;
+    container->arena = my_arena;
+    return &(container->unknown_fields);
+  }
+
+  // Templated functions.
+
+  template <typename T>
+  PROTOBUF_NOINLINE void DoClear() {
+    mutable_unknown_fields<T>()->Clear();
+  }
+
+  template <typename T>
+  PROTOBUF_NOINLINE void DoMergeFrom(const T& other) {
+    mutable_unknown_fields<T>()->MergeFrom(other);
+  }
+
+  template <typename T>
+  PROTOBUF_NOINLINE void DoSwap(T* other) {
+    mutable_unknown_fields<T>()->Swap(other);
+  }
+
+  // Private helper with debug checks for ~InternalMetadata()
+  void CheckedDestruct();
+};
+
+// String Template specializations.
+
+template <>
+PROTOBUF_EXPORT void InternalMetadata::DoClear<std::string>();
+template <>
+PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom<std::string>(
+    const std::string& other);
+template <>
+PROTOBUF_EXPORT void InternalMetadata::DoSwap<std::string>(std::string* other);
+
+// This helper RAII class is needed to efficiently parse unknown fields. We
+// should only call mutable_unknown_fields if there are actual unknown fields.
+// The obvious thing to just use a stack string and swap it at the end of
+// the parse won't work, because the destructor of StringOutputStream needs to
+// be called before we can modify the string (it check-fails). Using
+// LiteUnknownFieldSetter setter(&_internal_metadata_);
+// StringOutputStream stream(setter.buffer());
+// guarantees that the string is only swapped after stream is destroyed.
+class PROTOBUF_EXPORT LiteUnknownFieldSetter {
+ public:
+  explicit LiteUnknownFieldSetter(InternalMetadata* metadata)
+      : metadata_(metadata) {
+    if (metadata->have_unknown_fields()) {
+      buffer_.swap(*metadata->mutable_unknown_fields<std::string>());
+    }
+  }
+  ~LiteUnknownFieldSetter() {
+    if (!buffer_.empty())
+      metadata_->mutable_unknown_fields<std::string>()->swap(buffer_);
+  }
+  std::string* buffer() { return &buffer_; }
+
+ private:
+  InternalMetadata* metadata_;
+  std::string buffer_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_METADATA_LITE_H__
diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc
new file mode 100644
index 0000000..2582cfe
--- /dev/null
+++ b/src/google/protobuf/no_field_presence_test.cc
@@ -0,0 +1,575 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_no_field_presence.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+// Helper: checks that all fields have default (zero/empty) values.
+void CheckDefaultValues(
+    const proto2_nofieldpresence_unittest::TestAllTypes& m) {
+  EXPECT_EQ(0, m.optional_int32());
+  EXPECT_EQ(0, m.optional_int64());
+  EXPECT_EQ(0, m.optional_uint32());
+  EXPECT_EQ(0, m.optional_uint64());
+  EXPECT_EQ(0, m.optional_sint32());
+  EXPECT_EQ(0, m.optional_sint64());
+  EXPECT_EQ(0, m.optional_fixed32());
+  EXPECT_EQ(0, m.optional_fixed64());
+  EXPECT_EQ(0, m.optional_sfixed32());
+  EXPECT_EQ(0, m.optional_sfixed64());
+  EXPECT_EQ(0, m.optional_float());
+  EXPECT_EQ(0, m.optional_double());
+  EXPECT_EQ(false, m.optional_bool());
+  EXPECT_EQ(0, m.optional_string().size());
+  EXPECT_EQ(0, m.optional_bytes().size());
+
+  EXPECT_EQ(false, m.has_optional_nested_message());
+  // accessor for message fields returns default instance when not present
+  EXPECT_EQ(0, m.optional_nested_message().bb());
+  EXPECT_EQ(false, m.has_optional_proto2_message());
+  // Embedded proto2 messages still have proto2 semantics, e.g. non-zero default
+  // values. Here the submessage is not present but its accessor returns the
+  // default instance.
+  EXPECT_EQ(41, m.optional_proto2_message().default_int32());
+  EXPECT_EQ(false, m.has_optional_foreign_message());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::FOO,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_FOO,
+            m.optional_foreign_enum());
+
+
+  EXPECT_EQ(0, m.repeated_int32_size());
+  EXPECT_EQ(0, m.repeated_int64_size());
+  EXPECT_EQ(0, m.repeated_uint32_size());
+  EXPECT_EQ(0, m.repeated_uint64_size());
+  EXPECT_EQ(0, m.repeated_sint32_size());
+  EXPECT_EQ(0, m.repeated_sint64_size());
+  EXPECT_EQ(0, m.repeated_fixed32_size());
+  EXPECT_EQ(0, m.repeated_fixed64_size());
+  EXPECT_EQ(0, m.repeated_sfixed32_size());
+  EXPECT_EQ(0, m.repeated_sfixed64_size());
+  EXPECT_EQ(0, m.repeated_float_size());
+  EXPECT_EQ(0, m.repeated_double_size());
+  EXPECT_EQ(0, m.repeated_bool_size());
+  EXPECT_EQ(0, m.repeated_string_size());
+  EXPECT_EQ(0, m.repeated_bytes_size());
+  EXPECT_EQ(0, m.repeated_nested_message_size());
+  EXPECT_EQ(0, m.repeated_foreign_message_size());
+  EXPECT_EQ(0, m.repeated_proto2_message_size());
+  EXPECT_EQ(0, m.repeated_nested_enum_size());
+  EXPECT_EQ(0, m.repeated_foreign_enum_size());
+  EXPECT_EQ(0, m.repeated_lazy_message_size());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::ONEOF_FIELD_NOT_SET,
+            m.oneof_field_case());
+}
+
+void FillValues(proto2_nofieldpresence_unittest::TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_int64(101);
+  m->set_optional_uint32(102);
+  m->set_optional_uint64(103);
+  m->set_optional_sint32(104);
+  m->set_optional_sint64(105);
+  m->set_optional_fixed32(106);
+  m->set_optional_fixed64(107);
+  m->set_optional_sfixed32(108);
+  m->set_optional_sfixed64(109);
+  m->set_optional_float(110.0);
+  m->set_optional_double(111.0);
+  m->set_optional_bool(true);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->mutable_optional_proto2_message()->set_optional_int32(44);
+  m->set_optional_nested_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes::BAZ);
+  m->set_optional_foreign_enum(proto2_nofieldpresence_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->add_repeated_int32(100);
+  m->add_repeated_int64(101);
+  m->add_repeated_uint32(102);
+  m->add_repeated_uint64(103);
+  m->add_repeated_sint32(104);
+  m->add_repeated_sint64(105);
+  m->add_repeated_fixed32(106);
+  m->add_repeated_fixed64(107);
+  m->add_repeated_sfixed32(108);
+  m->add_repeated_sfixed64(109);
+  m->add_repeated_float(110.0);
+  m->add_repeated_double(111.0);
+  m->add_repeated_bool(true);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_proto2_message()->set_optional_int32(48);
+  m->add_repeated_nested_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes::BAZ);
+  m->add_repeated_foreign_enum(proto2_nofieldpresence_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void CheckNonDefaultValues(
+    const proto2_nofieldpresence_unittest::TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ(101, m.optional_int64());
+  EXPECT_EQ(102, m.optional_uint32());
+  EXPECT_EQ(103, m.optional_uint64());
+  EXPECT_EQ(104, m.optional_sint32());
+  EXPECT_EQ(105, m.optional_sint64());
+  EXPECT_EQ(106, m.optional_fixed32());
+  EXPECT_EQ(107, m.optional_fixed64());
+  EXPECT_EQ(108, m.optional_sfixed32());
+  EXPECT_EQ(109, m.optional_sfixed64());
+  EXPECT_EQ(110.0, m.optional_float());
+  EXPECT_EQ(111.0, m.optional_double());
+  EXPECT_EQ(true, m.optional_bool());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(true, m.has_optional_proto2_message());
+  EXPECT_EQ(44, m.optional_proto2_message().optional_int32());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::BAZ,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_BAZ,
+            m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_int64_size());
+  EXPECT_EQ(101, m.repeated_int64(0));
+  EXPECT_EQ(1, m.repeated_uint32_size());
+  EXPECT_EQ(102, m.repeated_uint32(0));
+  EXPECT_EQ(1, m.repeated_uint64_size());
+  EXPECT_EQ(103, m.repeated_uint64(0));
+  EXPECT_EQ(1, m.repeated_sint32_size());
+  EXPECT_EQ(104, m.repeated_sint32(0));
+  EXPECT_EQ(1, m.repeated_sint64_size());
+  EXPECT_EQ(105, m.repeated_sint64(0));
+  EXPECT_EQ(1, m.repeated_fixed32_size());
+  EXPECT_EQ(106, m.repeated_fixed32(0));
+  EXPECT_EQ(1, m.repeated_fixed64_size());
+  EXPECT_EQ(107, m.repeated_fixed64(0));
+  EXPECT_EQ(1, m.repeated_sfixed32_size());
+  EXPECT_EQ(108, m.repeated_sfixed32(0));
+  EXPECT_EQ(1, m.repeated_sfixed64_size());
+  EXPECT_EQ(109, m.repeated_sfixed64(0));
+  EXPECT_EQ(1, m.repeated_float_size());
+  EXPECT_EQ(110.0, m.repeated_float(0));
+  EXPECT_EQ(1, m.repeated_double_size());
+  EXPECT_EQ(111.0, m.repeated_double(0));
+  EXPECT_EQ(1, m.repeated_bool_size());
+  EXPECT_EQ(true, m.repeated_bool(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_proto2_message_size());
+  EXPECT_EQ(48, m.repeated_proto2_message(0).optional_int32());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_BAZ,
+            m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+TEST(NoFieldPresenceTest, BasicMessageTest) {
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  // Check default values, fill all fields, check values. We just want to
+  // exercise the basic getters/setter paths here to make sure no
+  // field-presence-related changes broke these.
+  CheckDefaultValues(message);
+  FillValues(&message);
+  CheckNonDefaultValues(message);
+
+  // Clear() should be equivalent to getting a freshly-constructed message.
+  message.Clear();
+  CheckDefaultValues(message);
+}
+
+TEST(NoFieldPresenceTest, MessageFieldPresenceTest) {
+  // check that presence still works properly for message fields.
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  EXPECT_EQ(false, message.has_optional_nested_message());
+  // Getter should fetch default instance, and not cause the field to become
+  // present.
+  EXPECT_EQ(0, message.optional_nested_message().bb());
+  EXPECT_EQ(false, message.has_optional_nested_message());
+  message.mutable_optional_nested_message()->set_bb(42);
+  EXPECT_EQ(true, message.has_optional_nested_message());
+  message.clear_optional_nested_message();
+  EXPECT_EQ(false, message.has_optional_nested_message());
+
+  // Likewise for a lazy message field.
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+  // Getter should fetch default instance, and not cause the field to become
+  // present.
+  EXPECT_EQ(0, message.optional_lazy_message().bb());
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+  message.mutable_optional_lazy_message()->set_bb(42);
+  EXPECT_EQ(true, message.has_optional_lazy_message());
+  message.clear_optional_lazy_message();
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+
+  // Test field presence of a message field on the default instance.
+  EXPECT_EQ(false,
+            proto2_nofieldpresence_unittest::TestAllTypes::default_instance()
+                .has_optional_nested_message());
+}
+
+TEST(NoFieldPresenceTest, ReflectionHasFieldTest) {
+  // check that HasField reports true on all scalar fields. Check that it
+  // behaves properly for message fields.
+
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  const Reflection* r = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  // Check initial state: scalars not present (due to need to be consistent with
+  // MergeFrom()), message fields not present, oneofs not present.
+  for (int i = 0; i < desc->field_count(); i++) {
+    const FieldDescriptor* field = desc->field(i);
+    if (field->is_repeated()) continue;
+    EXPECT_EQ(false, r->HasField(message, field));
+  }
+
+  // Test field presence of a message field on the default instance.
+  const FieldDescriptor* msg_field =
+      desc->FindFieldByName("optional_nested_message");
+  EXPECT_EQ(
+      false,
+      r->HasField(
+          proto2_nofieldpresence_unittest::TestAllTypes::default_instance(),
+          msg_field));
+
+  // Fill all fields, expect everything to report true (check oneofs below).
+  FillValues(&message);
+  for (int i = 0; i < desc->field_count(); i++) {
+    const FieldDescriptor* field = desc->field(i);
+    if (field->is_repeated() || field->containing_oneof()) {
+      continue;
+    }
+    if (field->options().ctype() != FieldOptions::STRING) {
+      continue;
+    }
+    EXPECT_EQ(true, r->HasField(message, field));
+  }
+
+  message.Clear();
+
+  // Check zero/empty-means-not-present semantics.
+  const FieldDescriptor* field_int32 = desc->FindFieldByName("optional_int32");
+  const FieldDescriptor* field_double =
+      desc->FindFieldByName("optional_double");
+  const FieldDescriptor* field_string =
+      desc->FindFieldByName("optional_string");
+
+  EXPECT_EQ(false, r->HasField(message, field_int32));
+  EXPECT_EQ(false, r->HasField(message, field_double));
+  EXPECT_EQ(false, r->HasField(message, field_string));
+
+  message.set_optional_int32(42);
+  EXPECT_EQ(true, r->HasField(message, field_int32));
+  message.set_optional_int32(0);
+  EXPECT_EQ(false, r->HasField(message, field_int32));
+
+  message.set_optional_double(42.0);
+  EXPECT_EQ(true, r->HasField(message, field_double));
+  message.set_optional_double(0.0);
+  EXPECT_EQ(false, r->HasField(message, field_double));
+
+  message.set_optional_string("test");
+  EXPECT_EQ(true, r->HasField(message, field_string));
+  message.set_optional_string("");
+  EXPECT_EQ(false, r->HasField(message, field_string));
+}
+
+TEST(NoFieldPresenceTest, ReflectionClearFieldTest) {
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+
+  const Reflection* r = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  const FieldDescriptor* field_int32 = desc->FindFieldByName("optional_int32");
+  const FieldDescriptor* field_double =
+      desc->FindFieldByName("optional_double");
+  const FieldDescriptor* field_string =
+      desc->FindFieldByName("optional_string");
+  const FieldDescriptor* field_message =
+      desc->FindFieldByName("optional_nested_message");
+  const FieldDescriptor* field_lazy =
+      desc->FindFieldByName("optional_lazy_message");
+
+  message.set_optional_int32(42);
+  r->ClearField(&message, field_int32);
+  EXPECT_EQ(0, message.optional_int32());
+
+  message.set_optional_double(42.0);
+  r->ClearField(&message, field_double);
+  EXPECT_EQ(0.0, message.optional_double());
+
+  message.set_optional_string("test");
+  r->ClearField(&message, field_string);
+  EXPECT_EQ("", message.optional_string());
+
+  message.mutable_optional_nested_message()->set_bb(1234);
+  r->ClearField(&message, field_message);
+  EXPECT_FALSE(message.has_optional_nested_message());
+  EXPECT_EQ(0, message.optional_nested_message().bb());
+
+  message.mutable_optional_lazy_message()->set_bb(42);
+  r->ClearField(&message, field_lazy);
+  EXPECT_FALSE(message.has_optional_lazy_message());
+  EXPECT_EQ(0, message.optional_lazy_message().bb());
+}
+
+TEST(NoFieldPresenceTest, HasFieldOneofsTest) {
+  // check that HasField behaves properly for oneofs.
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+
+  const Reflection* r = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+  const FieldDescriptor* desc_oneof_uint32 =
+      desc->FindFieldByName("oneof_uint32");
+  const FieldDescriptor* desc_oneof_nested_message =
+      desc->FindFieldByName("oneof_nested_message");
+  const FieldDescriptor* desc_oneof_string =
+      desc->FindFieldByName("oneof_string");
+  GOOGLE_CHECK(desc_oneof_uint32 != nullptr);
+  GOOGLE_CHECK(desc_oneof_nested_message != nullptr);
+  GOOGLE_CHECK(desc_oneof_string != nullptr);
+
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_string));
+
+  message.set_oneof_string("test");
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(true, r->HasField(message, desc_oneof_string));
+  message.mutable_oneof_nested_message()->set_bb(42);
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(true, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_string));
+
+  message.Clear();
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_string));
+}
+
+TEST(NoFieldPresenceTest, DontSerializeDefaultValuesTest) {
+  // check that serialized data contains only non-zero numeric fields/non-empty
+  // string/byte fields.
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  std::string output;
+
+  // All default values -> no output.
+  message.SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+
+  // Zero values -> still no output.
+  message.set_optional_int32(0);
+  message.set_optional_int64(0);
+  message.set_optional_uint32(0);
+  message.set_optional_uint64(0);
+  message.set_optional_sint32(0);
+  message.set_optional_sint64(0);
+  message.set_optional_fixed32(0);
+  message.set_optional_fixed64(0);
+  message.set_optional_sfixed32(0);
+  message.set_optional_sfixed64(0);
+  message.set_optional_float(0);
+  message.set_optional_double(0);
+  message.set_optional_bool(0);
+  message.set_optional_string("");
+  message.set_optional_bytes("");
+  message.set_optional_nested_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes::FOO);  // first enum entry
+  message.set_optional_foreign_enum(
+      proto2_nofieldpresence_unittest::FOREIGN_FOO);  // first enum entry
+
+  message.SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+
+  message.set_optional_int32(1);
+  message.SerializeToString(&output);
+  EXPECT_EQ(2, output.size());
+  EXPECT_EQ("\x08\x01", output);
+
+  message.set_optional_int32(0);
+  message.SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+}
+
+TEST(NoFieldPresenceTest, MergeFromIfNonzeroTest) {
+  // check that MergeFrom copies if nonzero/nondefault only.
+  proto2_nofieldpresence_unittest::TestAllTypes source;
+  proto2_nofieldpresence_unittest::TestAllTypes dest;
+
+  dest.set_optional_int32(42);
+  dest.set_optional_string("test");
+  source.set_optional_int32(0);
+  source.set_optional_string("");
+  // MergeFrom() copies only if present in serialization, i.e., non-zero.
+  dest.MergeFrom(source);
+  EXPECT_EQ(42, dest.optional_int32());
+  EXPECT_EQ("test", dest.optional_string());
+
+  source.set_optional_int32(84);
+  source.set_optional_string("test2");
+  dest.MergeFrom(source);
+  EXPECT_EQ(84, dest.optional_int32());
+  EXPECT_EQ("test2", dest.optional_string());
+}
+
+TEST(NoFieldPresenceTest, IsInitializedTest) {
+  // Check that IsInitialized works properly.
+  proto2_nofieldpresence_unittest::TestProto2Required message;
+
+  EXPECT_EQ(true, message.IsInitialized());
+  message.mutable_proto2()->set_a(1);
+  EXPECT_EQ(false, message.IsInitialized());
+  message.mutable_proto2()->set_b(1);
+  EXPECT_EQ(false, message.IsInitialized());
+  message.mutable_proto2()->set_c(1);
+  EXPECT_EQ(true, message.IsInitialized());
+}
+
+TEST(NoFieldPresenceTest, LazyMessageFieldHasBit) {
+  // Check that has-bit interaction with lazy message works (has-bit before and
+  // after lazy decode).
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  const Reflection* r = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+  const FieldDescriptor* field = desc->FindFieldByName("optional_lazy_message");
+  GOOGLE_CHECK(field != nullptr);
+
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+  EXPECT_EQ(false, r->HasField(message, field));
+
+  message.mutable_optional_lazy_message()->set_bb(42);
+  EXPECT_EQ(true, message.has_optional_lazy_message());
+  EXPECT_EQ(true, r->HasField(message, field));
+
+  // Serialize and parse with a new message object so that lazy field on new
+  // object is in unparsed state.
+  std::string output;
+  message.SerializeToString(&output);
+  proto2_nofieldpresence_unittest::TestAllTypes message2;
+  message2.ParseFromString(output);
+
+  EXPECT_EQ(true, message2.has_optional_lazy_message());
+  EXPECT_EQ(true, r->HasField(message2, field));
+
+  // Access field to force lazy parse.
+  EXPECT_EQ(42, message.optional_lazy_message().bb());
+  EXPECT_EQ(true, message2.has_optional_lazy_message());
+  EXPECT_EQ(true, r->HasField(message2, field));
+}
+
+TEST(NoFieldPresenceTest, OneofPresence) {
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  // oneof fields still have field presence -- ensure that this goes on the wire
+  // even though its value is the empty string.
+  message.set_oneof_string("");
+  std::string serialized;
+  message.SerializeToString(&serialized);
+  // Tag: 113 --> tag is (113 << 3) | 2 (length delimited) = 906
+  // varint: 0x8a 0x07
+  // Length: 0x00
+  EXPECT_EQ(3, serialized.size());
+  EXPECT_EQ(static_cast<char>(0x8a), serialized.at(0));
+  EXPECT_EQ(static_cast<char>(0x07), serialized.at(1));
+  EXPECT_EQ(static_cast<char>(0x00), serialized.at(2));
+
+  message.Clear();
+  EXPECT_TRUE(message.ParseFromString(serialized));
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofString,
+            message.oneof_field_case());
+
+  // Also test int32 and enum fields.
+  message.Clear();
+  message.set_oneof_uint32(0);  // would not go on wire if ordinary field.
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(3, serialized.size());
+  EXPECT_TRUE(message.ParseFromString(serialized));
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofUint32,
+            message.oneof_field_case());
+
+  message.Clear();
+  message.set_oneof_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes::FOO);  // default
+                                                            // value.
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(3, serialized.size());
+  EXPECT_TRUE(message.ParseFromString(serialized));
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofEnum,
+            message.oneof_field_case());
+
+  message.Clear();
+  message.set_oneof_string("test");
+  message.clear_oneof_string();
+  EXPECT_EQ(0, message.ByteSizeLong());
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/package_info.h b/src/google/protobuf/package_info.h
new file mode 100644
index 0000000..2b61679
--- /dev/null
+++ b/src/google/protobuf/package_info.h
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file exists solely to document the google::protobuf namespace.
+// It is not compiled into anything, but it may be read by an automated
+// documentation generator.
+
+// Core components of the Protocol Buffers runtime library.
+//
+// The files in this package represent the core of the Protocol Buffer
+// system.  All of them are part of the libprotobuf library.
+//
+// A note on thread-safety:
+//
+// Thread-safety in the Protocol Buffer library follows a simple rule:
+// unless explicitly noted otherwise, it is always safe to use an object
+// from multiple threads simultaneously as long as the object is declared
+// const in all threads (or, it is only used in ways that would be allowed
+// if it were declared const).  However, if an object is accessed in one
+// thread in a way that would not be allowed if it were const, then it is
+// not safe to access that object in any other thread simultaneously.
+//
+// Put simply, read-only access to an object can happen in multiple threads
+// simultaneously, but write access can only happen in a single thread at
+// a time.
+//
+// The implementation does contain some "const" methods which actually modify
+// the object behind the scenes -- e.g., to cache results -- but in these cases
+// mutex locking is used to make the access thread-safe.
+namespace google {
+namespace protobuf {
+// TODO(gerbens) remove this comment, we need it to prevent clang-format
+// from combining the brackets. Which would mess with extract script
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
new file mode 100644
index 0000000..59852fd
--- /dev/null
+++ b/src/google/protobuf/parse_context.cc
@@ -0,0 +1,548 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/parse_context.h>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/endian.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+// Only call if at start of tag.
+bool ParseEndsInSlopRegion(const char* begin, int overrun, int depth) {
+  constexpr int kSlopBytes = EpsCopyInputStream::kSlopBytes;
+  GOOGLE_DCHECK_GE(overrun, 0);
+  GOOGLE_DCHECK_LE(overrun, kSlopBytes);
+  auto ptr = begin + overrun;
+  auto end = begin + kSlopBytes;
+  while (ptr < end) {
+    uint32_t tag;
+    ptr = ReadTag(ptr, &tag);
+    if (ptr == nullptr || ptr > end) return false;
+    // ending on 0 tag is allowed and is the major reason for the necessity of
+    // this function.
+    if (tag == 0) return true;
+    switch (tag & 7) {
+      case 0: {  // Varint
+        uint64_t val;
+        ptr = VarintParse(ptr, &val);
+        if (ptr == nullptr) return false;
+        break;
+      }
+      case 1: {  // fixed64
+        ptr += 8;
+        break;
+      }
+      case 2: {  // len delim
+        int32_t size = ReadSize(&ptr);
+        if (ptr == nullptr || size > end - ptr) return false;
+        ptr += size;
+        break;
+      }
+      case 3: {  // start group
+        depth++;
+        break;
+      }
+      case 4: {                    // end group
+        if (--depth < 0) return true;  // We exit early
+        break;
+      }
+      case 5: {  // fixed32
+        ptr += 4;
+        break;
+      }
+      default:
+        return false;  // Unknown wireformat
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+const char* EpsCopyInputStream::NextBuffer(int overrun, int depth) {
+  if (next_chunk_ == nullptr) return nullptr;  // We've reached end of stream.
+  if (next_chunk_ != buffer_) {
+    GOOGLE_DCHECK(size_ > kSlopBytes);
+    // The chunk is large enough to be used directly
+    buffer_end_ = next_chunk_ + size_ - kSlopBytes;
+    auto res = next_chunk_;
+    next_chunk_ = buffer_;
+    if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+    return res;
+  }
+  // Move the slop bytes of previous buffer to start of the patch buffer.
+  // Note we must use memmove because the previous buffer could be part of
+  // buffer_.
+  std::memmove(buffer_, buffer_end_, kSlopBytes);
+  if (overall_limit_ > 0 &&
+      (depth < 0 || !ParseEndsInSlopRegion(buffer_, overrun, depth))) {
+    const void* data;
+    // ZeroCopyInputStream indicates Next may return 0 size buffers. Hence
+    // we loop.
+    while (StreamNext(&data)) {
+      if (size_ > kSlopBytes) {
+        // We got a large chunk
+        std::memcpy(buffer_ + kSlopBytes, data, kSlopBytes);
+        next_chunk_ = static_cast<const char*>(data);
+        buffer_end_ = buffer_ + kSlopBytes;
+        if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
+        return buffer_;
+      } else if (size_ > 0) {
+        std::memcpy(buffer_ + kSlopBytes, data, size_);
+        next_chunk_ = buffer_;
+        buffer_end_ = buffer_ + size_;
+        if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
+        return buffer_;
+      }
+      GOOGLE_DCHECK(size_ == 0) << size_;
+    }
+    overall_limit_ = 0;  // Next failed, no more needs for next
+  }
+  // End of stream or array
+  if (aliasing_ == kNoDelta) {
+    // If there is no more block and aliasing is true, the previous block
+    // is still valid and we can alias. We have users relying on string_view's
+    // obtained from protos to outlive the proto, when the parse was from an
+    // array. This guarantees string_view's are always aliased if parsed from
+    // an array.
+    aliasing_ = reinterpret_cast<std::uintptr_t>(buffer_end_) -
+                reinterpret_cast<std::uintptr_t>(buffer_);
+  }
+  next_chunk_ = nullptr;
+  buffer_end_ = buffer_ + kSlopBytes;
+  size_ = 0;
+  return buffer_;
+}
+
+const char* EpsCopyInputStream::Next() {
+  GOOGLE_DCHECK(limit_ > kSlopBytes);
+  auto p = NextBuffer(0 /* immaterial */, -1);
+  if (p == nullptr) {
+    limit_end_ = buffer_end_;
+    // Distinguish ending on a pushed limit or ending on end-of-stream.
+    SetEndOfStream();
+    return nullptr;
+  }
+  limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
+  limit_end_ = buffer_end_ + std::min(0, limit_);
+  return p;
+}
+
+std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(int overrun,
+                                                              int depth) {
+  // Did we exceeded the limit (parse error).
+  if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
+  GOOGLE_DCHECK(overrun != limit_);  // Guaranteed by caller.
+  GOOGLE_DCHECK(overrun < limit_);   // Follows from above
+  // TODO(gerbens) Instead of this dcheck we could just assign, and remove
+  // updating the limit_end from PopLimit, ie.
+  // limit_end_ = buffer_end_ + (std::min)(0, limit_);
+  // if (ptr < limit_end_) return {ptr, false};
+  GOOGLE_DCHECK(limit_end_ == buffer_end_ + (std::min)(0, limit_));
+  // At this point we know the following assertion holds.
+  GOOGLE_DCHECK_GT(limit_, 0);
+  GOOGLE_DCHECK(limit_end_ == buffer_end_);  // because limit_ > 0
+  const char* p;
+  do {
+    // We are past the end of buffer_end_, in the slop region.
+    GOOGLE_DCHECK_GE(overrun, 0);
+    p = NextBuffer(overrun, depth);
+    if (p == nullptr) {
+      // We are at the end of the stream
+      if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
+      GOOGLE_DCHECK_GT(limit_, 0);
+      limit_end_ = buffer_end_;
+      // Distinguish ending on a pushed limit or ending on end-of-stream.
+      SetEndOfStream();
+      return {buffer_end_, true};
+    }
+    limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
+    p += overrun;
+    overrun = p - buffer_end_;
+  } while (overrun >= 0);
+  limit_end_ = buffer_end_ + std::min(0, limit_);
+  return {p, false};
+}
+
+const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
+  return AppendSize(ptr, size, [](const char* /*p*/, int /*s*/) {});
+}
+
+const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
+                                                   std::string* str) {
+  str->clear();
+  if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
+    // Reserve the string up to a static safe size. If strings are bigger than
+    // this we proceed by growing the string as needed. This protects against
+    // malicious payloads making protobuf hold on to a lot of memory.
+    str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
+  }
+  return AppendSize(ptr, size,
+                    [str](const char* p, int s) { str->append(p, s); });
+}
+
+const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
+                                                     std::string* str) {
+  if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
+    // Reserve the string up to a static safe size. If strings are bigger than
+    // this we proceed by growing the string as needed. This protects against
+    // malicious payloads making protobuf hold on to a lot of memory.
+    str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
+  }
+  return AppendSize(ptr, size,
+                    [str](const char* p, int s) { str->append(p, s); });
+}
+
+
+const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
+  zcis_ = zcis;
+  const void* data;
+  int size;
+  limit_ = INT_MAX;
+  if (zcis->Next(&data, &size)) {
+    overall_limit_ -= size;
+    if (size > kSlopBytes) {
+      auto ptr = static_cast<const char*>(data);
+      limit_ -= size - kSlopBytes;
+      limit_end_ = buffer_end_ = ptr + size - kSlopBytes;
+      next_chunk_ = buffer_;
+      if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+      return ptr;
+    } else {
+      limit_end_ = buffer_end_ = buffer_ + kSlopBytes;
+      next_chunk_ = buffer_;
+      auto ptr = buffer_ + 2 * kSlopBytes - size;
+      std::memcpy(ptr, data, size);
+      return ptr;
+    }
+  }
+  overall_limit_ = 0;
+  next_chunk_ = nullptr;
+  size_ = 0;
+  limit_end_ = buffer_end_ = buffer_;
+  return buffer_;
+}
+
+const char* ParseContext::ReadSizeAndPushLimitAndDepth(const char* ptr,
+                                                       int* old_limit) {
+  int size = ReadSize(&ptr);
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) {
+    *old_limit = 0;  // Make sure this isn't uninitialized even on error return
+    return nullptr;
+  }
+  *old_limit = PushLimit(ptr, size);
+  if (--depth_ < 0) return nullptr;
+  return ptr;
+}
+
+const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
+  int old;
+  ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
+  ptr = ptr ? msg->_InternalParse(ptr, this) : nullptr;
+  depth_++;
+  if (!PopLimit(old)) return nullptr;
+  return ptr;
+}
+
+inline void WriteVarint(uint64_t val, std::string* s) {
+  while (val >= 128) {
+    uint8_t c = val | 0x80;
+    s->push_back(c);
+    val >>= 7;
+  }
+  s->push_back(val);
+}
+
+void WriteVarint(uint32_t num, uint64_t val, std::string* s) {
+  WriteVarint(num << 3, s);
+  WriteVarint(val, s);
+}
+
+void WriteLengthDelimited(uint32_t num, StringPiece val, std::string* s) {
+  WriteVarint((num << 3) + 2, s);
+  WriteVarint(val.size(), s);
+  s->append(val.data(), val.size());
+}
+
+std::pair<const char*, uint32_t> VarintParseSlow32(const char* p,
+                                                   uint32_t res) {
+  for (std::uint32_t i = 2; i < 5; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  // Accept >5 bytes
+  for (std::uint32_t i = 5; i < 10; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint64_t> VarintParseSlow64(const char* p,
+                                                   uint32_t res32) {
+  uint64_t res = res32;
+  for (std::uint32_t i = 2; i < 10; i++) {
+    uint64_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res) {
+  for (std::uint32_t i = 2; i < 5; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t res) {
+  for (std::uint32_t i = 1; i < 4; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  std::uint32_t byte = static_cast<uint8_t>(p[4]);
+  if (PROTOBUF_PREDICT_FALSE(byte >= 8)) return {nullptr, 0};  // size >= 2gb
+  res += (byte - 1) << 28;
+  // Protect against sign integer overflow in PushLimit. Limits are relative
+  // to buffer ends and ptr could potential be kSlopBytes beyond a buffer end.
+  // To protect against overflow we reject limits absurdly close to INT_MAX.
+  if (PROTOBUF_PREDICT_FALSE(res > INT_MAX - ParseContext::kSlopBytes)) {
+    return {nullptr, 0};
+  }
+  return {p + 5, res};
+}
+
+const char* StringParser(const char* begin, const char* end, void* object,
+                         ParseContext*) {
+  auto str = static_cast<std::string*>(object);
+  str->append(begin, end - begin);
+  return end;
+}
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
+                       bool emit_stacktrace);
+
+bool VerifyUTF8(StringPiece str, const char* field_name) {
+  if (!IsStructurallyValidUTF8(str)) {
+    PrintUTF8ErrorLog("", field_name, "parsing", false);
+    return false;
+  }
+  return true;
+}
+
+const char* InlineGreedyStringParser(std::string* s, const char* ptr,
+                                     ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+  return ctx->ReadString(ptr, size, s);
+}
+
+
+template <typename T, bool sign>
+const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
+  return ctx->ReadPackedVarint(ptr, [object](uint64_t varint) {
+    T val;
+    if (sign) {
+      if (sizeof(T) == 8) {
+        val = WireFormatLite::ZigZagDecode64(varint);
+      } else {
+        val = WireFormatLite::ZigZagDecode32(varint);
+      }
+    } else {
+      val = varint;
+    }
+    static_cast<RepeatedField<T>*>(object)->Add(val);
+  });
+}
+
+const char* PackedInt32Parser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return VarintParser<int32_t, false>(object, ptr, ctx);
+}
+const char* PackedUInt32Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<uint32_t, false>(object, ptr, ctx);
+}
+const char* PackedInt64Parser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return VarintParser<int64_t, false>(object, ptr, ctx);
+}
+const char* PackedUInt64Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<uint64_t, false>(object, ptr, ctx);
+}
+const char* PackedSInt32Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<int32_t, true>(object, ptr, ctx);
+}
+const char* PackedSInt64Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<int64_t, true>(object, ptr, ctx);
+}
+
+const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
+  return VarintParser<int, false>(object, ptr, ctx);
+}
+
+const char* PackedBoolParser(void* object, const char* ptr, ParseContext* ctx) {
+  return VarintParser<bool, false>(object, ptr, ctx);
+}
+
+template <typename T>
+const char* FixedParser(void* object, const char* ptr, ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  return ctx->ReadPackedFixed(ptr, size,
+                              static_cast<RepeatedField<T>*>(object));
+}
+
+const char* PackedFixed32Parser(void* object, const char* ptr,
+                                ParseContext* ctx) {
+  return FixedParser<uint32_t>(object, ptr, ctx);
+}
+const char* PackedSFixed32Parser(void* object, const char* ptr,
+                                 ParseContext* ctx) {
+  return FixedParser<int32_t>(object, ptr, ctx);
+}
+const char* PackedFixed64Parser(void* object, const char* ptr,
+                                ParseContext* ctx) {
+  return FixedParser<uint64_t>(object, ptr, ctx);
+}
+const char* PackedSFixed64Parser(void* object, const char* ptr,
+                                 ParseContext* ctx) {
+  return FixedParser<int64_t>(object, ptr, ctx);
+}
+const char* PackedFloatParser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return FixedParser<float>(object, ptr, ctx);
+}
+const char* PackedDoubleParser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return FixedParser<double>(object, ptr, ctx);
+}
+
+class UnknownFieldLiteParserHelper {
+ public:
+  explicit UnknownFieldLiteParserHelper(std::string* unknown)
+      : unknown_(unknown) {}
+
+  void AddVarint(uint32_t num, uint64_t value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8, unknown_);
+    WriteVarint(value, unknown_);
+  }
+  void AddFixed64(uint32_t num, uint64_t value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 1, unknown_);
+    char buffer[8];
+    io::CodedOutputStream::WriteLittleEndian64ToArray(
+        value, reinterpret_cast<uint8_t*>(buffer));
+    unknown_->append(buffer, 8);
+  }
+  const char* ParseLengthDelimited(uint32_t num, const char* ptr,
+                                   ParseContext* ctx) {
+    int size = ReadSize(&ptr);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (unknown_ == nullptr) return ctx->Skip(ptr, size);
+    WriteVarint(num * 8 + 2, unknown_);
+    WriteVarint(size, unknown_);
+    return ctx->AppendString(ptr, size, unknown_);
+  }
+  const char* ParseGroup(uint32_t num, const char* ptr, ParseContext* ctx) {
+    if (unknown_) WriteVarint(num * 8 + 3, unknown_);
+    ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (unknown_) WriteVarint(num * 8 + 4, unknown_);
+    return ptr;
+  }
+  void AddFixed32(uint32_t num, uint32_t value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 5, unknown_);
+    char buffer[4];
+    io::CodedOutputStream::WriteLittleEndian32ToArray(
+        value, reinterpret_cast<uint8_t*>(buffer));
+    unknown_->append(buffer, 4);
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return WireFormatParser(*this, ptr, ctx);
+  }
+
+ private:
+  std::string* unknown_;
+};
+
+const char* UnknownGroupLiteParse(std::string* unknown, const char* ptr,
+                                  ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(unknown);
+  return WireFormatParser(field_parser, ptr, ctx);
+}
+
+const char* UnknownFieldParse(uint32_t tag, std::string* unknown,
+                              const char* ptr, ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(unknown);
+  return FieldParser(tag, field_parser, ptr, ctx);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
new file mode 100644
index 0000000..7aea50c
--- /dev/null
+++ b/src/google/protobuf/parse_context.h
@@ -0,0 +1,1025 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_PARSE_CONTEXT_H__
+#define GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <type_traits>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/endian.h>
+#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/inlined_string_field.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+
+class UnknownFieldSet;
+class DescriptorPool;
+class MessageFactory;
+
+namespace internal {
+
+// Template code below needs to know about the existence of these functions.
+PROTOBUF_EXPORT void WriteVarint(uint32_t num, uint64_t val, std::string* s);
+PROTOBUF_EXPORT void WriteLengthDelimited(uint32_t num, StringPiece val,
+                                          std::string* s);
+// Inline because it is just forwarding to s->WriteVarint
+inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* s);
+inline void WriteLengthDelimited(uint32_t num, StringPiece val,
+                                 UnknownFieldSet* s);
+
+
+// The basic abstraction the parser is designed for is a slight modification
+// of the ZeroCopyInputStream (ZCIS) abstraction. A ZCIS presents a serialized
+// stream as a series of buffers that concatenate to the full stream.
+// Pictorially a ZCIS presents a stream in chunks like so
+// [---------------------------------------------------------------]
+// [---------------------] chunk 1
+//                      [----------------------------] chunk 2
+//                                          chunk 3 [--------------]
+//
+// Where the '-' represent the bytes which are vertically lined up with the
+// bytes of the stream. The proto parser requires its input to be presented
+// similarly with the extra
+// property that each chunk has kSlopBytes past its end that overlaps with the
+// first kSlopBytes of the next chunk, or if there is no next chunk at least its
+// still valid to read those bytes. Again, pictorially, we now have
+//
+// [---------------------------------------------------------------]
+// [-------------------....] chunk 1
+//                    [------------------------....] chunk 2
+//                                    chunk 3 [------------------..**]
+//                                                      chunk 4 [--****]
+// Here '-' mean the bytes of the stream or chunk and '.' means bytes past the
+// chunk that match up with the start of the next chunk. Above each chunk has
+// 4 '.' after the chunk. In the case these 'overflow' bytes represents bytes
+// past the stream, indicated by '*' above, their values are unspecified. It is
+// still legal to read them (ie. should not segfault). Reading past the
+// end should be detected by the user and indicated as an error.
+//
+// The reason for this, admittedly, unconventional invariant is to ruthlessly
+// optimize the protobuf parser. Having an overlap helps in two important ways.
+// Firstly it alleviates having to performing bounds checks if a piece of code
+// is guaranteed to not read more than kSlopBytes. Secondly, and more
+// importantly, the protobuf wireformat is such that reading a key/value pair is
+// always less than 16 bytes. This removes the need to change to next buffer in
+// the middle of reading primitive values. Hence there is no need to store and
+// load the current position.
+
+class PROTOBUF_EXPORT EpsCopyInputStream {
+ public:
+  enum { kSlopBytes = 16, kMaxCordBytesToCopy = 512 };
+
+  explicit EpsCopyInputStream(bool enable_aliasing)
+      : aliasing_(enable_aliasing ? kOnPatch : kNoAliasing) {}
+
+  void BackUp(const char* ptr) {
+    GOOGLE_DCHECK(ptr <= buffer_end_ + kSlopBytes);
+    int count;
+    if (next_chunk_ == buffer_) {
+      count = static_cast<int>(buffer_end_ + kSlopBytes - ptr);
+    } else {
+      count = size_ + static_cast<int>(buffer_end_ - ptr);
+    }
+    if (count > 0) StreamBackUp(count);
+  }
+
+  // If return value is negative it's an error
+  PROTOBUF_NODISCARD int PushLimit(const char* ptr, int limit) {
+    GOOGLE_DCHECK(limit >= 0 && limit <= INT_MAX - kSlopBytes);
+    // This add is safe due to the invariant above, because
+    // ptr - buffer_end_ <= kSlopBytes.
+    limit += static_cast<int>(ptr - buffer_end_);
+    limit_end_ = buffer_end_ + (std::min)(0, limit);
+    auto old_limit = limit_;
+    limit_ = limit;
+    return old_limit - limit;
+  }
+
+  PROTOBUF_NODISCARD bool PopLimit(int delta) {
+    if (PROTOBUF_PREDICT_FALSE(!EndedAtLimit())) return false;
+    limit_ = limit_ + delta;
+    // TODO(gerbens) We could remove this line and hoist the code to
+    // DoneFallback. Study the perf/bin-size effects.
+    limit_end_ = buffer_end_ + (std::min)(0, limit_);
+    return true;
+  }
+
+  PROTOBUF_NODISCARD const char* Skip(const char* ptr, int size) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      return ptr + size;
+    }
+    return SkipFallback(ptr, size);
+  }
+  PROTOBUF_NODISCARD const char* ReadString(const char* ptr, int size,
+                                            std::string* s) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      s->assign(ptr, size);
+      return ptr + size;
+    }
+    return ReadStringFallback(ptr, size, s);
+  }
+  PROTOBUF_NODISCARD const char* AppendString(const char* ptr, int size,
+                                              std::string* s) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      s->append(ptr, size);
+      return ptr + size;
+    }
+    return AppendStringFallback(ptr, size, s);
+  }
+  // Implemented in arenastring.cc
+  PROTOBUF_NODISCARD const char* ReadArenaString(const char* ptr,
+                                                 ArenaStringPtr* s,
+                                                 Arena* arena);
+
+  template <typename Tag, typename T>
+  PROTOBUF_NODISCARD const char* ReadRepeatedFixed(const char* ptr,
+                                                   Tag expected_tag,
+                                                   RepeatedField<T>* out);
+
+  template <typename T>
+  PROTOBUF_NODISCARD const char* ReadPackedFixed(const char* ptr, int size,
+                                                 RepeatedField<T>* out);
+  template <typename Add>
+  PROTOBUF_NODISCARD const char* ReadPackedVarint(const char* ptr, Add add);
+
+  uint32_t LastTag() const { return last_tag_minus_1_ + 1; }
+  bool ConsumeEndGroup(uint32_t start_tag) {
+    bool res = last_tag_minus_1_ == start_tag;
+    last_tag_minus_1_ = 0;
+    return res;
+  }
+  bool EndedAtLimit() const { return last_tag_minus_1_ == 0; }
+  bool EndedAtEndOfStream() const { return last_tag_minus_1_ == 1; }
+  void SetLastTag(uint32_t tag) { last_tag_minus_1_ = tag - 1; }
+  void SetEndOfStream() { last_tag_minus_1_ = 1; }
+  bool IsExceedingLimit(const char* ptr) {
+    return ptr > limit_end_ &&
+           (next_chunk_ == nullptr || ptr - buffer_end_ > limit_);
+  }
+  bool AliasingEnabled() const { return aliasing_ != kNoAliasing; }
+  int BytesUntilLimit(const char* ptr) const {
+    return limit_ + static_cast<int>(buffer_end_ - ptr);
+  }
+  // Returns true if more data is available, if false is returned one has to
+  // call Done for further checks.
+  bool DataAvailable(const char* ptr) { return ptr < limit_end_; }
+
+ protected:
+  // Returns true is limit (either an explicit limit or end of stream) is
+  // reached. It aligns *ptr across buffer seams.
+  // If limit is exceeded it returns true and ptr is set to null.
+  bool DoneWithCheck(const char** ptr, int d) {
+    GOOGLE_DCHECK(*ptr);
+    if (PROTOBUF_PREDICT_TRUE(*ptr < limit_end_)) return false;
+    int overrun = static_cast<int>(*ptr - buffer_end_);
+    GOOGLE_DCHECK_LE(overrun, kSlopBytes);  // Guaranteed by parse loop.
+    if (overrun ==
+        limit_) {  //  No need to flip buffers if we ended on a limit.
+      // If we actually overrun the buffer and next_chunk_ is null. It means
+      // the stream ended and we passed the stream end.
+      if (overrun > 0 && next_chunk_ == nullptr) *ptr = nullptr;
+      return true;
+    }
+    auto res = DoneFallback(overrun, d);
+    *ptr = res.first;
+    return res.second;
+  }
+
+  const char* InitFrom(StringPiece flat) {
+    overall_limit_ = 0;
+    if (flat.size() > kSlopBytes) {
+      limit_ = kSlopBytes;
+      limit_end_ = buffer_end_ = flat.data() + flat.size() - kSlopBytes;
+      next_chunk_ = buffer_;
+      if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+      return flat.data();
+    } else {
+      std::memcpy(buffer_, flat.data(), flat.size());
+      limit_ = 0;
+      limit_end_ = buffer_end_ = buffer_ + flat.size();
+      next_chunk_ = nullptr;
+      if (aliasing_ == kOnPatch) {
+        aliasing_ = reinterpret_cast<std::uintptr_t>(flat.data()) -
+                    reinterpret_cast<std::uintptr_t>(buffer_);
+      }
+      return buffer_;
+    }
+  }
+
+  const char* InitFrom(io::ZeroCopyInputStream* zcis);
+
+  const char* InitFrom(io::ZeroCopyInputStream* zcis, int limit) {
+    if (limit == -1) return InitFrom(zcis);
+    overall_limit_ = limit;
+    auto res = InitFrom(zcis);
+    limit_ = limit - static_cast<int>(buffer_end_ - res);
+    limit_end_ = buffer_end_ + (std::min)(0, limit_);
+    return res;
+  }
+
+ private:
+  const char* limit_end_;  // buffer_end_ + min(limit_, 0)
+  const char* buffer_end_;
+  const char* next_chunk_;
+  int size_;
+  int limit_;  // relative to buffer_end_;
+  io::ZeroCopyInputStream* zcis_ = nullptr;
+  char buffer_[2 * kSlopBytes] = {};
+  enum { kNoAliasing = 0, kOnPatch = 1, kNoDelta = 2 };
+  std::uintptr_t aliasing_ = kNoAliasing;
+  // This variable is used to communicate how the parse ended, in order to
+  // completely verify the parsed data. A wire-format parse can end because of
+  // one of the following conditions:
+  // 1) A parse can end on a pushed limit.
+  // 2) A parse can end on End Of Stream (EOS).
+  // 3) A parse can end on 0 tag (only valid for toplevel message).
+  // 4) A parse can end on an end-group tag.
+  // This variable should always be set to 0, which indicates case 1. If the
+  // parse terminated due to EOS (case 2), it's set to 1. In case the parse
+  // ended due to a terminating tag (case 3 and 4) it's set to (tag - 1).
+  // This var doesn't really belong in EpsCopyInputStream and should be part of
+  // the ParseContext, but case 2 is most easily and optimally implemented in
+  // DoneFallback.
+  uint32_t last_tag_minus_1_ = 0;
+  int overall_limit_ = INT_MAX;  // Overall limit independent of pushed limits.
+  // Pretty random large number that seems like a safe allocation on most
+  // systems. TODO(gerbens) do we need to set this as build flag?
+  enum { kSafeStringSize = 50000000 };
+
+  // Advances to next buffer chunk returns a pointer to the same logical place
+  // in the stream as set by overrun. Overrun indicates the position in the slop
+  // region the parse was left (0 <= overrun <= kSlopBytes). Returns true if at
+  // limit, at which point the returned pointer maybe null if there was an
+  // error. The invariant of this function is that it's guaranteed that
+  // kSlopBytes bytes can be accessed from the returned ptr. This function might
+  // advance more buffers than one in the underlying ZeroCopyInputStream.
+  std::pair<const char*, bool> DoneFallback(int overrun, int depth);
+  // Advances to the next buffer, at most one call to Next() on the underlying
+  // ZeroCopyInputStream is made. This function DOES NOT match the returned
+  // pointer to where in the slop region the parse ends, hence no overrun
+  // parameter. This is useful for string operations where you always copy
+  // to the end of the buffer (including the slop region).
+  const char* Next();
+  // overrun is the location in the slop region the stream currently is
+  // (0 <= overrun <= kSlopBytes). To prevent flipping to the next buffer of
+  // the ZeroCopyInputStream in the case the parse will end in the last
+  // kSlopBytes of the current buffer. depth is the current depth of nested
+  // groups (or negative if the use case does not need careful tracking).
+  inline const char* NextBuffer(int overrun, int depth);
+  const char* SkipFallback(const char* ptr, int size);
+  const char* AppendStringFallback(const char* ptr, int size, std::string* str);
+  const char* ReadStringFallback(const char* ptr, int size, std::string* str);
+  bool StreamNext(const void** data) {
+    bool res = zcis_->Next(data, &size_);
+    if (res) overall_limit_ -= size_;
+    return res;
+  }
+  void StreamBackUp(int count) {
+    zcis_->BackUp(count);
+    overall_limit_ += count;
+  }
+
+  template <typename A>
+  const char* AppendSize(const char* ptr, int size, const A& append) {
+    int chunk_size = buffer_end_ + kSlopBytes - ptr;
+    do {
+      GOOGLE_DCHECK(size > chunk_size);
+      if (next_chunk_ == nullptr) return nullptr;
+      append(ptr, chunk_size);
+      ptr += chunk_size;
+      size -= chunk_size;
+      // TODO(gerbens) Next calls NextBuffer which generates buffers with
+      // overlap and thus incurs cost of copying the slop regions. This is not
+      // necessary for reading strings. We should just call Next buffers.
+      if (limit_ <= kSlopBytes) return nullptr;
+      ptr = Next();
+      if (ptr == nullptr) return nullptr;  // passed the limit
+      ptr += kSlopBytes;
+      chunk_size = buffer_end_ + kSlopBytes - ptr;
+    } while (size > chunk_size);
+    append(ptr, size);
+    return ptr + size;
+  }
+
+  // AppendUntilEnd appends data until a limit (either a PushLimit or end of
+  // stream. Normal payloads are from length delimited fields which have an
+  // explicit size. Reading until limit only comes when the string takes
+  // the place of a protobuf, ie RawMessage/StringRawMessage, lazy fields and
+  // implicit weak messages. We keep these methods private and friend them.
+  template <typename A>
+  const char* AppendUntilEnd(const char* ptr, const A& append) {
+    if (ptr - buffer_end_ > limit_) return nullptr;
+    while (limit_ > kSlopBytes) {
+      size_t chunk_size = buffer_end_ + kSlopBytes - ptr;
+      append(ptr, chunk_size);
+      ptr = Next();
+      if (ptr == nullptr) return limit_end_;
+      ptr += kSlopBytes;
+    }
+    auto end = buffer_end_ + limit_;
+    GOOGLE_DCHECK(end >= ptr);
+    append(ptr, end - ptr);
+    return end;
+  }
+
+  PROTOBUF_NODISCARD const char* AppendString(const char* ptr,
+                                              std::string* str) {
+    return AppendUntilEnd(
+        ptr, [str](const char* p, ptrdiff_t s) { str->append(p, s); });
+  }
+  friend class ImplicitWeakMessage;
+};
+
+using LazyEagerVerifyFnType = const char* (*)(const char* ptr,
+                                              ParseContext* ctx);
+using LazyEagerVerifyFnRef = std::remove_pointer<LazyEagerVerifyFnType>::type&;
+
+// ParseContext holds all data that is global to the entire parse. Most
+// importantly it contains the input stream, but also recursion depth and also
+// stores the end group tag, in case a parser ended on a endgroup, to verify
+// matching start/end group tags.
+class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream {
+ public:
+  struct Data {
+    const DescriptorPool* pool = nullptr;
+    MessageFactory* factory = nullptr;
+    Arena* arena = nullptr;
+  };
+
+  template <typename... T>
+  ParseContext(int depth, bool aliasing, const char** start, T&&... args)
+      : EpsCopyInputStream(aliasing), depth_(depth) {
+    *start = InitFrom(std::forward<T>(args)...);
+  }
+
+  void TrackCorrectEnding() { group_depth_ = 0; }
+
+  bool Done(const char** ptr) { return DoneWithCheck(ptr, group_depth_); }
+
+  int depth() const { return depth_; }
+
+  Data& data() { return data_; }
+  const Data& data() const { return data_; }
+
+  const char* ParseMessage(MessageLite* msg, const char* ptr);
+
+  // Spawns a child parsing context that inherits key properties. New context
+  // inherits the following:
+  // --depth_, data_, check_required_fields_, lazy_parse_mode_
+  // The spawned context always disables aliasing (different input).
+  template <typename... T>
+  ParseContext Spawn(const char** start, T&&... args) {
+    ParseContext spawned(depth_, false, start, std::forward<T>(args)...);
+    // Transfer key context states.
+    spawned.data_ = data_;
+    return spawned;
+  }
+
+  // This overload supports those few cases where ParseMessage is called
+  // on a class that is not actually a proto message.
+  // TODO(jorg): Eliminate this use case.
+  template <typename T,
+            typename std::enable_if<!std::is_base_of<MessageLite, T>::value,
+                                    bool>::type = true>
+  PROTOBUF_NODISCARD const char* ParseMessage(T* msg, const char* ptr);
+
+  template <typename T>
+  PROTOBUF_NODISCARD PROTOBUF_NDEBUG_INLINE const char* ParseGroup(
+      T* msg, const char* ptr, uint32_t tag) {
+    if (--depth_ < 0) return nullptr;
+    group_depth_++;
+    ptr = msg->_InternalParse(ptr, this);
+    group_depth_--;
+    depth_++;
+    if (PROTOBUF_PREDICT_FALSE(!ConsumeEndGroup(tag))) return nullptr;
+    return ptr;
+  }
+
+ private:
+  // Out-of-line routine to save space in ParseContext::ParseMessage<T>
+  //   int old;
+  //   ptr = ReadSizeAndPushLimitAndDepth(ptr, &old)
+  // is equivalent to:
+  //   int size = ReadSize(&ptr);
+  //   if (!ptr) return nullptr;
+  //   int old = PushLimit(ptr, size);
+  //   if (--depth_ < 0) return nullptr;
+  PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(const char* ptr,
+                                                              int* old_limit);
+
+  // The context keeps an internal stack to keep track of the recursive
+  // part of the parse state.
+  // Current depth of the active parser, depth counts down.
+  // This is used to limit recursion depth (to prevent overflow on malicious
+  // data), but is also used to index in stack_ to store the current state.
+  int depth_;
+  // Unfortunately necessary for the fringe case of ending on 0 or end-group tag
+  // in the last kSlopBytes of a ZeroCopyInputStream chunk.
+  int group_depth_ = INT_MIN;
+  Data data_;
+};
+
+template <uint32_t tag>
+bool ExpectTag(const char* ptr) {
+  if (tag < 128) {
+    return *ptr == static_cast<char>(tag);
+  } else {
+    static_assert(tag < 128 * 128, "We only expect tags for 1 or 2 bytes");
+    char buf[2] = {static_cast<char>(tag | 0x80), static_cast<char>(tag >> 7)};
+    return std::memcmp(ptr, buf, 2) == 0;
+  }
+}
+
+template <int>
+struct EndianHelper;
+
+template <>
+struct EndianHelper<1> {
+  static uint8_t Load(const void* p) { return *static_cast<const uint8_t*>(p); }
+};
+
+template <>
+struct EndianHelper<2> {
+  static uint16_t Load(const void* p) {
+    uint16_t tmp;
+    std::memcpy(&tmp, p, 2);
+    return little_endian::ToHost(tmp);
+  }
+};
+
+template <>
+struct EndianHelper<4> {
+  static uint32_t Load(const void* p) {
+    uint32_t tmp;
+    std::memcpy(&tmp, p, 4);
+    return little_endian::ToHost(tmp);
+  }
+};
+
+template <>
+struct EndianHelper<8> {
+  static uint64_t Load(const void* p) {
+    uint64_t tmp;
+    std::memcpy(&tmp, p, 8);
+    return little_endian::ToHost(tmp);
+  }
+};
+
+template <typename T>
+T UnalignedLoad(const char* p) {
+  auto tmp = EndianHelper<sizeof(T)>::Load(p);
+  T res;
+  memcpy(&res, &tmp, sizeof(T));
+  return res;
+}
+
+PROTOBUF_EXPORT
+std::pair<const char*, uint32_t> VarintParseSlow32(const char* p, uint32_t res);
+PROTOBUF_EXPORT
+std::pair<const char*, uint64_t> VarintParseSlow64(const char* p, uint32_t res);
+
+inline const char* VarintParseSlow(const char* p, uint32_t res, uint32_t* out) {
+  auto tmp = VarintParseSlow32(p, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
+inline const char* VarintParseSlow(const char* p, uint32_t res, uint64_t* out) {
+  auto tmp = VarintParseSlow64(p, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
+template <typename T>
+PROTOBUF_NODISCARD const char* VarintParse(const char* p, T* out) {
+  auto ptr = reinterpret_cast<const uint8_t*>(p);
+  uint32_t res = ptr[0];
+  if (!(res & 0x80)) {
+    *out = res;
+    return p + 1;
+  }
+  uint32_t byte = ptr[1];
+  res += (byte - 1) << 7;
+  if (!(byte & 0x80)) {
+    *out = res;
+    return p + 2;
+  }
+  return VarintParseSlow(p, res, out);
+}
+
+// Used for tags, could read up to 5 bytes which must be available.
+// Caller must ensure its safe to call.
+
+PROTOBUF_EXPORT
+std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res);
+
+// Same as ParseVarint but only accept 5 bytes at most.
+inline const char* ReadTag(const char* p, uint32_t* out,
+                           uint32_t /*max_tag*/ = 0) {
+  uint32_t res = static_cast<uint8_t>(p[0]);
+  if (res < 128) {
+    *out = res;
+    return p + 1;
+  }
+  uint32_t second = static_cast<uint8_t>(p[1]);
+  res += (second - 1) << 7;
+  if (second < 128) {
+    *out = res;
+    return p + 2;
+  }
+  auto tmp = ReadTagFallback(p, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
+// As above, but optimized to consume very few registers while still being fast,
+// ReadTagInlined is useful for callers that don't mind the extra code but would
+// like to avoid an extern function call causing spills into the stack.
+//
+// Two support routines for ReadTagInlined come first...
+template <class T>
+PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE constexpr T RotateLeft(
+    T x, int s) noexcept {
+  return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
+         static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+PROTOBUF_NODISCARD inline PROTOBUF_ALWAYS_INLINE uint64_t
+RotRight7AndReplaceLowByte(uint64_t res, const char& byte) {
+#if defined(__x86_64__) && defined(__GNUC__)
+  // This will only use one register for `res`.
+  // `byte` comes as a reference to allow the compiler to generate code like:
+  //
+  //   rorq    $7, %rcx
+  //   movb    1(%rax), %cl
+  //
+  // which avoids loading the incoming bytes into a separate register first.
+  asm("ror $7,%0\n\t"
+      "movb %1,%b0"
+      : "+r"(res)
+      : "m"(byte));
+#else
+  res = RotateLeft(res, -7);
+  res = res & ~0xFF;
+  res |= 0xFF & byte;
+#endif
+  return res;
+};
+
+inline PROTOBUF_ALWAYS_INLINE
+const char* ReadTagInlined(const char* ptr, uint32_t* out) {
+  uint64_t res = 0xFF & ptr[0];
+  if (PROTOBUF_PREDICT_FALSE(res >= 128)) {
+    res = RotRight7AndReplaceLowByte(res, ptr[1]);
+    if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+      res = RotRight7AndReplaceLowByte(res, ptr[2]);
+      if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+        res = RotRight7AndReplaceLowByte(res, ptr[3]);
+        if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+          // Note: this wouldn't work if res were 32-bit,
+          // because then replacing the low byte would overwrite
+          // the bottom 4 bits of the result.
+          res = RotRight7AndReplaceLowByte(res, ptr[4]);
+          if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+            // The proto format does not permit longer than 5-byte encodings for
+            // tags.
+            *out = 0;
+            return nullptr;
+          }
+          *out = static_cast<uint32_t>(RotateLeft(res, 28));
+#if defined(__GNUC__)
+          // Note: this asm statement prevents the compiler from
+          // trying to share the "return ptr + constant" among all
+          // branches.
+          asm("" : "+r"(ptr));
+#endif
+          return ptr + 5;
+        }
+        *out = static_cast<uint32_t>(RotateLeft(res, 21));
+        return ptr + 4;
+      }
+      *out = static_cast<uint32_t>(RotateLeft(res, 14));
+      return ptr + 3;
+    }
+    *out = static_cast<uint32_t>(RotateLeft(res, 7));
+    return ptr + 2;
+  }
+  *out = static_cast<uint32_t>(res);
+  return ptr + 1;
+}
+
+// Decode 2 consecutive bytes of a varint and returns the value, shifted left
+// by 1. It simultaneous updates *ptr to *ptr + 1 or *ptr + 2 depending if the
+// first byte's continuation bit is set.
+// If bit 15 of return value is set (equivalent to the continuation bits of both
+// bytes being set) the varint continues, otherwise the parse is done. On x86
+// movsx eax, dil
+// and edi, eax
+// add eax, edi
+// adc [rsi], 1
+inline uint32_t DecodeTwoBytes(const char** ptr) {
+  uint32_t value = UnalignedLoad<uint16_t>(*ptr);
+  // Sign extend the low byte continuation bit
+  uint32_t x = static_cast<int8_t>(value);
+  value &= x;  // Mask out the high byte iff no continuation
+  // This add is an amazing operation, it cancels the low byte continuation bit
+  // from y transferring it to the carry. Simultaneously it also shifts the 7
+  // LSB left by one tightly against high byte varint bits. Hence value now
+  // contains the unpacked value shifted left by 1.
+  value += x;
+  // Use the carry to update the ptr appropriately.
+  *ptr += value < x ? 2 : 1;
+  return value;
+}
+
+// More efficient varint parsing for big varints
+inline const char* ParseBigVarint(const char* p, uint64_t* out) {
+  auto pnew = p;
+  auto tmp = DecodeTwoBytes(&pnew);
+  uint64_t res = tmp >> 1;
+  if (PROTOBUF_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
+    *out = res;
+    return pnew;
+  }
+  for (std::uint32_t i = 1; i < 5; i++) {
+    pnew = p + 2 * i;
+    tmp = DecodeTwoBytes(&pnew);
+    res += (static_cast<std::uint64_t>(tmp) - 2) << (14 * i - 1);
+    if (PROTOBUF_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
+      *out = res;
+      return pnew;
+    }
+  }
+  return nullptr;
+}
+
+PROTOBUF_EXPORT
+std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t first);
+// Used for tags, could read up to 5 bytes which must be available. Additionally
+// it makes sure the unsigned value fits a int32_t, otherwise returns nullptr.
+// Caller must ensure its safe to call.
+inline uint32_t ReadSize(const char** pp) {
+  auto p = *pp;
+  uint32_t res = static_cast<uint8_t>(p[0]);
+  if (res < 128) {
+    *pp = p + 1;
+    return res;
+  }
+  auto x = ReadSizeFallback(p, res);
+  *pp = x.first;
+  return x.second;
+}
+
+// Some convenience functions to simplify the generated parse loop code.
+// Returning the value and updating the buffer pointer allows for nicer
+// function composition. We rely on the compiler to inline this.
+// Also in debug compiles having local scoped variables tend to generated
+// stack frames that scale as O(num fields).
+inline uint64_t ReadVarint64(const char** p) {
+  uint64_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return tmp;
+}
+
+inline uint32_t ReadVarint32(const char** p) {
+  uint32_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return tmp;
+}
+
+inline int64_t ReadVarintZigZag64(const char** p) {
+  uint64_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return WireFormatLite::ZigZagDecode64(tmp);
+}
+
+inline int32_t ReadVarintZigZag32(const char** p) {
+  uint64_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
+}
+
+template <typename T, typename std::enable_if<
+                          !std::is_base_of<MessageLite, T>::value, bool>::type>
+PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
+                                                          const char* ptr) {
+  int old;
+  ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
+  ptr = ptr ? msg->_InternalParse(ptr, this) : nullptr;
+  depth_++;
+  if (!PopLimit(old)) return nullptr;
+  return ptr;
+}
+
+template <typename Tag, typename T>
+const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
+                                                  Tag expected_tag,
+                                                  RepeatedField<T>* out) {
+  do {
+    out->Add(UnalignedLoad<T>(ptr));
+    ptr += sizeof(T);
+    if (PROTOBUF_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
+  } while (UnalignedLoad<Tag>(ptr) == expected_tag && (ptr += sizeof(Tag)));
+  return ptr;
+}
+
+// Add any of the following lines to debug which parse function is failing.
+
+#define GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, ret) \
+  if (!(predicate)) {                                  \
+    /*  ::raise(SIGINT);  */                           \
+    /*  GOOGLE_LOG(ERROR) << "Parse failure";  */             \
+    return ret;                                        \
+  }
+
+#define GOOGLE_PROTOBUF_PARSER_ASSERT(predicate) \
+  GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
+
+template <typename T>
+const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
+                                                RepeatedField<T>* out) {
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  int nbytes = buffer_end_ + kSlopBytes - ptr;
+  while (size > nbytes) {
+    int num = nbytes / sizeof(T);
+    int old_entries = out->size();
+    out->Reserve(old_entries + num);
+    int block_size = num * sizeof(T);
+    auto dst = out->AddNAlreadyReserved(num);
+#ifdef PROTOBUF_LITTLE_ENDIAN
+    std::memcpy(dst, ptr, block_size);
+#else
+    for (int i = 0; i < num; i++)
+      dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
+#endif
+    size -= block_size;
+    if (limit_ <= kSlopBytes) return nullptr;
+    ptr = Next();
+    if (ptr == nullptr) return nullptr;
+    ptr += kSlopBytes - (nbytes - block_size);
+    nbytes = buffer_end_ + kSlopBytes - ptr;
+  }
+  int num = size / sizeof(T);
+  int old_entries = out->size();
+  out->Reserve(old_entries + num);
+  int block_size = num * sizeof(T);
+  auto dst = out->AddNAlreadyReserved(num);
+#ifdef PROTOBUF_LITTLE_ENDIAN
+  std::memcpy(dst, ptr, block_size);
+#else
+  for (int i = 0; i < num; i++) dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
+#endif
+  ptr += block_size;
+  if (size != block_size) return nullptr;
+  return ptr;
+}
+
+template <typename Add>
+const char* ReadPackedVarintArray(const char* ptr, const char* end, Add add) {
+  while (ptr < end) {
+    uint64_t varint;
+    ptr = VarintParse(ptr, &varint);
+    if (ptr == nullptr) return nullptr;
+    add(varint);
+  }
+  return ptr;
+}
+
+template <typename Add>
+const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  int chunk_size = buffer_end_ - ptr;
+  while (size > chunk_size) {
+    ptr = ReadPackedVarintArray(ptr, buffer_end_, add);
+    if (ptr == nullptr) return nullptr;
+    int overrun = ptr - buffer_end_;
+    GOOGLE_DCHECK(overrun >= 0 && overrun <= kSlopBytes);
+    if (size - chunk_size <= kSlopBytes) {
+      // The current buffer contains all the information needed, we don't need
+      // to flip buffers. However we must parse from a buffer with enough space
+      // so we are not prone to a buffer overflow.
+      char buf[kSlopBytes + 10] = {};
+      std::memcpy(buf, buffer_end_, kSlopBytes);
+      GOOGLE_CHECK_LE(size - chunk_size, kSlopBytes);
+      auto end = buf + (size - chunk_size);
+      auto res = ReadPackedVarintArray(buf + overrun, end, add);
+      if (res == nullptr || res != end) return nullptr;
+      return buffer_end_ + (res - buf);
+    }
+    size -= overrun + chunk_size;
+    GOOGLE_DCHECK_GT(size, 0);
+    // We must flip buffers
+    if (limit_ <= kSlopBytes) return nullptr;
+    ptr = Next();
+    if (ptr == nullptr) return nullptr;
+    ptr += overrun;
+    chunk_size = buffer_end_ - ptr;
+  }
+  auto end = ptr + size;
+  ptr = ReadPackedVarintArray(ptr, end, add);
+  return end == ptr ? ptr : nullptr;
+}
+
+// Helper for verification of utf8
+PROTOBUF_EXPORT
+bool VerifyUTF8(StringPiece s, const char* field_name);
+
+inline bool VerifyUTF8(const std::string* s, const char* field_name) {
+  return VerifyUTF8(*s, field_name);
+}
+
+// All the string parsers with or without UTF checking and for all CTypes.
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* InlineGreedyStringParser(
+    std::string* s, const char* ptr, ParseContext* ctx);
+
+
+template <typename T>
+PROTOBUF_NODISCARD const char* FieldParser(uint64_t tag, T& field_parser,
+                                           const char* ptr, ParseContext* ctx) {
+  uint32_t number = tag >> 3;
+  GOOGLE_PROTOBUF_PARSER_ASSERT(number != 0);
+  using WireType = internal::WireFormatLite::WireType;
+  switch (tag & 7) {
+    case WireType::WIRETYPE_VARINT: {
+      uint64_t value;
+      ptr = VarintParse(ptr, &value);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      field_parser.AddVarint(number, value);
+      break;
+    }
+    case WireType::WIRETYPE_FIXED64: {
+      uint64_t value = UnalignedLoad<uint64_t>(ptr);
+      ptr += 8;
+      field_parser.AddFixed64(number, value);
+      break;
+    }
+    case WireType::WIRETYPE_LENGTH_DELIMITED: {
+      ptr = field_parser.ParseLengthDelimited(number, ptr, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      break;
+    }
+    case WireType::WIRETYPE_START_GROUP: {
+      ptr = field_parser.ParseGroup(number, ptr, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      break;
+    }
+    case WireType::WIRETYPE_END_GROUP: {
+      GOOGLE_LOG(FATAL) << "Can't happen";
+      break;
+    }
+    case WireType::WIRETYPE_FIXED32: {
+      uint32_t value = UnalignedLoad<uint32_t>(ptr);
+      ptr += 4;
+      field_parser.AddFixed32(number, value);
+      break;
+    }
+    default:
+      return nullptr;
+  }
+  return ptr;
+}
+
+template <typename T>
+PROTOBUF_NODISCARD const char* WireFormatParser(T& field_parser,
+                                                const char* ptr,
+                                                ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ReadTag(ptr, &tag);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+    if (tag == 0 || (tag & 7) == 4) {
+      ctx->SetLastTag(tag);
+      return ptr;
+    }
+    ptr = FieldParser(tag, field_parser, ptr, ctx);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+  }
+  return ptr;
+}
+
+// The packed parsers parse repeated numeric primitives directly into  the
+// corresponding field
+
+// These are packed varints
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedUInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedUInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedEnumParser(
+    void* object, const char* ptr, ParseContext* ctx);
+
+template <typename T>
+PROTOBUF_NODISCARD const char* PackedEnumParser(void* object, const char* ptr,
+                                                ParseContext* ctx,
+                                                bool (*is_valid)(int),
+                                                InternalMetadata* metadata,
+                                                int field_num) {
+  return ctx->ReadPackedVarint(
+      ptr, [object, is_valid, metadata, field_num](uint64_t val) {
+        if (is_valid(val)) {
+          static_cast<RepeatedField<int>*>(object)->Add(val);
+        } else {
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields<T>());
+        }
+      });
+}
+
+template <typename T>
+PROTOBUF_NODISCARD const char* PackedEnumParserArg(
+    void* object, const char* ptr, ParseContext* ctx,
+    bool (*is_valid)(const void*, int), const void* data,
+    InternalMetadata* metadata, int field_num) {
+  return ctx->ReadPackedVarint(
+      ptr, [object, is_valid, data, metadata, field_num](uint64_t val) {
+        if (is_valid(data, val)) {
+          static_cast<RepeatedField<int>*>(object)->Add(val);
+        } else {
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields<T>());
+        }
+      });
+}
+
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedBoolParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedFixed32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSFixed32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedFixed64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSFixed64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedFloatParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedDoubleParser(
+    void* object, const char* ptr, ParseContext* ctx);
+
+// This is the only recursive parser.
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* UnknownGroupLiteParse(
+    std::string* unknown, const char* ptr, ParseContext* ctx);
+// This is a helper to for the UnknownGroupLiteParse but is actually also
+// useful in the generated code. It uses overload on std::string* vs
+// UnknownFieldSet* to make the generated code isomorphic between full and lite.
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* UnknownFieldParse(
+    uint32_t tag, std::string* unknown, const char* ptr, ParseContext* ctx);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
diff --git a/src/google/protobuf/port.h b/src/google/protobuf/port.h
new file mode 100644
index 0000000..a5c060b
--- /dev/null
+++ b/src/google/protobuf/port.h
@@ -0,0 +1,80 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A common header that is included across all protobuf headers.  We do our best
+// to avoid #defining any macros here; instead we generally put macros in
+// port_def.inc and port_undef.inc so they are not visible from outside of
+// protobuf.
+
+#ifndef GOOGLE_PROTOBUF_PORT_H__
+#define GOOGLE_PROTOBUF_PORT_H__
+
+#include <cstddef>
+#include <new>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+inline void SizedDelete(void* p, size_t size) {
+#if defined(__cpp_sized_deallocation)
+  ::operator delete(p, size);
+#else
+  ::operator delete(p);
+#endif
+}
+inline void SizedArrayDelete(void* p, size_t size) {
+#if defined(__cpp_sized_deallocation)
+  ::operator delete[](p, size);
+#else
+  ::operator delete[](p);
+#endif
+}
+
+// Tag type used to invoke the constinit constructor overload of classes
+// such as ArenaStringPtr and MapFieldBase. Such constructors are internal
+// implementation details of the library.
+struct ConstantInitialized {
+  explicit ConstantInitialized() = default;
+};
+
+// Tag type used to invoke the arena constructor overload of classes such
+// as ExtensionSet and MapFieldLite in aggregate initialization. These
+// classes typically don't have move/copy constructors, which rules out
+// explicit initialization in pre-C++17.
+struct ArenaInitialized {
+  explicit ArenaInitialized() = default;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PORT_H__
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
new file mode 100644
index 0000000..f00daf7
--- /dev/null
+++ b/src/google/protobuf/port_def.inc
@@ -0,0 +1,928 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 common macros that are used in protobuf.
+//
+// To hide these definitions from the outside world (and to prevent collisions
+// if more than one version of protobuf is #included in the same project) you
+// must follow this pattern when #including port_def.inc in a header file:
+//
+// #include "other_header.h"
+// #include "message.h"
+// // etc.
+//
+// #include "port_def.inc"  // MUST be last header included
+//
+// // Definitions for this header.
+//
+// #include "port_undef.inc"
+//
+// This is a textual header with no include guard, because we want to
+// detect/prohibit anytime it is #included twice without a corresponding
+// #undef.
+
+// The definitions in this file are intended to be portable across Clang,
+// GCC, and MSVC. Function-like macros are usable without an #ifdef guard.
+// Syntax macros (for example, attributes) are always defined, although
+// they may be empty.
+//
+// Some definitions rely on the NDEBUG macro and/or (in MSVC) _DEBUG:
+// - https://en.cppreference.com/w/c/error/assert
+// - https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros#microsoft-specific-predefined-macros
+//
+// References for predefined macros:
+// - Standard: https://en.cppreference.com/w/cpp/preprocessor/replace
+// - Clang: https://clang.llvm.org/docs/LanguageExtensions.html
+//          (see also GCC predefined macros)
+// - GCC: https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html
+// - MSVC: https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+// - Interactive (Clang/GCC only): https://www.compiler-explorer.com/z/hc6jKd3sj
+//
+// References for attributes (and extension attributes):
+// - Standard: https://en.cppreference.com/w/cpp/language/attributes
+// - Clang: https://clang.llvm.org/docs/AttributeReference.html
+// - GCC: https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+//        (see Clang attribute docs as well)
+//
+// References for standard C++ language conformance (and minimum versions):
+// - Clang: https://clang.llvm.org/cxx_status.html
+// - GCC: https://gcc.gnu.org/projects/cxx-status.html
+// - MSVC: https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance
+//
+// Historical release notes (which can help to determine minimum versions):
+// - Clang: https://releases.llvm.org/
+// - GCC: https://gcc.gnu.org/releases.html
+// - MSVC: https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-history
+//         https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-relnotes-history
+
+// Portable fallbacks for C++20 feature test macros:
+// https://en.cppreference.com/w/cpp/feature_test
+#ifndef __has_cpp_attribute
+#define __has_cpp_attribute(x) 0
+#define PROTOBUF_has_cpp_attribute_DEFINED_
+#endif
+
+// Portable fallback for Clang's __has_feature macro:
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
+#ifndef __has_feature
+#define __has_feature(x) 0
+#define PROTOBUF_has_feature_DEFINED_
+#endif
+
+// Portable fallback for Clang's __has_warning macro:
+#ifndef __has_warning
+#define __has_warning(x) 0
+#define PROTOBUF_has_warning_DEFINED_
+#endif
+
+// Portable fallbacks for the __has_attribute macro (GCC and Clang):
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+// https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#define PROTOBUF_has_attribute_DEFINED_
+#endif
+
+// Portable fallback for __has_builtin (GCC and Clang):
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin
+// https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fbuiltin.html
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#define PROTOBUF_has_builtin_DEFINED_
+#endif
+
+// Portable PROTOBUF_BUILTIN_BSWAPxx definitions
+// Code must check for availability, e.g.: `defined(PROTOBUF_BUILTIN_BSWAP32)`
+#ifdef PROTOBUF_BUILTIN_BSWAP16
+#error PROTOBUF_BUILTIN_BSWAP16 was previously defined
+#endif
+#ifdef PROTOBUF_BUILTIN_BSWAP32
+#error PROTOBUF_BUILTIN_BSWAP32 was previously defined
+#endif
+#ifdef PROTOBUF_BUILTIN_BSWAP64
+#error PROTOBUF_BUILTIN_BSWAP64 was previously defined
+#endif
+#if defined(__GNUC__) || __has_builtin(__builtin_bswap16)
+#define PROTOBUF_BUILTIN_BSWAP16(x) __builtin_bswap16(x)
+#endif
+#if defined(__GNUC__) || __has_builtin(__builtin_bswap32)
+#define PROTOBUF_BUILTIN_BSWAP32(x) __builtin_bswap32(x)
+#endif
+#if defined(__GNUC__) || __has_builtin(__builtin_bswap64)
+#define PROTOBUF_BUILTIN_BSWAP64(x) __builtin_bswap64(x)
+#endif
+
+// Portable check for GCC minimum version:
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) \
+    && defined(__GNUC_PATCHLEVEL__)
+#  define PROTOBUF_GNUC_MIN(x, y) \
+  (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
+#else
+#  define PROTOBUF_GNUC_MIN(x, y) 0
+#endif
+
+// Portable check for MSVC minimum version:
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+#if defined(_MSC_VER)
+#define PROTOBUF_MSC_VER_MIN(x) (_MSC_VER >= x)
+#else
+#define PROTOBUF_MSC_VER_MIN(x) 0
+#endif
+
+// Portable check for minimum C++ language version:
+// https://en.cppreference.com/w/cpp/preprocessor/replace
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+#if !defined(_MSVC_LANG)
+#define PROTOBUF_CPLUSPLUS_MIN(x) (__cplusplus >= x)
+#else
+#define PROTOBUF_CPLUSPLUS_MIN(x) (_MSVC_LANG >= x)
+#endif
+
+// Future versions of protobuf will include breaking changes to some APIs.
+// This macro can be set to enable these API changes ahead of time, so that
+// user code can be updated before upgrading versions of protobuf.
+// PROTOBUF_FUTURE_FINAL is used on classes that are historically not marked as
+// final, but that may be marked final in future (breaking) releases.
+// #define PROTOBUF_FUTURE_BREAKING_CHANGES 1
+// #define PROTOBUF_FUTURE_FINAL final
+#define PROTOBUF_FUTURE_FINAL
+
+#ifdef PROTOBUF_VERSION
+#error PROTOBUF_VERSION was previously defined
+#endif
+#define PROTOBUF_VERSION 3021009
+
+#ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC
+#error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined
+#endif
+#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC 3021000
+
+#ifdef PROTOBUF_MIN_PROTOC_VERSION
+#error PROTOBUF_MIN_PROTOC_VERSION was previously defined
+#endif
+#define PROTOBUF_MIN_PROTOC_VERSION 3021000
+
+#ifdef PROTOBUF_VERSION_SUFFIX
+#error PROTOBUF_VERSION_SUFFIX was previously defined
+#endif
+#define PROTOBUF_VERSION_SUFFIX ""
+
+#if defined(PROTOBUF_NAMESPACE) || defined(PROTOBUF_NAMESPACE_ID)
+#error PROTOBUF_NAMESPACE or PROTOBUF_NAMESPACE_ID was previously defined
+#endif
+#define PROTOBUF_NAMESPACE "google::protobuf"
+#define PROTOBUF_NAMESPACE_ID google::protobuf
+#define PROTOBUF_NAMESPACE_OPEN \
+  namespace google {            \
+  namespace protobuf {
+#define PROTOBUF_NAMESPACE_CLOSE \
+  } /* namespace protobuf */     \
+  } /* namespace google */
+
+#ifdef PROTOBUF_ALWAYS_INLINE
+#error PROTOBUF_ALWAYS_INLINE was previously defined
+#endif
+// For functions we want to force inline.
+#if defined(PROTOBUF_NO_INLINE)
+# define PROTOBUF_ALWAYS_INLINE
+#elif PROTOBUF_GNUC_MIN(3, 1)
+# define PROTOBUF_ALWAYS_INLINE __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define PROTOBUF_ALWAYS_INLINE __forceinline
+#else
+# define PROTOBUF_ALWAYS_INLINE
+#endif
+
+#ifdef PROTOBUF_NDEBUG_INLINE
+#error PROTOBUF_NDEBUG_INLINE was previously defined
+#endif
+// Avoid excessive inlining in non-optimized builds. Without other optimizations
+// the inlining is not going to provide benefits anyway and the huge resulting
+// functions, especially in the proto-generated serialization functions, produce
+// stack frames so large that many tests run into stack overflows (b/32192897).
+#if defined(NDEBUG) || (defined(_MSC_VER) && !defined(_DEBUG))
+# define PROTOBUF_NDEBUG_INLINE PROTOBUF_ALWAYS_INLINE
+#else
+# define PROTOBUF_NDEBUG_INLINE
+#endif
+
+// Note that PROTOBUF_NOINLINE is an attribute applied to functions, to prevent
+// them from being inlined by the compiler. This is different from
+// PROTOBUF_NO_INLINE, which is a user-supplied macro that disables forced
+// inlining by PROTOBUF_(ALWAYS|NDEBUG)_INLINE.
+#ifdef PROTOBUF_NOINLINE
+#error PROTOBUF_NOINLINE was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 1)
+# define PROTOBUF_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+// Seems to have been around since at least Visual Studio 2005
+# define PROTOBUF_NOINLINE __declspec(noinline)
+#endif
+
+#ifdef PROTOBUF_MUSTTAIL
+#error PROTOBUF_MUSTTAIL was previously defined
+#endif
+#ifdef PROTOBUF_TAILCALL
+#error PROTOBUF_TAILCALL was previously defined
+#endif
+#if __has_cpp_attribute(clang::musttail) && !defined(__arm__) && \
+    !defined(_ARCH_PPC) && !defined(__wasm__) &&                 \
+    !(defined(_MSC_VER) && defined(_M_IX86)) &&                  \
+    !(defined(__NDK_MAJOR__) && __NDK_MAJOR <= 24)
+#  ifndef PROTO2_OPENSOURCE
+// Compilation fails on ARM32: b/195943306
+// Compilation fails on powerpc64le: b/187985113
+// Compilation fails on X86 Windows:
+// https://github.com/llvm/llvm-project/issues/53271
+#  endif
+#define PROTOBUF_MUSTTAIL [[clang::musttail]]
+#define PROTOBUF_TAILCALL true
+#else
+#define PROTOBUF_MUSTTAIL
+#define PROTOBUF_TAILCALL false
+#endif
+
+#ifdef PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED
+#error PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED was previously defined
+#endif
+#if __has_attribute(exclusive_locks_required)
+#define PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED(...) \
+  __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#else
+#define PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED(...)
+#endif
+
+#ifdef PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
+#error PROTOBUF_NO_THREAD_SAFETY_ANALYSIS was previously defined
+#endif
+#if __has_attribute(no_thread_safety_analysis)
+#define PROTOBUF_NO_THREAD_SAFETY_ANALYSIS \
+  __attribute__((no_thread_safety_analysis))
+#else
+#define PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
+#endif
+
+#ifdef PROTOBUF_GUARDED_BY
+#error PROTOBUF_GUARDED_BY was previously defined
+#endif
+#if __has_attribute(guarded_by)
+#define PROTOBUF_GUARDED_BY(x) __attribute__((guarded_by(x)))
+#else
+#define PROTOBUF_GUARDED_BY(x)
+#endif
+
+#ifdef PROTOBUF_LOCKS_EXCLUDED
+#error PROTOBUF_LOCKS_EXCLUDED was previously defined
+#endif
+#if __has_attribute(locks_excluded)
+#define PROTOBUF_LOCKS_EXCLUDED(...) \
+  __attribute__((locks_excluded(__VA_ARGS__)))
+#else
+#define PROTOBUF_LOCKS_EXCLUDED(...)
+#endif
+
+#ifdef PROTOBUF_COLD
+#error PROTOBUF_COLD was previously defined
+#endif
+#if __has_attribute(cold) || PROTOBUF_GNUC_MIN(4, 3)
+# define PROTOBUF_COLD __attribute__((cold))
+#else
+# define PROTOBUF_COLD
+#endif
+
+#ifdef PROTOBUF_SECTION_VARIABLE
+#error PROTOBUF_SECTION_VARIABLE was previously defined
+#endif
+#if (__has_attribute(section) || defined(__GNUC__)) && defined(__ELF__)
+// Place a variable in the given ELF section.
+# define PROTOBUF_SECTION_VARIABLE(x) __attribute__((section(#x)))
+#else
+# define PROTOBUF_SECTION_VARIABLE(x)
+#endif
+
+#if defined(PROTOBUF_DEPRECATED)
+#error PROTOBUF_DEPRECATED was previously defined
+#endif
+#if defined(PROTOBUF_DEPRECATED_MSG)
+#error PROTOBUF_DEPRECATED_MSG was previously defined
+#endif
+#if __has_attribute(deprecated) || PROTOBUF_GNUC_MIN(3, 0)
+# define PROTOBUF_DEPRECATED __attribute__((deprecated))
+# define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+# define PROTOBUF_DEPRECATED __declspec(deprecated)
+# define PROTOBUF_DEPRECATED_MSG(msg) __declspec(deprecated(msg))
+#else
+# define PROTOBUF_DEPRECATED
+# define PROTOBUF_DEPRECATED_MSG(msg)
+#endif
+
+#if defined(PROTOBUF_DEPRECATED_ENUM)
+#error PROTOBUF_DEPRECATED_ENUM was previously defined
+#endif
+#if defined(__clang__) || PROTOBUF_GNUC_MIN(6, 0)
+// https://gcc.gnu.org/gcc-6/changes.html
+# define PROTOBUF_DEPRECATED_ENUM __attribute__((deprecated))
+#else
+# define PROTOBUF_DEPRECATED_ENUM
+#endif
+
+#ifdef PROTOBUF_FUNC_ALIGN
+#error PROTOBUF_FUNC_ALIGN was previously defined
+#endif
+#if __has_attribute(aligned) || PROTOBUF_GNUC_MIN(4, 3)
+#define PROTOBUF_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
+#else
+#define PROTOBUF_FUNC_ALIGN(bytes)
+#endif
+
+#ifdef PROTOBUF_RETURNS_NONNULL
+#error PROTOBUF_RETURNS_NONNULL was previously defined
+#endif
+#if __has_attribute(returns_nonnull) || PROTOBUF_GNUC_MIN(4, 9)
+#define PROTOBUF_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define PROTOBUF_RETURNS_NONNULL
+#endif
+
+#ifdef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#error PROTOBUF_ATTRIBUTE_REINITIALIZES was previously defined
+#endif
+#if __has_cpp_attribute(clang::reinitializes)
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES
+#endif
+
+// The minimum library version which works with the current version of the
+// headers.
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3021000
+
+#ifdef PROTOBUF_RTTI
+#error PROTOBUF_RTTI was previously defined
+#endif
+#if defined(GOOGLE_PROTOBUF_NO_RTTI) && GOOGLE_PROTOBUF_NO_RTTI
+// A user-provided definition GOOGLE_PROTOBUF_NO_RTTI=1 disables RTTI.
+#define PROTOBUF_RTTI 0
+#elif defined(__cpp_rtti)
+// https://en.cppreference.com/w/cpp/feature_test
+#define PROTOBUF_RTTI 1
+#elif __has_feature(cxx_rtti)
+// https://clang.llvm.org/docs/LanguageExtensions.html#c-rtti
+#define PROTOBUF_RTTI 1
+#elif defined(__GXX_RTTI)
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#define PROTOBUF_RTTI 1
+#elif defined(_CPPRTTI)
+// https://docs.microsoft.com/en-us/cpp/build/reference/gr-enable-run-time-type-information
+#define PROTOBUF_RTTI 1
+#else
+#define PROTOBUF_RTTI 0
+#endif
+
+// Returns the offset of the given field within the given aggregate type.
+// This is equivalent to the ANSI C offsetof() macro.  However, according
+// to the C++ standard, offsetof() only works on POD types, and GCC
+// enforces this requirement with a warning.  In practice, this rule is
+// unnecessarily strict; there is probably no compiler or platform on
+// which the offsets of the direct fields of a class are non-constant.
+// Fields inherited from superclasses *can* have non-constant offsets,
+// but that's not what this macro will be used for.
+#ifdef PROTOBUF_FIELD_OFFSET
+#error PROTOBUF_FIELD_OFFSET was previously defined
+#endif
+#if defined(__clang__)
+// For Clang we use __builtin_offsetof() and suppress the warning,
+// to avoid Control Flow Integrity and UBSan vptr sanitizers from
+// crashing while trying to validate the invalid reinterpret_casts.
+#define PROTOBUF_FIELD_OFFSET(TYPE, FIELD)                   \
+  _Pragma("clang diagnostic push")                           \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(TYPE, FIELD)                            \
+  _Pragma("clang diagnostic pop")
+#elif PROTOBUF_GNUC_MIN(4, 8)
+#define PROTOBUF_FIELD_OFFSET(TYPE, FIELD) __builtin_offsetof(TYPE, FIELD)
+#else  // defined(__clang__)
+// Note that we calculate relative to the pointer value 16 here since if we
+// just use zero, GCC complains about dereferencing a NULL pointer.  We
+// choose 16 rather than some other number just in case the compiler would
+// be confused by an unaligned pointer.
+#define PROTOBUF_FIELD_OFFSET(TYPE, FIELD)                                \
+  static_cast< ::uint32_t>(reinterpret_cast<const char*>(                   \
+                             &reinterpret_cast<const TYPE*>(16)->FIELD) - \
+                         reinterpret_cast<const char*>(16))
+#endif
+
+#ifdef PROTOBUF_EXPORT
+#error PROTOBUF_EXPORT was previously defined
+#endif
+
+#if defined(PROTOBUF_USE_DLLS) && defined(_MSC_VER)
+# if defined(LIBPROTOBUF_EXPORTS)
+#  define PROTOBUF_EXPORT __declspec(dllexport)
+#  define PROTOBUF_EXPORT_TEMPLATE_DECLARE
+#  define PROTOBUF_EXPORT_TEMPLATE_DEFINE __declspec(dllexport)
+# else
+#  define PROTOBUF_EXPORT __declspec(dllimport)
+#  define PROTOBUF_EXPORT_TEMPLATE_DECLARE
+#  define PROTOBUF_EXPORT_TEMPLATE_DEFINE __declspec(dllimport)
+# endif  // defined(LIBPROTOBUF_EXPORTS)
+#elif defined(PROTOBUF_USE_DLLS) && defined(LIBPROTOBUF_EXPORTS)
+# define PROTOBUF_EXPORT __attribute__((visibility("default")))
+# define PROTOBUF_EXPORT_TEMPLATE_DECLARE __attribute__((visibility("default")))
+# define PROTOBUF_EXPORT_TEMPLATE_DEFINE
+#else
+# define PROTOBUF_EXPORT
+# define PROTOBUF_EXPORT_TEMPLATE_DECLARE
+# define PROTOBUF_EXPORT_TEMPLATE_DEFINE
+#endif
+
+#ifdef PROTOC_EXPORT
+#error PROTOC_EXPORT was previously defined
+#endif
+
+#if defined(PROTOBUF_USE_DLLS) && defined(_MSC_VER)
+# if defined(LIBPROTOC_EXPORTS)
+#  define PROTOC_EXPORT __declspec(dllexport)
+# else
+#  define PROTOC_EXPORT __declspec(dllimport)
+# endif  // defined(LIBPROTOC_EXPORTS)
+#elif defined(PROTOBUF_USE_DLLS) && defined(LIBPROTOC_EXPORTS)
+# define PROTOC_EXPORT __attribute__((visibility("default")))
+#else
+# define PROTOC_EXPORT
+#endif
+
+#if defined(PROTOBUF_PREDICT_TRUE) || defined(PROTOBUF_PREDICT_FALSE)
+#error PROTOBUF_PREDICT_(TRUE|FALSE) was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 0)
+# define PROTOBUF_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
+# define PROTOBUF_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
+#else
+# define PROTOBUF_PREDICT_TRUE(x) (x)
+# define PROTOBUF_PREDICT_FALSE(x) (x)
+#endif
+
+#ifdef PROTOBUF_NODISCARD
+#error PROTOBUF_NODISCARD was previously defined
+#endif
+#if __has_cpp_attribute(nodiscard) && PROTOBUF_CPLUSPLUS_MIN(201703L)
+#define PROTOBUF_NODISCARD [[nodiscard]]
+#elif __has_attribute(warn_unused_result) || PROTOBUF_GNUC_MIN(4, 8)
+#define PROTOBUF_NODISCARD __attribute__((warn_unused_result))
+#else
+#define PROTOBUF_NODISCARD
+#endif
+
+// Enable all stable experiments if this flag is set.  This allows us to group
+// all of these experiments under a single build flag, which can be enabled in
+// the protobuf.stable-experiments TAP project.
+#ifdef PROTOBUF_ENABLE_STABLE_EXPERIMENTS
+#define PROTOBUF_FORCE_MESSAGE_OWNED_ARENA
+#endif  // !PROTOBUF_ENABLE_STABLE_EXPERIMENTS
+
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+#error PROTOBUF_FORCE_COPY_IN_RELEASE was previously defined
+#endif
+
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+#error PROTOBUF_FORCE_COPY_IN_SWAP was previously defined
+#endif
+
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+#error PROTOBUF_FORCE_COPY_IN_MOVE was previously defined
+#endif
+
+#ifdef PROTOBUF_FORCE_RESET_IN_CLEAR
+#error PROTOBUF_FORCE_RESET_IN_CLEAR was previously defined
+#endif
+
+// Force copy the default string to a string field so that non-optimized builds
+// have harder-to-rely-on address stability.
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+#error PROTOBUF_FORCE_COPY_DEFAULT_STRING was previously defined
+#endif
+
+#ifdef PROTOBUF_FALLTHROUGH_INTENDED
+#error PROTOBUF_FALLTHROUGH_INTENDED was previously defined
+#endif
+#if __has_cpp_attribute(fallthrough)
+#define PROTOBUF_FALLTHROUGH_INTENDED [[fallthrough]]
+#elif __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define PROTOBUF_FALLTHROUGH_INTENDED [[clang::fallthrough]]
+#elif PROTOBUF_GNUC_MIN(7, 0)
+#define PROTOBUF_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
+#else
+#define PROTOBUF_FALLTHROUGH_INTENDED
+#endif
+
+// PROTOBUF_ASSUME(pred) tells the compiler that it can assume pred is true. To
+// be safe, we also validate the assumption with a GOOGLE_DCHECK in unoptimized
+// builds. The macro does not do anything useful if the compiler does not
+// support __builtin_assume.
+#ifdef PROTOBUF_ASSUME
+#error PROTOBUF_ASSUME was previously defined
+#endif
+#if __has_builtin(__builtin_assume)
+#define PROTOBUF_ASSUME(pred) \
+  GOOGLE_DCHECK(pred);               \
+  __builtin_assume(pred)
+#else
+#define PROTOBUF_ASSUME(pred) GOOGLE_DCHECK(pred)
+#endif
+
+// Specify memory alignment for structs, classes, etc.
+// Use like:
+//   class PROTOBUF_ALIGNAS(16) MyClass { ... }
+//   PROTOBUF_ALIGNAS(16) int array[4];
+//
+// In most places you can use the C++11 keyword "alignas", which is preferred.
+//
+// But compilers have trouble mixing __attribute__((...)) syntax with
+// alignas(...) syntax.
+//
+// Doesn't work in clang or gcc:
+//   struct alignas(16) __attribute__((packed)) S { char c; };
+// Works in clang but not gcc:
+//   struct __attribute__((packed)) alignas(16) S2 { char c; };
+// Works in clang and gcc:
+//   struct alignas(16) S3 { char c; } __attribute__((packed));
+//
+// There are also some attributes that must be specified *before* a class
+// definition: visibility (used for exporting functions/classes) is one of
+// these attributes. This means that it is not possible to use alignas() with a
+// class that is marked as exported.
+#ifdef PROTOBUF_ALIGNAS
+#error PROTOBUF_ALIGNAS was previously defined
+#endif
+#if defined(_MSC_VER)
+#define PROTOBUF_ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#elif PROTOBUF_GNUC_MIN(3, 0)
+#define PROTOBUF_ALIGNAS(byte_alignment) \
+  __attribute__((aligned(byte_alignment)))
+#else
+#define PROTOBUF_ALIGNAS(byte_alignment) alignas(byte_alignment)
+#endif
+
+#ifdef PROTOBUF_FINAL
+#error PROTOBUF_FINAL was previously defined
+#endif
+#define PROTOBUF_FINAL final
+
+#ifdef PROTOBUF_THREAD_LOCAL
+#error PROTOBUF_THREAD_LOCAL was previously defined
+#endif
+#if defined(_MSC_VER)
+#define PROTOBUF_THREAD_LOCAL __declspec(thread)
+#else
+#define PROTOBUF_THREAD_LOCAL __thread
+#endif
+
+// TODO(b/228173843): cleanup PROTOBUF_LITTLE_ENDIAN in various 3p forks.
+#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+     __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define PROTOBUF_LITTLE_ENDIAN 1
+#ifdef PROTOBUF_BIG_ENDIAN
+#error Conflicting PROTOBUF_BIG_ENDIAN was previously defined
+#endif
+#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
+    __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define PROTOBUF_BIG_ENDIAN 1
+#elif defined(_WIN32) || defined(__x86_64__) || defined(__aarch64__)
+#define PROTOBUF_LITTLE_ENDIAN 1
+#else
+#error "endian detection failed for current compiler"
+#endif
+
+// For enabling message owned arena, one major blocker is semantic change from
+// moving to copying when there is ownership transfer (e.g., move ctor, swap,
+// set allocated, release). This change not only causes performance regression
+// but also breaks users code (e.g., dangling reference). For top-level
+// messages, since it owns the arena, we can mitigate the issue by transferring
+// ownership of arena. However, we cannot do that for nested messages. In order
+// to tell how many usages of nested messages affected by message owned arena,
+// we need to simulate the arena ownership.
+// This experiment is purely for the purpose of gathering data. All code guarded
+// by this flag is supposed to be removed after this experiment.
+#define PROTOBUF_MESSAGE_OWNED_ARENA_EXPERIMENT
+#ifdef PROTOBUF_CONSTINIT
+#error PROTOBUF_CONSTINIT was previously defined
+#endif
+#if defined(__cpp_constinit) && !defined(_MSC_VER)
+#define PROTOBUF_CONSTINIT constinit
+#define PROTOBUF_CONSTEXPR constexpr
+// Some older Clang versions incorrectly raise an error about
+// constant-initializing weak default instance pointers. Versions 12.0 and
+// higher seem to work, except that XCode 12.5.1 shows the error even though it
+// uses Clang 12.0.5.
+// Clang-cl on Windows raises error also.
+#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization) && \
+    ((defined(__APPLE__) && __clang_major__ >= 13) ||                \
+     (!defined(__APPLE__) && __clang_major__ >= 12))
+#define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
+#define PROTOBUF_CONSTEXPR constexpr
+#elif PROTOBUF_GNUC_MIN(12, 2)
+#define PROTOBUF_CONSTINIT __constinit
+#define PROTOBUF_CONSTEXPR constexpr
+// MSVC 17 currently seems to raise an error about constant-initialized pointers.
+#elif defined(_MSC_VER) && _MSC_VER >= 1930
+#define PROTOBUF_CONSTINIT
+#define PROTOBUF_CONSTEXPR constexpr
+#else
+#define PROTOBUF_CONSTINIT
+#define PROTOBUF_CONSTEXPR
+#endif
+
+// Some globals with an empty non-trivial destructor are annotated with
+// no_destroy for performance reasons. It reduces the cost of these globals in
+// non-opt mode and under sanitizers.
+#ifdef PROTOBUF_ATTRIBUTE_NO_DESTROY
+#error PROTOBUF_ATTRIBUTE_NO_DESTROY was previously defined
+#endif
+#if __has_cpp_attribute(clang::no_destroy)
+#define PROTOBUF_ATTRIBUTE_NO_DESTROY [[clang::no_destroy]]
+#else
+#define PROTOBUF_ATTRIBUTE_NO_DESTROY
+#endif
+
+// Force clang to always emit complete debug info for a type.
+// Clang uses constructor homing to determine when to emit debug info for a
+// type. If the constructor of a type is never used, which can happen in some
+// cases where member variables are constructed in place for optimization
+// purposes (see b/208803175 for an example), the type will have incomplete
+// debug info unless this attribute is used.
+#ifdef PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#error PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG was previously defined
+#endif
+#if __has_cpp_attribute(clang::standalone_debug)
+#define PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG [[clang::standalone_debug]]
+#else
+#define PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#endif
+
+// Protobuf extensions and reflection require registration of the protos linked
+// in the binary. Not until everything is registered does the runtime have a
+// complete view on all protos. When code is using reflection or extensions
+// in between registration calls this can lead to surprising behavior. By
+// having the registration run first we mitigate this scenario.
+// Highest priority is 101. We use 102 for registration, to allow code that
+// really wants to higher priority to still beat us. Some initialization happens
+// at higher priority, though, since it is needed before registration.
+#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 was previously defined
+#endif
+#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 0) && (!defined(__APPLE__) || defined(__clang__)) && \
+    !((defined(sun) || defined(__sun)) &&                                     \
+      (defined(__SVR4) || defined(__svr4__)))
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 __attribute__((init_priority((101))))
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 __attribute__((init_priority((102))))
+#else
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#endif
+
+#ifdef PROTOBUF_PRAGMA_INIT_SEG
+#error PROTOBUF_PRAGMA_INIT_SEG was previously defined
+#endif
+#ifdef _MSC_VER
+#define PROTOBUF_PRAGMA_INIT_SEG __pragma(init_seg(lib))
+#else
+#define PROTOBUF_PRAGMA_INIT_SEG
+#endif
+
+#ifdef PROTOBUF_ATTRIBUTE_WEAK
+#error PROTOBUF_ATTRIBUTE_WEAK was previously defined
+#endif
+#if __has_attribute(weak) && \
+    !defined(__APPLE__) && \
+    (!defined(_WIN32) || __clang_major__ < 9) && \
+    !defined(__MINGW32__)
+#define PROTOBUF_ATTRIBUTE_WEAK __attribute__((weak))
+#define PROTOBUF_HAVE_ATTRIBUTE_WEAK 1
+#else
+#define PROTOBUF_ATTRIBUTE_WEAK
+#define PROTOBUF_HAVE_ATTRIBUTE_WEAK 0
+#endif
+
+// Macros to detect sanitizers.
+#ifdef PROTOBUF_ASAN
+#error PROTOBUF_ASAN was previously defined
+#endif
+#ifdef PROTOBUF_MSAN
+#error PROTOBUF_MSAN was previously defined
+#endif
+#ifdef PROTOBUF_TSAN
+#error PROTOBUF_TSAN was previously defined
+#endif
+#if defined(__clang__)
+#  if __has_feature(address_sanitizer)
+#    define PROTOBUF_ASAN 1
+#  endif
+#  if __has_feature(thread_sanitizer)
+#    define PROTOBUF_TSAN 1
+#  endif
+#  if __has_feature(memory_sanitizer)
+#    define PROTOBUF_MSAN 1
+#  endif
+#elif PROTOBUF_GNUC_MIN(3, 0)
+// Double-guard is needed for -Wundef:
+#  ifdef __SANITIZE_ADDRESS__
+#  if    __SANITIZE_ADDRESS__
+#    define PROTOBUF_ASAN 1
+#  endif
+#  endif
+#  ifdef __SANITIZE_THREAD__
+#  if    __SANITIZE_THREAD__
+#    define PROTOBUF_TSAN 1
+#  endif
+#  endif
+#endif
+
+// Tail call table-driven parsing can be enabled by defining
+// PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER at compilation time. Note
+// that this macro is for small-scale testing only, and is not supported.
+#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
+#error PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED was previously declared
+#endif
+#if defined(PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER)
+#define PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED 1
+#endif
+
+#define PROTOBUF_TC_PARAM_DECL                                 \
+  ::google::protobuf::MessageLite *msg, const char *ptr,                 \
+      ::google::protobuf::internal::ParseContext *ctx,                   \
+      const ::google::protobuf::internal::TcParseTableBase *table,       \
+      uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
+
+#ifdef PROTOBUF_UNUSED
+#error PROTOBUF_UNUSED was previously defined
+#endif
+#if __has_cpp_attribute(maybe_unused) || \
+    (PROTOBUF_MSC_VER_MIN(1911) && PROTOBUF_CPLUSPLUS_MIN(201703L))
+#define PROTOBUF_UNUSED [[maybe_unused]]
+#elif __has_attribute(unused) || PROTOBUF_GNUC_MIN(3, 0)
+#define PROTOBUF_UNUSED __attribute__((__unused__))
+#else
+#define PROTOBUF_UNUSED
+#endif
+
+// ThreadSafeArenaz is turned off completely in opensource builds.
+
+// Windows declares several inconvenient macro names.  We #undef them and then
+// restore them in port_undef.inc.
+#ifdef _MSC_VER
+#pragma push_macro("CREATE_NEW")
+#undef CREATE_NEW
+#pragma push_macro("DELETE")
+#undef DELETE
+#pragma push_macro("DOUBLE_CLICK")
+#undef DOUBLE_CLICK
+#pragma push_macro("ERROR")
+#undef ERROR
+#pragma push_macro("ERROR_BUSY")
+#undef ERROR_BUSY
+#pragma push_macro("ERROR_INSTALL_FAILED")
+#undef ERROR_INSTALL_FAILED
+#pragma push_macro("ERROR_NOT_FOUND")
+#undef ERROR_NOT_FOUND
+#pragma push_macro("GetClassName")
+#undef GetClassName
+#pragma push_macro("GetMessage")
+#undef GetMessage
+#pragma push_macro("GetObject")
+#undef GetObject
+#pragma push_macro("IGNORE")
+#undef IGNORE
+#pragma push_macro("IN")
+#undef IN
+#pragma push_macro("INPUT_KEYBOARD")
+#undef INPUT_KEYBOARD
+#pragma push_macro("NO_ERROR")
+#undef NO_ERROR
+#pragma push_macro("OUT")
+#undef OUT
+#pragma push_macro("OPTIONAL")
+#undef OPTIONAL
+#pragma push_macro("min")
+#undef min
+#pragma push_macro("max")
+#undef max
+#pragma push_macro("NEAR")
+#undef NEAR
+#pragma push_macro("NO_DATA")
+#undef NO_DATA
+#pragma push_macro("REASON_UNKNOWN")
+#undef REASON_UNKNOWN
+#pragma push_macro("SERVICE_DISABLED")
+#undef SERVICE_DISABLED
+#pragma push_macro("SEVERITY_ERROR")
+#undef SEVERITY_ERROR
+#pragma push_macro("STATUS_PENDING")
+#undef STATUS_PENDING
+#pragma push_macro("STRICT")
+#undef STRICT
+#pragma push_macro("timezone")
+#undef timezone
+#endif  // _MSC_VER
+
+#ifdef __APPLE__
+// Inconvenient macro names from usr/include/math.h in some macOS SDKs.
+#pragma push_macro("DOMAIN")
+#undef DOMAIN
+// Inconvenient macro names from /usr/include/mach/boolean.h in some macOS SDKs.
+#pragma push_macro("TRUE")
+#undef TRUE
+#pragma push_macro("FALSE")
+#undef FALSE
+// Inconvenient macro names from usr/include/sys/syslimits.h in some macOS SDKs.
+#pragma push_macro("UID_MAX")
+#undef UID_MAX
+#endif  // __APPLE__
+
+#if defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER)
+// Don't let Objective-C Macros interfere with proto identifiers with the same
+// name.
+#pragma push_macro("DEBUG")
+#undef DEBUG
+#endif // defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER)
+
+#if PROTOBUF_GNUC_MIN(3, 0)
+// GCC does not allow disabling diagnostics within an expression:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60875, so we disable this one
+// globally even though it's only used for PROTOBUF_FIELD_OFFSET.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+// Silence some MSVC warnings in all our code.
+#ifdef _MSC_VER
+#pragma warning(push)
+// For non-trivial unions
+#pragma warning(disable : 4582)
+#pragma warning(disable : 4583)
+// For init_seg(lib)
+#pragma warning(disable : 4073)
+// To silence the fact that we will pop this push from another file
+#pragma warning(disable : 5031)
+// Conditional expression is constant
+#pragma warning(disable: 4127)
+// decimal digit terminates octal escape sequence
+#pragma warning(disable: 4125)
+#endif
+
+// We don't want code outside port_def doing complex testing, so
+// remove our portable condition test macros to nudge folks away from
+// using it themselves.
+#ifdef PROTOBUF_has_cpp_attribute_DEFINED_
+#  undef __has_cpp_attribute
+#  undef PROTOBUF_has_cpp_attribute_DEFINED_
+#endif
+#ifdef PROTOBUF_has_feature_DEFINED_
+#  undef __has_feature
+#  undef PROTOBUF_has_feature_DEFINED_
+#endif
+#ifdef PROTOBUF_has_warning_DEFINED_
+#  undef __has_warning
+#  undef PROTOBUF_has_warning_DEFINED_
+#endif
+#ifdef PROTOBUF_has_attribute_DEFINED_
+#  undef __has_attribute
+#  undef PROTOBUF_has_attribute_DEFINED_
+#endif
+#ifdef PROTOBUF_has_builtin_DEFINED_
+#  undef __has_builtin
+#  undef PROTOBUF_has_builtin_DEFINED_
+#endif
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
new file mode 100644
index 0000000..e880fa5
--- /dev/null
+++ b/src/google/protobuf/port_undef.inc
@@ -0,0 +1,160 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// #undefs all macros defined in port_def.inc.  See comments in port_def.inc
+// for more info.
+
+#ifndef PROTOBUF_NAMESPACE
+#error "port_undef.inc must be included after port_def.inc"
+#endif
+
+#undef PROTOBUF_BUILTIN_BSWAP16
+#undef PROTOBUF_BUILTIN_BSWAP32
+#undef PROTOBUF_BUILTIN_BSWAP64
+#undef PROTOBUF_GNUC_MIN
+#undef PROTOBUF_MSC_VER_MIN
+#undef PROTOBUF_CPLUSPLUS_MIN
+#undef PROTOBUF_NAMESPACE
+#undef PROTOBUF_NAMESPACE_ID
+#undef PROTOBUF_ALWAYS_INLINE
+#undef PROTOBUF_NDEBUG_INLINE
+#undef PROTOBUF_MUSTTAIL
+#undef PROTOBUF_TAILCALL
+#undef PROTOBUF_COLD
+#undef PROTOBUF_NOINLINE
+#undef PROTOBUF_SECTION_VARIABLE
+#undef PROTOBUF_DEPRECATED
+#undef PROTOBUF_DEPRECATED_ENUM
+#undef PROTOBUF_DEPRECATED_MSG
+#undef PROTOBUF_FUNC_ALIGN
+#undef PROTOBUF_RETURNS_NONNULL
+#undef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#undef PROTOBUF_RTTI
+#undef PROTOBUF_VERSION
+#undef PROTOBUF_VERSION_SUFFIX
+#undef PROTOBUF_FIELD_OFFSET
+#undef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC
+#undef PROTOBUF_MIN_PROTOC_VERSION
+#undef PROTOBUF_PREDICT_TRUE
+#undef PROTOBUF_PREDICT_FALSE
+#undef PROTOBUF_FALLTHROUGH_INTENDED
+#undef PROTOBUF_EXPORT
+#undef PROTOC_EXPORT
+#undef PROTOBUF_NODISCARD
+#undef PROTOBUF_FORCE_COPY_IN_RELEASE
+#undef PROTOBUF_FORCE_COPY_IN_SWAP
+#undef PROTOBUF_FORCE_COPY_IN_MOVE
+#undef PROTOBUF_FORCE_RESET_IN_CLEAR
+#undef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+#undef PROTOBUF_NAMESPACE_OPEN
+#undef PROTOBUF_NAMESPACE_CLOSE
+#undef PROTOBUF_UNUSED
+#undef PROTOBUF_ASSUME
+#undef PROTOBUF_EXPORT_TEMPLATE_DECLARE
+#undef PROTOBUF_EXPORT_TEMPLATE_DEFINE
+#undef PROTOBUF_ALIGNAS
+#undef PROTOBUF_FINAL
+#undef PROTOBUF_FUTURE_FINAL
+#undef PROTOBUF_THREAD_LOCAL
+#undef PROTOBUF_LITTLE_ENDIAN
+#undef PROTOBUF_BIG_ENDIAN
+#undef PROTOBUF_MESSAGE_OWNED_ARENA_EXPERIMENT
+#undef PROTOBUF_CONSTINIT
+#undef PROTOBUF_CONSTEXPR
+#undef PROTOBUF_ATTRIBUTE_WEAK
+#undef PROTOBUF_HAVE_ATTRIBUTE_WEAK
+#undef PROTOBUF_ATTRIBUTE_NO_DESTROY
+#undef PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#undef PROTOBUF_PRAGMA_INIT_SEG
+#undef PROTOBUF_ASAN
+#undef PROTOBUF_MSAN
+#undef PROTOBUF_TSAN
+#undef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
+#undef PROTOBUF_TC_PARAM_DECL
+#undef PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED
+#undef PROTOBUF_LOCKS_EXCLUDED
+#undef PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
+#undef PROTOBUF_GUARDED_BY
+
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+#undef PROTOBUF_FUTURE_BREAKING_CHANGES
+#endif
+
+// Restore macro that may have been #undef'd in port_def.inc.
+#ifdef _MSC_VER
+#pragma pop_macro("CREATE_NEW")
+#pragma pop_macro("DELETE")
+#pragma pop_macro("DOUBLE_CLICK")
+#pragma pop_macro("ERROR")
+#pragma pop_macro("ERROR_BUSY")
+#pragma pop_macro("ERROR_INSTALL_FAILED")
+#pragma pop_macro("ERROR_NOT_FOUND")
+#pragma pop_macro("GetClassName")
+#pragma pop_macro("GetMessage")
+#pragma pop_macro("GetObject")
+#pragma pop_macro("IGNORE")
+#pragma pop_macro("IN")
+#pragma pop_macro("INPUT_KEYBOARD")
+#pragma pop_macro("OUT")
+#pragma pop_macro("OPTIONAL")
+#pragma pop_macro("min")
+#pragma pop_macro("max")
+#pragma pop_macro("NEAR")
+#pragma pop_macro("NO_DATA")
+#pragma pop_macro("NO_ERROR")
+#pragma pop_macro("REASON_UNKNOWN")
+#pragma pop_macro("SERVICE_DISABLED")
+#pragma pop_macro("SEVERITY_ERROR")
+#pragma pop_macro("STRICT")
+#pragma pop_macro("STATUS_PENDING")
+#pragma pop_macro("timezone")
+#endif
+
+#ifdef __APPLE__
+#pragma pop_macro("DOMAIN")
+#pragma pop_macro("TRUE")
+#pragma pop_macro("FALSE")
+#pragma pop_macro("UID_MAX")
+#endif  // __APPLE__
+
+#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
+#pragma pop_macro("DEBUG")
+#endif // defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+// Pop the warning(push) from port_def.inc
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/src/google/protobuf/preserve_unknown_enum_test.cc b/src/google/protobuf/preserve_unknown_enum_test.cc
new file mode 100644
index 0000000..7e6bbf1
--- /dev/null
+++ b/src/google/protobuf/preserve_unknown_enum_test.cc
@@ -0,0 +1,290 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_preserve_unknown_enum.pb.h>
+#include <google/protobuf/unittest_preserve_unknown_enum2.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+void FillMessage(
+    proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra* message) {
+  message->set_e(proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->add_repeated_e(proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->add_repeated_packed_e(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->add_repeated_packed_unexpected_e(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->set_oneof_e_1(proto3_preserve_unknown_enum_unittest::E_EXTRA);
+}
+
+void CheckMessage(
+    const proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra& message) {
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA, message.e());
+  EXPECT_EQ(1, message.repeated_e_size());
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.repeated_e(0));
+  EXPECT_EQ(1, message.repeated_packed_e_size());
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.repeated_packed_e(0));
+  EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.repeated_packed_unexpected_e(0));
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.oneof_e_1());
+}
+
+void CheckMessage(
+    const proto3_preserve_unknown_enum_unittest::MyMessage& message) {
+  EXPECT_EQ(static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.e()));
+  EXPECT_EQ(1, message.repeated_e_size());
+  EXPECT_EQ(static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.repeated_e(0)));
+  EXPECT_EQ(1, message.repeated_packed_e_size());
+  EXPECT_EQ(static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.repeated_packed_e(0)));
+  EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
+  EXPECT_EQ(static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.repeated_packed_unexpected_e(0)));
+  EXPECT_EQ(static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.oneof_e_1()));
+}
+
+}  // anonymous namespace
+
+// Test that parsing preserves an unknown value in the enum field and does not
+// punt it to the UnknownFieldSet.
+TEST(PreserveUnknownEnumTest, PreserveParseAndSerialize) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+  std::string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  proto3_preserve_unknown_enum_unittest::MyMessage message;
+  EXPECT_EQ(true, message.ParseFromString(serialized));
+  CheckMessage(message);
+
+  serialized.clear();
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Test that reflection based implementation also keeps unknown enum values and
+// doesn't put them into UnknownFieldSet.
+TEST(PreserveUnknownEnumTest, PreserveParseAndSerializeDynamicMessage) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+  std::string serialized = orig_message.SerializeAsString();
+
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message(
+      factory
+          .GetPrototype(
+              proto3_preserve_unknown_enum_unittest::MyMessage::descriptor())
+          ->New());
+  EXPECT_EQ(true, message->ParseFromString(serialized));
+  message->DiscardUnknownFields();
+
+  serialized = message->SerializeAsString();
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Test that for proto2 messages, unknown values are in unknown fields.
+TEST(PreserveUnknownEnumTest, Proto2HidesUnknownValues) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+
+  std::string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  proto2_preserve_unknown_enum_unittest::MyMessage message;
+  EXPECT_EQ(true, message.ParseFromString(serialized));
+  // The intermediate message has everything in its "unknown fields".
+  proto2_preserve_unknown_enum_unittest::MyMessage message2 = message;
+  message2.DiscardUnknownFields();
+  EXPECT_EQ(0, message2.ByteSizeLong());
+
+  // But when we pass it to the correct structure, all values are there.
+  serialized.clear();
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Same as before, for a dynamic message.
+TEST(PreserveUnknownEnumTest, DynamicProto2HidesUnknownValues) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+
+  std::string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message(
+      factory
+          .GetPrototype(
+              proto2_preserve_unknown_enum_unittest::MyMessage::descriptor())
+          ->New());
+  EXPECT_EQ(true, message->ParseFromString(serialized));
+  // The intermediate message has everything in its "unknown fields".
+  proto2_preserve_unknown_enum_unittest::MyMessage message2;
+  message2.CopyFrom(*message);
+  message2.DiscardUnknownFields();
+  EXPECT_EQ(0, message2.ByteSizeLong());
+
+  // But when we pass it to the correct structure, all values are there.
+  serialized.clear();
+  message->SerializeToString(&serialized);
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Test that reflection provides EnumValueDescriptors for unknown values.
+TEST(PreserveUnknownEnumTest, DynamicEnumValueDescriptors) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+  std::string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  proto3_preserve_unknown_enum_unittest::MyMessage message;
+  EXPECT_EQ(true, message.ParseFromString(serialized));
+  CheckMessage(message);
+
+  const Reflection* r = message.GetReflection();
+  const Descriptor* d = message.GetDescriptor();
+  const FieldDescriptor* field = d->FindFieldByName("e");
+
+  // This should dynamically create an EnumValueDescriptor.
+  const EnumValueDescriptor* enum_value = r->GetEnum(message, field);
+  EXPECT_EQ(enum_value->number(),
+            static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA));
+
+  // Fetching value for a second time should return the same pointer.
+  const EnumValueDescriptor* enum_value_second = r->GetEnum(message, field);
+  EXPECT_EQ(enum_value, enum_value_second);
+
+  // Check the repeated case too.
+  const FieldDescriptor* repeated_field = d->FindFieldByName("repeated_e");
+  enum_value = r->GetRepeatedEnum(message, repeated_field, 0);
+  EXPECT_EQ(enum_value->number(),
+            static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA));
+  // Should reuse the same EnumValueDescriptor, even for a different field.
+  EXPECT_EQ(enum_value, enum_value_second);
+
+  // We should be able to use the returned value descriptor to set a value on
+  // another message.
+  Message* m = message.New();
+  r->SetEnum(m, field, enum_value);
+  EXPECT_EQ(enum_value, r->GetEnum(*m, field));
+  delete m;
+}
+
+// Test that the new integer-based enum reflection API works.
+TEST(PreserveUnknownEnumTest, IntegerEnumReflectionAPI) {
+  proto3_preserve_unknown_enum_unittest::MyMessage message;
+  const Reflection* r = message.GetReflection();
+  const Descriptor* d = message.GetDescriptor();
+
+  const FieldDescriptor* singular_field = d->FindFieldByName("e");
+  const FieldDescriptor* repeated_field = d->FindFieldByName("repeated_e");
+
+  r->SetEnumValue(&message, singular_field, 42);
+  EXPECT_EQ(42, r->GetEnumValue(message, singular_field));
+  r->AddEnumValue(&message, repeated_field, 42);
+  r->AddEnumValue(&message, repeated_field, 42);
+  EXPECT_EQ(42, r->GetRepeatedEnumValue(message, repeated_field, 0));
+  r->SetRepeatedEnumValue(&message, repeated_field, 1, 84);
+  EXPECT_EQ(84, r->GetRepeatedEnumValue(message, repeated_field, 1));
+  const EnumValueDescriptor* enum_value = r->GetEnum(message, singular_field);
+  EXPECT_EQ(42, enum_value->number());
+}
+
+// Test that the EnumValue API works properly for proto2 messages as well.
+TEST(PreserveUnknownEnumTest, Proto2CatchesUnknownValues) {
+  protobuf_unittest::TestAllTypes message;  // proto2 message
+  const Reflection* r = message.GetReflection();
+  const Descriptor* d = message.GetDescriptor();
+  const FieldDescriptor* repeated_field =
+      d->FindFieldByName("repeated_nested_enum");
+  // Add one element to the repeated field so that we can test
+  // SetRepeatedEnumValue.
+  const EnumValueDescriptor* enum_value =
+      repeated_field->enum_type()->FindValueByName("BAR");
+  EXPECT_TRUE(enum_value != nullptr);
+  r->AddEnum(&message, repeated_field, enum_value);
+
+  const FieldDescriptor* singular_field =
+      d->FindFieldByName("optional_nested_enum");
+  // Enum-field integer-based setters treat as unknown integer values as
+  // unknown fields.
+  r->SetEnumValue(&message, singular_field, 4242);
+  EXPECT_EQ(r->GetEnum(message, singular_field)->number(),
+            protobuf_unittest::TestAllTypes::FOO);
+  r->SetRepeatedEnumValue(&message, repeated_field, 0, 4242);
+  // repeated_nested_enum was set to bar above, this should not have changed.
+  EXPECT_EQ(r->GetRepeatedEnum(message, repeated_field, 0)->number(),
+            protobuf_unittest::TestAllTypes::BAR);
+  r->AddEnumValue(&message, repeated_field, 4242);
+  // No element should be added
+  EXPECT_EQ(message.repeated_nested_enum_size(), 1);
+
+  // We require the enums to end up in unknown field set
+  ASSERT_EQ(message.unknown_fields().field_count(), 3);
+  EXPECT_EQ(message.unknown_fields().field(0).number(),
+            singular_field->number());
+  EXPECT_EQ(message.unknown_fields().field(0).varint(), 4242);
+  EXPECT_EQ(message.unknown_fields().field(1).number(),
+            repeated_field->number());
+  EXPECT_EQ(message.unknown_fields().field(1).varint(), 4242);
+  EXPECT_EQ(message.unknown_fields().field(2).number(),
+            repeated_field->number());
+  EXPECT_EQ(message.unknown_fields().field(2).varint(), 4242);
+}
+
+TEST(PreserveUnknownEnumTest, SupportsUnknownEnumValuesAPI) {
+  protobuf_unittest::TestAllTypes proto2_message;
+  proto3_preserve_unknown_enum_unittest::MyMessage new_message;
+
+  const Reflection* proto2_reflection = proto2_message.GetReflection();
+  const Reflection* new_reflection = new_message.GetReflection();
+
+  EXPECT_FALSE(proto2_reflection->SupportsUnknownEnumValues());
+  EXPECT_TRUE(new_reflection->SupportsUnknownEnumValues());
+}
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_arena_lite_unittest.cc b/src/google/protobuf/proto3_arena_lite_unittest.cc
new file mode 100644
index 0000000..06b8d08
--- /dev/null
+++ b/src/google/protobuf/proto3_arena_lite_unittest.cc
@@ -0,0 +1,152 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <string>
+#include <vector>
+
+#include <google/protobuf/unittest_proto3_arena.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+using proto3_arena_unittest::TestAllTypes;
+
+namespace google {
+namespace protobuf {
+namespace {
+// We selectively set/check a few representative fields rather than all fields
+// as this test is only expected to cover the basics of arena support.
+void SetAllFields(TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->set_optional_nested_enum(proto3_arena_unittest::TestAllTypes::BAZ);
+  m->set_optional_foreign_enum(proto3_arena_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->add_repeated_int32(100);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_nested_enum(proto3_arena_unittest::TestAllTypes::BAZ);
+  m->add_repeated_foreign_enum(proto3_arena_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void ExpectAllFieldsSet(const TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::BAZ, m.optional_nested_enum());
+  EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ, m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ, m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+// In this file we only test some basic functionalities of arena support in
+// proto3 and expect the arena support to be fully tested in proto2 unittests
+// because proto3 shares most code with proto2.
+
+TEST(Proto3ArenaLiteTest, Parsing) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(*arena_message);
+}
+
+TEST(Proto3ArenaLiteTest, Swap) {
+  Arena arena1;
+  Arena arena2;
+
+  // Test Swap().
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+}
+
+TEST(Proto3ArenaLiteTest, SetAllocatedMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
+  nested->set_bb(118);
+  arena_message->set_allocated_optional_nested_message(nested);
+  EXPECT_EQ(118, arena_message->optional_nested_message().bb());
+}
+
+TEST(Proto3ArenaLiteTest, ReleaseMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  std::unique_ptr<TestAllTypes::NestedMessage> nested(
+      arena_message->release_optional_nested_message());
+  EXPECT_EQ(118, nested->bb());
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc
new file mode 100644
index 0000000..cfbe198
--- /dev/null
+++ b/src/google/protobuf/proto3_arena_unittest.cc
@@ -0,0 +1,635 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <string>
+#include <vector>
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_arena.pb.h>
+#include <google/protobuf/unittest_proto3_optional.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/test_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+using proto3_arena_unittest::ForeignMessage;
+using proto3_arena_unittest::TestAllTypes;
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+class Proto3ArenaTestHelper {
+ public:
+  template <typename T>
+  static Arena* GetOwningArena(const T& msg) {
+    return msg.GetOwningArena();
+  }
+};
+
+}  // namespace internal
+
+namespace {
+// We selectively set/check a few representative fields rather than all fields
+// as this test is only expected to cover the basics of arena support.
+void SetAllFields(TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->set_optional_nested_enum(proto3_arena_unittest::TestAllTypes::BAZ);
+  m->set_optional_foreign_enum(proto3_arena_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->mutable_optional_unverified_lazy_message()->set_bb(46);
+  m->add_repeated_int32(100);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_nested_enum(proto3_arena_unittest::TestAllTypes::BAZ);
+  m->add_repeated_foreign_enum(proto3_arena_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void ExpectAllFieldsSet(const TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::BAZ, m.optional_nested_enum());
+  EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ, m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+  EXPECT_EQ(true, m.has_optional_unverified_lazy_message());
+  EXPECT_EQ(46, m.optional_unverified_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ, m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+// In this file we only test some basic functionalities of arena support in
+// proto3 and expect the arena support to be fully tested in proto2 unittests
+// because proto3 shares most code with proto2.
+
+TEST(Proto3ArenaTest, Parsing) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(*arena_message);
+}
+
+TEST(Proto3ArenaTest, UnknownFields) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(*arena_message);
+
+  // In proto3 we can still get a pointer to the UnknownFieldSet through
+  // reflection API.
+  UnknownFieldSet* unknown_fields =
+      arena_message->GetReflection()->MutableUnknownFields(arena_message);
+  // We can modify this UnknownFieldSet.
+  unknown_fields->AddVarint(1, 2);
+  // And the unknown fields should be changed.
+  ASSERT_NE(original.ByteSizeLong(), arena_message->ByteSizeLong());
+  ASSERT_FALSE(
+      arena_message->GetReflection()->GetUnknownFields(*arena_message).empty());
+}
+
+TEST(Proto3ArenaTest, GetArena) {
+  Arena arena;
+
+  // Tests arena-allocated message and submessages.
+  auto* arena_message1 = Arena::CreateMessage<TestAllTypes>(&arena);
+  auto* arena_submessage1 = arena_message1->mutable_optional_foreign_message();
+  auto* arena_repeated_submessage1 =
+      arena_message1->add_repeated_foreign_message();
+  EXPECT_EQ(&arena, arena_message1->GetArena());
+  EXPECT_EQ(&arena, arena_submessage1->GetArena());
+  EXPECT_EQ(&arena, arena_repeated_submessage1->GetArena());
+
+  // Tests attached heap-allocated messages.
+  auto* arena_message2 = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message2->set_allocated_optional_foreign_message(new ForeignMessage());
+  arena_message2->mutable_repeated_foreign_message()->AddAllocated(
+      new ForeignMessage());
+  const auto& submessage2 = arena_message2->optional_foreign_message();
+  const auto& repeated_submessage2 =
+      arena_message2->repeated_foreign_message(0);
+  EXPECT_EQ(nullptr, submessage2.GetArena());
+  EXPECT_EQ(nullptr, repeated_submessage2.GetArena());
+
+  // Tests message created by Arena::Create.
+  auto* arena_message3 = Arena::Create<TestAllTypes>(&arena);
+  EXPECT_EQ(nullptr, arena_message3->GetArena());
+}
+
+TEST(Proto3ArenaTest, GetArenaWithUnknown) {
+  Arena arena;
+
+  // Tests arena-allocated message and submessages.
+  auto* arena_message1 = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message1->GetReflection()->MutableUnknownFields(arena_message1);
+  auto* arena_submessage1 = arena_message1->mutable_optional_foreign_message();
+  arena_submessage1->GetReflection()->MutableUnknownFields(arena_submessage1);
+  auto* arena_repeated_submessage1 =
+      arena_message1->add_repeated_foreign_message();
+  arena_repeated_submessage1->GetReflection()->MutableUnknownFields(
+      arena_repeated_submessage1);
+  EXPECT_EQ(&arena, arena_message1->GetArena());
+  EXPECT_EQ(&arena, arena_submessage1->GetArena());
+  EXPECT_EQ(&arena, arena_repeated_submessage1->GetArena());
+
+  // Tests attached heap-allocated messages.
+  auto* arena_message2 = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message2->set_allocated_optional_foreign_message(new ForeignMessage());
+  arena_message2->mutable_repeated_foreign_message()->AddAllocated(
+      new ForeignMessage());
+  auto* submessage2 = arena_message2->mutable_optional_foreign_message();
+  submessage2->GetReflection()->MutableUnknownFields(submessage2);
+  auto* repeated_submessage2 =
+      arena_message2->mutable_repeated_foreign_message(0);
+  repeated_submessage2->GetReflection()->MutableUnknownFields(
+      repeated_submessage2);
+  EXPECT_EQ(nullptr, submessage2->GetArena());
+  EXPECT_EQ(nullptr, repeated_submessage2->GetArena());
+}
+
+TEST(Proto3ArenaTest, Swap) {
+  Arena arena1;
+  Arena arena2;
+
+  // Test Swap().
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+}
+
+TEST(Proto3ArenaTest, SetAllocatedMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
+  nested->set_bb(118);
+  arena_message->set_allocated_optional_nested_message(nested);
+  EXPECT_EQ(118, arena_message->optional_nested_message().bb());
+}
+
+TEST(Proto3ArenaTest, ReleaseMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  std::unique_ptr<TestAllTypes::NestedMessage> nested(
+      arena_message->release_optional_nested_message());
+  EXPECT_EQ(118, nested->bb());
+}
+
+TEST(Proto3ArenaTest, MessageFieldClear) {
+  // GitHub issue #310: https://github.com/protocolbuffers/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());
+}
+
+TEST(Proto3OptionalTest, OptionalFields) {
+  protobuf_unittest::TestProto3Optional msg;
+  EXPECT_FALSE(msg.has_optional_int32());
+  msg.set_optional_int32(0);
+  EXPECT_TRUE(msg.has_optional_int32());
+
+  std::string serialized;
+  msg.SerializeToString(&serialized);
+  EXPECT_GT(serialized.size(), 0);
+
+  msg.clear_optional_int32();
+  EXPECT_FALSE(msg.has_optional_int32());
+  msg.SerializeToString(&serialized);
+  EXPECT_EQ(serialized.size(), 0);
+}
+
+TEST(Proto3OptionalTest, OptionalFieldDescriptor) {
+  const Descriptor* d = protobuf_unittest::TestProto3Optional::descriptor();
+
+  for (int i = 0; i < d->field_count(); i++) {
+    const FieldDescriptor* f = d->field(i);
+    if (HasPrefixString(f->name(), "singular")) {
+      EXPECT_FALSE(f->has_optional_keyword()) << f->full_name();
+      EXPECT_FALSE(f->has_presence()) << f->full_name();
+      EXPECT_FALSE(f->containing_oneof()) << f->full_name();
+    } else {
+      EXPECT_TRUE(f->has_optional_keyword()) << f->full_name();
+      EXPECT_TRUE(f->has_presence()) << f->full_name();
+      EXPECT_TRUE(f->containing_oneof()) << f->full_name();
+    }
+  }
+}
+
+TEST(Proto3OptionalTest, Extensions) {
+  const DescriptorPool* p = DescriptorPool::generated_pool();
+  const FieldDescriptor* no_optional = p->FindExtensionByName(
+      "protobuf_unittest.Proto3OptionalExtensions.ext_no_optional");
+  const FieldDescriptor* with_optional = p->FindExtensionByName(
+      "protobuf_unittest.Proto3OptionalExtensions.ext_with_optional");
+  GOOGLE_CHECK(no_optional);
+  GOOGLE_CHECK(with_optional);
+  EXPECT_FALSE(no_optional->has_optional_keyword());
+  EXPECT_TRUE(with_optional->has_optional_keyword());
+
+  const Descriptor* d = protobuf_unittest::Proto3OptionalExtensions::descriptor();
+  EXPECT_TRUE(d->options().HasExtension(
+      protobuf_unittest::Proto3OptionalExtensions::ext_no_optional));
+  EXPECT_TRUE(d->options().HasExtension(
+      protobuf_unittest::Proto3OptionalExtensions::ext_with_optional));
+  EXPECT_EQ(8, d->options().GetExtension(
+                   protobuf_unittest::Proto3OptionalExtensions::ext_no_optional));
+  EXPECT_EQ(16,
+            d->options().GetExtension(
+                protobuf_unittest::Proto3OptionalExtensions::ext_with_optional));
+
+  const Descriptor* d2 = protobuf_unittest::TestProto3Optional::descriptor();
+  EXPECT_FALSE(d2->options().HasExtension(
+      protobuf_unittest::Proto3OptionalExtensions::ext_no_optional));
+  EXPECT_FALSE(d2->options().HasExtension(
+      protobuf_unittest::Proto3OptionalExtensions::ext_with_optional));
+}
+
+TEST(Proto3OptionalTest, OptionalField) {
+  protobuf_unittest::TestProto3Optional msg;
+  EXPECT_FALSE(msg.has_optional_int32());
+  msg.set_optional_int32(0);
+  EXPECT_TRUE(msg.has_optional_int32());
+
+  std::string serialized;
+  msg.SerializeToString(&serialized);
+  EXPECT_GT(serialized.size(), 0);
+
+  msg.clear_optional_int32();
+  EXPECT_FALSE(msg.has_optional_int32());
+  msg.SerializeToString(&serialized);
+  EXPECT_EQ(serialized.size(), 0);
+}
+
+TEST(Proto3OptionalTest, OptionalFieldReflection) {
+  // Tests that oneof reflection works on synthetic oneofs.
+  //
+  // We test this more deeply elsewhere by parsing/serializing TextFormat (which
+  // doesn't treat synthetic oneofs specially, so reflects over them normally).
+  protobuf_unittest::TestProto3Optional msg;
+  const google::protobuf::Descriptor* d = msg.GetDescriptor();
+  const google::protobuf::Reflection* r = msg.GetReflection();
+  const google::protobuf::FieldDescriptor* f = d->FindFieldByName("optional_int32");
+  const google::protobuf::OneofDescriptor* o = d->FindOneofByName("_optional_int32");
+  GOOGLE_CHECK(f);
+  GOOGLE_CHECK(o);
+  EXPECT_TRUE(o->is_synthetic());
+
+  EXPECT_FALSE(r->HasField(msg, f));
+  EXPECT_FALSE(r->HasOneof(msg, o));
+  EXPECT_TRUE(r->GetOneofFieldDescriptor(msg, o) == nullptr);
+
+  r->SetInt32(&msg, f, 123);
+  EXPECT_EQ(123, msg.optional_int32());
+  EXPECT_EQ(123, r->GetInt32(msg, f));
+  EXPECT_TRUE(r->HasField(msg, f));
+  EXPECT_TRUE(r->HasOneof(msg, o));
+  EXPECT_EQ(f, r->GetOneofFieldDescriptor(msg, o));
+
+  std::vector<const FieldDescriptor*> fields;
+  r->ListFields(msg, &fields);
+  EXPECT_EQ(1, fields.size());
+  EXPECT_EQ(f, fields[0]);
+
+  r->ClearOneof(&msg, o);
+  EXPECT_FALSE(r->HasField(msg, f));
+  EXPECT_FALSE(r->HasOneof(msg, o));
+  EXPECT_TRUE(r->GetOneofFieldDescriptor(msg, o) == nullptr);
+
+  msg.set_optional_int32(123);
+  EXPECT_EQ(123, r->GetInt32(msg, f));
+  EXPECT_TRUE(r->HasField(msg, f));
+  EXPECT_TRUE(r->HasOneof(msg, o));
+  EXPECT_EQ(f, r->GetOneofFieldDescriptor(msg, o));
+
+  r->ClearOneof(&msg, o);
+  EXPECT_FALSE(r->HasField(msg, f));
+  EXPECT_FALSE(r->HasOneof(msg, o));
+  EXPECT_TRUE(r->GetOneofFieldDescriptor(msg, o) == nullptr);
+}
+
+// It's a regression test for b/160665543.
+TEST(Proto3OptionalTest, ClearNonOptionalMessageField) {
+  protobuf_unittest::TestProto3OptionalMessage msg;
+  msg.mutable_nested_message();
+  const google::protobuf::Descriptor* d = msg.GetDescriptor();
+  const google::protobuf::Reflection* r = msg.GetReflection();
+  const google::protobuf::FieldDescriptor* f = d->FindFieldByName("nested_message");
+  r->ClearField(&msg, f);
+}
+
+TEST(Proto3OptionalTest, ClearOptionalMessageField) {
+  protobuf_unittest::TestProto3OptionalMessage msg;
+  msg.mutable_optional_nested_message();
+  const google::protobuf::Descriptor* d = msg.GetDescriptor();
+  const google::protobuf::Reflection* r = msg.GetReflection();
+  const google::protobuf::FieldDescriptor* f =
+      d->FindFieldByName("optional_nested_message");
+  r->ClearField(&msg, f);
+}
+
+TEST(Proto3OptionalTest, SwapNonOptionalMessageField) {
+  protobuf_unittest::TestProto3OptionalMessage msg1;
+  protobuf_unittest::TestProto3OptionalMessage msg2;
+  msg1.mutable_nested_message();
+  const google::protobuf::Descriptor* d = msg1.GetDescriptor();
+  const google::protobuf::Reflection* r = msg1.GetReflection();
+  const google::protobuf::FieldDescriptor* f = d->FindFieldByName("nested_message");
+  r->SwapFields(&msg1, &msg2, {f});
+}
+
+TEST(Proto3OptionalTest, SwapOptionalMessageField) {
+  protobuf_unittest::TestProto3OptionalMessage msg1;
+  protobuf_unittest::TestProto3OptionalMessage msg2;
+  msg1.mutable_optional_nested_message();
+  const google::protobuf::Descriptor* d = msg1.GetDescriptor();
+  const google::protobuf::Reflection* r = msg1.GetReflection();
+  const google::protobuf::FieldDescriptor* f =
+      d->FindFieldByName("optional_nested_message");
+  r->SwapFields(&msg1, &msg2, {f});
+}
+
+void SetAllFieldsZero(protobuf_unittest::TestProto3Optional* msg) {
+  msg->set_optional_int32(0);
+  msg->set_optional_int64(0);
+  msg->set_optional_uint32(0);
+  msg->set_optional_uint64(0);
+  msg->set_optional_sint32(0);
+  msg->set_optional_sint64(0);
+  msg->set_optional_fixed32(0);
+  msg->set_optional_fixed64(0);
+  msg->set_optional_sfixed32(0);
+  msg->set_optional_sfixed64(0);
+  msg->set_optional_float(0);
+  msg->set_optional_double(0);
+  msg->set_optional_bool(false);
+  msg->set_optional_string("");
+  msg->set_optional_bytes("");
+  msg->mutable_optional_nested_message();
+  msg->mutable_lazy_nested_message();
+  msg->set_optional_nested_enum(
+      protobuf_unittest::TestProto3Optional::UNSPECIFIED);
+}
+
+void SetAllFieldsNonZero(protobuf_unittest::TestProto3Optional* msg) {
+  msg->set_optional_int32(101);
+  msg->set_optional_int64(102);
+  msg->set_optional_uint32(103);
+  msg->set_optional_uint64(104);
+  msg->set_optional_sint32(105);
+  msg->set_optional_sint64(106);
+  msg->set_optional_fixed32(107);
+  msg->set_optional_fixed64(108);
+  msg->set_optional_sfixed32(109);
+  msg->set_optional_sfixed64(110);
+  msg->set_optional_float(111);
+  msg->set_optional_double(112);
+  msg->set_optional_bool(true);
+  msg->set_optional_string("abc");
+  msg->set_optional_bytes("def");
+  msg->mutable_optional_nested_message();
+  msg->mutable_lazy_nested_message();
+  msg->set_optional_nested_enum(protobuf_unittest::TestProto3Optional::BAZ);
+}
+
+void TestAllFieldsZero(const protobuf_unittest::TestProto3Optional& msg) {
+  EXPECT_EQ(0, msg.optional_int32());
+  EXPECT_EQ(0, msg.optional_int64());
+  EXPECT_EQ(0, msg.optional_uint32());
+  EXPECT_EQ(0, msg.optional_uint64());
+  EXPECT_EQ(0, msg.optional_sint32());
+  EXPECT_EQ(0, msg.optional_sint64());
+  EXPECT_EQ(0, msg.optional_fixed32());
+  EXPECT_EQ(0, msg.optional_fixed64());
+  EXPECT_EQ(0, msg.optional_sfixed32());
+  EXPECT_EQ(0, msg.optional_sfixed64());
+  EXPECT_EQ(0, msg.optional_float());
+  EXPECT_EQ(0, msg.optional_double());
+  EXPECT_EQ(0, msg.optional_bool());
+  EXPECT_EQ("", msg.optional_string());
+  EXPECT_EQ("", msg.optional_bytes());
+  EXPECT_EQ(protobuf_unittest::TestProto3Optional::UNSPECIFIED,
+            msg.optional_nested_enum());
+
+  const Reflection* r = msg.GetReflection();
+  const Descriptor* d = msg.GetDescriptor();
+  EXPECT_EQ("", r->GetString(msg, d->FindFieldByName("optional_string")));
+}
+
+void TestAllFieldsNonZero(const protobuf_unittest::TestProto3Optional& msg) {
+  EXPECT_EQ(101, msg.optional_int32());
+  EXPECT_EQ(102, msg.optional_int64());
+  EXPECT_EQ(103, msg.optional_uint32());
+  EXPECT_EQ(104, msg.optional_uint64());
+  EXPECT_EQ(105, msg.optional_sint32());
+  EXPECT_EQ(106, msg.optional_sint64());
+  EXPECT_EQ(107, msg.optional_fixed32());
+  EXPECT_EQ(108, msg.optional_fixed64());
+  EXPECT_EQ(109, msg.optional_sfixed32());
+  EXPECT_EQ(110, msg.optional_sfixed64());
+  EXPECT_EQ(111, msg.optional_float());
+  EXPECT_EQ(112, msg.optional_double());
+  EXPECT_EQ(true, msg.optional_bool());
+  EXPECT_EQ("abc", msg.optional_string());
+  EXPECT_EQ("def", msg.optional_bytes());
+  EXPECT_EQ(protobuf_unittest::TestProto3Optional::BAZ,
+            msg.optional_nested_enum());
+}
+
+void TestAllFieldsSet(const protobuf_unittest::TestProto3Optional& msg,
+                      bool set) {
+  EXPECT_EQ(set, msg.has_optional_int32());
+  EXPECT_EQ(set, msg.has_optional_int64());
+  EXPECT_EQ(set, msg.has_optional_uint32());
+  EXPECT_EQ(set, msg.has_optional_uint64());
+  EXPECT_EQ(set, msg.has_optional_sint32());
+  EXPECT_EQ(set, msg.has_optional_sint64());
+  EXPECT_EQ(set, msg.has_optional_fixed32());
+  EXPECT_EQ(set, msg.has_optional_fixed64());
+  EXPECT_EQ(set, msg.has_optional_sfixed32());
+  EXPECT_EQ(set, msg.has_optional_sfixed64());
+  EXPECT_EQ(set, msg.has_optional_float());
+  EXPECT_EQ(set, msg.has_optional_double());
+  EXPECT_EQ(set, msg.has_optional_bool());
+  EXPECT_EQ(set, msg.has_optional_string());
+  EXPECT_EQ(set, msg.has_optional_bytes());
+  EXPECT_EQ(set, msg.has_optional_nested_message());
+  EXPECT_EQ(set, msg.has_lazy_nested_message());
+  EXPECT_EQ(set, msg.has_optional_nested_enum());
+}
+
+TEST(Proto3OptionalTest, BinaryRoundTrip) {
+  protobuf_unittest::TestProto3Optional msg;
+  TestAllFieldsSet(msg, false);
+  SetAllFieldsZero(&msg);
+  TestAllFieldsZero(msg);
+  TestAllFieldsSet(msg, true);
+
+  protobuf_unittest::TestProto3Optional msg2;
+  std::string serialized;
+  msg.SerializeToString(&serialized);
+  EXPECT_TRUE(msg2.ParseFromString(serialized));
+  TestAllFieldsZero(msg2);
+  TestAllFieldsSet(msg2, true);
+}
+
+TEST(Proto3OptionalTest, TextFormatRoundTripZeros) {
+  protobuf_unittest::TestProto3Optional msg;
+  SetAllFieldsZero(&msg);
+
+  protobuf_unittest::TestProto3Optional msg2;
+  std::string text;
+  EXPECT_TRUE(TextFormat::PrintToString(msg, &text));
+  EXPECT_TRUE(TextFormat::ParseFromString(text, &msg2));
+  TestAllFieldsSet(msg2, true);
+  TestAllFieldsZero(msg2);
+}
+
+TEST(Proto3OptionalTest, TextFormatRoundTripNonZeros) {
+  protobuf_unittest::TestProto3Optional msg;
+  SetAllFieldsNonZero(&msg);
+
+  protobuf_unittest::TestProto3Optional msg2;
+  std::string text;
+  EXPECT_TRUE(TextFormat::PrintToString(msg, &text));
+  EXPECT_TRUE(TextFormat::ParseFromString(text, &msg2));
+  TestAllFieldsSet(msg2, true);
+  TestAllFieldsNonZero(msg2);
+}
+
+TEST(Proto3OptionalTest, SwapRoundTripZero) {
+  protobuf_unittest::TestProto3Optional msg;
+  SetAllFieldsZero(&msg);
+  TestAllFieldsSet(msg, true);
+
+  protobuf_unittest::TestProto3Optional msg2;
+  msg.Swap(&msg2);
+  TestAllFieldsSet(msg2, true);
+  TestAllFieldsZero(msg2);
+}
+
+TEST(Proto3OptionalTest, SwapRoundTripNonZero) {
+  protobuf_unittest::TestProto3Optional msg;
+  SetAllFieldsNonZero(&msg);
+  TestAllFieldsSet(msg, true);
+
+  protobuf_unittest::TestProto3Optional msg2;
+  msg.Swap(&msg2);
+  TestAllFieldsSet(msg2, true);
+  TestAllFieldsNonZero(msg2);
+}
+
+TEST(Proto3OptionalTest, ReflectiveSwapRoundTrip) {
+  protobuf_unittest::TestProto3Optional msg;
+  SetAllFieldsZero(&msg);
+  TestAllFieldsSet(msg, true);
+
+  protobuf_unittest::TestProto3Optional msg2;
+  msg2.GetReflection()->Swap(&msg, &msg2);
+  TestAllFieldsSet(msg2, true);
+  TestAllFieldsZero(msg2);
+}
+
+TEST(Proto3OptionalTest, PlainFields) {
+  const Descriptor* d = TestAllTypes::descriptor();
+
+  EXPECT_FALSE(d->FindFieldByName("optional_int32")->has_presence());
+  EXPECT_TRUE(d->FindFieldByName("oneof_nested_message")->has_presence());
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_lite_unittest.cc b/src/google/protobuf/proto3_lite_unittest.cc
new file mode 100644
index 0000000..abeeedb
--- /dev/null
+++ b/src/google/protobuf/proto3_lite_unittest.cc
@@ -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.
+
+#include <google/protobuf/unittest_proto3.pb.h>
+
+#define LITE_TEST_NAME Proto3LiteTest
+#define UNITTEST ::proto3_unittest
+
+// Must include after the above macros.
+#include <google/protobuf/proto3_lite_unittest.inc>
+
+// Make extract script happy.
+namespace google {
+namespace protobuf {
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_lite_unittest.inc b/src/google/protobuf/proto3_lite_unittest.inc
new file mode 100644
index 0000000..5878163
--- /dev/null
+++ b/src/google/protobuf/proto3_lite_unittest.inc
@@ -0,0 +1,149 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <string>
+#include <vector>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+using UNITTEST::TestAllTypes;
+
+namespace google {
+namespace protobuf {
+namespace {
+// We selectively set/check a few representative fields rather than all fields
+// as this test is only expected to cover the basics of lite support.
+void SetAllFields(TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->set_optional_nested_enum(UNITTEST::TestAllTypes::BAZ);
+  m->set_optional_foreign_enum(
+      UNITTEST::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->mutable_optional_unverified_lazy_message()->set_bb(46);
+  m->add_repeated_int32(100);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_nested_enum(UNITTEST::TestAllTypes::BAZ);
+  m->add_repeated_foreign_enum(
+      UNITTEST::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void ExpectAllFieldsSet(const TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, m.optional_nested_enum());
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+  EXPECT_EQ(true, m.has_optional_unverified_lazy_message());
+  EXPECT_EQ(46, m.optional_unverified_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+// In this file we only test some basic functionalities of in proto3 and expect
+// the rest is fully tested in proto2 unittests because proto3 shares most code
+// with proto2.
+
+TEST(LITE_TEST_NAME, Parsing) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  TestAllTypes msg;
+  msg.ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(msg);
+}
+
+TEST(LITE_TEST_NAME, Swap) {
+  // Test Swap().
+  TestAllTypes msg1;
+  TestAllTypes msg2;
+  msg1.set_optional_string("123");
+  msg2.set_optional_string("3456");
+  msg1.Swap(&msg2);
+  EXPECT_EQ("3456", msg1.optional_string());
+  EXPECT_EQ("123", msg2.optional_string());
+  EXPECT_EQ(msg1.ByteSize(), msg2.ByteSize() + 1);
+}
+
+TEST(LITE_TEST_NAME, OneofHazzers) {
+  TestAllTypes msg;
+  msg.set_oneof_uint32(1);
+  msg.set_oneof_string("test");
+
+  EXPECT_EQ(true, msg.has_oneof_string());
+  EXPECT_EQ(false, msg.has_oneof_uint32());
+  EXPECT_EQ(false, msg.has_oneof_bytes());
+  EXPECT_EQ(false, msg.has_oneof_nested_message());
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h
new file mode 100644
index 0000000..7b75a43
--- /dev/null
+++ b/src/google/protobuf/reflection.h
@@ -0,0 +1,570 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This header defines the RepeatedFieldRef class template used to access
+// repeated fields with protobuf reflection API.
+#ifndef GOOGLE_PROTOBUF_REFLECTION_H__
+#define GOOGLE_PROTOBUF_REFLECTION_H__
+
+
+#include <memory>
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/generated_enum_util.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template <typename T, typename Enable = void>
+struct RefTypeTraits;
+}  // namespace internal
+
+template <typename T>
+RepeatedFieldRef<T> Reflection::GetRepeatedFieldRef(
+    const Message& message, const FieldDescriptor* field) const {
+  return RepeatedFieldRef<T>(message, field);
+}
+
+template <typename T>
+MutableRepeatedFieldRef<T> Reflection::GetMutableRepeatedFieldRef(
+    Message* message, const FieldDescriptor* field) const {
+  return MutableRepeatedFieldRef<T>(message, field);
+}
+
+// RepeatedFieldRef definition for non-message types.
+template <typename T>
+class RepeatedFieldRef<
+    T, typename std::enable_if<!std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  T Get(int index) const { return accessor_->template Get<T>(data_, index); }
+
+  typedef IteratorType iterator;
+  typedef IteratorType const_iterator;
+  typedef T value_type;
+  typedef T& reference;
+  typedef const T& const_reference;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin() const { return iterator(data_, accessor_, true); }
+  iterator end() const { return iterator(data_, accessor_, false); }
+
+ private:
+  friend class Reflection;
+  RepeatedFieldRef(const Message& message, const FieldDescriptor* field) {
+    const Reflection* reflection = message.GetReflection();
+    data_ = reflection->RepeatedFieldData(const_cast<Message*>(&message), field,
+                                          internal::RefTypeTraits<T>::cpp_type,
+                                          nullptr);
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+  }
+
+  const void* data_;
+  const AccessorType* accessor_;
+};
+
+// MutableRepeatedFieldRef definition for non-message types.
+template <typename T>
+class MutableRepeatedFieldRef<
+    T, typename std::enable_if<!std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  T Get(int index) const { return accessor_->template Get<T>(data_, index); }
+
+  void Set(int index, const T& value) const {
+    accessor_->template Set<T>(data_, index, value);
+  }
+  void Add(const T& value) const { accessor_->template Add<T>(data_, value); }
+  void RemoveLast() const { accessor_->RemoveLast(data_); }
+  void SwapElements(int index1, int index2) const {
+    accessor_->SwapElements(data_, index1, index2);
+  }
+  void Clear() const { accessor_->Clear(data_); }
+
+  void Swap(const MutableRepeatedFieldRef& other) const {
+    accessor_->Swap(data_, other.accessor_, other.data_);
+  }
+
+  template <typename Container>
+  void MergeFrom(const Container& container) const {
+    typedef typename Container::const_iterator Iterator;
+    for (Iterator it = container.begin(); it != container.end(); ++it) {
+      Add(*it);
+    }
+  }
+  template <typename Container>
+  void CopyFrom(const Container& container) const {
+    Clear();
+    MergeFrom(container);
+  }
+
+ private:
+  friend class Reflection;
+  MutableRepeatedFieldRef(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        message, field, internal::RefTypeTraits<T>::cpp_type, nullptr);
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+  }
+
+  void* data_;
+  const AccessorType* accessor_;
+};
+
+// RepeatedFieldRef definition for message types.
+template <typename T>
+class RepeatedFieldRef<
+    T, typename std::enable_if<std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  // This method returns a reference to the underlying message object if it
+  // exists. If a message object doesn't exist (e.g., data stored in serialized
+  // form), scratch_space will be filled with the data and a reference to it
+  // will be returned.
+  //
+  // Example:
+  //   RepeatedFieldRef<Message> h = ...
+  //   unique_ptr<Message> scratch_space(h.NewMessage());
+  //   const Message& item = h.Get(index, scratch_space.get());
+  const T& Get(int index, T* scratch_space) const {
+    return *static_cast<const T*>(accessor_->Get(data_, index, scratch_space));
+  }
+  // Create a new message of the same type as the messages stored in this
+  // repeated field. Caller takes ownership of the returned object.
+  T* NewMessage() const { return static_cast<T*>(default_instance_->New()); }
+
+  typedef IteratorType iterator;
+  typedef IteratorType const_iterator;
+  typedef T value_type;
+  typedef T& reference;
+  typedef const T& const_reference;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin() const {
+    return iterator(data_, accessor_, true, NewMessage());
+  }
+  iterator end() const {
+    // The end iterator must not be dereferenced, no need for scratch space.
+    return iterator(data_, accessor_, false, nullptr);
+  }
+
+ private:
+  friend class Reflection;
+  RepeatedFieldRef(const Message& message, const FieldDescriptor* field) {
+    const Reflection* reflection = message.GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        const_cast<Message*>(&message), field,
+        internal::RefTypeTraits<T>::cpp_type,
+        internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+    default_instance_ =
+        reflection->GetMessageFactory()->GetPrototype(field->message_type());
+  }
+
+  const void* data_;
+  const AccessorType* accessor_;
+  const Message* default_instance_;
+};
+
+// MutableRepeatedFieldRef definition for message types.
+template <typename T>
+class MutableRepeatedFieldRef<
+    T, typename std::enable_if<std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  // See comments for RepeatedFieldRef<Message>::Get()
+  const T& Get(int index, T* scratch_space) const {
+    return *static_cast<const T*>(accessor_->Get(data_, index, scratch_space));
+  }
+  // Create a new message of the same type as the messages stored in this
+  // repeated field. Caller takes ownership of the returned object.
+  T* NewMessage() const { return static_cast<T*>(default_instance_->New()); }
+
+  void Set(int index, const T& value) const {
+    accessor_->Set(data_, index, &value);
+  }
+  void Add(const T& value) const { accessor_->Add(data_, &value); }
+  void RemoveLast() const { accessor_->RemoveLast(data_); }
+  void SwapElements(int index1, int index2) const {
+    accessor_->SwapElements(data_, index1, index2);
+  }
+  void Clear() const { accessor_->Clear(data_); }
+
+  void Swap(const MutableRepeatedFieldRef& other) const {
+    accessor_->Swap(data_, other.accessor_, other.data_);
+  }
+
+  template <typename Container>
+  void MergeFrom(const Container& container) const {
+    typedef typename Container::const_iterator Iterator;
+    for (Iterator it = container.begin(); it != container.end(); ++it) {
+      Add(*it);
+    }
+  }
+  template <typename Container>
+  void CopyFrom(const Container& container) const {
+    Clear();
+    MergeFrom(container);
+  }
+
+ private:
+  friend class Reflection;
+  MutableRepeatedFieldRef(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        message, field, internal::RefTypeTraits<T>::cpp_type,
+        internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+    default_instance_ =
+        reflection->GetMessageFactory()->GetPrototype(field->message_type());
+  }
+
+  void* data_;
+  const AccessorType* accessor_;
+  const Message* default_instance_;
+};
+
+namespace internal {
+// Interfaces used to implement reflection RepeatedFieldRef API.
+// Reflection::GetRepeatedAccessor() should return a pointer to an singleton
+// object that implements the below interface.
+//
+// This interface passes/returns values using void pointers. The actual type
+// of the value depends on the field's cpp_type. Following is a mapping from
+// cpp_type to the type that should be used in this interface:
+//
+//   field->cpp_type()      T                Actual type of void*
+//   CPPTYPE_INT32        int32_t                 int32_t
+//   CPPTYPE_UINT32       uint32_t                uint32_t
+//   CPPTYPE_INT64        int64_t                 int64_t
+//   CPPTYPE_UINT64       uint64_t                uint64_t
+//   CPPTYPE_DOUBLE       double                  double
+//   CPPTYPE_FLOAT        float                   float
+//   CPPTYPE_BOOL         bool                    bool
+//   CPPTYPE_ENUM         generated enum type     int32_t
+//   CPPTYPE_STRING       string                  std::string
+//   CPPTYPE_MESSAGE      generated message type  google::protobuf::Message
+//                        or google::protobuf::Message
+//
+// Note that for enums we use int32_t in the interface.
+//
+// You can map from T to the actual type using RefTypeTraits:
+//   typedef RefTypeTraits<T>::AccessorValueType ActualType;
+class PROTOBUF_EXPORT RepeatedFieldAccessor {
+ public:
+  // Typedefs for clarity.
+  typedef void Field;
+  typedef void Value;
+  typedef void Iterator;
+
+  virtual bool IsEmpty(const Field* data) const = 0;
+  virtual int Size(const Field* data) const = 0;
+  // Depends on the underlying representation of the repeated field, this
+  // method can return a pointer to the underlying object if such an object
+  // exists, or fill the data into scratch_space and return scratch_space.
+  // Callers of this method must ensure scratch_space is a valid pointer
+  // to a mutable object of the correct type.
+  virtual const Value* Get(const Field* data, int index,
+                           Value* scratch_space) const = 0;
+
+  virtual void Clear(Field* data) const = 0;
+  virtual void Set(Field* data, int index, const Value* value) const = 0;
+  virtual void Add(Field* data, const Value* value) const = 0;
+  virtual void RemoveLast(Field* data) const = 0;
+  virtual void SwapElements(Field* data, int index1, int index2) const = 0;
+  virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator,
+                    Field* other_data) const = 0;
+
+  // Create an iterator that points at the beginning of the repeated field.
+  virtual Iterator* BeginIterator(const Field* data) const = 0;
+  // Create an iterator that points at the end of the repeated field.
+  virtual Iterator* EndIterator(const Field* data) const = 0;
+  // Make a copy of an iterator and return the new copy.
+  virtual Iterator* CopyIterator(const Field* data,
+                                 const Iterator* iterator) const = 0;
+  // Move an iterator to point to the next element.
+  virtual Iterator* AdvanceIterator(const Field* data,
+                                    Iterator* iterator) const = 0;
+  // Compare whether two iterators point to the same element.
+  virtual bool EqualsIterator(const Field* data, const Iterator* a,
+                              const Iterator* b) const = 0;
+  // Delete an iterator created by BeginIterator(), EndIterator() and
+  // CopyIterator().
+  virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0;
+  // Like Get() but for iterators.
+  virtual const Value* GetIteratorValue(const Field* data,
+                                        const Iterator* iterator,
+                                        Value* scratch_space) const = 0;
+
+  // Templated methods that make using this interface easier for non-message
+  // types.
+  template <typename T>
+  T Get(const Field* data, int index) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    ActualType scratch_space;
+    return static_cast<T>(*reinterpret_cast<const ActualType*>(
+        Get(data, index, static_cast<Value*>(&scratch_space))));
+  }
+
+  template <typename T, typename ValueType>
+  void Set(Field* data, int index, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32_t). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Set(data, index, static_cast<const Value*>(&tmp));
+  }
+
+  template <typename T, typename ValueType>
+  void Add(Field* data, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32_t). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Add(data, static_cast<const Value*>(&tmp));
+  }
+
+ protected:
+  // We want the destructor to be completely trivial as to allow it to be
+  // a function local static. Hence we make it non-virtual and protected,
+  // this class only live as part of a global singleton and should not be
+  // deleted.
+  ~RepeatedFieldAccessor() = default;
+};
+
+// Implement (Mutable)RepeatedFieldRef::iterator
+template <typename T>
+class RepeatedFieldRefIterator {
+  typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
+  typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
+  typedef typename RefTypeTraits<T>::IteratorPointerType IteratorPointerType;
+
+ public:
+  using iterator_category = std::forward_iterator_tag;
+  using value_type = T;
+  using pointer = T*;
+  using reference = T&;
+  using difference_type = std::ptrdiff_t;
+
+  // Constructor for non-message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor, bool begin)
+      : data_(data),
+        accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data)
+                        : accessor->EndIterator(data)),
+        // The end iterator must not be dereferenced, no need for scratch space.
+        scratch_space_(begin ? new AccessorValueType : nullptr) {}
+  // Constructor for message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor, bool begin,
+                           AccessorValueType* scratch_space)
+      : data_(data),
+        accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data)
+                        : accessor->EndIterator(data)),
+        scratch_space_(scratch_space) {}
+  ~RepeatedFieldRefIterator() { accessor_->DeleteIterator(data_, iterator_); }
+  RepeatedFieldRefIterator operator++(int) {
+    RepeatedFieldRefIterator tmp(*this);
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return tmp;
+  }
+  RepeatedFieldRefIterator& operator++() {
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return *this;
+  }
+  IteratorValueType operator*() const {
+    return static_cast<IteratorValueType>(
+        *static_cast<const AccessorValueType*>(accessor_->GetIteratorValue(
+            data_, iterator_, scratch_space_.get())));
+  }
+  IteratorPointerType operator->() const {
+    return static_cast<IteratorPointerType>(
+        accessor_->GetIteratorValue(data_, iterator_, scratch_space_.get()));
+  }
+  bool operator!=(const RepeatedFieldRefIterator& other) const {
+    assert(data_ == other.data_);
+    assert(accessor_ == other.accessor_);
+    return !accessor_->EqualsIterator(data_, iterator_, other.iterator_);
+  }
+  bool operator==(const RepeatedFieldRefIterator& other) const {
+    return !this->operator!=(other);
+  }
+
+  RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other)
+      : data_(other.data_),
+        accessor_(other.accessor_),
+        iterator_(accessor_->CopyIterator(data_, other.iterator_)) {}
+  RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) {
+    if (this != &other) {
+      accessor_->DeleteIterator(data_, iterator_);
+      data_ = other.data_;
+      accessor_ = other.accessor_;
+      iterator_ = accessor_->CopyIterator(data_, other.iterator_);
+    }
+    return *this;
+  }
+
+ protected:
+  const void* data_;
+  const RepeatedFieldAccessor* accessor_;
+  void* iterator_;
+  std::unique_ptr<AccessorValueType> scratch_space_;
+};
+
+// TypeTraits that maps the type parameter T of RepeatedFieldRef or
+// MutableRepeatedFieldRef to corresponding iterator type,
+// RepeatedFieldAccessor type, etc.
+template <typename T>
+struct PrimitiveTraits {
+  static constexpr bool is_primitive = false;
+};
+#define DEFINE_PRIMITIVE(TYPE, type)                 \
+  template <>                                        \
+  struct PrimitiveTraits<type> {                     \
+    static const bool is_primitive = true;           \
+    static const FieldDescriptor::CppType cpp_type = \
+        FieldDescriptor::CPPTYPE_##TYPE;             \
+  };
+DEFINE_PRIMITIVE(INT32, int32_t)
+DEFINE_PRIMITIVE(UINT32, uint32_t)
+DEFINE_PRIMITIVE(INT64, int64_t)
+DEFINE_PRIMITIVE(UINT64, uint64_t)
+DEFINE_PRIMITIVE(FLOAT, float)
+DEFINE_PRIMITIVE(DOUBLE, double)
+DEFINE_PRIMITIVE(BOOL, bool)
+#undef DEFINE_PRIMITIVE
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef T AccessorValueType;
+  typedef T IteratorValueType;
+  typedef T* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      PrimitiveTraits<T>::cpp_type;
+  static const Descriptor* GetMessageFieldDescriptor() { return nullptr; }
+};
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<is_proto_enum<T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  // We use int32_t for repeated enums in RepeatedFieldAccessor.
+  typedef int32_t AccessorValueType;
+  typedef T IteratorValueType;
+  typedef int32_t* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_ENUM;
+  static const Descriptor* GetMessageFieldDescriptor() { return nullptr; }
+};
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<std::is_same<std::string, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef std::string AccessorValueType;
+  typedef const std::string IteratorValueType;
+  typedef const std::string* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_STRING;
+  static const Descriptor* GetMessageFieldDescriptor() { return nullptr; }
+};
+
+template <typename T>
+struct MessageDescriptorGetter {
+  static const Descriptor* get() {
+    return T::default_instance().GetDescriptor();
+  }
+};
+template <>
+struct MessageDescriptorGetter<Message> {
+  static const Descriptor* get() { return nullptr; }
+};
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<std::is_base_of<Message, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef Message AccessorValueType;
+  typedef const T& IteratorValueType;
+  typedef const T* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_MESSAGE;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return MessageDescriptorGetter<T>::get();
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_H__
diff --git a/src/google/protobuf/reflection_internal.h b/src/google/protobuf/reflection_internal.h
new file mode 100644
index 0000000..f749c3e
--- /dev/null
+++ b/src/google/protobuf/reflection_internal.h
@@ -0,0 +1,364 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
+#define GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
+
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/repeated_field.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// A base class for RepeatedFieldAccessor implementations that can support
+// random-access efficiently. All iterator methods delegates the work to
+// corresponding random-access methods.
+class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor {
+ public:
+  Iterator* BeginIterator(const Field* /*data*/) const override {
+    return PositionToIterator(0);
+  }
+  Iterator* EndIterator(const Field* data) const override {
+    return PositionToIterator(this->Size(data));
+  }
+  Iterator* CopyIterator(const Field* /*data*/,
+                         const Iterator* iterator) const override {
+    return const_cast<Iterator*>(iterator);
+  }
+  Iterator* AdvanceIterator(const Field* /*data*/,
+                            Iterator* iterator) const override {
+    return PositionToIterator(IteratorToPosition(iterator) + 1);
+  }
+  bool EqualsIterator(const Field* /*data*/, const Iterator* a,
+                      const Iterator* b) const override {
+    return a == b;
+  }
+  void DeleteIterator(const Field* /*data*/,
+                      Iterator* /*iterator*/) const override {}
+  const Value* GetIteratorValue(const Field* data, const Iterator* iterator,
+                                Value* scratch_space) const override {
+    return Get(data, static_cast<int>(IteratorToPosition(iterator)),
+               scratch_space);
+  }
+
+ protected:
+  ~RandomAccessRepeatedFieldAccessor() = default;
+
+ private:
+  static intptr_t IteratorToPosition(const Iterator* iterator) {
+    return reinterpret_cast<intptr_t>(iterator);
+  }
+  static Iterator* PositionToIterator(intptr_t position) {
+    return reinterpret_cast<Iterator*>(position);
+  }
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedField<T>.
+template <typename T>
+class RepeatedFieldWrapper : public RandomAccessRepeatedFieldAccessor {
+ public:
+  RepeatedFieldWrapper() {}
+  bool IsEmpty(const Field* data) const override {
+    return GetRepeatedField(data)->empty();
+  }
+  int Size(const Field* data) const override {
+    return GetRepeatedField(data)->size();
+  }
+  const Value* Get(const Field* data, int index,
+                   Value* scratch_space) const override {
+    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  void Clear(Field* data) const override {
+    MutableRepeatedField(data)->Clear();
+  }
+  void Set(Field* data, int index, const Value* value) const override {
+    MutableRepeatedField(data)->Set(index, ConvertToT(value));
+  }
+  void Add(Field* data, const Value* value) const override {
+    MutableRepeatedField(data)->Add(ConvertToT(value));
+  }
+  void RemoveLast(Field* data) const override {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  void SwapElements(Field* data, int index1, int index2) const override {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+
+ protected:
+  ~RepeatedFieldWrapper() = default;
+  typedef RepeatedField<T> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(data);
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(data);
+  }
+
+  // Convert an object received by this accessor to an object to be stored in
+  // the underlying RepeatedField.
+  virtual T ConvertToT(const Value* value) const = 0;
+
+  // Convert an object stored in RepeatedPtrField to an object that will be
+  // returned by this accessor. If the two objects have the same type (true for
+  // string fields with ctype=STRING), a pointer to the source object can be
+  // returned directly. Otherwise, data should be copied from value to
+  // scratch_space and scratch_space should be returned.
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const = 0;
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedPtrField<T>.
+template <typename T>
+class RepeatedPtrFieldWrapper : public RandomAccessRepeatedFieldAccessor {
+ public:
+  bool IsEmpty(const Field* data) const override {
+    return GetRepeatedField(data)->empty();
+  }
+  int Size(const Field* data) const override {
+    return GetRepeatedField(data)->size();
+  }
+  const Value* Get(const Field* data, int index,
+                   Value* scratch_space) const override {
+    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  void Clear(Field* data) const override {
+    MutableRepeatedField(data)->Clear();
+  }
+  void Set(Field* data, int index, const Value* value) const override {
+    ConvertToT(value, MutableRepeatedField(data)->Mutable(index));
+  }
+  void Add(Field* data, const Value* value) const override {
+    T* allocated = New(value);
+    ConvertToT(value, allocated);
+    MutableRepeatedField(data)->AddAllocated(allocated);
+  }
+  void RemoveLast(Field* data) const override {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  void SwapElements(Field* data, int index1, int index2) const override {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+
+ protected:
+  ~RepeatedPtrFieldWrapper() = default;
+  typedef RepeatedPtrField<T> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(data);
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(data);
+  }
+
+  // Create a new T instance. For repeated message fields, T can be specified
+  // as google::protobuf::Message so we can't use "new T()" directly. In that case, value
+  // should be a message of the same type (it's ensured by the caller) and a
+  // new message object will be created using it.
+  virtual T* New(const Value* value) const = 0;
+
+  // Convert an object received by this accessor to an object that will be
+  // stored in the underlying RepeatedPtrField.
+  virtual void ConvertToT(const Value* value, T* result) const = 0;
+
+  // Convert an object stored in RepeatedPtrField to an object that will be
+  // returned by this accessor. If the two objects have the same type (true for
+  // string fields with ctype=STRING), a pointer to the source object can be
+  // returned directly. Otherwise, data should be copied from value to
+  // scratch_space and scratch_space should be returned.
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const = 0;
+};
+
+// An implementation of RandomAccessRepeatedFieldAccessor that manipulates
+// MapFieldBase.
+class MapFieldAccessor final : public RandomAccessRepeatedFieldAccessor {
+ public:
+  MapFieldAccessor() {}
+  virtual ~MapFieldAccessor() {}
+  bool IsEmpty(const Field* data) const override {
+    return GetRepeatedField(data)->empty();
+  }
+  int Size(const Field* data) const override {
+    return GetRepeatedField(data)->size();
+  }
+  const Value* Get(const Field* data, int index,
+                   Value* scratch_space) const override {
+    return ConvertFromEntry(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  void Clear(Field* data) const override {
+    MutableRepeatedField(data)->Clear();
+  }
+  void Set(Field* data, int index, const Value* value) const override {
+    ConvertToEntry(value, MutableRepeatedField(data)->Mutable(index));
+  }
+  void Add(Field* data, const Value* value) const override {
+    Message* allocated = New(value);
+    ConvertToEntry(value, allocated);
+    MutableRepeatedField(data)->AddAllocated(allocated);
+  }
+  void RemoveLast(Field* data) const override {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  void SwapElements(Field* data, int index1, int index2) const override {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  typedef RepeatedPtrField<Message> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(
+        (&reinterpret_cast<const MapFieldBase*>(data)->GetRepeatedField()));
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(
+        reinterpret_cast<MapFieldBase*>(data)->MutableRepeatedField());
+  }
+  virtual Message* New(const Value* value) const {
+    return static_cast<const Message*>(value)->New();
+  }
+  // Convert an object received by this accessor to an MapEntry message to be
+  // stored in the underlying MapFieldBase.
+  virtual void ConvertToEntry(const Value* value, Message* result) const {
+    result->CopyFrom(*static_cast<const Message*>(value));
+  }
+  // Convert a MapEntry message stored in the underlying MapFieldBase to an
+  // object that will be returned by this accessor.
+  virtual const Value* ConvertFromEntry(const Message& value,
+                                        Value* /*scratch_space*/) const {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+// Default implementations of RepeatedFieldAccessor for primitive types.
+template <typename T>
+class RepeatedFieldPrimitiveAccessor final : public RepeatedFieldWrapper<T> {
+  typedef void Field;
+  typedef void Value;
+  using RepeatedFieldWrapper<T>::MutableRepeatedField;
+
+ public:
+  RepeatedFieldPrimitiveAccessor() {}
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    // Currently RepeatedFieldPrimitiveAccessor is the only implementation of
+    // RepeatedFieldAccessor for primitive types. As we are using singletons
+    // for these accessors, here "other_mutator" must be "this".
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  T ConvertToT(const Value* value) const override {
+    return *static_cast<const T*>(value);
+  }
+  const Value* ConvertFromT(const T& value,
+                            Value* /*scratch_space*/) const override {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+// Default implementation of RepeatedFieldAccessor for string fields with
+// ctype=STRING.
+class RepeatedPtrFieldStringAccessor final
+    : public RepeatedPtrFieldWrapper<std::string> {
+  typedef void Field;
+  typedef void Value;
+  using RepeatedFieldAccessor::Add;
+
+ public:
+  RepeatedPtrFieldStringAccessor() {}
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    if (this == other_mutator) {
+      MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+    } else {
+      RepeatedPtrField<std::string> tmp;
+      tmp.Swap(MutableRepeatedField(data));
+      int other_size = other_mutator->Size(other_data);
+      for (int i = 0; i < other_size; ++i) {
+        Add<std::string>(data, other_mutator->Get<std::string>(other_data, i));
+      }
+      int size = Size(data);
+      other_mutator->Clear(other_data);
+      for (int i = 0; i < size; ++i) {
+        other_mutator->Add<std::string>(other_data, tmp.Get(i));
+      }
+    }
+  }
+
+ protected:
+  std::string* New(const Value*) const override { return new std::string(); }
+  void ConvertToT(const Value* value, std::string* result) const override {
+    *result = *static_cast<const std::string*>(value);
+  }
+  const Value* ConvertFromT(const std::string& value,
+                            Value* /*scratch_space*/) const override {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+
+class RepeatedPtrFieldMessageAccessor final
+    : public RepeatedPtrFieldWrapper<Message> {
+  typedef void Field;
+  typedef void Value;
+
+ public:
+  RepeatedPtrFieldMessageAccessor() {}
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  Message* New(const Value* value) const override {
+    return static_cast<const Message*>(value)->New();
+  }
+  void ConvertToT(const Value* value, Message* result) const override {
+    result->CopyFrom(*static_cast<const Message*>(value));
+  }
+  const Value* ConvertFromT(const Message& value,
+                            Value* /*scratch_space*/) const override {
+    return static_cast<const Value*>(&value);
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
new file mode 100644
index 0000000..3a1972e
--- /dev/null
+++ b/src/google/protobuf/reflection_ops.cc
@@ -0,0 +1,459 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/reflection_ops.h>
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/unknown_field_set.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+static const Reflection* GetReflectionOrDie(const Message& m) {
+  const Reflection* r = m.GetReflection();
+  if (r == nullptr) {
+    const Descriptor* d = m.GetDescriptor();
+    const std::string& mtype = d ? d->name() : "unknown";
+    // RawMessage is one known type for which GetReflection() returns nullptr.
+    GOOGLE_LOG(FATAL) << "Message does not support reflection (type " << mtype << ").";
+  }
+  return r;
+}
+
+void ReflectionOps::Copy(const Message& from, Message* to) {
+  if (&from == to) return;
+  Clear(to);
+  Merge(from, to);
+}
+
+void ReflectionOps::Merge(const Message& from, Message* to) {
+  GOOGLE_CHECK_NE(&from, to);
+
+  const Descriptor* descriptor = from.GetDescriptor();
+  GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
+      << "Tried to merge messages of different types "
+      << "(merge " << descriptor->full_name() << " to "
+      << to->GetDescriptor()->full_name() << ")";
+
+  const Reflection* from_reflection = GetReflectionOrDie(from);
+  const Reflection* to_reflection = GetReflectionOrDie(*to);
+  bool is_from_generated = (from_reflection->GetMessageFactory() ==
+                            google::protobuf::MessageFactory::generated_factory());
+  bool is_to_generated = (to_reflection->GetMessageFactory() ==
+                          google::protobuf::MessageFactory::generated_factory());
+
+  std::vector<const FieldDescriptor*> fields;
+  from_reflection->ListFieldsOmitStripped(from, &fields);
+  for (const FieldDescriptor* field : fields) {
+    if (field->is_repeated()) {
+      // Use map reflection if both are in map status and have the
+      // same map type to avoid sync with repeated field.
+      // Note: As from and to messages have the same descriptor, the
+      // map field types are the same if they are both generated
+      // messages or both dynamic messages.
+      if (is_from_generated == is_to_generated && field->is_map()) {
+        const MapFieldBase* from_field =
+            from_reflection->GetMapData(from, field);
+        MapFieldBase* to_field = to_reflection->MutableMapData(to, field);
+        if (to_field->IsMapValid() && from_field->IsMapValid()) {
+          to_field->MergeFrom(*from_field);
+          continue;
+        }
+      }
+      int count = from_reflection->FieldSize(from, field);
+      for (int j = 0; j < count; j++) {
+        switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD)                                      \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                                \
+    to_reflection->Add##METHOD(                                           \
+        to, field, from_reflection->GetRepeated##METHOD(from, field, j)); \
+    break;
+
+          HANDLE_TYPE(INT32, Int32);
+          HANDLE_TYPE(INT64, Int64);
+          HANDLE_TYPE(UINT32, UInt32);
+          HANDLE_TYPE(UINT64, UInt64);
+          HANDLE_TYPE(FLOAT, Float);
+          HANDLE_TYPE(DOUBLE, Double);
+          HANDLE_TYPE(BOOL, Bool);
+          HANDLE_TYPE(STRING, String);
+          HANDLE_TYPE(ENUM, Enum);
+#undef HANDLE_TYPE
+
+          case FieldDescriptor::CPPTYPE_MESSAGE:
+            const Message& from_child =
+                from_reflection->GetRepeatedMessage(from, field, j);
+            if (from_reflection == to_reflection) {
+              to_reflection
+                  ->AddMessage(to, field,
+                               from_child.GetReflection()->GetMessageFactory())
+                  ->MergeFrom(from_child);
+            } else {
+              to_reflection->AddMessage(to, field)->MergeFrom(from_child);
+            }
+            break;
+        }
+      }
+    } else {
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD)                                       \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                                 \
+    to_reflection->Set##METHOD(to, field,                                  \
+                               from_reflection->Get##METHOD(from, field)); \
+    break;
+
+        HANDLE_TYPE(INT32, Int32);
+        HANDLE_TYPE(INT64, Int64);
+        HANDLE_TYPE(UINT32, UInt32);
+        HANDLE_TYPE(UINT64, UInt64);
+        HANDLE_TYPE(FLOAT, Float);
+        HANDLE_TYPE(DOUBLE, Double);
+        HANDLE_TYPE(BOOL, Bool);
+        HANDLE_TYPE(STRING, String);
+        HANDLE_TYPE(ENUM, Enum);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          const Message& from_child = from_reflection->GetMessage(from, field);
+          if (from_reflection == to_reflection) {
+            to_reflection
+                ->MutableMessage(
+                    to, field, from_child.GetReflection()->GetMessageFactory())
+                ->MergeFrom(from_child);
+          } else {
+            to_reflection->MutableMessage(to, field)->MergeFrom(from_child);
+          }
+          break;
+      }
+    }
+  }
+
+  if (!from_reflection->GetUnknownFields(from).empty()) {
+    to_reflection->MutableUnknownFields(to)->MergeFrom(
+        from_reflection->GetUnknownFields(from));
+  }
+}
+
+void ReflectionOps::Clear(Message* message) {
+  const Reflection* reflection = GetReflectionOrDie(*message);
+
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFieldsOmitStripped(*message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    reflection->ClearField(message, field);
+  }
+
+  if (reflection->GetInternalMetadata(*message).have_unknown_fields()) {
+    reflection->MutableUnknownFields(message)->Clear();
+  }
+}
+
+bool ReflectionOps::IsInitialized(const Message& message, bool check_fields,
+                                  bool check_descendants) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = GetReflectionOrDie(message);
+  if (const int field_count = descriptor->field_count()) {
+    const FieldDescriptor* begin = descriptor->field(0);
+    const FieldDescriptor* end = begin + field_count;
+    GOOGLE_DCHECK_EQ(descriptor->field(field_count - 1), end - 1);
+
+    if (check_fields) {
+      // Check required fields of this message.
+      for (const FieldDescriptor* field = begin; field != end; ++field) {
+        if (field->is_required() && !reflection->HasField(message, field)) {
+          return false;
+        }
+      }
+    }
+
+    if (check_descendants) {
+      for (const FieldDescriptor* field = begin; field != end; ++field) {
+        if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          const Descriptor* message_type = field->message_type();
+          if (PROTOBUF_PREDICT_FALSE(message_type->options().map_entry())) {
+            if (message_type->field(1)->cpp_type() ==
+                FieldDescriptor::CPPTYPE_MESSAGE) {
+              const MapFieldBase* map_field =
+                  reflection->GetMapData(message, field);
+              if (map_field->IsMapValid()) {
+                MapIterator it(const_cast<Message*>(&message), field);
+                MapIterator end_map(const_cast<Message*>(&message), field);
+                for (map_field->MapBegin(&it), map_field->MapEnd(&end_map);
+                     it != end_map; ++it) {
+                  if (!it.GetValueRef().GetMessageValue().IsInitialized()) {
+                    return false;
+                  }
+                }
+              }
+            }
+          } else if (field->is_repeated()) {
+            const int size = reflection->FieldSize(message, field);
+            for (int j = 0; j < size; j++) {
+              if (!reflection->GetRepeatedMessage(message, field, j)
+                       .IsInitialized()) {
+                return false;
+              }
+            }
+          } else if (reflection->HasField(message, field)) {
+            if (!reflection->GetMessage(message, field).IsInitialized()) {
+              return false;
+            }
+          }
+        }
+      }
+    }
+  }
+  if (check_descendants && reflection->HasExtensionSet(message) &&
+      !reflection->GetExtensionSet(message).IsInitialized()) {
+    return false;
+  }
+  return true;
+}
+
+bool ReflectionOps::IsInitialized(const Message& message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = GetReflectionOrDie(message);
+
+  // Check required fields of this message.
+  {
+    const int field_count = descriptor->field_count();
+    for (int i = 0; i < field_count; i++) {
+      if (descriptor->field(i)->is_required()) {
+        if (!reflection->HasField(message, descriptor->field(i))) {
+          return false;
+        }
+      }
+    }
+  }
+
+  // Check that sub-messages are initialized.
+  std::vector<const FieldDescriptor*> fields;
+  // Should be safe to skip stripped fields because required fields are not
+  // stripped.
+  reflection->ListFieldsOmitStripped(message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+      if (field->is_map()) {
+        const FieldDescriptor* value_field = field->message_type()->field(1);
+        if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          const MapFieldBase* map_field =
+              reflection->GetMapData(message, field);
+          if (map_field->IsMapValid()) {
+            MapIterator iter(const_cast<Message*>(&message), field);
+            MapIterator end(const_cast<Message*>(&message), field);
+            for (map_field->MapBegin(&iter), map_field->MapEnd(&end);
+                 iter != end; ++iter) {
+              if (!iter.GetValueRef().GetMessageValue().IsInitialized()) {
+                return false;
+              }
+            }
+            continue;
+          }
+        } else {
+          continue;
+        }
+      }
+
+      if (field->is_repeated()) {
+        int size = reflection->FieldSize(message, field);
+
+        for (int j = 0; j < size; j++) {
+          if (!reflection->GetRepeatedMessage(message, field, j)
+                   .IsInitialized()) {
+            return false;
+          }
+        }
+      } else {
+        if (!reflection->GetMessage(message, field).IsInitialized()) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+static bool IsMapValueMessageTyped(const FieldDescriptor* map_field) {
+  return map_field->message_type()->field(1)->cpp_type() ==
+         FieldDescriptor::CPPTYPE_MESSAGE;
+}
+
+void ReflectionOps::DiscardUnknownFields(Message* message) {
+  const Reflection* reflection = GetReflectionOrDie(*message);
+
+  reflection->MutableUnknownFields(message)->Clear();
+
+  // Walk through the fields of this message and DiscardUnknownFields on any
+  // messages present.
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    // Skip over non-message fields.
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+      continue;
+    }
+    // Discard the unknown fields in maps that contain message values.
+    if (field->is_map() && IsMapValueMessageTyped(field)) {
+      const MapFieldBase* map_field =
+          reflection->MutableMapData(message, field);
+      if (map_field->IsMapValid()) {
+        MapIterator iter(message, field);
+        MapIterator end(message, field);
+        for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end;
+             ++iter) {
+          iter.MutableValueRef()->MutableMessageValue()->DiscardUnknownFields();
+        }
+      }
+      // Discard every unknown field inside messages in a repeated field.
+    } else if (field->is_repeated()) {
+      int size = reflection->FieldSize(*message, field);
+      for (int j = 0; j < size; j++) {
+        reflection->MutableRepeatedMessage(message, field, j)
+            ->DiscardUnknownFields();
+      }
+      // Discard the unknown fields inside an optional message.
+    } else {
+      reflection->MutableMessage(message, field)->DiscardUnknownFields();
+    }
+  }
+}
+
+static std::string SubMessagePrefix(const std::string& prefix,
+                                    const FieldDescriptor* field, int index) {
+  std::string result(prefix);
+  if (field->is_extension()) {
+    result.append("(");
+    result.append(field->full_name());
+    result.append(")");
+  } else {
+    result.append(field->name());
+  }
+  if (index != -1) {
+    result.append("[");
+    result.append(StrCat(index));
+    result.append("]");
+  }
+  result.append(".");
+  return result;
+}
+
+void ReflectionOps::FindInitializationErrors(const Message& message,
+                                             const std::string& prefix,
+                                             std::vector<std::string>* errors) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = GetReflectionOrDie(message);
+
+  // Check required fields of this message.
+  {
+    const int field_count = descriptor->field_count();
+    for (int i = 0; i < field_count; i++) {
+      if (descriptor->field(i)->is_required()) {
+        if (!reflection->HasField(message, descriptor->field(i))) {
+          errors->push_back(prefix + descriptor->field(i)->name());
+        }
+      }
+    }
+  }
+
+  // Check sub-messages.
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFieldsOmitStripped(message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+      if (field->is_repeated()) {
+        int size = reflection->FieldSize(message, field);
+
+        for (int j = 0; j < size; j++) {
+          const Message& sub_message =
+              reflection->GetRepeatedMessage(message, field, j);
+          FindInitializationErrors(sub_message,
+                                   SubMessagePrefix(prefix, field, j), errors);
+        }
+      } else {
+        const Message& sub_message = reflection->GetMessage(message, field);
+        FindInitializationErrors(sub_message,
+                                 SubMessagePrefix(prefix, field, -1), errors);
+      }
+    }
+  }
+}
+
+void GenericSwap(Message* lhs, Message* rhs) {
+#ifndef PROTOBUF_FORCE_COPY_IN_SWAP
+  GOOGLE_DCHECK(Arena::InternalGetOwningArena(lhs) !=
+         Arena::InternalGetOwningArena(rhs));
+  GOOGLE_DCHECK(Arena::InternalGetOwningArena(lhs) != nullptr ||
+         Arena::InternalGetOwningArena(rhs) != nullptr);
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+  // At least one of these must have an arena, so make `rhs` point to it.
+  Arena* arena = Arena::InternalGetOwningArena(rhs);
+  if (arena == nullptr) {
+    std::swap(lhs, rhs);
+    arena = Arena::InternalGetOwningArena(rhs);
+  }
+
+  // Improve efficiency by placing the temporary on an arena so that messages
+  // are copied twice rather than three times.
+  Message* tmp = rhs->New(arena);
+  tmp->CheckTypeAndMergeFrom(*lhs);
+  lhs->Clear();
+  lhs->CheckTypeAndMergeFrom(*rhs);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  rhs->Clear();
+  rhs->CheckTypeAndMergeFrom(*tmp);
+  if (arena == nullptr) delete tmp;
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  rhs->GetReflection()->Swap(tmp, rhs);
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/reflection_ops.h b/src/google/protobuf/reflection_ops.h
new file mode 100644
index 0000000..0a45702
--- /dev/null
+++ b/src/google/protobuf/reflection_ops.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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// 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_REFLECTION_OPS_H__
+#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Basic operations that can be performed using reflection.
+// These can be used as a cheap way to implement the corresponding
+// methods of the Message interface, though they are likely to be
+// slower than implementations tailored for the specific message type.
+//
+// This class should stay limited to operations needed to implement
+// the Message interface.
+//
+// This class is really a namespace that contains only static methods.
+class PROTOBUF_EXPORT ReflectionOps {
+ public:
+  static void Copy(const Message& from, Message* to);
+  static void Merge(const Message& from, Message* to);
+  static void Clear(Message* message);
+  static bool IsInitialized(const Message& message);
+  static bool IsInitialized(const Message& message, bool check_fields,
+                            bool check_descendants);
+  static void DiscardUnknownFields(Message* message);
+
+  // Finds all unset required fields in the message and adds their full
+  // paths (e.g. "foo.bar[5].baz") to *names.  "prefix" will be attached to
+  // the front of each name.
+  static void FindInitializationErrors(const Message& message,
+                                       const std::string& prefix,
+                                       std::vector<std::string>* errors);
+
+ private:
+  // All methods are static.  No need to construct.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_OPS_H__
diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc
new file mode 100644
index 0000000..513ce47
--- /dev/null
+++ b/src/google/protobuf/reflection_ops_unittest.cc
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/reflection_ops.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(ReflectionOpsTest, SanityCheck) {
+  unittest::TestAllTypes message;
+
+  TestUtil::SetAllFields(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(ReflectionOpsTest, Copy) {
+  unittest::TestAllTypes message, message2;
+
+  TestUtil::SetAllFields(&message);
+
+  ReflectionOps::Copy(message, &message2);
+
+  TestUtil::ExpectAllFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  ReflectionOps::Copy(message2, &message2);
+  TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(ReflectionOpsTest, CopyExtensions) {
+  unittest::TestAllExtensions message, message2;
+
+  TestUtil::SetAllExtensions(&message);
+
+  ReflectionOps::Copy(message, &message2);
+
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ReflectionOpsTest, CopyOneof) {
+  unittest::TestOneof2 message, message2;
+  TestUtil::SetOneof1(&message);
+  ReflectionOps::Copy(message, &message2);
+  TestUtil::ExpectOneofSet1(message2);
+
+  TestUtil::SetOneof2(&message);
+  TestUtil::ExpectOneofSet2(message);
+  ReflectionOps::Copy(message, &message2);
+  TestUtil::ExpectOneofSet2(message2);
+}
+
+TEST(ReflectionOpsTest, Merge) {
+  // Note:  Copy is implemented in terms of Merge() so technically the Copy
+  //   test already tested most of this.
+
+  unittest::TestAllTypes message, message2;
+
+  TestUtil::SetAllFields(&message);
+
+  // This field will test merging into an empty spot.
+  message2.set_optional_int32(message.optional_int32());
+  message.clear_optional_int32();
+
+  // This tests overwriting.
+  message2.set_optional_string(message.optional_string());
+  message.set_optional_string("something else");
+
+  // This tests concatenating.
+  message2.add_repeated_int32(message.repeated_int32(1));
+  int32_t i = message.repeated_int32(0);
+  message.clear_repeated_int32();
+  message.add_repeated_int32(i);
+
+  ReflectionOps::Merge(message2, &message);
+
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(ReflectionOpsTest, MergeExtensions) {
+  // Note:  Copy is implemented in terms of Merge() so technically the Copy
+  //   test already tested most of this.
+
+  unittest::TestAllExtensions message, message2;
+
+  TestUtil::SetAllExtensions(&message);
+
+  // This field will test merging into an empty spot.
+  message2.SetExtension(
+      unittest::optional_int32_extension,
+      message.GetExtension(unittest::optional_int32_extension));
+  message.ClearExtension(unittest::optional_int32_extension);
+
+  // This tests overwriting.
+  message2.SetExtension(
+      unittest::optional_string_extension,
+      message.GetExtension(unittest::optional_string_extension));
+  message.SetExtension(unittest::optional_string_extension, "something else");
+
+  // This tests concatenating.
+  message2.AddExtension(
+      unittest::repeated_int32_extension,
+      message.GetExtension(unittest::repeated_int32_extension, 1));
+  int32_t i = message.GetExtension(unittest::repeated_int32_extension, 0);
+  message.ClearExtension(unittest::repeated_int32_extension);
+  message.AddExtension(unittest::repeated_int32_extension, i);
+
+  ReflectionOps::Merge(message2, &message);
+
+  TestUtil::ExpectAllExtensionsSet(message);
+}
+
+TEST(ReflectionOpsTest, MergeUnknown) {
+  // Test that the messages' UnknownFieldSets are correctly merged.
+  unittest::TestEmptyMessage message1, message2;
+  message1.mutable_unknown_fields()->AddVarint(1234, 1);
+  message2.mutable_unknown_fields()->AddVarint(1234, 2);
+
+  ReflectionOps::Merge(message2, &message1);
+
+  ASSERT_EQ(2, message1.unknown_fields().field_count());
+  ASSERT_EQ(UnknownField::TYPE_VARINT,
+            message1.unknown_fields().field(0).type());
+  EXPECT_EQ(1, message1.unknown_fields().field(0).varint());
+  ASSERT_EQ(UnknownField::TYPE_VARINT,
+            message1.unknown_fields().field(1).type());
+  EXPECT_EQ(2, message1.unknown_fields().field(1).varint());
+}
+
+TEST(ReflectionOpsTest, MergeOneof) {
+  unittest::TestOneof2 message1, message2;
+  TestUtil::SetOneof1(&message1);
+
+  // Merge to empty message
+  ReflectionOps::Merge(message1, &message2);
+  TestUtil::ExpectOneofSet1(message2);
+
+  // Merge with the same oneof fields
+  ReflectionOps::Merge(message1, &message2);
+  TestUtil::ExpectOneofSet1(message2);
+
+  // Merge with different oneof fields
+  TestUtil::SetOneof2(&message1);
+  ReflectionOps::Merge(message1, &message2);
+  TestUtil::ExpectOneofSet2(message2);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST(ReflectionOpsTest, MergeFromSelf) {
+  // Note:  Copy is implemented in terms of Merge() so technically the Copy
+  //   test already tested most of this.
+
+  unittest::TestAllTypes message;
+
+  EXPECT_DEATH(ReflectionOps::Merge(message, &message), "&from");
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST(ReflectionOpsTest, Clear) {
+  unittest::TestAllTypes message;
+
+  TestUtil::SetAllFields(&message);
+
+  ReflectionOps::Clear(&message);
+
+  TestUtil::ExpectClear(message);
+
+  // Check that getting embedded messages returns the objects created during
+  // SetAllFields() rather than default instances.
+  EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(),
+            &message.optionalgroup());
+  EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
+            &message.optional_nested_message());
+  EXPECT_NE(&unittest::ForeignMessage::default_instance(),
+            &message.optional_foreign_message());
+  EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
+            &message.optional_import_message());
+}
+
+TEST(ReflectionOpsTest, ClearExtensions) {
+  unittest::TestAllExtensions message;
+
+  TestUtil::SetAllExtensions(&message);
+
+  ReflectionOps::Clear(&message);
+
+  TestUtil::ExpectExtensionsClear(message);
+
+  // Check that getting embedded messages returns the objects created during
+  // SetAllExtensions() rather than default instances.
+  EXPECT_NE(&unittest::OptionalGroup_extension::default_instance(),
+            &message.GetExtension(unittest::optionalgroup_extension));
+  EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
+            &message.GetExtension(unittest::optional_nested_message_extension));
+  EXPECT_NE(
+      &unittest::ForeignMessage::default_instance(),
+      &message.GetExtension(unittest::optional_foreign_message_extension));
+  EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
+            &message.GetExtension(unittest::optional_import_message_extension));
+}
+
+TEST(ReflectionOpsTest, ClearUnknown) {
+  // Test that the message's UnknownFieldSet is correctly cleared.
+  unittest::TestEmptyMessage message;
+  message.mutable_unknown_fields()->AddVarint(1234, 1);
+
+  ReflectionOps::Clear(&message);
+
+  EXPECT_EQ(0, message.unknown_fields().field_count());
+}
+
+TEST(ReflectionOpsTest, ClearOneof) {
+  unittest::TestOneof2 message;
+
+  TestUtil::ExpectOneofClear(message);
+  TestUtil::SetOneof1(&message);
+  TestUtil::ExpectOneofSet1(message);
+  ReflectionOps::Clear(&message);
+  TestUtil::ExpectOneofClear(message);
+
+  TestUtil::SetOneof1(&message);
+  TestUtil::ExpectOneofSet1(message);
+  TestUtil::SetOneof2(&message);
+  TestUtil::ExpectOneofSet2(message);
+  ReflectionOps::Clear(&message);
+  TestUtil::ExpectOneofClear(message);
+}
+
+TEST(ReflectionOpsTest, DiscardUnknownFields) {
+  unittest::TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+
+  // Set some unknown fields in message.
+  message.mutable_unknown_fields()->AddVarint(123456, 654321);
+  message.mutable_optional_nested_message()
+      ->mutable_unknown_fields()
+      ->AddVarint(123456, 654321);
+  message.mutable_repeated_nested_message(0)
+      ->mutable_unknown_fields()
+      ->AddVarint(123456, 654321);
+
+  EXPECT_EQ(1, message.unknown_fields().field_count());
+  EXPECT_EQ(1,
+            message.optional_nested_message().unknown_fields().field_count());
+  EXPECT_EQ(1,
+            message.repeated_nested_message(0).unknown_fields().field_count());
+
+  // Discard them.
+  ReflectionOps::DiscardUnknownFields(&message);
+  TestUtil::ExpectAllFieldsSet(message);
+
+  EXPECT_EQ(0, message.unknown_fields().field_count());
+  EXPECT_EQ(0,
+            message.optional_nested_message().unknown_fields().field_count());
+  EXPECT_EQ(0,
+            message.repeated_nested_message(0).unknown_fields().field_count());
+}
+
+TEST(ReflectionOpsTest, DiscardUnknownExtensions) {
+  unittest::TestAllExtensions message;
+  TestUtil::SetAllExtensions(&message);
+
+  // Set some unknown fields.
+  message.mutable_unknown_fields()->AddVarint(123456, 654321);
+  message.MutableExtension(unittest::optional_nested_message_extension)
+      ->mutable_unknown_fields()
+      ->AddVarint(123456, 654321);
+  message.MutableExtension(unittest::repeated_nested_message_extension, 0)
+      ->mutable_unknown_fields()
+      ->AddVarint(123456, 654321);
+
+  EXPECT_EQ(1, message.unknown_fields().field_count());
+  EXPECT_EQ(1, message.GetExtension(unittest::optional_nested_message_extension)
+                   .unknown_fields()
+                   .field_count());
+  EXPECT_EQ(1,
+            message.GetExtension(unittest::repeated_nested_message_extension, 0)
+                .unknown_fields()
+                .field_count());
+
+  // Discard them.
+  ReflectionOps::DiscardUnknownFields(&message);
+  TestUtil::ExpectAllExtensionsSet(message);
+
+  EXPECT_EQ(0, message.unknown_fields().field_count());
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_nested_message_extension)
+                   .unknown_fields()
+                   .field_count());
+  EXPECT_EQ(0,
+            message.GetExtension(unittest::repeated_nested_message_extension, 0)
+                .unknown_fields()
+                .field_count());
+}
+
+TEST(ReflectionOpsTest, IsInitialized) {
+  unittest::TestRequired message;
+
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+  message.set_a(1);
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, true, true));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+  message.set_b(2);
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, true, true));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+  message.set_c(3);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+}
+
+TEST(ReflectionOpsTest, ForeignIsInitialized) {
+  unittest::TestRequiredForeign message;
+
+  // Starts out initialized because the foreign message is itself an optional
+  // field.
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Once we create that field, the message is no longer initialized.
+  message.mutable_optional_message();
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Initialize it.  Now we're initialized.
+  message.mutable_optional_message()->set_a(1);
+  message.mutable_optional_message()->set_b(2);
+  message.mutable_optional_message()->set_c(3);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Add a repeated version of the message.  No longer initialized.
+  unittest::TestRequired* sub_message = message.add_repeated_message();
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Initialize that repeated version.
+  sub_message->set_a(1);
+  sub_message->set_b(2);
+  sub_message->set_c(3);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+}
+
+TEST(ReflectionOpsTest, ExtensionIsInitialized) {
+  unittest::TestAllExtensions message;
+
+  // Starts out initialized because the foreign message is itself an optional
+  // field.
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Once we create that field, the message is no longer initialized.
+  message.MutableExtension(unittest::TestRequired::single);
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Initialize it.  Now we're initialized.
+  message.MutableExtension(unittest::TestRequired::single)->set_a(1);
+  message.MutableExtension(unittest::TestRequired::single)->set_b(2);
+  message.MutableExtension(unittest::TestRequired::single)->set_c(3);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Add a repeated version of the message.  No longer initialized.
+  message.AddExtension(unittest::TestRequired::multi);
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, false, true));
+
+  // Initialize that repeated version.
+  message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1);
+  message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2);
+  message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+}
+
+TEST(ReflectionOpsTest, OneofIsInitialized) {
+  unittest::TestRequiredOneof message;
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+
+  message.mutable_foo_message();
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, false, true));
+
+  message.set_foo_int(1);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+
+  message.mutable_foo_message();
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_FALSE(ReflectionOps::IsInitialized(message, false, true));
+  message.mutable_foo_message()->set_required_double(0.1);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, true, false));
+  EXPECT_TRUE(ReflectionOps::IsInitialized(message, false, true));
+}
+
+static std::string FindInitializationErrors(const Message& message) {
+  std::vector<std::string> errors;
+  ReflectionOps::FindInitializationErrors(message, "", &errors);
+  return Join(errors, ",");
+}
+
+TEST(ReflectionOpsTest, FindInitializationErrors) {
+  unittest::TestRequired message;
+  EXPECT_EQ("a,b,c", FindInitializationErrors(message));
+}
+
+TEST(ReflectionOpsTest, FindForeignInitializationErrors) {
+  unittest::TestRequiredForeign message;
+  message.mutable_optional_message();
+  message.add_repeated_message();
+  message.add_repeated_message();
+  EXPECT_EQ(
+      "optional_message.a,"
+      "optional_message.b,"
+      "optional_message.c,"
+      "repeated_message[0].a,"
+      "repeated_message[0].b,"
+      "repeated_message[0].c,"
+      "repeated_message[1].a,"
+      "repeated_message[1].b,"
+      "repeated_message[1].c",
+      FindInitializationErrors(message));
+}
+
+TEST(ReflectionOpsTest, FindExtensionInitializationErrors) {
+  unittest::TestAllExtensions message;
+  message.MutableExtension(unittest::TestRequired::single);
+  message.AddExtension(unittest::TestRequired::multi);
+  message.AddExtension(unittest::TestRequired::multi);
+  EXPECT_EQ(
+      "(protobuf_unittest.TestRequired.single).a,"
+      "(protobuf_unittest.TestRequired.single).b,"
+      "(protobuf_unittest.TestRequired.single).c,"
+      "(protobuf_unittest.TestRequired.multi)[0].a,"
+      "(protobuf_unittest.TestRequired.multi)[0].b,"
+      "(protobuf_unittest.TestRequired.multi)[0].c,"
+      "(protobuf_unittest.TestRequired.multi)[1].a,"
+      "(protobuf_unittest.TestRequired.multi)[1].b,"
+      "(protobuf_unittest.TestRequired.multi)[1].c",
+      FindInitializationErrors(message));
+}
+
+TEST(ReflectionOpsTest, FindOneofInitializationErrors) {
+  unittest::TestRequiredOneof message;
+  message.mutable_foo_message();
+  EXPECT_EQ("foo_message.required_double", FindInitializationErrors(message));
+}
+
+TEST(ReflectionOpsTest, GenericSwap) {
+  Arena arena;
+  {
+    unittest::TestAllTypes message;
+    auto* arena_message = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+    TestUtil::SetAllFields(arena_message);
+    const uint64_t initial_arena_size = arena.SpaceUsed();
+
+    GenericSwap(&message, arena_message);
+
+    TestUtil::ExpectAllFieldsSet(message);
+    TestUtil::ExpectClear(*arena_message);
+    // The temp should be allocated on the arena in this case.
+    EXPECT_GT(arena.SpaceUsed(), initial_arena_size);
+  }
+  {
+    unittest::TestAllTypes message;
+    auto* arena_message = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+    TestUtil::SetAllFields(arena_message);
+    const uint64_t initial_arena_size = arena.SpaceUsed();
+
+    GenericSwap(arena_message, &message);
+
+    TestUtil::ExpectAllFieldsSet(message);
+    TestUtil::ExpectClear(*arena_message);
+    // The temp should be allocated on the arena in this case.
+    EXPECT_GT(arena.SpaceUsed(), initial_arena_size);
+  }
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/reflection_tester.cc b/src/google/protobuf/reflection_tester.cc
new file mode 100644
index 0000000..4c6db03
--- /dev/null
+++ b/src/google/protobuf/reflection_tester.cc
@@ -0,0 +1,1673 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/reflection_tester.h>
+
+#include <gtest/gtest.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+
+// Must include last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+MapReflectionTester::MapReflectionTester(const Descriptor* base_descriptor)
+    : base_descriptor_(base_descriptor) {
+  const DescriptorPool* pool = base_descriptor->file()->pool();
+  std::string package = base_descriptor->file()->package();
+
+  map_enum_foo_ = pool->FindEnumValueByName(package + ".MAP_ENUM_FOO");
+  map_enum_bar_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAR");
+  map_enum_baz_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAZ");
+
+  foreign_c_ = pool->FindFieldByName(package + ".ForeignMessage.c");
+  map_int32_int32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.key");
+  map_int32_int32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.value");
+  map_int64_int64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.key");
+  map_int64_int64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.value");
+  map_uint32_uint32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.key");
+  map_uint32_uint32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.value");
+  map_uint64_uint64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.key");
+  map_uint64_uint64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.value");
+  map_sint32_sint32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.key");
+  map_sint32_sint32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.value");
+  map_sint64_sint64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.key");
+  map_sint64_sint64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.value");
+  map_fixed32_fixed32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.key");
+  map_fixed32_fixed32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.value");
+  map_fixed64_fixed64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.key");
+  map_fixed64_fixed64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.value");
+  map_sfixed32_sfixed32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSfixed32Sfixed32Entry.key");
+  map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapSfixed32Sfixed32Entry.value");
+  map_sfixed64_sfixed64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSfixed64Sfixed64Entry.key");
+  map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapSfixed64Sfixed64Entry.value");
+  map_int32_float_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.key");
+  map_int32_float_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.value");
+  map_int32_double_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.key");
+  map_int32_double_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.value");
+  map_bool_bool_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.key");
+  map_bool_bool_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.value");
+  map_string_string_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.key");
+  map_string_string_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.value");
+  map_int32_bytes_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.key");
+  map_int32_bytes_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.value");
+  map_int32_enum_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.key");
+  map_int32_enum_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.value");
+  map_int32_foreign_message_key_ = pool->FindFieldByName(
+      package + ".TestMap.MapInt32ForeignMessageEntry.key");
+  map_int32_foreign_message_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapInt32ForeignMessageEntry.value");
+
+  EXPECT_FALSE(map_enum_foo_ == nullptr);
+  EXPECT_FALSE(map_enum_bar_ == nullptr);
+  EXPECT_FALSE(map_enum_baz_ == nullptr);
+  EXPECT_FALSE(map_int32_int32_key_ == nullptr);
+  EXPECT_FALSE(map_int32_int32_val_ == nullptr);
+  EXPECT_FALSE(map_int64_int64_key_ == nullptr);
+  EXPECT_FALSE(map_int64_int64_val_ == nullptr);
+  EXPECT_FALSE(map_uint32_uint32_key_ == nullptr);
+  EXPECT_FALSE(map_uint32_uint32_val_ == nullptr);
+  EXPECT_FALSE(map_uint64_uint64_key_ == nullptr);
+  EXPECT_FALSE(map_uint64_uint64_val_ == nullptr);
+  EXPECT_FALSE(map_sint32_sint32_key_ == nullptr);
+  EXPECT_FALSE(map_sint32_sint32_val_ == nullptr);
+  EXPECT_FALSE(map_sint64_sint64_key_ == nullptr);
+  EXPECT_FALSE(map_sint64_sint64_val_ == nullptr);
+  EXPECT_FALSE(map_fixed32_fixed32_key_ == nullptr);
+  EXPECT_FALSE(map_fixed32_fixed32_val_ == nullptr);
+  EXPECT_FALSE(map_fixed64_fixed64_key_ == nullptr);
+  EXPECT_FALSE(map_fixed64_fixed64_val_ == nullptr);
+  EXPECT_FALSE(map_sfixed32_sfixed32_key_ == nullptr);
+  EXPECT_FALSE(map_sfixed32_sfixed32_val_ == nullptr);
+  EXPECT_FALSE(map_sfixed64_sfixed64_key_ == nullptr);
+  EXPECT_FALSE(map_sfixed64_sfixed64_val_ == nullptr);
+  EXPECT_FALSE(map_int32_float_key_ == nullptr);
+  EXPECT_FALSE(map_int32_float_val_ == nullptr);
+  EXPECT_FALSE(map_int32_double_key_ == nullptr);
+  EXPECT_FALSE(map_int32_double_val_ == nullptr);
+  EXPECT_FALSE(map_bool_bool_key_ == nullptr);
+  EXPECT_FALSE(map_bool_bool_val_ == nullptr);
+  EXPECT_FALSE(map_string_string_key_ == nullptr);
+  EXPECT_FALSE(map_string_string_val_ == nullptr);
+  EXPECT_FALSE(map_int32_bytes_key_ == nullptr);
+  EXPECT_FALSE(map_int32_bytes_val_ == nullptr);
+  EXPECT_FALSE(map_int32_enum_key_ == nullptr);
+  EXPECT_FALSE(map_int32_enum_val_ == nullptr);
+  EXPECT_FALSE(map_int32_foreign_message_key_ == nullptr);
+  EXPECT_FALSE(map_int32_foreign_message_val_ == nullptr);
+
+  std::vector<const FieldDescriptor*> all_map_descriptors = {
+      map_int32_int32_key_,
+      map_int32_int32_val_,
+      map_int64_int64_key_,
+      map_int64_int64_val_,
+      map_uint32_uint32_key_,
+      map_uint32_uint32_val_,
+      map_uint64_uint64_key_,
+      map_uint64_uint64_val_,
+      map_sint32_sint32_key_,
+      map_sint32_sint32_val_,
+      map_sint64_sint64_key_,
+      map_sint64_sint64_val_,
+      map_fixed32_fixed32_key_,
+      map_fixed32_fixed32_val_,
+      map_fixed64_fixed64_key_,
+      map_fixed64_fixed64_val_,
+      map_sfixed32_sfixed32_key_,
+      map_sfixed32_sfixed32_val_,
+      map_sfixed64_sfixed64_key_,
+      map_sfixed64_sfixed64_val_,
+      map_int32_float_key_,
+      map_int32_float_val_,
+      map_int32_double_key_,
+      map_int32_double_val_,
+      map_bool_bool_key_,
+      map_bool_bool_val_,
+      map_string_string_key_,
+      map_string_string_val_,
+      map_int32_bytes_key_,
+      map_int32_bytes_val_,
+      map_int32_enum_key_,
+      map_int32_enum_val_,
+      map_int32_foreign_message_key_,
+      map_int32_foreign_message_val_};
+  for (const FieldDescriptor* fdesc : all_map_descriptors) {
+    GOOGLE_CHECK(fdesc->containing_type() != nullptr) << fdesc->name();
+    if (fdesc->name() == "key") {
+      EXPECT_EQ(fdesc->containing_type()->map_key(), fdesc);
+    } else {
+      EXPECT_EQ(fdesc->name(), "value");
+      EXPECT_EQ(fdesc->containing_type()->map_value(), fdesc);
+    }
+  }
+}
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
+const FieldDescriptor* MapReflectionTester::F(const std::string& name) {
+  const FieldDescriptor* result = nullptr;
+  result = base_descriptor_->FindFieldByName(name);
+  GOOGLE_CHECK(result != nullptr);
+  return result;
+}
+
+void MapReflectionTester::SetMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = nullptr;
+  Message* sub_foreign_message = nullptr;
+
+  // Add first element.
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 0);
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 0);
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
+                                         0);
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
+                                         0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
+                                         0);
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
+                                         0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_key_, 0);
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_key_, 0);
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 0);
+  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
+                                         0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 0);
+  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
+                                          0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, false);
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, false);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
+                                          "0");
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
+                                          "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 0);
+  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
+                                          "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 0);
+  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
+                                        map_enum_bar_);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_int32_foreign_message_key_, 0);
+  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
+      sub_message, map_int32_foreign_message_val_, nullptr);
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 0);
+
+  // Add second element
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 1);
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 1);
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
+                                         1);
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
+                                         1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
+                                         1);
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
+                                         1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_key_, 1);
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_key_, 1);
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 1);
+  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
+                                         1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 1);
+  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
+                                          1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, true);
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, true);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
+                                          "1");
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
+                                          "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 1);
+  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
+                                          "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 1);
+  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
+                                        map_enum_baz_);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_int32_foreign_message_key_, 1);
+  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
+      sub_message, map_int32_foreign_message_val_, nullptr);
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 1);
+}
+
+void MapReflectionTester::SetMapFieldsViaMapReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  Message* sub_foreign_message = nullptr;
+  MapValueRef map_val;
+  MapValueConstRef map_val_const;
+
+  // Add first element.
+  MapKey map_key;
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_int32"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                 map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int64_int64"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                 map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_uint32_uint32"),
+                                          map_key, &map_val_const));
+  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_FALSE(reflection->LookupMapValue(*message, F("map_bool_bool"), map_key,
+                                          &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"),
+                                                 map_key, &map_val));
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("0");
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_string_string"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_string_string"), map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_bytes"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"),
+                                                 map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_enum"),
+                                          map_key, &map_val_const));
+  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_FALSE(reflection->LookupMapValue(
+      *message, F("map_int32_foreign_message"), map_key, &map_val_const));
+  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::GetMapValueViaMapReflection(
+    Message* message, const std::string& field_name, const MapKey& map_key,
+    MapValueRef* map_val) {
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
+                                                  map_key, map_val));
+}
+
+Message* MapReflectionTester::GetMapEntryViaReflection(
+    Message* message, const std::string& field_name, int index) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MutableRepeatedMessage(message, F(field_name), index);
+}
+
+MapIterator MapReflectionTester::MapBegin(Message* message,
+                                          const std::string& field_name) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MapBegin(message, F(field_name));
+}
+
+MapIterator MapReflectionTester::MapEnd(Message* message,
+                                        const std::string& field_name) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MapEnd(message, F(field_name));
+}
+
+int MapReflectionTester::MapSize(const Message& message,
+                                 const std::string& field_name) {
+  const Reflection* reflection = message.GetReflection();
+  return reflection->MapSize(message, F(field_name));
+}
+
+void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, F("map_int32_int32"));
+  reflection->ClearField(message, F("map_int64_int64"));
+  reflection->ClearField(message, F("map_uint32_uint32"));
+  reflection->ClearField(message, F("map_uint64_uint64"));
+  reflection->ClearField(message, F("map_sint32_sint32"));
+  reflection->ClearField(message, F("map_sint64_sint64"));
+  reflection->ClearField(message, F("map_fixed32_fixed32"));
+  reflection->ClearField(message, F("map_fixed64_fixed64"));
+  reflection->ClearField(message, F("map_sfixed32_sfixed32"));
+  reflection->ClearField(message, F("map_sfixed64_sfixed64"));
+  reflection->ClearField(message, F("map_int32_float"));
+  reflection->ClearField(message, F("map_int32_double"));
+  reflection->ClearField(message, F("map_bool_bool"));
+  reflection->ClearField(message, F("map_string_string"));
+  reflection->ClearField(message, F("map_int32_bytes"));
+  reflection->ClearField(message, F("map_int32_enum"));
+  reflection->ClearField(message, F("map_int32_foreign_message"));
+}
+
+void MapReflectionTester::ModifyMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  MapValueRef map_val;
+  Message* sub_foreign_message;
+
+  // Modify the second element
+  MapKey map_key;
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                  map_key, &map_val));
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                  map_key, &map_val));
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
+                                     &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
+                                     &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
+                                     map_key, &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
+                                     map_key, &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
+                                     &map_val);
+  map_val.SetFloatValue(2.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
+                                     &map_val);
+  map_val.SetDoubleValue(2.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
+                                     &map_val);
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
+                                     &map_val);
+  map_val.SetEnumValue(map_enum_foo_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 2);
+}
+
+void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->RemoveLast(message, field);
+  }
+}
+
+void MapReflectionTester::ReleaseLastMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    Message* released = reflection->ReleaseLast(message, field);
+    ASSERT_TRUE(released != nullptr)
+        << "ReleaseLast returned nullptr for: " << field->name();
+    delete released;
+  }
+}
+
+void MapReflectionTester::SwapMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->SwapElements(message, field, 0, 1);
+  }
+}
+
+void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = nullptr;
+
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflection(
+    const Message& message) {
+  std::string scratch;
+  const Reflection* reflection = message.GetReflection();
+  const Message* sub_message;
+  MapKey map_key;
+  MapValueConstRef map_value_const_ref;
+
+  // -----------------------------------------------------------------
+
+  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_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_int32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_int32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_int32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_TRUE(
+            reflection->ContainsMapKey(message, F("map_int32_int32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_int32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int64_int64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_int64_int64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_int64_int64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt64Value(i);
+        EXPECT_TRUE(
+            reflection->ContainsMapKey(message, F("map_int64_int64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int64_int64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint32_t, uint32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_uint32_uint32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
+        uint32_t key = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_uint32_uint32_key_);
+        uint32_t val = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_uint32_uint32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt32Value(i);
+        EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint32_uint32"),
+                                               map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint32_uint32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint64_t, uint64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_uint64_uint64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
+        uint64_t key = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_uint64_uint64_key_);
+        uint64_t val = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_uint64_uint64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt64Value(i);
+        EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint64_uint64"),
+                                               map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint64_uint64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_sint32_sint32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sint32_sint32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sint32_sint32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sint32_sint32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint32_sint32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_sint64_sint64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sint64_sint64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sint64_sint64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt64Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sint64_sint64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint64_sint64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint32_t, uint32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_fixed32_fixed32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_fixed32_fixed32"), i);
+        uint32_t key = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_fixed32_fixed32_key_);
+        uint32_t val = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_fixed32_fixed32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_fixed32_fixed32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(
+            message, F("map_fixed32_fixed32"), map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint64_t, uint64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_fixed64_fixed64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_fixed64_fixed64"), i);
+        uint64_t key = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_fixed64_fixed64_key_);
+        uint64_t val = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_fixed64_fixed64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt64Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_fixed64_fixed64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(
+            message, F("map_fixed64_fixed64"), map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(
+              message, F("map_sfixed32_sfixed32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_sfixed32_sfixed32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sfixed32_sfixed32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sfixed32_sfixed32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sfixed32_sfixed32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message,
+                                               F("map_sfixed32_sfixed32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(
+              message, F("map_sfixed64_sfixed64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_sfixed64_sfixed64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sfixed64_sfixed64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sfixed64_sfixed64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt64Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sfixed64_sfixed64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message,
+                                               F("map_sfixed64_sfixed64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_float"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_float_key_);
+        float val = sub_message->GetReflection()->GetFloat(
+            *sub_message, map_int32_float_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_float"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_float"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetFloatValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_double"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_double_key_);
+        double val = sub_message->GetReflection()->GetDouble(
+            *sub_message, map_int32_double_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_double"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_double"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetDoubleValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    std::vector<bool> keys = {false, true};
+    std::vector<bool> vals = {false, true};
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_bool_bool"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
+        bool key = sub_message->GetReflection()->GetBool(*sub_message,
+                                                         map_bool_bool_key_);
+        bool val = sub_message->GetReflection()->GetBool(*sub_message,
+                                                         map_bool_bool_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetBoolValue(keys[i]);
+        EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"),
+                                                   map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_bool_bool"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetBoolValue(), vals[i]);
+      }
+    }
+  }
+  {
+    std::map<std::string, std::string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    std::vector<std::string> keys = {"0", "1"};
+    std::vector<std::string> vals = {"0", "1"};
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_string_string"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
+        std::string key = sub_message->GetReflection()->GetString(
+            *sub_message, map_string_string_key_);
+        std::string val = sub_message->GetReflection()->GetString(
+            *sub_message, map_string_string_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetStringValue(keys[i]);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_string_string"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_string_string"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetStringValue(), vals[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, std::string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_bytes"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_bytes_key_);
+        std::string val = sub_message->GetReflection()->GetString(
+            *sub_message, map_int32_bytes_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_bytes"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_bytes"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetStringValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_enum"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_enum_key_);
+        const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
+            *sub_message, map_int32_enum_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"),
+                                                   map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_enum"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetEnumValue(), map[i]->number());
+      }
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(
+              message, F("map_int32_foreign_message"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_int32_foreign_message"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_foreign_message_key_);
+        const Message& foreign_message =
+            sub_message->GetReflection()->GetMessage(
+                *sub_message, map_int32_foreign_message_val_);
+        int32_t val = foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                                foreign_c_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_foreign_message"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message,
+                                               F("map_int32_foreign_message"),
+                                               map_key, &map_value_const_ref));
+        const Message& foreign_message = map_value_const_ref.GetMessageValue();
+        EXPECT_EQ(foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                            foreign_c_),
+                  map[i]);
+      }
+    }
+  }
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
+    Message* message) {
+  std::string scratch;
+  std::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_t, int32_t> 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->SpaceUsedLong();
+      message->ByteSizeLong();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int64_t, int64_t> 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_t, uint32_t> 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_t, uint64_t> 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_t, int32_t> 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_t, int64_t> 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_t, uint32_t> 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_t, uint64_t> 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_t, int32_t> 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_t, 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_t, 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<std::string, std::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->SpaceUsedLong();
+      message->ByteSizeLong();
+      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
+                iter.GetValueRef().GetStringValue());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int32_t, std::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_t, 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_t, int32_t> 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->SpaceUsedLong();
+      message->ByteSizeLong();
+      const Message& sub_message = iter.GetValueRef().GetMessageValue();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
+    }
+    EXPECT_EQ(size, 2);
+  }
+}
+
+void MapReflectionTester::ExpectClearViaReflection(const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  // Map fields are empty.
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
+  EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message"))
+                  ->IsMapValid());
+}
+
+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")));
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/reflection_tester.h b/src/google/protobuf/reflection_tester.h
new file mode 100644
index 0000000..3a2dc81
--- /dev/null
+++ b/src/google/protobuf/reflection_tester.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.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_TESTER_H__
+#define GOOGLE_PROTOBUF_REFLECTION_TESTER_H__
+
+#include <google/protobuf/message.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Provides APIs to test protocol buffers reflectively.
+class MapReflectionTester {
+ public:
+  // base_descriptor must be a descriptor for TestMap, which is used for
+  // MapReflectionTester to fetch the FieldDescriptors needed to use the
+  // reflection interface.
+  explicit MapReflectionTester(const Descriptor* base_descriptor);
+
+  void SetMapFieldsViaReflection(Message* message);
+  void SetMapFieldsViaMapReflection(Message* message);
+  void ClearMapFieldsViaReflection(Message* message);
+  void ModifyMapFieldsViaReflection(Message* message);
+  void RemoveLastMapsViaReflection(Message* message);
+  void ReleaseLastMapsViaReflection(Message* message);
+  void SwapMapsViaReflection(Message* message);
+  void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message);
+  void ExpectMapFieldsSetViaReflection(const Message& message);
+  void ExpectMapFieldsSetViaReflectionIterator(Message* message);
+  void ExpectClearViaReflection(const Message& message);
+  void ExpectClearViaReflectionIterator(Message* message);
+  void GetMapValueViaMapReflection(Message* message,
+                                   const std::string& field_name,
+                                   const MapKey& map_key, MapValueRef* map_val);
+  Message* GetMapEntryViaReflection(Message* message,
+                                    const std::string& field_name, int index);
+  MapIterator MapBegin(Message* message, const std::string& field_name);
+  MapIterator MapEnd(Message* message, const std::string& field_name);
+  int MapSize(const Message& message, const std::string& field_name);
+
+ private:
+  const FieldDescriptor* F(const std::string& name);
+
+  const Descriptor* base_descriptor_;
+
+  const EnumValueDescriptor* map_enum_bar_;
+  const EnumValueDescriptor* map_enum_baz_;
+  const EnumValueDescriptor* map_enum_foo_;
+
+  const FieldDescriptor* foreign_c_;
+  const FieldDescriptor* map_int32_int32_key_;
+  const FieldDescriptor* map_int32_int32_val_;
+  const FieldDescriptor* map_int64_int64_key_;
+  const FieldDescriptor* map_int64_int64_val_;
+  const FieldDescriptor* map_uint32_uint32_key_;
+  const FieldDescriptor* map_uint32_uint32_val_;
+  const FieldDescriptor* map_uint64_uint64_key_;
+  const FieldDescriptor* map_uint64_uint64_val_;
+  const FieldDescriptor* map_sint32_sint32_key_;
+  const FieldDescriptor* map_sint32_sint32_val_;
+  const FieldDescriptor* map_sint64_sint64_key_;
+  const FieldDescriptor* map_sint64_sint64_val_;
+  const FieldDescriptor* map_fixed32_fixed32_key_;
+  const FieldDescriptor* map_fixed32_fixed32_val_;
+  const FieldDescriptor* map_fixed64_fixed64_key_;
+  const FieldDescriptor* map_fixed64_fixed64_val_;
+  const FieldDescriptor* map_sfixed32_sfixed32_key_;
+  const FieldDescriptor* map_sfixed32_sfixed32_val_;
+  const FieldDescriptor* map_sfixed64_sfixed64_key_;
+  const FieldDescriptor* map_sfixed64_sfixed64_val_;
+  const FieldDescriptor* map_int32_float_key_;
+  const FieldDescriptor* map_int32_float_val_;
+  const FieldDescriptor* map_int32_double_key_;
+  const FieldDescriptor* map_int32_double_val_;
+  const FieldDescriptor* map_bool_bool_key_;
+  const FieldDescriptor* map_bool_bool_val_;
+  const FieldDescriptor* map_string_string_key_;
+  const FieldDescriptor* map_string_string_val_;
+  const FieldDescriptor* map_int32_bytes_key_;
+  const FieldDescriptor* map_int32_bytes_val_;
+  const FieldDescriptor* map_int32_enum_key_;
+  const FieldDescriptor* map_int32_enum_val_;
+  const FieldDescriptor* map_int32_foreign_message_key_;
+  const FieldDescriptor* map_int32_foreign_message_val_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_TESTER_H__
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
new file mode 100644
index 0000000..7264d0a
--- /dev/null
+++ b/src/google/protobuf/repeated_field.cc
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/repeated_field.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<bool>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<float>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<double>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedPtrField<std::string>;
+
+namespace internal {
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<bool>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<int32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<uint32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<int64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<uint64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<float>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<double>;
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
new file mode 100644
index 0000000..3fb734e
--- /dev/null
+++ b/src/google/protobuf/repeated_field.h
@@ -0,0 +1,1219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// RepeatedField and RepeatedPtrField are used by generated protocol message
+// classes to manipulate repeated fields.  These classes are very similar to
+// STL's vector, but include a number of optimizations found to be useful
+// specifically in the case of Protocol Buffers.  RepeatedPtrField is
+// particularly different from STL vector as it manages ownership of the
+// pointers that it contains.
+//
+// This header covers RepeatedField.
+
+#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+
+
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_ptr_field.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace internal {
+
+template <typename T, int kRepHeaderSize>
+constexpr int RepeatedFieldLowerClampLimit() {
+  // The header is padded to be at least `sizeof(T)` when it would be smaller
+  // otherwise.
+  static_assert(sizeof(T) <= kRepHeaderSize, "");
+  // We want to pad the minimum size to be a power of two bytes, including the
+  // header.
+  // The first allocation is kRepHeaderSize bytes worth of elements for a total
+  // of 2*kRepHeaderSize bytes.
+  // For an 8-byte header, we allocate 8 bool, 2 ints, or 1 int64.
+  return kRepHeaderSize / sizeof(T);
+}
+
+// kRepeatedFieldUpperClampLimit is the lowest signed integer value that
+// overflows when multiplied by 2 (which is undefined behavior). Sizes above
+// this will clamp to the maximum int value instead of following exponential
+// growth when growing a repeated field.
+constexpr int kRepeatedFieldUpperClampLimit =
+    (std::numeric_limits<int>::max() / 2) + 1;
+
+template <typename Iter>
+inline int CalculateReserve(Iter begin, Iter end, std::forward_iterator_tag) {
+  return static_cast<int>(std::distance(begin, end));
+}
+
+template <typename Iter>
+inline int CalculateReserve(Iter /*begin*/, Iter /*end*/,
+                            std::input_iterator_tag /*unused*/) {
+  return -1;
+}
+
+template <typename Iter>
+inline int CalculateReserve(Iter begin, Iter end) {
+  typedef typename std::iterator_traits<Iter>::iterator_category Category;
+  return CalculateReserve(begin, end, Category());
+}
+
+// Swaps two blocks of memory of size sizeof(T).
+template <typename T>
+inline void SwapBlock(char* p, char* q) {
+  T tmp;
+  memcpy(&tmp, p, sizeof(T));
+  memcpy(p, q, sizeof(T));
+  memcpy(q, &tmp, sizeof(T));
+}
+
+// Swaps two blocks of memory of size kSize:
+//  template <int kSize> void memswap(char* p, char* q);
+template <int kSize>
+inline typename std::enable_if<(kSize == 0), void>::type memswap(char*, char*) {
+}
+
+#define PROTO_MEMSWAP_DEF_SIZE(reg_type, max_size)                           \
+  template <int kSize>                                                       \
+  typename std::enable_if<(kSize >= sizeof(reg_type) && kSize < (max_size)), \
+                          void>::type                                        \
+  memswap(char* p, char* q) {                                                \
+    SwapBlock<reg_type>(p, q);                                               \
+    memswap<kSize - sizeof(reg_type)>(p + sizeof(reg_type),                  \
+                                      q + sizeof(reg_type));                 \
+  }
+
+PROTO_MEMSWAP_DEF_SIZE(uint8_t, 2)
+PROTO_MEMSWAP_DEF_SIZE(uint16_t, 4)
+PROTO_MEMSWAP_DEF_SIZE(uint32_t, 8)
+
+#ifdef __SIZEOF_INT128__
+PROTO_MEMSWAP_DEF_SIZE(uint64_t, 16)
+PROTO_MEMSWAP_DEF_SIZE(__uint128_t, (1u << 31))
+#else
+PROTO_MEMSWAP_DEF_SIZE(uint64_t, (1u << 31))
+#endif
+
+#undef PROTO_MEMSWAP_DEF_SIZE
+
+template <typename Element>
+class RepeatedIterator;
+
+}  // namespace internal
+
+// RepeatedField is used to represent repeated fields of a primitive type (in
+// other words, everything except strings and nested Messages).  Most users will
+// not ever use a RepeatedField directly; they will use the get-by-index,
+// set-by-index, and add accessors that are generated for all repeated fields.
+template <typename Element>
+class RepeatedField final {
+  static_assert(
+      alignof(Arena) >= alignof(Element),
+      "We only support types that have an alignment smaller than Arena");
+
+ public:
+  constexpr RepeatedField();
+  explicit RepeatedField(Arena* arena);
+
+  RepeatedField(const RepeatedField& other);
+
+  template <typename Iter,
+            typename = typename std::enable_if<std::is_constructible<
+                Element, decltype(*std::declval<Iter>())>::value>::type>
+  RepeatedField(Iter begin, Iter end);
+
+  ~RepeatedField();
+
+  RepeatedField& operator=(const RepeatedField& other);
+
+  RepeatedField(RepeatedField&& other) noexcept;
+  RepeatedField& operator=(RepeatedField&& other) noexcept;
+
+  bool empty() const;
+  int size() const;
+
+  const Element& Get(int index) const;
+  Element* Mutable(int index);
+
+  const Element& operator[](int index) const { return Get(index); }
+  Element& operator[](int index) { return *Mutable(index); }
+
+  const Element& at(int index) const;
+  Element& at(int index);
+
+  void Set(int index, const Element& value);
+  void Add(const Element& value);
+  // Appends a new element and returns a pointer to it.
+  // The new element is uninitialized if |Element| is a POD type.
+  Element* Add();
+  // Appends elements in the range [begin, end) after reserving
+  // the appropriate number of elements.
+  template <typename Iter>
+  void Add(Iter begin, Iter end);
+
+  // Removes the last element in the array.
+  void RemoveLast();
+
+  // Extracts elements with indices in "[start .. start+num-1]".
+  // Copies them into "elements[0 .. num-1]" if "elements" is not nullptr.
+  // Caution: also moves elements with indices [start+num ..].
+  // Calling this routine inside a loop can cause quadratic behavior.
+  void ExtractSubrange(int start, int num, Element* elements);
+
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear();
+  void MergeFrom(const RepeatedField& other);
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void CopyFrom(const RepeatedField& other);
+
+  // Replaces the contents with RepeatedField(begin, end).
+  template <typename Iter>
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end);
+
+  // Reserves space to expand the field to at least the given size.  If the
+  // array is grown, it will always be at least doubled in size.
+  void Reserve(int new_size);
+
+  // Resizes the RepeatedField to a new, smaller size.  This is O(1).
+  void Truncate(int new_size);
+
+  void AddAlreadyReserved(const Element& value);
+  // Appends a new element and return a pointer to it.
+  // The new element is uninitialized if |Element| is a POD type.
+  // Should be called only if Capacity() > Size().
+  Element* AddAlreadyReserved();
+  Element* AddNAlreadyReserved(int elements);
+  int Capacity() const;
+
+  // Like STL resize.  Uses value to fill appended elements.
+  // Like Truncate() if new_size <= size(), otherwise this is
+  // O(new_size - size()).
+  void Resize(int new_size, const Element& value);
+
+  // Gets the underlying array.  This pointer is possibly invalidated by
+  // any add or remove operation.
+  Element* mutable_data();
+  const Element* data() const;
+
+  // Swaps entire contents with "other". If they are separate arenas then,
+  // copies data between each other.
+  void Swap(RepeatedField* other);
+
+  // Swaps entire contents with "other". Should be called only if the caller can
+  // guarantee that both repeated fields are on the same arena or are on the
+  // heap. Swapping between different arenas is disallowed and caught by a
+  // GOOGLE_DCHECK (see API docs for details).
+  void UnsafeArenaSwap(RepeatedField* other);
+
+  // Swaps two elements.
+  void SwapElements(int index1, int index2);
+
+  // STL-like iterator support
+  typedef internal::RepeatedIterator<Element> iterator;
+  typedef internal::RepeatedIterator<const Element> const_iterator;
+  typedef Element value_type;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin();
+  const_iterator begin() const;
+  const_iterator cbegin() const;
+  iterator end();
+  const_iterator end() const;
+  const_iterator cend() const;
+
+  // Reverse iterator support
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef std::reverse_iterator<iterator> reverse_iterator;
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // Returns the number of bytes used by the repeated field, excluding
+  // sizeof(*this)
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+  // 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 RepeatedField stores its elements.
+  inline Arena* GetArena() const {
+    return GetOwningArena();
+  }
+
+  // For internal use only.
+  //
+  // This is public due to it being called by generated code.
+  inline void InternalSwap(RepeatedField* other);
+
+ private:
+  template <typename T> friend class Arena::InternalHelper;
+
+  // Gets the Arena on which this RepeatedField stores its elements.
+  inline Arena* GetOwningArena() const {
+    return (total_size_ == 0) ? static_cast<Arena*>(arena_or_elements_)
+                              : rep()->arena;
+  }
+
+  static constexpr int kInitialSize = 0;
+  // A note on the representation here (see also comment below for
+  // RepeatedPtrFieldBase's struct Rep):
+  //
+  // We maintain the same sizeof(RepeatedField) as before we added arena support
+  // so that we do not degrade performance by bloating memory usage. Directly
+  // adding an arena_ element to RepeatedField is quite costly. By using
+  // indirection in this way, we keep the same size when the RepeatedField is
+  // empty (common case), and add only an 8-byte header to the elements array
+  // when non-empty. We make sure to place the size fields directly in the
+  // RepeatedField class to avoid costly cache misses due to the indirection.
+  int current_size_;
+  int total_size_;
+  // Pad the Rep after arena allow for power-of-two byte sizes when
+  // sizeof(Element) > sizeof(Arena*). eg for 16-byte objects.
+  static PROTOBUF_CONSTEXPR const size_t kRepHeaderSize =
+      sizeof(Arena*) < sizeof(Element) ? sizeof(Element) : sizeof(Arena*);
+  struct Rep {
+    Arena* arena;
+    Element* elements() {
+      return reinterpret_cast<Element*>(reinterpret_cast<char*>(this) +
+                                        kRepHeaderSize);
+    }
+  };
+
+  // If total_size_ == 0 this points to an Arena otherwise it points to the
+  // elements member of a Rep struct. Using this invariant allows the storage of
+  // the arena pointer without an extra allocation in the constructor.
+  void* arena_or_elements_;
+
+  // Returns a pointer to elements array.
+  // pre-condition: the array must have been allocated.
+  Element* elements() const {
+    GOOGLE_DCHECK_GT(total_size_, 0);
+    // Because of above pre-condition this cast is safe.
+    return unsafe_elements();
+  }
+
+  // Returns a pointer to elements array if it exists; otherwise either null or
+  // an invalid pointer is returned. This only happens for empty repeated
+  // fields, where you can't dereference this pointer anyway (it's empty).
+  Element* unsafe_elements() const {
+    return static_cast<Element*>(arena_or_elements_);
+  }
+
+  // Returns a pointer to the Rep struct.
+  // pre-condition: the Rep must have been allocated, ie elements() is safe.
+  Rep* rep() const {
+    return reinterpret_cast<Rep*>(reinterpret_cast<char*>(elements()) -
+                                  kRepHeaderSize);
+  }
+
+  friend class Arena;
+  typedef void InternalArenaConstructable_;
+
+  // Moves the contents of |from| into |to|, possibly clobbering |from| in the
+  // process.  For primitive types this is just a memcpy(), but it could be
+  // specialized for non-primitive types to, say, swap each element instead.
+  void MoveArray(Element* to, Element* from, int size);
+
+  // Copies the elements of |from| into |to|.
+  void CopyArray(Element* to, const Element* from, int size);
+
+  // Internal helper to delete all elements and deallocate the storage.
+  void InternalDeallocate(Rep* rep, int size, bool in_destructor) {
+    if (rep != nullptr) {
+      Element* e = &rep->elements()[0];
+      if (!std::is_trivial<Element>::value) {
+        Element* limit = &rep->elements()[size];
+        for (; e < limit; e++) {
+          e->~Element();
+        }
+      }
+      const size_t bytes = size * sizeof(*e) + kRepHeaderSize;
+      if (rep->arena == nullptr) {
+        internal::SizedDelete(rep, bytes);
+      } else if (!in_destructor) {
+        // If we are in the destructor, we might be being destroyed as part of
+        // the arena teardown. We can't try and return blocks to the arena then.
+        rep->arena->ReturnArrayMemory(rep, bytes);
+      }
+    }
+  }
+
+  // This class is a performance wrapper around RepeatedField::Add(const T&)
+  // function. In general unless a RepeatedField is a local stack variable LLVM
+  // has a hard time optimizing Add. The machine code tends to be
+  // loop:
+  // mov %size, dword ptr [%repeated_field]       // load
+  // cmp %size, dword ptr [%repeated_field + 4]
+  // jae fallback
+  // mov %buffer, qword ptr [%repeated_field + 8]
+  // mov dword [%buffer + %size * 4], %value
+  // inc %size                                    // increment
+  // mov dword ptr [%repeated_field], %size       // store
+  // jmp loop
+  //
+  // This puts a load/store in each iteration of the important loop variable
+  // size. It's a pretty bad compile that happens even in simple cases, but
+  // largely the presence of the fallback path disturbs the compilers mem-to-reg
+  // analysis.
+  //
+  // This class takes ownership of a repeated field for the duration of its
+  // lifetime. The repeated field should not be accessed during this time, ie.
+  // only access through this class is allowed. This class should always be a
+  // function local stack variable. Intended use
+  //
+  // void AddSequence(const int* begin, const int* end, RepeatedField<int>* out)
+  // {
+  //   RepeatedFieldAdder<int> adder(out);  // Take ownership of out
+  //   for (auto it = begin; it != end; ++it) {
+  //     adder.Add(*it);
+  //   }
+  // }
+  //
+  // Typically, due to the fact that adder is a local stack variable, the
+  // compiler will be successful in mem-to-reg transformation and the machine
+  // code will be loop: cmp %size, %capacity jae fallback mov dword ptr [%buffer
+  // + %size * 4], %val inc %size jmp loop
+  //
+  // The first version executes at 7 cycles per iteration while the second
+  // version executes at only 1 or 2 cycles.
+  template <int = 0, bool = std::is_trivial<Element>::value>
+  class FastAdderImpl {
+   public:
+    explicit FastAdderImpl(RepeatedField* rf) : repeated_field_(rf) {
+      index_ = repeated_field_->current_size_;
+      capacity_ = repeated_field_->total_size_;
+      buffer_ = repeated_field_->unsafe_elements();
+    }
+    ~FastAdderImpl() { repeated_field_->current_size_ = index_; }
+
+    void Add(Element val) {
+      if (index_ == capacity_) {
+        repeated_field_->current_size_ = index_;
+        repeated_field_->Reserve(index_ + 1);
+        capacity_ = repeated_field_->total_size_;
+        buffer_ = repeated_field_->unsafe_elements();
+      }
+      buffer_[index_++] = val;
+    }
+
+   private:
+    RepeatedField* repeated_field_;
+    int index_;
+    int capacity_;
+    Element* buffer_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastAdderImpl);
+  };
+
+  // FastAdder is a wrapper for adding fields. The specialization above handles
+  // POD types more efficiently than RepeatedField.
+  template <int I>
+  class FastAdderImpl<I, false> {
+   public:
+    explicit FastAdderImpl(RepeatedField* rf) : repeated_field_(rf) {}
+    void Add(const Element& val) { repeated_field_->Add(val); }
+
+   private:
+    RepeatedField* repeated_field_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastAdderImpl);
+  };
+
+  using FastAdder = FastAdderImpl<>;
+
+  friend class TestRepeatedFieldHelper;
+  friend class ::google::protobuf::internal::ParseContext;
+};
+
+namespace internal {
+
+// This is a helper template to copy an array of elements efficiently when they
+// have a trivial copy constructor, and correctly otherwise. This really
+// shouldn't be necessary, but our compiler doesn't optimize std::copy very
+// effectively.
+template <typename Element,
+          bool HasTrivialCopy = std::is_trivial<Element>::value>
+struct ElementCopier {
+  void operator()(Element* to, const Element* from, int array_size);
+};
+
+}  // namespace internal
+
+// implementation ====================================================
+
+template <typename Element>
+constexpr RepeatedField<Element>::RepeatedField()
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(Arena* arena)
+    : current_size_(0), total_size_(0), arena_or_elements_(arena) {}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
+  if (other.current_size_ != 0) {
+    Reserve(other.size());
+    AddNAlreadyReserved(other.size());
+    CopyArray(Mutable(0), &other.Get(0), other.size());
+  }
+}
+
+template <typename Element>
+template <typename Iter, typename>
+RepeatedField<Element>::RepeatedField(Iter begin, Iter end)
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
+  Add(begin, end);
+}
+
+template <typename Element>
+RepeatedField<Element>::~RepeatedField() {
+#ifndef NDEBUG
+  // Try to trigger segfault / asan failure in non-opt builds if arena_
+  // lifetime has ended before the destructor.
+  auto arena = GetOwningArena();
+  if (arena) (void)arena->SpaceAllocated();
+#endif
+  if (total_size_ > 0) {
+    InternalDeallocate(rep(), total_size_, true);
+  }
+}
+
+template <typename Element>
+inline RepeatedField<Element>& RepeatedField<Element>::operator=(
+    const RepeatedField& other) {
+  if (this != &other) CopyFrom(other);
+  return *this;
+}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(RepeatedField&& other) noexcept
+    : RepeatedField() {
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+  CopyFrom(other);
+#else   // PROTOBUF_FORCE_COPY_IN_MOVE
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // other is on an arena. This field can't be on an arena because arena
+  // construction always uses the Arena* accepting constructor.
+  if (other.GetOwningArena()) {
+    CopyFrom(other);
+  } else {
+    InternalSwap(&other);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+}
+
+template <typename Element>
+inline RepeatedField<Element>& RepeatedField<Element>::operator=(
+    RepeatedField&& other) noexcept {
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // the two fields are on different arenas.
+  if (this != &other) {
+    if (GetOwningArena() != other.GetOwningArena()
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        || GetOwningArena() == nullptr
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      CopyFrom(other);
+    } else {
+      InternalSwap(&other);
+    }
+  }
+  return *this;
+}
+
+template <typename Element>
+inline bool RepeatedField<Element>::empty() const {
+  return current_size_ == 0;
+}
+
+template <typename Element>
+inline int RepeatedField<Element>::size() const {
+  return current_size_;
+}
+
+template <typename Element>
+inline int RepeatedField<Element>::Capacity() const {
+  return total_size_;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::AddAlreadyReserved(const Element& value) {
+  GOOGLE_DCHECK_LT(current_size_, total_size_);
+  elements()[current_size_++] = value;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::AddAlreadyReserved() {
+  GOOGLE_DCHECK_LT(current_size_, total_size_);
+  return &elements()[current_size_++];
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::AddNAlreadyReserved(int elements) {
+  GOOGLE_DCHECK_GE(total_size_ - current_size_, elements)
+      << total_size_ << ", " << current_size_;
+  // Warning: sometimes people call this when elements == 0 and
+  // total_size_ == 0. In this case the return pointer points to a zero size
+  // array (n == 0). Hence we can just use unsafe_elements(), because the user
+  // cannot dereference the pointer anyway.
+  Element* ret = unsafe_elements() + current_size_;
+  current_size_ += elements;
+  return ret;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Resize(int new_size, const Element& value) {
+  GOOGLE_DCHECK_GE(new_size, 0);
+  if (new_size > current_size_) {
+    Reserve(new_size);
+    std::fill(&elements()[current_size_], &elements()[new_size], value);
+  }
+  current_size_ = new_size;
+}
+
+template <typename Element>
+inline const Element& RepeatedField<Element>::Get(int index) const {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline const Element& RepeatedField<Element>::at(int index) const {
+  GOOGLE_CHECK_GE(index, 0);
+  GOOGLE_CHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline Element& RepeatedField<Element>::at(int index) {
+  GOOGLE_CHECK_GE(index, 0);
+  GOOGLE_CHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::Mutable(int index) {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return &elements()[index];
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Set(int index, const Element& value) {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  elements()[index] = value;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Add(const Element& value) {
+  uint32_t size = current_size_;
+  if (static_cast<int>(size) == total_size_) {
+    // value could reference an element of the array. Reserving new space will
+    // invalidate the reference. So we must make a copy first.
+    auto tmp = value;
+    Reserve(total_size_ + 1);
+    elements()[size] = std::move(tmp);
+  } else {
+    elements()[size] = value;
+  }
+  current_size_ = size + 1;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::Add() {
+  uint32_t size = current_size_;
+  if (static_cast<int>(size) == total_size_) Reserve(total_size_ + 1);
+  auto ptr = &elements()[size];
+  current_size_ = size + 1;
+  return ptr;
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedField<Element>::Add(Iter begin, Iter end) {
+  int reserve = internal::CalculateReserve(begin, end);
+  if (reserve != -1) {
+    if (reserve == 0) {
+      return;
+    }
+
+    Reserve(reserve + size());
+    // TODO(ckennelly):  The compiler loses track of the buffer freshly
+    // allocated by Reserve() by the time we call elements, so it cannot
+    // guarantee that elements does not alias [begin(), end()).
+    //
+    // If restrict is available, annotating the pointer obtained from elements()
+    // causes this to lower to memcpy instead of memmove.
+    std::copy(begin, end, elements() + size());
+    current_size_ = reserve + size();
+  } else {
+    FastAdder fast_adder(this);
+    for (; begin != end; ++begin) fast_adder.Add(*begin);
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::RemoveLast() {
+  GOOGLE_DCHECK_GT(current_size_, 0);
+  current_size_--;
+}
+
+template <typename Element>
+void RepeatedField<Element>::ExtractSubrange(int start, int num,
+                                             Element* elements) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, this->current_size_);
+
+  // Save the values of the removed elements if requested.
+  if (elements != nullptr) {
+    for (int i = 0; i < num; ++i) elements[i] = this->Get(i + start);
+  }
+
+  // Slide remaining elements down to fill the gap.
+  if (num > 0) {
+    for (int i = start + num; i < this->current_size_; ++i)
+      this->Set(i - num, this->Get(i));
+    this->Truncate(this->current_size_ - num);
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Clear() {
+  current_size_ = 0;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::MergeFrom(const RepeatedField& other) {
+  GOOGLE_DCHECK_NE(&other, this);
+  if (other.current_size_ != 0) {
+    int existing_size = size();
+    Reserve(existing_size + other.size());
+    AddNAlreadyReserved(other.size());
+    CopyArray(Mutable(existing_size), &other.Get(0), other.size());
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::CopyFrom(const RepeatedField& other) {
+  if (&other == this) return;
+  Clear();
+  MergeFrom(other);
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedField<Element>::Assign(Iter begin, Iter end) {
+  Clear();
+  Add(begin, end);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+    const_iterator position) {
+  return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+    const_iterator first, const_iterator last) {
+  size_type first_offset = first - cbegin();
+  if (first != last) {
+    Truncate(std::copy(last, cend(), begin() + first_offset) - cbegin());
+  }
+  return begin() + first_offset;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::mutable_data() {
+  return unsafe_elements();
+}
+
+template <typename Element>
+inline const Element* RepeatedField<Element>::data() const {
+  return unsafe_elements();
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::InternalSwap(RepeatedField* other) {
+  GOOGLE_DCHECK(this != other);
+
+  // Swap all fields at once.
+  static_assert(std::is_standard_layout<RepeatedField<Element>>::value,
+                "offsetof() requires standard layout before c++17");
+  internal::memswap<offsetof(RepeatedField, arena_or_elements_) +
+                    sizeof(this->arena_or_elements_) -
+                    offsetof(RepeatedField, current_size_)>(
+      reinterpret_cast<char*>(this) + offsetof(RepeatedField, current_size_),
+      reinterpret_cast<char*>(other) + offsetof(RepeatedField, current_size_));
+}
+
+template <typename Element>
+void RepeatedField<Element>::Swap(RepeatedField* other) {
+  if (this == other) return;
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetOwningArena() != nullptr &&
+      GetOwningArena() == other->GetOwningArena()) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetOwningArena() == other->GetOwningArena()) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    InternalSwap(other);
+  } else {
+    RepeatedField<Element> temp(other->GetOwningArena());
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->UnsafeArenaSwap(&temp);
+  }
+}
+
+template <typename Element>
+void RepeatedField<Element>::UnsafeArenaSwap(RepeatedField* other) {
+  if (this == other) return;
+  GOOGLE_DCHECK_EQ(GetOwningArena(), other->GetOwningArena());
+  InternalSwap(other);
+}
+
+template <typename Element>
+void RepeatedField<Element>::SwapElements(int index1, int index2) {
+  using std::swap;  // enable ADL with fallback
+  swap(elements()[index1], elements()[index2]);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator
+RepeatedField<Element>::begin() {
+  return iterator(unsafe_elements());
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::begin() const {
+  return const_iterator(unsafe_elements());
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cbegin() const {
+  return const_iterator(unsafe_elements());
+}
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::end() {
+  return iterator(unsafe_elements() + current_size_);
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::end() const {
+  return const_iterator(unsafe_elements() + current_size_);
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cend() const {
+  return const_iterator(unsafe_elements() + current_size_);
+}
+
+template <typename Element>
+inline size_t RepeatedField<Element>::SpaceUsedExcludingSelfLong() const {
+  return total_size_ > 0 ? (total_size_ * sizeof(Element) + kRepHeaderSize) : 0;
+}
+
+namespace internal {
+// Returns the new size for a reserved field based on its 'total_size' and the
+// requested 'new_size'. The result is clamped to the closed interval:
+//   [internal::kMinRepeatedFieldAllocationSize,
+//    std::numeric_limits<int>::max()]
+// Requires:
+//     new_size > total_size &&
+//     (total_size == 0 ||
+//      total_size >= kRepeatedFieldLowerClampLimit)
+template <typename T, int kRepHeaderSize>
+inline int CalculateReserveSize(int total_size, int new_size) {
+  constexpr int lower_limit = RepeatedFieldLowerClampLimit<T, kRepHeaderSize>();
+  if (new_size < lower_limit) {
+    // Clamp to smallest allowed size.
+    return lower_limit;
+  }
+  constexpr int kMaxSizeBeforeClamp =
+      (std::numeric_limits<int>::max() - kRepHeaderSize) / 2;
+  if (PROTOBUF_PREDICT_FALSE(total_size > kMaxSizeBeforeClamp)) {
+    return std::numeric_limits<int>::max();
+  }
+  // We want to double the number of bytes, not the number of elements, to try
+  // to stay within power-of-two allocations.
+  // The allocation has kRepHeaderSize + sizeof(T) * capacity.
+  int doubled_size = 2 * total_size + kRepHeaderSize / sizeof(T);
+  return std::max(doubled_size, new_size);
+}
+}  // namespace internal
+
+// Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant
+// amount of code bloat.
+template <typename Element>
+void RepeatedField<Element>::Reserve(int new_size) {
+  if (total_size_ >= new_size) return;
+  Rep* old_rep = total_size_ > 0 ? rep() : nullptr;
+  Rep* new_rep;
+  Arena* arena = GetOwningArena();
+
+  new_size = internal::CalculateReserveSize<Element, kRepHeaderSize>(
+      total_size_, new_size);
+
+  GOOGLE_DCHECK_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.";
+  size_t bytes =
+      kRepHeaderSize + sizeof(Element) * static_cast<size_t>(new_size);
+  if (arena == nullptr) {
+    new_rep = static_cast<Rep*>(::operator new(bytes));
+  } else {
+    new_rep = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
+  }
+  new_rep->arena = arena;
+  int old_total_size = total_size_;
+  // Already known: new_size >= internal::kMinRepeatedFieldAllocationSize
+  // Maintain invariant:
+  //     total_size_ == 0 ||
+  //     total_size_ >= internal::kMinRepeatedFieldAllocationSize
+  total_size_ = new_size;
+  arena_or_elements_ = new_rep->elements();
+  // Invoke placement-new on newly allocated elements. We shouldn't have to do
+  // this, since Element is supposed to be POD, but a previous version of this
+  // code allocated storage with "new Element[size]" and some code uses
+  // RepeatedField with non-POD types, relying on constructor invocation. If
+  // Element has a trivial constructor (e.g., int32_t), gcc (tested with -O2)
+  // completely removes this loop because the loop body is empty, so this has no
+  // effect unless its side-effects are required for correctness.
+  // Note that we do this before MoveArray() below because Element's copy
+  // assignment implementation will want an initialized instance first.
+  Element* e = &elements()[0];
+  Element* limit = e + total_size_;
+  for (; e < limit; e++) {
+    new (e) Element;
+  }
+  if (current_size_ > 0) {
+    MoveArray(&elements()[0], old_rep->elements(), current_size_);
+  }
+
+  // Likewise, we need to invoke destructors on the old array.
+  InternalDeallocate(old_rep, old_total_size, false);
+
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Truncate(int new_size) {
+  GOOGLE_DCHECK_LE(new_size, current_size_);
+  if (current_size_ > 0) {
+    current_size_ = new_size;
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::MoveArray(Element* to, Element* from,
+                                              int array_size) {
+  CopyArray(to, from, array_size);
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::CopyArray(Element* to, const Element* from,
+                                              int array_size) {
+  internal::ElementCopier<Element>()(to, from, array_size);
+}
+
+namespace internal {
+
+template <typename Element, bool HasTrivialCopy>
+void ElementCopier<Element, HasTrivialCopy>::operator()(Element* to,
+                                                        const Element* from,
+                                                        int array_size) {
+  std::copy(from, from + array_size, to);
+}
+
+template <typename Element>
+struct ElementCopier<Element, true> {
+  void operator()(Element* to, const Element* from, int array_size) {
+    memcpy(to, from, static_cast<size_t>(array_size) * sizeof(Element));
+  }
+};
+
+}  // namespace internal
+
+
+// -------------------------------------------------------------------
+
+// Iterators and helper functions that follow the spirit of the STL
+// std::back_insert_iterator and std::back_inserter but are tailor-made
+// for RepeatedField and RepeatedPtrField. Typical usage would be:
+//
+//   std::copy(some_sequence.begin(), some_sequence.end(),
+//             RepeatedFieldBackInserter(proto.mutable_sequence()));
+//
+// Ported by johannes from util/gtl/proto-array-iterators.h
+
+namespace internal {
+
+// STL-like iterator implementation for RepeatedField.  You should not
+// refer to this class directly; use RepeatedField<T>::iterator instead.
+//
+// Note: All of the iterator operators *must* be inlined to avoid performance
+// regressions.  This is caused by the extern template declarations below (which
+// are required because of the RepeatedField extern template declarations).  If
+// any of these functions aren't explicitly inlined (e.g. defined in the class),
+// the compiler isn't allowed to inline them.
+template <typename Element>
+class RepeatedIterator {
+ public:
+  using iterator_category = std::random_access_iterator_tag;
+  // Note: remove_const is necessary for std::partial_sum, which uses value_type
+  // to determine the summation variable type.
+  using value_type = typename std::remove_const<Element>::type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = Element*;
+  using reference = Element&;
+
+  constexpr RepeatedIterator() noexcept : it_(nullptr) {}
+
+  // Allows "upcasting" from RepeatedIterator<T**> to
+  // RepeatedIterator<const T*const*>.
+  template <typename OtherElement,
+            typename std::enable_if<std::is_convertible<
+                OtherElement*, pointer>::value>::type* = nullptr>
+  constexpr RepeatedIterator(
+      const RepeatedIterator<OtherElement>& other) noexcept
+      : it_(other.it_) {}
+
+  // dereferenceable
+  constexpr reference operator*() const noexcept { return *it_; }
+  constexpr pointer operator->() const noexcept { return it_; }
+
+ private:
+  // Helper alias to hide the internal type.
+  using iterator = RepeatedIterator<Element>;
+
+ public:
+  // {inc,dec}rementable
+  iterator& operator++() noexcept {
+    ++it_;
+    return *this;
+  }
+  iterator operator++(int) noexcept { return iterator(it_++); }
+  iterator& operator--() noexcept {
+    --it_;
+    return *this;
+  }
+  iterator operator--(int) noexcept { return iterator(it_--); }
+
+  // equality_comparable
+  friend constexpr bool operator==(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ == y.it_;
+  }
+  friend constexpr bool operator!=(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ != y.it_;
+  }
+
+  // less_than_comparable
+  friend constexpr bool operator<(const iterator& x,
+                                  const iterator& y) noexcept {
+    return x.it_ < y.it_;
+  }
+  friend constexpr bool operator<=(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ <= y.it_;
+  }
+  friend constexpr bool operator>(const iterator& x,
+                                  const iterator& y) noexcept {
+    return x.it_ > y.it_;
+  }
+  friend constexpr bool operator>=(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ >= y.it_;
+  }
+
+  // addable, subtractable
+  iterator& operator+=(difference_type d) noexcept {
+    it_ += d;
+    return *this;
+  }
+  constexpr iterator operator+(difference_type d) const noexcept {
+    return iterator(it_ + d);
+  }
+  friend constexpr iterator operator+(const difference_type d,
+                                      iterator it) noexcept {
+    return it + d;
+  }
+
+  iterator& operator-=(difference_type d) noexcept {
+    it_ -= d;
+    return *this;
+  }
+  iterator constexpr operator-(difference_type d) const noexcept {
+    return iterator(it_ - d);
+  }
+
+  // indexable
+  constexpr reference operator[](difference_type d) const noexcept {
+    return it_[d];
+  }
+
+  // random access iterator
+  friend constexpr difference_type operator-(iterator it1,
+                                             iterator it2) noexcept {
+    return it1.it_ - it2.it_;
+  }
+
+ private:
+  template <typename OtherElement>
+  friend class RepeatedIterator;
+
+  // Allow construction from RepeatedField.
+  friend class RepeatedField<value_type>;
+  explicit RepeatedIterator(Element* it) noexcept : it_(it) {}
+
+  // The internal iterator.
+  Element* it_;
+};
+
+// A back inserter for RepeatedField objects.
+template <typename T>
+class RepeatedFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  explicit RepeatedFieldBackInsertIterator(
+      RepeatedField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  RepeatedFieldBackInsertIterator<T>& operator=(const T& value) {
+    field_->Add(value);
+    return *this;
+  }
+  RepeatedFieldBackInsertIterator<T>& operator*() { return *this; }
+  RepeatedFieldBackInsertIterator<T>& operator++() { return *this; }
+  RepeatedFieldBackInsertIterator<T>& operator++(int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedField<T>* field_;
+};
+
+}  // namespace internal
+
+// Provides a back insert iterator for RepeatedField instances,
+// similar to std::back_inserter().
+template <typename T>
+internal::RepeatedFieldBackInsertIterator<T> RepeatedFieldBackInserter(
+    RepeatedField<T>* const mutable_field) {
+  return internal::RepeatedFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Extern declarations of common instantiations to reduce library bloat.
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<bool>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<float>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<double>;
+
+namespace internal {
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedIterator<bool>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<int32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<uint32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<int64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<uint64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedIterator<float>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedIterator<double>;
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REPEATED_FIELD_H__
diff --git a/src/google/protobuf/repeated_field_reflection_unittest.cc b/src/google/protobuf/repeated_field_reflection_unittest.cc
new file mode 100644
index 0000000..25e8200
--- /dev/null
+++ b/src/google/protobuf/repeated_field_reflection_unittest.cc
@@ -0,0 +1,709 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: tgs@google.com (Tom Szymanski)
+//
+// Test reflection methods for aggregate access to Repeated[Ptr]Fields.
+// This test proto2 methods on a proto2 layout.
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/reflection.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/test_util.h>
+
+namespace google {
+namespace protobuf {
+
+using unittest::ForeignMessage;
+using unittest::TestAllExtensions;
+using unittest::TestAllTypes;
+
+namespace {
+
+static int Func(int i, int j) { return i * j; }
+
+static std::string StrFunc(int i, int j) { return StrCat(Func(i, 4)); }
+
+TEST(RepeatedFieldReflectionTest, RegularFields) {
+  TestAllTypes message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    message.add_repeated_int32(Func(i, 1));
+    message.add_repeated_double(Func(i, 2));
+    message.add_repeated_string(StrFunc(i, 5));
+    message.add_repeated_foreign_message()->set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+  const FieldDescriptor* fd_repeated_double =
+      desc->FindFieldByName("repeated_double");
+  const FieldDescriptor* fd_repeated_string =
+      desc->FindFieldByName("repeated_string");
+  const FieldDescriptor* fd_repeated_foreign_message =
+      desc->FindFieldByName("repeated_foreign_message");
+
+  // Get RepeatedField objects for all fields of interest.
+  const RepeatedField<int32_t>& rf_int32 =
+      refl->GetRepeatedField<int32_t>(message, fd_repeated_int32);
+  const RepeatedField<double>& rf_double =
+      refl->GetRepeatedField<double>(message, fd_repeated_double);
+
+  // Get mutable RepeatedField objects for all fields of interest.
+  RepeatedField<int32_t>* mrf_int32 =
+      refl->MutableRepeatedField<int32_t>(&message, fd_repeated_int32);
+  RepeatedField<double>* mrf_double =
+      refl->MutableRepeatedField<double>(&message, fd_repeated_double);
+
+  // Get RepeatedPtrField objects for all fields of interest.
+  const RepeatedPtrField<std::string>& rpf_string =
+      refl->GetRepeatedPtrField<std::string>(message, fd_repeated_string);
+  const RepeatedPtrField<ForeignMessage>& rpf_foreign_message =
+      refl->GetRepeatedPtrField<ForeignMessage>(message,
+                                                fd_repeated_foreign_message);
+  const RepeatedPtrField<Message>& rpf_message =
+      refl->GetRepeatedPtrField<Message>(message, fd_repeated_foreign_message);
+
+  // Get mutable RepeatedPtrField objects for all fields of interest.
+  RepeatedPtrField<std::string>* mrpf_string =
+      refl->MutableRepeatedPtrField<std::string>(&message, fd_repeated_string);
+  RepeatedPtrField<ForeignMessage>* mrpf_foreign_message =
+      refl->MutableRepeatedPtrField<ForeignMessage>(
+          &message, fd_repeated_foreign_message);
+  RepeatedPtrField<Message>* mrpf_message =
+      refl->MutableRepeatedPtrField<Message>(&message,
+                                             fd_repeated_foreign_message);
+
+  // Make sure we can do gets and sets through the Repeated[Ptr]Field objects.
+  for (int i = 0; i < 10; ++i) {
+    // Check gets through const objects.
+    EXPECT_EQ(rf_int32.Get(i), Func(i, 1));
+    EXPECT_EQ(rf_double.Get(i), Func(i, 2));
+    EXPECT_EQ(rpf_string.Get(i), StrFunc(i, 5));
+    EXPECT_EQ(rpf_foreign_message.Get(i).c(), Func(i, 6));
+    EXPECT_EQ(down_cast<const ForeignMessage*>(&rpf_message.Get(i))->c(),
+              Func(i, 6));
+
+    // Check gets through mutable objects.
+    EXPECT_EQ(mrf_int32->Get(i), Func(i, 1));
+    EXPECT_EQ(mrf_double->Get(i), Func(i, 2));
+    EXPECT_EQ(mrpf_string->Get(i), StrFunc(i, 5));
+    EXPECT_EQ(mrpf_foreign_message->Get(i).c(), Func(i, 6));
+    EXPECT_EQ(down_cast<const ForeignMessage*>(&mrpf_message->Get(i))->c(),
+              Func(i, 6));
+
+    // Check sets through mutable objects.
+    mrf_int32->Set(i, Func(i, -1));
+    mrf_double->Set(i, Func(i, -2));
+    mrpf_string->Mutable(i)->assign(StrFunc(i, -5));
+    mrpf_foreign_message->Mutable(i)->set_c(Func(i, -6));
+    EXPECT_EQ(message.repeated_int32(i), Func(i, -1));
+    EXPECT_EQ(message.repeated_double(i), Func(i, -2));
+    EXPECT_EQ(message.repeated_string(i), StrFunc(i, -5));
+    EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, -6));
+    down_cast<ForeignMessage*>(mrpf_message->Mutable(i))->set_c(Func(i, 7));
+    EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7));
+  }
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  // Make sure types are checked correctly at runtime.
+  const FieldDescriptor* fd_optional_int32 =
+      desc->FindFieldByName("optional_int32");
+  EXPECT_DEATH(refl->GetRepeatedField<int32_t>(message, fd_optional_int32),
+               "requires a repeated field");
+  EXPECT_DEATH(refl->GetRepeatedField<double>(message, fd_repeated_int32),
+               "not the right type");
+  EXPECT_DEATH(refl->GetRepeatedPtrField<TestAllTypes>(
+                   message, fd_repeated_foreign_message),
+               "wrong submessage type");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+
+TEST(RepeatedFieldReflectionTest, ExtensionFields) {
+  TestAllExtensions extended_message;
+  const Reflection* refl = extended_message.GetReflection();
+  const Descriptor* desc = extended_message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    extended_message.AddExtension(unittest::repeated_int64_extension,
+                                  Func(i, 1));
+  }
+
+  const FieldDescriptor* fd_repeated_int64_extension =
+      desc->file()->FindExtensionByName("repeated_int64_extension");
+  GOOGLE_CHECK(fd_repeated_int64_extension != nullptr);
+
+  const RepeatedField<int64_t>& rf_int64_extension =
+      refl->GetRepeatedField<int64_t>(extended_message,
+                                      fd_repeated_int64_extension);
+
+  RepeatedField<int64_t>* mrf_int64_extension =
+      refl->MutableRepeatedField<int64_t>(&extended_message,
+                                          fd_repeated_int64_extension);
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i));
+    mrf_int64_extension->Set(i, Func(i, -1));
+    EXPECT_EQ(Func(i, -1), extended_message.GetExtension(
+                               unittest::repeated_int64_extension, i));
+  }
+}
+
+template <typename Ref, typename MessageType, typename ValueType>
+void TestRepeatedFieldRefIteratorForPrimitive(
+    const Ref& handle, const MessageType& message,
+    ValueType (MessageType::*GetFunc)(int) const) {
+  int index = 0;
+  for (typename Ref::const_iterator it = handle.begin(); it != handle.end();
+       ++it) {
+    EXPECT_EQ((message.*GetFunc)(index), *it);
+    ++index;
+  }
+  EXPECT_EQ(handle.size(), index);
+}
+
+template <typename MessageType, typename ValueType>
+void TestRepeatedFieldRefIteratorForString(
+    const RepeatedFieldRef<std::string>& handle, const MessageType& message,
+    ValueType (MessageType::*GetFunc)(int) const) {
+  int index = 0;
+  for (typename RepeatedFieldRef<std::string>::const_iterator it =
+           handle.begin();
+       it != handle.end(); ++it) {
+    // Test both operator* and operator->
+    EXPECT_EQ((message.*GetFunc)(index), *it);
+    EXPECT_EQ((message.*GetFunc)(index).size(), it->size());
+    ++index;
+  }
+  EXPECT_EQ(handle.size(), index);
+}
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+  TestAllTypes message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    message.add_repeated_int32(Func(i, 1));
+    message.add_repeated_double(Func(i, 2));
+    message.add_repeated_string(StrFunc(i, 5));
+    message.add_repeated_foreign_message()->set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+  const FieldDescriptor* fd_repeated_double =
+      desc->FindFieldByName("repeated_double");
+  const FieldDescriptor* fd_repeated_string =
+      desc->FindFieldByName("repeated_string");
+  const FieldDescriptor* fd_repeated_foreign_message =
+      desc->FindFieldByName("repeated_foreign_message");
+
+  // Get RepeatedFieldRef objects for all fields of interest.
+  const RepeatedFieldRef<int32_t> rf_int32 =
+      refl->GetRepeatedFieldRef<int32_t>(message, fd_repeated_int32);
+  const RepeatedFieldRef<double> rf_double =
+      refl->GetRepeatedFieldRef<double>(message, fd_repeated_double);
+  const RepeatedFieldRef<std::string> rf_string =
+      refl->GetRepeatedFieldRef<std::string>(message, fd_repeated_string);
+  const RepeatedFieldRef<ForeignMessage> rf_foreign_message =
+      refl->GetRepeatedFieldRef<ForeignMessage>(message,
+                                                fd_repeated_foreign_message);
+  const RepeatedFieldRef<Message> rf_message =
+      refl->GetRepeatedFieldRef<Message>(message, fd_repeated_foreign_message);
+
+  // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<int32_t> mrf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32_t>(&message, fd_repeated_int32);
+  const MutableRepeatedFieldRef<double> mrf_double =
+      refl->GetMutableRepeatedFieldRef<double>(&message, fd_repeated_double);
+  const MutableRepeatedFieldRef<std::string> mrf_string =
+      refl->GetMutableRepeatedFieldRef<std::string>(&message,
+                                                    fd_repeated_string);
+  const MutableRepeatedFieldRef<ForeignMessage> mrf_foreign_message =
+      refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+          &message, fd_repeated_foreign_message);
+  const MutableRepeatedFieldRef<Message> mrf_message =
+      refl->GetMutableRepeatedFieldRef<Message>(&message,
+                                                fd_repeated_foreign_message);
+
+  EXPECT_EQ(message.repeated_int32_size(), rf_int32.size());
+  EXPECT_EQ(message.repeated_int32_size(), mrf_int32.size());
+  EXPECT_EQ(message.repeated_double_size(), rf_double.size());
+  EXPECT_EQ(message.repeated_double_size(), mrf_double.size());
+  EXPECT_EQ(message.repeated_string_size(), rf_string.size());
+  EXPECT_EQ(message.repeated_string_size(), mrf_string.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(), rf_foreign_message.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(),
+            mrf_foreign_message.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(), rf_message.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(), mrf_message.size());
+
+  EXPECT_FALSE(rf_int32.empty());
+  EXPECT_FALSE(mrf_int32.empty());
+  EXPECT_FALSE(rf_double.empty());
+  EXPECT_FALSE(mrf_double.empty());
+  EXPECT_FALSE(rf_string.empty());
+  EXPECT_FALSE(mrf_string.empty());
+  EXPECT_FALSE(rf_foreign_message.empty());
+  EXPECT_FALSE(mrf_foreign_message.empty());
+  EXPECT_FALSE(rf_message.empty());
+  EXPECT_FALSE(mrf_message.empty());
+
+  // Make sure we can do gets and sets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; ++i) {
+    // Check gets through const objects.
+    EXPECT_EQ(rf_int32.Get(i), Func(i, 1));
+    EXPECT_EQ(rf_double.Get(i), Func(i, 2));
+    EXPECT_EQ(rf_string.Get(i), StrFunc(i, 5));
+    ForeignMessage scratch_space;
+    EXPECT_EQ(rf_foreign_message.Get(i, &scratch_space).c(), Func(i, 6));
+    EXPECT_EQ(
+        down_cast<const ForeignMessage&>(rf_message.Get(i, &scratch_space)).c(),
+        Func(i, 6));
+
+    // Check gets through mutable objects.
+    EXPECT_EQ(mrf_int32.Get(i), Func(i, 1));
+    EXPECT_EQ(mrf_double.Get(i), Func(i, 2));
+    EXPECT_EQ(mrf_string.Get(i), StrFunc(i, 5));
+    EXPECT_EQ(mrf_foreign_message.Get(i, &scratch_space).c(), Func(i, 6));
+    EXPECT_EQ(
+        down_cast<const ForeignMessage&>(mrf_message.Get(i, &scratch_space))
+            .c(),
+        Func(i, 6));
+
+    // Check sets through mutable objects.
+    mrf_int32.Set(i, Func(i, -1));
+    mrf_double.Set(i, Func(i, -2));
+    mrf_string.Set(i, StrFunc(i, -5));
+    ForeignMessage foreign_message;
+    foreign_message.set_c(Func(i, -6));
+    mrf_foreign_message.Set(i, foreign_message);
+    EXPECT_EQ(message.repeated_int32(i), Func(i, -1));
+    EXPECT_EQ(message.repeated_double(i), Func(i, -2));
+    EXPECT_EQ(message.repeated_string(i), StrFunc(i, -5));
+    EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, -6));
+    foreign_message.set_c(Func(i, 7));
+    mrf_message.Set(i, foreign_message);
+    EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7));
+  }
+
+  // Test iterators.
+  TestRepeatedFieldRefIteratorForPrimitive(rf_int32, message,
+                                           &TestAllTypes::repeated_int32);
+  TestRepeatedFieldRefIteratorForPrimitive(rf_double, message,
+                                           &TestAllTypes::repeated_double);
+  TestRepeatedFieldRefIteratorForString(rf_string, message,
+                                        &TestAllTypes::repeated_string);
+
+  // Test iterators for message fields.
+  typedef RepeatedFieldRef<ForeignMessage>::iterator MessageIterator;
+  int index = 0;
+  for (MessageIterator it = rf_foreign_message.begin();
+       it != rf_foreign_message.end(); ++it) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), it->c());
+    ++index;
+  }
+  EXPECT_EQ(10, index);
+
+  // Test iterator operators that are not usually used in regular for-loops.
+  // Including: post increment, assign, ==.
+  MessageIterator old_it = rf_foreign_message.begin();
+  MessageIterator new_it = old_it++;
+  EXPECT_FALSE(old_it == new_it);
+  // Check that old_it++ increments old_it once.
+  for (index = 1; old_it != rf_foreign_message.end(); ++old_it, ++index) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), old_it->c());
+  }
+  EXPECT_EQ(10, index);
+  // Test assign operator.
+  old_it = new_it;
+  for (index = 0; old_it != rf_foreign_message.end(); ++old_it, ++index) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), old_it->c());
+  }
+  EXPECT_EQ(10, index);
+  // Check that the returned value of old_it++ is the one before increment.
+  for (index = 0; new_it != rf_foreign_message.end(); ++new_it, ++index) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), new_it->c());
+  }
+  EXPECT_EQ(10, index);
+
+  // Test MutableRepeatedFieldRef::Add()
+  mrf_int32.Add(1234);
+  mrf_double.Add(1234.0);
+  mrf_string.Add("1234");
+  ForeignMessage foreign_message;
+  foreign_message.set_c(1234);
+  mrf_foreign_message.Add(foreign_message);
+  EXPECT_EQ(1234, message.repeated_int32(10));
+  EXPECT_EQ(1234.0, message.repeated_double(10));
+  EXPECT_EQ("1234", message.repeated_string(10));
+  EXPECT_EQ(1234, message.repeated_foreign_message(10).c());
+
+  // Test MutableRepeatedFieldRef::RemoveLast()
+  mrf_int32.RemoveLast();
+  mrf_double.RemoveLast();
+  mrf_string.RemoveLast();
+  mrf_foreign_message.RemoveLast();
+  EXPECT_EQ(10, message.repeated_int32_size());
+  EXPECT_EQ(10, message.repeated_double_size());
+  EXPECT_EQ(10, message.repeated_string_size());
+  EXPECT_EQ(10, message.repeated_foreign_message_size());
+
+  // Test MutableRepeatedFieldRef::SwapElements()
+  mrf_int32.SwapElements(0, 9);
+  mrf_double.SwapElements(0, 9);
+  mrf_string.SwapElements(0, 9);
+  mrf_foreign_message.SwapElements(0, 9);
+  EXPECT_EQ(Func(9, -1), message.repeated_int32(0));
+  EXPECT_EQ(Func(0, -1), message.repeated_int32(9));
+  EXPECT_EQ(Func(9, -2), message.repeated_double(0));
+  EXPECT_EQ(Func(0, -2), message.repeated_double(9));
+  EXPECT_EQ(StrFunc(9, -5), message.repeated_string(0));
+  EXPECT_EQ(StrFunc(0, -5), message.repeated_string(9));
+  EXPECT_EQ(Func(9, 7), message.repeated_foreign_message(0).c());
+  EXPECT_EQ(Func(0, 7), message.repeated_foreign_message(9).c());
+
+  // Test MutableRepeatedFieldRef::Clear()
+  mrf_int32.Clear();
+  mrf_double.Clear();
+  mrf_string.Clear();
+  mrf_foreign_message.Clear();
+  EXPECT_EQ(0, message.repeated_int32_size());
+  EXPECT_EQ(0, message.repeated_double_size());
+  EXPECT_EQ(0, message.repeated_string_size());
+  EXPECT_EQ(0, message.repeated_foreign_message_size());
+
+  // Test (Mutable)RepeatedFieldRef::empty()
+  EXPECT_TRUE(rf_int32.empty());
+  EXPECT_TRUE(mrf_int32.empty());
+  EXPECT_TRUE(rf_double.empty());
+  EXPECT_TRUE(mrf_double.empty());
+  EXPECT_TRUE(rf_string.empty());
+  EXPECT_TRUE(mrf_string.empty());
+  EXPECT_TRUE(rf_foreign_message.empty());
+  EXPECT_TRUE(mrf_foreign_message.empty());
+  EXPECT_TRUE(rf_message.empty());
+  EXPECT_TRUE(mrf_message.empty());
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+  // Make sure types are checked correctly at runtime.
+  const FieldDescriptor* fd_optional_int32 =
+      desc->FindFieldByName("optional_int32");
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<int32_t>(message, fd_optional_int32),
+               "");
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<double>(message, fd_repeated_int32),
+               "");
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<TestAllTypes>(
+                   message, fd_repeated_foreign_message),
+               "");
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForEnums) {
+  TestAllTypes message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    message.add_repeated_nested_enum(TestAllTypes::BAR);
+  }
+
+  const FieldDescriptor* fd_repeated_nested_enum =
+      desc->FindFieldByName("repeated_nested_enum");
+  const RepeatedFieldRef<TestAllTypes::NestedEnum> enum_ref =
+      refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          message, fd_repeated_nested_enum);
+  const MutableRepeatedFieldRef<TestAllTypes::NestedEnum> mutable_enum_ref =
+      refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          &message, fd_repeated_nested_enum);
+  const RepeatedFieldRef<int32_t> int32_ref =
+      refl->GetRepeatedFieldRef<int32_t>(message, fd_repeated_nested_enum);
+  const MutableRepeatedFieldRef<int32_t> mutable_int32_ref =
+      refl->GetMutableRepeatedFieldRef<int32_t>(&message,
+                                                fd_repeated_nested_enum);
+
+  EXPECT_EQ(message.repeated_nested_enum_size(), enum_ref.size());
+  EXPECT_EQ(message.repeated_nested_enum_size(), mutable_enum_ref.size());
+  EXPECT_EQ(message.repeated_nested_enum_size(), int32_ref.size());
+  EXPECT_EQ(message.repeated_nested_enum_size(), mutable_int32_ref.size());
+
+  EXPECT_FALSE(enum_ref.empty());
+  EXPECT_FALSE(mutable_enum_ref.empty());
+  EXPECT_FALSE(int32_ref.empty());
+  EXPECT_FALSE(mutable_int32_ref.empty());
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAR, mutable_enum_ref.Get(i));
+    mutable_enum_ref.Set(i, TestAllTypes::BAZ);
+    EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(i));
+
+    message.set_repeated_nested_enum(i, TestAllTypes::BAR);
+    EXPECT_EQ(TestAllTypes::BAR, int32_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAR, mutable_int32_ref.Get(i));
+    mutable_int32_ref.Set(i, TestAllTypes::BAZ);
+    EXPECT_EQ(TestAllTypes::BAZ, int32_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(i));
+  }
+
+  TestRepeatedFieldRefIteratorForPrimitive(enum_ref, message,
+                                           &TestAllTypes::repeated_nested_enum);
+  TestRepeatedFieldRefIteratorForPrimitive(int32_ref, message,
+                                           &TestAllTypes::repeated_nested_enum);
+
+  // Test Add()
+  mutable_enum_ref.Add(TestAllTypes::FOO);
+  EXPECT_EQ(TestAllTypes::FOO, message.repeated_nested_enum(10));
+  mutable_int32_ref.Add(TestAllTypes::BAR);
+  EXPECT_EQ(TestAllTypes::BAR, message.repeated_nested_enum(11));
+
+  // Test RemoveLast()
+  mutable_enum_ref.RemoveLast();
+  EXPECT_EQ(11, message.repeated_nested_enum_size());
+  mutable_int32_ref.RemoveLast();
+  EXPECT_EQ(10, message.repeated_nested_enum_size());
+
+  // Test SwapElements()
+  mutable_enum_ref.Set(0, TestAllTypes::BAR);
+  mutable_enum_ref.Set(9, TestAllTypes::BAZ);
+  mutable_enum_ref.SwapElements(0, 9);
+  EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(0));
+  EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(9));
+  mutable_int32_ref.SwapElements(0, 9);
+  EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(0));
+  EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(9));
+
+  // Test Clear()
+  mutable_enum_ref.Clear();
+  EXPECT_EQ(0, message.repeated_nested_enum_size());
+  mutable_enum_ref.Add(TestAllTypes::FOO);
+  EXPECT_EQ(1, message.repeated_nested_enum_size());
+  mutable_int32_ref.Clear();
+  EXPECT_EQ(0, message.repeated_nested_enum_size());
+
+  // Test empty()
+  EXPECT_TRUE(enum_ref.empty());
+  EXPECT_TRUE(mutable_enum_ref.empty());
+  EXPECT_TRUE(int32_ref.empty());
+  EXPECT_TRUE(mutable_int32_ref.empty());
+}
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForExtensionFields) {
+  TestAllExtensions extended_message;
+  const Reflection* refl = extended_message.GetReflection();
+  const Descriptor* desc = extended_message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    extended_message.AddExtension(unittest::repeated_int64_extension,
+                                  Func(i, 1));
+  }
+
+  const FieldDescriptor* fd_repeated_int64_extension =
+      desc->file()->FindExtensionByName("repeated_int64_extension");
+  GOOGLE_CHECK(fd_repeated_int64_extension != nullptr);
+
+  const RepeatedFieldRef<int64_t> rf_int64_extension =
+      refl->GetRepeatedFieldRef<int64_t>(extended_message,
+                                         fd_repeated_int64_extension);
+
+  const MutableRepeatedFieldRef<int64_t> mrf_int64_extension =
+      refl->GetMutableRepeatedFieldRef<int64_t>(&extended_message,
+                                                fd_repeated_int64_extension);
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i));
+    mrf_int64_extension.Set(i, Func(i, -1));
+    EXPECT_EQ(Func(i, -1), extended_message.GetExtension(
+                               unittest::repeated_int64_extension, i));
+  }
+}
+
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+  // Set-up message content.
+  TestAllTypes m0, m1, m2;
+  for (int i = 0; i < 10; ++i) {
+    m0.add_repeated_int32(Func(i, 1));
+    m0.add_repeated_double(Func(i, 2));
+    m0.add_repeated_string(StrFunc(i, 5));
+    m0.add_repeated_foreign_message()->set_c(Func(i, 6));
+    m0.add_repeated_nested_enum(TestAllTypes::FOO);
+    m1.add_repeated_int32(Func(i, 11));
+    m1.add_repeated_double(Func(i, 12));
+    m1.add_repeated_string(StrFunc(i, 15));
+    m1.add_repeated_foreign_message()->set_c(Func(i, 16));
+    m1.add_repeated_nested_enum(TestAllTypes::BAR);
+    m2.add_repeated_int32(Func(i, 21));
+    m2.add_repeated_double(Func(i, 22));
+    m2.add_repeated_string(StrFunc(i, 25));
+    m2.add_repeated_foreign_message()->set_c(Func(i, 26));
+    m2.add_repeated_nested_enum(TestAllTypes::BAZ);
+  }
+
+  const Reflection* refl = m0.GetReflection();
+  const Descriptor* desc = m0.GetDescriptor();
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+  const FieldDescriptor* fd_repeated_double =
+      desc->FindFieldByName("repeated_double");
+  const FieldDescriptor* fd_repeated_string =
+      desc->FindFieldByName("repeated_string");
+  const FieldDescriptor* fd_repeated_foreign_message =
+      desc->FindFieldByName("repeated_foreign_message");
+  const FieldDescriptor* fd_repeated_nested_enum =
+      desc->FindFieldByName("repeated_nested_enum");
+
+  // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<int32_t> mrf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32_t>(&m0, fd_repeated_int32);
+  const MutableRepeatedFieldRef<double> mrf_double =
+      refl->GetMutableRepeatedFieldRef<double>(&m0, fd_repeated_double);
+  const MutableRepeatedFieldRef<std::string> mrf_string =
+      refl->GetMutableRepeatedFieldRef<std::string>(&m0, fd_repeated_string);
+  const MutableRepeatedFieldRef<ForeignMessage> mrf_foreign_message =
+      refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+          &m0, fd_repeated_foreign_message);
+  const MutableRepeatedFieldRef<TestAllTypes::NestedEnum> mrf_nested_enum =
+      refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          &m0, fd_repeated_nested_enum);
+
+  // Test MutableRepeatedRef::CopyFrom
+  mrf_int32.CopyFrom(refl->GetRepeatedFieldRef<int32_t>(m1, fd_repeated_int32));
+  mrf_double.CopyFrom(
+      refl->GetRepeatedFieldRef<double>(m1, fd_repeated_double));
+  mrf_string.CopyFrom(
+      refl->GetRepeatedFieldRef<std::string>(m1, fd_repeated_string));
+  mrf_foreign_message.CopyFrom(refl->GetRepeatedFieldRef<ForeignMessage>(
+      m1, fd_repeated_foreign_message));
+  mrf_nested_enum.CopyFrom(refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+      m1, fd_repeated_nested_enum));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 11), m0.repeated_int32(i));
+    EXPECT_EQ(Func(i, 12), m0.repeated_double(i));
+    EXPECT_EQ(StrFunc(i, 15), m0.repeated_string(i));
+    EXPECT_EQ(Func(i, 16), m0.repeated_foreign_message(i).c());
+    EXPECT_EQ(TestAllTypes::BAR, m0.repeated_nested_enum(i));
+  }
+
+  // Test MutableRepeatedRef::MergeFrom
+  mrf_int32.MergeFrom(
+      refl->GetRepeatedFieldRef<int32_t>(m2, fd_repeated_int32));
+  mrf_double.MergeFrom(
+      refl->GetRepeatedFieldRef<double>(m2, fd_repeated_double));
+  mrf_string.MergeFrom(
+      refl->GetRepeatedFieldRef<std::string>(m2, fd_repeated_string));
+  mrf_foreign_message.MergeFrom(refl->GetRepeatedFieldRef<ForeignMessage>(
+      m2, fd_repeated_foreign_message));
+  mrf_nested_enum.MergeFrom(refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+      m2, fd_repeated_nested_enum));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 21), m0.repeated_int32(i + 10));
+    EXPECT_EQ(Func(i, 22), m0.repeated_double(i + 10));
+    EXPECT_EQ(StrFunc(i, 25), m0.repeated_string(i + 10));
+    EXPECT_EQ(Func(i, 26), m0.repeated_foreign_message(i + 10).c());
+    EXPECT_EQ(TestAllTypes::BAZ, m0.repeated_nested_enum(i + 10));
+  }
+
+  // Test MutableRepeatedRef::Swap
+  // Swap between m0 and m2.
+  mrf_int32.Swap(
+      refl->GetMutableRepeatedFieldRef<int32_t>(&m2, fd_repeated_int32));
+  mrf_double.Swap(
+      refl->GetMutableRepeatedFieldRef<double>(&m2, fd_repeated_double));
+  mrf_string.Swap(
+      refl->GetMutableRepeatedFieldRef<std::string>(&m2, fd_repeated_string));
+  mrf_foreign_message.Swap(refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+      &m2, fd_repeated_foreign_message));
+  mrf_nested_enum.Swap(
+      refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          &m2, fd_repeated_nested_enum));
+  for (int i = 0; i < 10; ++i) {
+    // Check the content of m0.
+    EXPECT_EQ(Func(i, 21), m0.repeated_int32(i));
+    EXPECT_EQ(Func(i, 22), m0.repeated_double(i));
+    EXPECT_EQ(StrFunc(i, 25), m0.repeated_string(i));
+    EXPECT_EQ(Func(i, 26), m0.repeated_foreign_message(i).c());
+    EXPECT_EQ(TestAllTypes::BAZ, m0.repeated_nested_enum(i));
+
+    // Check the content of m2.
+    EXPECT_EQ(Func(i, 11), m2.repeated_int32(i));
+    EXPECT_EQ(Func(i, 12), m2.repeated_double(i));
+    EXPECT_EQ(StrFunc(i, 15), m2.repeated_string(i));
+    EXPECT_EQ(Func(i, 16), m2.repeated_foreign_message(i).c());
+    EXPECT_EQ(TestAllTypes::BAR, m2.repeated_nested_enum(i));
+    EXPECT_EQ(Func(i, 21), m2.repeated_int32(i + 10));
+    EXPECT_EQ(Func(i, 22), m2.repeated_double(i + 10));
+    EXPECT_EQ(StrFunc(i, 25), m2.repeated_string(i + 10));
+    EXPECT_EQ(Func(i, 26), m2.repeated_foreign_message(i + 10).c());
+    EXPECT_EQ(TestAllTypes::BAZ, m2.repeated_nested_enum(i + 10));
+  }
+}
+
+// Test that GetRepeatedFieldRef/MutableRepeatedFieldRef works with
+// DynamicMessage.
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefDynamicMessage) {
+  // DynamicMessage shares the same memory layout as generated message
+  // and use the same GeneratedMessageReflection code for reflection.
+  // All code paths should already be covered by the other tests for
+  // generated messages. Here we just test one field.
+
+  const Descriptor* desc = TestAllTypes::descriptor();
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> dynamic_message(factory.GetPrototype(desc)->New());
+  const Reflection* refl = dynamic_message->GetReflection();
+
+  MutableRepeatedFieldRef<int32_t> rf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32_t>(dynamic_message.get(),
+                                                fd_repeated_int32);
+  rf_int32.Add(1234);
+  EXPECT_EQ(1, refl->FieldSize(*dynamic_message, fd_repeated_int32));
+  EXPECT_EQ(1234,
+            refl->GetRepeatedInt32(*dynamic_message, fd_repeated_int32, 0));
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
new file mode 100644
index 0000000..d8a82bf
--- /dev/null
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -0,0 +1,2363 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// TODO(kenton):  Improve this unittest to bring it up to the standards of
+//   other proto2 unittests.
+
+#include <google/protobuf/repeated_field.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <iterator>
+#include <limits>
+#include <list>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+using ::protobuf_unittest::TestAllTypes;
+using ::testing::AllOf;
+using ::testing::ElementsAre;
+using ::testing::Ge;
+using ::testing::Le;
+
+TEST(RepeatedField, ConstInit) {
+  PROTOBUF_CONSTINIT static RepeatedField<int> field{};  // NOLINT
+  EXPECT_TRUE(field.empty());
+}
+
+// Test operations on a small RepeatedField.
+TEST(RepeatedField, Small) {
+  RepeatedField<int> field;
+
+  EXPECT_TRUE(field.empty());
+  EXPECT_EQ(field.size(), 0);
+
+  field.Add(5);
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 1);
+  EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
+
+  field.Add(42);
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 2);
+  EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
+  EXPECT_EQ(field.Get(1), 42);
+  EXPECT_EQ(field.at(1), 42);
+
+  field.Set(1, 23);
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 2);
+  EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
+  EXPECT_EQ(field.Get(1), 23);
+  EXPECT_EQ(field.at(1), 23);
+
+  field.at(1) = 25;
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 2);
+  EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
+  EXPECT_EQ(field.Get(1), 25);
+  EXPECT_EQ(field.at(1), 25);
+
+  field.RemoveLast();
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 1);
+  EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
+
+  field.Clear();
+
+  EXPECT_TRUE(field.empty());
+  EXPECT_EQ(field.size(), 0);
+  // Additional bytes are for 'struct Rep' header.
+  int expected_usage =
+      (sizeof(Arena*) > sizeof(int) ? sizeof(Arena*) / sizeof(int) : 3) *
+          sizeof(int) +
+      sizeof(Arena*);
+  EXPECT_GE(field.SpaceUsedExcludingSelf(), expected_usage);
+}
+
+
+// Test operations on a RepeatedField which is large enough to allocate a
+// separate array.
+TEST(RepeatedField, Large) {
+  RepeatedField<int> field;
+
+  for (int i = 0; i < 16; i++) {
+    field.Add(i * i);
+  }
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 16);
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(field.Get(i), i * i);
+  }
+
+  int expected_usage = 16 * sizeof(int);
+  EXPECT_GE(field.SpaceUsedExcludingSelf(), expected_usage);
+}
+
+template <typename Rep>
+void CheckAllocationSizes(bool is_ptr) {
+  using T = typename Rep::value_type;
+  // Use a large initial block to make the checks below easier to predict.
+  std::string buf(1 << 20, 0);
+
+  Arena arena(&buf[0], buf.size());
+  auto* rep = Arena::CreateMessage<Rep>(&arena);
+  size_t prev = arena.SpaceUsed();
+
+  for (int i = 0; i < 100; ++i) {
+    rep->Add(T{});
+    if (sizeof(void*) == 8) {
+      // For RepeatedPtrField we also allocate the T in the arena.
+      // Subtract those from the count.
+      size_t new_used = arena.SpaceUsed() - (is_ptr ? sizeof(T) * (i + 1) : 0);
+      size_t last_alloc = new_used - prev;
+      prev = new_used;
+
+      // When we actually allocated something, check the size.
+      if (last_alloc != 0) {
+        // Must be `>= 16`, as expected by the Arena.
+        ASSERT_GE(last_alloc, 16);
+        // Must be of a power of two.
+        size_t log2 = Bits::Log2FloorNonZero64(last_alloc);
+        ASSERT_EQ((1 << log2), last_alloc);
+      }
+
+      // The byte size must be a multiple of 8.
+      ASSERT_EQ(rep->Capacity() * sizeof(T) % 8, 0);
+    }
+  }
+}
+
+TEST(RepeatedField, ArenaAllocationSizesMatchExpectedValues) {
+  // RepeatedField guarantees that in 64-bit mode we never allocate anything
+  // smaller than 16 bytes from an arena.
+  // This is important to avoid a branch in the reallocation path.
+  // This is also important because allocating anything less would be wasting
+  // memory.
+  // If the allocation size is wrong, ReturnArrayMemory will GOOGLE_DCHECK.
+  CheckAllocationSizes<RepeatedField<bool>>(false);
+  CheckAllocationSizes<RepeatedField<uint8_t>>(false);
+  CheckAllocationSizes<RepeatedField<uint16_t>>(false);
+  CheckAllocationSizes<RepeatedField<uint32_t>>(false);
+  CheckAllocationSizes<RepeatedField<uint64_t>>(false);
+  CheckAllocationSizes<RepeatedField<std::pair<uint64_t, uint64_t>>>(false);
+}
+
+template <typename Rep>
+void CheckNaturalGrowthOnArenasReuseBlocks(bool is_ptr) {
+  Arena arena;
+  std::vector<Rep*> values;
+  using T = typename Rep::value_type;
+
+  static constexpr int kNumFields = 100;
+  static constexpr int kNumElems = 1000;
+  for (int i = 0; i < kNumFields; ++i) {
+    values.push_back(Arena::CreateMessage<Rep>(&arena));
+    auto& field = *values.back();
+    for (int j = 0; j < kNumElems; ++j) {
+      field.Add(T{});
+    }
+  }
+
+  size_t used_bytes_if_reusing =
+      values.size() * values[0]->Capacity() * (is_ptr ? sizeof(T*) : sizeof(T));
+  // Use a 2% slack for other overhead.
+  // If we were not reusing the blocks, the actual value would be ~2x the
+  // expected.
+  EXPECT_THAT(
+      arena.SpaceUsed() - (is_ptr ? sizeof(T) * kNumElems * kNumFields : 0),
+      AllOf(Ge(used_bytes_if_reusing), Le(1.02 * used_bytes_if_reusing)));
+}
+
+TEST(RepeatedField, NaturalGrowthOnArenasReuseBlocks) {
+  CheckNaturalGrowthOnArenasReuseBlocks<RepeatedField<int>>(false);
+}
+
+// Test swapping between various types of RepeatedFields.
+TEST(RepeatedField, SwapSmallSmall) {
+  RepeatedField<int> field1;
+  RepeatedField<int> field2;
+
+  field1.Add(5);
+  field1.Add(42);
+
+  EXPECT_FALSE(field1.empty());
+  EXPECT_EQ(field1.size(), 2);
+  EXPECT_EQ(field1.Get(0), 5);
+  EXPECT_EQ(field1.Get(1), 42);
+
+  EXPECT_TRUE(field2.empty());
+  EXPECT_EQ(field2.size(), 0);
+
+  field1.Swap(&field2);
+
+  EXPECT_TRUE(field1.empty());
+  EXPECT_EQ(field1.size(), 0);
+
+  EXPECT_FALSE(field2.empty());
+  EXPECT_EQ(field2.size(), 2);
+  EXPECT_EQ(field2.Get(0), 5);
+  EXPECT_EQ(field2.Get(1), 42);
+}
+
+TEST(RepeatedField, SwapLargeSmall) {
+  RepeatedField<int> field1;
+  RepeatedField<int> field2;
+
+  for (int i = 0; i < 16; i++) {
+    field1.Add(i * i);
+  }
+  field2.Add(5);
+  field2.Add(42);
+  field1.Swap(&field2);
+
+  EXPECT_EQ(field1.size(), 2);
+  EXPECT_EQ(field1.Get(0), 5);
+  EXPECT_EQ(field1.Get(1), 42);
+  EXPECT_EQ(field2.size(), 16);
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(field2.Get(i), i * i);
+  }
+}
+
+TEST(RepeatedField, SwapLargeLarge) {
+  RepeatedField<int> field1;
+  RepeatedField<int> field2;
+
+  field1.Add(5);
+  field1.Add(42);
+  for (int i = 0; i < 16; i++) {
+    field1.Add(i);
+    field2.Add(i * i);
+  }
+  field2.Swap(&field1);
+
+  EXPECT_EQ(field1.size(), 16);
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(field1.Get(i), i * i);
+  }
+  EXPECT_EQ(field2.size(), 18);
+  EXPECT_EQ(field2.Get(0), 5);
+  EXPECT_EQ(field2.Get(1), 42);
+  for (int i = 2; i < 18; i++) {
+    EXPECT_EQ(field2.Get(i), i - 2);
+  }
+}
+
+// Determines how much space was reserved by the given field by adding elements
+// to it until it re-allocates its space.
+static int ReservedSpace(RepeatedField<int>* field) {
+  const int* ptr = field->data();
+  do {
+    field->Add(0);
+  } while (field->data() == ptr);
+
+  return field->size() - 1;
+}
+
+TEST(RepeatedField, ReserveMoreThanDouble) {
+  // Reserve more than double the previous space in the field and expect the
+  // field to reserve exactly the amount specified.
+  RepeatedField<int> field;
+  field.Reserve(20);
+
+  EXPECT_LE(20, ReservedSpace(&field));
+}
+
+TEST(RepeatedField, ReserveLessThanDouble) {
+  // Reserve less than double the previous space in the field and expect the
+  // field to grow by double instead.
+  RepeatedField<int> field;
+  field.Reserve(20);
+  int capacity = field.Capacity();
+  field.Reserve(capacity * 1.5);
+
+  EXPECT_LE(2 * capacity, ReservedSpace(&field));
+}
+
+TEST(RepeatedField, ReserveLessThanExisting) {
+  // Reserve less than the previous space in the field and expect the
+  // field to not re-allocate at all.
+  RepeatedField<int> field;
+  field.Reserve(20);
+  const int* previous_ptr = field.data();
+  field.Reserve(10);
+
+  EXPECT_EQ(previous_ptr, field.data());
+  EXPECT_LE(20, ReservedSpace(&field));
+}
+
+TEST(RepeatedField, Resize) {
+  RepeatedField<int> field;
+  field.Resize(2, 1);
+  EXPECT_EQ(2, field.size());
+  field.Resize(5, 2);
+  EXPECT_EQ(5, field.size());
+  field.Resize(4, 3);
+  ASSERT_EQ(4, field.size());
+  EXPECT_EQ(1, field.Get(0));
+  EXPECT_EQ(1, field.Get(1));
+  EXPECT_EQ(2, field.Get(2));
+  EXPECT_EQ(2, field.Get(3));
+  field.Resize(0, 4);
+  EXPECT_TRUE(field.empty());
+}
+
+TEST(RepeatedField, ReserveNothing) {
+  RepeatedField<int> field;
+  EXPECT_EQ(0, field.Capacity());
+
+  field.Reserve(-1);
+  EXPECT_EQ(0, field.Capacity());
+}
+
+TEST(RepeatedField, ReserveLowerClamp) {
+  int clamped_value = internal::CalculateReserveSize<bool, sizeof(void*)>(0, 1);
+  EXPECT_GE(clamped_value, 8 / sizeof(bool));
+  EXPECT_EQ((internal::RepeatedFieldLowerClampLimit<bool, sizeof(void*)>()),
+            clamped_value);
+  // EXPECT_EQ(clamped_value, (internal::CalculateReserveSize<bool,
+  // sizeof(void*)>( clamped_value, 2)));
+
+  clamped_value = internal::CalculateReserveSize<int, sizeof(void*)>(0, 1);
+  EXPECT_GE(clamped_value, 8 / sizeof(int));
+  EXPECT_EQ((internal::RepeatedFieldLowerClampLimit<int, sizeof(void*)>()),
+            clamped_value);
+  // EXPECT_EQ(clamped_value, (internal::CalculateReserveSize<int,
+  // sizeof(void*)>( clamped_value, 2)));
+}
+
+TEST(RepeatedField, ReserveGrowth) {
+  // Make sure the field capacity doubles in size on repeated reservation.
+  for (int size = internal::RepeatedFieldLowerClampLimit<int, sizeof(void*)>(),
+           i = 0;
+       i < 4; ++i) {
+    int next =
+        sizeof(Arena*) >= sizeof(int)
+            ?
+            // for small enough elements, we double number of total bytes
+            ((2 * (size * sizeof(int) + sizeof(Arena*))) - sizeof(Arena*)) /
+                sizeof(int)
+            :
+            // we just double the number of elements if too large size.
+            size * 2;
+    EXPECT_EQ(next, (internal::CalculateReserveSize<int, sizeof(void*)>(
+                        size, size + 1)));
+    size = next;
+  }
+}
+
+TEST(RepeatedField, ReserveLarge) {
+  const int old_size = 10;
+  // This is a size we won't get by doubling:
+  const int new_size = old_size * 3 + 1;
+
+  // Reserving more than 2x current capacity should grow directly to that size.
+  EXPECT_EQ(new_size, (internal::CalculateReserveSize<int, sizeof(void*)>(
+                          old_size, new_size)));
+}
+
+TEST(RepeatedField, ReserveHuge) {
+  // Largest value that does not clamp to the large limit:
+  constexpr int non_clamping_limit =
+      (std::numeric_limits<int>::max() - sizeof(Arena*)) / 2;
+  ASSERT_LT(2 * non_clamping_limit, std::numeric_limits<int>::max());
+  EXPECT_LT((internal::CalculateReserveSize<int, sizeof(void*)>(
+                non_clamping_limit, non_clamping_limit + 1)),
+            std::numeric_limits<int>::max());
+
+  // Smallest size that *will* clamp to the upper limit:
+  constexpr int min_clamping_size = std::numeric_limits<int>::max() / 2 + 1;
+  EXPECT_EQ((internal::CalculateReserveSize<int, sizeof(void*)>(
+                min_clamping_size, min_clamping_size + 1)),
+            std::numeric_limits<int>::max());
+
+#ifdef PROTOBUF_TEST_ALLOW_LARGE_ALLOC
+  // The rest of this test may allocate several GB of memory, so it is only
+  // built if explicitly requested.
+  RepeatedField<int> huge_field;
+
+  // Reserve a size for huge_field that will clamp.
+  huge_field.Reserve(min_clamping_size);
+  EXPECT_GE(huge_field.Capacity(), min_clamping_size);
+  ASSERT_LT(huge_field.Capacity(), std::numeric_limits<int>::max() - 1);
+
+#ifndef PROTOBUF_ASAN
+  // The array containing all the fields is, in theory, up to MAXINT-1 in size.
+  // However, some compilers can't handle a struct whose size is larger
+  // than 2GB, and the protocol buffer format doesn't handle more than 2GB of
+  // data at once, either.  So we limit it, but the code below accesses beyond
+  // that limit.
+
+  // Allocation may return more memory than we requested. However, the updated
+  // size must still be clamped to a valid range.
+  huge_field.Reserve(huge_field.Capacity() + 1);
+  EXPECT_EQ(huge_field.Capacity(), std::numeric_limits<int>::max());
+#endif  // PROTOBUF_ASAN
+#endif  // PROTOBUF_TEST_ALLOW_LARGE_ALLOC
+}
+
+TEST(RepeatedField, MergeFrom) {
+  RepeatedField<int> source, destination;
+  source.Add(4);
+  source.Add(5);
+  destination.Add(1);
+  destination.Add(2);
+  destination.Add(3);
+
+  destination.MergeFrom(source);
+
+  ASSERT_EQ(5, destination.size());
+  EXPECT_EQ(1, destination.Get(0));
+  EXPECT_EQ(2, destination.Get(1));
+  EXPECT_EQ(3, destination.Get(2));
+  EXPECT_EQ(4, destination.Get(3));
+  EXPECT_EQ(5, destination.Get(4));
+}
+
+
+TEST(RepeatedField, CopyFrom) {
+  RepeatedField<int> source, destination;
+  source.Add(4);
+  source.Add(5);
+  destination.Add(1);
+  destination.Add(2);
+  destination.Add(3);
+
+  destination.CopyFrom(source);
+
+  ASSERT_EQ(2, destination.size());
+  EXPECT_EQ(4, destination.Get(0));
+  EXPECT_EQ(5, destination.Get(1));
+}
+
+TEST(RepeatedField, CopyFromSelf) {
+  RepeatedField<int> me;
+  me.Add(3);
+  me.CopyFrom(me);
+  ASSERT_EQ(1, me.size());
+  EXPECT_EQ(3, me.Get(0));
+}
+
+TEST(RepeatedField, Erase) {
+  RepeatedField<int> me;
+  RepeatedField<int>::iterator it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  me.Add(1);
+  me.Add(2);
+  me.Add(3);
+  it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  me.Add(4);
+  me.Add(5);
+  me.Add(6);
+  it = me.erase(me.begin() + 2, me.end());
+  EXPECT_TRUE(me.begin() + 2 == it);
+  EXPECT_EQ(2, me.size());
+  EXPECT_EQ(4, me.Get(0));
+  EXPECT_EQ(5, me.Get(1));
+
+  me.Add(6);
+  me.Add(7);
+  me.Add(8);
+  it = me.erase(me.begin() + 1, me.begin() + 3);
+  EXPECT_TRUE(me.begin() + 1 == it);
+  EXPECT_EQ(3, me.size());
+  EXPECT_EQ(4, me.Get(0));
+  EXPECT_EQ(7, me.Get(1));
+  EXPECT_EQ(8, me.Get(2));
+}
+
+// Add contents of empty container to an empty field.
+TEST(RepeatedField, AddRange1) {
+  RepeatedField<int> me;
+  std::vector<int> values;
+
+  me.Add(values.begin(), values.end());
+  ASSERT_EQ(me.size(), 0);
+}
+
+// Add contents of container with one thing to an empty field.
+TEST(RepeatedField, AddRange2) {
+  RepeatedField<int> me;
+  std::vector<int> values;
+  values.push_back(-1);
+
+  me.Add(values.begin(), values.end());
+  ASSERT_EQ(me.size(), 1);
+  ASSERT_EQ(me.Get(0), values[0]);
+}
+
+// Add contents of container with more than one thing to an empty field.
+TEST(RepeatedField, AddRange3) {
+  RepeatedField<int> me;
+  std::vector<int> values;
+  values.push_back(0);
+  values.push_back(1);
+
+  me.Add(values.begin(), values.end());
+  ASSERT_EQ(me.size(), 2);
+  ASSERT_EQ(me.Get(0), values[0]);
+  ASSERT_EQ(me.Get(1), values[1]);
+}
+
+// Add contents of container with more than one thing to a non-empty field.
+TEST(RepeatedField, AddRange4) {
+  RepeatedField<int> me;
+  me.Add(0);
+  me.Add(1);
+
+  std::vector<int> values;
+  values.push_back(2);
+  values.push_back(3);
+
+  me.Add(values.begin(), values.end());
+  ASSERT_EQ(me.size(), 4);
+  ASSERT_EQ(me.Get(0), 0);
+  ASSERT_EQ(me.Get(1), 1);
+  ASSERT_EQ(me.Get(2), values[0]);
+  ASSERT_EQ(me.Get(3), values[1]);
+}
+
+// Add contents of a stringstream in order to test code paths where there is
+// an input iterator.
+TEST(RepeatedField, AddRange5) {
+  RepeatedField<int> me;
+
+  std::stringstream ss;
+  ss << 1 << ' ' << 2;
+
+  me.Add(std::istream_iterator<int>(ss), std::istream_iterator<int>());
+  ASSERT_EQ(me.size(), 2);
+  ASSERT_EQ(me.Get(0), 1);
+  ASSERT_EQ(me.Get(1), 2);
+}
+
+TEST(RepeatedField, AddAndAssignRanges) {
+  RepeatedField<int> field;
+
+  int vals[] = {2, 27, 2875, 609250};
+  field.Assign(std::begin(vals), std::end(vals));
+
+  ASSERT_EQ(field.size(), 4);
+  EXPECT_EQ(field.Get(0), 2);
+  EXPECT_EQ(field.Get(1), 27);
+  EXPECT_EQ(field.Get(2), 2875);
+  EXPECT_EQ(field.Get(3), 609250);
+
+  field.Add(std::begin(vals), std::end(vals));
+  ASSERT_EQ(field.size(), 8);
+  EXPECT_EQ(field.Get(0), 2);
+  EXPECT_EQ(field.Get(1), 27);
+  EXPECT_EQ(field.Get(2), 2875);
+  EXPECT_EQ(field.Get(3), 609250);
+  EXPECT_EQ(field.Get(4), 2);
+  EXPECT_EQ(field.Get(5), 27);
+  EXPECT_EQ(field.Get(6), 2875);
+  EXPECT_EQ(field.Get(7), 609250);
+}
+
+TEST(RepeatedField, CopyConstruct) {
+  RepeatedField<int> source;
+  source.Add(1);
+  source.Add(2);
+
+  RepeatedField<int> destination(source);
+
+  ASSERT_EQ(2, destination.size());
+  EXPECT_EQ(1, destination.Get(0));
+  EXPECT_EQ(2, destination.Get(1));
+}
+
+TEST(RepeatedField, IteratorConstruct) {
+  std::vector<int> values;
+  RepeatedField<int> empty(values.begin(), values.end());
+  ASSERT_EQ(values.size(), empty.size());
+
+  values.push_back(1);
+  values.push_back(2);
+
+  RepeatedField<int> field(values.begin(), values.end());
+  ASSERT_EQ(values.size(), field.size());
+  EXPECT_EQ(values[0], field.Get(0));
+  EXPECT_EQ(values[1], field.Get(1));
+
+  RepeatedField<int> other(field.begin(), field.end());
+  ASSERT_EQ(values.size(), other.size());
+  EXPECT_EQ(values[0], other.Get(0));
+  EXPECT_EQ(values[1], other.Get(1));
+}
+
+TEST(RepeatedField, CopyAssign) {
+  RepeatedField<int> source, destination;
+  source.Add(4);
+  source.Add(5);
+  destination.Add(1);
+  destination.Add(2);
+  destination.Add(3);
+
+  destination = source;
+
+  ASSERT_EQ(2, destination.size());
+  EXPECT_EQ(4, destination.Get(0));
+  EXPECT_EQ(5, destination.Get(1));
+}
+
+TEST(RepeatedField, SelfAssign) {
+  // Verify that assignment to self does not destroy data.
+  RepeatedField<int> source, *p;
+  p = &source;
+  source.Add(7);
+  source.Add(8);
+
+  *p = source;
+
+  ASSERT_EQ(2, source.size());
+  EXPECT_EQ(7, source.Get(0));
+  EXPECT_EQ(8, source.Get(1));
+}
+
+TEST(RepeatedField, MoveConstruct) {
+  {
+    RepeatedField<int> source;
+    source.Add(1);
+    source.Add(2);
+    const int* data = source.data();
+    RepeatedField<int> destination = std::move(source);
+    EXPECT_EQ(data, destination.data());
+    EXPECT_THAT(destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_TRUE(source.empty());
+  }
+  {
+    Arena arena;
+    RepeatedField<int>* source =
+        Arena::CreateMessage<RepeatedField<int>>(&arena);
+    source->Add(1);
+    source->Add(2);
+    RepeatedField<int> destination = std::move(*source);
+    EXPECT_EQ(nullptr, destination.GetArena());
+    EXPECT_THAT(destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(*source, ElementsAre(1, 2));
+  }
+}
+
+TEST(RepeatedField, MoveAssign) {
+  {
+    RepeatedField<int> source;
+    source.Add(1);
+    source.Add(2);
+    RepeatedField<int> destination;
+    destination.Add(3);
+    const int* source_data = source.data();
+    const int* destination_data = destination.data();
+    destination = std::move(source);
+    EXPECT_EQ(source_data, destination.data());
+    EXPECT_THAT(destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_EQ(destination_data, source.data());
+    EXPECT_THAT(source, ElementsAre(3));
+  }
+  {
+    Arena arena;
+    RepeatedField<int>* source =
+        Arena::CreateMessage<RepeatedField<int>>(&arena);
+    source->Add(1);
+    source->Add(2);
+    RepeatedField<int>* destination =
+        Arena::CreateMessage<RepeatedField<int>>(&arena);
+    destination->Add(3);
+    const int* source_data = source->data();
+    const int* destination_data = destination->data();
+    *destination = std::move(*source);
+    EXPECT_EQ(source_data, destination->data());
+    EXPECT_THAT(*destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_EQ(destination_data, source->data());
+    EXPECT_THAT(*source, ElementsAre(3));
+  }
+  {
+    Arena source_arena;
+    RepeatedField<int>* source =
+        Arena::CreateMessage<RepeatedField<int>>(&source_arena);
+    source->Add(1);
+    source->Add(2);
+    Arena destination_arena;
+    RepeatedField<int>* destination =
+        Arena::CreateMessage<RepeatedField<int>>(&destination_arena);
+    destination->Add(3);
+    *destination = std::move(*source);
+    EXPECT_THAT(*destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(*source, ElementsAre(1, 2));
+  }
+  {
+    Arena arena;
+    RepeatedField<int>* source =
+        Arena::CreateMessage<RepeatedField<int>>(&arena);
+    source->Add(1);
+    source->Add(2);
+    RepeatedField<int> destination;
+    destination.Add(3);
+    destination = std::move(*source);
+    EXPECT_THAT(destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(*source, ElementsAre(1, 2));
+  }
+  {
+    RepeatedField<int> source;
+    source.Add(1);
+    source.Add(2);
+    Arena arena;
+    RepeatedField<int>* destination =
+        Arena::CreateMessage<RepeatedField<int>>(&arena);
+    destination->Add(3);
+    *destination = std::move(source);
+    EXPECT_THAT(*destination, ElementsAre(1, 2));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(source, ElementsAre(1, 2));
+  }
+  {
+    RepeatedField<int> field;
+    // An alias to defeat -Wself-move.
+    RepeatedField<int>& alias = field;
+    field.Add(1);
+    field.Add(2);
+    const int* data = field.data();
+    field = std::move(alias);
+    EXPECT_EQ(data, field.data());
+    EXPECT_THAT(field, ElementsAre(1, 2));
+  }
+  {
+    Arena arena;
+    RepeatedField<int>* field =
+        Arena::CreateMessage<RepeatedField<int>>(&arena);
+    field->Add(1);
+    field->Add(2);
+    const int* data = field->data();
+    *field = std::move(*field);
+    EXPECT_EQ(data, field->data());
+    EXPECT_THAT(*field, ElementsAre(1, 2));
+  }
+}
+
+TEST(Movable, Works) {
+  class NonMoveConstructible {
+   public:
+    NonMoveConstructible(NonMoveConstructible&&) = delete;
+    NonMoveConstructible& operator=(NonMoveConstructible&&) { return *this; }
+  };
+  class NonMoveAssignable {
+   public:
+    NonMoveAssignable(NonMoveAssignable&&) {}
+    NonMoveAssignable& operator=(NonMoveConstructible&&) = delete;
+  };
+  class NonMovable {
+   public:
+    NonMovable(NonMovable&&) = delete;
+    NonMovable& operator=(NonMovable&&) = delete;
+  };
+
+  EXPECT_TRUE(internal::IsMovable<std::string>::value);
+
+  EXPECT_FALSE(std::is_move_constructible<NonMoveConstructible>::value);
+  EXPECT_TRUE(std::is_move_assignable<NonMoveConstructible>::value);
+  EXPECT_FALSE(internal::IsMovable<NonMoveConstructible>::value);
+
+  EXPECT_TRUE(std::is_move_constructible<NonMoveAssignable>::value);
+  EXPECT_FALSE(std::is_move_assignable<NonMoveAssignable>::value);
+  EXPECT_FALSE(internal::IsMovable<NonMoveAssignable>::value);
+
+  EXPECT_FALSE(internal::IsMovable<NonMovable>::value);
+}
+
+TEST(RepeatedField, MoveAdd) {
+  RepeatedPtrField<TestAllTypes> field;
+  TestAllTypes test_all_types;
+  auto* optional_nested_message =
+      test_all_types.mutable_optional_nested_message();
+  optional_nested_message->set_bb(42);
+  field.Add(std::move(test_all_types));
+
+  EXPECT_EQ(optional_nested_message,
+            field.Mutable(0)->mutable_optional_nested_message());
+}
+
+TEST(RepeatedField, MutableDataIsMutable) {
+  RepeatedField<int> field;
+  field.Add(1);
+  EXPECT_EQ(1, field.Get(0));
+  // The fact that this line compiles would be enough, but we'll check the
+  // value anyway.
+  *field.mutable_data() = 2;
+  EXPECT_EQ(2, field.Get(0));
+}
+
+TEST(RepeatedField, SubscriptOperators) {
+  RepeatedField<int> field;
+  field.Add(1);
+  EXPECT_EQ(1, field.Get(0));
+  EXPECT_EQ(1, field[0]);
+  EXPECT_EQ(field.Mutable(0), &field[0]);
+  const RepeatedField<int>& const_field = field;
+  EXPECT_EQ(field.data(), &const_field[0]);
+}
+
+TEST(RepeatedField, Truncate) {
+  RepeatedField<int> field;
+
+  field.Add(12);
+  field.Add(34);
+  field.Add(56);
+  field.Add(78);
+  EXPECT_EQ(4, field.size());
+
+  field.Truncate(3);
+  EXPECT_EQ(3, field.size());
+
+  field.Add(90);
+  EXPECT_EQ(4, field.size());
+  EXPECT_EQ(90, field.Get(3));
+
+  // Truncations that don't change the size are allowed, but growing is not
+  // allowed.
+  field.Truncate(field.size());
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size");
+#endif
+}
+
+
+TEST(RepeatedField, ExtractSubrange) {
+  // Exhaustively test every subrange in arrays of all sizes from 0 through 9.
+  for (int sz = 0; sz < 10; ++sz) {
+    for (int num = 0; num <= sz; ++num) {
+      for (int start = 0; start < sz - num; ++start) {
+        // Create RepeatedField with sz elements having values 0 through sz-1.
+        RepeatedField<int32_t> field;
+        for (int i = 0; i < sz; ++i) field.Add(i);
+        EXPECT_EQ(field.size(), sz);
+
+        // Create a catcher array and call ExtractSubrange.
+        int32_t catcher[10];
+        for (int i = 0; i < 10; ++i) catcher[i] = -1;
+        field.ExtractSubrange(start, num, catcher);
+
+        // Does the resulting array have the right size?
+        EXPECT_EQ(field.size(), sz - num);
+
+        // Were the removed elements extracted into the catcher array?
+        for (int i = 0; i < num; ++i) EXPECT_EQ(catcher[i], start + i);
+        EXPECT_EQ(catcher[num], -1);
+
+        // Does the resulting array contain the right values?
+        for (int i = 0; i < start; ++i) EXPECT_EQ(field.Get(i), i);
+        for (int i = start; i < field.size(); ++i)
+          EXPECT_EQ(field.Get(i), i + num);
+      }
+    }
+  }
+}
+
+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<std::string> field;
+  for (int i = 0; i < 32; i++) {
+    field.Add(std::string("abcdefghijklmnopqrstuvwxyz0123456789"));
+  }
+  EXPECT_EQ(32, field.size());
+  field.Clear();
+  EXPECT_EQ(0, field.size());
+  EXPECT_LE(32, field.Capacity());
+
+  field.Reserve(1024);
+  EXPECT_EQ(0, field.size());
+  EXPECT_LE(1024, field.Capacity());
+  // Finish test -- |field| should destroy the cleared-but-not-yet-destroyed
+  // strings.
+}
+
+TEST(RepeatedField, TestSAddFromSelf) {
+  RepeatedField<int> field;
+  field.Add(0);
+  for (int i = 0; i < 1000; i++) {
+    field.Add(field[0]);
+  }
+}
+
+// ===================================================================
+// RepeatedPtrField tests.  These pretty much just mirror the RepeatedField
+// tests above.
+
+TEST(RepeatedPtrField, ConstInit) {
+  PROTOBUF_CONSTINIT static RepeatedPtrField<std::string> field{};  // NOLINT
+  EXPECT_TRUE(field.empty());
+}
+
+// This helper overload set tests whether X::f can be called with a braced pair,
+// X::f({a, b}) of std::string iterators (specifically, pointers: That call is
+// ambiguous if and only if the call to ValidResolutionPointerRange is not.
+template <typename X>
+auto ValidResolutionPointerRange(const std::string* p)
+    -> decltype(X::f({p, p + 2}), std::true_type{});
+template <typename X>
+std::false_type ValidResolutionPointerRange(void*);
+
+TEST(RepeatedPtrField, UnambiguousConstructor) {
+  struct X {
+    static bool f(std::vector<std::string>) { return false; }
+    static bool f(google::protobuf::RepeatedPtrField<std::string>) { return true; }
+
+    static bool g(std::vector<int>) { return false; }
+    static bool g(google::protobuf::RepeatedPtrField<std::string>) { return true; }
+  };
+
+  // RepeatedPtrField has no initializer-list constructor, and a constructor
+  // from to const char* values is excluded by its constraints.
+  EXPECT_FALSE(X::f({"abc", "xyz"}));
+
+  // Construction from a pair of int* is also not ambiguous.
+  int a[5] = {};
+  EXPECT_FALSE(X::g({a, a + 5}));
+
+  // Construction from string iterators for the unique string overload "g"
+  // works.
+  // Disabling this for now, this is actually ambiguous with libstdc++.
+  // std::string b[2] = {"abc", "xyz"};
+  // EXPECT_TRUE(X::g({b, b + 2}));
+
+  // Construction from string iterators for "f" is ambiguous, since both
+  // containers are equally good.
+  //
+  // X::f({b, b + 2});  // error => ValidResolutionPointerRange is unambiguous.
+  EXPECT_FALSE(decltype(ValidResolutionPointerRange<X>(nullptr))::value);
+}
+
+TEST(RepeatedPtrField, Small) {
+  RepeatedPtrField<std::string> field;
+
+  EXPECT_TRUE(field.empty());
+  EXPECT_EQ(field.size(), 0);
+
+  field.Add()->assign("foo");
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 1);
+  EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
+
+  field.Add()->assign("bar");
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 2);
+  EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
+  EXPECT_EQ(field.Get(1), "bar");
+  EXPECT_EQ(field.at(1), "bar");
+
+  field.Mutable(1)->assign("baz");
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 2);
+  EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
+  EXPECT_EQ(field.Get(1), "baz");
+  EXPECT_EQ(field.at(1), "baz");
+
+  field.RemoveLast();
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 1);
+  EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
+
+  field.Clear();
+
+  EXPECT_TRUE(field.empty());
+  EXPECT_EQ(field.size(), 0);
+}
+
+TEST(RepeatedPtrField, Large) {
+  RepeatedPtrField<std::string> field;
+
+  for (int i = 0; i < 16; i++) {
+    *field.Add() += 'a' + i;
+  }
+
+  EXPECT_EQ(field.size(), 16);
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(field.Get(i).size(), 1);
+    EXPECT_EQ(field.Get(i)[0], 'a' + i);
+  }
+
+  int min_expected_usage = 16 * sizeof(std::string);
+  EXPECT_GE(field.SpaceUsedExcludingSelf(), min_expected_usage);
+}
+
+TEST(RepeatedPtrField, ArenaAllocationSizesMatchExpectedValues) {
+  CheckAllocationSizes<RepeatedPtrField<std::string>>(true);
+}
+
+TEST(RepeatedPtrField, NaturalGrowthOnArenasReuseBlocks) {
+  CheckNaturalGrowthOnArenasReuseBlocks<RepeatedPtrField<std::string>>(true);
+}
+
+TEST(RepeatedPtrField, AddAndAssignRanges) {
+  RepeatedPtrField<std::string> field;
+
+  const char* vals[] = {"abc", "x", "yz", "xyzzy"};
+  field.Assign(std::begin(vals), std::end(vals));
+
+  ASSERT_EQ(field.size(), 4);
+  EXPECT_EQ(field.Get(0), "abc");
+  EXPECT_EQ(field.Get(1), "x");
+  EXPECT_EQ(field.Get(2), "yz");
+  EXPECT_EQ(field.Get(3), "xyzzy");
+
+  field.Add(std::begin(vals), std::end(vals));
+  ASSERT_EQ(field.size(), 8);
+  EXPECT_EQ(field.Get(0), "abc");
+  EXPECT_EQ(field.Get(1), "x");
+  EXPECT_EQ(field.Get(2), "yz");
+  EXPECT_EQ(field.Get(3), "xyzzy");
+  EXPECT_EQ(field.Get(4), "abc");
+  EXPECT_EQ(field.Get(5), "x");
+  EXPECT_EQ(field.Get(6), "yz");
+  EXPECT_EQ(field.Get(7), "xyzzy");
+}
+
+TEST(RepeatedPtrField, SwapSmallSmall) {
+  RepeatedPtrField<std::string> field1;
+  RepeatedPtrField<std::string> field2;
+
+  EXPECT_TRUE(field1.empty());
+  EXPECT_EQ(field1.size(), 0);
+  EXPECT_TRUE(field2.empty());
+  EXPECT_EQ(field2.size(), 0);
+
+  field1.Add()->assign("foo");
+  field1.Add()->assign("bar");
+
+  EXPECT_FALSE(field1.empty());
+  EXPECT_EQ(field1.size(), 2);
+  EXPECT_EQ(field1.Get(0), "foo");
+  EXPECT_EQ(field1.Get(1), "bar");
+
+  EXPECT_TRUE(field2.empty());
+  EXPECT_EQ(field2.size(), 0);
+
+  field1.Swap(&field2);
+
+  EXPECT_TRUE(field1.empty());
+  EXPECT_EQ(field1.size(), 0);
+
+  EXPECT_EQ(field2.size(), 2);
+  EXPECT_EQ(field2.Get(0), "foo");
+  EXPECT_EQ(field2.Get(1), "bar");
+}
+
+TEST(RepeatedPtrField, SwapLargeSmall) {
+  RepeatedPtrField<std::string> field1;
+  RepeatedPtrField<std::string> field2;
+
+  field2.Add()->assign("foo");
+  field2.Add()->assign("bar");
+  for (int i = 0; i < 16; i++) {
+    *field1.Add() += 'a' + i;
+  }
+  field1.Swap(&field2);
+
+  EXPECT_EQ(field1.size(), 2);
+  EXPECT_EQ(field1.Get(0), "foo");
+  EXPECT_EQ(field1.Get(1), "bar");
+  EXPECT_EQ(field2.size(), 16);
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(field2.Get(i).size(), 1);
+    EXPECT_EQ(field2.Get(i)[0], 'a' + i);
+  }
+}
+
+TEST(RepeatedPtrField, SwapLargeLarge) {
+  RepeatedPtrField<std::string> field1;
+  RepeatedPtrField<std::string> field2;
+
+  field1.Add()->assign("foo");
+  field1.Add()->assign("bar");
+  for (int i = 0; i < 16; i++) {
+    *field1.Add() += 'A' + i;
+    *field2.Add() += 'a' + i;
+  }
+  field2.Swap(&field1);
+
+  EXPECT_EQ(field1.size(), 16);
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(field1.Get(i).size(), 1);
+    EXPECT_EQ(field1.Get(i)[0], 'a' + i);
+  }
+  EXPECT_EQ(field2.size(), 18);
+  EXPECT_EQ(field2.Get(0), "foo");
+  EXPECT_EQ(field2.Get(1), "bar");
+  for (int i = 2; i < 18; i++) {
+    EXPECT_EQ(field2.Get(i).size(), 1);
+    EXPECT_EQ(field2.Get(i)[0], 'A' + i - 2);
+  }
+}
+
+static int ReservedSpace(RepeatedPtrField<std::string>* field) {
+  const std::string* const* ptr = field->data();
+  do {
+    field->Add();
+  } while (field->data() == ptr);
+
+  return field->size() - 1;
+}
+
+TEST(RepeatedPtrField, ReserveMoreThanDouble) {
+  RepeatedPtrField<std::string> field;
+  field.Reserve(20);
+
+  EXPECT_LE(20, ReservedSpace(&field));
+}
+
+TEST(RepeatedPtrField, ReserveLessThanDouble) {
+  RepeatedPtrField<std::string> field;
+  field.Reserve(20);
+
+  int capacity = field.Capacity();
+  // Grow by 1.5x
+  field.Reserve(capacity + (capacity >> 2));
+
+  EXPECT_LE(2 * capacity, ReservedSpace(&field));
+}
+
+TEST(RepeatedPtrField, ReserveLessThanExisting) {
+  RepeatedPtrField<std::string> field;
+  field.Reserve(20);
+  const std::string* const* previous_ptr = field.data();
+  field.Reserve(10);
+
+  EXPECT_EQ(previous_ptr, field.data());
+  EXPECT_LE(20, ReservedSpace(&field));
+}
+
+TEST(RepeatedPtrField, ReserveDoesntLoseAllocated) {
+  // Check that a bug is fixed:  An earlier implementation of Reserve()
+  // failed to copy pointers to allocated-but-cleared objects, possibly
+  // leading to segfaults.
+  RepeatedPtrField<std::string> field;
+  std::string* first = field.Add();
+  field.RemoveLast();
+
+  field.Reserve(20);
+  EXPECT_EQ(first, field.Add());
+}
+
+// Clearing elements is tricky with RepeatedPtrFields since the memory for
+// the elements is retained and reused.
+TEST(RepeatedPtrField, ClearedElements) {
+  RepeatedPtrField<std::string> field;
+
+  std::string* original = field.Add();
+  *original = "foo";
+
+  EXPECT_EQ(field.ClearedCount(), 0);
+
+  field.RemoveLast();
+  EXPECT_TRUE(original->empty());
+  EXPECT_EQ(field.ClearedCount(), 1);
+
+  EXPECT_EQ(field.Add(),
+            original);  // Should return same string for reuse.
+  EXPECT_EQ(field.UnsafeArenaReleaseLast(), original);  // We take ownership.
+  EXPECT_EQ(field.ClearedCount(), 0);
+
+  EXPECT_NE(field.Add(), original);  // Should NOT return the same string.
+  EXPECT_EQ(field.ClearedCount(), 0);
+
+  field.UnsafeArenaAddAllocated(original);  // Give ownership back.
+  EXPECT_EQ(field.ClearedCount(), 0);
+  EXPECT_EQ(field.Mutable(1), original);
+
+  field.Clear();
+  EXPECT_EQ(field.ClearedCount(), 2);
+#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
+  EXPECT_EQ(field.ReleaseCleared(), original);  // Take ownership again.
+  EXPECT_EQ(field.ClearedCount(), 1);
+  EXPECT_NE(field.Add(), original);
+  EXPECT_EQ(field.ClearedCount(), 0);
+  EXPECT_NE(field.Add(), original);
+  EXPECT_EQ(field.ClearedCount(), 0);
+
+  field.AddCleared(original);  // Give ownership back, but as a cleared object.
+  EXPECT_EQ(field.ClearedCount(), 1);
+  EXPECT_EQ(field.Add(), original);
+  EXPECT_EQ(field.ClearedCount(), 0);
+#endif  // !PROTOBUF_FUTURE_BREAKING_CHANGES
+}
+
+// Test all code paths in AddAllocated().
+TEST(RepeatedPtrField, AddAllocated) {
+  RepeatedPtrField<std::string> field;
+  while (field.size() < field.Capacity()) {
+    field.Add()->assign("filler");
+  }
+
+  int index = field.size();
+
+  // First branch:  Field is at capacity with no cleared objects.
+  std::string* foo = new std::string("foo");
+  field.AddAllocated(foo);
+  EXPECT_EQ(index + 1, field.size());
+  EXPECT_EQ(0, field.ClearedCount());
+  EXPECT_EQ(foo, &field.Get(index));
+
+  // Last branch:  Field is not at capacity and there are no cleared objects.
+  std::string* bar = new std::string("bar");
+  field.AddAllocated(bar);
+  ++index;
+  EXPECT_EQ(index + 1, field.size());
+  EXPECT_EQ(0, field.ClearedCount());
+  EXPECT_EQ(bar, &field.Get(index));
+
+  // Third branch:  Field is not at capacity and there are no cleared objects.
+  field.RemoveLast();
+  std::string* baz = new std::string("baz");
+  field.AddAllocated(baz);
+  EXPECT_EQ(index + 1, field.size());
+  EXPECT_EQ(1, field.ClearedCount());
+  EXPECT_EQ(baz, &field.Get(index));
+
+  // Second branch:  Field is at capacity but has some cleared objects.
+  while (field.size() < field.Capacity()) {
+    field.Add()->assign("filler2");
+  }
+  field.RemoveLast();
+  index = field.size();
+  std::string* moo = new std::string("moo");
+  field.AddAllocated(moo);
+  EXPECT_EQ(index + 1, field.size());
+  // We should have discarded the cleared object.
+  EXPECT_EQ(0, field.ClearedCount());
+  EXPECT_EQ(moo, &field.Get(index));
+}
+
+TEST(RepeatedPtrField, AddAllocatedDifferentArena) {
+  RepeatedPtrField<TestAllTypes> field;
+  Arena arena;
+  auto* msg = Arena::CreateMessage<TestAllTypes>(&arena);
+  field.AddAllocated(msg);
+}
+
+TEST(RepeatedPtrField, MergeFrom) {
+  RepeatedPtrField<std::string> source, destination;
+  source.Add()->assign("4");
+  source.Add()->assign("5");
+  destination.Add()->assign("1");
+  destination.Add()->assign("2");
+  destination.Add()->assign("3");
+
+  destination.MergeFrom(source);
+
+  ASSERT_EQ(5, destination.size());
+  EXPECT_EQ("1", destination.Get(0));
+  EXPECT_EQ("2", destination.Get(1));
+  EXPECT_EQ("3", destination.Get(2));
+  EXPECT_EQ("4", destination.Get(3));
+  EXPECT_EQ("5", destination.Get(4));
+}
+
+
+TEST(RepeatedPtrField, CopyFrom) {
+  RepeatedPtrField<std::string> source, destination;
+  source.Add()->assign("4");
+  source.Add()->assign("5");
+  destination.Add()->assign("1");
+  destination.Add()->assign("2");
+  destination.Add()->assign("3");
+
+  destination.CopyFrom(source);
+
+  ASSERT_EQ(2, destination.size());
+  EXPECT_EQ("4", destination.Get(0));
+  EXPECT_EQ("5", destination.Get(1));
+}
+
+TEST(RepeatedPtrField, CopyFromSelf) {
+  RepeatedPtrField<std::string> me;
+  me.Add()->assign("1");
+  me.CopyFrom(me);
+  ASSERT_EQ(1, me.size());
+  EXPECT_EQ("1", me.Get(0));
+}
+
+TEST(RepeatedPtrField, Erase) {
+  RepeatedPtrField<std::string> me;
+  RepeatedPtrField<std::string>::iterator it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  *me.Add() = "1";
+  *me.Add() = "2";
+  *me.Add() = "3";
+  it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  *me.Add() = "4";
+  *me.Add() = "5";
+  *me.Add() = "6";
+  it = me.erase(me.begin() + 2, me.end());
+  EXPECT_TRUE(me.begin() + 2 == it);
+  EXPECT_EQ(2, me.size());
+  EXPECT_EQ("4", me.Get(0));
+  EXPECT_EQ("5", me.Get(1));
+
+  *me.Add() = "6";
+  *me.Add() = "7";
+  *me.Add() = "8";
+  it = me.erase(me.begin() + 1, me.begin() + 3);
+  EXPECT_TRUE(me.begin() + 1 == it);
+  EXPECT_EQ(3, me.size());
+  EXPECT_EQ("4", me.Get(0));
+  EXPECT_EQ("7", me.Get(1));
+  EXPECT_EQ("8", me.Get(2));
+}
+
+TEST(RepeatedPtrField, CopyConstruct) {
+  RepeatedPtrField<std::string> source;
+  source.Add()->assign("1");
+  source.Add()->assign("2");
+
+  RepeatedPtrField<std::string> destination(source);
+
+  ASSERT_EQ(2, destination.size());
+  EXPECT_EQ("1", destination.Get(0));
+  EXPECT_EQ("2", destination.Get(1));
+}
+
+TEST(RepeatedPtrField, IteratorConstruct_String) {
+  std::vector<std::string> values;
+  values.push_back("1");
+  values.push_back("2");
+
+  RepeatedPtrField<std::string> field(values.begin(), values.end());
+  ASSERT_EQ(values.size(), field.size());
+  EXPECT_EQ(values[0], field.Get(0));
+  EXPECT_EQ(values[1], field.Get(1));
+
+  RepeatedPtrField<std::string> other(field.begin(), field.end());
+  ASSERT_EQ(values.size(), other.size());
+  EXPECT_EQ(values[0], other.Get(0));
+  EXPECT_EQ(values[1], other.Get(1));
+}
+
+TEST(RepeatedPtrField, IteratorConstruct_Proto) {
+  typedef TestAllTypes::NestedMessage Nested;
+  std::vector<Nested> values;
+  values.push_back(Nested());
+  values.back().set_bb(1);
+  values.push_back(Nested());
+  values.back().set_bb(2);
+
+  RepeatedPtrField<Nested> field(values.begin(), values.end());
+  ASSERT_EQ(values.size(), field.size());
+  EXPECT_EQ(values[0].bb(), field.Get(0).bb());
+  EXPECT_EQ(values[1].bb(), field.Get(1).bb());
+
+  RepeatedPtrField<Nested> other(field.begin(), field.end());
+  ASSERT_EQ(values.size(), other.size());
+  EXPECT_EQ(values[0].bb(), other.Get(0).bb());
+  EXPECT_EQ(values[1].bb(), other.Get(1).bb());
+}
+
+TEST(RepeatedPtrField, CopyAssign) {
+  RepeatedPtrField<std::string> source, destination;
+  source.Add()->assign("4");
+  source.Add()->assign("5");
+  destination.Add()->assign("1");
+  destination.Add()->assign("2");
+  destination.Add()->assign("3");
+
+  destination = source;
+
+  ASSERT_EQ(2, destination.size());
+  EXPECT_EQ("4", destination.Get(0));
+  EXPECT_EQ("5", destination.Get(1));
+}
+
+TEST(RepeatedPtrField, SelfAssign) {
+  // Verify that assignment to self does not destroy data.
+  RepeatedPtrField<std::string> source, *p;
+  p = &source;
+  source.Add()->assign("7");
+  source.Add()->assign("8");
+
+  *p = source;
+
+  ASSERT_EQ(2, source.size());
+  EXPECT_EQ("7", source.Get(0));
+  EXPECT_EQ("8", source.Get(1));
+}
+
+TEST(RepeatedPtrField, MoveConstruct) {
+  {
+    RepeatedPtrField<std::string> source;
+    *source.Add() = "1";
+    *source.Add() = "2";
+    const std::string* const* data = source.data();
+    RepeatedPtrField<std::string> destination = std::move(source);
+    EXPECT_EQ(data, destination.data());
+    EXPECT_THAT(destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_TRUE(source.empty());
+  }
+  {
+    Arena arena;
+    RepeatedPtrField<std::string>* source =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&arena);
+    *source->Add() = "1";
+    *source->Add() = "2";
+    RepeatedPtrField<std::string> destination = std::move(*source);
+    EXPECT_EQ(nullptr, destination.GetArena());
+    EXPECT_THAT(destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(*source, ElementsAre("1", "2"));
+  }
+}
+
+TEST(RepeatedPtrField, MoveAssign) {
+  {
+    RepeatedPtrField<std::string> source;
+    *source.Add() = "1";
+    *source.Add() = "2";
+    RepeatedPtrField<std::string> destination;
+    *destination.Add() = "3";
+    const std::string* const* source_data = source.data();
+    const std::string* const* destination_data = destination.data();
+    destination = std::move(source);
+    EXPECT_EQ(source_data, destination.data());
+    EXPECT_THAT(destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_EQ(destination_data, source.data());
+    EXPECT_THAT(source, ElementsAre("3"));
+  }
+  {
+    Arena arena;
+    RepeatedPtrField<std::string>* source =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&arena);
+    *source->Add() = "1";
+    *source->Add() = "2";
+    RepeatedPtrField<std::string>* destination =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&arena);
+    *destination->Add() = "3";
+    const std::string* const* source_data = source->data();
+    const std::string* const* destination_data = destination->data();
+    *destination = std::move(*source);
+    EXPECT_EQ(source_data, destination->data());
+    EXPECT_THAT(*destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_EQ(destination_data, source->data());
+    EXPECT_THAT(*source, ElementsAre("3"));
+  }
+  {
+    Arena source_arena;
+    RepeatedPtrField<std::string>* source =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&source_arena);
+    *source->Add() = "1";
+    *source->Add() = "2";
+    Arena destination_arena;
+    RepeatedPtrField<std::string>* destination =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&destination_arena);
+    *destination->Add() = "3";
+    *destination = std::move(*source);
+    EXPECT_THAT(*destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(*source, ElementsAre("1", "2"));
+  }
+  {
+    Arena arena;
+    RepeatedPtrField<std::string>* source =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&arena);
+    *source->Add() = "1";
+    *source->Add() = "2";
+    RepeatedPtrField<std::string> destination;
+    *destination.Add() = "3";
+    destination = std::move(*source);
+    EXPECT_THAT(destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(*source, ElementsAre("1", "2"));
+  }
+  {
+    RepeatedPtrField<std::string> source;
+    *source.Add() = "1";
+    *source.Add() = "2";
+    Arena arena;
+    RepeatedPtrField<std::string>* destination =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&arena);
+    *destination->Add() = "3";
+    *destination = std::move(source);
+    EXPECT_THAT(*destination, ElementsAre("1", "2"));
+    // This property isn't guaranteed but it's useful to have a test that would
+    // catch changes in this area.
+    EXPECT_THAT(source, ElementsAre("1", "2"));
+  }
+  {
+    RepeatedPtrField<std::string> field;
+    // An alias to defeat -Wself-move.
+    RepeatedPtrField<std::string>& alias = field;
+    *field.Add() = "1";
+    *field.Add() = "2";
+    const std::string* const* data = field.data();
+    field = std::move(alias);
+    EXPECT_EQ(data, field.data());
+    EXPECT_THAT(field, ElementsAre("1", "2"));
+  }
+  {
+    Arena arena;
+    RepeatedPtrField<std::string>* field =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(&arena);
+    *field->Add() = "1";
+    *field->Add() = "2";
+    const std::string* const* data = field->data();
+    *field = std::move(*field);
+    EXPECT_EQ(data, field->data());
+    EXPECT_THAT(*field, ElementsAre("1", "2"));
+  }
+}
+
+TEST(RepeatedPtrField, MutableDataIsMutable) {
+  RepeatedPtrField<std::string> field;
+  *field.Add() = "1";
+  EXPECT_EQ("1", field.Get(0));
+  // The fact that this line compiles would be enough, but we'll check the
+  // value anyway.
+  std::string** data = field.mutable_data();
+  **data = "2";
+  EXPECT_EQ("2", field.Get(0));
+}
+
+TEST(RepeatedPtrField, SubscriptOperators) {
+  RepeatedPtrField<std::string> field;
+  *field.Add() = "1";
+  EXPECT_EQ("1", field.Get(0));
+  EXPECT_EQ("1", field[0]);
+  EXPECT_EQ(field.Mutable(0), &field[0]);
+  const RepeatedPtrField<std::string>& const_field = field;
+  EXPECT_EQ(*field.data(), &const_field[0]);
+}
+
+TEST(RepeatedPtrField, ExtractSubrange) {
+  // Exhaustively test every subrange in arrays of all sizes from 0 through 9
+  // with 0 through 3 cleared elements at the end.
+  for (int sz = 0; sz < 10; ++sz) {
+    for (int num = 0; num <= sz; ++num) {
+      for (int start = 0; start < sz - num; ++start) {
+        for (int extra = 0; extra < 4; ++extra) {
+          std::vector<std::string*> subject;
+
+          // Create an array with "sz" elements and "extra" cleared elements.
+          // Use an arena to avoid copies from debug-build stability checks.
+          Arena arena;
+          RepeatedPtrField<std::string> field(&arena);
+          for (int i = 0; i < sz + extra; ++i) {
+            subject.push_back(new std::string());
+            field.AddAllocated(subject[i]);
+          }
+          EXPECT_EQ(field.size(), sz + extra);
+          for (int i = 0; i < extra; ++i) field.RemoveLast();
+          EXPECT_EQ(field.size(), sz);
+          EXPECT_EQ(field.ClearedCount(), extra);
+
+          // Create a catcher array and call ExtractSubrange.
+          std::string* catcher[10];
+          for (int i = 0; i < 10; ++i) catcher[i] = nullptr;
+          field.ExtractSubrange(start, num, catcher);
+
+          // Does the resulting array have the right size?
+          EXPECT_EQ(field.size(), sz - num);
+
+          // Were the removed elements extracted into the catcher array?
+          for (int i = 0; i < num; ++i)
+            EXPECT_EQ(*catcher[i], *subject[start + i]);
+          EXPECT_EQ(nullptr, catcher[num]);
+
+          // Does the resulting array contain the right values?
+          for (int i = 0; i < start; ++i)
+            EXPECT_EQ(field.Mutable(i), subject[i]);
+          for (int i = start; i < field.size(); ++i)
+            EXPECT_EQ(field.Mutable(i), subject[i + num]);
+
+          // Reinstate the cleared elements.
+          EXPECT_EQ(field.ClearedCount(), extra);
+          for (int i = 0; i < extra; ++i) field.Add();
+          EXPECT_EQ(field.ClearedCount(), 0);
+          EXPECT_EQ(field.size(), sz - num + extra);
+
+          // Make sure the extra elements are all there (in some order).
+          for (int i = sz; i < sz + extra; ++i) {
+            int count = 0;
+            for (int j = sz; j < sz + extra; ++j) {
+              if (field.Mutable(j - num) == subject[i]) count += 1;
+            }
+            EXPECT_EQ(count, 1);
+          }
+
+          // Release the caught elements.
+          for (int i = 0; i < num; ++i) delete catcher[i];
+        }
+      }
+    }
+  }
+}
+
+TEST(RepeatedPtrField, DeleteSubrange) {
+  // DeleteSubrange is a trivial extension of ExtendSubrange.
+}
+
+// ===================================================================
+
+// Iterator tests stolen from net/proto/proto-array_unittest.
+class RepeatedFieldIteratorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    for (int i = 0; i < 3; ++i) {
+      proto_array_.Add(i);
+    }
+  }
+
+  RepeatedField<int> proto_array_;
+};
+
+TEST_F(RepeatedFieldIteratorTest, Convertible) {
+  RepeatedField<int>::iterator iter = proto_array_.begin();
+  RepeatedField<int>::const_iterator c_iter = iter;
+  RepeatedField<int>::value_type value = *c_iter;
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(RepeatedFieldIteratorTest, MutableIteration) {
+  RepeatedField<int>::iterator iter = proto_array_.begin();
+  EXPECT_EQ(0, *iter);
+  ++iter;
+  EXPECT_EQ(1, *iter++);
+  EXPECT_EQ(2, *iter);
+  ++iter;
+  EXPECT_TRUE(proto_array_.end() == iter);
+
+  EXPECT_EQ(2, *(proto_array_.end() - 1));
+}
+
+TEST_F(RepeatedFieldIteratorTest, ConstIteration) {
+  const RepeatedField<int>& const_proto_array = proto_array_;
+  RepeatedField<int>::const_iterator iter = const_proto_array.begin();
+  EXPECT_EQ(0, *iter);
+  ++iter;
+  EXPECT_EQ(1, *iter++);
+  EXPECT_EQ(2, *iter);
+  ++iter;
+  EXPECT_TRUE(const_proto_array.end() == iter);
+  EXPECT_EQ(2, *(const_proto_array.end() - 1));
+}
+
+TEST_F(RepeatedFieldIteratorTest, Mutation) {
+  RepeatedField<int>::iterator iter = proto_array_.begin();
+  *iter = 7;
+  EXPECT_EQ(7, proto_array_.Get(0));
+}
+
+// -------------------------------------------------------------------
+
+class RepeatedPtrFieldIteratorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    proto_array_.Add()->assign("foo");
+    proto_array_.Add()->assign("bar");
+    proto_array_.Add()->assign("baz");
+  }
+
+  RepeatedPtrField<std::string> proto_array_;
+};
+
+TEST_F(RepeatedPtrFieldIteratorTest, Convertible) {
+  RepeatedPtrField<std::string>::iterator iter = proto_array_.begin();
+  RepeatedPtrField<std::string>::const_iterator c_iter = iter;
+  RepeatedPtrField<std::string>::value_type value = *c_iter;
+  EXPECT_EQ("foo", value);
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, MutableIteration) {
+  RepeatedPtrField<std::string>::iterator iter = proto_array_.begin();
+  EXPECT_EQ("foo", *iter);
+  ++iter;
+  EXPECT_EQ("bar", *(iter++));
+  EXPECT_EQ("baz", *iter);
+  ++iter;
+  EXPECT_TRUE(proto_array_.end() == iter);
+  EXPECT_EQ("baz", *(--proto_array_.end()));
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, ConstIteration) {
+  const RepeatedPtrField<std::string>& const_proto_array = proto_array_;
+  RepeatedPtrField<std::string>::const_iterator iter =
+      const_proto_array.begin();
+  iter - const_proto_array.cbegin();
+  EXPECT_EQ("foo", *iter);
+  ++iter;
+  EXPECT_EQ("bar", *(iter++));
+  EXPECT_EQ("baz", *iter);
+  ++iter;
+  EXPECT_TRUE(const_proto_array.end() == iter);
+  EXPECT_EQ("baz", *(--const_proto_array.end()));
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, MutableReverseIteration) {
+  RepeatedPtrField<std::string>::reverse_iterator iter = proto_array_.rbegin();
+  EXPECT_EQ("baz", *iter);
+  ++iter;
+  EXPECT_EQ("bar", *(iter++));
+  EXPECT_EQ("foo", *iter);
+  ++iter;
+  EXPECT_TRUE(proto_array_.rend() == iter);
+  EXPECT_EQ("foo", *(--proto_array_.rend()));
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, ConstReverseIteration) {
+  const RepeatedPtrField<std::string>& const_proto_array = proto_array_;
+  RepeatedPtrField<std::string>::const_reverse_iterator iter =
+      const_proto_array.rbegin();
+  EXPECT_EQ("baz", *iter);
+  ++iter;
+  EXPECT_EQ("bar", *(iter++));
+  EXPECT_EQ("foo", *iter);
+  ++iter;
+  EXPECT_TRUE(const_proto_array.rend() == iter);
+  EXPECT_EQ("foo", *(--const_proto_array.rend()));
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, RandomAccess) {
+  RepeatedPtrField<std::string>::iterator iter = proto_array_.begin();
+  RepeatedPtrField<std::string>::iterator iter2 = iter;
+  ++iter2;
+  ++iter2;
+  EXPECT_TRUE(iter + 2 == iter2);
+  EXPECT_TRUE(iter == iter2 - 2);
+  EXPECT_EQ("baz", iter[2]);
+  EXPECT_EQ("baz", *(iter + 2));
+  EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, RandomAccessConst) {
+  RepeatedPtrField<std::string>::const_iterator iter = proto_array_.cbegin();
+  RepeatedPtrField<std::string>::const_iterator iter2 = iter;
+  ++iter2;
+  ++iter2;
+  EXPECT_TRUE(iter + 2 == iter2);
+  EXPECT_TRUE(iter == iter2 - 2);
+  EXPECT_EQ("baz", iter[2]);
+  EXPECT_EQ("baz", *(iter + 2));
+  EXPECT_EQ(3, proto_array_.cend() - proto_array_.cbegin());
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, DifferenceConstConversion) {
+  EXPECT_EQ(3, proto_array_.end() - proto_array_.cbegin());
+  EXPECT_EQ(3, proto_array_.cend() - proto_array_.begin());
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, Comparable) {
+  RepeatedPtrField<std::string>::const_iterator iter = proto_array_.begin();
+  RepeatedPtrField<std::string>::const_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, ComparableConstConversion) {
+  RepeatedPtrField<std::string>::iterator iter = proto_array_.begin();
+  RepeatedPtrField<std::string>::const_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter == proto_array_.cbegin());
+  EXPECT_TRUE(proto_array_.cbegin() == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter2 != iter);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
+// Uninitialized iterator does not point to any of the RepeatedPtrField.
+TEST_F(RepeatedPtrFieldIteratorTest, UninitializedIterator) {
+  RepeatedPtrField<std::string>::iterator iter;
+  EXPECT_TRUE(iter != proto_array_.begin());
+  EXPECT_TRUE(iter != proto_array_.begin() + 1);
+  EXPECT_TRUE(iter != proto_array_.begin() + 2);
+  EXPECT_TRUE(iter != proto_array_.begin() + 3);
+  EXPECT_TRUE(iter != proto_array_.end());
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) {
+  proto_array_.Clear();
+  proto_array_.Add()->assign("a");
+  proto_array_.Add()->assign("c");
+  proto_array_.Add()->assign("d");
+  proto_array_.Add()->assign("n");
+  proto_array_.Add()->assign("p");
+  proto_array_.Add()->assign("x");
+  proto_array_.Add()->assign("y");
+
+  std::string v = "f";
+  RepeatedPtrField<std::string>::const_iterator it =
+      std::lower_bound(proto_array_.begin(), proto_array_.end(), v);
+
+  EXPECT_EQ(*it, "n");
+  EXPECT_TRUE(it == proto_array_.begin() + 3);
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, Mutation) {
+  RepeatedPtrField<std::string>::iterator iter = proto_array_.begin();
+  *iter = "moo";
+  EXPECT_EQ("moo", proto_array_.Get(0));
+}
+
+// -------------------------------------------------------------------
+
+class RepeatedPtrFieldPtrsIteratorTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    proto_array_.Add()->assign("foo");
+    proto_array_.Add()->assign("bar");
+    proto_array_.Add()->assign("baz");
+    const_proto_array_ = &proto_array_;
+  }
+
+  RepeatedPtrField<std::string> proto_array_;
+  const RepeatedPtrField<std::string>* const_proto_array_;
+};
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  static_cast<void>(iter);
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertibleConstPtr) {
+  RepeatedPtrField<std::string>::const_pointer_iterator iter =
+      const_proto_array_->pointer_begin();
+  static_cast<void>(iter);
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  EXPECT_EQ("foo", **iter);
+  ++iter;
+  EXPECT_EQ("bar", **(iter++));
+  EXPECT_EQ("baz", **iter);
+  ++iter;
+  EXPECT_TRUE(proto_array_.pointer_end() == iter);
+  EXPECT_EQ("baz", **(--proto_array_.pointer_end()));
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutableConstPtrIteration) {
+  RepeatedPtrField<std::string>::const_pointer_iterator iter =
+      const_proto_array_->pointer_begin();
+  EXPECT_EQ("foo", **iter);
+  ++iter;
+  EXPECT_EQ("bar", **(iter++));
+  EXPECT_EQ("baz", **iter);
+  ++iter;
+  EXPECT_TRUE(const_proto_array_->pointer_end() == iter);
+  EXPECT_EQ("baz", **(--const_proto_array_->pointer_end()));
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  RepeatedPtrField<std::string>::pointer_iterator iter2 = iter;
+  ++iter2;
+  ++iter2;
+  EXPECT_TRUE(iter + 2 == iter2);
+  EXPECT_TRUE(iter == iter2 - 2);
+  EXPECT_EQ("baz", *iter[2]);
+  EXPECT_EQ("baz", **(iter + 2));
+  EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomConstPtrAccess) {
+  RepeatedPtrField<std::string>::const_pointer_iterator iter =
+      const_proto_array_->pointer_begin();
+  RepeatedPtrField<std::string>::const_pointer_iterator iter2 = iter;
+  ++iter2;
+  ++iter2;
+  EXPECT_TRUE(iter + 2 == iter2);
+  EXPECT_TRUE(iter == iter2 - 2);
+  EXPECT_EQ("baz", *iter[2]);
+  EXPECT_EQ("baz", **(iter + 2));
+  EXPECT_EQ(3, const_proto_array_->end() - const_proto_array_->begin());
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, DifferenceConstConversion) {
+  EXPECT_EQ(3,
+            proto_array_.pointer_end() - const_proto_array_->pointer_begin());
+  EXPECT_EQ(3,
+            const_proto_array_->pointer_end() - proto_array_.pointer_begin());
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  RepeatedPtrField<std::string>::pointer_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparableConstPtr) {
+  RepeatedPtrField<std::string>::const_pointer_iterator iter =
+      const_proto_array_->pointer_begin();
+  RepeatedPtrField<std::string>::const_pointer_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparableConstConversion) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  RepeatedPtrField<std::string>::const_pointer_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter == const_proto_array_->pointer_begin());
+  EXPECT_TRUE(const_proto_array_->pointer_begin() == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter2 != iter);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
+// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs.
+// Dereferencing an uninitialized iterator crashes the process.
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
+  RepeatedPtrField<std::string>::pointer_iterator iter;
+  EXPECT_TRUE(iter != proto_array_.pointer_begin());
+  EXPECT_TRUE(iter != proto_array_.pointer_begin() + 1);
+  EXPECT_TRUE(iter != proto_array_.pointer_begin() + 2);
+  EXPECT_TRUE(iter != proto_array_.pointer_begin() + 3);
+  EXPECT_TRUE(iter != proto_array_.pointer_end());
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedConstPtrIterator) {
+  RepeatedPtrField<std::string>::const_pointer_iterator iter;
+  EXPECT_TRUE(iter != const_proto_array_->pointer_begin());
+  EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 1);
+  EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 2);
+  EXPECT_TRUE(iter != const_proto_array_->pointer_begin() + 3);
+  EXPECT_TRUE(iter != const_proto_array_->pointer_end());
+}
+
+// This comparison functor is required by the tests for RepeatedPtrOverPtrs.
+// They operate on strings and need to compare strings as strings in
+// any stl algorithm, even though the iterator returns a pointer to a
+// string
+// - i.e. *iter has type std::string*.
+struct StringLessThan {
+  bool operator()(const std::string* z, const std::string* y) const {
+    return *z < *y;
+  }
+};
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) {
+  proto_array_.Clear();
+  proto_array_.Add()->assign("a");
+  proto_array_.Add()->assign("c");
+  proto_array_.Add()->assign("d");
+  proto_array_.Add()->assign("n");
+  proto_array_.Add()->assign("p");
+  proto_array_.Add()->assign("x");
+  proto_array_.Add()->assign("y");
+
+  {
+    std::string v = "f";
+    RepeatedPtrField<std::string>::pointer_iterator it =
+        std::lower_bound(proto_array_.pointer_begin(),
+                         proto_array_.pointer_end(), &v, StringLessThan());
+
+    GOOGLE_CHECK(*it != nullptr);
+
+    EXPECT_EQ(**it, "n");
+    EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
+  }
+  {
+    std::string v = "f";
+    RepeatedPtrField<std::string>::const_pointer_iterator it = std::lower_bound(
+        const_proto_array_->pointer_begin(), const_proto_array_->pointer_end(),
+        &v, StringLessThan());
+
+    GOOGLE_CHECK(*it != nullptr);
+
+    EXPECT_EQ(**it, "n");
+    EXPECT_TRUE(it == const_proto_array_->pointer_begin() + 3);
+  }
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  **iter = "moo";
+  EXPECT_EQ("moo", proto_array_.Get(0));
+
+  EXPECT_EQ("bar", proto_array_.Get(1));
+  EXPECT_EQ("baz", proto_array_.Get(2));
+  ++iter;
+  delete *iter;
+  *iter = new std::string("a");
+  ++iter;
+  delete *iter;
+  *iter = new std::string("b");
+  EXPECT_EQ("a", proto_array_.Get(1));
+  EXPECT_EQ("b", proto_array_.Get(2));
+}
+
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, Sort) {
+  proto_array_.Add()->assign("c");
+  proto_array_.Add()->assign("d");
+  proto_array_.Add()->assign("n");
+  proto_array_.Add()->assign("p");
+  proto_array_.Add()->assign("a");
+  proto_array_.Add()->assign("y");
+  proto_array_.Add()->assign("x");
+  EXPECT_EQ("foo", proto_array_.Get(0));
+  EXPECT_EQ("n", proto_array_.Get(5));
+  EXPECT_EQ("x", proto_array_.Get(9));
+  std::sort(proto_array_.pointer_begin(), proto_array_.pointer_end(),
+            StringLessThan());
+  EXPECT_EQ("a", proto_array_.Get(0));
+  EXPECT_EQ("baz", proto_array_.Get(2));
+  EXPECT_EQ("y", proto_array_.Get(9));
+}
+
+// -----------------------------------------------------------------------------
+// Unit-tests for the insert iterators
+// google::protobuf::RepeatedFieldBackInserter,
+// google::protobuf::AllocatedRepeatedPtrFieldBackInserter
+// Ported from util/gtl/proto-array-iterators_unittest.
+
+class RepeatedFieldInsertionIteratorsTest : public testing::Test {
+ protected:
+  std::list<double> halves;
+  std::list<int> fibonacci;
+  std::vector<std::string> words;
+  typedef TestAllTypes::NestedMessage Nested;
+  Nested nesteds[2];
+  std::vector<Nested*> nested_ptrs;
+  TestAllTypes protobuffer;
+
+  void SetUp() override {
+    fibonacci.push_back(1);
+    fibonacci.push_back(1);
+    fibonacci.push_back(2);
+    fibonacci.push_back(3);
+    fibonacci.push_back(5);
+    fibonacci.push_back(8);
+    std::copy(fibonacci.begin(), fibonacci.end(),
+              RepeatedFieldBackInserter(protobuffer.mutable_repeated_int32()));
+
+    halves.push_back(1.0);
+    halves.push_back(0.5);
+    halves.push_back(0.25);
+    halves.push_back(0.125);
+    halves.push_back(0.0625);
+    std::copy(halves.begin(), halves.end(),
+              RepeatedFieldBackInserter(protobuffer.mutable_repeated_double()));
+
+    words.push_back("Able");
+    words.push_back("was");
+    words.push_back("I");
+    words.push_back("ere");
+    words.push_back("I");
+    words.push_back("saw");
+    words.push_back("Elba");
+    std::copy(words.begin(), words.end(),
+              RepeatedFieldBackInserter(protobuffer.mutable_repeated_string()));
+
+    nesteds[0].set_bb(17);
+    nesteds[1].set_bb(4711);
+    std::copy(&nesteds[0], &nesteds[2],
+              RepeatedFieldBackInserter(
+                  protobuffer.mutable_repeated_nested_message()));
+
+    nested_ptrs.push_back(new Nested);
+    nested_ptrs.back()->set_bb(170);
+    nested_ptrs.push_back(new Nested);
+    nested_ptrs.back()->set_bb(47110);
+    std::copy(nested_ptrs.begin(), nested_ptrs.end(),
+              RepeatedFieldBackInserter(
+                  protobuffer.mutable_repeated_nested_message()));
+  }
+
+  void TearDown() override {
+    for (auto ptr : nested_ptrs) {
+      delete ptr;
+    }
+  }
+};
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Fibonacci) {
+  EXPECT_TRUE(std::equal(fibonacci.begin(), fibonacci.end(),
+                         protobuffer.repeated_int32().begin()));
+  EXPECT_TRUE(std::equal(protobuffer.repeated_int32().begin(),
+                         protobuffer.repeated_int32().end(),
+                         fibonacci.begin()));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Halves) {
+  EXPECT_TRUE(std::equal(halves.begin(), halves.end(),
+                         protobuffer.repeated_double().begin()));
+  EXPECT_TRUE(std::equal(protobuffer.repeated_double().begin(),
+                         protobuffer.repeated_double().end(), halves.begin()));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Words) {
+  ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
+  for (int i = 0; i < words.size(); ++i)
+    EXPECT_EQ(words.at(i), protobuffer.repeated_string(i));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Words2) {
+  words.clear();
+  words.push_back("sing");
+  words.push_back("a");
+  words.push_back("song");
+  words.push_back("of");
+  words.push_back("six");
+  words.push_back("pence");
+  protobuffer.mutable_repeated_string()->Clear();
+  std::copy(
+      words.begin(), words.end(),
+      RepeatedPtrFieldBackInserter(protobuffer.mutable_repeated_string()));
+  ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
+  for (int i = 0; i < words.size(); ++i)
+    EXPECT_EQ(words.at(i), protobuffer.repeated_string(i));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, Nesteds) {
+  ASSERT_EQ(protobuffer.repeated_nested_message_size(), 4);
+  EXPECT_EQ(protobuffer.repeated_nested_message(0).bb(), 17);
+  EXPECT_EQ(protobuffer.repeated_nested_message(1).bb(), 4711);
+  EXPECT_EQ(protobuffer.repeated_nested_message(2).bb(), 170);
+  EXPECT_EQ(protobuffer.repeated_nested_message(3).bb(), 47110);
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest,
+       AllocatedRepeatedPtrFieldWithStringIntData) {
+  std::vector<Nested*> data;
+  TestAllTypes goldenproto;
+  for (int i = 0; i < 10; ++i) {
+    Nested* new_data = new Nested;
+    new_data->set_bb(i);
+    data.push_back(new_data);
+
+    new_data = goldenproto.add_repeated_nested_message();
+    new_data->set_bb(i);
+  }
+  TestAllTypes testproto;
+  std::copy(data.begin(), data.end(),
+            AllocatedRepeatedPtrFieldBackInserter(
+                testproto.mutable_repeated_nested_message()));
+  EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest,
+       AllocatedRepeatedPtrFieldWithString) {
+  std::vector<std::string*> data;
+  TestAllTypes goldenproto;
+  for (int i = 0; i < 10; ++i) {
+    std::string* new_data = new std::string;
+    *new_data = "name-" + StrCat(i);
+    data.push_back(new_data);
+
+    new_data = goldenproto.add_repeated_string();
+    *new_data = "name-" + StrCat(i);
+  }
+  TestAllTypes testproto;
+  std::copy(data.begin(), data.end(),
+            AllocatedRepeatedPtrFieldBackInserter(
+                testproto.mutable_repeated_string()));
+  EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest,
+       UnsafeArenaAllocatedRepeatedPtrFieldWithStringIntData) {
+  std::vector<Nested*> data;
+  Arena arena;
+  auto* goldenproto = Arena::CreateMessage<TestAllTypes>(&arena);
+  for (int i = 0; i < 10; ++i) {
+    auto* new_data = goldenproto->add_repeated_nested_message();
+    new_data->set_bb(i);
+    data.push_back(new_data);
+  }
+  auto* testproto = Arena::CreateMessage<TestAllTypes>(&arena);
+  std::copy(data.begin(), data.end(),
+            UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+                testproto->mutable_repeated_nested_message()));
+  EXPECT_EQ(testproto->DebugString(), goldenproto->DebugString());
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest,
+       UnsafeArenaAllocatedRepeatedPtrFieldWithString) {
+  std::vector<std::string*> data;
+  Arena arena;
+  auto* goldenproto = Arena::CreateMessage<TestAllTypes>(&arena);
+  for (int i = 0; i < 10; ++i) {
+    auto* new_data = goldenproto->add_repeated_string();
+    *new_data = "name-" + StrCat(i);
+    data.push_back(new_data);
+  }
+  auto* testproto = Arena::CreateMessage<TestAllTypes>(&arena);
+  std::copy(data.begin(), data.end(),
+            UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+                testproto->mutable_repeated_string()));
+  EXPECT_EQ(testproto->DebugString(), goldenproto->DebugString());
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, MoveStrings) {
+  std::vector<std::string> src = {"a", "b", "c", "d"};
+  std::vector<std::string> copy =
+      src;  // copy since move leaves in undefined state
+  TestAllTypes testproto;
+  std::move(copy.begin(), copy.end(),
+            RepeatedFieldBackInserter(testproto.mutable_repeated_string()));
+
+  ASSERT_THAT(testproto.repeated_string(), testing::ElementsAreArray(src));
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest, MoveProtos) {
+  auto make_nested = [](int32_t x) {
+    Nested ret;
+    ret.set_bb(x);
+    return ret;
+  };
+  std::vector<Nested> src = {make_nested(3), make_nested(5), make_nested(7)};
+  std::vector<Nested> copy = src;  // copy since move leaves in undefined state
+  TestAllTypes testproto;
+  std::move(
+      copy.begin(), copy.end(),
+      RepeatedFieldBackInserter(testproto.mutable_repeated_nested_message()));
+
+  ASSERT_EQ(src.size(), testproto.repeated_nested_message_size());
+  for (int i = 0; i < src.size(); ++i) {
+    EXPECT_EQ(src[i].DebugString(),
+              testproto.repeated_nested_message(i).DebugString());
+  }
+}
+
+}  // namespace
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/repeated_ptr_field.cc b/src/google/protobuf/repeated_ptr_field.cc
new file mode 100644
index 0000000..8e86727
--- /dev/null
+++ b/src/google/protobuf/repeated_ptr_field.cc
@@ -0,0 +1,152 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
+  int new_size = current_size_ + extend_amount;
+  if (total_size_ >= new_size) {
+    // N.B.: rep_ is non-nullptr because extend_amount is always > 0, hence
+    // total_size must be non-zero since it is lower-bounded by new_size.
+    return &rep_->elements[current_size_];
+  }
+  Rep* old_rep = rep_;
+  Arena* arena = GetOwningArena();
+  new_size = internal::CalculateReserveSize<void*, kRepHeaderSize>(total_size_,
+                                                                   new_size);
+  GOOGLE_CHECK_LE(static_cast<int64_t>(new_size),
+           static_cast<int64_t>(
+               (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
+               sizeof(old_rep->elements[0])))
+      << "Requested size is too large to fit into size_t.";
+  size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size;
+  if (arena == nullptr) {
+    rep_ = reinterpret_cast<Rep*>(::operator new(bytes));
+  } else {
+    rep_ = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
+  }
+  const int old_total_size = total_size_;
+  total_size_ = new_size;
+  if (old_rep) {
+    if (old_rep->allocated_size > 0) {
+      memcpy(rep_->elements, old_rep->elements,
+             old_rep->allocated_size * sizeof(rep_->elements[0]));
+    }
+    rep_->allocated_size = old_rep->allocated_size;
+
+    const size_t old_size =
+        old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize;
+    if (arena == nullptr) {
+      internal::SizedDelete(old_rep, old_size);
+    } else {
+      arena_->ReturnArrayMemory(old_rep, old_size);
+    }
+  } else {
+    rep_->allocated_size = 0;
+  }
+  return &rep_->elements[current_size_];
+}
+
+void RepeatedPtrFieldBase::Reserve(int new_size) {
+  if (new_size > current_size_) {
+    InternalExtend(new_size - current_size_);
+  }
+}
+
+void RepeatedPtrFieldBase::DestroyProtos() {
+  GOOGLE_DCHECK(rep_);
+  GOOGLE_DCHECK(arena_ == nullptr);
+  int n = rep_->allocated_size;
+  void* const* elements = rep_->elements;
+  for (int i = 0; i < n; i++) {
+    delete static_cast<MessageLite*>(elements[i]);
+  }
+  const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
+  internal::SizedDelete(rep_, size);
+  rep_ = nullptr;
+}
+
+void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) {
+  if (!rep_ || rep_->allocated_size == total_size_) {
+    InternalExtend(1);  // Equivalent to "Reserve(total_size_ + 1)"
+  }
+  ++rep_->allocated_size;
+  rep_->elements[current_size_++] = obj;
+  return obj;
+}
+
+void RepeatedPtrFieldBase::CloseGap(int start, int num) {
+  if (rep_ == nullptr) return;
+  // Close up a gap of "num" elements starting at offset "start".
+  for (int i = start + num; i < rep_->allocated_size; ++i)
+    rep_->elements[i - num] = rep_->elements[i];
+  current_size_ -= num;
+  rep_->allocated_size -= num;
+}
+
+MessageLite* RepeatedPtrFieldBase::AddWeak(const MessageLite* prototype) {
+  if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+    return reinterpret_cast<MessageLite*>(rep_->elements[current_size_++]);
+  }
+  if (!rep_ || rep_->allocated_size == total_size_) {
+    Reserve(total_size_ + 1);
+  }
+  ++rep_->allocated_size;
+  MessageLite* result = prototype
+                            ? prototype->New(arena_)
+                            : Arena::CreateMessage<ImplicitWeakMessage>(arena_);
+  rep_->elements[current_size_++] = result;
+  return result;
+}
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h
new file mode 100644
index 0000000..401230b
--- /dev/null
+++ b/src/google/protobuf/repeated_ptr_field.h
@@ -0,0 +1,1970 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// RepeatedField and RepeatedPtrField are used by generated protocol message
+// classes to manipulate repeated fields.  These classes are very similar to
+// STL's vector, but include a number of optimizations found to be useful
+// specifically in the case of Protocol Buffers.  RepeatedPtrField is
+// particularly different from STL vector as it manages ownership of the
+// pointers that it contains.
+//
+// This header covers RepeatedPtrField.
+
+// IWYU pragma: private, include "net/proto2/public/repeated_field.h"
+
+#ifndef GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
+#define GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
+
+#include <utility>
+
+#ifdef _MSC_VER
+// This is required for min/max on VS2013 only.
+#include <algorithm>
+#endif
+
+#include <iterator>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class Reflection;
+
+template <typename T>
+struct WeakRepeatedPtrField;
+
+namespace internal {
+
+class MergePartialFromCodedStreamHelper;
+class SwapFieldHelper;
+
+
+}  // namespace internal
+
+namespace internal {
+template <typename It>
+class RepeatedPtrIterator;
+template <typename It, typename VoidPtr>
+class RepeatedPtrOverPtrsIterator;
+}  // namespace internal
+
+namespace internal {
+
+// type-traits helper for RepeatedPtrFieldBase: we only want to invoke
+// arena-related "copy if on different arena" behavior if the necessary methods
+// exist on the contained type. In particular, we rely on MergeFrom() existing
+// as a general proxy for the fact that a copy will work, and we also provide a
+// specific override for std::string*.
+template <typename T>
+struct TypeImplementsMergeBehaviorProbeForMergeFrom {
+  typedef char HasMerge;
+  typedef long HasNoMerge;
+
+  // We accept either of:
+  // - void MergeFrom(const T& other)
+  // - bool MergeFrom(const T& other)
+  //
+  // We mangle these names a bit to avoid compatibility issues in 'unclean'
+  // include environments that may have, e.g., "#define test ..." (yes, this
+  // exists).
+  template <typename U, typename RetType, RetType (U::*)(const U& arg)>
+  struct CheckType;
+  template <typename U>
+  static HasMerge Check(CheckType<U, void, &U::MergeFrom>*);
+  template <typename U>
+  static HasMerge Check(CheckType<U, bool, &U::MergeFrom>*);
+  template <typename U>
+  static HasNoMerge Check(...);
+
+  // Resolves to either std::true_type or std::false_type.
+  typedef std::integral_constant<bool,
+                                 (sizeof(Check<T>(0)) == sizeof(HasMerge))>
+      type;
+};
+
+template <typename T, typename = void>
+struct TypeImplementsMergeBehavior
+    : TypeImplementsMergeBehaviorProbeForMergeFrom<T> {};
+
+
+template <>
+struct TypeImplementsMergeBehavior<std::string> {
+  typedef std::true_type type;
+};
+
+template <typename T>
+struct IsMovable
+    : std::integral_constant<bool, std::is_move_constructible<T>::value &&
+                                       std::is_move_assignable<T>::value> {};
+
+// This is the common base class for RepeatedPtrFields.  It deals only in void*
+// pointers.  Users should not use this interface directly.
+//
+// The methods of this interface correspond to the methods of RepeatedPtrField,
+// but may have a template argument called TypeHandler.  Its signature is:
+//   class TypeHandler {
+//    public:
+//     typedef MyType Type;
+//     static Type* New();
+//     static Type* NewFromPrototype(const Type* prototype,
+//                                       Arena* arena);
+//     static void Delete(Type*);
+//     static void Clear(Type*);
+//     static void Merge(const Type& from, Type* to);
+//
+//     // Only needs to be implemented if SpaceUsedExcludingSelf() is called.
+//     static int SpaceUsedLong(const Type&);
+//   };
+class PROTOBUF_EXPORT RepeatedPtrFieldBase {
+ protected:
+  constexpr RepeatedPtrFieldBase()
+      : arena_(nullptr), current_size_(0), total_size_(0), rep_(nullptr) {}
+  explicit RepeatedPtrFieldBase(Arena* arena)
+      : arena_(arena), current_size_(0), total_size_(0), rep_(nullptr) {}
+
+  RepeatedPtrFieldBase(const RepeatedPtrFieldBase&) = delete;
+  RepeatedPtrFieldBase& operator=(const RepeatedPtrFieldBase&) = delete;
+
+  ~RepeatedPtrFieldBase() {
+#ifndef NDEBUG
+    // Try to trigger segfault / asan failure in non-opt builds. If arena_
+    // lifetime has ended before the destructor.
+    if (arena_) (void)arena_->SpaceAllocated();
+#endif
+  }
+
+  bool empty() const { return current_size_ == 0; }
+  int size() const { return current_size_; }
+  int Capacity() const { return total_size_; }
+
+  template <typename TypeHandler>
+  const typename TypeHandler::Type& at(int index) const {
+    GOOGLE_CHECK_GE(index, 0);
+    GOOGLE_CHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type& at(int index) {
+    GOOGLE_CHECK_GE(index, 0);
+    GOOGLE_CHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* Mutable(int index) {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    return cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* Add(
+      const typename TypeHandler::Type* prototype = nullptr) {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      return cast<TypeHandler>(rep_->elements[current_size_++]);
+    }
+    typename TypeHandler::Type* result =
+        TypeHandler::NewFromPrototype(prototype, arena_);
+    return reinterpret_cast<typename TypeHandler::Type*>(
+        AddOutOfLineHelper(result));
+  }
+
+  template <
+      typename TypeHandler,
+      typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr>
+  inline void Add(typename TypeHandler::Type&& value) {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      *cast<TypeHandler>(rep_->elements[current_size_++]) = std::move(value);
+      return;
+    }
+    if (!rep_ || rep_->allocated_size == total_size_) {
+      Reserve(total_size_ + 1);
+    }
+    ++rep_->allocated_size;
+    typename TypeHandler::Type* result =
+        TypeHandler::New(arena_, std::move(value));
+    rep_->elements[current_size_++] = result;
+  }
+
+  template <typename TypeHandler>
+  void Delete(int index) {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    TypeHandler::Delete(cast<TypeHandler>(rep_->elements[index]), arena_);
+  }
+
+  // Must be called from destructor.
+  template <typename TypeHandler>
+  void Destroy() {
+    if (rep_ != nullptr && arena_ == nullptr) {
+      int n = rep_->allocated_size;
+      void* const* elements = rep_->elements;
+      for (int i = 0; i < n; i++) {
+        TypeHandler::Delete(cast<TypeHandler>(elements[i]), nullptr);
+      }
+      const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
+      internal::SizedDelete(rep_, size);
+    }
+    rep_ = nullptr;
+  }
+
+  bool NeedsDestroy() const { return rep_ != nullptr && arena_ == nullptr; }
+  void DestroyProtos();  // implemented in the cc file
+
+ public:
+  // The next few methods are public so that they can be called from generated
+  // code when implicit weak fields are used, but they should never be called by
+  // application code.
+
+  template <typename TypeHandler>
+  const typename TypeHandler::Type& Get(int index) const {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  // Creates and adds an element using the given prototype, without introducing
+  // a link-time dependency on the concrete message type. This method is used to
+  // implement implicit weak fields. The prototype may be nullptr, in which case
+  // an ImplicitWeakMessage will be used as a placeholder.
+  MessageLite* AddWeak(const MessageLite* prototype);
+
+  template <typename TypeHandler>
+  void Clear() {
+    const int n = current_size_;
+    GOOGLE_DCHECK_GE(n, 0);
+    if (n > 0) {
+      void* const* elements = rep_->elements;
+      int i = 0;
+      do {
+        TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
+      } while (i < n);
+      current_size_ = 0;
+    }
+  }
+
+  template <typename TypeHandler>
+  void MergeFrom(const RepeatedPtrFieldBase& other) {
+    // To avoid unnecessary code duplication and reduce binary size, we use a
+    // layered approach to implementing MergeFrom(). The toplevel method is
+    // templated, so we get a small thunk per concrete message type in the
+    // binary. This calls a shared implementation with most of the logic,
+    // passing a function pointer to another type-specific piece of code that
+    // calls the object-allocate and merge handlers.
+    GOOGLE_DCHECK_NE(&other, this);
+    if (other.current_size_ == 0) return;
+    MergeFromInternal(other,
+                      &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
+  }
+
+  inline void InternalSwap(RepeatedPtrFieldBase* rhs) {
+    GOOGLE_DCHECK(this != rhs);
+
+    // Swap all fields at once.
+    auto temp = std::make_tuple(rhs->arena_, rhs->current_size_,
+                                rhs->total_size_, rhs->rep_);
+    std::tie(rhs->arena_, rhs->current_size_, rhs->total_size_, rhs->rep_) =
+        std::make_tuple(arena_, current_size_, total_size_, rep_);
+    std::tie(arena_, current_size_, total_size_, rep_) = temp;
+  }
+
+ protected:
+  template <typename TypeHandler>
+  void RemoveLast() {
+    GOOGLE_DCHECK_GT(current_size_, 0);
+    TypeHandler::Clear(cast<TypeHandler>(rep_->elements[--current_size_]));
+  }
+
+  template <typename TypeHandler>
+  void CopyFrom(const RepeatedPtrFieldBase& other) {
+    if (&other == this) return;
+    RepeatedPtrFieldBase::Clear<TypeHandler>();
+    RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
+  }
+
+  void CloseGap(int start, int num);  // implemented in the cc file
+
+  void Reserve(int new_size);  // implemented in the cc file
+
+  template <typename TypeHandler>
+  static inline typename TypeHandler::Type* copy(
+      typename TypeHandler::Type* value) {
+    auto* new_value = TypeHandler::NewFromPrototype(value, nullptr);
+    TypeHandler::Merge(*value, new_value);
+    return new_value;
+  }
+
+  // Used for constructing iterators.
+  void* const* raw_data() const { return rep_ ? rep_->elements : nullptr; }
+  void** raw_mutable_data() const {
+    return rep_ ? const_cast<void**>(rep_->elements) : nullptr;
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type** mutable_data() {
+    // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
+    //   method entirely.
+    return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
+  }
+
+  template <typename TypeHandler>
+  const typename TypeHandler::Type* const* data() const {
+    // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
+    //   method entirely.
+    return reinterpret_cast<const typename TypeHandler::Type* const*>(
+        raw_data());
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NDEBUG_INLINE void Swap(RepeatedPtrFieldBase* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena())
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena())
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    {
+      InternalSwap(other);
+    } else {
+      SwapFallback<TypeHandler>(other);
+    }
+  }
+
+  void SwapElements(int index1, int index2) {
+    using std::swap;  // enable ADL with fallback
+    swap(rep_->elements[index1], rep_->elements[index2]);
+  }
+
+  template <typename TypeHandler>
+  size_t SpaceUsedExcludingSelfLong() const {
+    size_t allocated_bytes = static_cast<size_t>(total_size_) * sizeof(void*);
+    if (rep_ != nullptr) {
+      for (int i = 0; i < rep_->allocated_size; ++i) {
+        allocated_bytes +=
+            TypeHandler::SpaceUsedLong(*cast<TypeHandler>(rep_->elements[i]));
+      }
+      allocated_bytes += kRepHeaderSize;
+    }
+    return allocated_bytes;
+  }
+
+  // Advanced memory management --------------------------------------
+
+  // Like Add(), but if there are no cleared objects to use, returns nullptr.
+  template <typename TypeHandler>
+  typename TypeHandler::Type* AddFromCleared() {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      return cast<TypeHandler>(rep_->elements[current_size_++]);
+    } else {
+      return nullptr;
+    }
+  }
+
+  template <typename TypeHandler>
+  void AddAllocated(typename TypeHandler::Type* value) {
+    typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+    AddAllocatedInternal<TypeHandler>(value, t);
+  }
+
+  template <typename TypeHandler>
+  void UnsafeArenaAddAllocated(typename TypeHandler::Type* value) {
+    // Make room for the new pointer.
+    if (!rep_ || current_size_ == total_size_) {
+      // The array is completely full with no cleared objects, so grow it.
+      Reserve(total_size_ + 1);
+      ++rep_->allocated_size;
+    } else if (rep_->allocated_size == total_size_) {
+      // There is no more space in the pointer array because it contains some
+      // cleared objects awaiting reuse.  We don't want to grow the array in
+      // this case because otherwise a loop calling AddAllocated() followed by
+      // Clear() would leak memory.
+      TypeHandler::Delete(cast<TypeHandler>(rep_->elements[current_size_]),
+                          arena_);
+    } else if (current_size_ < rep_->allocated_size) {
+      // We have some cleared objects.  We don't care about their order, so we
+      // can just move the first one to the end to make space.
+      rep_->elements[rep_->allocated_size] = rep_->elements[current_size_];
+      ++rep_->allocated_size;
+    } else {
+      // There are no cleared objects.
+      ++rep_->allocated_size;
+    }
+
+    rep_->elements[current_size_++] = value;
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseLast() {
+    typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+    return ReleaseLastInternal<TypeHandler>(t);
+  }
+
+  // Releases and returns the last element, but does not do out-of-arena copy.
+  // Instead, just returns the raw pointer to the contained element in the
+  // arena.
+  template <typename TypeHandler>
+  typename TypeHandler::Type* UnsafeArenaReleaseLast() {
+    GOOGLE_DCHECK_GT(current_size_, 0);
+    typename TypeHandler::Type* result =
+        cast<TypeHandler>(rep_->elements[--current_size_]);
+    --rep_->allocated_size;
+    if (current_size_ < rep_->allocated_size) {
+      // There are cleared elements on the end; replace the removed element
+      // with the last allocated element.
+      rep_->elements[current_size_] = rep_->elements[rep_->allocated_size];
+    }
+    return result;
+  }
+
+  int ClearedCount() const {
+    return rep_ ? (rep_->allocated_size - current_size_) : 0;
+  }
+
+  template <typename TypeHandler>
+  void AddCleared(typename TypeHandler::Type* value) {
+    GOOGLE_DCHECK(GetOwningArena() == nullptr) << "AddCleared() can only be used on a "
+                                           "RepeatedPtrField not on an arena.";
+    GOOGLE_DCHECK(TypeHandler::GetOwningArena(value) == nullptr)
+        << "AddCleared() can only accept values not on an arena.";
+    if (!rep_ || rep_->allocated_size == total_size_) {
+      Reserve(total_size_ + 1);
+    }
+    rep_->elements[rep_->allocated_size++] = value;
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared() {
+    GOOGLE_DCHECK(GetOwningArena() == nullptr)
+        << "ReleaseCleared() can only be used on a RepeatedPtrField not on "
+        << "an arena.";
+    GOOGLE_DCHECK(GetOwningArena() == nullptr);
+    GOOGLE_DCHECK(rep_ != nullptr);
+    GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_);
+    return cast<TypeHandler>(rep_->elements[--rep_->allocated_size]);
+  }
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type) {
+    // AddAllocated version that implements arena-safe copying behavior.
+    Arena* element_arena =
+        reinterpret_cast<Arena*>(TypeHandler::GetOwningArena(value));
+    Arena* arena = GetOwningArena();
+    if (arena == element_arena && rep_ && rep_->allocated_size < total_size_) {
+      // Fast path: underlying arena representation (tagged pointer) is equal to
+      // our arena pointer, and we can add to array without resizing it (at
+      // least one slot that is not allocated).
+      void** elems = rep_->elements;
+      if (current_size_ < rep_->allocated_size) {
+        // Make space at [current] by moving first allocated element to end of
+        // allocated list.
+        elems[rep_->allocated_size] = elems[current_size_];
+      }
+      elems[current_size_] = value;
+      current_size_ = current_size_ + 1;
+      rep_->allocated_size = rep_->allocated_size + 1;
+    } else {
+      AddAllocatedSlowWithCopy<TypeHandler>(value, element_arena, arena);
+    }
+  }
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(
+      // AddAllocated version that does not implement arena-safe copying
+      // behavior.
+      typename TypeHandler::Type* value, std::false_type) {
+    if (rep_ && rep_->allocated_size < total_size_) {
+      // Fast path: underlying arena representation (tagged pointer) is equal to
+      // our arena pointer, and we can add to array without resizing it (at
+      // least one slot that is not allocated).
+      void** elems = rep_->elements;
+      if (current_size_ < rep_->allocated_size) {
+        // Make space at [current] by moving first allocated element to end of
+        // allocated list.
+        elems[rep_->allocated_size] = elems[current_size_];
+      }
+      elems[current_size_] = value;
+      current_size_ = current_size_ + 1;
+      ++rep_->allocated_size;
+    } else {
+      UnsafeArenaAddAllocated<TypeHandler>(value);
+    }
+  }
+
+  // Slowpath handles all cases, copying if necessary.
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy(
+      // Pass value_arena and my_arena to avoid duplicate virtual call (value)
+      // or load (mine).
+      typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
+    // Ensure that either the value is in the same arena, or if not, we do the
+    // appropriate thing: Own() it (if it's on heap and we're in an arena) or
+    // copy it to our arena/heap (otherwise).
+    if (my_arena != nullptr && value_arena == nullptr) {
+      my_arena->Own(value);
+    } else if (my_arena != value_arena) {
+      typename TypeHandler::Type* new_value =
+          TypeHandler::NewFromPrototype(value, my_arena);
+      TypeHandler::Merge(*value, new_value);
+      TypeHandler::Delete(value, value_arena);
+      value = new_value;
+    }
+
+    UnsafeArenaAddAllocated<TypeHandler>(value);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* ReleaseLastInternal(std::true_type) {
+    // ReleaseLast() for types that implement merge/copy behavior.
+    // First, release an element.
+    typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
+    // Now perform a copy if we're on an arena.
+    Arena* arena = GetOwningArena();
+
+    typename TypeHandler::Type* new_result;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+    new_result = copy<TypeHandler>(result);
+    if (arena == nullptr) delete result;
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+    new_result = (arena == nullptr) ? result : copy<TypeHandler>(result);
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+    return new_result;
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* ReleaseLastInternal(std::false_type) {
+    // ReleaseLast() for types that *do not* implement merge/copy behavior --
+    // this is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if
+    // we're on an arena, since the user really should implement the copy
+    // operation in this case.
+    GOOGLE_DCHECK(GetOwningArena() == nullptr)
+        << "ReleaseLast() called on a RepeatedPtrField that is on an arena, "
+        << "with a type that does not implement MergeFrom. This is unsafe; "
+        << "please implement MergeFrom for your type.";
+    return UnsafeArenaReleaseLast<TypeHandler>();
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    GOOGLE_DCHECK(GetOwningArena() == nullptr ||
+           other->GetOwningArena() != GetOwningArena());
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    GOOGLE_DCHECK(other->GetOwningArena() != GetOwningArena());
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+
+    // Copy semantics in this case. We try to improve efficiency by placing the
+    // temporary on |other|'s arena so that messages are copied twice rather
+    // than three times.
+    RepeatedPtrFieldBase temp(other->GetOwningArena());
+    temp.MergeFrom<TypeHandler>(*this);
+    this->Clear<TypeHandler>();
+    this->MergeFrom<TypeHandler>(*other);
+    other->InternalSwap(&temp);
+    temp.Destroy<TypeHandler>();  // Frees rep_ if `other` had no arena.
+  }
+
+  inline Arena* GetArena() const { return arena_; }
+
+ protected:
+  inline Arena* GetOwningArena() const { return arena_; }
+
+ private:
+  template <typename T> friend class Arena::InternalHelper;
+
+  static constexpr int kInitialSize = 0;
+  // A few notes on internal representation:
+  //
+  // We use an indirected approach, with struct Rep, to keep
+  // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support
+  // was added; namely, 3 8-byte machine words on x86-64. An instance of Rep is
+  // allocated only when the repeated field is non-empty, and it is a
+  // dynamically-sized struct (the header is directly followed by elements[]).
+  // We place arena_ and current_size_ directly in the object to avoid cache
+  // misses due to the indirection, because these fields are checked frequently.
+  // Placing all fields directly in the RepeatedPtrFieldBase instance would cost
+  // significant performance for memory-sensitive workloads.
+  Arena* arena_;
+  int current_size_;
+  int total_size_;
+  struct Rep {
+    int allocated_size;
+    // Here we declare a huge array as a way of approximating C's "flexible
+    // array member" feature without relying on undefined behavior.
+    void* elements[(std::numeric_limits<int>::max() - 2 * sizeof(int)) /
+                   sizeof(void*)];
+  };
+  static constexpr size_t kRepHeaderSize = offsetof(Rep, elements);
+  Rep* rep_;
+
+  template <typename TypeHandler>
+  static inline typename TypeHandler::Type* cast(void* element) {
+    return reinterpret_cast<typename TypeHandler::Type*>(element);
+  }
+  template <typename TypeHandler>
+  static inline const typename TypeHandler::Type* cast(const void* element) {
+    return reinterpret_cast<const typename TypeHandler::Type*>(element);
+  }
+
+  // Non-templated inner function to avoid code duplication. Takes a function
+  // pointer to the type-specific (templated) inner allocate/merge loop.
+  void MergeFromInternal(const RepeatedPtrFieldBase& other,
+                         void (RepeatedPtrFieldBase::*inner_loop)(void**,
+                                                                  void**, int,
+                                                                  int)) {
+    // Note: wrapper has already guaranteed that other.rep_ != nullptr here.
+    int other_size = other.current_size_;
+    void** other_elements = other.rep_->elements;
+    void** new_elements = InternalExtend(other_size);
+    int allocated_elems = rep_->allocated_size - current_size_;
+    (this->*inner_loop)(new_elements, other_elements, other_size,
+                        allocated_elems);
+    current_size_ += other_size;
+    if (rep_->allocated_size < current_size_) {
+      rep_->allocated_size = current_size_;
+    }
+  }
+
+  // Merges other_elems to our_elems.
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void MergeFromInnerLoop(void** our_elems,
+                                            void** other_elems, int length,
+                                            int already_allocated) {
+    if (already_allocated < length) {
+      Arena* arena = GetOwningArena();
+      typename TypeHandler::Type* elem_prototype =
+          reinterpret_cast<typename TypeHandler::Type*>(other_elems[0]);
+      for (int i = already_allocated; i < length; i++) {
+        // Allocate a new empty element that we'll merge into below
+        typename TypeHandler::Type* new_elem =
+            TypeHandler::NewFromPrototype(elem_prototype, arena);
+        our_elems[i] = new_elem;
+      }
+    }
+    // Main loop that does the actual merging
+    for (int i = 0; i < length; i++) {
+      // Already allocated: use existing element.
+      typename TypeHandler::Type* other_elem =
+          reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
+      typename TypeHandler::Type* new_elem =
+          reinterpret_cast<typename TypeHandler::Type*>(our_elems[i]);
+      TypeHandler::Merge(*other_elem, new_elem);
+    }
+  }
+
+  // Internal helper: extends array space if necessary to contain
+  // |extend_amount| more elements, and returns a pointer to the element
+  // immediately following the old list of elements.  This interface factors out
+  // common behavior from Reserve() and MergeFrom() to reduce code size.
+  // |extend_amount| must be > 0.
+  void** InternalExtend(int extend_amount);
+
+  // Internal helper for Add: adds "obj" as the next element in the
+  // array, including potentially resizing the array with Reserve if
+  // needed
+  void* AddOutOfLineHelper(void* obj);
+
+  // The reflection implementation needs to call protected methods directly,
+  // reinterpreting pointers as being to Message instead of a specific Message
+  // subclass.
+  friend class ::PROTOBUF_NAMESPACE_ID::Reflection;
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::SwapFieldHelper;
+
+  // ExtensionSet stores repeated message extensions as
+  // RepeatedPtrField<MessageLite>, but non-lite ExtensionSets need to implement
+  // SpaceUsedLong(), and thus need to call SpaceUsedExcludingSelfLong()
+  // reinterpreting MessageLite as Message.  ExtensionSet also needs to make use
+  // of AddFromCleared(), which is not part of the public interface.
+  friend class ExtensionSet;
+
+  // The MapFieldBase implementation needs to call protected methods directly,
+  // reinterpreting pointers as being to Message instead of a specific Message
+  // subclass.
+  friend class MapFieldBase;
+  friend class MapFieldBaseStub;
+
+  // The table-driven MergePartialFromCodedStream implementation needs to
+  // operate on RepeatedPtrField<MessageLite>.
+  friend class MergePartialFromCodedStreamHelper;
+  friend class AccessorHelper;
+  template <typename T>
+  friend struct google::protobuf::WeakRepeatedPtrField;
+  friend class internal::TcParser;  // TODO(jorg): Remove this friend.
+};
+
+template <typename GenericType>
+class GenericTypeHandler {
+ public:
+  typedef GenericType Type;
+  using Movable = IsMovable<GenericType>;
+
+  static inline GenericType* New(Arena* arena) {
+    return Arena::CreateMaybeMessage<Type>(arena);
+  }
+  static inline GenericType* New(Arena* arena, GenericType&& value) {
+    return Arena::Create<GenericType>(arena, std::move(value));
+  }
+  static inline GenericType* NewFromPrototype(const GenericType* /*prototype*/,
+                                              Arena* arena = nullptr) {
+    return New(arena);
+  }
+  static inline void Delete(GenericType* value, Arena* arena) {
+    if (arena == nullptr) {
+      delete value;
+    }
+  }
+  static inline Arena* GetOwningArena(GenericType* value) {
+    return Arena::GetOwningArena<Type>(value);
+  }
+
+  static inline void Clear(GenericType* value) { value->Clear(); }
+  static void Merge(const GenericType& from, GenericType* to);
+  static inline size_t SpaceUsedLong(const GenericType& value) {
+    return value.SpaceUsedLong();
+  }
+};
+
+// NewFromPrototypeHelper() is not defined inline here, as we will need to do a
+// virtual function dispatch anyways to go from Message* to call New/Merge. (The
+// additional helper is needed as a workaround for MSVC.)
+MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, Arena* arena);
+
+template <>
+inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
+    const MessageLite* prototype, Arena* arena) {
+  return NewFromPrototypeHelper(prototype, arena);
+}
+template <>
+inline Arena* GenericTypeHandler<MessageLite>::GetOwningArena(
+    MessageLite* value) {
+  return value->GetOwningArena();
+}
+
+template <typename GenericType>
+PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
+    const GenericType& from, GenericType* to) {
+  to->MergeFrom(from);
+}
+template <>
+void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
+                                            MessageLite* to);
+
+template <>
+inline void GenericTypeHandler<std::string>::Clear(std::string* value) {
+  value->clear();
+}
+template <>
+void GenericTypeHandler<std::string>::Merge(const std::string& from,
+                                            std::string* to);
+
+// Message specialization bodies defined in message.cc. This split is necessary
+// to allow proto2-lite (which includes this header) to be independent of
+// Message.
+template <>
+PROTOBUF_EXPORT Message* GenericTypeHandler<Message>::NewFromPrototype(
+    const Message* prototype, Arena* arena);
+template <>
+PROTOBUF_EXPORT Arena* GenericTypeHandler<Message>::GetOwningArena(
+    Message* value);
+
+class StringTypeHandler {
+ public:
+  typedef std::string Type;
+  using Movable = IsMovable<Type>;
+
+  static inline std::string* New(Arena* arena) {
+    return Arena::Create<std::string>(arena);
+  }
+  static inline std::string* New(Arena* arena, std::string&& value) {
+    return Arena::Create<std::string>(arena, std::move(value));
+  }
+  static inline std::string* NewFromPrototype(const std::string*,
+                                              Arena* arena) {
+    return New(arena);
+  }
+  static inline Arena* GetOwningArena(std::string*) { return nullptr; }
+  static inline void Delete(std::string* value, Arena* arena) {
+    if (arena == nullptr) {
+      delete value;
+    }
+  }
+  static inline void Clear(std::string* value) { value->clear(); }
+  static inline void Merge(const std::string& from, std::string* to) {
+    *to = from;
+  }
+  static size_t SpaceUsedLong(const std::string& value) {
+    return sizeof(value) + StringSpaceUsedExcludingSelfLong(value);
+  }
+};
+
+}  // namespace internal
+
+// RepeatedPtrField is like RepeatedField, but used for repeated strings or
+// Messages.
+template <typename Element>
+class RepeatedPtrField final : private internal::RepeatedPtrFieldBase {
+
+ public:
+  constexpr RepeatedPtrField();
+  explicit RepeatedPtrField(Arena* arena);
+
+  RepeatedPtrField(const RepeatedPtrField& other);
+
+  template <typename Iter,
+            typename = typename std::enable_if<std::is_constructible<
+                Element, decltype(*std::declval<Iter>())>::value>::type>
+  RepeatedPtrField(Iter begin, Iter end);
+
+  ~RepeatedPtrField();
+
+  RepeatedPtrField& operator=(const RepeatedPtrField& other);
+
+  RepeatedPtrField(RepeatedPtrField&& other) noexcept;
+  RepeatedPtrField& operator=(RepeatedPtrField&& other) noexcept;
+
+  bool empty() const;
+  int size() const;
+
+  const Element& Get(int index) const;
+  Element* Mutable(int index);
+
+  // Unlike std::vector, adding an element to a RepeatedPtrField doesn't always
+  // make a new element; it might re-use an element left over from when the
+  // field was Clear()'d or reize()'d smaller.  For this reason, Add() is the
+  // fastest API for adding a new element.
+  Element* Add();
+
+  // `Add(std::move(value));` is equivalent to `*Add() = std::move(value);`
+  // It will either move-construct to the end of this field, or swap value
+  // with the new-or-recycled element at the end of this field.  Note that
+  // this operation is very slow if this RepeatedPtrField is not on the
+  // same Arena, if any, as `value`.
+  void Add(Element&& value);
+
+  // Copying to the end of this RepeatedPtrField is slowest of all; it can't
+  // reliably copy-construct to the last element of this RepeatedPtrField, for
+  // example (unlike std::vector).
+  // We currently block this API.  The right way to add to the end is to call
+  // Add() and modify the element it points to.
+  // If you must add an existing value, call `*Add() = value;`
+  void Add(const Element& value) = delete;
+
+  // Append elements in the range [begin, end) after reserving
+  // the appropriate number of elements.
+  template <typename Iter>
+  void Add(Iter begin, Iter end);
+
+  const Element& operator[](int index) const { return Get(index); }
+  Element& operator[](int index) { return *Mutable(index); }
+
+  const Element& at(int index) const;
+  Element& at(int index);
+
+  // Removes the last element in the array.
+  // Ownership of the element is retained by the array.
+  void RemoveLast();
+
+  // Deletes elements with indices in the range [start .. start+num-1].
+  // Caution: moves all elements with indices [start+num .. ].
+  // Calling this routine inside a loop can cause quadratic behavior.
+  void DeleteSubrange(int start, int num);
+
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear();
+  void MergeFrom(const RepeatedPtrField& other);
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void CopyFrom(const RepeatedPtrField& other);
+
+  // Replaces the contents with RepeatedPtrField(begin, end).
+  template <typename Iter>
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end);
+
+  // Reserves space to expand the field to at least the given size.  This only
+  // resizes the pointer array; it doesn't allocate any objects.  If the
+  // array is grown, it will always be at least doubled in size.
+  void Reserve(int new_size);
+
+  int Capacity() const;
+
+  // Gets the underlying array.  This pointer is possibly invalidated by
+  // any add or remove operation.
+  //
+  // This API is deprecated. Instead of directly working with element array,
+  // use APIs in repeated_field_util.h; e.g. sorting, etc.
+  PROTOBUF_DEPRECATED_MSG("Use APIs in repeated_field_util.h")
+  Element** mutable_data();
+  const Element* const* data() const;
+
+  // Swaps entire contents with "other". If they are on separate arenas, then
+  // copies data.
+  void Swap(RepeatedPtrField* other);
+
+  // Swaps entire contents with "other". Caller should guarantee that either
+  // both fields are on the same arena or both are on the heap. Swapping between
+  // different arenas with this function is disallowed and is caught via
+  // GOOGLE_DCHECK.
+  void UnsafeArenaSwap(RepeatedPtrField* other);
+
+  // Swaps two elements.
+  void SwapElements(int index1, int index2);
+
+  // STL-like iterator support
+  typedef internal::RepeatedPtrIterator<Element> iterator;
+  typedef internal::RepeatedPtrIterator<const Element> const_iterator;
+  typedef Element value_type;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin();
+  const_iterator begin() const;
+  const_iterator cbegin() const;
+  iterator end();
+  const_iterator end() const;
+  const_iterator cend() const;
+
+  // Reverse iterator support
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef std::reverse_iterator<iterator> reverse_iterator;
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // Custom STL-like iterator that iterates over and returns the underlying
+  // pointers to Element rather than Element itself.
+  typedef internal::RepeatedPtrOverPtrsIterator<Element*, void*>
+      pointer_iterator;
+  typedef internal::RepeatedPtrOverPtrsIterator<const Element* const,
+                                                const void* const>
+      const_pointer_iterator;
+  pointer_iterator pointer_begin();
+  const_pointer_iterator pointer_begin() const;
+  pointer_iterator pointer_end();
+  const_pointer_iterator pointer_end() const;
+
+  // Returns (an estimate of) the number of bytes used by the repeated field,
+  // excluding sizeof(*this).
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+  // Advanced memory management --------------------------------------
+  // When hardcore memory management becomes necessary -- as it sometimes
+  // does here at Google -- the following methods may be useful.
+
+  // Adds an already-allocated object, passing ownership to the
+  // RepeatedPtrField.
+  //
+  // Note that some special behavior occurs with respect to arenas:
+  //
+  //   (i) if this field holds submessages, the new submessage will be copied if
+  //   the original is in an arena and this RepeatedPtrField is either in a
+  //   different arena, or on the heap.
+  //   (ii) if this field holds strings, the passed-in string *must* be
+  //   heap-allocated, not arena-allocated. There is no way to dynamically check
+  //   this at runtime, so User Beware.
+  void AddAllocated(Element* value);
+
+  // Removes and returns the last element, passing ownership to the caller.
+  // Requires:  size() > 0
+  //
+  // If this RepeatedPtrField is on an arena, an object copy is required to pass
+  // ownership back to the user (for compatible semantics). Use
+  // UnsafeArenaReleaseLast() if this behavior is undesired.
+  PROTOBUF_NODISCARD Element* ReleaseLast();
+
+  // Adds an already-allocated object, skipping arena-ownership checks. The user
+  // must guarantee that the given object is in the same arena as this
+  // RepeatedPtrField.
+  // It is also useful in legacy code that uses temporary ownership to avoid
+  // copies. Example:
+  //   RepeatedPtrField<T> temp_field;
+  //   temp_field.UnsafeArenaAddAllocated(new T);
+  //   ... // Do something with temp_field
+  //   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
+  // If you put temp_field on the arena this fails, because the ownership
+  // transfers to the arena at the "AddAllocated" call and is not released
+  // anymore, causing a double delete. UnsafeArenaAddAllocated prevents this.
+  void UnsafeArenaAddAllocated(Element* value);
+
+  // Removes and returns the last element.  Unlike ReleaseLast, the returned
+  // pointer is always to the original object.  This may be in an arena, in
+  // which case it would have the arena's lifetime.
+  // Requires: current_size_ > 0
+  Element* UnsafeArenaReleaseLast();
+
+  // Extracts elements with indices in the range "[start .. start+num-1]".
+  // The caller assumes ownership of the extracted elements and is responsible
+  // for deleting them when they are no longer needed.
+  // If "elements" is non-nullptr, then pointers to the extracted elements
+  // are stored in "elements[0 .. num-1]" for the convenience of the caller.
+  // If "elements" is nullptr, then the caller must use some other mechanism
+  // to perform any further operations (like deletion) on these elements.
+  // Caution: implementation also moves elements with indices [start+num ..].
+  // Calling this routine inside a loop can cause quadratic behavior.
+  //
+  // Memory copying behavior is identical to ReleaseLast(), described above: if
+  // this RepeatedPtrField is on an arena, an object copy is performed for each
+  // returned element, so that all returned element pointers are to
+  // heap-allocated copies. If this copy is not desired, the user should call
+  // UnsafeArenaExtractSubrange().
+  void ExtractSubrange(int start, int num, Element** elements);
+
+  // Identical to ExtractSubrange() described above, except that no object
+  // copies are ever performed. Instead, the raw object pointers are returned.
+  // Thus, if on an arena, the returned objects must not be freed, because they
+  // will not be heap-allocated objects.
+  void UnsafeArenaExtractSubrange(int start, int num, Element** elements);
+
+  // When elements are removed by calls to RemoveLast() or Clear(), they
+  // are not actually freed.  Instead, they are cleared and kept so that
+  // they can be reused later.  This can save lots of CPU time when
+  // repeatedly reusing a protocol message for similar purposes.
+  //
+  // Hardcore programs may choose to manipulate these cleared objects
+  // to better optimize memory management using the following routines.
+
+  // Gets the number of cleared objects that are currently being kept
+  // around for reuse.
+  int ClearedCount() const;
+#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
+  // Adds an element to the pool of cleared objects, passing ownership to
+  // the RepeatedPtrField.  The element must be cleared prior to calling
+  // this method.
+  //
+  // This method cannot be called when either the repeated field or |value| is
+  // on an arena; both cases will trigger a GOOGLE_DCHECK-failure.
+  void AddCleared(Element* value);
+  // Removes and returns a single element from the cleared pool, passing
+  // ownership to the caller.  The element is guaranteed to be cleared.
+  // Requires:  ClearedCount() > 0
+  //
+  // This method cannot be called when the repeated field is on an arena; doing
+  // so will trigger a GOOGLE_DCHECK-failure.
+  PROTOBUF_NODISCARD Element* ReleaseCleared();
+#endif  // !PROTOBUF_FUTURE_BREAKING_CHANGES
+
+  // 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.
+  inline Arena* GetArena() const;
+
+  // For internal use only.
+  //
+  // This is public due to it being called by generated code.
+  void InternalSwap(RepeatedPtrField* other) {
+    internal::RepeatedPtrFieldBase::InternalSwap(other);
+  }
+
+ private:
+  // Note:  RepeatedPtrField SHOULD NOT be subclassed by users.
+  class TypeHandler;
+
+  // Internal version of GetArena().
+  inline Arena* GetOwningArena() const;
+
+  // Implementations for ExtractSubrange(). The copying behavior must be
+  // included only if the type supports the necessary operations (e.g.,
+  // MergeFrom()), so we must resolve this at compile time. ExtractSubrange()
+  // uses SFINAE to choose one of the below implementations.
+  void ExtractSubrangeInternal(int start, int num, Element** elements,
+                               std::true_type);
+  void ExtractSubrangeInternal(int start, int num, Element** elements,
+                               std::false_type);
+
+  friend class Arena;
+
+  template <typename T>
+  friend struct WeakRepeatedPtrField;
+
+  typedef void InternalArenaConstructable_;
+
+};
+
+// -------------------------------------------------------------------
+
+template <typename Element>
+class RepeatedPtrField<Element>::TypeHandler
+    : public internal::GenericTypeHandler<Element> {};
+
+template <>
+class RepeatedPtrField<std::string>::TypeHandler
+    : public internal::StringTypeHandler {};
+
+template <typename Element>
+constexpr RepeatedPtrField<Element>::RepeatedPtrField()
+    : RepeatedPtrFieldBase() {}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(Arena* arena)
+    : RepeatedPtrFieldBase(arena) {}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(
+    const RepeatedPtrField& other)
+    : RepeatedPtrFieldBase() {
+  MergeFrom(other);
+}
+
+template <typename Element>
+template <typename Iter, typename>
+inline RepeatedPtrField<Element>::RepeatedPtrField(Iter begin, Iter end) {
+  Add(begin, end);
+}
+
+template <typename Element>
+RepeatedPtrField<Element>::~RepeatedPtrField() {
+#ifdef __cpp_if_constexpr
+  if constexpr (std::is_base_of<MessageLite, Element>::value) {
+#else
+  if (std::is_base_of<MessageLite, Element>::value) {
+#endif
+    if (NeedsDestroy()) DestroyProtos();
+  } else {
+    Destroy<TypeHandler>();
+  }
+}
+
+template <typename Element>
+inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
+    const RepeatedPtrField& other) {
+  if (this != &other) CopyFrom(other);
+  return *this;
+}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(
+    RepeatedPtrField&& other) noexcept
+    : RepeatedPtrField() {
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+  CopyFrom(other);
+#else   // PROTOBUF_FORCE_COPY_IN_MOVE
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // other is on an arena. This field can't be on an arena because arena
+  // construction always uses the Arena* accepting constructor.
+  if (other.GetOwningArena()) {
+    CopyFrom(other);
+  } else {
+    InternalSwap(&other);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+}
+
+template <typename Element>
+inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
+    RepeatedPtrField&& other) noexcept {
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // the two fields are on different arenas.
+  if (this != &other) {
+    if (GetOwningArena() != other.GetOwningArena()
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        || GetOwningArena() == nullptr
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      CopyFrom(other);
+    } else {
+      InternalSwap(&other);
+    }
+  }
+  return *this;
+}
+
+template <typename Element>
+inline bool RepeatedPtrField<Element>::empty() const {
+  return RepeatedPtrFieldBase::empty();
+}
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::size() const {
+  return RepeatedPtrFieldBase::size();
+}
+
+template <typename Element>
+inline const Element& RepeatedPtrField<Element>::Get(int index) const {
+  return RepeatedPtrFieldBase::Get<TypeHandler>(index);
+}
+
+template <typename Element>
+inline const Element& RepeatedPtrField<Element>::at(int index) const {
+  return RepeatedPtrFieldBase::at<TypeHandler>(index);
+}
+
+template <typename Element>
+inline Element& RepeatedPtrField<Element>::at(int index) {
+  return RepeatedPtrFieldBase::at<TypeHandler>(index);
+}
+
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::Mutable(int index) {
+  return RepeatedPtrFieldBase::Mutable<TypeHandler>(index);
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::Add() {
+  return RepeatedPtrFieldBase::Add<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Add(Element&& value) {
+  RepeatedPtrFieldBase::Add<TypeHandler>(std::move(value));
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedPtrField<Element>::Add(Iter begin, Iter end) {
+  if (std::is_base_of<
+          std::forward_iterator_tag,
+          typename std::iterator_traits<Iter>::iterator_category>::value) {
+    int reserve = std::distance(begin, end);
+    Reserve(size() + reserve);
+  }
+  for (; begin != end; ++begin) {
+    *Add() = *begin;
+  }
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::RemoveLast() {
+  RepeatedPtrFieldBase::RemoveLast<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::DeleteSubrange(int start, int num) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+  for (int i = 0; i < num; ++i) {
+    RepeatedPtrFieldBase::Delete<TypeHandler>(start + i);
+  }
+  UnsafeArenaExtractSubrange(start, num, nullptr);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrange(int start, int num,
+                                                       Element** elements) {
+  typename internal::TypeImplementsMergeBehavior<
+      typename TypeHandler::Type>::type t;
+  ExtractSubrangeInternal(start, num, elements, t);
+}
+
+// ExtractSubrange() implementation for types that implement merge/copy
+// behavior.
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrangeInternal(
+    int start, int num, Element** elements, std::true_type) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+
+  if (num == 0) return;
+
+  GOOGLE_DCHECK_NE(elements, nullptr)
+      << "Releasing elements without transferring ownership is an unsafe "
+         "operation.  Use UnsafeArenaExtractSubrange.";
+  if (elements == nullptr) {
+    CloseGap(start, num);
+    return;
+  }
+
+  Arena* arena = GetOwningArena();
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  // Always copy.
+  for (int i = 0; i < num; ++i) {
+    elements[i] = copy<TypeHandler>(
+        RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start));
+  }
+  if (arena == nullptr) {
+    for (int i = 0; i < num; ++i) {
+      delete RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+    }
+  }
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+  // If we're on an arena, we perform a copy for each element so that the
+  // returned elements are heap-allocated. Otherwise, just forward it.
+  if (arena != nullptr) {
+    for (int i = 0; i < num; ++i) {
+      elements[i] = copy<TypeHandler>(
+          RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start));
+    }
+  } else {
+    for (int i = 0; i < num; ++i) {
+      elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+    }
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  CloseGap(start, num);
+}
+
+// ExtractSubrange() implementation for types that do not implement merge/copy
+// behavior.
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrangeInternal(
+    int start, int num, Element** elements, std::false_type) {
+  // This case is identical to UnsafeArenaExtractSubrange(). However, since
+  // ExtractSubrange() must return heap-allocated objects by contract, and we
+  // cannot fulfill this contract if we are an on arena, we must GOOGLE_DCHECK() that
+  // we are not on an arena.
+  GOOGLE_DCHECK(GetOwningArena() == nullptr)
+      << "ExtractSubrange() when arena is non-nullptr is only supported when "
+      << "the Element type supplies a MergeFrom() operation to make copies.";
+  UnsafeArenaExtractSubrange(start, num, elements);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaExtractSubrange(
+    int start, int num, Element** elements) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+
+  if (num > 0) {
+    // Save the values of the removed elements if requested.
+    if (elements != nullptr) {
+      for (int i = 0; i < num; ++i) {
+        elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+      }
+    }
+    CloseGap(start, num);
+  }
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Clear() {
+  RepeatedPtrFieldBase::Clear<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::MergeFrom(
+    const RepeatedPtrField& other) {
+  RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::CopyFrom(const RepeatedPtrField& other) {
+  RepeatedPtrFieldBase::CopyFrom<TypeHandler>(other);
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedPtrField<Element>::Assign(Iter begin, Iter end) {
+  Clear();
+  Add(begin, end);
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator position) {
+  return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator first, const_iterator last) {
+  size_type pos_offset = std::distance(cbegin(), first);
+  size_type last_offset = std::distance(cbegin(), last);
+  DeleteSubrange(pos_offset, last_offset - pos_offset);
+  return begin() + pos_offset;
+}
+
+template <typename Element>
+inline Element** RepeatedPtrField<Element>::mutable_data() {
+  return RepeatedPtrFieldBase::mutable_data<TypeHandler>();
+}
+
+template <typename Element>
+inline const Element* const* RepeatedPtrField<Element>::data() const {
+  return RepeatedPtrFieldBase::data<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
+  if (this == other) return;
+  RepeatedPtrFieldBase::Swap<TypeHandler>(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaSwap(
+    RepeatedPtrField* other) {
+  if (this == other) return;
+  GOOGLE_DCHECK_EQ(GetOwningArena(), other->GetOwningArena());
+  RepeatedPtrFieldBase::InternalSwap(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
+  RepeatedPtrFieldBase::SwapElements(index1, index2);
+}
+
+template <typename Element>
+inline Arena* RepeatedPtrField<Element>::GetArena() const {
+  return RepeatedPtrFieldBase::GetArena();
+}
+
+template <typename Element>
+inline Arena* RepeatedPtrField<Element>::GetOwningArena() const {
+  return RepeatedPtrFieldBase::GetOwningArena();
+}
+
+template <typename Element>
+inline size_t RepeatedPtrField<Element>::SpaceUsedExcludingSelfLong() const {
+  return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::AddAllocated(Element* value) {
+  RepeatedPtrFieldBase::AddAllocated<TypeHandler>(value);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaAddAllocated(Element* value) {
+  RepeatedPtrFieldBase::UnsafeArenaAddAllocated<TypeHandler>(value);
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::ReleaseLast() {
+  return RepeatedPtrFieldBase::ReleaseLast<TypeHandler>();
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::UnsafeArenaReleaseLast() {
+  return RepeatedPtrFieldBase::UnsafeArenaReleaseLast<TypeHandler>();
+}
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::ClearedCount() const {
+  return RepeatedPtrFieldBase::ClearedCount();
+}
+
+#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
+template <typename Element>
+inline void RepeatedPtrField<Element>::AddCleared(Element* value) {
+  return RepeatedPtrFieldBase::AddCleared<TypeHandler>(value);
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::ReleaseCleared() {
+  return RepeatedPtrFieldBase::ReleaseCleared<TypeHandler>();
+}
+#endif  // !PROTOBUF_FUTURE_BREAKING_CHANGES
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Reserve(int new_size) {
+  return RepeatedPtrFieldBase::Reserve(new_size);
+}
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::Capacity() const {
+  return RepeatedPtrFieldBase::Capacity();
+}
+
+// -------------------------------------------------------------------
+
+namespace internal {
+
+// STL-like iterator implementation for RepeatedPtrField.  You should not
+// refer to this class directly; use RepeatedPtrField<T>::iterator instead.
+//
+// The iterator for RepeatedPtrField<T>, RepeatedPtrIterator<T>, is
+// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors.h,
+// but adds random-access operators and is modified to wrap a void** base
+// iterator (since RepeatedPtrField stores its array as a void* array and
+// casting void** to T** would violate C++ aliasing rules).
+//
+// This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin
+// (jyasskin@google.com).
+template <typename Element>
+class RepeatedPtrIterator {
+ public:
+  using iterator = RepeatedPtrIterator<Element>;
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = typename std::remove_const<Element>::type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = Element*;
+  using reference = Element&;
+
+  RepeatedPtrIterator() : it_(nullptr) {}
+  explicit RepeatedPtrIterator(void* const* it) : it_(it) {}
+
+  // Allows "upcasting" from RepeatedPtrIterator<T**> to
+  // RepeatedPtrIterator<const T*const*>.
+  template <typename OtherElement,
+            typename std::enable_if<std::is_convertible<
+                OtherElement*, pointer>::value>::type* = nullptr>
+  RepeatedPtrIterator(const RepeatedPtrIterator<OtherElement>& other)
+      : it_(other.it_) {}
+
+  // dereferenceable
+  reference operator*() const { return *reinterpret_cast<Element*>(*it_); }
+  pointer operator->() const { return &(operator*()); }
+
+  // {inc,dec}rementable
+  iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  iterator operator++(int) { return iterator(it_++); }
+  iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  iterator operator--(int) { return iterator(it_--); }
+
+  // equality_comparable
+  friend bool operator==(const iterator& x, const iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend bool operator!=(const iterator& x, const iterator& y) {
+    return x.it_ != y.it_;
+  }
+
+  // less_than_comparable
+  friend bool operator<(const iterator& x, const iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend bool operator<=(const iterator& x, const iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend bool operator>(const iterator& x, const iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend bool operator>=(const iterator& x, const iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  // addable, subtractable
+  iterator& operator+=(difference_type d) {
+    it_ += d;
+    return *this;
+  }
+  friend iterator operator+(iterator it, const difference_type d) {
+    it += d;
+    return it;
+  }
+  friend iterator operator+(const difference_type d, iterator it) {
+    it += d;
+    return it;
+  }
+  iterator& operator-=(difference_type d) {
+    it_ -= d;
+    return *this;
+  }
+  friend iterator operator-(iterator it, difference_type d) {
+    it -= d;
+    return it;
+  }
+
+  // indexable
+  reference operator[](difference_type d) const { return *(*this + d); }
+
+  // random access iterator
+  friend difference_type operator-(iterator it1, iterator it2) {
+    return it1.it_ - it2.it_;
+  }
+
+ private:
+  template <typename OtherElement>
+  friend class RepeatedPtrIterator;
+
+  // The internal iterator.
+  void* const* it_;
+};
+
+// Provides an iterator that operates on pointers to the underlying objects
+// rather than the objects themselves as RepeatedPtrIterator does.
+// Consider using this when working with stl algorithms that change
+// the array.
+// The VoidPtr template parameter holds the type-agnostic pointer value
+// referenced by the iterator.  It should either be "void *" for a mutable
+// iterator, or "const void* const" for a constant iterator.
+template <typename Element, typename VoidPtr>
+class RepeatedPtrOverPtrsIterator {
+ public:
+  using iterator = RepeatedPtrOverPtrsIterator<Element, VoidPtr>;
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = typename std::remove_const<Element>::type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = Element*;
+  using reference = Element&;
+
+  RepeatedPtrOverPtrsIterator() : it_(nullptr) {}
+  explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {}
+
+  // Allows "upcasting" from RepeatedPtrOverPtrsIterator<T**> to
+  // RepeatedPtrOverPtrsIterator<const T*const*>.
+  template <
+      typename OtherElement, typename OtherVoidPtr,
+      typename std::enable_if<
+          std::is_convertible<OtherElement*, pointer>::value &&
+          std::is_convertible<OtherVoidPtr*, VoidPtr>::value>::type* = nullptr>
+  RepeatedPtrOverPtrsIterator(
+      const RepeatedPtrOverPtrsIterator<OtherElement, OtherVoidPtr>& other)
+      : it_(other.it_) {}
+
+  // dereferenceable
+  reference operator*() const { return *reinterpret_cast<Element*>(it_); }
+  pointer operator->() const { return &(operator*()); }
+
+  // {inc,dec}rementable
+  iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  iterator operator++(int) { return iterator(it_++); }
+  iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  iterator operator--(int) { return iterator(it_--); }
+
+  // equality_comparable
+  friend bool operator==(const iterator& x, const iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend bool operator!=(const iterator& x, const iterator& y) {
+    return x.it_ != y.it_;
+  }
+
+  // less_than_comparable
+  friend bool operator<(const iterator& x, const iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend bool operator<=(const iterator& x, const iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend bool operator>(const iterator& x, const iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend bool operator>=(const iterator& x, const iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  // addable, subtractable
+  iterator& operator+=(difference_type d) {
+    it_ += d;
+    return *this;
+  }
+  friend iterator operator+(iterator it, difference_type d) {
+    it += d;
+    return it;
+  }
+  friend iterator operator+(difference_type d, iterator it) {
+    it += d;
+    return it;
+  }
+  iterator& operator-=(difference_type d) {
+    it_ -= d;
+    return *this;
+  }
+  friend iterator operator-(iterator it, difference_type d) {
+    it -= d;
+    return it;
+  }
+
+  // indexable
+  reference operator[](difference_type d) const { return *(*this + d); }
+
+  // random access iterator
+  friend difference_type operator-(iterator it1, iterator it2) {
+    return it1.it_ - it2.it_;
+  }
+
+ private:
+  template <typename OtherElement, typename OtherVoidPtr>
+  friend class RepeatedPtrOverPtrsIterator;
+
+  // The internal iterator.
+  VoidPtr* it_;
+};
+
+}  // namespace internal
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::begin() {
+  return iterator(raw_data());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::begin() const {
+  return iterator(raw_data());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cbegin() const {
+  return begin();
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::end() {
+  return iterator(raw_data() + size());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::end() const {
+  return iterator(raw_data() + size());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cend() const {
+  return end();
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::pointer_iterator
+RepeatedPtrField<Element>::pointer_begin() {
+  return pointer_iterator(raw_mutable_data());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_begin() const {
+  return const_pointer_iterator(const_cast<const void* const*>(raw_data()));
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::pointer_iterator
+RepeatedPtrField<Element>::pointer_end() {
+  return pointer_iterator(raw_mutable_data() + size());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_end() const {
+  return const_pointer_iterator(
+      const_cast<const void* const*>(raw_data() + size()));
+}
+
+// Iterators and helper functions that follow the spirit of the STL
+// std::back_insert_iterator and std::back_inserter but are tailor-made
+// for RepeatedField and RepeatedPtrField. Typical usage would be:
+//
+//   std::copy(some_sequence.begin(), some_sequence.end(),
+//             RepeatedFieldBackInserter(proto.mutable_sequence()));
+//
+// Ported by johannes from util/gtl/proto-array-iterators.h
+
+namespace internal {
+
+// A back inserter for RepeatedPtrField objects.
+template <typename T>
+class RepeatedPtrFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  RepeatedPtrFieldBackInsertIterator(RepeatedPtrField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  RepeatedPtrFieldBackInsertIterator<T>& operator=(const T& value) {
+    *field_->Add() = value;
+    return *this;
+  }
+  RepeatedPtrFieldBackInsertIterator<T>& operator=(
+      const T* const ptr_to_value) {
+    *field_->Add() = *ptr_to_value;
+    return *this;
+  }
+  RepeatedPtrFieldBackInsertIterator<T>& operator=(T&& value) {
+    *field_->Add() = std::move(value);
+    return *this;
+  }
+  RepeatedPtrFieldBackInsertIterator<T>& operator*() { return *this; }
+  RepeatedPtrFieldBackInsertIterator<T>& operator++() { return *this; }
+  RepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedPtrField<T>* field_;
+};
+
+// A back inserter for RepeatedPtrFields that inserts by transferring ownership
+// of a pointer.
+template <typename T>
+class AllocatedRepeatedPtrFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  explicit AllocatedRepeatedPtrFieldBackInsertIterator(
+      RepeatedPtrField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=(
+      T* const ptr_to_value) {
+    field_->AddAllocated(ptr_to_value);
+    return *this;
+  }
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() { return *this; }
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() { return *this; }
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedPtrField<T>* field_;
+};
+
+// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one
+// uses the UnsafeArenaAddAllocated instead.
+template <typename T>
+class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator(
+      RepeatedPtrField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=(
+      T const* const ptr_to_value) {
+    field_->UnsafeArenaAddAllocated(const_cast<T*>(ptr_to_value));
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() {
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() {
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
+      int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedPtrField<T>* field_;
+};
+
+}  // namespace internal
+
+// Provides a back insert iterator for RepeatedPtrField instances,
+// similar to std::back_inserter().
+template <typename T>
+internal::RepeatedPtrFieldBackInsertIterator<T> RepeatedPtrFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Special back insert iterator for RepeatedPtrField instances, just in
+// case someone wants to write generic template code that can access both
+// RepeatedFields and RepeatedPtrFields using a common name.
+template <typename T>
+internal::RepeatedPtrFieldBackInsertIterator<T> RepeatedFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Provides a back insert iterator for RepeatedPtrField instances
+// similar to std::back_inserter() which transfers the ownership while
+// copying elements.
+template <typename T>
+internal::AllocatedRepeatedPtrFieldBackInsertIterator<T>
+AllocatedRepeatedPtrFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::AllocatedRepeatedPtrFieldBackInsertIterator<T>(
+      mutable_field);
+}
+
+// Similar to AllocatedRepeatedPtrFieldBackInserter, using
+// UnsafeArenaAddAllocated instead of AddAllocated.
+// This is slightly faster if that matters. It is also useful in legacy code
+// that uses temporary ownership to avoid copies. Example:
+//   RepeatedPtrField<T> temp_field;
+//   temp_field.UnsafeArenaAddAllocated(new T);
+//   ... // Do something with temp_field
+//   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
+// Putting temp_field on the arena fails because the ownership transfers to the
+// arena at the "AddAllocated" call and is not released anymore causing a
+// double delete. This function uses UnsafeArenaAddAllocated to prevent this.
+template <typename T>
+internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>
+UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>(
+      mutable_field);
+}
+
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedPtrField<std::string>;
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
diff --git a/src/google/protobuf/service.cc b/src/google/protobuf/service.cc
new file mode 100644
index 0000000..5394568
--- /dev/null
+++ b/src/google/protobuf/service.cc
@@ -0,0 +1,45 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/service.h>
+
+namespace google {
+namespace protobuf {
+
+Service::~Service() {}
+RpcChannel::~RpcChannel() {}
+RpcController::~RpcController() {}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h
new file mode 100644
index 0000000..d288eb5
--- /dev/null
+++ b/src/google/protobuf/service.h
@@ -0,0 +1,295 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// DEPRECATED:  This module declares the abstract interfaces underlying proto2
+// RPC services.  These are intended to be independent of any particular RPC
+// implementation, so that proto2 services can be used on top of a variety
+// of implementations.  Starting with version 2.3.0, RPC implementations should
+// not try to build on these, but should instead provide code generator plugins
+// which generate code specific to the particular RPC implementation.  This way
+// the generated code can be more appropriate for the implementation in use
+// and can avoid unnecessary layers of indirection.
+//
+//
+// When you use the protocol compiler to compile a service definition, it
+// generates two classes:  An abstract interface for the service (with
+// methods matching the service definition) and a "stub" implementation.
+// A stub is just a type-safe wrapper around an RpcChannel which emulates a
+// local implementation of the service.
+//
+// For example, the service definition:
+//   service MyService {
+//     rpc Foo(MyRequest) returns(MyResponse);
+//   }
+// will generate abstract interface "MyService" and class "MyService::Stub".
+// You could implement a MyService as follows:
+//   class MyServiceImpl : public MyService {
+//    public:
+//     MyServiceImpl() {}
+//     ~MyServiceImpl() {}
+//
+//     // implements MyService ---------------------------------------
+//
+//     void Foo(google::protobuf::RpcController* controller,
+//              const MyRequest* request,
+//              MyResponse* response,
+//              Closure* done) {
+//       // ... read request and fill in response ...
+//       done->Run();
+//     }
+//   };
+// You would then register an instance of MyServiceImpl with your RPC server
+// implementation.  (How to do that depends on the implementation.)
+//
+// 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 hypothetical "MyRpcChannel" as an example:
+//   MyRpcChannel channel("rpc:hostname:1234/myservice");
+//   MyRpcController controller;
+//   MyServiceImpl::Stub stub(&channel);
+//   FooRequest request;
+//   FooResponse response;
+//
+//   // ... fill in request ...
+//
+//   stub.Foo(&controller, request, &response, NewCallback(HandleResponse));
+//
+// On Thread-Safety:
+//
+// Different RPC implementations may make different guarantees about what
+// threads they may run callbacks on, and what threads the application is
+// allowed to use to call the RPC system.  Portable software should be ready
+// for callbacks to be called on any thread, but should not try to call the
+// RPC system from any thread except for the ones on which it received the
+// callbacks.  Realistically, though, simple software will probably want to
+// use a single-threaded RPC system while high-end software will want to
+// use multiple threads.  RPC implementations should provide multiple
+// choices.
+
+#ifndef GOOGLE_PROTOBUF_SERVICE_H__
+#define GOOGLE_PROTOBUF_SERVICE_H__
+
+
+#include <string>
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Service;
+class RpcController;
+class RpcChannel;
+
+// Defined in other files.
+class Descriptor;         // descriptor.h
+class ServiceDescriptor;  // descriptor.h
+class MethodDescriptor;   // descriptor.h
+class Message;            // message.h
+
+// Abstract base interface for protocol-buffer-based RPC services.  Services
+// themselves are abstract interfaces (implemented either by servers or as
+// stubs), but they subclass this base interface.  The methods of this
+// interface can be used to call the methods of the Service without knowing
+// its exact type at compile time (analogous to Reflection).
+class PROTOBUF_EXPORT Service {
+ public:
+  inline Service() {}
+  virtual ~Service();
+
+  // When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second
+  // parameter to the constructor to tell it to delete its RpcChannel when
+  // destroyed.
+  enum ChannelOwnership { STUB_OWNS_CHANNEL, STUB_DOESNT_OWN_CHANNEL };
+
+  // Get the ServiceDescriptor describing this service and its methods.
+  virtual const ServiceDescriptor* GetDescriptor() = 0;
+
+  // Call a method of the service specified by MethodDescriptor.  This is
+  // normally implemented as a simple switch() that calls the standard
+  // definitions of the service's methods.
+  //
+  // Preconditions:
+  // * method->service() == GetDescriptor()
+  // * request and response are of the exact same classes as the objects
+  //   returned by GetRequestPrototype(method) and
+  //   GetResponsePrototype(method).
+  // * After the call has started, the request must not be modified and the
+  //   response must not be accessed at all until "done" is called.
+  // * "controller" is of the correct type for the RPC implementation being
+  //   used by this Service.  For stubs, the "correct type" depends on the
+  //   RpcChannel which the stub is using.  Server-side Service
+  //   implementations are expected to accept whatever type of RpcController
+  //   the server-side RPC implementation uses.
+  //
+  // Postconditions:
+  // * "done" will be called when the method is complete.  This may be
+  //   before CallMethod() returns or it may be at some point in the future.
+  // * If the RPC succeeded, "response" contains the response returned by
+  //   the server.
+  // * If the RPC failed, "response"'s contents are undefined.  The
+  //   RpcController can be queried to determine if an error occurred and
+  //   possibly to get more information about the error.
+  virtual void CallMethod(const MethodDescriptor* method,
+                          RpcController* controller, const Message* request,
+                          Message* response, Closure* done) = 0;
+
+  // CallMethod() requires that the request and response passed in are of a
+  // particular subclass of Message.  GetRequestPrototype() and
+  // GetResponsePrototype() get the default instances of these required types.
+  // You can then call Message::New() on these instances to construct mutable
+  // objects which you can then pass to CallMethod().
+  //
+  // Example:
+  //   const MethodDescriptor* method =
+  //     service->GetDescriptor()->FindMethodByName("Foo");
+  //   Message* request  = stub->GetRequestPrototype (method)->New();
+  //   Message* response = stub->GetResponsePrototype(method)->New();
+  //   request->ParseFromString(input);
+  //   service->CallMethod(method, *request, response, callback);
+  virtual const Message& GetRequestPrototype(
+      const MethodDescriptor* method) const = 0;
+  virtual const Message& GetResponsePrototype(
+      const MethodDescriptor* method) const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service);
+};
+
+// An RpcController mediates a single method call.  The primary purpose of
+// the controller is to provide a way to manipulate settings specific to the
+// RPC implementation and to find out about RPC-level errors.
+//
+// The methods provided by the RpcController interface are intended to be a
+// "least common denominator" set of features which we expect all
+// implementations to support.  Specific implementations may provide more
+// advanced features (e.g. deadline propagation).
+class PROTOBUF_EXPORT RpcController {
+ public:
+  inline RpcController() {}
+  virtual ~RpcController();
+
+  // Client-side methods ---------------------------------------------
+  // These calls may be made from the client side only.  Their results
+  // are undefined on the server side (may crash).
+
+  // Resets the RpcController to its initial state so that it may be reused in
+  // a new call.  Must not be called while an RPC is in progress.
+  virtual void Reset() = 0;
+
+  // After a call has finished, returns true if the call failed.  The possible
+  // reasons for failure depend on the RPC implementation.  Failed() must not
+  // be called before a call has finished.  If Failed() returns true, the
+  // contents of the response message are undefined.
+  virtual bool Failed() const = 0;
+
+  // If Failed() is true, returns a human-readable description of the error.
+  virtual std::string ErrorText() const = 0;
+
+  // Advises the RPC system that the caller desires that the RPC call be
+  // canceled.  The RPC system may cancel it immediately, may wait awhile and
+  // then cancel it, or may not even cancel the call at all.  If the call is
+  // canceled, the "done" callback will still be called and the RpcController
+  // will indicate that the call failed at that time.
+  virtual void StartCancel() = 0;
+
+  // Server-side methods ---------------------------------------------
+  // These calls may be made from the server side only.  Their results
+  // are undefined on the client side (may crash).
+
+  // Causes Failed() to return true on the client side.  "reason" will be
+  // incorporated into the message returned by ErrorText().  If you find
+  // you need to return machine-readable information about failures, you
+  // should incorporate it into your response protocol buffer and should
+  // NOT call SetFailed().
+  virtual void SetFailed(const std::string& reason) = 0;
+
+  // If true, indicates that the client canceled the RPC, so the server may
+  // as well give up on replying to it.  The server should still call the
+  // final "done" callback.
+  virtual bool IsCanceled() const = 0;
+
+  // Asks that the given callback be called when the RPC is canceled.  The
+  // callback will always be called exactly once.  If the RPC completes without
+  // being canceled, the callback will be called after completion.  If the RPC
+  // has already been canceled when NotifyOnCancel() is called, the callback
+  // will be called immediately.
+  //
+  // NotifyOnCancel() must be called no more than once per request.
+  virtual void NotifyOnCancel(Closure* callback) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController);
+};
+
+// Abstract interface for an RPC channel.  An RpcChannel represents a
+// communication line to a Service which can be used to call that Service's
+// methods.  The Service may be running on another machine.  Normally, you
+// should not call an RpcChannel directly, but instead construct a stub Service
+// wrapping it.  Example:
+//   RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234");
+//   MyService* service = new MyService::Stub(channel);
+//   service->MyMethod(request, &response, callback);
+class PROTOBUF_EXPORT RpcChannel {
+ public:
+  inline RpcChannel() {}
+  virtual ~RpcChannel();
+
+  // Call the given method of the remote service.  The signature of this
+  // procedure looks the same as Service::CallMethod(), but the requirements
+  // are less strict in one important way:  the request and response objects
+  // need not be of any specific class as long as their descriptors are
+  // method->input_type() and method->output_type().
+  virtual void CallMethod(const MethodDescriptor* method,
+                          RpcController* controller, const Message* request,
+                          Message* response, Closure* done) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_SERVICE_H__
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
new file mode 100644
index 0000000..e7525e9
--- /dev/null
+++ b/src/google/protobuf/source_context.pb.cc
@@ -0,0 +1,297 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#include <google/protobuf/source_context.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR SourceContext::SourceContext(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.file_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct SourceContextDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR SourceContextDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~SourceContextDefaultTypeInternal() {}
+  union {
+    SourceContext _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceContextDefaultTypeInternal _SourceContext_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceContext, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceContext, _impl_.file_name_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceContext)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n$google/protobuf/source_context.proto\022\017"
+  "google.protobuf\"\"\n\rSourceContext\022\021\n\tfile"
+  "_name\030\001 \001(\tB\212\001\n\023com.google.protobufB\022Sou"
+  "rceContextProtoP\001Z6google.golang.org/pro"
+  "tobuf/types/known/sourcecontextpb\242\002\003GPB\252"
+  "\002\036Google.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+    false, false, 240, descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto,
+    "google/protobuf/source_context.proto",
+    &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fsource_5fcontext_2eproto(&descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class SourceContext::_Internal {
+ public:
+};
+
+SourceContext::SourceContext(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceContext)
+}
+SourceContext::SourceContext(const SourceContext& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  SourceContext* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_name_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.file_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.file_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_file_name().empty()) {
+    _this->_impl_.file_name_.Set(from._internal_file_name(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceContext)
+}
+
+inline void SourceContext::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_name_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.file_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.file_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+SourceContext::~SourceContext() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceContext)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void SourceContext::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.file_name_.Destroy();
+}
+
+void SourceContext::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void SourceContext::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceContext)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.file_name_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* SourceContext::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string file_name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_file_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.SourceContext.file_name"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* SourceContext::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string file_name = 1;
+  if (!this->_internal_file_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_file_name().data(), static_cast<int>(this->_internal_file_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.SourceContext.file_name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_file_name(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceContext)
+  return target;
+}
+
+size_t SourceContext::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceContext)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string file_name = 1;
+  if (!this->_internal_file_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_file_name());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceContext::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    SourceContext::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceContext::GetClassData() const { return &_class_data_; }
+
+
+void SourceContext::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<SourceContext*>(&to_msg);
+  auto& from = static_cast<const SourceContext&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceContext)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_file_name().empty()) {
+    _this->_internal_set_file_name(from._internal_file_name());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void SourceContext::CopyFrom(const SourceContext& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceContext)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceContext::IsInitialized() const {
+  return true;
+}
+
+void SourceContext::InternalSwap(SourceContext* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.file_name_, lhs_arena,
+      &other->_impl_.file_name_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata SourceContext::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter, &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceContext*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceContext >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceContext >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
new file mode 100644
index 0000000..acf2773
--- /dev/null
+++ b/src/google/protobuf/source_context.pb.h
@@ -0,0 +1,282 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fsource_5fcontext_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fsource_5fcontext_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fsource_5fcontext_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class SourceContext;
+struct SourceContextDefaultTypeInternal;
+PROTOBUF_EXPORT extern SourceContextDefaultTypeInternal _SourceContext_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::SourceContext* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT SourceContext final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceContext) */ {
+ public:
+  inline SourceContext() : SourceContext(nullptr) {}
+  ~SourceContext() override;
+  explicit PROTOBUF_CONSTEXPR SourceContext(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  SourceContext(const SourceContext& from);
+  SourceContext(SourceContext&& from) noexcept
+    : SourceContext() {
+    *this = ::std::move(from);
+  }
+
+  inline SourceContext& operator=(const SourceContext& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline SourceContext& operator=(SourceContext&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const SourceContext& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const SourceContext* internal_default_instance() {
+    return reinterpret_cast<const SourceContext*>(
+               &_SourceContext_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(SourceContext& a, SourceContext& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(SourceContext* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(SourceContext* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  SourceContext* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<SourceContext>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const SourceContext& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const SourceContext& from) {
+    SourceContext::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(SourceContext* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.SourceContext";
+  }
+  protected:
+  explicit SourceContext(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFileNameFieldNumber = 1,
+  };
+  // string file_name = 1;
+  void clear_file_name();
+  const std::string& file_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_file_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_file_name();
+  PROTOBUF_NODISCARD std::string* release_file_name();
+  void set_allocated_file_name(std::string* file_name);
+  private:
+  const std::string& _internal_file_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_file_name(const std::string& value);
+  std::string* _internal_mutable_file_name();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceContext)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr file_name_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// SourceContext
+
+// string file_name = 1;
+inline void SourceContext::clear_file_name() {
+  _impl_.file_name_.ClearToEmpty();
+}
+inline const std::string& SourceContext::file_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceContext.file_name)
+  return _internal_file_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void SourceContext::set_file_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.file_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceContext.file_name)
+}
+inline std::string* SourceContext::mutable_file_name() {
+  std::string* _s = _internal_mutable_file_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceContext.file_name)
+  return _s;
+}
+inline const std::string& SourceContext::_internal_file_name() const {
+  return _impl_.file_name_.Get();
+}
+inline void SourceContext::_internal_set_file_name(const std::string& value) {
+  
+  _impl_.file_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* SourceContext::_internal_mutable_file_name() {
+  
+  return _impl_.file_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* SourceContext::release_file_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name)
+  return _impl_.file_name_.Release();
+}
+inline void SourceContext::set_allocated_file_name(std::string* file_name) {
+  if (file_name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.file_name_.SetAllocated(file_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.file_name_.IsDefault()) {
+    _impl_.file_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceContext.file_name)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fsource_5fcontext_2eproto
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
new file mode 100644
index 0000000..06bfc43
--- /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 objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb";
+
+// `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_context.proto"`.
+  string file_name = 1;
+}
diff --git a/src/google/protobuf/string_member_robber.h b/src/google/protobuf/string_member_robber.h
new file mode 100644
index 0000000..a4c1051
--- /dev/null
+++ b/src/google/protobuf/string_member_robber.h
@@ -0,0 +1,38 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STRING_MEMBER_ROBBER_H__
+#define GOOGLE_PROTOBUF_STRING_MEMBER_ROBBER_H__
+
+#include <string>
+#include <type_traits>
+
+
+#endif  // GOOGLE_PROTOBUF_STRING_MEMBER_ROBBER_H__
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
new file mode 100644
index 0000000..87c72d4
--- /dev/null
+++ b/src/google/protobuf/struct.pb.cc
@@ -0,0 +1,1057 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#include <google/protobuf/struct.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse(
+    ::_pbi::ConstantInitialized) {}
+struct Struct_FieldsEntry_DoNotUseDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR Struct_FieldsEntry_DoNotUseDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~Struct_FieldsEntry_DoNotUseDefaultTypeInternal() {}
+  union {
+    Struct_FieldsEntry_DoNotUse _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Struct_FieldsEntry_DoNotUseDefaultTypeInternal _Struct_FieldsEntry_DoNotUse_default_instance_;
+PROTOBUF_CONSTEXPR Struct::Struct(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.fields_)*/{::_pbi::ConstantInitialized()}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct StructDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR StructDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~StructDefaultTypeInternal() {}
+  union {
+    Struct _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StructDefaultTypeInternal _Struct_default_instance_;
+PROTOBUF_CONSTEXPR Value::Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.kind_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_._oneof_case_)*/{}} {}
+struct ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ValueDefaultTypeInternal() {}
+  union {
+    Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ValueDefaultTypeInternal _Value_default_instance_;
+PROTOBUF_CONSTEXPR ListValue::ListValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.values_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct ListValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ListValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ListValueDefaultTypeInternal() {}
+  union {
+    ListValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ListValueDefaultTypeInternal _ListValue_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fstruct_2eproto[4];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[1];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, _has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, key_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, value_),
+  0,
+  1,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct, _impl_.fields_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _impl_._oneof_case_[0]),
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _impl_.kind_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ListValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ListValue, _impl_.values_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, 8, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse)},
+  { 10, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Struct)},
+  { 17, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Value)},
+  { 30, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ListValue)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Struct_FieldsEntry_DoNotUse_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ListValue_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\034google/protobuf/struct.proto\022\017google.p"
+  "rotobuf\"\204\001\n\006Struct\0223\n\006fields\030\001 \003(\0132#.goo"
+  "gle.protobuf.Struct.FieldsEntry\032E\n\013Field"
+  "sEntry\022\013\n\003key\030\001 \001(\t\022%\n\005value\030\002 \001(\0132\026.goo"
+  "gle.protobuf.Value:\0028\001\"\352\001\n\005Value\0220\n\nnull"
+  "_value\030\001 \001(\0162\032.google.protobuf.NullValue"
+  "H\000\022\026\n\014number_value\030\002 \001(\001H\000\022\026\n\014string_val"
+  "ue\030\003 \001(\tH\000\022\024\n\nbool_value\030\004 \001(\010H\000\022/\n\014stru"
+  "ct_value\030\005 \001(\0132\027.google.protobuf.StructH"
+  "\000\0220\n\nlist_value\030\006 \001(\0132\032.google.protobuf."
+  "ListValueH\000B\006\n\004kind\"3\n\tListValue\022&\n\006valu"
+  "es\030\001 \003(\0132\026.google.protobuf.Value*\033\n\tNull"
+  "Value\022\016\n\nNULL_VALUE\020\000B\177\n\023com.google.prot"
+  "obufB\013StructProtoP\001Z/google.golang.org/p"
+  "rotobuf/types/known/structpb\370\001\001\242\002\003GPB\252\002\036"
+  "Google.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fstruct_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
+    false, false, 638, descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto,
+    "google/protobuf/struct.proto",
+    &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once, nullptr, 0, 4,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fstruct_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fstruct_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fstruct_2eproto(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* NullValue_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[0];
+}
+bool NullValue_IsValid(int value) {
+  switch (value) {
+    case 0:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// ===================================================================
+
+Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse() {}
+Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena)
+    : SuperType(arena) {}
+void Struct_FieldsEntry_DoNotUse::MergeFrom(const Struct_FieldsEntry_DoNotUse& other) {
+  MergeFromInternal(other);
+}
+::PROTOBUF_NAMESPACE_ID::Metadata Struct_FieldsEntry_DoNotUse::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[0]);
+}
+
+// ===================================================================
+
+class Struct::_Internal {
+ public:
+};
+
+Struct::Struct(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  if (arena != nullptr && !is_message_owned) {
+    arena->OwnCustomDestructor(this, &Struct::ArenaDtor);
+  }
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Struct)
+}
+Struct::Struct(const Struct& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Struct* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_.fields_)*/{}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.fields_.MergeFrom(from._impl_.fields_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Struct)
+}
+
+inline void Struct::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_.fields_)*/{::_pbi::ArenaInitialized(), arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Struct::~Struct() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Struct)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    ArenaDtor(this);
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Struct::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.fields_.Destruct();
+  _impl_.fields_.~MapField();
+}
+
+void Struct::ArenaDtor(void* object) {
+  Struct* _this = reinterpret_cast< Struct* >(object);
+  _this->_impl_.fields_.Destruct();
+}
+void Struct::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Struct::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Struct)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.fields_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Struct::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // map<string, .google.protobuf.Value> fields = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(&_impl_.fields_, ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Struct::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // map<string, .google.protobuf.Value> fields = 1;
+  if (!this->_internal_fields().empty()) {
+    using MapType = ::_pb::Map<std::string, ::PROTOBUF_NAMESPACE_ID::Value>;
+    using WireHelper = Struct_FieldsEntry_DoNotUse::Funcs;
+    const auto& map_field = this->_internal_fields();
+    auto check_utf8 = [](const MapType::value_type& entry) {
+      (void)entry;
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+        entry.first.data(), static_cast<int>(entry.first.length()),
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+        "google.protobuf.Struct.FieldsEntry.key");
+    };
+
+    if (stream->IsSerializationDeterministic() && map_field.size() > 1) {
+      for (const auto& entry : ::_pbi::MapSorterPtr<MapType>(map_field)) {
+        target = WireHelper::InternalSerialize(1, entry.first, entry.second, target, stream);
+        check_utf8(entry);
+      }
+    } else {
+      for (const auto& entry : map_field) {
+        target = WireHelper::InternalSerialize(1, entry.first, entry.second, target, stream);
+        check_utf8(entry);
+      }
+    }
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Struct)
+  return target;
+}
+
+size_t Struct::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Struct)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // map<string, .google.protobuf.Value> fields = 1;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->_internal_fields_size());
+  for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >::const_iterator
+      it = this->_internal_fields().begin();
+      it != this->_internal_fields().end(); ++it) {
+    total_size += Struct_FieldsEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Struct::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Struct::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Struct::GetClassData() const { return &_class_data_; }
+
+
+void Struct::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Struct*>(&to_msg);
+  auto& from = static_cast<const Struct&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Struct)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.fields_.MergeFrom(from._impl_.fields_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Struct::CopyFrom(const Struct& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Struct)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Struct::IsInitialized() const {
+  return true;
+}
+
+void Struct::InternalSwap(Struct* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.fields_.InternalSwap(&other->_impl_.fields_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Struct::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[1]);
+}
+
+// ===================================================================
+
+class Value::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::Struct& struct_value(const Value* msg);
+  static const ::PROTOBUF_NAMESPACE_ID::ListValue& list_value(const Value* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::Struct&
+Value::_Internal::struct_value(const Value* msg) {
+  return *msg->_impl_.kind_.struct_value_;
+}
+const ::PROTOBUF_NAMESPACE_ID::ListValue&
+Value::_Internal::list_value(const Value* msg) {
+  return *msg->_impl_.kind_.list_value_;
+}
+void Value::set_allocated_struct_value(::PROTOBUF_NAMESPACE_ID::Struct* struct_value) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  clear_kind();
+  if (struct_value) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+      ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(struct_value);
+    if (message_arena != submessage_arena) {
+      struct_value = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, struct_value, submessage_arena);
+    }
+    set_has_struct_value();
+    _impl_.kind_.struct_value_ = struct_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.struct_value)
+}
+void Value::set_allocated_list_value(::PROTOBUF_NAMESPACE_ID::ListValue* list_value) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  clear_kind();
+  if (list_value) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+      ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(list_value);
+    if (message_arena != submessage_arena) {
+      list_value = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, list_value, submessage_arena);
+    }
+    set_has_list_value();
+    _impl_.kind_.list_value_ = list_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value)
+}
+Value::Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Value)
+}
+Value::Value(const Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.kind_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._oneof_case_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  clear_has_kind();
+  switch (from.kind_case()) {
+    case kNullValue: {
+      _this->_internal_set_null_value(from._internal_null_value());
+      break;
+    }
+    case kNumberValue: {
+      _this->_internal_set_number_value(from._internal_number_value());
+      break;
+    }
+    case kStringValue: {
+      _this->_internal_set_string_value(from._internal_string_value());
+      break;
+    }
+    case kBoolValue: {
+      _this->_internal_set_bool_value(from._internal_bool_value());
+      break;
+    }
+    case kStructValue: {
+      _this->_internal_mutable_struct_value()->::PROTOBUF_NAMESPACE_ID::Struct::MergeFrom(
+          from._internal_struct_value());
+      break;
+    }
+    case kListValue: {
+      _this->_internal_mutable_list_value()->::PROTOBUF_NAMESPACE_ID::ListValue::MergeFrom(
+          from._internal_list_value());
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Value)
+}
+
+inline void Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.kind_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._oneof_case_)*/{}
+  };
+  clear_has_kind();
+}
+
+Value::~Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  if (has_kind()) {
+    clear_kind();
+  }
+}
+
+void Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Value::clear_kind() {
+// @@protoc_insertion_point(one_of_clear_start:google.protobuf.Value)
+  switch (kind_case()) {
+    case kNullValue: {
+      // No need to clear
+      break;
+    }
+    case kNumberValue: {
+      // No need to clear
+      break;
+    }
+    case kStringValue: {
+      _impl_.kind_.string_value_.Destroy();
+      break;
+    }
+    case kBoolValue: {
+      // No need to clear
+      break;
+    }
+    case kStructValue: {
+      if (GetArenaForAllocation() == nullptr) {
+        delete _impl_.kind_.struct_value_;
+      }
+      break;
+    }
+    case kListValue: {
+      if (GetArenaForAllocation() == nullptr) {
+        delete _impl_.kind_.list_value_;
+      }
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  _impl_._oneof_case_[0] = KIND_NOT_SET;
+}
+
+
+void Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  clear_kind();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // .google.protobuf.NullValue null_value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_null_value(static_cast<::PROTOBUF_NAMESPACE_ID::NullValue>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      // double number_value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 17)) {
+          _internal_set_number_value(::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr));
+          ptr += sizeof(double);
+        } else
+          goto handle_unusual;
+        continue;
+      // string string_value = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_string_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Value.string_value"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bool bool_value = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          _internal_set_bool_value(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Struct struct_value = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr = ctx->ParseMessage(_internal_mutable_struct_value(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.ListValue list_value = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr = ctx->ParseMessage(_internal_mutable_list_value(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // .google.protobuf.NullValue null_value = 1;
+  if (_internal_has_null_value()) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      1, this->_internal_null_value(), target);
+  }
+
+  // double number_value = 2;
+  if (_internal_has_number_value()) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(2, this->_internal_number_value(), target);
+  }
+
+  // string string_value = 3;
+  if (_internal_has_string_value()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_string_value().data(), static_cast<int>(this->_internal_string_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Value.string_value");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_string_value(), target);
+  }
+
+  // bool bool_value = 4;
+  if (_internal_has_bool_value()) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(4, this->_internal_bool_value(), target);
+  }
+
+  // .google.protobuf.Struct struct_value = 5;
+  if (_internal_has_struct_value()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(5, _Internal::struct_value(this),
+        _Internal::struct_value(this).GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.ListValue list_value = 6;
+  if (_internal_has_list_value()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(6, _Internal::list_value(this),
+        _Internal::list_value(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
+  return target;
+}
+
+size_t Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  switch (kind_case()) {
+    // .google.protobuf.NullValue null_value = 1;
+    case kNullValue: {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_null_value());
+      break;
+    }
+    // double number_value = 2;
+    case kNumberValue: {
+      total_size += 1 + 8;
+      break;
+    }
+    // string string_value = 3;
+    case kStringValue: {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_string_value());
+      break;
+    }
+    // bool bool_value = 4;
+    case kBoolValue: {
+      total_size += 1 + 1;
+      break;
+    }
+    // .google.protobuf.Struct struct_value = 5;
+    case kStructValue: {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.kind_.struct_value_);
+      break;
+    }
+    // .google.protobuf.ListValue list_value = 6;
+    case kListValue: {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.kind_.list_value_);
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Value::GetClassData() const { return &_class_data_; }
+
+
+void Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Value*>(&to_msg);
+  auto& from = static_cast<const Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  switch (from.kind_case()) {
+    case kNullValue: {
+      _this->_internal_set_null_value(from._internal_null_value());
+      break;
+    }
+    case kNumberValue: {
+      _this->_internal_set_number_value(from._internal_number_value());
+      break;
+    }
+    case kStringValue: {
+      _this->_internal_set_string_value(from._internal_string_value());
+      break;
+    }
+    case kBoolValue: {
+      _this->_internal_set_bool_value(from._internal_bool_value());
+      break;
+    }
+    case kStructValue: {
+      _this->_internal_mutable_struct_value()->::PROTOBUF_NAMESPACE_ID::Struct::MergeFrom(
+          from._internal_struct_value());
+      break;
+    }
+    case kListValue: {
+      _this->_internal_mutable_list_value()->::PROTOBUF_NAMESPACE_ID::ListValue::MergeFrom(
+          from._internal_list_value());
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Value::CopyFrom(const Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Value::IsInitialized() const {
+  return true;
+}
+
+void Value::InternalSwap(Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.kind_, other->_impl_.kind_);
+  swap(_impl_._oneof_case_[0], other->_impl_._oneof_case_[0]);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[2]);
+}
+
+// ===================================================================
+
+class ListValue::_Internal {
+ public:
+};
+
+ListValue::ListValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ListValue)
+}
+ListValue::ListValue(const ListValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ListValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.values_){from._impl_.values_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ListValue)
+}
+
+inline void ListValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.values_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+ListValue::~ListValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ListValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ListValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.values_.~RepeatedPtrField();
+}
+
+void ListValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ListValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ListValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.values_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ListValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.Value values = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_values(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ListValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ListValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Value values = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_values_size()); i < n; i++) {
+    const auto& repfield = this->_internal_values(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
+  return target;
+}
+
+size_t ListValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ListValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Value values = 1;
+  total_size += 1UL * this->_internal_values_size();
+  for (const auto& msg : this->_impl_.values_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ListValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ListValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ListValue::GetClassData() const { return &_class_data_; }
+
+
+void ListValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ListValue*>(&to_msg);
+  auto& from = static_cast<const ListValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ListValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.values_.MergeFrom(from._impl_.values_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ListValue::CopyFrom(const ListValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ListValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ListValue::IsInitialized() const {
+  return true;
+}
+
+void ListValue::InternalSwap(ListValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.values_.InternalSwap(&other->_impl_.values_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ListValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[3]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Struct >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ListValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ListValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ListValue >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
new file mode 100644
index 0000000..134a1bd
--- /dev/null
+++ b/src/google/protobuf/struct.pb.h
@@ -0,0 +1,1177 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fstruct_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fstruct_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/map.h>  // IWYU pragma: export
+#include <google/protobuf/map_entry.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)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fstruct_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fstruct_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class ListValue;
+struct ListValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern ListValueDefaultTypeInternal _ListValue_default_instance_;
+class Struct;
+struct StructDefaultTypeInternal;
+PROTOBUF_EXPORT extern StructDefaultTypeInternal _Struct_default_instance_;
+class Struct_FieldsEntry_DoNotUse;
+struct Struct_FieldsEntry_DoNotUseDefaultTypeInternal;
+PROTOBUF_EXPORT extern Struct_FieldsEntry_DoNotUseDefaultTypeInternal _Struct_FieldsEntry_DoNotUse_default_instance_;
+class Value;
+struct ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern ValueDefaultTypeInternal _Value_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ListValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ListValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Struct* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Struct>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Value>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+enum NullValue : int {
+  NULL_VALUE = 0,
+  NullValue_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
+  NullValue_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool NullValue_IsValid(int value);
+constexpr NullValue NullValue_MIN = NULL_VALUE;
+constexpr NullValue NullValue_MAX = NULL_VALUE;
+constexpr int NullValue_ARRAYSIZE = NullValue_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* NullValue_descriptor();
+template<typename T>
+inline const std::string& NullValue_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, NullValue>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function NullValue_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    NullValue_descriptor(), enum_t_value);
+}
+inline bool NullValue_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, NullValue* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<NullValue>(
+    NullValue_descriptor(), name, value);
+}
+// ===================================================================
+
+class Struct_FieldsEntry_DoNotUse : public ::PROTOBUF_NAMESPACE_ID::internal::MapEntry<Struct_FieldsEntry_DoNotUse, 
+    std::string, ::PROTOBUF_NAMESPACE_ID::Value,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> {
+public:
+  typedef ::PROTOBUF_NAMESPACE_ID::internal::MapEntry<Struct_FieldsEntry_DoNotUse, 
+    std::string, ::PROTOBUF_NAMESPACE_ID::Value,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> SuperType;
+  Struct_FieldsEntry_DoNotUse();
+  explicit PROTOBUF_CONSTEXPR Struct_FieldsEntry_DoNotUse(
+      ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+  explicit Struct_FieldsEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena);
+  void MergeFrom(const Struct_FieldsEntry_DoNotUse& other);
+  static const Struct_FieldsEntry_DoNotUse* internal_default_instance() { return reinterpret_cast<const Struct_FieldsEntry_DoNotUse*>(&_Struct_FieldsEntry_DoNotUse_default_instance_); }
+  static bool ValidateKey(std::string* s) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast<int>(s->size()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE, "google.protobuf.Struct.FieldsEntry.key");
+ }
+  static bool ValidateValue(void*) { return true; }
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Struct final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Struct) */ {
+ public:
+  inline Struct() : Struct(nullptr) {}
+  ~Struct() override;
+  explicit PROTOBUF_CONSTEXPR Struct(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Struct(const Struct& from);
+  Struct(Struct&& from) noexcept
+    : Struct() {
+    *this = ::std::move(from);
+  }
+
+  inline Struct& operator=(const Struct& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Struct& operator=(Struct&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Struct& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Struct* internal_default_instance() {
+    return reinterpret_cast<const Struct*>(
+               &_Struct_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(Struct& a, Struct& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Struct* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Struct* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Struct* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Struct>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Struct& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Struct& from) {
+    Struct::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Struct* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Struct";
+  }
+  protected:
+  explicit Struct(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  private:
+  static void ArenaDtor(void* object);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFieldsFieldNumber = 1,
+  };
+  // map<string, .google.protobuf.Value> fields = 1;
+  int fields_size() const;
+  private:
+  int _internal_fields_size() const;
+  public:
+  void clear_fields();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+      _internal_fields() const;
+  ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+      _internal_mutable_fields();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+      fields() const;
+  ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+      mutable_fields();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Struct)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::MapField<
+        Struct_FieldsEntry_DoNotUse,
+        std::string, ::PROTOBUF_NAMESPACE_ID::Value,
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING,
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> fields_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Value) */ {
+ public:
+  inline Value() : Value(nullptr) {}
+  ~Value() override;
+  explicit PROTOBUF_CONSTEXPR Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Value(const Value& from);
+  Value(Value&& from) noexcept
+    : Value() {
+    *this = ::std::move(from);
+  }
+
+  inline Value& operator=(const Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Value& operator=(Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Value& default_instance() {
+    return *internal_default_instance();
+  }
+  enum KindCase {
+    kNullValue = 1,
+    kNumberValue = 2,
+    kStringValue = 3,
+    kBoolValue = 4,
+    kStructValue = 5,
+    kListValue = 6,
+    KIND_NOT_SET = 0,
+  };
+
+  static inline const Value* internal_default_instance() {
+    return reinterpret_cast<const Value*>(
+               &_Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Value& a, Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Value& from) {
+    Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Value";
+  }
+  protected:
+  explicit Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNullValueFieldNumber = 1,
+    kNumberValueFieldNumber = 2,
+    kStringValueFieldNumber = 3,
+    kBoolValueFieldNumber = 4,
+    kStructValueFieldNumber = 5,
+    kListValueFieldNumber = 6,
+  };
+  // .google.protobuf.NullValue null_value = 1;
+  bool has_null_value() const;
+  private:
+  bool _internal_has_null_value() const;
+  public:
+  void clear_null_value();
+  ::PROTOBUF_NAMESPACE_ID::NullValue null_value() const;
+  void set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::NullValue _internal_null_value() const;
+  void _internal_set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value);
+  public:
+
+  // double number_value = 2;
+  bool has_number_value() const;
+  private:
+  bool _internal_has_number_value() const;
+  public:
+  void clear_number_value();
+  double number_value() const;
+  void set_number_value(double value);
+  private:
+  double _internal_number_value() const;
+  void _internal_set_number_value(double value);
+  public:
+
+  // string string_value = 3;
+  bool has_string_value() const;
+  private:
+  bool _internal_has_string_value() const;
+  public:
+  void clear_string_value();
+  const std::string& string_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_string_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_string_value();
+  PROTOBUF_NODISCARD std::string* release_string_value();
+  void set_allocated_string_value(std::string* string_value);
+  private:
+  const std::string& _internal_string_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_string_value(const std::string& value);
+  std::string* _internal_mutable_string_value();
+  public:
+
+  // bool bool_value = 4;
+  bool has_bool_value() const;
+  private:
+  bool _internal_has_bool_value() const;
+  public:
+  void clear_bool_value();
+  bool bool_value() const;
+  void set_bool_value(bool value);
+  private:
+  bool _internal_bool_value() const;
+  void _internal_set_bool_value(bool value);
+  public:
+
+  // .google.protobuf.Struct struct_value = 5;
+  bool has_struct_value() const;
+  private:
+  bool _internal_has_struct_value() const;
+  public:
+  void clear_struct_value();
+  const ::PROTOBUF_NAMESPACE_ID::Struct& struct_value() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::Struct* release_struct_value();
+  ::PROTOBUF_NAMESPACE_ID::Struct* mutable_struct_value();
+  void set_allocated_struct_value(::PROTOBUF_NAMESPACE_ID::Struct* struct_value);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Struct& _internal_struct_value() const;
+  ::PROTOBUF_NAMESPACE_ID::Struct* _internal_mutable_struct_value();
+  public:
+  void unsafe_arena_set_allocated_struct_value(
+      ::PROTOBUF_NAMESPACE_ID::Struct* struct_value);
+  ::PROTOBUF_NAMESPACE_ID::Struct* unsafe_arena_release_struct_value();
+
+  // .google.protobuf.ListValue list_value = 6;
+  bool has_list_value() const;
+  private:
+  bool _internal_has_list_value() const;
+  public:
+  void clear_list_value();
+  const ::PROTOBUF_NAMESPACE_ID::ListValue& list_value() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::ListValue* release_list_value();
+  ::PROTOBUF_NAMESPACE_ID::ListValue* mutable_list_value();
+  void set_allocated_list_value(::PROTOBUF_NAMESPACE_ID::ListValue* list_value);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ListValue& _internal_list_value() const;
+  ::PROTOBUF_NAMESPACE_ID::ListValue* _internal_mutable_list_value();
+  public:
+  void unsafe_arena_set_allocated_list_value(
+      ::PROTOBUF_NAMESPACE_ID::ListValue* list_value);
+  ::PROTOBUF_NAMESPACE_ID::ListValue* unsafe_arena_release_list_value();
+
+  void clear_kind();
+  KindCase kind_case() const;
+  // @@protoc_insertion_point(class_scope:google.protobuf.Value)
+ private:
+  class _Internal;
+  void set_has_null_value();
+  void set_has_number_value();
+  void set_has_string_value();
+  void set_has_bool_value();
+  void set_has_struct_value();
+  void set_has_list_value();
+
+  inline bool has_kind() const;
+  inline void clear_has_kind();
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    union KindUnion {
+      constexpr KindUnion() : _constinit_{} {}
+        ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized _constinit_;
+      int null_value_;
+      double number_value_;
+      ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr string_value_;
+      bool bool_value_;
+      ::PROTOBUF_NAMESPACE_ID::Struct* struct_value_;
+      ::PROTOBUF_NAMESPACE_ID::ListValue* list_value_;
+    } kind_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    uint32_t _oneof_case_[1];
+
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ListValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ListValue) */ {
+ public:
+  inline ListValue() : ListValue(nullptr) {}
+  ~ListValue() override;
+  explicit PROTOBUF_CONSTEXPR ListValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ListValue(const ListValue& from);
+  ListValue(ListValue&& from) noexcept
+    : ListValue() {
+    *this = ::std::move(from);
+  }
+
+  inline ListValue& operator=(const ListValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ListValue& operator=(ListValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ListValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ListValue* internal_default_instance() {
+    return reinterpret_cast<const ListValue*>(
+               &_ListValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(ListValue& a, ListValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ListValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ListValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ListValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ListValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ListValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ListValue& from) {
+    ListValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ListValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ListValue";
+  }
+  protected:
+  explicit ListValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValuesFieldNumber = 1,
+  };
+  // repeated .google.protobuf.Value values = 1;
+  int values_size() const;
+  private:
+  int _internal_values_size() const;
+  public:
+  void clear_values();
+  ::PROTOBUF_NAMESPACE_ID::Value* mutable_values(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >*
+      mutable_values();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Value& _internal_values(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Value* _internal_add_values();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Value& values(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Value* add_values();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >&
+      values() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ListValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value > values_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// Struct
+
+// map<string, .google.protobuf.Value> fields = 1;
+inline int Struct::_internal_fields_size() const {
+  return _impl_.fields_.size();
+}
+inline int Struct::fields_size() const {
+  return _internal_fields_size();
+}
+inline void Struct::clear_fields() {
+  _impl_.fields_.Clear();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+Struct::_internal_fields() const {
+  return _impl_.fields_.GetMap();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+Struct::fields() const {
+  // @@protoc_insertion_point(field_map:google.protobuf.Struct.fields)
+  return _internal_fields();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+Struct::_internal_mutable_fields() {
+  return _impl_.fields_.MutableMap();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+Struct::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_map:google.protobuf.Struct.fields)
+  return _internal_mutable_fields();
+}
+
+// -------------------------------------------------------------------
+
+// Value
+
+// .google.protobuf.NullValue null_value = 1;
+inline bool Value::_internal_has_null_value() const {
+  return kind_case() == kNullValue;
+}
+inline bool Value::has_null_value() const {
+  return _internal_has_null_value();
+}
+inline void Value::set_has_null_value() {
+  _impl_._oneof_case_[0] = kNullValue;
+}
+inline void Value::clear_null_value() {
+  if (_internal_has_null_value()) {
+    _impl_.kind_.null_value_ = 0;
+    clear_has_kind();
+  }
+}
+inline ::PROTOBUF_NAMESPACE_ID::NullValue Value::_internal_null_value() const {
+  if (_internal_has_null_value()) {
+    return static_cast< ::PROTOBUF_NAMESPACE_ID::NullValue >(_impl_.kind_.null_value_);
+  }
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::NullValue >(0);
+}
+inline ::PROTOBUF_NAMESPACE_ID::NullValue Value::null_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.null_value)
+  return _internal_null_value();
+}
+inline void Value::_internal_set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value) {
+  if (!_internal_has_null_value()) {
+    clear_kind();
+    set_has_null_value();
+  }
+  _impl_.kind_.null_value_ = value;
+}
+inline void Value::set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value) {
+  _internal_set_null_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.null_value)
+}
+
+// double number_value = 2;
+inline bool Value::_internal_has_number_value() const {
+  return kind_case() == kNumberValue;
+}
+inline bool Value::has_number_value() const {
+  return _internal_has_number_value();
+}
+inline void Value::set_has_number_value() {
+  _impl_._oneof_case_[0] = kNumberValue;
+}
+inline void Value::clear_number_value() {
+  if (_internal_has_number_value()) {
+    _impl_.kind_.number_value_ = 0;
+    clear_has_kind();
+  }
+}
+inline double Value::_internal_number_value() const {
+  if (_internal_has_number_value()) {
+    return _impl_.kind_.number_value_;
+  }
+  return 0;
+}
+inline void Value::_internal_set_number_value(double value) {
+  if (!_internal_has_number_value()) {
+    clear_kind();
+    set_has_number_value();
+  }
+  _impl_.kind_.number_value_ = value;
+}
+inline double Value::number_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.number_value)
+  return _internal_number_value();
+}
+inline void Value::set_number_value(double value) {
+  _internal_set_number_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.number_value)
+}
+
+// string string_value = 3;
+inline bool Value::_internal_has_string_value() const {
+  return kind_case() == kStringValue;
+}
+inline bool Value::has_string_value() const {
+  return _internal_has_string_value();
+}
+inline void Value::set_has_string_value() {
+  _impl_._oneof_case_[0] = kStringValue;
+}
+inline void Value::clear_string_value() {
+  if (_internal_has_string_value()) {
+    _impl_.kind_.string_value_.Destroy();
+    clear_has_kind();
+  }
+}
+inline const std::string& Value::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.string_value)
+  return _internal_string_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline void Value::set_string_value(ArgT0&& arg0, ArgT... args) {
+  if (!_internal_has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitDefault();
+  }
+  _impl_.kind_.string_value_.Set( static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
+}
+inline std::string* Value::mutable_string_value() {
+  std::string* _s = _internal_mutable_string_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.string_value)
+  return _s;
+}
+inline const std::string& Value::_internal_string_value() const {
+  if (_internal_has_string_value()) {
+    return _impl_.kind_.string_value_.Get();
+  }
+  return ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited();
+}
+inline void Value::_internal_set_string_value(const std::string& value) {
+  if (!_internal_has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitDefault();
+  }
+  _impl_.kind_.string_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Value::_internal_mutable_string_value() {
+  if (!_internal_has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitDefault();
+  }
+  return _impl_.kind_.string_value_.Mutable(      GetArenaForAllocation());
+}
+inline std::string* Value::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value)
+  if (_internal_has_string_value()) {
+    clear_has_kind();
+    return _impl_.kind_.string_value_.Release();
+  } else {
+    return nullptr;
+  }
+}
+inline void Value::set_allocated_string_value(std::string* string_value) {
+  if (has_kind()) {
+    clear_kind();
+  }
+  if (string_value != nullptr) {
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitAllocated(string_value, GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.string_value)
+}
+
+// bool bool_value = 4;
+inline bool Value::_internal_has_bool_value() const {
+  return kind_case() == kBoolValue;
+}
+inline bool Value::has_bool_value() const {
+  return _internal_has_bool_value();
+}
+inline void Value::set_has_bool_value() {
+  _impl_._oneof_case_[0] = kBoolValue;
+}
+inline void Value::clear_bool_value() {
+  if (_internal_has_bool_value()) {
+    _impl_.kind_.bool_value_ = false;
+    clear_has_kind();
+  }
+}
+inline bool Value::_internal_bool_value() const {
+  if (_internal_has_bool_value()) {
+    return _impl_.kind_.bool_value_;
+  }
+  return false;
+}
+inline void Value::_internal_set_bool_value(bool value) {
+  if (!_internal_has_bool_value()) {
+    clear_kind();
+    set_has_bool_value();
+  }
+  _impl_.kind_.bool_value_ = value;
+}
+inline bool Value::bool_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.bool_value)
+  return _internal_bool_value();
+}
+inline void Value::set_bool_value(bool value) {
+  _internal_set_bool_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.bool_value)
+}
+
+// .google.protobuf.Struct struct_value = 5;
+inline bool Value::_internal_has_struct_value() const {
+  return kind_case() == kStructValue;
+}
+inline bool Value::has_struct_value() const {
+  return _internal_has_struct_value();
+}
+inline void Value::set_has_struct_value() {
+  _impl_._oneof_case_[0] = kStructValue;
+}
+inline void Value::clear_struct_value() {
+  if (_internal_has_struct_value()) {
+    if (GetArenaForAllocation() == nullptr) {
+      delete _impl_.kind_.struct_value_;
+    }
+    clear_has_kind();
+  }
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::release_struct_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value)
+  if (_internal_has_struct_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::Struct* temp = _impl_.kind_.struct_value_;
+    if (GetArenaForAllocation() != nullptr) {
+      temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+    }
+    _impl_.kind_.struct_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Struct& Value::_internal_struct_value() const {
+  return _internal_has_struct_value()
+      ? *_impl_.kind_.struct_value_
+      : reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::Struct&>(::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Struct& Value::struct_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.struct_value)
+  return _internal_struct_value();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::unsafe_arena_release_struct_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.Value.struct_value)
+  if (_internal_has_struct_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::Struct* temp = _impl_.kind_.struct_value_;
+    _impl_.kind_.struct_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline void Value::unsafe_arena_set_allocated_struct_value(::PROTOBUF_NAMESPACE_ID::Struct* struct_value) {
+  clear_kind();
+  if (struct_value) {
+    set_has_struct_value();
+    _impl_.kind_.struct_value_ = struct_value;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Value.struct_value)
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::_internal_mutable_struct_value() {
+  if (!_internal_has_struct_value()) {
+    clear_kind();
+    set_has_struct_value();
+    _impl_.kind_.struct_value_ = CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct >(GetArenaForAllocation());
+  }
+  return _impl_.kind_.struct_value_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::mutable_struct_value() {
+  ::PROTOBUF_NAMESPACE_ID::Struct* _msg = _internal_mutable_struct_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.struct_value)
+  return _msg;
+}
+
+// .google.protobuf.ListValue list_value = 6;
+inline bool Value::_internal_has_list_value() const {
+  return kind_case() == kListValue;
+}
+inline bool Value::has_list_value() const {
+  return _internal_has_list_value();
+}
+inline void Value::set_has_list_value() {
+  _impl_._oneof_case_[0] = kListValue;
+}
+inline void Value::clear_list_value() {
+  if (_internal_has_list_value()) {
+    if (GetArenaForAllocation() == nullptr) {
+      delete _impl_.kind_.list_value_;
+    }
+    clear_has_kind();
+  }
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::release_list_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value)
+  if (_internal_has_list_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::ListValue* temp = _impl_.kind_.list_value_;
+    if (GetArenaForAllocation() != nullptr) {
+      temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+    }
+    _impl_.kind_.list_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ListValue& Value::_internal_list_value() const {
+  return _internal_has_list_value()
+      ? *_impl_.kind_.list_value_
+      : reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::ListValue&>(::PROTOBUF_NAMESPACE_ID::_ListValue_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ListValue& Value::list_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.list_value)
+  return _internal_list_value();
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::unsafe_arena_release_list_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.Value.list_value)
+  if (_internal_has_list_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::ListValue* temp = _impl_.kind_.list_value_;
+    _impl_.kind_.list_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline void Value::unsafe_arena_set_allocated_list_value(::PROTOBUF_NAMESPACE_ID::ListValue* list_value) {
+  clear_kind();
+  if (list_value) {
+    set_has_list_value();
+    _impl_.kind_.list_value_ = list_value;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Value.list_value)
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::_internal_mutable_list_value() {
+  if (!_internal_has_list_value()) {
+    clear_kind();
+    set_has_list_value();
+    _impl_.kind_.list_value_ = CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ListValue >(GetArenaForAllocation());
+  }
+  return _impl_.kind_.list_value_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::mutable_list_value() {
+  ::PROTOBUF_NAMESPACE_ID::ListValue* _msg = _internal_mutable_list_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.list_value)
+  return _msg;
+}
+
+inline bool Value::has_kind() const {
+  return kind_case() != KIND_NOT_SET;
+}
+inline void Value::clear_has_kind() {
+  _impl_._oneof_case_[0] = KIND_NOT_SET;
+}
+inline Value::KindCase Value::kind_case() const {
+  return Value::KindCase(_impl_._oneof_case_[0]);
+}
+// -------------------------------------------------------------------
+
+// ListValue
+
+// repeated .google.protobuf.Value values = 1;
+inline int ListValue::_internal_values_size() const {
+  return _impl_.values_.size();
+}
+inline int ListValue::values_size() const {
+  return _internal_values_size();
+}
+inline void ListValue::clear_values() {
+  _impl_.values_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Value* ListValue::mutable_values(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ListValue.values)
+  return _impl_.values_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >*
+ListValue::mutable_values() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ListValue.values)
+  return &_impl_.values_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Value& ListValue::_internal_values(int index) const {
+  return _impl_.values_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Value& ListValue::values(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ListValue.values)
+  return _internal_values(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Value* ListValue::_internal_add_values() {
+  return _impl_.values_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Value* ListValue::add_values() {
+  ::PROTOBUF_NAMESPACE_ID::Value* _add = _internal_add_values();
+  // @@protoc_insertion_point(field_add:google.protobuf.ListValue.values)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >&
+ListValue::values() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values)
+  return _impl_.values_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::NullValue> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::NullValue>() {
+  return ::PROTOBUF_NAMESPACE_ID::NullValue_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fstruct_2eproto
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
new file mode 100644
index 0000000..0ac843c
--- /dev/null
+++ b/src/google/protobuf/struct.proto
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/structpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "StructProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// `Struct` represents a structured data value, consisting of fields
+// which map to dynamically typed values. In some languages, `Struct`
+// might be supported by a native representation. For example, in
+// scripting languages like JS a struct is represented as an
+// object. The details of that representation are described together
+// with the proto support for the language.
+//
+// The JSON representation for `Struct` is JSON object.
+message Struct {
+  // Unordered map of dynamically typed values.
+  map<string, Value> fields = 1;
+}
+
+// `Value` represents a dynamically typed value which can be either
+// null, a number, a string, a boolean, a recursive struct value, or a
+// list of values. A producer of value is expected to set one of these
+// variants. Absence of any variant indicates an error.
+//
+// The JSON representation for `Value` is JSON value.
+message Value {
+  // The kind of value.
+  oneof kind {
+    // Represents a null value.
+    NullValue null_value = 1;
+    // Represents a double value.
+    double number_value = 2;
+    // Represents a string value.
+    string string_value = 3;
+    // Represents a boolean value.
+    bool bool_value = 4;
+    // Represents a structured value.
+    Struct struct_value = 5;
+    // Represents a repeated `Value`.
+    ListValue list_value = 6;
+  }
+}
+
+// `NullValue` is a singleton enumeration to represent the null value for the
+// `Value` type union.
+//
+//  The JSON representation for `NullValue` is JSON `null`.
+enum NullValue {
+  // Null value.
+  NULL_VALUE = 0;
+}
+
+// `ListValue` is a wrapper around a repeated field of values.
+//
+// The JSON representation for `ListValue` is JSON array.
+message ListValue {
+  // Repeated field of dynamically typed values.
+  repeated Value values = 1;
+}
diff --git a/src/google/protobuf/stubs/bytestream.cc b/src/google/protobuf/stubs/bytestream.cc
new file mode 100644
index 0000000..980d6f6
--- /dev/null
+++ b/src/google/protobuf/stubs/bytestream.cc
@@ -0,0 +1,194 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/stubs/bytestream.h>
+
+#include <string.h>
+#include <algorithm>
+
+#include <google/protobuf/stubs/logging.h>
+
+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_ = nullptr;
+  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();
+  return StringPiece(piece.data(), std::min(piece.size(), limit_));
+}
+
+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..c7a48de
--- /dev/null
+++ b/src/google/protobuf/stubs/bytestream.h
@@ -0,0 +1,351 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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>
+
+#include <google/protobuf/port_def.inc>
+
+class CordByteSink;
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+// An abstract interface for an object that consumes a sequence of bytes. This
+// interface offers a way to append data as well as a Flush() function.
+//
+// Example:
+//
+//   string my_data;
+//   ...
+//   ByteSink* sink = ...
+//   sink->Append(my_data.data(), my_data.size());
+//   sink->Flush();
+//
+class PROTOBUF_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 implementation 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 PROTOBUF_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 PROTOBUF_EXPORT UncheckedArrayByteSink : public ByteSink {
+ public:
+  explicit UncheckedArrayByteSink(char* dest) : dest_(dest) {}
+  virtual void Append(const char* data, size_t n) override;
+
+  // 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 PROTOBUF_EXPORT CheckedArrayByteSink : public ByteSink {
+ public:
+  CheckedArrayByteSink(char* outbuf, size_t capacity);
+  virtual void Append(const char* bytes, size_t n) override;
+
+  // 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 accommodate 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 PROTOBUF_EXPORT GrowingArrayByteSink : public strings::ByteSink {
+ public:
+  explicit GrowingArrayByteSink(size_t estimated_size);
+  virtual ~GrowingArrayByteSink();
+  virtual void Append(const char* bytes, size_t n) override;
+
+  // 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 PROTOBUF_EXPORT StringByteSink : public ByteSink {
+ public:
+  explicit StringByteSink(std::string* dest) : dest_(dest) {}
+  virtual void Append(const char* data, size_t n) override;
+
+ private:
+  std::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 PROTOBUF_EXPORT NullByteSink : public ByteSink {
+ public:
+  NullByteSink() {}
+  void Append(const char* /*data*/, size_t /*n*/) override {}
+
+ 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 PROTOBUF_EXPORT ArrayByteSource : public ByteSource {
+ public:
+  explicit ArrayByteSource(StringPiece s) : input_(s) {}
+
+  virtual size_t Available() const override;
+  virtual StringPiece Peek() override;
+  virtual void Skip(size_t n) override;
+
+ 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 PROTOBUF_EXPORT LimitByteSource : public ByteSource {
+ public:
+  // Returns at most "limit" bytes from "source".
+  LimitByteSource(ByteSource* source, size_t limit);
+
+  virtual size_t Available() const override;
+  virtual StringPiece Peek() override;
+  virtual void Skip(size_t n) override;
+
+  // 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) override;
+
+ private:
+  ByteSource* source_;
+  size_t limit_;
+};
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..cb11825
--- /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);
+  std::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);
+  std::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());
+
+  {
+    std::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());
+  }
+
+  {
+    std::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);
+  std::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(std::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) {
+  std::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..43d546d
--- /dev/null
+++ b/src/google/protobuf/stubs/callback.h
@@ -0,0 +1,583 @@
+#ifndef GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
+#define GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
+
+#include <type_traits>
+
+#include <google/protobuf/stubs/macros.h>
+
+#include <google/protobuf/port_def.inc>
+
+// ===================================================================
+// 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(std::string s);
+//   NewCallback(&Foo, "foo");          // WON'T WORK:  const char* != string
+//   NewCallback(&Foo, std::string("foo"));  // WORKS
+// Also note that the arguments cannot be references:
+//   void Foo(const std::string& s);
+//   std::string my_str;
+//   NewCallback(&Foo, my_str);  // WON'T WORK:  Can't use references.
+// However, correctly-typed pointers will work just fine.
+class PROTOBUF_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 PROTOBUF_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 PROTOBUF_EXPORT ResultCallback2 {
+ public:
+  ResultCallback2() {}
+  virtual ~ResultCallback2() {}
+
+  virtual R Run(A1,A2) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback2);
+};
+
+namespace internal {
+
+class PROTOBUF_EXPORT FunctionClosure0 : public Closure {
+ public:
+  typedef void (*FunctionType)();
+
+  FunctionClosure0(FunctionType function, bool self_deleting)
+    : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionClosure0();
+
+  void Run() override {
+    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() override {
+    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() override {
+    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() override {
+    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() override {
+    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() override {
+    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() override {
+    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() override {
+    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) override {
+    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) override {
+    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 std::remove_reference<T>::type base_type;
+  typedef const base_type& type;
+};
+
+template<typename R, typename T>
+class MethodResultCallback_0_0 : public ResultCallback<R> {
+ public:
+  typedef R (T::*MethodType)();
+  MethodResultCallback_0_0(T* object, MethodType method, bool self_deleting)
+      : object_(object),
+        method_(method),
+        self_deleting_(self_deleting) {}
+  ~MethodResultCallback_0_0() {}
+
+  R Run() {
+    bool needs_delete = self_deleting_;
+    R result = (object_->*method_)();
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  T* object_;
+  MethodType method_;
+  bool self_deleting_;
+};
+
+template <typename R, typename T, typename P1, typename P2, typename P3,
+          typename P4, typename P5, typename P6, typename A1, typename A2>
+class MethodResultCallback_6_2 : public ResultCallback2<R, A1, A2> {
+ public:
+  typedef R (T::*MethodType)(P1, P2, P3, P4, P5, P6, A1, A2);
+  MethodResultCallback_6_2(T* object, MethodType method, bool self_deleting,
+                           P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
+      : object_(object),
+        method_(method),
+        self_deleting_(self_deleting),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4),
+        p5_(p5),
+        p6_(p6) {}
+  ~MethodResultCallback_6_2() {}
+
+  R Run(A1 a1, A2 a2) override {
+    bool needs_delete = self_deleting_;
+    R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, p6_, a1, a2);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  T* object_;
+  MethodType method_;
+  bool self_deleting_;
+  typename std::remove_reference<P1>::type p1_;
+  typename std::remove_reference<P2>::type p2_;
+  typename std::remove_reference<P3>::type p3_;
+  typename std::remove_reference<P4>::type p4_;
+  typename std::remove_reference<P5>::type p5_;
+  typename std::remove_reference<P6>::type p6_;
+};
+
+}  // 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);
+}
+
+// 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_0_0
+template <typename R, typename T1, typename T2>
+inline ResultCallback<R>* NewPermanentCallback(
+    T1* object, R (T2::*function)()) {
+  return new internal::MethodResultCallback_0_0<R, T1>(object, function, false);
+}
+
+// See MethodResultCallback_6_2
+template <typename R, typename T, typename P1, typename P2, typename P3,
+          typename P4, typename P5, typename P6, typename A1, typename A2>
+inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
+    T* object, R (T::*function)(P1, P2, P3, P4, P5, P6, 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,
+    typename internal::InternalConstRef<P6>::type p6) {
+  return new internal::MethodResultCallback_6_2<R, T, P1, P2, P3, P4, P5, P6,
+                                                A1, A2>(object, function, false,
+                                                        p1, p2, p3, p4, p5, p6);
+}
+
+// A function which does nothing.  Useful for creating no-op callbacks, e.g.:
+//   Closure* nothing = NewCallback(&DoNothing);
+void PROTOBUF_EXPORT DoNothing();
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
diff --git a/src/google/protobuf/stubs/casts.h b/src/google/protobuf/stubs/casts.h
new file mode 100644
index 0000000..ad29dac
--- /dev/null
+++ b/src/google/protobuf/stubs/casts.h
@@ -0,0 +1,138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_CASTS_H__
+#define GOOGLE_PROTOBUF_CASTS_H__
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+#include <type_traits>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertible to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed.  When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo?  It
+// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
+// when you downcast, you should use this macro.  In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not).  In normal mode, we do the efficient static_cast<>
+// instead.  Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+//    This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {                   // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, To>(0);
+  }
+
+#if !defined(NDEBUG) && PROTOBUF_RTTI
+  assert(f == nullptr || dynamic_cast<To>(f) != nullptr);  // RTTI: debug mode only!
+#endif
+  return static_cast<To>(f);
+}
+
+template<typename To, typename From>    // use like this: down_cast<T&>(foo);
+inline To down_cast(From& f) {
+  typedef typename std::remove_reference<To>::type* ToAsPointer;
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, ToAsPointer>(0);
+  }
+
+#if !defined(NDEBUG) && PROTOBUF_RTTI
+  // RTTI: debug mode only!
+  assert(dynamic_cast<ToAsPointer>(&f) != nullptr);
+#endif
+  return *static_cast<ToAsPointer>(&f);
+}
+
+template<typename To, typename From>
+inline To bit_cast(const From& from) {
+  static_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
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_CASTS_H__
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
new file mode 100644
index 0000000..e0a807f
--- /dev/null
+++ b/src/google/protobuf/stubs/common.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/common.h>
+
+#include <atomic>
+#include <errno.h>
+#include <sstream>
+#include <stdio.h>
+#include <vector>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN  // We only need minimal includes
+#endif
+#include <windows.h>
+#define snprintf _snprintf    // see comment in strutil.cc
+#endif
+#if defined(__ANDROID__)
+#include <android/log.h>
+#endif
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/once.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 <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+void VerifyVersion(int headerVersion,
+                   int minLibraryVersion,
+                   const char* filename) {
+  if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) {
+    // Library is too old for headers.
+    GOOGLE_LOG(FATAL)
+      << "This program requires version " << VersionString(minLibraryVersion)
+      << " of the Protocol Buffer runtime library, but the installed version "
+         "is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ".  Please update "
+         "your library.  If you compiled the program yourself, make sure that "
+         "your headers are from the same version of Protocol Buffers as your "
+         "link-time library.  (Version verification failed in \""
+      << filename << "\".)";
+  }
+  if (headerVersion < kMinHeaderVersionForLibrary) {
+    // Headers are too old for library.
+    GOOGLE_LOG(FATAL)
+      << "This program was compiled against version "
+      << VersionString(headerVersion) << " of the Protocol Buffer runtime "
+         "library, which is not compatible with the installed version ("
+      << VersionString(GOOGLE_PROTOBUF_VERSION) <<  ").  Contact the program "
+         "author for an update.  If you compiled the program yourself, make "
+         "sure that your headers are from the same version of Protocol Buffers "
+         "as your link-time library.  (Version verification failed in \""
+      << filename << "\".)";
+  }
+}
+
+std::string VersionString(int version) {
+  int major = version / 1000000;
+  int minor = (version / 1000) % 1000;
+  int micro = version % 1000;
+
+  // 128 bytes should always be enough, but we use snprintf() anyway to be
+  // safe.
+  char buffer[128];
+  snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro);
+
+  // Guard against broken MSVC snprintf().
+  buffer[sizeof(buffer)-1] = '\0';
+
+  return buffer;
+}
+
+}  // namespace internal
+
+// ===================================================================
+// emulates google3/base/logging.cc
+
+// If the minimum logging level is not set, we default to logging messages for
+// all levels.
+#ifndef GOOGLE_PROTOBUF_MIN_LOG_LEVEL
+#define GOOGLE_PROTOBUF_MIN_LOG_LEVEL LOGLEVEL_INFO
+#endif
+
+namespace internal {
+
+#if defined(__ANDROID__)
+inline void DefaultLogHandler(LogLevel level, const char* filename, int line,
+                              const std::string& message) {
+  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");
+  }
+}
+
+#else
+void DefaultLogHandler(LogLevel level, const char* filename, int line,
+                       const std::string& message) {
+  if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
+    return;
+  }
+  static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
+
+  // We use fprintf() instead of cerr because we want this to work at static
+  // initialization time.
+  fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
+          level_names[level], filename, line, message.c_str());
+  fflush(stderr);  // Needed on MSVC.
+}
+#endif
+
+void NullLogHandler(LogLevel /* level */, const char* /* filename */,
+                    int /* line */, const std::string& /* message */) {
+  // Nothing.
+}
+
+static LogHandler* log_handler_ = &DefaultLogHandler;
+static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0);
+
+LogMessage& LogMessage::operator<<(const std::string& value) {
+  message_ += value;
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const char* value) {
+  message_ += value;
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const StringPiece& value) {
+  message_ += value.ToString();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const util::Status& status) {
+  message_ += status.ToString();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const uint128& value) {
+  std::ostringstream str;
+  str << value;
+  message_ += str.str();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(char value) {
+  return *this << StringPiece(&value, 1);
+}
+
+LogMessage& LogMessage::operator<<(void* value) {
+  StrAppend(&message_, strings::Hex(reinterpret_cast<uintptr_t>(value)));
+  return *this;
+}
+
+#undef DECLARE_STREAM_OPERATOR
+#define DECLARE_STREAM_OPERATOR(TYPE)              \
+  LogMessage& LogMessage::operator<<(TYPE value) { \
+    StrAppend(&message_, value);                   \
+    return *this;                                  \
+  }
+
+DECLARE_STREAM_OPERATOR(int)
+DECLARE_STREAM_OPERATOR(unsigned int)
+DECLARE_STREAM_OPERATOR(long)           // NOLINT(runtime/int)
+DECLARE_STREAM_OPERATOR(unsigned long)  // NOLINT(runtime/int)
+DECLARE_STREAM_OPERATOR(double)
+DECLARE_STREAM_OPERATOR(long long)           // NOLINT(runtime/int)
+DECLARE_STREAM_OPERATOR(unsigned long long)  // NOLINT(runtime/int)
+#undef DECLARE_STREAM_OPERATOR
+
+LogMessage::LogMessage(LogLevel level, const char* filename, int line)
+  : level_(level), filename_(filename), line_(line) {}
+LogMessage::~LogMessage() {}
+
+void LogMessage::Finish() {
+  bool suppress = false;
+
+  if (level_ != LOGLEVEL_FATAL) {
+    suppress = log_silencer_count_ > 0;
+  }
+
+  if (!suppress) {
+    log_handler_(level_, filename_, line_, message_);
+  }
+
+  if (level_ == LOGLEVEL_FATAL) {
+#if PROTOBUF_USE_EXCEPTIONS
+    throw FatalException(filename_, line_, message_);
+#else
+    abort();
+#endif
+  }
+}
+
+void LogFinisher::operator=(LogMessage& other) {
+  other.Finish();
+}
+
+}  // namespace internal
+
+LogHandler* SetLogHandler(LogHandler* new_func) {
+  LogHandler* old = internal::log_handler_;
+  if (old == &internal::NullLogHandler) {
+    old = nullptr;
+  }
+  if (new_func == nullptr) {
+    internal::log_handler_ = &internal::NullLogHandler;
+  } else {
+    internal::log_handler_ = new_func;
+  }
+  return old;
+}
+
+LogSilencer::LogSilencer() {
+  ++internal::log_silencer_count_;
+};
+
+LogSilencer::~LogSilencer() {
+  --internal::log_silencer_count_;
+};
+
+// ===================================================================
+// emulates google3/base/callback.cc
+
+Closure::~Closure() {}
+
+namespace internal { FunctionClosure0::~FunctionClosure0() {} }
+
+void DoNothing() {}
+
+// ===================================================================
+// emulates google3/util/endian/endian.h
+//
+// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in
+// google/protobuf/io/coded_stream.h and therefore can not be used here.
+// Maybe move that macro definition here in the future.
+uint32_t ghtonl(uint32_t x) {
+  union {
+    uint32_t result;
+    uint8_t result_array[4];
+  };
+  result_array[0] = static_cast<uint8_t>(x >> 24);
+  result_array[1] = static_cast<uint8_t>((x >> 16) & 0xFF);
+  result_array[2] = static_cast<uint8_t>((x >> 8) & 0xFF);
+  result_array[3] = static_cast<uint8_t>(x & 0xFF);
+  return result;
+}
+
+#if PROTOBUF_USE_EXCEPTIONS
+FatalException::~FatalException() throw() {}
+
+const char* FatalException::what() const throw() {
+  return message_.c_str();
+}
+#endif
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
new file mode 100644
index 0000000..8a1db2b
--- /dev/null
+++ b/src/google/protobuf/stubs/common.h
@@ -0,0 +1,197 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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) and others
+//
+// Contains basic types and utilities used by the rest of the library.
+
+#ifndef GOOGLE_PROTOBUF_COMMON_H__
+#define GOOGLE_PROTOBUF_COMMON_H__
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/platform_macros.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+#ifndef PROTOBUF_USE_EXCEPTIONS
+#if defined(_MSC_VER) && defined(_CPPUNWIND)
+  #define PROTOBUF_USE_EXCEPTIONS 1
+#elif defined(__EXCEPTIONS)
+  #define PROTOBUF_USE_EXCEPTIONS 1
+#else
+  #define PROTOBUF_USE_EXCEPTIONS 0
+#endif
+#endif
+
+#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
+
+#include <google/protobuf/port_def.inc>
+
+namespace std {}
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Some of these constants are macros rather than const ints so that they can
+// be used in #if directives.
+
+// The current version, represented as a single integer to make comparison
+// easier:  major * 10^6 + minor * 10^3 + micro
+#define GOOGLE_PROTOBUF_VERSION 3021009
+
+// A suffix string for alpha, beta or rc releases. Empty for stable releases.
+#define GOOGLE_PROTOBUF_VERSION_SUFFIX ""
+
+// The minimum header version which works with the current version of
+// the library.  This constant should only be used by protoc's C++ code
+// generator.
+static const int kMinHeaderVersionForLibrary = 3021000;
+
+// The minimum protoc version which works with the current version of the
+// headers.
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3021000
+
+// The minimum header version which works with the current version of
+// protoc.  This constant should only be used in VerifyVersion().
+static const int kMinHeaderVersionForProtoc = 3021000;
+
+// Verifies that the headers and libraries are compatible.  Use the macro
+// below to call this.
+void PROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion,
+                                   const char* filename);
+
+// Converts a numeric version number to a string.
+std::string PROTOBUF_EXPORT VersionString(int version);
+
+}  // namespace internal
+
+// Place this macro in your main() function (or somewhere before you attempt
+// to use the protobuf library) to verify that the version you link against
+// matches the headers you compiled against.  If a version mismatch is
+// detected, the process will abort.
+#define GOOGLE_PROTOBUF_VERIFY_VERSION                                    \
+  ::google::protobuf::internal::VerifyVersion(                            \
+    GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION,         \
+    __FILE__)
+
+
+// ===================================================================
+// from google3/util/utf8/public/unilib.h
+
+namespace internal {
+
+// Checks if the buffer contains structurally-valid UTF-8.  Implemented in
+// structurally_valid.cc.
+PROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
+
+inline bool IsStructurallyValidUTF8(StringPiece str) {
+  return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
+}
+
+// Returns initial number of bytes of structurally valid UTF-8.
+PROTOBUF_EXPORT int UTF8SpnStructurallyValid(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.
+//
+PROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid(StringPiece str, char* dst,
+                                                    char replace_char);
+
+}  // namespace internal
+
+// This lives in message_lite.h now, but we leave this here for any users that
+// #include common.h and not message_lite.h.
+PROTOBUF_EXPORT void ShutdownProtobufLibrary();
+
+namespace internal {
+
+// Strongly references the given variable such that the linker will be forced
+// to pull in this variable's translation unit.
+template <typename T>
+void StrongReference(const T& var) {
+  auto volatile unused = &var;
+  (void)&unused;  // Use address to avoid an extra load of "unused".
+}
+
+}  // namespace internal
+
+#if PROTOBUF_USE_EXCEPTIONS
+class FatalException : public std::exception {
+ public:
+  FatalException(const char* filename, int line, const std::string& message)
+      : filename_(filename), line_(line), message_(message) {}
+  virtual ~FatalException() throw();
+
+  const char* what() const throw() override;
+
+  const char* filename() const { return filename_; }
+  int line() const { return line_; }
+  const std::string& message() const { return message_; }
+
+ private:
+  const char* filename_;
+  const int line_;
+  const std::string message_;
+};
+#endif
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMMON_H__
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
new file mode 100644
index 0000000..c55e452
--- /dev/null
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -0,0 +1,358 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <vector>
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/casts.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>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+// TODO(kenton):  More tests.
+
+#ifdef PACKAGE_VERSION  // only defined when using automake, not MSVC
+
+TEST(VersionTest, VersionMatchesConfig) {
+  // Verify that the version string specified in config.h matches the one
+  // in common.h.  The config.h version is a string which may have a suffix
+  // like "beta" or "rc1", so we remove that.
+  std::string version = PACKAGE_VERSION;
+  int pos = 0;
+  while (pos < version.size() &&
+         (ascii_isdigit(version[pos]) || version[pos] == '.')) {
+    ++pos;
+  }
+  version.erase(pos);
+
+  EXPECT_EQ(version, internal::VersionString(GOOGLE_PROTOBUF_VERSION));
+}
+
+#endif  // PACKAGE_VERSION
+
+TEST(CommonTest, IntMinMaxConstants) {
+  // kint32min was declared incorrectly in the first release of protobufs.
+  // Ugh.
+  EXPECT_LT(kint32min, kint32max);
+  EXPECT_EQ(static_cast<uint32>(kint32min), static_cast<uint32>(kint32max) + 1);
+  EXPECT_LT(kint64min, kint64max);
+  EXPECT_EQ(static_cast<uint64>(kint64min), static_cast<uint64>(kint64max) + 1);
+  EXPECT_EQ(0, kuint32max + 1);
+  EXPECT_EQ(0, kuint64max + 1);
+}
+
+std::vector<std::string> captured_messages_;
+
+void CaptureLog(LogLevel level, const char* filename, int line,
+                const std::string& message) {
+  captured_messages_.push_back(
+    strings::Substitute("$0 $1:$2: $3",
+      implicit_cast<int>(level), filename, line, message));
+}
+
+TEST(LoggingTest, DefaultLogging) {
+  CaptureTestStderr();
+  int line = __LINE__;
+  GOOGLE_LOG(INFO   ) << "A message.";
+  GOOGLE_LOG(WARNING) << "A warning.";
+  GOOGLE_LOG(ERROR  ) << "An error.";
+
+  std::string text = GetCapturedTestStderr();
+  EXPECT_EQ(
+    "[libprotobuf INFO " __FILE__ ":" + SimpleItoa(line + 1) + "] A message.\n"
+    "[libprotobuf WARNING " __FILE__ ":" + SimpleItoa(line + 2) + "] A warning.\n"
+    "[libprotobuf ERROR " __FILE__ ":" + SimpleItoa(line + 3) + "] An error.\n",
+    text);
+}
+
+TEST(LoggingTest, NullLogging) {
+  LogHandler* old_handler = SetLogHandler(nullptr);
+
+  CaptureTestStderr();
+  GOOGLE_LOG(INFO   ) << "A message.";
+  GOOGLE_LOG(WARNING) << "A warning.";
+  GOOGLE_LOG(ERROR  ) << "An error.";
+
+  EXPECT_TRUE(SetLogHandler(old_handler) == nullptr);
+
+  std::string text = GetCapturedTestStderr();
+  EXPECT_EQ("", text);
+}
+
+TEST(LoggingTest, CaptureLogging) {
+  captured_messages_.clear();
+
+  LogHandler* old_handler = SetLogHandler(&CaptureLog);
+
+  int start_line = __LINE__;
+  GOOGLE_LOG(ERROR) << "An error.";
+  GOOGLE_LOG(WARNING) << "A warning.";
+
+  EXPECT_TRUE(SetLogHandler(old_handler) == &CaptureLog);
+
+  ASSERT_EQ(2, captured_messages_.size());
+  EXPECT_EQ(
+    "2 " __FILE__ ":" + SimpleItoa(start_line + 1) + ": An error.",
+    captured_messages_[0]);
+  EXPECT_EQ(
+    "1 " __FILE__ ":" + SimpleItoa(start_line + 2) + ": A warning.",
+    captured_messages_[1]);
+}
+
+TEST(LoggingTest, SilenceLogging) {
+  captured_messages_.clear();
+
+  LogHandler* old_handler = SetLogHandler(&CaptureLog);
+
+  int line1 = __LINE__; GOOGLE_LOG(INFO) << "Visible1";
+  LogSilencer* silencer1 = new LogSilencer;
+  GOOGLE_LOG(INFO) << "Not visible.";
+  LogSilencer* silencer2 = new LogSilencer;
+  GOOGLE_LOG(INFO) << "Not visible.";
+  delete silencer1;
+  GOOGLE_LOG(INFO) << "Not visible.";
+  delete silencer2;
+  int line2 = __LINE__; GOOGLE_LOG(INFO) << "Visible2";
+
+  EXPECT_TRUE(SetLogHandler(old_handler) == &CaptureLog);
+
+  ASSERT_EQ(2, captured_messages_.size());
+  EXPECT_EQ(
+    "0 " __FILE__ ":" + SimpleItoa(line1) + ": Visible1",
+    captured_messages_[0]);
+  EXPECT_EQ(
+    "0 " __FILE__ ":" + SimpleItoa(line2) + ": Visible2",
+    captured_messages_[1]);
+}
+
+class ClosureTest : public testing::Test {
+ public:
+  void SetA123Method()   { a_ = 123; }
+  static void SetA123Function() { current_instance_->a_ = 123; }
+
+  void SetAMethod(int a)         { a_ = a; }
+  void SetCMethod(std::string c) { c_ = c; }
+
+  static void SetAFunction(int a)         { current_instance_->a_ = a; }
+  static void SetCFunction(std::string c) { current_instance_->c_ = c; }
+
+  void SetABMethod(int a, const char* b)  { a_ = a; b_ = b; }
+  static void SetABFunction(int a, const char* b) {
+    current_instance_->a_ = a;
+    current_instance_->b_ = b;
+  }
+
+  virtual void SetUp() {
+    current_instance_ = this;
+    a_ = 0;
+    b_ = nullptr;
+    c_.clear();
+    permanent_closure_ = nullptr;
+  }
+
+  void DeleteClosureInCallback() {
+    delete permanent_closure_;
+  }
+
+  int a_;
+  const char* b_;
+  std::string c_;
+  Closure* permanent_closure_;
+
+  static ClosureTest* current_instance_;
+};
+
+ClosureTest* ClosureTest::current_instance_ = nullptr;
+
+TEST_F(ClosureTest, TestClosureFunction0) {
+  Closure* closure = NewCallback(&SetA123Function);
+  EXPECT_NE(123, a_);
+  closure->Run();
+  EXPECT_EQ(123, a_);
+}
+
+TEST_F(ClosureTest, TestClosureMethod0) {
+  Closure* closure = NewCallback(current_instance_,
+                                 &ClosureTest::SetA123Method);
+  EXPECT_NE(123, a_);
+  closure->Run();
+  EXPECT_EQ(123, a_);
+}
+
+TEST_F(ClosureTest, TestClosureFunction1) {
+  Closure* closure = NewCallback(&SetAFunction, 456);
+  EXPECT_NE(456, a_);
+  closure->Run();
+  EXPECT_EQ(456, a_);
+}
+
+TEST_F(ClosureTest, TestClosureMethod1) {
+  Closure* closure = NewCallback(current_instance_,
+                                 &ClosureTest::SetAMethod, 456);
+  EXPECT_NE(456, a_);
+  closure->Run();
+  EXPECT_EQ(456, a_);
+}
+
+TEST_F(ClosureTest, TestClosureFunction1String) {
+  Closure* closure = NewCallback(&SetCFunction, std::string("test"));
+  EXPECT_NE("test", c_);
+  closure->Run();
+  EXPECT_EQ("test", c_);
+}
+
+TEST_F(ClosureTest, TestClosureMethod1String) {
+  Closure* closure = NewCallback(current_instance_, &ClosureTest::SetCMethod,
+                                 std::string("test"));
+  EXPECT_NE("test", c_);
+  closure->Run();
+  EXPECT_EQ("test", c_);
+}
+
+TEST_F(ClosureTest, TestClosureFunction2) {
+  const char* cstr = "hello";
+  Closure* closure = NewCallback(&SetABFunction, 789, cstr);
+  EXPECT_NE(789, a_);
+  EXPECT_NE(cstr, b_);
+  closure->Run();
+  EXPECT_EQ(789, a_);
+  EXPECT_EQ(cstr, b_);
+}
+
+TEST_F(ClosureTest, TestClosureMethod2) {
+  const char* cstr = "hello";
+  Closure* closure = NewCallback(current_instance_,
+                                 &ClosureTest::SetABMethod, 789, cstr);
+  EXPECT_NE(789, a_);
+  EXPECT_NE(cstr, b_);
+  closure->Run();
+  EXPECT_EQ(789, a_);
+  EXPECT_EQ(cstr, b_);
+}
+
+// Repeat all of the above with NewPermanentCallback()
+
+TEST_F(ClosureTest, TestPermanentClosureFunction0) {
+  Closure* closure = NewPermanentCallback(&SetA123Function);
+  EXPECT_NE(123, a_);
+  closure->Run();
+  EXPECT_EQ(123, a_);
+  a_ = 0;
+  closure->Run();
+  EXPECT_EQ(123, a_);
+  delete closure;
+}
+
+TEST_F(ClosureTest, TestPermanentClosureMethod0) {
+  Closure* closure = NewPermanentCallback(current_instance_,
+                                          &ClosureTest::SetA123Method);
+  EXPECT_NE(123, a_);
+  closure->Run();
+  EXPECT_EQ(123, a_);
+  a_ = 0;
+  closure->Run();
+  EXPECT_EQ(123, a_);
+  delete closure;
+}
+
+TEST_F(ClosureTest, TestPermanentClosureFunction1) {
+  Closure* closure = NewPermanentCallback(&SetAFunction, 456);
+  EXPECT_NE(456, a_);
+  closure->Run();
+  EXPECT_EQ(456, a_);
+  a_ = 0;
+  closure->Run();
+  EXPECT_EQ(456, a_);
+  delete closure;
+}
+
+TEST_F(ClosureTest, TestPermanentClosureMethod1) {
+  Closure* closure = NewPermanentCallback(current_instance_,
+                                          &ClosureTest::SetAMethod, 456);
+  EXPECT_NE(456, a_);
+  closure->Run();
+  EXPECT_EQ(456, a_);
+  a_ = 0;
+  closure->Run();
+  EXPECT_EQ(456, a_);
+  delete closure;
+}
+
+TEST_F(ClosureTest, TestPermanentClosureFunction2) {
+  const char* cstr = "hello";
+  Closure* closure = NewPermanentCallback(&SetABFunction, 789, cstr);
+  EXPECT_NE(789, a_);
+  EXPECT_NE(cstr, b_);
+  closure->Run();
+  EXPECT_EQ(789, a_);
+  EXPECT_EQ(cstr, b_);
+  a_ = 0;
+  b_ = nullptr;
+  closure->Run();
+  EXPECT_EQ(789, a_);
+  EXPECT_EQ(cstr, b_);
+  delete closure;
+}
+
+TEST_F(ClosureTest, TestPermanentClosureMethod2) {
+  const char* cstr = "hello";
+  Closure* closure = NewPermanentCallback(current_instance_,
+                                          &ClosureTest::SetABMethod, 789, cstr);
+  EXPECT_NE(789, a_);
+  EXPECT_NE(cstr, b_);
+  closure->Run();
+  EXPECT_EQ(789, a_);
+  EXPECT_EQ(cstr, b_);
+  a_ = 0;
+  b_ = nullptr;
+  closure->Run();
+  EXPECT_EQ(789, a_);
+  EXPECT_EQ(cstr, b_);
+  delete closure;
+}
+
+TEST_F(ClosureTest, TestPermanentClosureDeleteInCallback) {
+  permanent_closure_ = NewPermanentCallback((ClosureTest*) this,
+      &ClosureTest::DeleteClosureInCallback);
+  permanent_closure_->Run();
+}
+
+}  // anonymous namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
new file mode 100644
index 0000000..a7ec068
--- /dev/null
+++ b/src/google/protobuf/stubs/hash.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
+#define GOOGLE_PROTOBUF_STUBS_HASH_H__
+
+#include <cstring>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
+  namespace google {                                      \
+  namespace protobuf {
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
+
+namespace google {
+namespace protobuf {
+
+template <typename Key>
+struct hash : public std::hash<Key> {};
+
+template <typename Key>
+struct hash<const Key*> {
+  inline size_t operator()(const Key* key) const {
+    return reinterpret_cast<size_t>(key);
+  }
+};
+
+// Unlike the old SGI version, the TR1 "hash" does not special-case char*.  So,
+// we go ahead and provide our own implementation.
+template <>
+struct hash<const char*> {
+  inline size_t operator()(const char* str) const {
+    size_t result = 0;
+    for (; *str != '\0'; str++) {
+      result = 5 * result + static_cast<size_t>(*str);
+    }
+    return result;
+  }
+};
+
+template<>
+struct hash<bool> {
+  size_t operator()(bool x) const {
+    return static_cast<size_t>(x);
+  }
+};
+
+template <>
+struct hash<std::string> {
+  inline size_t operator()(const std::string& key) const {
+    return hash<const char*>()(key.c_str());
+  }
+
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+  inline bool operator()(const std::string& a, const std::string& b) const {
+    return a < b;
+  }
+};
+
+template <typename First, typename Second>
+struct hash<std::pair<First, Second> > {
+  inline size_t operator()(const std::pair<First, Second>& key) const {
+    size_t first_hash = hash<First>()(key.first);
+    size_t second_hash = hash<Second>()(key.second);
+
+    // FIXME(kenton):  What is the best way to compute this hash?  I have
+    // no idea!  This seems a bit better than an XOR.
+    return first_hash * ((1 << 16) - 1) + second_hash;
+  }
+
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+  inline bool operator()(const std::pair<First, Second>& a,
+                           const std::pair<First, Second>& b) const {
+    return a < b;
+  }
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_HASH_H__
diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc
new file mode 100644
index 0000000..a151cfb
--- /dev/null
+++ b/src/google/protobuf/stubs/int128.cc
@@ -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.
+
+#include <google/protobuf/stubs/int128.h>
+
+#include <iomanip>
+#include <ostream>  // NOLINT(readability/streams)
+#include <sstream>
+
+#include <google/protobuf/stubs/logging.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+const uint128_pod kuint128max = {uint64_t{0xFFFFFFFFFFFFFFFFu},
+                                 uint64_t{0xFFFFFFFFFFFFFFFFu}};
+
+// 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_t n) {
+  GOOGLE_DCHECK_NE(0, n);
+  int pos = 0;
+  STEP(uint64_t, n, pos, 0x20);
+  uint32_t n32 = n;
+  STEP(uint32_t, n32, pos, 0x10);
+  STEP(uint32_t, n32, pos, 0x08);
+  STEP(uint32_t, n32, pos, 0x04);
+  return pos + ((uint64_t{0x3333333322221100u} >> (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_t hi = Uint128High64(n)) {
+    return Fls64(hi) + 64;
+  }
+  return Fls64(Uint128Low64(n));
+}
+
+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_;
+  } else if (dividend < divisor) {
+    *quotient_ret = 0;
+    *remainder_ret = dividend;
+    return;
+  } else {
+    int dividend_bit_length = Fls128(dividend);
+    int divisor_bit_length = Fls128(divisor);
+    int difference = dividend_bit_length - divisor_bit_length;
+    uint128 quotient = 0;
+    while (difference >= 0) {
+      quotient <<= 1;
+      uint128 shifted_divisor = divisor << difference;
+      if (shifted_divisor <= dividend) {
+        dividend -= shifted_divisor;
+        quotient += 1;
+      }
+      difference -= 1;
+    }
+    //record the final quotient and remainder
+    *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 =
+          static_cast<uint64_t>(uint64_t{0x1000000000000000u});  // 16^15
+      div_base_log = 15;
+      break;
+    case std::ios::oct:
+      div = static_cast<uint64_t>(
+          uint64_t{01000000000000000000000u});  // 8^21
+      div_base_log = 21;
+      break;
+    default:  // std::ios::dec
+      div = static_cast<uint64_t>(
+          uint64_t{10000000000000000000u});  // 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);
+  auto repSize = static_cast<std::streamsize>(rep.size());
+  if (width > repSize) {
+    if ((flags & std::ios::adjustfield) == std::ios::left) {
+      rep.append(width - repSize, o.fill());
+    } else {
+      rep.insert(static_cast<std::string::size_type>(0), width - repSize,
+                 o.fill());
+    }
+  }
+
+  // Stream the final representation in a single "<<" call.
+  return o << rep;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>  // NOLINT
diff --git a/src/google/protobuf/stubs/int128.h b/src/google/protobuf/stubs/int128.h
new file mode 100644
index 0000000..92d7bdf
--- /dev/null
+++ b/src/google/protobuf/stubs/int128.h
@@ -0,0 +1,387 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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>
+
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_EXPORT uint128 {
+ public:
+  UINT128_CONSTEXPR uint128();  // Sets to 0, but don't trust on this behavior.
+  UINT128_CONSTEXPR uint128(uint64_t top, uint64_t bottom);
+#ifndef SWIG
+  UINT128_CONSTEXPR uint128(int bottom);
+  UINT128_CONSTEXPR uint128(uint32_t bottom);   // Top 96 bits = 0
+#endif
+  UINT128_CONSTEXPR uint128(uint64_t bottom);   // hi_ = 0
+  UINT128_CONSTEXPR uint128(const uint128_pod &val);
+
+  // Trivial copy constructor, assignment operator and destructor.
+
+  void Initialize(uint64_t top, uint64_t 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_t Uint128Low64(const uint128& v);
+  friend uint64_t Uint128High64(const uint128& v);
+
+  // We add "std::" to avoid including all of port.h.
+  PROTOBUF_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_t lo_;
+  uint64_t hi_;
+
+  // Not implemented, just declared for catching automatic type conversions.
+  uint128(uint8_t);
+  uint128(uint16_t);
+  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_t hi;
+  uint64_t lo;
+};
+
+PROTOBUF_EXPORT extern const uint128_pod kuint128max;
+
+// allow uint128 to be logged
+PROTOBUF_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_t Uint128Low64(const uint128& v) { return v.lo_; }
+inline uint64_t 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_t top, uint64_t 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_t bottom)
+    : lo_(bottom), hi_(0) {}
+#ifndef SWIG
+inline UINT128_CONSTEXPR uint128::uint128(uint32_t bottom)
+    : lo_(bottom), hi_(0) {}
+inline UINT128_CONSTEXPR uint128::uint128(int bottom)
+    : lo_(bottom), hi_(static_cast<int64_t>((bottom < 0) ? -1 : 0)) {}
+#endif
+
+#undef UINT128_CONSTEXPR
+
+inline void uint128::Initialize(uint64_t top, uint64_t 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_t hi_flip = ~Uint128High64(val);
+  const uint64_t lo_flip = ~Uint128Low64(val);
+  const uint64_t 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_t new_hi = (Uint128High64(val) << amount) |
+                      (Uint128Low64(val) >> (64 - amount));
+    uint64_t 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_t new_hi = Uint128High64(val) >> amount;
+    uint64_t 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_t 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_t a96 = hi_ >> 32;
+  uint64_t a64 = hi_ & 0xffffffffu;
+  uint64_t a32 = lo_ >> 32;
+  uint64_t a00 = lo_ & 0xffffffffu;
+  uint64_t b96 = b.hi_ >> 32;
+  uint64_t b64 = b.hi_ & 0xffffffffu;
+  uint64_t b32 = b.lo_ >> 32;
+  uint64_t 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_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
+  uint64_t 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
+
+#include <google/protobuf/port_undef.inc>
+
+#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..b1634f0
--- /dev/null
+++ b/src/google/protobuf/stubs/int128_unittest.cc
@@ -0,0 +1,511 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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>
+
+#include <google/protobuf/port_def.inc>
+
+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, std::numeric_limits<uint64_t>::max());
+  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), std::numeric_limits<uint64_t>::max());
+  EXPECT_EQ(Uint128Low64(biggest), std::numeric_limits<uint64_t>::max());
+  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 + std::numeric_limits<uint64_t>::max(), 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), std::numeric_limits<uint64_t>::max());
+  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(uint64_t{0xffffeeeeddddccccu}, uint64_t{0xbbbbaaaa99998888u});
+  b = uint128(uint64_t{0x7777666655554444u}, uint64_t{0x3333222211110000u});
+  c = a * b;
+  EXPECT_EQ(
+      uint128(uint64_t{0x530EDA741C71D4C3u}, uint64_t{0xBF25975319080000u}), c);
+  EXPECT_EQ(0, c - b * a);
+  EXPECT_EQ(a * a - b * b, (a + b) * (a - b));
+
+  // Verified with dc.
+  a = uint128(uint64_t{0x0123456789abcdefu}, uint64_t{0xfedcba9876543210u});
+  b = uint128(uint64_t{0x02468ace13579bdfu}, uint64_t{0xfdb97531eca86420u});
+  c = a * b;
+  EXPECT_EQ(
+      uint128(uint64_t{0x97a87f4f261ba3f2u}, uint64_t{0x342d0bbf48948200u}), 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_t>(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(uint64_t{0x530eda741c71d4c3u}, uint64_t{0xbf25975319080000u});
+  q = uint128(uint64_t{0x4de2cab081u}, uint64_t{0x14c34ab4676e4babu});
+  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.
+  std::swap(q, b);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(q, result_q);
+  EXPECT_EQ(r, result_r);
+  // Restore.
+  std::swap(b, q);
+
+  // Dividend < divisor; result should be q:0 r:<dividend>.
+  std::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.
+  std::swap(a, q);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(0, result_q);
+  EXPECT_EQ(a, result_r);
+  // Restore.
+  std::swap(q, a);
+  std::swap(b, a);
+
+  // Try a large remainder.
+  b = a / 2 + 1;
+  uint128 expected_r(uint64_t{0x29876d3a0e38ea61u},
+                     uint64_t{0xdf92cba98c83ffffu});
+  // 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_t RandomUint64() {
+  uint64_t v1 = rand();
+  uint64_t v2 = rand();
+  uint64_t 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(uint64_t{0x8000000000000000u}, 0), std::ios::dec, 0, '_',
+       "170141183460469231731687303715884105728"},
+      {uint128(uint64_t{0x8000000000000000u}, 0), std::ios::oct, 0, '_',
+       "2000000000000000000000000000000000000000000"},
+      {uint128(uint64_t{0x8000000000000000u}, 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) {
+    std::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
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/stubs/logging.h b/src/google/protobuf/stubs/logging.h
new file mode 100644
index 0000000..8ecc2fa
--- /dev/null
+++ b/src/google/protobuf/stubs/logging.h
@@ -0,0 +1,239 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_LOGGING_H_
+#define GOOGLE_PROTOBUF_STUBS_LOGGING_H_
+
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <google/protobuf/port_def.inc>
+
+// ===================================================================
+// 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 uint128;
+namespace internal {
+
+class LogFinisher;
+
+class PROTOBUF_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 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 PROTOBUF_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 == nullptr) {
+    GOOGLE_LOG(FATAL) << name;
+  }
+  return val;
+}
+}  // namespace internal
+#define GOOGLE_CHECK_NOTNULL(A)               \
+  ::google::protobuf::internal::CheckNotNull( \
+      __FILE__, __LINE__, "'" #A "' must not be nullptr", (A))
+
+#ifdef NDEBUG
+
+#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false)
+
+#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
+#define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E))
+#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B))
+#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B))
+#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) <  (B))
+#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B))
+#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) >  (B))
+#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B))
+
+#else  // NDEBUG
+
+#define GOOGLE_DLOG GOOGLE_LOG
+
+#define GOOGLE_DCHECK    GOOGLE_CHECK
+#define GOOGLE_DCHECK_OK GOOGLE_CHECK_OK
+#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
+#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
+#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
+#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
+#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
+#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
+
+#endif  // !NDEBUG
+
+typedef void LogHandler(LogLevel level, const char* filename, int line,
+                        const std::string& message);
+
+// The protobuf library sometimes writes warning and error messages to
+// stderr.  These messages are primarily useful for developers, but may
+// also help end users figure out a problem.  If you would prefer that
+// these messages be sent somewhere other than stderr, call SetLogHandler()
+// to set your own handler.  This returns the old handler.  Set the handler
+// to nullptr 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.
+PROTOBUF_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 PROTOBUF_EXPORT LogSilencer {
+ public:
+  LogSilencer();
+  ~LogSilencer();
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..ae9a8b9
--- /dev/null
+++ b/src/google/protobuf/stubs/macros.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_MACROS_H__
+#define GOOGLE_PROTOBUF_MACROS_H__
+
+namespace google {
+namespace protobuf {
+
+#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
+#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
+  TypeName(const TypeName&) = delete;               \
+  void operator=(const TypeName&) = delete
+
+#undef GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS
+#define GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName() = delete;                                  \
+  TypeName(const TypeName&) = delete;                   \
+  void operator=(const TypeName&) = delete
+
+// ===================================================================
+// from google3/base/basictypes.h
+
+// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.
+//
+// GOOGLE_ARRAYSIZE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
+// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+//
+// Kudos to Jorg Brown for this simple and elegant implementation.
+
+#undef GOOGLE_ARRAYSIZE
+#define GOOGLE_ARRAYSIZE(a) \
+  ((sizeof(a) / sizeof(*(a))) / \
+   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MACROS_H__
diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h
new file mode 100644
index 0000000..24e098a
--- /dev/null
+++ b/src/google/protobuf/stubs/map_util.h
@@ -0,0 +1,769 @@
+// 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.
+
+// from google3/util/gtl/map_util.h
+// Author: Anton Carver
+
+#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+
+#include <stddef.h>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// Local implementation of RemoveConst to avoid including base/type_traits.h.
+template <class T> struct RemoveConst { typedef T type; };
+template <class T> struct RemoveConst<const T> : RemoveConst<T> {};
+}  // namespace internal
+
+//
+// Find*()
+//
+
+// Returns a const reference to the value associated with the given key if it
+// exists. Crashes otherwise.
+//
+// This is intended as a replacement for operator[] as an rvalue (for reading)
+// when the key is guaranteed to exist.
+//
+// operator[] for lookup is discouraged for several reasons:
+//  * It has a side-effect of inserting missing keys
+//  * It is not thread-safe (even when it is not inserting, it can still
+//      choose to resize the underlying storage)
+//  * It invalidates iterators (when it chooses to resize)
+//  * It default constructs a value object even if it doesn't need to
+//
+// This version assumes the key is printable, and includes it in the fatal log
+// message.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDie(const Collection& collection,
+          const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+  return it->second;
+}
+
+// Same as above, but returns a non-const reference.
+template <class Collection>
+typename Collection::value_type::second_type&
+FindOrDie(Collection& collection,  // NOLINT
+          const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+  return it->second;
+}
+
+// Same as FindOrDie above, but doesn't log the key on failure.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDieNoPrint(const Collection& collection,
+                 const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found";
+  return it->second;
+}
+
+// Same as above, but returns a non-const reference.
+template <class Collection>
+typename Collection::value_type::second_type&
+FindOrDieNoPrint(Collection& collection,  // NOLINT
+                 const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found";
+  return it->second;
+}
+
+// Returns a const reference to the value associated with the given key if it
+// exists, otherwise returns a const reference to the provided default value.
+//
+// WARNING: If a temporary object is passed as the default "value,"
+// this function will return a reference to that temporary object,
+// which will be destroyed at the end of the statement. A common
+// example: if you have a map with string values, and you pass a char*
+// as the default "value," either use the returned value immediately
+// or store it in a string (not string&).
+// Details: http://go/findwithdefault
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindWithDefault(const Collection& collection,
+                const typename Collection::value_type::first_type& key,
+                const typename Collection::value_type::second_type& value) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return value;
+  }
+  return it->second;
+}
+
+// Returns a pointer to the const value associated with the given key if it
+// exists, or nullptr otherwise.
+template <class Collection>
+const typename Collection::value_type::second_type*
+FindOrNull(const Collection& collection,
+           const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  return &it->second;
+}
+
+// Same as above but returns a pointer to the non-const value.
+template <class Collection>
+typename Collection::value_type::second_type*
+FindOrNull(Collection& collection,  // NOLINT
+           const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  return &it->second;
+}
+
+// Returns the pointer value associated with the given key. If none is found,
+// nullptr is returned. The function is designed to be used with a map of keys to
+// pointers.
+//
+// This function does not distinguish between a missing key and a key mapped
+// to nullptr.
+template <class Collection>
+typename Collection::value_type::second_type
+FindPtrOrNull(const Collection& collection,
+              const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return typename Collection::value_type::second_type();
+  }
+  return it->second;
+}
+
+// Same as above, except takes non-const reference to collection.
+//
+// This function is needed for containers that propagate constness to the
+// pointee, such as boost::ptr_map.
+template <class Collection>
+typename Collection::value_type::second_type
+FindPtrOrNull(Collection& collection,  // NOLINT
+              const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return typename Collection::value_type::second_type();
+  }
+  return it->second;
+}
+
+// Finds the pointer value associated with the given key in a map whose values
+// are linked_ptrs. Returns nullptr if key is not found.
+template <class Collection>
+typename Collection::value_type::second_type::element_type*
+FindLinkedPtrOrNull(const Collection& collection,
+                    const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  // Since linked_ptr::get() is a const member returning a non const,
+  // we do not need a version of this function taking a non const collection.
+  return it->second.get();
+}
+
+// Same as above, but dies if the key is not found.
+template <class Collection>
+typename Collection::value_type::second_type::element_type&
+FindLinkedPtrOrDie(const Collection& collection,
+                   const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) <<  "key not found: " << key;
+  // Since linked_ptr::operator*() is a const member returning a non const,
+  // we do not need a version of this function taking a non const collection.
+  return *it->second;
+}
+
+// Finds the value associated with the given key and copies it to *value (if not
+// nullptr). Returns false if the key was not found, true otherwise.
+template <class Collection, class Key, class Value>
+bool FindCopy(const Collection& collection,
+              const Key& key,
+              Value* const value) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return false;
+  }
+  if (value) {
+    *value = it->second;
+  }
+  return true;
+}
+
+//
+// Contains*()
+//
+
+// Returns true if and only if the given collection contains the given key.
+template <class Collection, class Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+  return collection.find(key) != collection.end();
+}
+
+// Returns true if and only if the given collection contains the given key-value
+// pair.
+template <class Collection, class Key, class Value>
+bool ContainsKeyValuePair(const Collection& collection,
+                          const Key& key,
+                          const Value& value) {
+  typedef typename Collection::const_iterator const_iterator;
+  std::pair<const_iterator, const_iterator> range = collection.equal_range(key);
+  for (const_iterator it = range.first; it != range.second; ++it) {
+    if (it->second == value) {
+      return true;
+    }
+  }
+  return false;
+}
+
+//
+// Insert*()
+//
+
+// Inserts the given key-value pair into the collection. Returns true if and
+// only if the key from the given pair didn't previously exist. Otherwise, the
+// value in the map is replaced with the value from the given pair.
+template <class Collection>
+bool InsertOrUpdate(Collection* const collection,
+                    const typename Collection::value_type& vt) {
+  std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+  if (!ret.second) {
+    // update
+    ret.first->second = vt.second;
+    return false;
+  }
+  return true;
+}
+
+// Same as above, except that the key and value are passed separately.
+template <class Collection>
+bool InsertOrUpdate(Collection* const collection,
+                    const typename Collection::value_type::first_type& key,
+                    const typename Collection::value_type::second_type& value) {
+  return InsertOrUpdate(
+      collection, typename Collection::value_type(key, value));
+}
+
+// Inserts/updates all the key-value pairs from the range defined by the
+// iterators "first" and "last" into the given collection.
+template <class Collection, class InputIterator>
+void InsertOrUpdateMany(Collection* const collection,
+                        InputIterator first, InputIterator last) {
+  for (; first != last; ++first) {
+    InsertOrUpdate(collection, *first);
+  }
+}
+
+// Change the value associated with a particular key in a map or hash_map
+// of the form map<Key, Value*> which owns the objects pointed to by the
+// value pointers.  If there was an existing value for the key, it is deleted.
+// True indicates an insert took place, false indicates an update + delete.
+template <class Collection>
+bool InsertAndDeleteExisting(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& value) {
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, value));
+  if (!ret.second) {
+    delete ret.first->second;
+    ret.first->second = value;
+    return false;
+  }
+  return true;
+}
+
+// Inserts the given key and value into the given collection if and only if the
+// given key did NOT already exist in the collection. If the key previously
+// existed in the collection, the value is not changed. Returns true if the
+// key-value pair was inserted; returns false if the key was already present.
+template <class Collection>
+bool InsertIfNotPresent(Collection* const collection,
+                        const typename Collection::value_type& vt) {
+  return collection->insert(vt).second;
+}
+
+// Same as above except the key and value are passed separately.
+template <class Collection>
+bool InsertIfNotPresent(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& value) {
+  return InsertIfNotPresent(
+      collection, typename Collection::value_type(key, value));
+}
+
+// Same as above except dies if the key already exists in the collection.
+template <class Collection>
+void InsertOrDie(Collection* const collection,
+                 const typename Collection::value_type& value) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value))
+      << "duplicate value: " << value;
+}
+
+// Same as above except doesn't log the value on error.
+template <class Collection>
+void InsertOrDieNoPrint(Collection* const collection,
+                        const typename Collection::value_type& value) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
+}
+
+// Inserts the key-value pair into the collection. Dies if key was already
+// present.
+template <class Collection>
+void InsertOrDie(Collection* const collection,
+                 const typename Collection::value_type::first_type& key,
+                 const typename Collection::value_type::second_type& data) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, key, data))
+      << "duplicate key: " << key;
+}
+
+// Same as above except doesn't log the key on error.
+template <class Collection>
+void InsertOrDieNoPrint(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& data) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key.";
+}
+
+// Inserts a new key and default-initialized value. Dies if the key was already
+// present. Returns a reference to the value. Example usage:
+//
+// map<int, SomeProto> m;
+// SomeProto& proto = InsertKeyOrDie(&m, 3);
+// proto.set_field("foo");
+template <class Collection>
+typename Collection::value_type::second_type& InsertKeyOrDie(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typedef typename Collection::value_type value_type;
+  std::pair<typename Collection::iterator, bool> res =
+      collection->insert(value_type(key, typename value_type::second_type()));
+  GOOGLE_CHECK(res.second) << "duplicate key: " << key;
+  return res.first->second;
+}
+
+//
+// Lookup*()
+//
+
+// Looks up a given key and value pair in a collection and inserts the key-value
+// pair if it's not already present. Returns a reference to the value associated
+// with the key.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsert(Collection* const collection,
+               const typename Collection::value_type& vt) {
+  return collection->insert(vt).first->second;
+}
+
+// Same as above except the key-value are passed separately.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsert(Collection* const collection,
+               const typename Collection::value_type::first_type& key,
+               const typename Collection::value_type::second_type& value) {
+  return LookupOrInsert(
+      collection, typename Collection::value_type(key, value));
+}
+
+// Counts the number of equivalent elements in the given "sequence", and stores
+// the results in "count_map" with element as the key and count as the value.
+//
+// Example:
+//   vector<string> v = {"a", "b", "c", "a", "b"};
+//   map<string, int> m;
+//   AddTokenCounts(v, 1, &m);
+//   assert(m["a"] == 2);
+//   assert(m["b"] == 2);
+//   assert(m["c"] == 1);
+template <typename Sequence, typename Collection>
+void AddTokenCounts(
+    const Sequence& sequence,
+    const typename Collection::value_type::second_type& increment,
+    Collection* const count_map) {
+  for (typename Sequence::const_iterator it = sequence.begin();
+       it != sequence.end(); ++it) {
+    typename Collection::value_type::second_type& value =
+        LookupOrInsert(count_map, *it,
+                       typename Collection::value_type::second_type());
+    value += increment;
+  }
+}
+
+// Returns a reference to the value associated with key. If not found, a value
+// is default constructed on the heap and added to the map.
+//
+// This function is useful for containers of the form map<Key, Value*>, where
+// inserting a new key, value pair involves constructing a new heap-allocated
+// Value, and storing a pointer to that in the collection.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsertNew(Collection* const collection,
+                  const typename Collection::value_type::first_type& key) {
+  typedef typename std::iterator_traits<
+    typename Collection::value_type::second_type>::value_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(
+          key,
+          static_cast<typename Collection::value_type::second_type>(nullptr)));
+  if (ret.second) {
+    ret.first->second = new Element();
+  }
+  return ret.first->second;
+}
+
+// Same as above but constructs the value using the single-argument constructor
+// and the given "arg".
+template <class Collection, class Arg>
+typename Collection::value_type::second_type&
+LookupOrInsertNew(Collection* const collection,
+                  const typename Collection::value_type::first_type& key,
+                  const Arg& arg) {
+  typedef typename std::iterator_traits<
+    typename Collection::value_type::second_type>::value_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(
+          key,
+          static_cast<typename Collection::value_type::second_type>(nullptr)));
+  if (ret.second) {
+    ret.first->second = new Element(arg);
+  }
+  return ret.first->second;
+}
+
+// Lookup of linked/shared pointers is used in two scenarios:
+//
+// Use LookupOrInsertNewLinkedPtr if the container owns the elements.
+// In this case it is fine working with the raw pointer as long as it is
+// guaranteed that no other thread can delete/update an accessed element.
+// A mutex will need to lock the container operation as well as the use
+// of the returned elements. Finding an element may be performed using
+// FindLinkedPtr*().
+//
+// Use LookupOrInsertNewSharedPtr if the container does not own the elements
+// for their whole lifetime. This is typically the case when a reader allows
+// parallel updates to the container. In this case a Mutex only needs to lock
+// container operations, but all element operations must be performed on the
+// shared pointer. Finding an element must be performed using FindPtr*() and
+// cannot be done with FindLinkedPtr*() even though it compiles.
+
+// Lookup a key in a map or hash_map whose values are linked_ptrs.  If it is
+// missing, set collection[key].reset(new Value::element_type) and return that.
+// Value::element_type must be default constructable.
+template <class Collection>
+typename Collection::value_type::second_type::element_type*
+LookupOrInsertNewLinkedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typedef typename Collection::value_type::second_type Value;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, Value()));
+  if (ret.second) {
+    ret.first->second.reset(new typename Value::element_type);
+  }
+  return ret.first->second.get();
+}
+
+// A variant of LookupOrInsertNewLinkedPtr where the value is constructed using
+// a single-parameter constructor.  Note: the constructor argument is computed
+// even if it will not be used, so only values cheap to compute should be passed
+// here.  On the other hand it does not matter how expensive the construction of
+// the actual stored value is, as that only occurs if necessary.
+template <class Collection, class Arg>
+typename Collection::value_type::second_type::element_type*
+LookupOrInsertNewLinkedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const Arg& arg) {
+  typedef typename Collection::value_type::second_type Value;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, Value()));
+  if (ret.second) {
+    ret.first->second.reset(new typename Value::element_type(arg));
+  }
+  return ret.first->second.get();
+}
+
+// Lookup a key in a map or hash_map whose values are shared_ptrs.  If it is
+// missing, set collection[key].reset(new Value::element_type). Unlike
+// LookupOrInsertNewLinkedPtr, this function returns the shared_ptr instead of
+// the raw pointer. Value::element_type must be default constructable.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsertNewSharedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typedef typename Collection::value_type::second_type SharedPtr;
+  typedef typename Collection::value_type::second_type::element_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, SharedPtr()));
+  if (ret.second) {
+    ret.first->second.reset(new Element());
+  }
+  return ret.first->second;
+}
+
+// A variant of LookupOrInsertNewSharedPtr where the value is constructed using
+// a single-parameter constructor.  Note: the constructor argument is computed
+// even if it will not be used, so only values cheap to compute should be passed
+// here.  On the other hand it does not matter how expensive the construction of
+// the actual stored value is, as that only occurs if necessary.
+template <class Collection, class Arg>
+typename Collection::value_type::second_type&
+LookupOrInsertNewSharedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const Arg& arg) {
+  typedef typename Collection::value_type::second_type SharedPtr;
+  typedef typename Collection::value_type::second_type::element_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, SharedPtr()));
+  if (ret.second) {
+    ret.first->second.reset(new Element(arg));
+  }
+  return ret.first->second;
+}
+
+//
+// Misc Utility Functions
+//
+
+// Updates the value associated with the given key. If the key was not already
+// present, then the key-value pair are inserted and "previous" is unchanged. If
+// the key was already present, the value is updated and "*previous" will
+// contain a copy of the old value.
+//
+// InsertOrReturnExisting has complementary behavior that returns the
+// address of an already existing value, rather than updating it.
+template <class Collection>
+bool UpdateReturnCopy(Collection* const collection,
+                      const typename Collection::value_type::first_type& key,
+                      const typename Collection::value_type::second_type& value,
+                      typename Collection::value_type::second_type* previous) {
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, value));
+  if (!ret.second) {
+    // update
+    if (previous) {
+      *previous = ret.first->second;
+    }
+    ret.first->second = value;
+    return true;
+  }
+  return false;
+}
+
+// Same as above except that the key and value are passed as a pair.
+template <class Collection>
+bool UpdateReturnCopy(Collection* const collection,
+                      const typename Collection::value_type& vt,
+                      typename Collection::value_type::second_type* previous) {
+  std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+  if (!ret.second) {
+    // update
+    if (previous) {
+      *previous = ret.first->second;
+    }
+    ret.first->second = vt.second;
+    return true;
+  }
+  return false;
+}
+
+// Tries to insert the given key-value pair into the collection. Returns nullptr if
+// the insert succeeds. Otherwise, returns a pointer to the existing value.
+//
+// This complements UpdateReturnCopy in that it allows to update only after
+// verifying the old value and still insert quickly without having to look up
+// twice. Unlike UpdateReturnCopy this also does not come with the issue of an
+// undefined previous* in case new data was inserted.
+template <class Collection>
+typename Collection::value_type::second_type* InsertOrReturnExisting(
+    Collection* const collection, const typename Collection::value_type& vt) {
+  std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+  if (ret.second) {
+    return nullptr;  // Inserted, no existing previous value.
+  } else {
+    return &ret.first->second;  // Return address of already existing value.
+  }
+}
+
+// Same as above, except for explicit key and data.
+template <class Collection>
+typename Collection::value_type::second_type* InsertOrReturnExisting(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& data) {
+  return InsertOrReturnExisting(collection,
+                                typename Collection::value_type(key, data));
+}
+
+// Erases the collection item identified by the given key, and returns the value
+// associated with that key. It is assumed that the value (i.e., the
+// mapped_type) is a pointer. Returns nullptr if the key was not found in the
+// collection.
+//
+// Examples:
+//   map<string, MyType*> my_map;
+//
+// One line cleanup:
+//     delete EraseKeyReturnValuePtr(&my_map, "abc");
+//
+// Use returned value:
+//     std::unique_ptr<MyType> value_ptr(
+//         EraseKeyReturnValuePtr(&my_map, "abc"));
+//     if (value_ptr.get())
+//       value_ptr->DoSomething();
+//
+template <class Collection>
+typename Collection::value_type::second_type EraseKeyReturnValuePtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection->find(key);
+  if (it == collection->end()) {
+    return nullptr;
+  }
+  typename Collection::value_type::second_type v = it->second;
+  collection->erase(it);
+  return v;
+}
+
+// Inserts all the keys from map_container into key_container, which must
+// support insert(MapContainer::key_type).
+//
+// Note: any initial contents of the key_container are not cleared.
+template <class MapContainer, class KeyContainer>
+void InsertKeysFromMap(const MapContainer& map_container,
+                       KeyContainer* key_container) {
+  GOOGLE_CHECK(key_container != nullptr);
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    key_container->insert(it->first);
+  }
+}
+
+// Appends all the keys from map_container into key_container, which must
+// support push_back(MapContainer::key_type).
+//
+// Note: any initial contents of the key_container are not cleared.
+template <class MapContainer, class KeyContainer>
+void AppendKeysFromMap(const MapContainer& map_container,
+                       KeyContainer* key_container) {
+  GOOGLE_CHECK(key_container != nullptr);
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    key_container->push_back(it->first);
+  }
+}
+
+// A more specialized overload of AppendKeysFromMap to optimize reallocations
+// for the common case in which we're appending keys to a vector and hence can
+// (and sometimes should) call reserve() first.
+//
+// (It would be possible to play SFINAE games to call reserve() for any
+// container that supports it, but this seems to get us 99% of what we need
+// without the complexity of a SFINAE-based solution.)
+template <class MapContainer, class KeyType>
+void AppendKeysFromMap(const MapContainer& map_container,
+                       std::vector<KeyType>* key_container) {
+  GOOGLE_CHECK(key_container != nullptr);
+  // We now have the opportunity to call reserve(). Calling reserve() every
+  // time is a bad idea for some use cases: libstdc++'s implementation of
+  // vector<>::reserve() resizes the vector's backing store to exactly the
+  // given size (unless it's already at least that big). Because of this,
+  // the use case that involves appending a lot of small maps (total size
+  // N) one by one to a vector would be O(N^2). But never calling reserve()
+  // loses the opportunity to improve the use case of adding from a large
+  // map to an empty vector (this improves performance by up to 33%). A
+  // number of heuristics are possible; see the discussion in
+  // cl/34081696. Here we use the simplest one.
+  if (key_container->empty()) {
+    key_container->reserve(map_container.size());
+  }
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    key_container->push_back(it->first);
+  }
+}
+
+// Inserts all the values from map_container into value_container, which must
+// support push_back(MapContainer::mapped_type).
+//
+// Note: any initial contents of the value_container are not cleared.
+template <class MapContainer, class ValueContainer>
+void AppendValuesFromMap(const MapContainer& map_container,
+                         ValueContainer* value_container) {
+  GOOGLE_CHECK(value_container != nullptr);
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    value_container->push_back(it->second);
+  }
+}
+
+// A more specialized overload of AppendValuesFromMap to optimize reallocations
+// for the common case in which we're appending values to a vector and hence
+// can (and sometimes should) call reserve() first.
+//
+// (It would be possible to play SFINAE games to call reserve() for any
+// container that supports it, but this seems to get us 99% of what we need
+// without the complexity of a SFINAE-based solution.)
+template <class MapContainer, class ValueType>
+void AppendValuesFromMap(const MapContainer& map_container,
+                         std::vector<ValueType>* value_container) {
+  GOOGLE_CHECK(value_container != nullptr);
+  // See AppendKeysFromMap for why this is done.
+  if (value_container->empty()) {
+    value_container->reserve(map_container.size());
+  }
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    value_container->push_back(it->second);
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
diff --git a/src/google/protobuf/stubs/mathutil.h b/src/google/protobuf/stubs/mathutil.h
new file mode 100644
index 0000000..1d16bce
--- /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 <cmath>
+#include <float.h>
+#include <limits>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Like std::make_unsigned_t except floating point types map to themselves.
+template <typename T>
+using MakeUnsignedT =
+    typename std::conditional<std::is_integral<T>::value, std::make_unsigned<T>,
+                              std::common_type<T>>::type::type;
+
+// Like std::isnan() except a template function that is defined for all numeric
+// types.
+template <typename T,
+          typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
+bool IsNan(T /*val*/) {
+  return false;
+}
+
+template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
+                                              int>::type = 0>
+bool IsNan(T val) {
+  return std::isnan(val);
+}
+
+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) || internal::IsNan(value)) {
+      return value;
+    }
+    return value > T(0) ? 1 : -1;
+  }
+
+  template <typename T>
+  static bool AlmostEquals(T a, T b) {
+    return 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 internal::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 internal::MakeUnsignedT<T> AbsDiff(const T x, const T y) {
+    // Carries out arithmetic as unsigned to avoid overflow.
+    typedef typename internal::MakeUnsignedT<T> 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 (std::numeric_limits<T>::is_integer) {
+    return x == y;
+  } else {
+    if (!std::isfinite(x) || !std::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..c459991
--- /dev/null
+++ b/src/google/protobuf/stubs/mutex.h
@@ -0,0 +1,218 @@
+// 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_
+
+#include <mutex>
+
+#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
+#include <windows.h>
+
+// GetMessage conflicts with GeneratedMessageReflection::GetMessage().
+#ifdef GetMessage
+#undef GetMessage
+#endif
+
+#endif
+
+#include <google/protobuf/stubs/macros.h>
+
+// Define thread-safety annotations for use below, if we are building with
+// Clang.
+#if defined(__clang__) && !defined(SWIG)
+#define GOOGLE_PROTOBUF_ACQUIRE(...) \
+  __attribute__((acquire_capability(__VA_ARGS__)))
+#define GOOGLE_PROTOBUF_RELEASE(...) \
+  __attribute__((release_capability(__VA_ARGS__)))
+#define GOOGLE_PROTOBUF_SCOPED_CAPABILITY __attribute__((scoped_lockable))
+#define GOOGLE_PROTOBUF_CAPABILITY(x) __attribute__((capability(x)))
+#else
+#define GOOGLE_PROTOBUF_ACQUIRE(...)
+#define GOOGLE_PROTOBUF_RELEASE(...)
+#define GOOGLE_PROTOBUF_SCOPED_CAPABILITY
+#define GOOGLE_PROTOBUF_CAPABILITY(x)
+#endif
+
+#include <google/protobuf/port_def.inc>
+
+// ===================================================================
+// emulates google3/base/mutex.h
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#define GOOGLE_PROTOBUF_LINKER_INITIALIZED
+
+#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
+// This class is a lightweight replacement for std::mutex on Windows platforms.
+// std::mutex does not work on Windows XP SP2 with the latest VC++ libraries,
+// because it utilizes the Concurrency Runtime that is only supported on Windows
+// XP SP3 and above.
+class PROTOBUF_EXPORT CriticalSectionLock {
+ public:
+  CriticalSectionLock() { InitializeCriticalSection(&critical_section_); }
+  ~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); }
+  void lock() { EnterCriticalSection(&critical_section_); }
+  void unlock() { LeaveCriticalSection(&critical_section_); }
+
+ private:
+  CRITICAL_SECTION critical_section_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CriticalSectionLock);
+};
+
+#endif
+
+// In MSVC std::mutex does not have a constexpr constructor.
+// This wrapper makes the constructor constexpr.
+template <typename T>
+class CallOnceInitializedMutex {
+ public:
+  constexpr CallOnceInitializedMutex() : flag_{}, buf_{} {}
+  ~CallOnceInitializedMutex() { get().~T(); }
+
+  void lock() { get().lock(); }
+  void unlock() { get().unlock(); }
+
+ private:
+  T& get() {
+    std::call_once(flag_, [&] { ::new (static_cast<void*>(&buf_)) T(); });
+    return reinterpret_cast<T&>(buf_);
+  }
+
+  std::once_flag flag_;
+  alignas(T) char buf_[sizeof(T)];
+};
+
+// Mutex is a natural type to wrap. As both google and other organization have
+// specialized mutexes. gRPC also provides an injection mechanism for custom
+// mutexes.
+class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
+ public:
+#if defined(__QNX__)
+  constexpr WrappedMutex() = default;
+#else
+  constexpr WrappedMutex() {}
+#endif
+  void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); }
+  void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.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() const {}
+
+ private:
+#if defined(GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP)
+  CallOnceInitializedMutex<CriticalSectionLock> mu_{};
+#elif defined(_WIN32)
+  CallOnceInitializedMutex<std::mutex> mu_{};
+#else
+  std::mutex mu_{};
+#endif
+};
+
+using Mutex = WrappedMutex;
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class GOOGLE_PROTOBUF_SCOPED_CAPABILITY PROTOBUF_EXPORT MutexLock {
+ public:
+  explicit MutexLock(Mutex* mu) GOOGLE_PROTOBUF_ACQUIRE(mu) : mu_(mu) {
+    this->mu_->Lock();
+  }
+  ~MutexLock() GOOGLE_PROTOBUF_RELEASE() { 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 nullptr.
+class PROTOBUF_EXPORT MutexLockMaybe {
+ public:
+  explicit MutexLockMaybe(Mutex *mu) :
+    mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
+  ~MutexLockMaybe() { if (this->mu_ != nullptr) { 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 == nullptr) {
+      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
+
+#undef GOOGLE_PROTOBUF_ACQUIRE
+#undef GOOGLE_PROTOBUF_RELEASE
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MUTEX_H_
diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h
new file mode 100644
index 0000000..070d36d
--- /dev/null
+++ b/src/google/protobuf/stubs/once.h
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_ONCE_H__
+#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
+
+#include <mutex>
+#include <utility>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+using once_flag = std::once_flag;
+template <typename... Args>
+void call_once(Args&&... args ) {
+  std::call_once(std::forward<Args>(args)...);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_ONCE_H__
diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h
new file mode 100644
index 0000000..d10faf9
--- /dev/null
+++ b/src/google/protobuf/stubs/platform_macros.h
@@ -0,0 +1,138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_PLATFORM_MACROS_H_
+#define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
+
+#define GOOGLE_PROTOBUF_PLATFORM_ERROR \
+#error "Host platform was not detected as supported by protobuf"
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+//   or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define GOOGLE_PROTOBUF_ARCH_X64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define GOOGLE_PROTOBUF_ARCH_IA32 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__QNX__)
+#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1
+#if defined(__aarch64__)
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(_M_ARM) || defined(__ARMEL__)
+#define GOOGLE_PROTOBUF_ARCH_ARM 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(_M_ARM64)
+#define GOOGLE_PROTOBUF_ARCH_ARM 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__aarch64__)
+#define GOOGLE_PROTOBUF_ARCH_AARCH64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__mips__)
+#if defined(__LP64__)
+#define GOOGLE_PROTOBUF_ARCH_MIPS64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_MIPS 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(__pnacl__)
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(sparc)
+#define GOOGLE_PROTOBUF_ARCH_SPARC 1
+#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__)
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
+#define GOOGLE_PROTOBUF_ARCH_POWER 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__PPC__)
+#define GOOGLE_PROTOBUF_ARCH_PPC 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__GNUC__)
+# if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
+// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
+# elif defined(__clang__)
+#  if !__has_extension(c_atomic)
+GOOGLE_PROTOBUF_PLATFORM_ERROR
+#  endif
+// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
+# endif
+# if __LP64__
+#  define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+# else
+#  define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+# endif
+#else
+GOOGLE_PROTOBUF_PLATFORM_ERROR
+#endif
+
+#if defined(__APPLE__)
+#define GOOGLE_PROTOBUF_OS_APPLE
+#include <Availability.h>
+#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
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+// __thread keyword requires at least 10.7
+#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..b074cb1
--- /dev/null
+++ b/src/google/protobuf/stubs/port.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_PORT_H_
+#define GOOGLE_PROTOBUF_STUBS_PORT_H_
+
+#include <assert.h>
+#include <cstdint>
+#include <stdlib.h>
+#include <cstddef>
+#include <string>
+#include <string.h>
+
+#include <google/protobuf/stubs/platform_macros.h>
+
+#include <google/protobuf/port_def.inc>
+
+#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 defined(_MSC_VER) && _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
+#ifdef __APPLE__
+#include <machine/endian.h>  // __BYTE_ORDER
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>  // __BYTE_ORDER
+#elif (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__))
+#include <sys/isa_defs.h>  // __BYTE_ORDER
+#elif defined(_AIX) || defined(__TOS_AIX__)
+#include <sys/machine.h>  // BYTE_ORDER
+#else
+#if !defined(__QNX__)
+#include <endian.h>  // __BYTE_ORDER
+#endif
+#endif
+#if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) ||   \
+     (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
+     (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN)) &&      \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+#define PROTOBUF_LITTLE_ENDIAN 1
+#endif
+#endif
+
+// These #includes are for the byte swap functions declared later on.
+#ifdef _MSC_VER
+#include <stdlib.h>  // NOLINT(build/include)
+#include <intrin.h>
+#elif defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__)
+#include <byteswap.h>  // IWYU pragma: export
+#endif
+
+// Legacy: some users reference these (internal-only) macros even though we
+// don't need them any more.
+#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
+
+#define PROTOBUF_RUNTIME_DEPRECATED(message) PROTOBUF_DEPRECATED_MSG(message)
+#define GOOGLE_PROTOBUF_RUNTIME_DEPRECATED(message) \
+  PROTOBUF_DEPRECATED_MSG(message)
+
+// ===================================================================
+// from google3/base/port.h
+
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
+     (defined(_MSC_VER) && _MSC_VER >= 1900))
+// Define this to 1 if the code is compiled in C++11 mode; leave it
+// undefined otherwise.  Do NOT define it to 0 -- that causes
+// '#ifdef LANG_CXX11' to behave differently from '#if LANG_CXX11'.
+#define LANG_CXX11 1
+#else
+#error "Protobuf requires at least C++11."
+#endif
+
+namespace google {
+namespace protobuf {
+
+using ConstStringParam = const std::string &;
+
+typedef unsigned int uint;
+
+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;
+
+static const int32 kint32max = 0x7FFFFFFF;
+static const int32 kint32min = -kint32max - 1;
+static const int64 kint64max = int64_t{0x7FFFFFFFFFFFFFFF};
+static const int64 kint64min = -kint64max - 1;
+static const uint32 kuint32max = 0xFFFFFFFFu;
+static const uint64 kuint64max = uint64_t{0xFFFFFFFFFFFFFFFFu};
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
+    defined(MEMORY_SANITIZER)
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+uint16_t __sanitizer_unaligned_load16(const void *p);
+uint32_t __sanitizer_unaligned_load32(const void *p);
+uint64_t __sanitizer_unaligned_load64(const void *p);
+void __sanitizer_unaligned_store16(void *p, uint16_t v);
+void __sanitizer_unaligned_store32(void *p, uint32_t v);
+void __sanitizer_unaligned_store64(void *p, uint64_t v);
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
+
+inline uint16_t GOOGLE_UNALIGNED_LOAD16(const void *p) {
+  return __sanitizer_unaligned_load16(p);
+}
+
+inline uint32_t GOOGLE_UNALIGNED_LOAD32(const void *p) {
+  return __sanitizer_unaligned_load32(p);
+}
+
+inline uint64_t GOOGLE_UNALIGNED_LOAD64(const void *p) {
+  return __sanitizer_unaligned_load64(p);
+}
+
+inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16_t v) {
+  __sanitizer_unaligned_store16(p, v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32_t v) {
+  __sanitizer_unaligned_store32(p, v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64_t v) {
+  __sanitizer_unaligned_store64(p, v);
+}
+
+#elif defined(GOOGLE_PROTOBUF_USE_UNALIGNED) && GOOGLE_PROTOBUF_USE_UNALIGNED
+
+#define GOOGLE_UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16_t *>(_p))
+#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32_t *>(_p))
+#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64_t *>(_p))
+
+#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16_t *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32_t *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64_t *>(_p) = (_val))
+
+#else
+inline uint16_t GOOGLE_UNALIGNED_LOAD16(const void *p) {
+  uint16_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32_t GOOGLE_UNALIGNED_LOAD32(const void *p) {
+  uint32_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64_t GOOGLE_UNALIGNED_LOAD64(const void *p) {
+  uint64_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16_t v) {
+  memcpy(p, &v, sizeof v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32_t v) {
+  memcpy(p, &v, sizeof v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64_t v) {
+  memcpy(p, &v, sizeof v);
+}
+#endif
+
+#if defined(GOOGLE_PROTOBUF_OS_NACL) \
+    || (defined(__ANDROID__) && defined(__clang__) \
+        && (__clang_major__ == 3 && __clang_minor__ == 8) \
+        && (__clang_patchlevel__ < 275480))
+# define GOOGLE_PROTOBUF_USE_PORTABLE_LOG2
+#endif
+
+// The following guarantees declaration of the byte swap functions.
+#ifdef _MSC_VER
+#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(__linux__) && !defined(__ANDROID__) && !defined(__CYGWIN__)
+
+#ifndef bswap_16
+static inline uint16_t bswap_16(uint16_t x) {
+  return static_cast<uint16_t>(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));
+}
+#define bswap_16(x) bswap_16(x)
+#endif
+
+#ifndef bswap_32
+static inline uint32_t bswap_32(uint32_t x) {
+  return (((x & 0xFF) << 24) |
+          ((x & 0xFF00) << 8) |
+          ((x & 0xFF0000) >> 8) |
+          ((x & 0xFF000000) >> 24));
+}
+#define bswap_32(x) bswap_32(x)
+#endif
+
+#ifndef bswap_64
+static inline uint64_t bswap_64(uint64_t x) {
+  return (((x & uint64_t{0xFFu}) << 56) | ((x & uint64_t{0xFF00u}) << 40) |
+          ((x & uint64_t{0xFF0000u}) << 24) |
+          ((x & uint64_t{0xFF000000u}) << 8) |
+          ((x & uint64_t{0xFF00000000u}) >> 8) |
+          ((x & uint64_t{0xFF0000000000u}) >> 24) |
+          ((x & uint64_t{0xFF000000000000u}) >> 40) |
+          ((x & uint64_t{0xFF00000000000000u}) >> 56));
+}
+#define bswap_64(x) bswap_64(x)
+#endif
+
+#endif
+
+// ===================================================================
+// from google3/util/bits/bits.h
+
+class Bits {
+ public:
+  static uint32_t Log2FloorNonZero(uint32_t n) {
+#if defined(__GNUC__)
+  return 31 ^ static_cast<uint32_t>(__builtin_clz(n));
+#elif defined(_MSC_VER)
+  unsigned long where;
+  _BitScanReverse(&where, n);
+  return where;
+#else
+  return Log2FloorNonZero_Portable(n);
+#endif
+  }
+
+  static uint32_t Log2FloorNonZero64(uint64_t n) {
+    // Older versions of clang run into an instruction-selection failure when
+    // it encounters __builtin_clzll:
+    // https://bugs.chromium.org/p/nativeclient/issues/detail?id=4395
+    // This includes arm-nacl-clang and clang in older Android NDK versions.
+    // To work around this, when we build with those we use the portable
+    // implementation instead.
+#if defined(__GNUC__) && !defined(GOOGLE_PROTOBUF_USE_PORTABLE_LOG2)
+  return 63 ^ static_cast<uint32_t>(__builtin_clzll(n));
+#elif defined(_MSC_VER) && defined(_M_X64)
+  unsigned long where;
+  _BitScanReverse64(&where, n);
+  return where;
+#else
+  return Log2FloorNonZero64_Portable(n);
+#endif
+  }
+ private:
+  static int Log2FloorNonZero_Portable(uint32_t n) {
+    if (n == 0)
+      return -1;
+    int log = 0;
+    uint32_t value = n;
+    for (int i = 4; i >= 0; --i) {
+      int shift = (1 << i);
+      uint32_t x = value >> shift;
+      if (x != 0) {
+        value = x;
+        log += shift;
+      }
+    }
+    assert(value == 1);
+    return log;
+  }
+
+  static int Log2FloorNonZero64_Portable(uint64_t n) {
+    const uint32_t topbits = static_cast<uint32_t>(n >> 32);
+    if (topbits == 0) {
+      // Top bits are zero, so scan in bottom bits
+      return static_cast<int>(Log2FloorNonZero(static_cast<uint32_t>(n)));
+    } else {
+      return 32 + static_cast<int>(Log2FloorNonZero(topbits));
+    }
+  }
+};
+
+// ===================================================================
+// from google3/util/endian/endian.h
+PROTOBUF_EXPORT uint32_t ghtonl(uint32_t x);
+
+class BigEndian {
+ public:
+#ifdef PROTOBUF_LITTLE_ENDIAN
+
+  static uint16_t FromHost16(uint16_t x) { return bswap_16(x); }
+  static uint16_t ToHost16(uint16_t x) { return bswap_16(x); }
+
+  static uint32_t FromHost32(uint32_t x) { return bswap_32(x); }
+  static uint32_t ToHost32(uint32_t x) { return bswap_32(x); }
+
+  static uint64_t FromHost64(uint64_t x) { return bswap_64(x); }
+  static uint64_t ToHost64(uint64_t x) { return bswap_64(x); }
+
+  static bool IsLittleEndian() { return true; }
+
+#else
+
+  static uint16_t FromHost16(uint16_t x) { return x; }
+  static uint16_t ToHost16(uint16_t x) { return x; }
+
+  static uint32_t FromHost32(uint32_t x) { return x; }
+  static uint32_t ToHost32(uint32_t x) { return x; }
+
+  static uint64_t FromHost64(uint64_t x) { return x; }
+  static uint64_t ToHost64(uint64_t x) { return x; }
+
+  static bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+  // Functions to do unaligned loads and stores in big-endian order.
+  static uint16_t Load16(const void *p) {
+    return ToHost16(GOOGLE_UNALIGNED_LOAD16(p));
+  }
+
+  static void Store16(void *p, uint16_t v) {
+    GOOGLE_UNALIGNED_STORE16(p, FromHost16(v));
+  }
+
+  static uint32_t Load32(const void *p) {
+    return ToHost32(GOOGLE_UNALIGNED_LOAD32(p));
+  }
+
+  static void Store32(void *p, uint32_t v) {
+    GOOGLE_UNALIGNED_STORE32(p, FromHost32(v));
+  }
+
+  static uint64_t Load64(const void *p) {
+    return ToHost64(GOOGLE_UNALIGNED_LOAD64(p));
+  }
+
+  static void Store64(void *p, uint64_t v) {
+    GOOGLE_UNALIGNED_STORE64(p, FromHost64(v));
+  }
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_PORT_H_
diff --git a/src/google/protobuf/stubs/status.cc b/src/google/protobuf/stubs/status.cc
new file mode 100644
index 0000000..f5c0fa4
--- /dev/null
+++ b/src/google/protobuf/stubs/status.cc
@@ -0,0 +1,262 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 status_internal {
+namespace {
+
+inline std::string StatusCodeToString(StatusCode code) {
+  switch (code) {
+    case StatusCode::kOk:
+      return "OK";
+    case StatusCode::kCancelled:
+      return "CANCELLED";
+    case StatusCode::kUnknown:
+      return "UNKNOWN";
+    case StatusCode::kInvalidArgument:
+      return "INVALID_ARGUMENT";
+    case StatusCode::kDeadlineExceeded:
+      return "DEADLINE_EXCEEDED";
+    case StatusCode::kNotFound:
+      return "NOT_FOUND";
+    case StatusCode::kAlreadyExists:
+      return "ALREADY_EXISTS";
+    case StatusCode::kPermissionDenied:
+      return "PERMISSION_DENIED";
+    case StatusCode::kUnauthenticated:
+      return "UNAUTHENTICATED";
+    case StatusCode::kResourceExhausted:
+      return "RESOURCE_EXHAUSTED";
+    case StatusCode::kFailedPrecondition:
+      return "FAILED_PRECONDITION";
+    case StatusCode::kAborted:
+      return "ABORTED";
+    case StatusCode::kOutOfRange:
+      return "OUT_OF_RANGE";
+    case StatusCode::kUnimplemented:
+      return "UNIMPLEMENTED";
+    case StatusCode::kInternal:
+      return "INTERNAL";
+    case StatusCode::kUnavailable:
+      return "UNAVAILABLE";
+    case StatusCode::kDataLoss:
+      return "DATA_LOSS";
+  }
+
+  // No default clause, clang will abort if a code is missing from
+  // above switch.
+  return "UNKNOWN";
+}
+
+}  // namespace
+
+Status::Status() : error_code_(StatusCode::kOk) {}
+
+Status::Status(StatusCode error_code, StringPiece error_message)
+    : error_code_(error_code) {
+  if (error_code != StatusCode::kOk) {
+    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_;
+}
+
+std::string Status::ToString() const {
+  if (error_code_ == StatusCode::kOk) {
+    return "OK";
+  } else {
+    if (error_message_.empty()) {
+      return StatusCodeToString(error_code_);
+    } else {
+      return StatusCodeToString(error_code_) + ":" + error_message_;
+    }
+  }
+}
+
+Status OkStatus() { return Status(); }
+
+std::ostream& operator<<(std::ostream& os, const Status& x) {
+  os << x.ToString();
+  return os;
+}
+
+bool IsAborted(const Status& status) {
+  return status.code() == StatusCode::kAborted;
+}
+
+bool IsAlreadyExists(const Status& status) {
+  return status.code() == StatusCode::kAlreadyExists;
+}
+
+bool IsCancelled(const Status& status) {
+  return status.code() == StatusCode::kCancelled;
+}
+
+bool IsDataLoss(const Status& status) {
+  return status.code() == StatusCode::kDataLoss;
+}
+
+bool IsDeadlineExceeded(const Status& status) {
+  return status.code() == StatusCode::kDeadlineExceeded;
+}
+
+bool IsFailedPrecondition(const Status& status) {
+  return status.code() == StatusCode::kFailedPrecondition;
+}
+
+bool IsInternal(const Status& status) {
+  return status.code() == StatusCode::kInternal;
+}
+
+bool IsInvalidArgument(const Status& status) {
+  return status.code() == StatusCode::kInvalidArgument;
+}
+
+bool IsNotFound(const Status& status) {
+  return status.code() == StatusCode::kNotFound;
+}
+
+bool IsOutOfRange(const Status& status) {
+  return status.code() == StatusCode::kOutOfRange;
+}
+
+bool IsPermissionDenied(const Status& status) {
+  return status.code() == StatusCode::kPermissionDenied;
+}
+
+bool IsResourceExhausted(const Status& status) {
+  return status.code() == StatusCode::kResourceExhausted;
+}
+
+bool IsUnauthenticated(const Status& status) {
+  return status.code() == StatusCode::kUnauthenticated;
+}
+
+bool IsUnavailable(const Status& status) {
+  return status.code() == StatusCode::kUnavailable;
+}
+
+bool IsUnimplemented(const Status& status) {
+  return status.code() == StatusCode::kUnimplemented;
+}
+
+bool IsUnknown(const Status& status) {
+  return status.code() == StatusCode::kUnknown;
+}
+
+Status AbortedError(StringPiece message) {
+  return Status(StatusCode::kAborted, message);
+}
+
+Status AlreadyExistsError(StringPiece message) {
+  return Status(StatusCode::kAlreadyExists, message);
+}
+
+Status CancelledError(StringPiece message) {
+  return Status(StatusCode::kCancelled, message);
+}
+
+Status DataLossError(StringPiece message) {
+  return Status(StatusCode::kDataLoss, message);
+}
+
+Status DeadlineExceededError(StringPiece message) {
+  return Status(StatusCode::kDeadlineExceeded, message);
+}
+
+Status FailedPreconditionError(StringPiece message) {
+  return Status(StatusCode::kFailedPrecondition, message);
+}
+
+Status InternalError(StringPiece message) {
+  return Status(StatusCode::kInternal, message);
+}
+
+Status InvalidArgumentError(StringPiece message) {
+  return Status(StatusCode::kInvalidArgument, message);
+}
+
+Status NotFoundError(StringPiece message) {
+  return Status(StatusCode::kNotFound, message);
+}
+
+Status OutOfRangeError(StringPiece message) {
+  return Status(StatusCode::kOutOfRange, message);
+}
+
+Status PermissionDeniedError(StringPiece message) {
+  return Status(StatusCode::kPermissionDenied, message);
+}
+
+Status ResourceExhaustedError(StringPiece message) {
+  return Status(StatusCode::kResourceExhausted, message);
+}
+
+Status UnauthenticatedError(StringPiece message) {
+  return Status(StatusCode::kUnauthenticated, message);
+}
+
+Status UnavailableError(StringPiece message) {
+  return Status(StatusCode::kUnavailable, message);
+}
+
+Status UnimplementedError(StringPiece message) {
+  return Status(StatusCode::kUnimplemented, message);
+}
+
+Status UnknownError(StringPiece message) {
+  return Status(StatusCode::kUnknown, message);
+}
+
+}  // namespace status_internal
+}  // 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..c858cf6
--- /dev/null
+++ b/src/google/protobuf/stubs/status.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUS_H_
+
+#include <string>
+
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace status_internal {
+
+// These values must match error codes defined in google/rpc/code.proto.
+enum class StatusCode : int {
+  kOk = 0,
+  kCancelled = 1,
+  kUnknown = 2,
+  kInvalidArgument = 3,
+  kDeadlineExceeded = 4,
+  kNotFound = 5,
+  kAlreadyExists = 6,
+  kPermissionDenied = 7,
+  kUnauthenticated = 16,
+  kResourceExhausted = 8,
+  kFailedPrecondition = 9,
+  kAborted = 10,
+  kOutOfRange = 11,
+  kUnimplemented = 12,
+  kInternal = 13,
+  kUnavailable = 14,
+  kDataLoss = 15,
+};
+
+class PROTOBUF_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::kOk is
+  // constructed.
+  Status(StatusCode error_code, StringPiece error_message);
+  Status(const Status&);
+  Status& operator=(const Status& x);
+  ~Status() {}
+
+  // Accessor
+  bool ok() const { return error_code_ == StatusCode::kOk; }
+  StatusCode code() const { return error_code_; }
+  StringPiece 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.
+  std::string ToString() const;
+
+ private:
+  StatusCode error_code_;
+  std::string error_message_;
+};
+
+// Returns an OK status, equivalent to a default constructed instance. Prefer
+// usage of `OkStatus()` when constructing such an OK status.
+PROTOBUF_EXPORT Status OkStatus();
+
+// Prints a human-readable representation of 'x' to 'os'.
+PROTOBUF_EXPORT std::ostream& operator<<(std::ostream& os, const Status& x);
+
+// These convenience functions return `true` if a given status matches the
+// `StatusCode` error code of its associated function.
+PROTOBUF_EXPORT bool IsAborted(const Status& status);
+PROTOBUF_EXPORT bool IsAlreadyExists(const Status& status);
+PROTOBUF_EXPORT bool IsCancelled(const Status& status);
+PROTOBUF_EXPORT bool IsDataLoss(const Status& status);
+PROTOBUF_EXPORT bool IsDeadlineExceeded(const Status& status);
+PROTOBUF_EXPORT bool IsFailedPrecondition(const Status& status);
+PROTOBUF_EXPORT bool IsInternal(const Status& status);
+PROTOBUF_EXPORT bool IsInvalidArgument(const Status& status);
+PROTOBUF_EXPORT bool IsNotFound(const Status& status);
+PROTOBUF_EXPORT bool IsOutOfRange(const Status& status);
+PROTOBUF_EXPORT bool IsPermissionDenied(const Status& status);
+PROTOBUF_EXPORT bool IsResourceExhausted(const Status& status);
+PROTOBUF_EXPORT bool IsUnauthenticated(const Status& status);
+PROTOBUF_EXPORT bool IsUnavailable(const Status& status);
+PROTOBUF_EXPORT bool IsUnimplemented(const Status& status);
+PROTOBUF_EXPORT bool IsUnknown(const Status& status);
+
+// These convenience functions create an `Status` object with an error code as
+// indicated by the associated function name, using the error message passed in
+// `message`.
+//
+// These functions are intentionally named `*Error` rather than `*Status` to
+// match the names from Abseil:
+// https://github.com/abseil/abseil-cpp/blob/2e9532cc6c701a8323d0cffb468999ab804095ab/absl/status/status.h#L716
+PROTOBUF_EXPORT Status AbortedError(StringPiece message);
+PROTOBUF_EXPORT Status AlreadyExistsError(StringPiece message);
+PROTOBUF_EXPORT Status CancelledError(StringPiece message);
+PROTOBUF_EXPORT Status DataLossError(StringPiece message);
+PROTOBUF_EXPORT Status DeadlineExceededError(StringPiece message);
+PROTOBUF_EXPORT Status FailedPreconditionError(StringPiece message);
+PROTOBUF_EXPORT Status InternalError(StringPiece message);
+PROTOBUF_EXPORT Status InvalidArgumentError(StringPiece message);
+PROTOBUF_EXPORT Status NotFoundError(StringPiece message);
+PROTOBUF_EXPORT Status OutOfRangeError(StringPiece message);
+PROTOBUF_EXPORT Status PermissionDeniedError(StringPiece message);
+PROTOBUF_EXPORT Status ResourceExhaustedError(StringPiece message);
+PROTOBUF_EXPORT Status UnauthenticatedError(StringPiece message);
+PROTOBUF_EXPORT Status UnavailableError(StringPiece message);
+PROTOBUF_EXPORT Status UnimplementedError(StringPiece message);
+PROTOBUF_EXPORT Status UnknownError(StringPiece message);
+
+}  // namespace status_internal
+
+using ::google::protobuf::util::status_internal::Status;
+using ::google::protobuf::util::status_internal::StatusCode;
+
+using ::google::protobuf::util::status_internal::IsAborted;
+using ::google::protobuf::util::status_internal::IsAlreadyExists;
+using ::google::protobuf::util::status_internal::IsCancelled;
+using ::google::protobuf::util::status_internal::IsDataLoss;
+using ::google::protobuf::util::status_internal::IsDeadlineExceeded;
+using ::google::protobuf::util::status_internal::IsFailedPrecondition;
+using ::google::protobuf::util::status_internal::IsInternal;
+using ::google::protobuf::util::status_internal::IsInvalidArgument;
+using ::google::protobuf::util::status_internal::IsNotFound;
+using ::google::protobuf::util::status_internal::IsOutOfRange;
+using ::google::protobuf::util::status_internal::IsPermissionDenied;
+using ::google::protobuf::util::status_internal::IsResourceExhausted;
+using ::google::protobuf::util::status_internal::IsUnauthenticated;
+using ::google::protobuf::util::status_internal::IsUnavailable;
+using ::google::protobuf::util::status_internal::IsUnimplemented;
+using ::google::protobuf::util::status_internal::IsUnknown;
+
+using ::google::protobuf::util::status_internal::AbortedError;
+using ::google::protobuf::util::status_internal::AlreadyExistsError;
+using ::google::protobuf::util::status_internal::CancelledError;
+using ::google::protobuf::util::status_internal::DataLossError;
+using ::google::protobuf::util::status_internal::DeadlineExceededError;
+using ::google::protobuf::util::status_internal::FailedPreconditionError;
+using ::google::protobuf::util::status_internal::InternalError;
+using ::google::protobuf::util::status_internal::InvalidArgumentError;
+using ::google::protobuf::util::status_internal::NotFoundError;
+using ::google::protobuf::util::status_internal::OkStatus;
+using ::google::protobuf::util::status_internal::OutOfRangeError;
+using ::google::protobuf::util::status_internal::PermissionDeniedError;
+using ::google::protobuf::util::status_internal::ResourceExhaustedError;
+using ::google::protobuf::util::status_internal::UnauthenticatedError;
+using ::google::protobuf::util::status_internal::UnavailableError;
+using ::google::protobuf::util::status_internal::UnimplementedError;
+using ::google::protobuf::util::status_internal::UnknownError;
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..407ff4c
--- /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 PROTOBUF_NAMESPACE_ID::util::Status _status = (expr);              \
+    if (PROTOBUF_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.value();
+  }
+  return result.status();
+}
+
+#define ASSIGN_OR_RETURN_IMPL(status, lhs, rexpr) \
+  Status status = DoAssignOrReturn(lhs, (rexpr)); \
+  if (PROTOBUF_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..9e9edf7
--- /dev/null
+++ b/src/google/protobuf/stubs/status_test.cc
@@ -0,0 +1,278 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#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, Constructor) {
+  EXPECT_EQ(util::StatusCode::kOk,
+            util::Status(util::StatusCode::kOk, "").code());
+  EXPECT_EQ(util::StatusCode::kCancelled,
+            util::Status(util::StatusCode::kCancelled, "").code());
+  EXPECT_EQ(util::StatusCode::kUnknown,
+            util::Status(util::StatusCode::kUnknown, "").code());
+  EXPECT_EQ(util::StatusCode::kInvalidArgument,
+            util::Status(util::StatusCode::kInvalidArgument, "").code());
+  EXPECT_EQ(util::StatusCode::kDeadlineExceeded,
+            util::Status(util::StatusCode::kDeadlineExceeded, "").code());
+  EXPECT_EQ(util::StatusCode::kNotFound,
+            util::Status(util::StatusCode::kNotFound, "").code());
+  EXPECT_EQ(util::StatusCode::kAlreadyExists,
+            util::Status(util::StatusCode::kAlreadyExists, "").code());
+  EXPECT_EQ(util::StatusCode::kPermissionDenied,
+            util::Status(util::StatusCode::kPermissionDenied, "").code());
+  EXPECT_EQ(util::StatusCode::kUnauthenticated,
+            util::Status(util::StatusCode::kUnauthenticated, "").code());
+  EXPECT_EQ(util::StatusCode::kResourceExhausted,
+            util::Status(util::StatusCode::kResourceExhausted, "").code());
+  EXPECT_EQ(util::StatusCode::kFailedPrecondition,
+            util::Status(util::StatusCode::kFailedPrecondition, "").code());
+  EXPECT_EQ(util::StatusCode::kAborted,
+            util::Status(util::StatusCode::kAborted, "").code());
+  EXPECT_EQ(util::StatusCode::kOutOfRange,
+            util::Status(util::StatusCode::kOutOfRange, "").code());
+  EXPECT_EQ(util::StatusCode::kUnimplemented,
+            util::Status(util::StatusCode::kUnimplemented, "").code());
+  EXPECT_EQ(util::StatusCode::kInternal,
+            util::Status(util::StatusCode::kInternal, "").code());
+  EXPECT_EQ(util::StatusCode::kUnavailable,
+            util::Status(util::StatusCode::kUnavailable, "").code());
+  EXPECT_EQ(util::StatusCode::kDataLoss,
+            util::Status(util::StatusCode::kDataLoss, "").code());
+}
+
+TEST(Status, ConstructorZero) {
+  util::Status status(util::StatusCode::kOk, "msg");
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ("OK", status.ToString());
+  EXPECT_EQ(util::OkStatus(), status);
+}
+
+TEST(Status, ConvenienceConstructors) {
+  EXPECT_EQ(util::StatusCode::kOk, util::OkStatus().code());
+  EXPECT_EQ("", util::OkStatus().message());
+
+  EXPECT_EQ(util::StatusCode::kCancelled, util::CancelledError("").code());
+  EXPECT_EQ("", util::CancelledError("").message());
+  EXPECT_EQ("foo", util::CancelledError("foo").message());
+  EXPECT_EQ("bar", util::CancelledError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kUnknown, util::UnknownError("").code());
+  EXPECT_EQ("", util::UnknownError("").message());
+  EXPECT_EQ("foo", util::UnknownError("foo").message());
+  EXPECT_EQ("bar", util::UnknownError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kInvalidArgument,
+            util::InvalidArgumentError("").code());
+  EXPECT_EQ("", util::InvalidArgumentError("").message());
+  EXPECT_EQ("foo", util::InvalidArgumentError("foo").message());
+  EXPECT_EQ("bar", util::InvalidArgumentError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kDeadlineExceeded,
+            util::DeadlineExceededError("").code());
+  EXPECT_EQ("", util::DeadlineExceededError("").message());
+  EXPECT_EQ("foo", util::DeadlineExceededError("foo").message());
+  EXPECT_EQ("bar", util::DeadlineExceededError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kNotFound, util::NotFoundError("").code());
+  EXPECT_EQ("", util::NotFoundError("").message());
+  EXPECT_EQ("foo", util::NotFoundError("foo").message());
+  EXPECT_EQ("bar", util::NotFoundError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kAlreadyExists,
+            util::AlreadyExistsError("").code());
+  EXPECT_EQ("", util::AlreadyExistsError("").message());
+  EXPECT_EQ("foo", util::AlreadyExistsError("foo").message());
+  EXPECT_EQ("bar", util::AlreadyExistsError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kPermissionDenied,
+            util::PermissionDeniedError("").code());
+  EXPECT_EQ("", util::PermissionDeniedError("").message());
+  EXPECT_EQ("foo", util::PermissionDeniedError("foo").message());
+  EXPECT_EQ("bar", util::PermissionDeniedError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kUnauthenticated,
+            util::UnauthenticatedError("").code());
+  EXPECT_EQ("", util::UnauthenticatedError("").message());
+  EXPECT_EQ("foo", util::UnauthenticatedError("foo").message());
+  EXPECT_EQ("bar", util::UnauthenticatedError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kResourceExhausted,
+            util::ResourceExhaustedError("").code());
+  EXPECT_EQ("", util::ResourceExhaustedError("").message());
+  EXPECT_EQ("foo", util::ResourceExhaustedError("foo").message());
+  EXPECT_EQ("bar", util::ResourceExhaustedError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kFailedPrecondition,
+            util::FailedPreconditionError("").code());
+  EXPECT_EQ("", util::FailedPreconditionError("").message());
+  EXPECT_EQ("foo", util::FailedPreconditionError("foo").message());
+  EXPECT_EQ("bar", util::FailedPreconditionError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kAborted, util::AbortedError("").code());
+  EXPECT_EQ("", util::AbortedError("").message());
+  EXPECT_EQ("foo", util::AbortedError("foo").message());
+  EXPECT_EQ("bar", util::AbortedError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kOutOfRange, util::OutOfRangeError("").code());
+  EXPECT_EQ("", util::OutOfRangeError("").message());
+  EXPECT_EQ("foo", util::OutOfRangeError("foo").message());
+  EXPECT_EQ("bar", util::OutOfRangeError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kUnimplemented,
+            util::UnimplementedError("").code());
+  EXPECT_EQ("", util::UnimplementedError("").message());
+  EXPECT_EQ("foo", util::UnimplementedError("foo").message());
+  EXPECT_EQ("bar", util::UnimplementedError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kInternal, util::InternalError("").code());
+  EXPECT_EQ("", util::InternalError("").message());
+  EXPECT_EQ("foo", util::InternalError("foo").message());
+  EXPECT_EQ("bar", util::InternalError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kUnavailable, util::UnavailableError("").code());
+  EXPECT_EQ("", util::UnavailableError("").message());
+  EXPECT_EQ("foo", util::UnavailableError("foo").message());
+  EXPECT_EQ("bar", util::UnavailableError("bar").message());
+
+  EXPECT_EQ(util::StatusCode::kDataLoss, util::DataLossError("").code());
+  EXPECT_EQ("", util::DataLossError("").message());
+  EXPECT_EQ("foo", util::DataLossError("foo").message());
+  EXPECT_EQ("bar", util::DataLossError("bar").message());
+}
+
+TEST(Status, ConvenienceTests) {
+  EXPECT_TRUE(util::OkStatus().ok());
+  EXPECT_TRUE(util::IsCancelled(util::CancelledError("")));
+  EXPECT_TRUE(util::IsUnknown(util::UnknownError("")));
+  EXPECT_TRUE(util::IsInvalidArgument(util::InvalidArgumentError("")));
+  EXPECT_TRUE(util::IsDeadlineExceeded(util::DeadlineExceededError("")));
+  EXPECT_TRUE(util::IsNotFound(util::NotFoundError("")));
+  EXPECT_TRUE(util::IsAlreadyExists(util::AlreadyExistsError("")));
+  EXPECT_TRUE(util::IsPermissionDenied(util::PermissionDeniedError("")));
+  EXPECT_TRUE(util::IsUnauthenticated(util::UnauthenticatedError("")));
+  EXPECT_TRUE(util::IsResourceExhausted(util::ResourceExhaustedError("")));
+  EXPECT_TRUE(util::IsFailedPrecondition(util::FailedPreconditionError("")));
+  EXPECT_TRUE(util::IsAborted(util::AbortedError("")));
+  EXPECT_TRUE(util::IsOutOfRange(util::OutOfRangeError("")));
+  EXPECT_TRUE(util::IsUnimplemented(util::UnimplementedError("")));
+  EXPECT_TRUE(util::IsInternal(util::InternalError("")));
+  EXPECT_TRUE(util::IsUnavailable(util::UnavailableError("")));
+  EXPECT_TRUE(util::IsDataLoss(util::DataLossError("")));
+}
+
+TEST(Status, Empty) {
+  util::Status status;
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ(util::OkStatus(), status);
+  EXPECT_EQ(util::StatusCode::kOk, status.code());
+  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::InvalidArgumentError("");
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ("", status.message().ToString());
+  EXPECT_EQ("INVALID_ARGUMENT", status.ToString());
+  status = util::InvalidArgumentError("msg");
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ("msg", status.message().ToString());
+  EXPECT_EQ("INVALID_ARGUMENT:msg", status.ToString());
+  status = util::Status(util::StatusCode::kOk, "msg");
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ("", status.message().ToString());
+  EXPECT_EQ("OK", status.ToString());
+}
+
+TEST(Status, Copy) {
+  util::Status a = util::UnknownError("message");
+  util::Status b(a);
+  ASSERT_EQ(a.ToString(), b.ToString());
+}
+
+TEST(Status, Assign) {
+  util::Status a = util::UnknownError("message");
+  util::Status b;
+  b = a;
+  ASSERT_EQ(a.ToString(), b.ToString());
+}
+
+TEST(Status, AssignEmpty) {
+  util::Status a = util::UnknownError("message");
+  util::Status b;
+  a = b;
+  ASSERT_EQ(std::string("OK"), a.ToString());
+  ASSERT_TRUE(b.ok());
+  ASSERT_TRUE(a.ok());
+}
+
+TEST(Status, EqualsOK) { ASSERT_EQ(util::OkStatus(), util::Status()); }
+
+TEST(Status, EqualsSame) {
+  const util::Status a = util::CancelledError("message");
+  const util::Status b = util::CancelledError("message");
+  ASSERT_EQ(a, b);
+}
+
+TEST(Status, EqualsCopy) {
+  const util::Status a = util::CancelledError("message");
+  const util::Status b = a;
+  ASSERT_EQ(a, b);
+}
+
+TEST(Status, EqualsDifferentCode) {
+  const util::Status a = util::CancelledError("message");
+  const util::Status b = util::UnknownError("message");
+  ASSERT_NE(a, b);
+}
+
+TEST(Status, EqualsDifferentMessage) {
+  const util::Status a = util::CancelledError("message");
+  const util::Status b = util::CancelledError("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..9c0a178
--- /dev/null
+++ b/src/google/protobuf/stubs/statusor.cc
@@ -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.
+
+#include <google/protobuf/stubs/statusor.h>
+
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace statusor_internal {
+
+void StatusOrHelper::Crash(const Status& status) {
+  GOOGLE_LOG(FATAL) << "Attempting to fetch value instead of handling error "
+                    << status.ToString();
+}
+
+}  // namespace statusor_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..20e603e
--- /dev/null
+++ b/src/google/protobuf/stubs/statusor.h
@@ -0,0 +1,253 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 OkStatus(). Further, StatusOr<T*> does not allow the
+// contained pointer to be nullptr.
+//
+// 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.value();
+//    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.value());
+//    foo->DoSomethingCool();
+//  } else {
+//    LOG(ERROR) << result.status();
+//  }
+//
+// Example factory implementation returning StatusOr<T*>:
+//
+//  StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
+//    if (arg <= 0) {
+//      return InvalidArgumentError("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>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace statusor_internal {
+
+template<typename T>
+class StatusOr {
+  template<typename U> friend class StatusOr;
+
+ public:
+  using value_type = T;
+
+  // Construct a new StatusOr with Status::UNKNOWN status.
+  // Construct a new StatusOr with UnknownError() status.
+  explicit StatusOr();
+
+  // Construct a new StatusOr with the given non-ok status. After calling
+  // this constructor, calls to value() 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 != OkStatus(). This requirement is DCHECKed.
+  // In optimized builds, passing OkStatus() 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 nullptr. After calling this constructor, calls to
+  // value() 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 != nullptr. 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 OkStatus().
+  const Status& status() const;
+
+  // Returns this->status().ok()
+  bool ok() const;
+
+  // Returns a reference to our current value, or CHECK-fails if !this->ok().
+  const T& value () const;
+
+ private:
+  Status status_;
+  T value_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation details for StatusOr<T>
+
+class PROTOBUF_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 nullptr.
+  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 == nullptr; }
+};
+
+template <typename T>
+inline StatusOr<T>::StatusOr() : status_(util::UnknownError("")) {}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const Status& status) {
+  if (status.ok()) {
+    status_ = util::InternalError("OkStatus() is not a valid argument.");
+  } else {
+    status_ = status;
+  }
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const T& value) {
+  if (StatusOrHelper::Specialize<T>::IsValueNull(value)) {
+    status_ = util::InternalError("nullptr is not a valid argument.");
+  } else {
+    status_ = util::OkStatus();
+    value_ = value;
+  }
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
+    : status_(other.status_), value_(other.value_) {
+}
+
+template<typename T>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
+  status_ = other.status_;
+  value_ = other.value_;
+  return *this;
+}
+
+template<typename T>
+template<typename U>
+inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
+    : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
+}
+
+template<typename T>
+template<typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
+  status_ = other.status_;
+  if (status_.ok()) value_ = other.value_;
+  return *this;
+}
+
+template<typename T>
+inline const Status& StatusOr<T>::status() const {
+  return status_;
+}
+
+template<typename T>
+inline bool StatusOr<T>::ok() const {
+  return status().ok();
+}
+
+template<typename T>
+inline const T& StatusOr<T>::value() const {
+  if (!status_.ok()) {
+    StatusOrHelper::Crash(status_);
+  }
+  return value_;
+}
+
+}  // namespace statusor_internal
+
+using ::google::protobuf::util::statusor_internal::StatusOr;
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..403adcc
--- /dev/null
+++ b/src/google/protobuf/stubs/statusor_test.cc
@@ -0,0 +1,272 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#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(util::UnknownError(""), thing.status());
+}
+
+TEST(StatusOr, TestStatusCtor) {
+  StatusOr<int> thing(util::CancelledError(""));
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(util::CancelledError(""), thing.status());
+}
+
+TEST(StatusOr, TestValueCtor) {
+  const int kI = 4;
+  StatusOr<int> thing(kI);
+  EXPECT_TRUE(thing.ok());
+  EXPECT_EQ(kI, thing.value());
+}
+
+TEST(StatusOr, TestCopyCtorStatusOk) {
+  const int kI = 4;
+  StatusOr<int> original(kI);
+  StatusOr<int> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+  EXPECT_EQ(original.value(), copy.value());
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOk) {
+  StatusOr<int> original(util::CancelledError(""));
+  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.value(), copy.value());
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
+  StatusOr<int> original(util::CancelledError(""));
+  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.value(), target.value());
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOk) {
+  StatusOr<int> source(util::CancelledError(""));
+  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.value(), target.value());
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOkConverting) {
+  StatusOr<int> source(util::CancelledError(""));
+  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(util::CancelledError(""));
+  EXPECT_FALSE(bad.ok());
+  EXPECT_EQ(util::CancelledError(""), bad.status());
+}
+
+TEST(StatusOr, TestValue) {
+  const int kI = 4;
+  StatusOr<int> thing(kI);
+  EXPECT_EQ(kI, thing.value());
+}
+
+TEST(StatusOr, TestValueConst) {
+  const int kI = 4;
+  const StatusOr<int> thing(kI);
+  EXPECT_EQ(kI, thing.value());
+}
+
+TEST(StatusOr, TestPointerDefaultCtor) {
+  StatusOr<int*> thing;
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(util::UnknownError(""), thing.status());
+}
+
+TEST(StatusOr, TestPointerStatusCtor) {
+  StatusOr<int*> thing(util::CancelledError(""));
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(util::CancelledError(""), thing.status());
+}
+
+TEST(StatusOr, TestPointerValueCtor) {
+  const int kI = 4;
+  StatusOr<const int*> thing(&kI);
+  EXPECT_TRUE(thing.ok());
+  EXPECT_EQ(&kI, thing.value());
+}
+
+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.value(), copy.value());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
+  StatusOr<int*> original(util::CancelledError(""));
+  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.value()), copy.value());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
+  StatusOr<Derived*> original(util::CancelledError(""));
+  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.value(), target.value());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
+  StatusOr<int*> source(util::CancelledError(""));
+  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.value()), target.value());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) {
+  StatusOr<Derived*> source(util::CancelledError(""));
+  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(util::CancelledError(""));
+  EXPECT_EQ(util::CancelledError(""), bad.status());
+}
+
+TEST(StatusOr, TestPointerValue) {
+  const int kI = 0;
+  StatusOr<const int*> thing(&kI);
+  EXPECT_EQ(&kI, thing.value());
+}
+
+TEST(StatusOr, TestPointerValueConst) {
+  const int kI = 0;
+  const StatusOr<const int*> thing(&kI);
+  EXPECT_EQ(&kI, thing.value());
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/stl_util.h b/src/google/protobuf/stubs/stl_util.h
new file mode 100644
index 0000000..e6260d0
--- /dev/null
+++ b/src/google/protobuf/stubs/stl_util.h
@@ -0,0 +1,90 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/util/gtl/stl_util.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+#include <algorithm>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>  // NOLINT
+
+namespace google {
+namespace protobuf {
+
+// Inside Google, this function implements a horrible, disgusting hack in which
+// we reach into the string's private implementation and resize it without
+// initializing the new bytes.  In some cases doing this can significantly
+// improve performance.  However, since it's totally non-portable it has no
+// place in open source code.  Feel free to fill this function in with your
+// own disgusting hack if you want the perf boost.
+inline void STLStringResizeUninitialized(std::string* s, size_t new_size) {
+  s->resize(new_size);
+}
+
+// As above, but we make sure to follow amortized growth in which we always
+// increase the capacity by at least a constant factor >1.
+inline void STLStringResizeUninitializedAmortized(std::string* s,
+                                                  size_t new_size) {
+  const size_t cap = s->capacity();
+  if (new_size > cap) {
+    // Make sure to always grow by at least a factor of 2x.
+    s->reserve(std::max<size_t>(new_size, 2 * cap));
+  }
+  STLStringResizeUninitialized(s, new_size);
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(std::string* str) {
+  // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+  return str->empty() ? nullptr : &*str->begin();
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>  // NOLINT
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
diff --git a/src/google/protobuf/stubs/stringpiece.cc b/src/google/protobuf/stubs/stringpiece.cc
new file mode 100644
index 0000000..7188046
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece.cc
@@ -0,0 +1,256 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <string.h>
+#include <algorithm>
+#include <climits>
+#include <string>
+#include <ostream>
+
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace stringpiece_internal {
+
+std::ostream& operator<<(std::ostream& o, StringPiece piece) {
+  o.write(piece.data(), piece.size());
+  return o;
+}
+
+void StringPiece::LogFatalSizeTooBig(size_t size, const char* details) {
+  GOOGLE_LOG(FATAL) << "size too big: " << size << " details: " << details;
+}
+
+void StringPiece::CopyToString(std::string* target) const {
+  target->assign(ptr_, length_);
+}
+
+void StringPiece::AppendToString(std::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::size_type StringPiece::copy(char* buf, size_type n,
+                                         size_type pos) const {
+  size_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::size_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::size_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 != nullptr ? result - ptr_ : npos;
+}
+
+StringPiece::size_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::size_type StringPiece::rfind(char c, size_type pos) const {
+  // Note: memrchr() is not available on Windows.
+  if (empty()) return npos;
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (ptr_[i] == c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  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::size_type length = characters_wanted.length();
+  const char* const data = characters_wanted.data();
+  for (StringPiece::size_type i = 0; i < length; ++i) {
+    table[static_cast<unsigned char>(data[i])] = true;
+  }
+}
+
+StringPiece::size_type StringPiece::find_first_of(StringPiece s,
+                                                  size_type pos) const {
+  if (empty() || s.empty()) {
+    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 (size_type i = pos; i < length_; ++i) {
+    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_first_not_of(StringPiece s,
+                                                      size_type pos) const {
+  if (empty()) return npos;
+  if (s.empty()) 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 (size_type i = pos; i < length_; ++i) {
+    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_first_not_of(char c,
+                                                      size_type pos) const {
+  if (empty()) return npos;
+
+  for (; pos < static_cast<size_type>(length_); ++pos) {
+    if (ptr_[pos] != c) {
+      return pos;
+    }
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_last_of(StringPiece s,
+                                                 size_type pos) const {
+  if (empty() || s.empty()) 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 (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_last_not_of(StringPiece s,
+                                                     size_type pos) const {
+  if (empty()) return npos;
+
+  size_type i = std::min(pos, length() - 1);
+  if (s.empty()) 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) {
+    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_last_not_of(char c,
+                                                     size_type pos) const {
+  if (empty()) return npos;
+  size_type i = std::min(pos, length_ - 1);
+  for (;; --i) {
+    if (ptr_[i] != c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  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 stringpiece_internal
+}  // 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..c63e25b
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece.h
@@ -0,0 +1,402 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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(nullptr)
+//   StringPiece(nullptr, 0)
+// For all of the above, sp.data() == nullptr, sp.length() == 0,
+// and sp.empty() == true.  Also, if you create a StringPiece with
+// a non-null pointer then sp.data() != nullptr.  Once created,
+// sp.data() will stay either nullptr or not-nullptr, except if you call
+// sp.clear() or sp.set().
+//
+// Thus, you can use StringPiece(nullptr) to signal an out-of-band value
+// that is different from other StringPiece values.  This is similar
+// to the way that const char* p1 = nullptr; is different from
+// const char* p2 = "";.
+//
+// There are many ways to create an empty StringPiece:
+//   StringPiece()
+//   StringPiece(nullptr)
+//   StringPiece(nullptr, 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 nullptr.
+// For some empty StringPiece values, sp.data() will not be nullptr.
+//
+// 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(nullptr) == StringPiece("abc", 0)
+//  StringPiece(nullptr, 0) == StringPiece("abcdef"+6, 0)
+//
+// Look carefully at this example:
+//   StringPiece("") == nullptr
+// True or false?  TRUE, because StringPiece::operator== converts
+// the right-hand side from nullptr to StringPiece(nullptr),
+// 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 == nullptr; }  // BAD
+// Do not do that.  Write one of these instead:
+//   bool TestNull(StringPiece sp) { return sp.data() == nullptr; }
+//   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>
+
+#if defined(__cpp_lib_string_view)
+#include <string_view>
+#endif
+
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace stringpiece_internal {
+
+class PROTOBUF_EXPORT StringPiece {
+ public:
+  using traits_type = std::char_traits<char>;
+  using value_type = char;
+  using pointer = char*;
+  using const_pointer = const char*;
+  using reference = char&;
+  using const_reference = const char&;
+  using const_iterator = const char*;
+  using iterator = const_iterator;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using reverse_iterator = const_reverse_iterator;
+  using size_type = size_t;
+  using difference_type = std::ptrdiff_t;
+
+ private:
+  const char* ptr_;
+  size_type length_;
+
+  static constexpr size_type kMaxSize =
+      (std::numeric_limits<difference_type>::max)();
+
+  static size_type CheckSize(size_type size) {
+#if !defined(NDEBUG) || defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
+    if (PROTOBUF_PREDICT_FALSE(size > kMaxSize)) {
+      // Some people grep for this message in logs
+      // so take care if you ever change it.
+      LogFatalSizeTooBig(size, "string length exceeds max size");
+    }
+#endif
+    return size;
+  }
+
+  // Out-of-line error path.
+  static void LogFatalSizeTooBig(size_type 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_(nullptr), length_(0) {}
+
+  StringPiece(const char* str)  // NOLINT(runtime/explicit)
+      : ptr_(str), length_(0) {
+    if (str != nullptr) {
+      length_ = CheckSize(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_ = CheckSize(str.size());
+  }
+
+#if defined(__cpp_lib_string_view)
+  StringPiece(  // NOLINT(runtime/explicit)
+      std::string_view str)
+      : ptr_(str.data()), length_(0) {
+    length_ = CheckSize(str.size());
+  }
+#endif
+
+  StringPiece(const char* offset, size_type len)
+      : ptr_(offset), length_(CheckSize(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_pointer data() const { return ptr_; }
+  size_type size() const { return length_; }
+  size_type length() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  char operator[](size_type i) const {
+    assert(i < length_);
+    return ptr_[i];
+  }
+
+  void remove_prefix(size_type n) {
+    assert(length_ >= n);
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  void remove_suffix(size_type n) {
+    assert(length_ >= n);
+    length_ -= n;
+  }
+
+  // returns {-1, 0, 1}
+  int compare(StringPiece x) const {
+    size_type min_size = length_ < x.length_ ? length_ : x.length_;
+    int r = memcmp(ptr_, x.ptr_, static_cast<size_t>(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;
+  }
+
+  std::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.
+  std::string ToString() const {
+    if (ptr_ == nullptr) return "";
+    return std::string(data(), static_cast<size_type>(size()));
+  }
+
+  explicit operator std::string() const { return ToString(); }
+
+  void CopyToString(std::string* target) const;
+  void AppendToString(std::string* target) const;
+
+  bool starts_with(StringPiece x) const {
+    return (length_ >= x.length_) &&
+           (memcmp(ptr_, x.ptr_, static_cast<size_t>(x.length_)) == 0);
+  }
+
+  bool ends_with(StringPiece x) const {
+    return ((length_ >= x.length_) &&
+            (memcmp(ptr_ + (length_-x.length_), x.ptr_,
+                 static_cast<size_t>(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
+  static const size_type npos;
+  const_iterator begin() const { return ptr_; }
+  const_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_);
+  }
+  size_type max_size() const { return length_; }
+  size_type capacity() const { return length_; }
+
+  // cpplint.py emits a false positive [build/include_what_you_use]
+  size_type copy(char* buf, size_type n, size_type pos = 0) const;  // NOLINT
+
+  bool contains(StringPiece s) const;
+
+  size_type find(StringPiece s, size_type pos = 0) const;
+  size_type find(char c, size_type pos = 0) const;
+  size_type rfind(StringPiece s, size_type pos = npos) const;
+  size_type rfind(char c, size_type pos = npos) const;
+
+  size_type find_first_of(StringPiece s, size_type pos = 0) const;
+  size_type find_first_of(char c, size_type pos = 0) const {
+    return find(c, pos);
+  }
+  size_type find_first_not_of(StringPiece s, size_type pos = 0) const;
+  size_type find_first_not_of(char c, size_type pos = 0) const;
+  size_type find_last_of(StringPiece s, size_type pos = npos) const;
+  size_type find_last_of(char c, size_type pos = npos) const {
+    return rfind(c, pos);
+  }
+  size_type find_last_not_of(StringPiece s, size_type pos = npos) const;
+  size_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::size_type len = x.size();
+  if (len != y.size()) {
+    return false;
+  }
+
+  return x.data() == y.data() || len <= 0 ||
+      memcmp(x.data(), y.data(), static_cast<size_t>(len)) == 0;
+}
+
+inline bool operator!=(StringPiece x, StringPiece y) {
+  return !(x == y);
+}
+
+inline bool operator<(StringPiece x, StringPiece y) {
+  const StringPiece::size_type min_size =
+      x.size() < y.size() ? x.size() : y.size();
+  const int r = memcmp(x.data(), y.data(), static_cast<size_t>(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 stringpiece_internal
+
+using ::google::protobuf::stringpiece_internal::StringPiece;
+
+}  // 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 + static_cast<size_t>(*str);
+    }
+    return result;
+  }
+};
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
+
+#include <google/protobuf/port_undef.inc>
+
+#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..ba904cb
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece_unittest.cc
@@ -0,0 +1,695 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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() == nullptr);
+    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
+    std::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) {
+  std::string s1("foo");
+  std::string s2("bar");
+  std::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, ==, "", nullptr);
+  COMPARE(true, ==, nullptr, "");
+  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");
+
+  std::string x;
+  for (int i = 0; i < 256; i++) {
+    x += 'a';
+    std::string y = x;
+    COMPARE(true, ==, x, y);
+    for (int j = 0; j < i; j++) {
+      std::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;
+  std::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() == nullptr);
+
+  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");
+  const StringPiece e;
+  const StringPiece f("123" "\0" "456", 7);
+
+  EXPECT_EQ(StringPiece::npos, std::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(e), 0);
+  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(e.find(b), StringPiece::npos);
+  EXPECT_EQ(e.find(b, 7), StringPiece::npos);
+
+  size_t empty_search_pos = std::string().find(std::string());
+  EXPECT_EQ(e.find(e), empty_search_pos);
+  EXPECT_EQ(e.find(e, 4), std::string().find(std::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(e.find('\0'), StringPiece::npos);
+  EXPECT_EQ(e.find('\0', 7), StringPiece::npos);
+  EXPECT_EQ(e.find('x'), 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(e), a.as_string().rfind(std::string()));
+  EXPECT_EQ(a.rfind(e, 17), 17);
+  EXPECT_EQ(a.rfind(g), StringPiece::npos);
+  EXPECT_EQ(e.rfind(b), StringPiece::npos);
+  EXPECT_EQ(e.rfind(b, 7), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
+  EXPECT_EQ(e.rfind(e), std::string().rfind(std::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(e.rfind('o'), 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(e), StringPiece::npos);
+  EXPECT_EQ(e.find_first_of(b), 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(e), 0);
+  // empty string nonsense
+  EXPECT_EQ(e.find_first_not_of(a), 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(e.find_first_not_of('x'), 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(e), StringPiece::npos);
+  EXPECT_EQ(f.find_last_of(e, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(e), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(f), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(e, 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(e), f.size()-1);
+  EXPECT_EQ(f.find_last_not_of(e, 4), 4);
+  EXPECT_EQ(e.find_last_not_of(e), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(f), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(e, 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(e.find_last_not_of('x'), 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(e.substr(99), e);
+  EXPECT_EQ(e.substr(0, 99), e);
+  EXPECT_EQ(e.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);
+}
+
+TEST(StringPiece, Custom) {
+  StringPiece a("foobar");
+  std::string s1("123");
+  s1 += '\0';
+  s1 += "456";
+  StringPiece b(s1);
+  StringPiece e;
+  std::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);
+
+  c = StringPiece("foobar", 7);
+
+  // as_string
+  std::string s3(a.as_string().c_str(), 7);
+  EXPECT_EQ(c, s3);
+  std::string s4(e.as_string());
+  EXPECT_TRUE(s4.empty());
+
+  // ToString
+  {
+    std::string s5(a.ToString().c_str(), 7);
+    EXPECT_EQ(c, s5);
+    std::string s6(e.ToString());
+    EXPECT_TRUE(s6.empty());
+  }
+
+  // Consume
+  {
+    StringPiece str("foobar");
+    EXPECT_TRUE(str.Consume("foo"));
+    EXPECT_EQ(str, "bar");
+    EXPECT_FALSE(str.Consume("foo"));
+    EXPECT_FALSE(str.Consume("barbar"));
+    EXPECT_FALSE(str.Consume("ar"));
+    EXPECT_EQ(str, "bar");
+  }
+
+  {
+    StringPiece str("foobar");
+    EXPECT_TRUE(str.ConsumeFromEnd("bar"));
+    EXPECT_EQ(str, "foo");
+    EXPECT_FALSE(str.ConsumeFromEnd("bar"));
+    EXPECT_FALSE(str.ConsumeFromEnd("foofoo"));
+    EXPECT_FALSE(str.ConsumeFromEnd("fo"));
+    EXPECT_EQ(str, "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(nullptr);
+  EXPECT_EQ(s.data(), (const char*)nullptr);
+  EXPECT_EQ(s.size(), 0);
+
+  // .ToString() on a StringPiece with nullptr 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", std::string("hello"));
+  EXPECT_LT("hello", std::string("world"));
+}
+
+TEST(ComparisonOpsTest, HeterogenousStringPieceEquals) {
+  EXPECT_EQ(StringPiece("hello"), std::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'));
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+#ifndef NDEBUG
+TEST(NonNegativeLenTest, NonNegativeLen) {
+  EXPECT_DEATH(StringPiece("xyz", -1), "string length exceeds max size");
+}
+#endif  // ndef DEBUG
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc
new file mode 100644
index 0000000..a6ad4c0
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf.cc
@@ -0,0 +1,175 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include <errno.h>
+#include <stdarg.h> // For va_list and related operations
+#include <stdio.h> // MSVC requires this for _vsnprintf
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _MSC_VER
+#ifndef va_copy
+// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
+// pointer into the stack and is safe to copy.
+#define va_copy(dest, src) ((dest) = (src))
+#endif
+#endif
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+  // First try with a small fixed size buffer
+  static const int kSpaceLength = 1024;
+  char space[kSpaceLength];
+
+  // It's possible for methods that use a va_list to invalidate
+  // the data in it upon use.  The fix is to make a copy
+  // of the structure before using it and use that copy instead.
+  va_list backup_ap;
+  va_copy(backup_ap, ap);
+  int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result < kSpaceLength) {
+    if (result >= 0) {
+      // Normal case -- everything fit.
+      dst->append(space, result);
+      return;
+    }
+
+#ifdef _MSC_VER
+    {
+      // Error or MSVC running out of space.  MSVC 8.0 and higher
+      // can be asked about space needed with the special idiom below:
+      va_copy(backup_ap, ap);
+      result = vsnprintf(nullptr, 0, format, backup_ap);
+      va_end(backup_ap);
+    }
+#endif
+
+    if (result < 0) {
+      // Just an error.
+      return;
+    }
+  }
+
+  // Increase the buffer size to the size requested by vsnprintf,
+  // plus one for the closing \0.
+  int length = result+1;
+  char* buf = new char[length];
+
+  // Restore the va_list before we use it again
+  va_copy(backup_ap, ap);
+  result = vsnprintf(buf, length, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result >= 0 && result < length) {
+    // It fit
+    dst->append(buf, result);
+  }
+  delete[] buf;
+}
+
+std::string StringPrintf(const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+
+// Max arguments supported by StringPrintVector
+const int kStringPrintfVectorMaxArgs = 32;
+
+// An empty block of zero for filler arguments.  This is const so that if
+// printf tries to write to it (via %n) then the program gets a SIGSEGV
+// and we can fix the problem or protect against an attack.
+static const char string_printf_empty_block[256] = { '\0' };
+
+std::string StringPrintfVector(const char* format,
+                               const std::vector<std::string>& v) {
+  GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs)
+      << "StringPrintfVector currently only supports up to "
+      << kStringPrintfVectorMaxArgs << " arguments. "
+      << "Feel free to add support for more if you need it.";
+
+  // Add filler arguments so that bogus format+args have a harder time
+  // crashing the program, corrupting the program (%n),
+  // or displaying random chunks of memory to users.
+
+  const char* cstr[kStringPrintfVectorMaxArgs];
+  for (int i = 0; i < v.size(); ++i) {
+    cstr[i] = v[i].c_str();
+  }
+  for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) {
+    cstr[i] = &string_printf_empty_block[0];
+  }
+
+  // I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
+  // or any way to build a va_list by hand, or any API for printf
+  // that accepts an array of arguments.  The best I can do is stick
+  // this COMPILE_ASSERT right next to the actual statement.
+
+  static_assert(kStringPrintfVectorMaxArgs == 32, "arg_count_mismatch");
+  return StringPrintf(format,
+                      cstr[0], cstr[1], cstr[2], cstr[3], cstr[4],
+                      cstr[5], cstr[6], cstr[7], cstr[8], cstr[9],
+                      cstr[10], cstr[11], cstr[12], cstr[13], cstr[14],
+                      cstr[15], cstr[16], cstr[17], cstr[18], cstr[19],
+                      cstr[20], cstr[21], cstr[22], cstr[23], cstr[24],
+                      cstr[25], cstr[26], cstr[27], cstr[28], cstr[29],
+                      cstr[30], cstr[31]);
+}
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/stringprintf.h b/src/google/protobuf/stubs/stringprintf.h
new file mode 100644
index 0000000..e3858be
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf.h
@@ -0,0 +1,85 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf.h
+//
+// Printf variants that place their output in a C++ string.
+//
+// Usage:
+//      string result = StringPrintf("%d %s\n", 10, "hello");
+//      SStringPrintf(&result, "%d %s\n", 10, "hello");
+//      StringAppendF(&result, "%d %s\n", 20, "there");
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+
+#include <stdarg.h>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Return a C++ string
+PROTOBUF_EXPORT extern std::string StringPrintf(const char* format, ...);
+
+// Store result into a supplied string and return it
+PROTOBUF_EXPORT extern const std::string& SStringPrintf(std::string* dst,
+                                                        const char* format,
+                                                        ...);
+
+// Append result to a supplied string
+PROTOBUF_EXPORT extern void StringAppendF(std::string* dst, const char* format,
+                                          ...);
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string.  All other routines are just convenience wrappers around it.
+PROTOBUF_EXPORT extern void StringAppendV(std::string* dst, const char* format,
+                                          va_list ap);
+
+// The max arguments supported by StringPrintfVector
+PROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs;
+
+// You can use this version when all your arguments are strings, but
+// you don't know how many arguments you'll have at compile time.
+// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
+PROTOBUF_EXPORT extern std::string StringPrintfVector(
+    const char* format, const std::vector<std::string>& v);
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
diff --git a/src/google/protobuf/stubs/stringprintf_unittest.cc b/src/google/protobuf/stubs/stringprintf_unittest.cc
new file mode 100644
index 0000000..dbecd2b
--- /dev/null
+++ b/src/google/protobuf/stubs/stringprintf_unittest.cc
@@ -0,0 +1,155 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf_unittest.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+#include <array>
+#include <cerrno>
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(StringPrintfTest, Empty) {
+#if 0
+  // gcc 2.95.3, gcc 4.1.0, and gcc 4.2.2 all warn about this:
+  // warning: zero-length printf format string.
+  // so we do not allow them in google3.
+  EXPECT_EQ("", StringPrintf(""));
+#endif
+  EXPECT_EQ("", StringPrintf("%s", std::string().c_str()));
+  EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringPrintfTest, Misc) {
+// MSVC and mingw does not support $ format specifier.
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+  EXPECT_EQ("123hello w", StringPrintf("%3$d%2$s %1$c", 'w', "hello", 123));
+#endif  // !_MSC_VER
+}
+
+TEST(StringAppendFTest, Empty) {
+  std::string value("Hello");
+  const char* empty = "";
+  StringAppendF(&value, "%s", empty);
+  EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, EmptyString) {
+  std::string value("Hello");
+  StringAppendF(&value, "%s", "");
+  EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, String) {
+  std::string value("Hello");
+  StringAppendF(&value, " %s", "World");
+  EXPECT_EQ("Hello World", value);
+}
+
+TEST(StringAppendFTest, Int) {
+  std::string value("Hello");
+  StringAppendF(&value, " %d", 123);
+  EXPECT_EQ("Hello 123", value);
+}
+
+TEST(StringPrintfTest, Multibyte) {
+  // If we are in multibyte mode and feed invalid multibyte sequence,
+  // StringPrintf should return an empty string instead of running
+  // out of memory while trying to determine destination buffer size.
+  // see b/4194543.
+
+  char* old_locale_c = setlocale(LC_CTYPE, nullptr);
+  ASSERT_TRUE(old_locale_c != nullptr);
+  std::string old_locale = old_locale_c;
+  // Push locale with multibyte mode
+  setlocale(LC_CTYPE, "en_US.utf8");
+
+  const char kInvalidCodePoint[] = "\375\067s";
+  std::string value = StringPrintf("%.*s", 3, kInvalidCodePoint);
+
+  // In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf
+  // returns error given an invalid codepoint. Other versions
+  // (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim.
+  // We test that the output is one of the above.
+  EXPECT_TRUE(value.empty() || value == kInvalidCodePoint);
+
+  // Repeat with longer string, to make sure that the dynamically
+  // allocated path in StringAppendV is handled correctly.
+  const size_t n = 2048;
+  std::array<char, n + 1> buf;
+  memset(&buf[0], ' ', n - 3);
+  memcpy(&buf[0] + n - 3, kInvalidCodePoint, 4);
+  value = StringPrintf("%.*s", n, &buf[0]);
+  // See GRTEv2 vs. GRTEv3 comment above.
+  EXPECT_TRUE(value.empty() || value == &buf[0]);
+
+  setlocale(LC_CTYPE, old_locale.c_str());
+}
+
+TEST(StringPrintfTest, NoMultibyte) {
+  // No multibyte handling, but the string contains funny chars.
+  char* old_locale_c = setlocale(LC_CTYPE, nullptr);
+  ASSERT_TRUE(old_locale_c != nullptr);
+  std::string old_locale = old_locale_c;
+  setlocale(LC_CTYPE, "POSIX");
+  std::string value = StringPrintf("%.*s", 3, "\375\067s");
+  setlocale(LC_CTYPE, old_locale.c_str());
+  EXPECT_EQ("\375\067s", value);
+}
+
+TEST(StringPrintfTest, DontOverwriteErrno) {
+  // Check that errno isn't overwritten unless we're printing
+  // something significantly larger than what people are normally
+  // printing in their badly written PLOG() statements.
+  errno = ECHILD;
+  std::string value = StringPrintf("Hello, %s!", "World");
+  EXPECT_EQ(ECHILD, errno);
+}
+
+TEST(StringPrintfTest, LargeBuf) {
+  // Check that the large buffer is handled correctly.
+  int n = 2048;
+  char* buf = new char[n+1];
+  memset(buf, ' ', n);
+  buf[n] = 0;
+  std::string value = StringPrintf("%s", buf);
+  EXPECT_EQ(buf, value);
+  delete[] buf;
+}
+
+}  // anonymous namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/structurally_valid.cc b/src/google/protobuf/stubs/structurally_valid.cc
new file mode 100644
index 0000000..a535736
--- /dev/null
+++ b/src/google/protobuf/stubs/structurally_valid.cc
@@ -0,0 +1,617 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: jrm@google.com (Jim Meehan)
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// These four-byte entries compactly encode how many bytes 0..255 to delete
+// in making a string replacement, how many bytes to add 0..255, and the offset
+// 0..64k-1 of the replacement string in remap_string.
+struct RemapEntry {
+  uint8_t delete_bytes;
+  uint8_t add_bytes;
+  uint16_t bytes_offset;
+};
+
+// Exit type codes for state tables. All but the first get stuffed into
+// signed one-byte entries. The first is only generated by executable code.
+// To distinguish from next-state entries, these must be contiguous and
+// all <= kExitNone
+typedef enum {
+  kExitDstSpaceFull = 239,
+  kExitIllegalStructure,  // 240
+  kExitOK,                // 241
+  kExitReject,            // ...
+  kExitReplace1,
+  kExitReplace2,
+  kExitReplace3,
+  kExitReplace21,
+  kExitReplace31,
+  kExitReplace32,
+  kExitReplaceOffset1,
+  kExitReplaceOffset2,
+  kExitReplace1S0,
+  kExitSpecial,
+  kExitDoAgain,
+  kExitRejectAlt,
+  kExitNone               // 255
+} ExitReason;
+
+
+// This struct represents one entire state table. The three initialized byte
+// areas are state_table, remap_base, and remap_string. state0 and state0_size
+// give the byte offset and length within state_table of the initial state --
+// table lookups are expected to start and end in this state, but for
+// truncated UTF-8 strings, may end in a different state. These allow a quick
+// test for that condition. entry_shift is 8 for tables subscripted by a full
+// byte value and 6 for space-optimized tables subscripted by only six
+// significant bits in UTF-8 continuation bytes.
+typedef struct {
+  const uint32_t state0;
+  const uint32_t state0_size;
+  const uint32_t total_size;
+  const int max_expand;
+  const int entry_shift;
+  const int bytes_per_entry;
+  const uint32_t losub;
+  const uint32_t hiadd;
+  const uint8_t* state_table;
+  const RemapEntry* remap_base;
+  const uint8_t* remap_string;
+  const uint8_t* fast_state;
+} UTF8StateMachineObj;
+
+typedef UTF8StateMachineObj UTF8ScanObj;
+
+#define X__ (kExitIllegalStructure)
+#define RJ_ (kExitReject)
+#define S1_ (kExitReplace1)
+#define S2_ (kExitReplace2)
+#define S3_ (kExitReplace3)
+#define S21 (kExitReplace21)
+#define S31 (kExitReplace31)
+#define S32 (kExitReplace32)
+#define T1_ (kExitReplaceOffset1)
+#define T2_ (kExitReplaceOffset2)
+#define S11 (kExitReplace1S0)
+#define SP_ (kExitSpecial)
+#define D__ (kExitDoAgain)
+#define RJA (kExitRejectAlt)
+
+//  Entire table has 9 state blocks of 256 entries each
+static const unsigned int utf8acceptnonsurrogates_STATE0 = 0;     // state[0]
+static const unsigned int utf8acceptnonsurrogates_STATE0_SIZE = 256;  // =[1]
+static const unsigned int utf8acceptnonsurrogates_TOTAL_SIZE = 2304;
+static const unsigned int utf8acceptnonsurrogates_MAX_EXPAND_X4 = 0;
+static const unsigned int utf8acceptnonsurrogates_SHIFT = 8;
+static const unsigned int utf8acceptnonsurrogates_BYTES = 1;
+static const unsigned int utf8acceptnonsurrogates_LOSUB = 0x20202020;
+static const unsigned int utf8acceptnonsurrogates_HIADD = 0x00000000;
+
+static const uint8_t utf8acceptnonsurrogates[] = {
+// state[0] 0x000000 Byte 1
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__,   1,   1,   1,   1,   1,   1,    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,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   7,   3,   3,
+  4,   5,   5,   5,   6, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[1] 0x000080 Byte 2 of 2
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[2] 0x000000 Byte 2 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[3] 0x001000 Byte 2 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[4] 0x000000 Byte 2 of 4
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[5] 0x040000 Byte 2 of 4
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[6] 0x100000 Byte 2 of 4
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[7] 0x00d000 Byte 2 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  8,   8,   8,   8,   8,   8,   8,   8,    8,   8,   8,   8,   8,   8,   8,   8,
+  8,   8,   8,   8,   8,   8,   8,   8,    8,   8,   8,   8,   8,   8,   8,   8,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[8] 0x00d800 Byte 3 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+};
+
+// Remap base[0] = (del, add, string_offset)
+static const RemapEntry utf8acceptnonsurrogates_remap_base[] = {
+{0, 0, 0} };
+
+// Remap string[0]
+static const unsigned char utf8acceptnonsurrogates_remap_string[] = {
+0 };
+
+static const unsigned char utf8acceptnonsurrogates_fast[256] = {
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  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 UTF8ScanObj utf8acceptnonsurrogates_obj = {
+  utf8acceptnonsurrogates_STATE0,
+  utf8acceptnonsurrogates_STATE0_SIZE,
+  utf8acceptnonsurrogates_TOTAL_SIZE,
+  utf8acceptnonsurrogates_MAX_EXPAND_X4,
+  utf8acceptnonsurrogates_SHIFT,
+  utf8acceptnonsurrogates_BYTES,
+  utf8acceptnonsurrogates_LOSUB,
+  utf8acceptnonsurrogates_HIADD,
+  utf8acceptnonsurrogates,
+  utf8acceptnonsurrogates_remap_base,
+  utf8acceptnonsurrogates_remap_string,
+  utf8acceptnonsurrogates_fast
+};
+
+
+#undef X__
+#undef RJ_
+#undef S1_
+#undef S2_
+#undef S3_
+#undef S21
+#undef S31
+#undef S32
+#undef T1_
+#undef T2_
+#undef S11
+#undef SP_
+#undef D__
+#undef RJA
+
+// Return true if current Tbl pointer is within state0 range
+// Note that unsigned compare checks both ends of range simultaneously
+static inline bool InStateZero(const UTF8ScanObj* st, const uint8_t* Tbl) {
+  const uint8_t* Tbl0 = &st->state_table[st->state0];
+  return (static_cast<uint32_t>(Tbl - Tbl0) < st->state0_size);
+}
+
+namespace {
+
+// Scan a UTF-8 string based on state table.
+// Always scan complete UTF-8 characters
+// Set number of bytes scanned. Return reason for exiting
+int UTF8GenericScan(const UTF8ScanObj* st,
+                    const char * str,
+                    int str_length,
+                    int* bytes_consumed) {
+  *bytes_consumed = 0;
+  if (str_length == 0) return kExitOK;
+
+  int eshift = st->entry_shift;
+  const uint8_t* isrc = reinterpret_cast<const uint8_t*>(str);
+  const uint8_t* src = isrc;
+  const uint8_t* srclimit = isrc + str_length;
+  const uint8_t* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
+  const uint8_t* Tbl_0 = &st->state_table[st->state0];
+
+ DoAgain:
+  // Do state-table scan
+  int e = 0;
+  uint8_t c;
+  const uint8_t* Tbl2 = &st->fast_state[0];
+  const uint32_t losub = st->losub;
+  const uint32_t hiadd = st->hiadd;
+  // Check initial few bytes one at a time until 8-byte aligned
+  //----------------------------
+  while ((((uintptr_t)src & 0x07) != 0) &&
+         (src < srclimit) &&
+         Tbl2[src[0]] == 0) {
+    src++;
+  }
+  if (((uintptr_t)src & 0x07) == 0) {
+    // Do fast for groups of 8 identity bytes.
+    // This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop,
+    // including slowing slightly on cr/lf/ht
+    //----------------------------
+    while (src < srclimit8) {
+      uint32_t s0123 = (reinterpret_cast<const uint32_t *>(src))[0];
+      uint32_t s4567 = (reinterpret_cast<const uint32_t *>(src))[1];
+      src += 8;
+      // This is a fast range check for all bytes in [lowsub..0x80-hiadd)
+      uint32_t temp = (s0123 - losub) | (s0123 + hiadd) |
+                      (s4567 - losub) | (s4567 + hiadd);
+      if ((temp & 0x80808080) != 0) {
+        // We typically end up here on cr/lf/ht; src was incremented
+        int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) |
+                    (Tbl2[src[-6]] | Tbl2[src[-5]]);
+        if (e0123 != 0) {
+          src -= 8;
+          break;
+        }    // Exit on Non-interchange
+        e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) |
+                (Tbl2[src[-2]] | Tbl2[src[-1]]);
+        if (e0123 != 0) {
+          src -= 4;
+          break;
+        }    // Exit on Non-interchange
+        // Else OK, go around again
+      }
+    }
+  }
+  //----------------------------
+
+  // Byte-at-a-time scan
+  //----------------------------
+  const uint8_t* Tbl = Tbl_0;
+  while (src < srclimit) {
+    c = *src;
+    e = Tbl[c];
+    src++;
+    if (e >= kExitIllegalStructure) {break;}
+    Tbl = &Tbl_0[e << eshift];
+  }
+  //----------------------------
+
+  // Exit possibilities:
+  //  Some exit code, !state0, back up over last char
+  //  Some exit code, state0, back up one byte exactly
+  //  source consumed, !state0, back up over partial char
+  //  source consumed, state0, exit OK
+  // For illegal byte in state0, avoid backup up over PREVIOUS char
+  // For truncated last char, back up to beginning of it
+
+  if (e >= kExitIllegalStructure) {
+    // Back up over exactly one byte of rejected/illegal UTF-8 character
+    src--;
+    // Back up more if needed
+    if (!InStateZero(st, Tbl)) {
+      do {
+        src--;
+      } while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
+    }
+  } else if (!InStateZero(st, Tbl)) {
+    // Back up over truncated UTF-8 character
+    e = kExitIllegalStructure;
+    do {
+      src--;
+    } while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
+  } else {
+    // Normal termination, source fully consumed
+    e = kExitOK;
+  }
+
+  if (e == kExitDoAgain) {
+    // Loop back up to the fast scan
+    goto DoAgain;
+  }
+
+  *bytes_consumed = src - isrc;
+  return e;
+}
+
+int UTF8GenericScanFastAscii(const UTF8ScanObj* st,
+                    const char * str,
+                    int str_length,
+                    int* bytes_consumed) {
+  *bytes_consumed = 0;
+  if (str_length == 0) return kExitOK;
+
+  const uint8_t* isrc =  reinterpret_cast<const uint8_t*>(str);
+  const uint8_t* src = isrc;
+  const uint8_t* srclimit = isrc + str_length;
+  const uint8_t* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
+  int n;
+  int rest_consumed;
+  int exit_reason;
+  do {
+    // Check initial few bytes one at a time until 8-byte aligned
+    while ((((uintptr_t)src & 0x07) != 0) &&
+           (src < srclimit) && (src[0] < 0x80)) {
+      src++;
+    }
+    if (((uintptr_t)src & 0x07) == 0) {
+      while ((src < srclimit8) &&
+             (((reinterpret_cast<const uint32_t*>(src)[0] |
+                reinterpret_cast<const uint32_t*>(src)[1]) &
+               0x80808080) == 0)) {
+        src += 8;
+      }
+    }
+    while ((src < srclimit) && (src[0] < 0x80)) {
+      src++;
+    }
+    // Run state table on the rest
+    n = src - isrc;
+    exit_reason = UTF8GenericScan(st, str + n, str_length - n, &rest_consumed);
+    src += rest_consumed;
+  } while ( exit_reason == kExitDoAgain );
+
+  *bytes_consumed = src - isrc;
+  return exit_reason;
+}
+
+// Hack:  On some compilers the static tables are initialized at startup.
+//   We can't use them until they are initialized.  However, some Protocol
+//   Buffer parsing happens at static init time and may try to validate
+//   UTF-8 strings.  Since UTF-8 validation is only used for debugging
+//   anyway, we simply always return success if initialization hasn't
+//   occurred yet.
+
+bool module_initialized_ = false;
+
+struct InitDetector {
+  InitDetector() {
+    module_initialized_ = true;
+  }
+};
+InitDetector init_detector;
+
+}  // namespace
+
+bool IsStructurallyValidUTF8(const char* buf, int len) {
+  if (!module_initialized_) return true;
+
+  int bytes_consumed = 0;
+  UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
+                           buf, len, &bytes_consumed);
+  return (bytes_consumed == len);
+}
+
+int UTF8SpnStructurallyValid(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(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/structurally_valid_unittest.cc b/src/google/protobuf/stubs/structurally_valid_unittest.cc
new file mode 100644
index 0000000..ebd9c42
--- /dev/null
+++ b/src/google/protobuf/stubs/structurally_valid_unittest.cc
@@ -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.
+
+// Copyright 2008 Google Inc. All Rights Reserved.
+// Author: xpeng@google.com (Peter Peng)
+
+#include <google/protobuf/stubs/common.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(StructurallyValidTest, ValidUTF8String) {
+  // On GCC, this string can be written as:
+  //   "abcd 1234 - \u2014\u2013\u2212"
+  // MSVC seems to interpret \u differently.
+  std::string valid_str(
+      "abcd 1234 - \342\200\224\342\200\223\342\210\222 - xyz789");
+  EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data(),
+                                      valid_str.size()));
+  // Additional check for pointer alignment
+  for (int i = 1; i < 8; ++i) {
+    EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data() + i,
+                                        valid_str.size() - i));
+  }
+}
+
+TEST(StructurallyValidTest, InvalidUTF8String) {
+  const std::string invalid_str("abcd\xA0\xB0\xA0\xB0\xA0\xB0 - xyz789");
+  EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data(),
+                                       invalid_str.size()));
+  // Additional check for pointer alignment
+  for (int i = 1; i < 8; ++i) {
+    EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data() + i,
+                                         invalid_str.size() - i));
+  }
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
new file mode 100644
index 0000000..594c8ea
--- /dev/null
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -0,0 +1,2479 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/strings/strutil.cc
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <errno.h>
+#include <float.h>    // FLT_DIG and DBL_DIG
+#include <limits.h>
+#include <stdio.h>
+#include <cmath>
+#include <iterator>
+#include <limits>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+#ifdef _WIN32
+// MSVC has only _snprintf, not snprintf.
+//
+// MinGW has both snprintf and _snprintf, but they appear to be different
+// functions.  The former is buggy.  When invoked like so:
+//   char buffer[32];
+//   snprintf(buffer, 32, "%.*g\n", FLT_DIG, 1.23e10f);
+// it prints "1.23000e+10".  This is plainly wrong:  %g should never print
+// trailing zeros after the decimal point.  For some reason this bug only
+// occurs with some input values, not all.  In any case, _snprintf does the
+// right thing, so we use it.
+#define snprintf _snprintf
+#endif
+
+namespace google {
+namespace protobuf {
+
+// These are defined as macros on some platforms.  #undef them so that we can
+// redefine them.
+#undef isxdigit
+#undef isprint
+
+// The definitions of these in ctype.h change based on locale.  Since our
+// string manipulation is all in relation to the protocol buffer and C++
+// languages, we always want to use the C locale.  So, we re-define these
+// exactly as we want them.
+inline bool isxdigit(char c) {
+  return ('0' <= c && c <= '9') ||
+         ('a' <= c && c <= 'f') ||
+         ('A' <= c && c <= 'F');
+}
+
+inline bool isprint(char c) {
+  return c >= 0x20 && c <= 0x7E;
+}
+
+// ----------------------------------------------------------------------
+// ReplaceCharacters
+//    Replaces any occurrence of the character 'remove' (or the characters
+//    in 'remove') with the character 'replacewith'.
+// ----------------------------------------------------------------------
+void ReplaceCharacters(std::string *s, const char *remove, char replacewith) {
+  const char *str_start = s->c_str();
+  const char *str = str_start;
+  for (str = strpbrk(str, remove);
+       str != nullptr;
+       str = strpbrk(str + 1, remove)) {
+    (*s)[str - str_start] = replacewith;
+  }
+}
+
+void StripWhitespace(std::string *str) {
+  int str_length = str->length();
+
+  // Strip off leading whitespace.
+  int first = 0;
+  while (first < str_length && ascii_isspace(str->at(first))) {
+    ++first;
+  }
+  // If entire string is white space.
+  if (first == str_length) {
+    str->clear();
+    return;
+  }
+  if (first > 0) {
+    str->erase(0, first);
+    str_length -= first;
+  }
+
+  // Strip off trailing whitespace.
+  int last = str_length - 1;
+  while (last >= 0 && ascii_isspace(str->at(last))) {
+    --last;
+  }
+  if (last != (str_length - 1) && last >= 0) {
+    str->erase(last + 1, std::string::npos);
+  }
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+//    Replace the "old" pattern with the "new" pattern in a string,
+//    and append the result to "res".  If replace_all is false,
+//    it only replaces the first instance of "old."
+// ----------------------------------------------------------------------
+
+void StringReplace(const std::string &s, const std::string &oldsub,
+                   const std::string &newsub, bool replace_all,
+                   std::string *res) {
+  if (oldsub.empty()) {
+    res->append(s);  // if empty, append the given string.
+    return;
+  }
+
+  std::string::size_type start_pos = 0;
+  std::string::size_type pos;
+  do {
+    pos = s.find(oldsub, start_pos);
+    if (pos == std::string::npos) {
+      break;
+    }
+    res->append(s, start_pos, pos - start_pos);
+    res->append(newsub);
+    start_pos = pos + oldsub.size();  // start searching again after the "old"
+  } while (replace_all);
+  res->append(s, start_pos, s.length() - start_pos);
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+//    Give me a string and two patterns "old" and "new", and I replace
+//    the first instance of "old" in the string with "new", if it
+//    exists.  If "global" is true; call this repeatedly until it
+//    fails.  RETURN a new string, regardless of whether the replacement
+//    happened or not.
+// ----------------------------------------------------------------------
+
+std::string StringReplace(const std::string &s, const std::string &oldsub,
+                          const std::string &newsub, bool replace_all) {
+  std::string ret;
+  StringReplace(s, oldsub, newsub, replace_all, &ret);
+  return ret;
+}
+
+// ----------------------------------------------------------------------
+// SplitStringUsing()
+//    Split a string using a character delimiter. Append the components
+//    to 'result'.
+//
+// Note: For multi-character delimiters, this routine will split on *ANY* of
+// the characters in the string, not the entire string as a single delimiter.
+// ----------------------------------------------------------------------
+template <typename ITR>
+static inline void SplitStringToIteratorUsing(StringPiece full,
+                                              const char *delim, ITR &result) {
+  // Optimize the common case where delim is a single character.
+  if (delim[0] != '\0' && delim[1] == '\0') {
+    char c = delim[0];
+    const char* p = full.data();
+    const char* end = p + full.size();
+    while (p != end) {
+      if (*p == c) {
+        ++p;
+      } else {
+        const char* start = p;
+        while (++p != end && *p != c);
+        *result++ = std::string(start, p - start);
+      }
+    }
+    return;
+  }
+
+  std::string::size_type begin_index, end_index;
+  begin_index = full.find_first_not_of(delim);
+  while (begin_index != std::string::npos) {
+    end_index = full.find_first_of(delim, begin_index);
+    if (end_index == std::string::npos) {
+      *result++ = std::string(full.substr(begin_index));
+      return;
+    }
+    *result++ =
+        std::string(full.substr(begin_index, (end_index - begin_index)));
+    begin_index = full.find_first_not_of(delim, end_index);
+  }
+}
+
+void SplitStringUsing(StringPiece full, const char *delim,
+                      std::vector<std::string> *result) {
+  std::back_insert_iterator<std::vector<std::string> > it(*result);
+  SplitStringToIteratorUsing(full, delim, it);
+}
+
+// Split a string using a character delimiter. Append the components
+// to 'result'.  If there are consecutive delimiters, this function
+// will return corresponding empty strings. The string is split into
+// at most the specified number of pieces greedily. This means that the
+// last piece may possibly be split further. To split into as many pieces
+// as possible, specify 0 as the number of pieces.
+//
+// If "full" is the empty string, yields an empty string as the only value.
+//
+// If "pieces" is negative for some reason, it returns the whole string
+// ----------------------------------------------------------------------
+template <typename ITR>
+static inline void SplitStringToIteratorAllowEmpty(StringPiece full,
+                                                   const char *delim,
+                                                   int pieces, ITR &result) {
+  std::string::size_type begin_index, end_index;
+  begin_index = 0;
+
+  for (int i = 0; (i < pieces-1) || (pieces == 0); i++) {
+    end_index = full.find_first_of(delim, begin_index);
+    if (end_index == std::string::npos) {
+      *result++ = std::string(full.substr(begin_index));
+      return;
+    }
+    *result++ =
+        std::string(full.substr(begin_index, (end_index - begin_index)));
+    begin_index = end_index + 1;
+  }
+  *result++ = std::string(full.substr(begin_index));
+}
+
+void SplitStringAllowEmpty(StringPiece full, const char *delim,
+                           std::vector<std::string> *result) {
+  std::back_insert_iterator<std::vector<std::string> > it(*result);
+  SplitStringToIteratorAllowEmpty(full, delim, 0, it);
+}
+
+// ----------------------------------------------------------------------
+// JoinStrings()
+//    This merges a vector of string components with delim inserted
+//    as separaters between components.
+//
+// ----------------------------------------------------------------------
+template <class ITERATOR>
+static void JoinStringsIterator(const ITERATOR &start, const ITERATOR &end,
+                                const char *delim, std::string *result) {
+  GOOGLE_CHECK(result != nullptr);
+  result->clear();
+  int delim_length = strlen(delim);
+
+  // Precompute resulting length so we can reserve() memory in one shot.
+  int length = 0;
+  for (ITERATOR iter = start; iter != end; ++iter) {
+    if (iter != start) {
+      length += delim_length;
+    }
+    length += iter->size();
+  }
+  result->reserve(length);
+
+  // Now combine everything.
+  for (ITERATOR iter = start; iter != end; ++iter) {
+    if (iter != start) {
+      result->append(delim, delim_length);
+    }
+    result->append(iter->data(), iter->size());
+  }
+}
+
+void JoinStrings(const std::vector<std::string> &components, const char *delim,
+                 std::string *result) {
+  JoinStringsIterator(components.begin(), components.end(), delim, result);
+}
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeSequences()
+//    This does all the unescaping that C does: \ooo, \r, \n, etc
+//    Returns length of resulting string.
+//    The implementation of \x parses any positive number of hex digits,
+//    but it is an error if the value requires more than 8 bits, and the
+//    result is truncated to 8 bits.
+//
+//    The second call stores its errors in a supplied string vector.
+//    If the string vector pointer is nullptr, it reports the errors with LOG().
+// ----------------------------------------------------------------------
+
+#define IS_OCTAL_DIGIT(c) (((c) >= '0') && ((c) <= '7'))
+
+// 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)
+
+int UnescapeCEscapeSequences(const char* source, char* dest) {
+  return UnescapeCEscapeSequences(source, dest, nullptr);
+}
+
+int UnescapeCEscapeSequences(const char *source, char *dest,
+                             std::vector<std::string> *errors) {
+  GOOGLE_DCHECK(errors == nullptr) << "Error reporting not implemented.";
+
+  char* d = dest;
+  const char* p = source;
+
+  // Small optimization for case where source = dest and there's no escaping
+  while ( p == d && *p != '\0' && *p != '\\' )
+    p++, d++;
+
+  while (*p != '\0') {
+    if (*p != '\\') {
+      *d++ = *p++;
+    } else {
+      switch ( *++p ) {                    // skip past the '\\'
+        case '\0':
+          LOG_STRING(ERROR, errors) << "String cannot end with \\";
+          *d = '\0';
+          return d - dest;   // we're done with p
+        case 'a':  *d++ = '\a';  break;
+        case 'b':  *d++ = '\b';  break;
+        case 'f':  *d++ = '\f';  break;
+        case 'n':  *d++ = '\n';  break;
+        case 'r':  *d++ = '\r';  break;
+        case 't':  *d++ = '\t';  break;
+        case 'v':  *d++ = '\v';  break;
+        case '\\': *d++ = '\\';  break;
+        case '?':  *d++ = '\?';  break;    // \?  Who knew?
+        case '\'': *d++ = '\'';  break;
+        case '"':  *d++ = '\"';  break;
+        case '0': case '1': case '2': case '3':  // octal digit: 1 to 3 digits
+        case '4': case '5': case '6': case '7': {
+          char ch = *p - '0';
+          if ( IS_OCTAL_DIGIT(p[1]) )
+            ch = ch * 8 + *++p - '0';
+          if ( IS_OCTAL_DIGIT(p[1]) )      // safe (and easy) to do this twice
+            ch = ch * 8 + *++p - '0';      // now points at last digit
+          *d++ = ch;
+          break;
+        }
+        case 'x': case 'X': {
+          if (!isxdigit(p[1])) {
+            if (p[1] == '\0') {
+              LOG_STRING(ERROR, errors) << "String cannot end with \\x";
+            } else {
+              LOG_STRING(ERROR, errors) <<
+                "\\x cannot be followed by non-hex digit: \\" << *p << p[1];
+            }
+            break;
+          }
+          unsigned int ch = 0;
+          const char *hex_start = p;
+          while (isxdigit(p[1]))  // arbitrarily many hex digits
+            ch = (ch << 4) + hex_digit_to_int(*++p);
+          if (ch > 0xFF)
+            LOG_STRING(ERROR, errors)
+                << "Value of "
+                << "\\" << std::string(hex_start, p + 1 - hex_start)
+                << " exceeds 8 bits";
+          *d++ = ch;
+          break;
+        }
+#if 0  // TODO(kenton):  Support \u and \U?  Requires runetochar().
+        case 'u': {
+          // \uhhhh => convert 4 hex digits to UTF-8
+          char32 rune = 0;
+          const char *hex_start = p;
+          for (int i = 0; i < 4; ++i) {
+            if (isxdigit(p[1])) {  // Look one char ahead.
+              rune = (rune << 4) + hex_digit_to_int(*++p);  // Advance p.
+            } else {
+              LOG_STRING(ERROR, errors)
+                << "\\u must be followed by 4 hex digits: \\"
+                <<  std::string(hex_start, p+1-hex_start);
+              break;
+            }
+          }
+          d += runetochar(d, &rune);
+          break;
+        }
+        case 'U': {
+          // \Uhhhhhhhh => convert 8 hex digits to UTF-8
+          char32 rune = 0;
+          const char *hex_start = p;
+          for (int i = 0; i < 8; ++i) {
+            if (isxdigit(p[1])) {  // Look one char ahead.
+              // Don't change rune until we're sure this
+              // is within the Unicode limit, but do advance p.
+              char32 newrune = (rune << 4) + hex_digit_to_int(*++p);
+              if (newrune > 0x10FFFF) {
+                LOG_STRING(ERROR, errors)
+                  << "Value of \\"
+                  << std::string(hex_start, p + 1 - hex_start)
+                  << " exceeds Unicode limit (0x10FFFF)";
+                break;
+              } else {
+                rune = newrune;
+              }
+            } else {
+              LOG_STRING(ERROR, errors)
+                << "\\U must be followed by 8 hex digits: \\"
+                <<  std::string(hex_start, p+1-hex_start);
+              break;
+            }
+          }
+          d += runetochar(d, &rune);
+          break;
+        }
+#endif
+        default:
+          LOG_STRING(ERROR, errors) << "Unknown escape sequence: \\" << *p;
+      }
+      p++;                                 // read past letter we escaped
+    }
+  }
+  *d = '\0';
+  return d - dest;
+}
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeString()
+//    This does the same thing as UnescapeCEscapeSequences, but creates
+//    a new string. The caller does not need to worry about allocating
+//    a dest buffer. This should be used for non performance critical
+//    tasks such as printing debug messages. It is safe for src and dest
+//    to be the same.
+//
+//    The second call stores its errors in a supplied string vector.
+//    If the string vector pointer is nullptr, it reports the errors with LOG().
+//
+//    In the first and second calls, the length of dest is returned. In the
+//    the third call, the new string is returned.
+// ----------------------------------------------------------------------
+int UnescapeCEscapeString(const std::string &src, std::string *dest) {
+  return UnescapeCEscapeString(src, dest, nullptr);
+}
+
+int UnescapeCEscapeString(const std::string &src, std::string *dest,
+                          std::vector<std::string> *errors) {
+  std::unique_ptr<char[]> unescaped(new char[src.size() + 1]);
+  int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), errors);
+  GOOGLE_CHECK(dest);
+  dest->assign(unescaped.get(), len);
+  return len;
+}
+
+std::string UnescapeCEscapeString(const std::string &src) {
+  std::unique_ptr<char[]> unescaped(new char[src.size() + 1]);
+  int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), nullptr);
+  return std::string(unescaped.get(), len);
+}
+
+// ----------------------------------------------------------------------
+// CEscapeString()
+// CHexEscapeString()
+//    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. The 'Hex' version uses
+//    hexadecimal rather than octal sequences.
+//    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.
+// ----------------------------------------------------------------------
+int CEscapeInternal(const char* src, int src_len, char* dest,
+                    int dest_len, bool use_hex, bool utf8_safe) {
+  const char* src_end = src + src_len;
+  int used = 0;
+  bool last_hex_escape = false; // true if last output char was \xNN
+
+  for (; src < src_end; src++) {
+    if (dest_len - used < 2)   // Need space for two letter escape
+      return -1;
+
+    bool is_hex_escape = false;
+    switch (*src) {
+      case '\n': dest[used++] = '\\'; dest[used++] = 'n';  break;
+      case '\r': dest[used++] = '\\'; dest[used++] = 'r';  break;
+      case '\t': dest[used++] = '\\'; dest[used++] = 't';  break;
+      case '\"': dest[used++] = '\\'; dest[used++] = '\"'; break;
+      case '\'': dest[used++] = '\\'; dest[used++] = '\''; break;
+      case '\\': dest[used++] = '\\'; dest[used++] = '\\'; break;
+      default:
+        // Note that if we emit \xNN and the src 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 ((!utf8_safe || static_cast<uint8_t>(*src) < 0x80) &&
+            (!isprint(*src) ||
+             (last_hex_escape && isxdigit(*src)))) {
+          if (dest_len - used < 4) // need space for 4 letter escape
+            return -1;
+          sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"),
+                  static_cast<uint8_t>(*src));
+          is_hex_escape = use_hex;
+          used += 4;
+        } else {
+          dest[used++] = *src; break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+
+  if (dest_len - used < 1)   // make sure that there is room for \0
+    return -1;
+
+  dest[used] = '\0';   // doesn't count towards return value though
+  return used;
+}
+
+// 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 (StringPiece::size_type i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    escaped_len += c_escaped_len[c];
+  }
+  return escaped_len;
+}
+
+// ----------------------------------------------------------------------
+// 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, std::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 (StringPiece::size_type 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;
+    }
+  }
+}
+
+std::string CEscape(const std::string &src) {
+  std::string dest;
+  CEscapeAndAppend(src, &dest);
+  return dest;
+}
+
+namespace strings {
+
+std::string Utf8SafeCEscape(const std::string &src) {
+  const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
+  std::unique_ptr<char[]> dest(new char[dest_length]);
+  const int len = CEscapeInternal(src.data(), src.size(),
+                                  dest.get(), dest_length, false, true);
+  GOOGLE_DCHECK_GE(len, 0);
+  return std::string(dest.get(), len);
+}
+
+std::string CHexEscape(const std::string &src) {
+  const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
+  std::unique_ptr<char[]> dest(new char[dest_length]);
+  const int len = CEscapeInternal(src.data(), src.size(),
+                                  dest.get(), dest_length, true, false);
+  GOOGLE_DCHECK_GE(len, 0);
+  return std::string(dest.get(), len);
+}
+
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// strto32_adaptor()
+// strtou32_adaptor()
+//    Implementation of strto[u]l replacements that have identical
+//    overflow and underflow characteristics for both ILP-32 and LP-64
+//    platforms, including errno preservation in error-free calls.
+// ----------------------------------------------------------------------
+
+int32_t strto32_adaptor(const char *nptr, char **endptr, int base) {
+  const int saved_errno = errno;
+  errno = 0;
+  const long result = strtol(nptr, endptr, base);
+  if (errno == ERANGE && result == LONG_MIN) {
+    return std::numeric_limits<int32_t>::min();
+  } else if (errno == ERANGE && result == LONG_MAX) {
+    return std::numeric_limits<int32_t>::max();
+  } else if (errno == 0 && result < std::numeric_limits<int32_t>::min()) {
+    errno = ERANGE;
+    return std::numeric_limits<int32_t>::min();
+  } else if (errno == 0 && result > std::numeric_limits<int32_t>::max()) {
+    errno = ERANGE;
+    return std::numeric_limits<int32_t>::max();
+  }
+  if (errno == 0)
+    errno = saved_errno;
+  return static_cast<int32_t>(result);
+}
+
+uint32_t strtou32_adaptor(const char *nptr, char **endptr, int base) {
+  const int saved_errno = errno;
+  errno = 0;
+  const unsigned long result = strtoul(nptr, endptr, base);
+  if (errno == ERANGE && result == ULONG_MAX) {
+    return std::numeric_limits<uint32_t>::max();
+  } else if (errno == 0 && result > std::numeric_limits<uint32_t>::max()) {
+    errno = ERANGE;
+    return std::numeric_limits<uint32_t>::max();
+  }
+  if (errno == 0)
+    errno = saved_errno;
+  return static_cast<uint32_t>(result);
+}
+
+inline bool safe_parse_sign(std::string *text /*inout*/,
+                            bool *negative_ptr /*output*/) {
+  const char* start = text->data();
+  const char* end = start + text->size();
+
+  // Consume whitespace.
+  while (start < end && (start[0] == ' ')) {
+    ++start;
+  }
+  while (start < end && (end[-1] == ' ')) {
+    --end;
+  }
+  if (start >= end) {
+    return false;
+  }
+
+  // Consume sign.
+  *negative_ptr = (start[0] == '-');
+  if (*negative_ptr || start[0] == '+') {
+    ++start;
+    if (start >= end) {
+      return false;
+    }
+  }
+  *text = text->substr(start - text->data(), end - start);
+  return true;
+}
+
+template <typename IntType>
+bool safe_parse_positive_int(std::string text, IntType *value_p) {
+  int base = 10;
+  IntType value = 0;
+  const IntType vmax = std::numeric_limits<IntType>::max();
+  assert(vmax > 0);
+  assert(vmax >= base);
+  const IntType vmax_over_base = vmax / base;
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = c - '0';
+    if (digit >= base || digit < 0) {
+      *value_p = value;
+      return false;
+    }
+    if (value > vmax_over_base) {
+      *value_p = vmax;
+      return false;
+    }
+    value *= base;
+    if (value > vmax - digit) {
+      *value_p = vmax;
+      return false;
+    }
+    value += digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+template <typename IntType>
+bool safe_parse_negative_int(const std::string &text, IntType *value_p) {
+  int base = 10;
+  IntType value = 0;
+  const IntType vmin = std::numeric_limits<IntType>::min();
+  assert(vmin < 0);
+  assert(vmin <= 0 - 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.
+  // 2011 c++ standard tightens the spec but we cannot rely on it.
+  if (vmin % base > 0) {
+    vmin_over_base += 1;
+  }
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = c - '0';
+    if (digit >= base || digit < 0) {
+      *value_p = value;
+      return false;
+    }
+    if (value < vmin_over_base) {
+      *value_p = vmin;
+      return false;
+    }
+    value *= base;
+    if (value < vmin + digit) {
+      *value_p = vmin;
+      return false;
+    }
+    value -= digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+template <typename IntType>
+bool safe_int_internal(std::string text, IntType *value_p) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign(&text, &negative)) {
+    return false;
+  }
+  if (!negative) {
+    return safe_parse_positive_int(text, value_p);
+  } else {
+    return safe_parse_negative_int(text, value_p);
+  }
+}
+
+template <typename IntType>
+bool safe_uint_internal(std::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()
+// FastHexToBuffer()
+// FastHex64ToBuffer()
+// FastHex32ToBuffer()
+// ----------------------------------------------------------------------
+
+// Offset into buffer where FastInt64ToBuffer places the end of string
+// null character.  Also used by FastInt64ToBufferLeft.
+static const int kFastInt64ToBufferOffset = 21;
+
+char *FastInt64ToBuffer(int64_t i, char* buffer) {
+  // We could collapse the positive and negative sections, but that
+  // would be slightly slower for positive numbers...
+  // 22 bytes is enough to store -2**64, -18446744073709551616.
+  char* p = buffer + kFastInt64ToBufferOffset;
+  *p-- = '\0';
+  if (i >= 0) {
+    do {
+      *p-- = '0' + i % 10;
+      i /= 10;
+    } while (i > 0);
+    return p + 1;
+  } else {
+    // On different platforms, % and / have different behaviors for
+    // negative numbers, so we need to jump through hoops to make sure
+    // we don't divide negative numbers.
+    if (i > -10) {
+      i = -i;
+      *p-- = '0' + i;
+      *p = '-';
+      return p;
+    } else {
+      // Make sure we aren't at MIN_INT, in which case we can't say i = -i
+      i = i + 10;
+      i = -i;
+      *p-- = '0' + i % 10;
+      // Undo what we did a moment ago
+      i = i / 10 + 1;
+      do {
+        *p-- = '0' + i % 10;
+        i /= 10;
+      } while (i > 0);
+      *p = '-';
+      return p;
+    }
+  }
+}
+
+// Offset into buffer where FastInt32ToBuffer places the end of string
+// null character.  Also used by FastInt32ToBufferLeft
+static const int kFastInt32ToBufferOffset = 11;
+
+// Yes, this is a duplicate of FastInt64ToBuffer.  But, we need this for the
+// compiler to generate 32 bit arithmetic instructions.  It's much faster, at
+// least with 32 bit binaries.
+char *FastInt32ToBuffer(int32_t i, char* buffer) {
+  // We could collapse the positive and negative sections, but that
+  // would be slightly slower for positive numbers...
+  // 12 bytes is enough to store -2**32, -4294967296.
+  char* p = buffer + kFastInt32ToBufferOffset;
+  *p-- = '\0';
+  if (i >= 0) {
+    do {
+      *p-- = '0' + i % 10;
+      i /= 10;
+    } while (i > 0);
+    return p + 1;
+  } else {
+    // On different platforms, % and / have different behaviors for
+    // negative numbers, so we need to jump through hoops to make sure
+    // we don't divide negative numbers.
+    if (i > -10) {
+      i = -i;
+      *p-- = '0' + i;
+      *p = '-';
+      return p;
+    } else {
+      // Make sure we aren't at MIN_INT, in which case we can't say i = -i
+      i = i + 10;
+      i = -i;
+      *p-- = '0' + i % 10;
+      // Undo what we did a moment ago
+      i = i / 10 + 1;
+      do {
+        *p-- = '0' + i % 10;
+        i /= 10;
+      } while (i > 0);
+      *p = '-';
+      return p;
+    }
+  }
+}
+
+char *FastHexToBuffer(int i, char* buffer) {
+  GOOGLE_CHECK(i >= 0) << "FastHexToBuffer() wants non-negative integers, not " << i;
+
+  static const char *hexdigits = "0123456789abcdef";
+  char *p = buffer + 21;
+  *p-- = '\0';
+  do {
+    *p-- = hexdigits[i & 15];   // mod by 16
+    i >>= 4;                    // divide by 16
+  } while (i > 0);
+  return p + 1;
+}
+
+char *InternalFastHexToBuffer(uint64_t value, char* buffer, int num_byte) {
+  static const char *hexdigits = "0123456789abcdef";
+  buffer[num_byte] = '\0';
+  for (int i = num_byte - 1; i >= 0; i--) {
+#ifdef _M_X64
+    // MSVC x64 platform has a bug optimizing the uint32(value) in the #else
+    // block. Given that the uint32 cast was to improve performance on 32-bit
+    // platforms, we use 64-bit '&' directly.
+    buffer[i] = hexdigits[value & 0xf];
+#else
+    buffer[i] = hexdigits[uint32_t(value) & 0xf];
+#endif
+    value >>= 4;
+  }
+  return buffer;
+}
+
+char *FastHex64ToBuffer(uint64_t value, char* buffer) {
+  return InternalFastHexToBuffer(value, buffer, 16);
+}
+
+char *FastHex32ToBuffer(uint32_t value, char* buffer) {
+  return InternalFastHexToBuffer(value, buffer, 8);
+}
+
+// ----------------------------------------------------------------------
+// FastInt32ToBufferLeft()
+// FastUInt32ToBufferLeft()
+// FastInt64ToBufferLeft()
+// FastUInt64ToBufferLeft()
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer (hence the name, as the
+// output is left-aligned).  The caller is responsible for ensuring that
+// the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the string (i.e. the null character
+// terminating the string).
+// ----------------------------------------------------------------------
+
+static const char two_ASCII_digits[100][2] = {
+  {'0','0'}, {'0','1'}, {'0','2'}, {'0','3'}, {'0','4'},
+  {'0','5'}, {'0','6'}, {'0','7'}, {'0','8'}, {'0','9'},
+  {'1','0'}, {'1','1'}, {'1','2'}, {'1','3'}, {'1','4'},
+  {'1','5'}, {'1','6'}, {'1','7'}, {'1','8'}, {'1','9'},
+  {'2','0'}, {'2','1'}, {'2','2'}, {'2','3'}, {'2','4'},
+  {'2','5'}, {'2','6'}, {'2','7'}, {'2','8'}, {'2','9'},
+  {'3','0'}, {'3','1'}, {'3','2'}, {'3','3'}, {'3','4'},
+  {'3','5'}, {'3','6'}, {'3','7'}, {'3','8'}, {'3','9'},
+  {'4','0'}, {'4','1'}, {'4','2'}, {'4','3'}, {'4','4'},
+  {'4','5'}, {'4','6'}, {'4','7'}, {'4','8'}, {'4','9'},
+  {'5','0'}, {'5','1'}, {'5','2'}, {'5','3'}, {'5','4'},
+  {'5','5'}, {'5','6'}, {'5','7'}, {'5','8'}, {'5','9'},
+  {'6','0'}, {'6','1'}, {'6','2'}, {'6','3'}, {'6','4'},
+  {'6','5'}, {'6','6'}, {'6','7'}, {'6','8'}, {'6','9'},
+  {'7','0'}, {'7','1'}, {'7','2'}, {'7','3'}, {'7','4'},
+  {'7','5'}, {'7','6'}, {'7','7'}, {'7','8'}, {'7','9'},
+  {'8','0'}, {'8','1'}, {'8','2'}, {'8','3'}, {'8','4'},
+  {'8','5'}, {'8','6'}, {'8','7'}, {'8','8'}, {'8','9'},
+  {'9','0'}, {'9','1'}, {'9','2'}, {'9','3'}, {'9','4'},
+  {'9','5'}, {'9','6'}, {'9','7'}, {'9','8'}, {'9','9'}
+};
+
+char* FastUInt32ToBufferLeft(uint32_t u, char* buffer) {
+  uint32_t digits;
+  const char *ASCII_digits = nullptr;
+  // The idea of this implementation is to trim the number of divides to as few
+  // as possible by using multiplication and subtraction rather than mod (%),
+  // and by outputting two digits at a time rather than one.
+  // The huge-number case is first, in the hopes that the compiler will output
+  // that case in one branch-free block of code, and only output conditional
+  // branches into it from below.
+  if (u >= 1000000000) {  // >= 1,000,000,000
+    digits = u / 100000000;  // 100,000,000
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt100_000_000:
+    u -= digits * 100000000;  // 100,000,000
+lt100_000_000:
+    digits = u / 1000000;  // 1,000,000
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt1_000_000:
+    u -= digits * 1000000;  // 1,000,000
+lt1_000_000:
+    digits = u / 10000;  // 10,000
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt10_000:
+    u -= digits * 10000;  // 10,000
+lt10_000:
+    digits = u / 100;
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt100:
+    u -= digits * 100;
+lt100:
+    digits = u;
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+done:
+    *buffer = 0;
+    return buffer;
+  }
+
+  if (u < 100) {
+    digits = u;
+    if (u >= 10) goto lt100;
+    *buffer++ = '0' + digits;
+    goto done;
+  }
+  if (u  <  10000) {   // 10,000
+    if (u >= 1000) goto lt10_000;
+    digits = u / 100;
+    *buffer++ = '0' + digits;
+    goto sublt100;
+  }
+  if (u  <  1000000) {   // 1,000,000
+    if (u >= 100000) goto lt1_000_000;
+    digits = u / 10000;  //    10,000
+    *buffer++ = '0' + digits;
+    goto sublt10_000;
+  }
+  if (u  <  100000000) {   // 100,000,000
+    if (u >= 10000000) goto lt100_000_000;
+    digits = u / 1000000;  //   1,000,000
+    *buffer++ = '0' + digits;
+    goto sublt1_000_000;
+  }
+  // we already know that u < 1,000,000,000
+  digits = u / 100000000;   // 100,000,000
+  *buffer++ = '0' + digits;
+  goto sublt100_000_000;
+}
+
+char* FastInt32ToBufferLeft(int32_t i, char* buffer) {
+  uint32_t u = 0;
+  if (i < 0) {
+    *buffer++ = '-';
+    u -= i;
+  } else {
+    u = i;
+  }
+  return FastUInt32ToBufferLeft(u, buffer);
+}
+
+char* FastUInt64ToBufferLeft(uint64_t u64, char* buffer) {
+  int digits;
+  const char *ASCII_digits = nullptr;
+
+  uint32_t u = static_cast<uint32_t>(u64);
+  if (u == u64) return FastUInt32ToBufferLeft(u, buffer);
+
+  uint64_t top_11_digits = u64 / 1000000000;
+  buffer = FastUInt64ToBufferLeft(top_11_digits, buffer);
+  u = u64 - (top_11_digits * 1000000000);
+
+  digits = u / 10000000;  // 10,000,000
+  GOOGLE_DCHECK_LT(digits, 100);
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 10000000;  // 10,000,000
+  digits = u / 100000;  // 100,000
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 100000;  // 100,000
+  digits = u / 1000;  // 1,000
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 1000;  // 1,000
+  digits = u / 10;
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 10;
+  digits = u;
+  *buffer++ = '0' + digits;
+  *buffer = 0;
+  return buffer;
+}
+
+char* FastInt64ToBufferLeft(int64_t i, char* buffer) {
+  uint64_t u = 0;
+  if (i < 0) {
+    *buffer++ = '-';
+    u -= i;
+  } else {
+    u = i;
+  }
+  return FastUInt64ToBufferLeft(u, buffer);
+}
+
+// ----------------------------------------------------------------------
+// SimpleItoa()
+//    Description: converts an integer to a string.
+//
+//    Return value: string
+// ----------------------------------------------------------------------
+
+std::string SimpleItoa(int i) {
+  char buffer[kFastToBufferSize];
+  return (sizeof(i) == 4) ?
+    FastInt32ToBuffer(i, buffer) :
+    FastInt64ToBuffer(i, buffer);
+}
+
+std::string SimpleItoa(unsigned int i) {
+  char buffer[kFastToBufferSize];
+  return std::string(buffer, (sizeof(i) == 4)
+                                 ? FastUInt32ToBufferLeft(i, buffer)
+                                 : FastUInt64ToBufferLeft(i, buffer));
+}
+
+std::string SimpleItoa(long i) {
+  char buffer[kFastToBufferSize];
+  return (sizeof(i) == 4) ?
+    FastInt32ToBuffer(i, buffer) :
+    FastInt64ToBuffer(i, buffer);
+}
+
+std::string SimpleItoa(unsigned long i) {
+  char buffer[kFastToBufferSize];
+  return std::string(buffer, (sizeof(i) == 4)
+                                 ? FastUInt32ToBufferLeft(i, buffer)
+                                 : FastUInt64ToBufferLeft(i, buffer));
+}
+
+std::string SimpleItoa(long long i) {
+  char buffer[kFastToBufferSize];
+  return (sizeof(i) == 4) ?
+    FastInt32ToBuffer(i, buffer) :
+    FastInt64ToBuffer(i, buffer);
+}
+
+std::string SimpleItoa(unsigned long long i) {
+  char buffer[kFastToBufferSize];
+  return std::string(buffer, (sizeof(i) == 4)
+                                 ? FastUInt32ToBufferLeft(i, buffer)
+                                 : FastUInt64ToBufferLeft(i, buffer));
+}
+
+// ----------------------------------------------------------------------
+// SimpleDtoa()
+// SimpleFtoa()
+// DoubleToBuffer()
+// FloatToBuffer()
+//    We want to print the value without losing precision, but we also do
+//    not want to print more digits than necessary.  This turns out to be
+//    trickier than it sounds.  Numbers like 0.2 cannot be represented
+//    exactly in binary.  If we print 0.2 with a very large precision,
+//    e.g. "%.50g", we get "0.2000000000000000111022302462515654042363167".
+//    On the other hand, if we set the precision too low, we lose
+//    significant digits when printing numbers that actually need them.
+//    It turns out there is no precision value that does the right thing
+//    for all numbers.
+//
+//    Our strategy is to first try printing with a precision that is never
+//    over-precise, then parse the result with strtod() to see if it
+//    matches.  If not, we print again with a precision that will always
+//    give a precise result, but may use more digits than necessary.
+//
+//    An arguably better strategy would be to use the algorithm described
+//    in "How to Print Floating-Point Numbers Accurately" by Steele &
+//    White, e.g. as implemented by David M. Gay's dtoa().  It turns out,
+//    however, that the following implementation is about as fast as
+//    DMG's code.  Furthermore, DMG's code locks mutexes, which means it
+//    will not scale well on multi-core machines.  DMG's code is slightly
+//    more accurate (in that it will never use more digits than
+//    necessary), but this is probably irrelevant for most users.
+//
+//    Rob Pike and Ken Thompson also have an implementation of dtoa() in
+//    third_party/fmt/fltfmt.cc.  Their implementation is similar to this
+//    one in that it makes guesses and then uses strtod() to check them.
+//    Their implementation is faster because they use their own code to
+//    generate the digits in the first place rather than use snprintf(),
+//    thus avoiding format string parsing overhead.  However, this makes
+//    it considerably more complicated than the following implementation,
+//    and it is embedded in a larger library.  If speed turns out to be
+//    an issue, we could re-implement this in terms of their
+//    implementation.
+// ----------------------------------------------------------------------
+
+std::string SimpleDtoa(double value) {
+  char buffer[kDoubleToBufferSize];
+  return DoubleToBuffer(value, buffer);
+}
+
+std::string SimpleFtoa(float value) {
+  char buffer[kFloatToBufferSize];
+  return FloatToBuffer(value, buffer);
+}
+
+static inline bool IsValidFloatChar(char c) {
+  return ('0' <= c && c <= '9') ||
+         c == 'e' || c == 'E' ||
+         c == '+' || c == '-';
+}
+
+void DelocalizeRadix(char* buffer) {
+  // Fast check:  if the buffer has a normal decimal point, assume no
+  // translation is needed.
+  if (strchr(buffer, '.') != nullptr) return;
+
+  // Find the first unknown character.
+  while (IsValidFloatChar(*buffer)) ++buffer;
+
+  if (*buffer == '\0') {
+    // No radix character found.
+    return;
+  }
+
+  // We are now pointing at the locale-specific radix character.  Replace it
+  // with '.'.
+  *buffer = '.';
+  ++buffer;
+
+  if (!IsValidFloatChar(*buffer) && *buffer != '\0') {
+    // It appears the radix was a multi-byte character.  We need to remove the
+    // extra bytes.
+    char* target = buffer;
+    do { ++buffer; } while (!IsValidFloatChar(*buffer) && *buffer != '\0');
+    memmove(target, buffer, strlen(buffer) + 1);
+  }
+}
+
+char* DoubleToBuffer(double value, char* buffer) {
+  // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all
+  // platforms these days.  Just in case some system exists where DBL_DIG
+  // is significantly larger -- and risks overflowing our buffer -- we have
+  // this assert.
+  static_assert(DBL_DIG < 20, "DBL_DIG_is_too_big");
+
+  if (value == std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "inf");
+    return buffer;
+  } else if (value == -std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "-inf");
+    return buffer;
+  } else if (std::isnan(value)) {
+    strcpy(buffer, "nan");
+    return buffer;
+  }
+
+  int snprintf_result =
+    snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG, value);
+
+  // The snprintf should never overflow because the buffer is significantly
+  // larger than the precision we asked for.
+  GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
+
+  // We need to make parsed_value volatile in order to force the compiler to
+  // write it out to the stack.  Otherwise, it may keep the value in a
+  // register, and if it does that, it may keep it as a long double instead
+  // of a double.  This long double may have extra bits that make it compare
+  // unequal to "value" even though it would be exactly equal if it were
+  // truncated to a double.
+  volatile double parsed_value = internal::NoLocaleStrtod(buffer, nullptr);
+  if (parsed_value != value) {
+    snprintf_result =
+        snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG + 2, value);
+
+    // Should never overflow; see above.
+    GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
+  }
+
+  DelocalizeRadix(buffer);
+  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 (size_t 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 != nullptr) << "nullptr 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
+#if defined(_WIN32) || defined (__hpux)  // has no strtof()
+  *value = internal::NoLocaleStrtod(str, &endptr);
+#else
+  *value = strtof(str, &endptr);
+#endif
+  return *str != 0 && *endptr == 0 && errno == 0;
+}
+
+bool safe_strtod(const char* str, double* value) {
+  char* endptr;
+  *value = internal::NoLocaleStrtod(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 std::string &str, int32_t *value) {
+  return safe_int_internal(str, value);
+}
+
+bool safe_strtou32(const std::string &str, uint32_t *value) {
+  return safe_uint_internal(str, value);
+}
+
+bool safe_strto64(const std::string &str, int64_t *value) {
+  return safe_int_internal(str, value);
+}
+
+bool safe_strtou64(const std::string &str, uint64_t *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
+  // is significantly larger -- and risks overflowing our buffer -- we have
+  // this assert.
+  static_assert(FLT_DIG < 10, "FLT_DIG_is_too_big");
+
+  if (value == std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "inf");
+    return buffer;
+  } else if (value == -std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "-inf");
+    return buffer;
+  } else if (std::isnan(value)) {
+    strcpy(buffer, "nan");
+    return buffer;
+  }
+
+  int snprintf_result =
+    snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG, value);
+
+  // The snprintf should never overflow because the buffer is significantly
+  // larger than the precision we asked for.
+  GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
+
+  float parsed_value;
+  if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
+    snprintf_result =
+        snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG + 3, value);
+
+    // Should never overflow; see above.
+    GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
+  }
+
+  DelocalizeRadix(buffer);
+  return buffer;
+}
+
+namespace strings {
+
+AlphaNum::AlphaNum(strings::Hex hex) {
+  char *const end = &digits[kFastToBufferSize];
+  char *writer = end;
+  uint64_t value = hex.value;
+  uint64_t width = hex.spec;
+  // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
+  // where 0x10000 is the smallest hex number that is as wide as the user
+  // asked for.
+  uint64_t mask = (static_cast<uint64_t>(1) << ((width - 1) * 4)) | value;
+  static const char hexdigits[] = "0123456789abcdef";
+  do {
+    *--writer = hexdigits[value & 0xF];
+    value >>= 4;
+    mask >>= 4;
+  } while (mask != 0);
+  piece_data_ = writer;
+  piece_size_ = end - writer;
+}
+
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or integers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, C++ strings, and integer values.
+// ----------------------------------------------------------------------
+
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten.  It comes in multiple flavors to minimize
+// call overhead.
+static char *Append1(char *out, const AlphaNum &x) {
+  if (x.size() > 0) {
+    memcpy(out, x.data(), x.size());
+    out += x.size();
+  }
+  return out;
+}
+
+static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
+  if (x1.size() > 0) {
+    memcpy(out, x1.data(), x1.size());
+    out += x1.size();
+  }
+  if (x2.size() > 0) {
+    memcpy(out, x2.data(), x2.size());
+    out += x2.size();
+  }
+  return out;
+}
+
+static char *Append4(char *out, const AlphaNum &x1, const AlphaNum &x2,
+                     const AlphaNum &x3, const AlphaNum &x4) {
+  if (x1.size() > 0) {
+    memcpy(out, x1.data(), x1.size());
+    out += x1.size();
+  }
+  if (x2.size() > 0) {
+    memcpy(out, x2.data(), x2.size());
+    out += x2.size();
+  }
+  if (x3.size() > 0) {
+    memcpy(out, x3.data(), x3.size());
+    out += x3.size();
+  }
+  if (x4.size() > 0) {
+    memcpy(out, x4.data(), x4.size());
+    out += x4.size();
+  }
+  return out;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b) {
+  std::string result;
+  result.resize(a.size() + b.size());
+  char *const begin = &*result.begin();
+  char *out = Append2(begin, a, b);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size());
+  char *const begin = &*result.begin();
+  char *out = Append2(begin, a, b);
+  out = Append1(out, c);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append1(out, e);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append2(out, e, f);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+                   const AlphaNum &g) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append2(out, e, f);
+  out = Append1(out, g);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::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) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size() + h.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append4(out, e, f, g, h);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::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) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size() + h.size() + i.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append4(out, e, f, g, h);
+  out = Append1(out, i);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+// It's possible to call StrAppend with a char * pointer that is partway into
+// the string we're appending to.  However the results of this are random.
+// Therefore, check for this in debug mode.  Use unsigned math so we only have
+// to do one comparison.
+#define GOOGLE_DCHECK_NO_OVERLAP(dest, src) \
+    GOOGLE_DCHECK_GT(uintptr_t((src).data() - (dest).data()), \
+                     uintptr_t((dest).size()))
+
+void StrAppend(std::string *result, const AlphaNum &a) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  result->append(a.data(), a.size());
+}
+
+void StrAppend(std::string *result, const AlphaNum &a, const AlphaNum &b) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  std::string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size());
+  char *const begin = &*result->begin();
+  char *out = Append2(begin + old_size, a, b);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(std::string *result, const AlphaNum &a, const AlphaNum &b,
+               const AlphaNum &c) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+  std::string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size() + c.size());
+  char *const begin = &*result->begin();
+  char *out = Append2(begin + old_size, a, b);
+  out = Append1(out, c);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(std::string *result, const AlphaNum &a, const AlphaNum &b,
+               const AlphaNum &c, const AlphaNum &d) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, d);
+  std::string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size() + c.size() + d.size());
+  char *const begin = &*result->begin();
+  char *out = Append4(begin + old_size, a, b, c, d);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+int GlobalReplaceSubstring(const std::string &substring,
+                           const std::string &replacement, std::string *s) {
+  GOOGLE_CHECK(s != nullptr);
+  if (s->empty() || substring.empty())
+    return 0;
+  std::string tmp;
+  int num_replacements = 0;
+  int pos = 0;
+  for (StringPiece::size_type match_pos =
+           s->find(substring.data(), pos, substring.length());
+       match_pos != std::string::npos; pos = match_pos + substring.length(),
+                              match_pos = s->find(substring.data(), pos,
+                                                  substring.length())) {
+    ++num_replacements;
+    // Append the original content before the match.
+    tmp.append(*s, pos, match_pos - pos);
+    // Append the replacement for the match.
+    tmp.append(replacement.begin(), replacement.end());
+  }
+  // Append the content after the last match. If no replacements were made, the
+  // original string is left untouched.
+  if (num_replacements > 0) {
+    tmp.append(*s, pos, s->length() - pos);
+    s->swap(tmp);
+  }
+  return num_replacements;
+}
+
+int CalculateBase64EscapedLen(int input_len, bool do_padding) {
+  // Base64 encodes three bytes of input at a time. If the input is not
+  // divisible by three, we pad as appropriate.
+  //
+  // (from http://tools.ietf.org/html/rfc3548)
+  // Special processing is performed if fewer than 24 bits are available
+  // at the end of the data being encoded.  A full encoding quantum is
+  // always completed at the end of a quantity.  When fewer than 24 input
+  // bits are available in an input group, zero bits are added (on the
+  // right) to form an integral number of 6-bit groups.  Padding at the
+  // end of the data is performed using the '=' character.  Since all base
+  // 64 input is an integral number of octets, only the following cases
+  // can arise:
+
+
+  // Base64 encodes each three bytes of input into four bytes of output.
+  int len = (input_len / 3) * 4;
+
+  if (input_len % 3 == 0) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (1) the final quantum of encoding input is an integral multiple of 24
+    // bits; here, the final unit of encoded output will be an integral
+    // multiple of 4 characters with no "=" padding,
+  } else if (input_len % 3 == 1) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (2) the final quantum of encoding input is exactly 8 bits; here, the
+    // final unit of encoded output will be two characters followed by two
+    // "=" padding characters, or
+    len += 2;
+    if (do_padding) {
+      len += 2;
+    }
+  } else {  // (input_len % 3 == 2)
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (3) the final quantum of encoding input is exactly 16 bits; here, the
+    // final unit of encoded output will be three characters followed by one
+    // "=" padding character.
+    len += 3;
+    if (do_padding) {
+      len += 1;
+    }
+  }
+
+  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>
+// #include <stdio.h>
+// main()
+// {
+//   static const char Base64[] =
+//     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+//   const 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 == nullptr) || (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*/,
+   7/*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*/,
+   7/*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, std::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, std::string *dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
+}
+
+bool WebSafeBase64Unescape(StringPiece src, std::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 ciphertext.
+  // 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_t 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 cipherblock.
+      if ((szdest -= 2) < 0) return 0;
+      uint32_t 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 cipherblock.
+      if ((szdest -= 3) < 0) return 0;
+      uint32_t 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_t 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,
+                          std::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, std::string *dest,
+                  bool do_padding) {
+  Base64EscapeInternal(src, szsrc, dest, do_padding, kBase64Chars);
+}
+
+void WebSafeBase64Escape(const unsigned char *src, int szsrc, std::string *dest,
+                         bool do_padding) {
+  Base64EscapeInternal(src, szsrc, dest, do_padding, kWebSafeBase64Chars);
+}
+
+void Base64Escape(StringPiece src, std::string *dest) {
+  Base64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+               src.size(), dest, true);
+}
+
+void WebSafeBase64Escape(StringPiece src, std::string *dest) {
+  WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+                      src.size(), dest, false);
+}
+
+void WebSafeBase64EscapeWithPadding(StringPiece src, std::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_t code_point, char* output) {
+  uint32_t 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+
+// 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_t*>(src)];
+}
+
+// ----------------------------------------------------------------------
+// CleanStringLineEndings()
+//   Clean up a multi-line string to conform to Unix line endings.
+//   Reads from src and appends to dst, so usually dst should be empty.
+//
+//   If there is no line ending at the end of a non-empty string, it can
+//   be added automatically.
+//
+//   Four different types of input are correctly handled:
+//
+//     - Unix/Linux files: line ending is LF: pass through unchanged
+//
+//     - DOS/Windows files: line ending is CRLF: convert to LF
+//
+//     - Legacy Mac files: line ending is CR: convert to LF
+//
+//     - Garbled files: random line endings: convert gracefully
+//                      lonely CR, lonely LF, CRLF: convert to LF
+//
+//   @param src The multi-line string to convert
+//   @param dst The converted string is appended to this string
+//   @param auto_end_last_line Automatically terminate the last line
+//
+//   Limitations:
+//
+//     This does not do the right thing for CRCRLF files created by
+//     broken programs that do another Unix->DOS conversion on files
+//     that are already in CRLF format.  For this, a two-pass approach
+//     brute-force would be needed that
+//
+//       (1) determines the presence of LF (first one is ok)
+//       (2) if yes, removes any CR, else convert every CR to LF
+
+void CleanStringLineEndings(const std::string &src, std::string *dst,
+                            bool auto_end_last_line) {
+  if (dst->empty()) {
+    dst->append(src);
+    CleanStringLineEndings(dst, auto_end_last_line);
+  } else {
+    std::string tmp = src;
+    CleanStringLineEndings(&tmp, auto_end_last_line);
+    dst->append(tmp);
+  }
+}
+
+void CleanStringLineEndings(std::string *str, bool auto_end_last_line) {
+  ptrdiff_t output_pos = 0;
+  bool r_seen = false;
+  ptrdiff_t len = str->size();
+
+  char *p = &(*str)[0];
+
+  for (ptrdiff_t input_pos = 0; input_pos < len;) {
+    if (!r_seen && input_pos + 8 < len) {
+      uint64_t v = GOOGLE_UNALIGNED_LOAD64(p + input_pos);
+      // Loop over groups of 8 bytes at a time until we come across
+      // a word that has a byte whose value is less than or equal to
+      // '\r' (i.e. could contain a \n (0x0a) or a \r (0x0d) ).
+      //
+      // We use a has_less macro that quickly tests a whole 64-bit
+      // word to see if any of the bytes has a value < N.
+      //
+      // For more details, see:
+      //   http://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
+#define has_less(x, n) (((x) - ~0ULL / 255 * (n)) & ~(x) & ~0ULL / 255 * 128)
+      if (!has_less(v, '\r' + 1)) {
+#undef has_less
+        // No byte in this word has a value that could be a \r or a \n
+        if (output_pos != input_pos) {
+          GOOGLE_UNALIGNED_STORE64(p + output_pos, v);
+        }
+        input_pos += 8;
+        output_pos += 8;
+        continue;
+      }
+    }
+    std::string::const_reference in = p[input_pos];
+    if (in == '\r') {
+      if (r_seen) p[output_pos++] = '\n';
+      r_seen = true;
+    } else if (in == '\n') {
+      if (input_pos != output_pos)
+        p[output_pos++] = '\n';
+      else
+        output_pos++;
+      r_seen = false;
+    } else {
+      if (r_seen) p[output_pos++] = '\n';
+      r_seen = false;
+      if (input_pos != output_pos)
+        p[output_pos++] = in;
+      else
+        output_pos++;
+    }
+    input_pos++;
+  }
+  if (r_seen ||
+      (auto_end_last_line && output_pos > 0 && p[output_pos - 1] != '\n')) {
+    str->resize(output_pos + 1);
+    str->operator[](output_pos) = '\n';
+  } else if (output_pos < len) {
+    str->resize(output_pos);
+  }
+}
+
+namespace internal {
+
+// ----------------------------------------------------------------------
+// NoLocaleStrtod()
+//   This code will make you cry.
+// ----------------------------------------------------------------------
+
+namespace {
+
+// Returns a string identical to *input except that the character pointed to
+// by radix_pos (which should be '.') is replaced with the locale-specific
+// radix character.
+std::string LocalizeRadix(const char *input, const char *radix_pos) {
+  // Determine the locale-specific radix character by calling sprintf() to
+  // print the number 1.5, then stripping off the digits.  As far as I can
+  // tell, this is the only portable, thread-safe way to get the C library
+  // to divuldge the locale's radix character.  No, localeconv() is NOT
+  // thread-safe.
+  char temp[16];
+  int size = snprintf(temp, sizeof(temp), "%.1f", 1.5);
+  GOOGLE_CHECK_EQ(temp[0], '1');
+  GOOGLE_CHECK_EQ(temp[size - 1], '5');
+  GOOGLE_CHECK_LE(size, 6);
+
+  // Now replace the '.' in the input with it.
+  std::string result;
+  result.reserve(strlen(input) + size - 3);
+  result.append(input, radix_pos);
+  result.append(temp + 1, size - 2);
+  result.append(radix_pos + 1);
+  return result;
+}
+
+}  // namespace
+
+double NoLocaleStrtod(const char *str, char **endptr) {
+  // We cannot simply set the locale to "C" temporarily with setlocale()
+  // as this is not thread-safe.  Instead, we try to parse in the current
+  // locale first.  If parsing stops at a '.' character, then this is a
+  // pretty good hint that we're actually in some other locale in which
+  // '.' is not the radix character.
+
+  char *temp_endptr;
+  double result = strtod(str, &temp_endptr);
+  if (endptr != NULL) *endptr = temp_endptr;
+  if (*temp_endptr != '.') return result;
+
+  // Parsing halted on a '.'.  Perhaps we're in a different locale?  Let's
+  // try to replace the '.' with a locale-specific radix character and
+  // try again.
+  std::string localized = LocalizeRadix(str, temp_endptr);
+  const char *localized_cstr = localized.c_str();
+  char *localized_endptr;
+  result = strtod(localized_cstr, &localized_endptr);
+  if ((localized_endptr - localized_cstr) > (temp_endptr - str)) {
+    // This attempt got further, so replacing the decimal must have helped.
+    // Update endptr to point at the right location.
+    if (endptr != NULL) {
+      // size_diff is non-zero if the localized radix has multiple bytes.
+      int size_diff = localized.size() - strlen(str);
+      // const_cast is necessary to match the strtod() interface.
+      *endptr = const_cast<char *>(
+          str + (localized_endptr - localized_cstr - size_diff));
+    }
+  }
+
+  return result;
+}
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
new file mode 100644
index 0000000..9658abf
--- /dev/null
+++ b/src/google/protobuf/stubs/strutil.h
@@ -0,0 +1,950 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/strings/strutil.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <stdlib.h>
+
+#include <cstring>
+#include <google/protobuf/port_def.inc>
+#include <vector>
+
+namespace google {
+namespace protobuf {
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#define strtoll  _strtoi64
+#define strtoull _strtoui64
+#elif defined(__DECCXX) && defined(__osf__)
+// HP C++ on Tru64 does not have strtoll, but strtol is already 64-bit.
+#define strtoll strtol
+#define strtoull strtoul
+#endif
+
+// ----------------------------------------------------------------------
+// ascii_isalnum()
+//    Check if an ASCII character is alphanumeric.  We can't use ctype's
+//    isalnum() because it is affected by locale.  This function is applied
+//    to identifiers in the protocol buffer language, not to natural-language
+//    strings, so locale should not be taken into account.
+// ascii_isdigit()
+//    Like above, but only accepts digits.
+// ascii_isspace()
+//    Check if the character is a space character.
+// ----------------------------------------------------------------------
+
+inline bool ascii_isalnum(char c) {
+  return ('a' <= c && c <= 'z') ||
+         ('A' <= c && c <= 'Z') ||
+         ('0' <= c && c <= '9');
+}
+
+inline bool ascii_isdigit(char c) {
+  return ('0' <= c && c <= '9');
+}
+
+inline bool ascii_isspace(char c) {
+  return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
+      c == '\r';
+}
+
+inline bool ascii_isupper(char c) {
+  return c >= 'A' && c <= 'Z';
+}
+
+inline bool ascii_islower(char c) {
+  return c >= 'a' && c <= 'z';
+}
+
+inline char ascii_toupper(char c) {
+  return ascii_islower(c) ? c - ('a' - 'A') : c;
+}
+
+inline char ascii_tolower(char c) {
+  return ascii_isupper(c) ? c + ('a' - 'A') : c;
+}
+
+inline int hex_digit_to_int(char c) {
+  /* Assume ASCII. */
+  int x = static_cast<unsigned char>(c);
+  if (x > '9') {
+    x += 9;
+  }
+  return x & 0xf;
+}
+
+// ----------------------------------------------------------------------
+// HasPrefixString()
+//    Check if a string begins with a given prefix.
+// StripPrefixString()
+//    Given a string and a putative prefix, returns the string minus the
+//    prefix string if the prefix matches, otherwise the original
+//    string.
+// ----------------------------------------------------------------------
+inline bool HasPrefixString(StringPiece str, StringPiece prefix) {
+  return str.size() >= prefix.size() &&
+         memcmp(str.data(), prefix.data(), prefix.size()) == 0;
+}
+
+inline std::string StripPrefixString(const std::string& str,
+                                     const std::string& prefix) {
+  if (HasPrefixString(str, prefix)) {
+    return str.substr(prefix.size());
+  } else {
+    return str;
+  }
+}
+
+// ----------------------------------------------------------------------
+// HasSuffixString()
+//    Return true if str ends in suffix.
+// StripSuffixString()
+//    Given a string and a putative suffix, returns the string minus the
+//    suffix string if the suffix matches, otherwise the original
+//    string.
+// ----------------------------------------------------------------------
+inline bool HasSuffixString(StringPiece str, StringPiece suffix) {
+  return str.size() >= suffix.size() &&
+         memcmp(str.data() + str.size() - suffix.size(), suffix.data(),
+                suffix.size()) == 0;
+}
+
+inline std::string StripSuffixString(const std::string& str,
+                                     const std::string& suffix) {
+  if (HasSuffixString(str, suffix)) {
+    return str.substr(0, str.size() - suffix.size());
+  } else {
+    return str;
+  }
+}
+
+// ----------------------------------------------------------------------
+// ReplaceCharacters
+//    Replaces any occurrence of the character 'remove' (or the characters
+//    in 'remove') with the character 'replacewith'.
+//    Good for keeping html characters or protocol characters (\t) out
+//    of places where they might cause a problem.
+// StripWhitespace
+//    Removes whitespaces from both ends of the given string.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void ReplaceCharacters(std::string* s, const char* remove,
+                                       char replacewith);
+
+PROTOBUF_EXPORT void StripWhitespace(std::string* s);
+
+// ----------------------------------------------------------------------
+// LowerString()
+// UpperString()
+// ToUpper()
+//    Convert the characters in "s" to lowercase or uppercase.  ASCII-only:
+//    these functions intentionally ignore locale because they are applied to
+//    identifiers used in the Protocol Buffer language, not to natural-language
+//    strings.
+// ----------------------------------------------------------------------
+
+inline void LowerString(std::string* s) {
+  std::string::iterator end = s->end();
+  for (std::string::iterator i = s->begin(); i != end; ++i) {
+    // tolower() changes based on locale.  We don't want this!
+    if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
+  }
+}
+
+inline void UpperString(std::string* s) {
+  std::string::iterator end = s->end();
+  for (std::string::iterator i = s->begin(); i != end; ++i) {
+    // toupper() changes based on locale.  We don't want this!
+    if ('a' <= *i && *i <= 'z') *i += 'A' - 'a';
+  }
+}
+
+inline void ToUpper(std::string* s) { UpperString(s); }
+
+inline std::string ToUpper(const std::string& s) {
+  std::string out = s;
+  UpperString(&out);
+  return out;
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+//    Give me a string and two patterns "old" and "new", and I replace
+//    the first instance of "old" in the string with "new", if it
+//    exists.  RETURN a new string, regardless of whether the replacement
+//    happened or not.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT std::string StringReplace(const std::string& s,
+                                          const std::string& oldsub,
+                                          const std::string& newsub,
+                                          bool replace_all);
+
+// ----------------------------------------------------------------------
+// SplitStringUsing()
+//    Split a string using a character delimiter. Append the components
+//    to 'result'.  If there are consecutive delimiters, this function skips
+//    over all of them.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void SplitStringUsing(StringPiece full, const char* delim,
+                                      std::vector<std::string>* res);
+
+// Split a string using one or more byte delimiters, presented
+// as a nul-terminated c string. Append the components to 'result'.
+// If there are consecutive delimiters, this function will return
+// corresponding empty strings.  If you want to drop the empty
+// strings, try SplitStringUsing().
+//
+// If "full" is the empty string, yields an empty string as the only value.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void SplitStringAllowEmpty(StringPiece full, const char* delim,
+                                           std::vector<std::string>* result);
+
+// ----------------------------------------------------------------------
+// Split()
+//    Split a string using a character delimiter.
+// ----------------------------------------------------------------------
+inline std::vector<std::string> Split(StringPiece full, const char* delim,
+                                      bool skip_empty = true) {
+  std::vector<std::string> result;
+  if (skip_empty) {
+    SplitStringUsing(full, delim, &result);
+  } else {
+    SplitStringAllowEmpty(full, delim, &result);
+  }
+  return result;
+}
+
+// ----------------------------------------------------------------------
+// JoinStrings()
+//    These methods concatenate a vector of strings into a C++ string, using
+//    the C-string "delim" as a separator between components. There are two
+//    flavors of the function, one flavor returns the concatenated string,
+//    another takes a pointer to the target string. In the latter case the
+//    target string is cleared and overwritten.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void JoinStrings(const std::vector<std::string>& components,
+                                 const char* delim, std::string* result);
+
+inline std::string JoinStrings(const std::vector<std::string>& components,
+                               const char* delim) {
+  std::string result;
+  JoinStrings(components, delim, &result);
+  return result;
+}
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeSequences()
+//    Copies "source" to "dest", rewriting C-style escape sequences
+//    -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII
+//    equivalents.  "dest" must be sufficiently large to hold all
+//    the characters in the rewritten string (i.e. at least as large
+//    as strlen(source) + 1 should be safe, since the replacements
+//    are always shorter than the original escaped sequences).  It's
+//    safe for source and dest to be the same.  RETURNS the length
+//    of dest.
+//
+//    It allows hex sequences \xhh, or generally \xhhhhh with an
+//    arbitrary number of hex digits, but all of them together must
+//    specify a value of a single byte (e.g. \x0045 is equivalent
+//    to \x45, and \x1234 is erroneous).
+//
+//    It also allows escape sequences of the form \uhhhh (exactly four
+//    hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight
+//    hex digits, upper or lower case) to specify a Unicode code
+//    point. The dest array will contain the UTF8-encoded version of
+//    that code-point (e.g., if source contains \u2019, then dest will
+//    contain the three bytes 0xE2, 0x80, and 0x99).
+//
+//    Errors: In the first form of the call, errors are reported with
+//    LOG(ERROR). The same is true for the second form of the call if
+//    the pointer to the string std::vector is nullptr; otherwise, error
+//    messages are stored in the std::vector. In either case, the effect on
+//    the dest array is not defined, but rest of the source will be
+//    processed.
+//    ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest);
+PROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest,
+                                             std::vector<std::string>* errors);
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeString()
+//    This does the same thing as UnescapeCEscapeSequences, but creates
+//    a new string. The caller does not need to worry about allocating
+//    a dest buffer. This should be used for non performance critical
+//    tasks such as printing debug messages. It is safe for src and dest
+//    to be the same.
+//
+//    The second call stores its errors in a supplied string vector.
+//    If the string vector pointer is nullptr, it reports the errors with LOG().
+//
+//    In the first and second calls, the length of dest is returned. In the
+//    the third call, the new string is returned.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT int UnescapeCEscapeString(const std::string& src,
+                                          std::string* dest);
+PROTOBUF_EXPORT int UnescapeCEscapeString(const std::string& src,
+                                          std::string* dest,
+                                          std::vector<std::string>* errors);
+PROTOBUF_EXPORT std::string UnescapeCEscapeString(const std::string& src);
+
+// ----------------------------------------------------------------------
+// CEscape()
+//    Escapes 'src' using C-style escape sequences and returns the resulting
+//    string.
+//
+//    Escaped chars: \n, \r, \t, ", ', \, and !isprint().
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string CEscape(const std::string& src);
+
+// ----------------------------------------------------------------------
+// CEscapeAndAppend()
+//    Escapes 'src' using C-style escape sequences, and appends the escaped
+//    string to 'dest'.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, std::string* dest);
+
+namespace strings {
+// Like CEscape() but does not escape bytes with the upper bit set.
+PROTOBUF_EXPORT std::string Utf8SafeCEscape(const std::string& src);
+
+// Like CEscape() but uses hex (\x) escapes instead of octals.
+PROTOBUF_EXPORT std::string CHexEscape(const std::string& src);
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// strto32()
+// strtou32()
+// strto64()
+// strtou64()
+//    Architecture-neutral plug compatible replacements for strtol() and
+//    strtoul().  Long's have different lengths on ILP-32 and LP-64
+//    platforms, so using these is safer, from the point of view of
+//    overflow behavior, than using the standard libc functions.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int32_t strto32_adaptor(const char* nptr, char** endptr,
+                                        int base);
+PROTOBUF_EXPORT uint32_t strtou32_adaptor(const char* nptr, char** endptr,
+                                          int base);
+
+inline int32_t strto32(const char *nptr, char **endptr, int base) {
+  if (sizeof(int32_t) == sizeof(long))
+    return strtol(nptr, endptr, base);
+  else
+    return strto32_adaptor(nptr, endptr, base);
+}
+
+inline uint32_t strtou32(const char *nptr, char **endptr, int base) {
+  if (sizeof(uint32_t) == sizeof(unsigned long))
+    return strtoul(nptr, endptr, base);
+  else
+    return strtou32_adaptor(nptr, endptr, base);
+}
+
+// For now, long long is 64-bit on all the platforms we care about, so these
+// functions can simply pass the call to strto[u]ll.
+inline int64_t strto64(const char *nptr, char **endptr, int base) {
+  static_assert(sizeof(int64_t) == sizeof(long long),
+                "sizeof int64_t is not sizeof long long");
+  return strtoll(nptr, endptr, base);
+}
+
+inline uint64_t strtou64(const char *nptr, char **endptr, int base) {
+  static_assert(sizeof(uint64_t) == sizeof(unsigned long long),
+                "sizeof uint64_t is not sizeof unsigned long long");
+  return strtoull(nptr, endptr, base);
+}
+
+// ----------------------------------------------------------------------
+// safe_strtob()
+// safe_strto32()
+// safe_strtou32()
+// safe_strto64()
+// safe_strtou64()
+// safe_strtof()
+// safe_strtod()
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT bool safe_strtob(StringPiece str, bool* value);
+
+PROTOBUF_EXPORT bool safe_strto32(const std::string& str, int32_t* value);
+PROTOBUF_EXPORT bool safe_strtou32(const std::string& str, uint32_t* value);
+inline bool safe_strto32(const char* str, int32_t* value) {
+  return safe_strto32(std::string(str), value);
+}
+inline bool safe_strto32(StringPiece str, int32_t* value) {
+  return safe_strto32(str.ToString(), value);
+}
+inline bool safe_strtou32(const char* str, uint32_t* value) {
+  return safe_strtou32(std::string(str), value);
+}
+inline bool safe_strtou32(StringPiece str, uint32_t* value) {
+  return safe_strtou32(str.ToString(), value);
+}
+
+PROTOBUF_EXPORT bool safe_strto64(const std::string& str, int64_t* value);
+PROTOBUF_EXPORT bool safe_strtou64(const std::string& str, uint64_t* value);
+inline bool safe_strto64(const char* str, int64_t* value) {
+  return safe_strto64(std::string(str), value);
+}
+inline bool safe_strto64(StringPiece str, int64_t* value) {
+  return safe_strto64(str.ToString(), value);
+}
+inline bool safe_strtou64(const char* str, uint64_t* value) {
+  return safe_strtou64(std::string(str), value);
+}
+inline bool safe_strtou64(StringPiece str, uint64_t* value) {
+  return safe_strtou64(str.ToString(), value);
+}
+
+PROTOBUF_EXPORT bool safe_strtof(const char* str, float* value);
+PROTOBUF_EXPORT bool safe_strtod(const char* str, double* value);
+inline bool safe_strtof(const std::string& str, float* value) {
+  return safe_strtof(str.c_str(), value);
+}
+inline bool safe_strtod(const std::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);
+}
+
+// ----------------------------------------------------------------------
+// FastIntToBuffer()
+// FastHexToBuffer()
+// FastHex64ToBuffer()
+// FastHex32ToBuffer()
+// FastTimeToBuffer()
+//    These are intended for speed.  FastIntToBuffer() assumes the
+//    integer is non-negative.  FastHexToBuffer() puts output in
+//    hex rather than decimal.  FastTimeToBuffer() puts the output
+//    into RFC822 format.
+//
+//    FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format,
+//    padded to exactly 16 bytes (plus one byte for '\0')
+//
+//    FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format,
+//    padded to exactly 8 bytes (plus one byte for '\0')
+//
+//       All functions take the output buffer as an arg.
+//    They all return a pointer to the beginning of the output,
+//    which may not be the beginning of the input buffer.
+// ----------------------------------------------------------------------
+
+// Suggested buffer size for FastToBuffer functions.  Also works with
+// DoubleToBuffer() and FloatToBuffer().
+static const int kFastToBufferSize = 32;
+
+PROTOBUF_EXPORT char* FastInt32ToBuffer(int32_t i, char* buffer);
+PROTOBUF_EXPORT char* FastInt64ToBuffer(int64_t i, char* buffer);
+char* FastUInt32ToBuffer(uint32_t i, char* buffer);  // inline below
+char* FastUInt64ToBuffer(uint64_t i, char* buffer);  // inline below
+PROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer);
+PROTOBUF_EXPORT char* FastHex64ToBuffer(uint64_t i, char* buffer);
+PROTOBUF_EXPORT char* FastHex32ToBuffer(uint32_t i, char* buffer);
+
+// at least 22 bytes long
+inline char* FastIntToBuffer(int i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
+}
+inline char* FastUIntToBuffer(unsigned int i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
+}
+inline char* FastLongToBuffer(long i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
+}
+inline char* FastULongToBuffer(unsigned long i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
+}
+
+// ----------------------------------------------------------------------
+// FastInt32ToBufferLeft()
+// FastUInt32ToBufferLeft()
+// FastInt64ToBufferLeft()
+// FastUInt64ToBufferLeft()
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer (hence the name, as the
+// output is left-aligned).  The caller is responsible for ensuring that
+// the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the string (i.e. the null character
+// terminating the string).
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32_t i, char* buffer);
+PROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32_t i, char* buffer);
+PROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64_t i, char* buffer);
+PROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64_t i, char* buffer);
+
+// Just define these in terms of the above.
+inline char* FastUInt32ToBuffer(uint32_t i, char* buffer) {
+  FastUInt32ToBufferLeft(i, buffer);
+  return buffer;
+}
+inline char* FastUInt64ToBuffer(uint64_t i, char* buffer) {
+  FastUInt64ToBufferLeft(i, buffer);
+  return buffer;
+}
+
+inline std::string SimpleBtoa(bool value) { return value ? "true" : "false"; }
+
+// ----------------------------------------------------------------------
+// SimpleItoa()
+//    Description: converts an integer to a string.
+//
+//    Return value: string
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string SimpleItoa(int i);
+PROTOBUF_EXPORT std::string SimpleItoa(unsigned int i);
+PROTOBUF_EXPORT std::string SimpleItoa(long i);
+PROTOBUF_EXPORT std::string SimpleItoa(unsigned long i);
+PROTOBUF_EXPORT std::string SimpleItoa(long long i);
+PROTOBUF_EXPORT std::string SimpleItoa(unsigned long long i);
+
+// ----------------------------------------------------------------------
+// SimpleDtoa()
+// SimpleFtoa()
+// DoubleToBuffer()
+// FloatToBuffer()
+//    Description: converts a double or float to a string which, if
+//    passed to NoLocaleStrtod(), will produce the exact same original double
+//    (except in case of NaN; all NaNs are considered the same value).
+//    We try to keep the string short but it's not guaranteed to be as
+//    short as possible.
+//
+//    DoubleToBuffer() and FloatToBuffer() write the text to the given
+//    buffer and return it.  The buffer must be at least
+//    kDoubleToBufferSize bytes for doubles and kFloatToBufferSize
+//    bytes for floats.  kFastToBufferSize is also guaranteed to be large
+//    enough to hold either.
+//
+//    Return value: string
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string SimpleDtoa(double value);
+PROTOBUF_EXPORT std::string SimpleFtoa(float value);
+
+PROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer);
+PROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer);
+
+// In practice, doubles should never need more than 24 bytes and floats
+// should never need more than 14 (including null terminators), but we
+// overestimate to be safe.
+static const int kDoubleToBufferSize = 32;
+static const int kFloatToBufferSize = 24;
+
+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_t value;
+  enum PadSpec spec;
+  template <class Int>
+  explicit Hex(Int v, PadSpec s = NO_PAD)
+      : spec(s) {
+    // Prevent sign-extension by casting integers to
+    // their unsigned counterparts.
+#ifdef LANG_CXX11
+    static_assert(
+        sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
+        "Unknown integer type");
+#endif
+    value = sizeof(v) == 1 ? static_cast<uint8_t>(v)
+          : sizeof(v) == 2 ? static_cast<uint16_t>(v)
+          : sizeof(v) == 4 ? static_cast<uint32_t>(v)
+          : static_cast<uint64_t>(v);
+  }
+};
+
+struct PROTOBUF_EXPORT AlphaNum {
+  const char *piece_data_;  // move these to string_ref eventually
+  size_t piece_size_;       // move these to string_ref eventually
+
+  char digits[kFastToBufferSize];
+
+  // No bool ctor -- bools convert to an integral type.
+  // A bool ctor would also convert incoming pointers (bletch).
+
+  AlphaNum(int i32)
+      : piece_data_(digits),
+        piece_size_(FastInt32ToBufferLeft(i32, digits) - &digits[0]) {}
+  AlphaNum(unsigned int u32)
+      : piece_data_(digits),
+        piece_size_(FastUInt32ToBufferLeft(u32, digits) - &digits[0]) {}
+  AlphaNum(long long i64)
+      : piece_data_(digits),
+        piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
+  AlphaNum(unsigned long long u64)
+      : piece_data_(digits),
+        piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
+
+  // Note: on some architectures, "long" is only 32 bits, not 64, but the
+  // performance hit of using FastInt64ToBufferLeft to handle 32-bit values
+  // is quite minor.
+  AlphaNum(long i64)
+      : piece_data_(digits),
+        piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
+  AlphaNum(unsigned long u64)
+      : piece_data_(digits),
+        piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
+
+  AlphaNum(float f)
+    : piece_data_(digits), piece_size_(strlen(FloatToBuffer(f, digits))) {}
+  AlphaNum(double f)
+    : piece_data_(digits), piece_size_(strlen(DoubleToBuffer(f, digits))) {}
+
+  AlphaNum(Hex hex);
+
+  AlphaNum(const char* c_str)
+      : piece_data_(c_str), piece_size_(strlen(c_str)) {}
+  // TODO: Add a string_ref constructor, eventually
+  // AlphaNum(const StringPiece &pc) : piece(pc) {}
+
+  AlphaNum(const std::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_; }
+
+ private:
+  // Use ":" not ':'
+  AlphaNum(char c);  // NOLINT(runtime/explicit)
+
+  // Disallow copy and assign.
+  AlphaNum(const AlphaNum&);
+  void operator=(const AlphaNum&);
+};
+
+}  // namespace strings
+
+using strings::AlphaNum;
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or numbers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, strings, bool values,
+//    and numeric values.
+//
+//    Don't use this for user-visible strings.  The localization process
+//    works poorly on strings built up out of fragments.
+//
+//    For clarity and performance, don't use StrCat when appending to a
+//    string.  In particular, avoid using any of these (anti-)patterns:
+//      str.append(StrCat(...)
+//      str += StrCat(...)
+//      str = StrCat(str, ...)
+//    where the last is the worse, with the potential to change a loop
+//    from a linear time operation with O(1) dynamic allocations into a
+//    quadratic time operation with O(n) dynamic allocations.  StrAppend
+//    is a better choice than any of the above, subject to the restriction
+//    of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
+//    be a reference into str.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e, const AlphaNum& f);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e, const AlphaNum& f,
+                                   const AlphaNum& g);
+PROTOBUF_EXPORT std::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);
+PROTOBUF_EXPORT std::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 std::string StrCat(const AlphaNum& a) {
+  return std::string(a.data(), a.size());
+}
+
+// ----------------------------------------------------------------------
+// StrAppend()
+//    Same as above, but adds the output to the given string.
+//    WARNING: For speed, StrAppend does not try to check each of its input
+//    arguments to be sure that they are not a subset of the string being
+//    appended to.  That is, while this will work:
+//
+//    string s = "foo";
+//    s += s;
+//
+//    This will not (necessarily) work:
+//
+//    string s = "foo";
+//    StrAppend(&s, s);
+//
+//    Note: while StrCat supports appending up to 9 arguments, StrAppend
+//    is currently limited to 4.  That's rarely an issue except when
+//    automatically transforming StrCat to StrAppend, and can easily be
+//    worked around as consecutive calls to StrAppend are quite efficient.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a);
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
+                               const AlphaNum& b);
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
+                               const AlphaNum& b, const AlphaNum& c);
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
+                               const AlphaNum& b, const AlphaNum& c,
+                               const AlphaNum& d);
+
+// ----------------------------------------------------------------------
+// Join()
+//    These methods concatenate a range of components into a C++ string, using
+//    the C-string "delim" as a separator between components.
+// ----------------------------------------------------------------------
+template <typename Iterator>
+void Join(Iterator start, Iterator end, const char* delim,
+          std::string* result) {
+  for (Iterator it = start; it != end; ++it) {
+    if (it != start) {
+      result->append(delim);
+    }
+    StrAppend(result, *it);
+  }
+}
+
+template <typename Range>
+std::string Join(const Range& components, const char* delim) {
+  std::string result;
+  Join(components.begin(), components.end(), delim, &result);
+  return result;
+}
+
+// ----------------------------------------------------------------------
+// ToHex()
+//    Return a lower-case hex string representation of the given integer.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string ToHex(uint64_t num);
+
+// ----------------------------------------------------------------------
+// GlobalReplaceSubstring()
+//    Replaces all instances of a substring in a string.  Does nothing
+//    if 'substring' is empty.  Returns the number of replacements.
+//
+//    NOTE: The string pieces must not overlap s.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int GlobalReplaceSubstring(const std::string& substring,
+                                           const std::string& replacement,
+                                           std::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.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT bool Base64Unescape(StringPiece src, std::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.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int WebSafeBase64Unescape(const char* src, int slen, char* dest,
+                                          int szdest);
+PROTOBUF_EXPORT bool WebSafeBase64Unescape(StringPiece src, std::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.
+PROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len, bool do_padding);
+// Use this version when calling Base64Escape without a do_padding arg.
+PROTOBUF_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 "=".
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int Base64Escape(const unsigned char* src, int slen, char* dest,
+                                 int szdest);
+PROTOBUF_EXPORT int WebSafeBase64Escape(const unsigned char* src, int slen,
+                                        char* dest, int szdest,
+                                        bool do_padding);
+// Encode src into dest with padding.
+PROTOBUF_EXPORT void Base64Escape(StringPiece src, std::string* dest);
+// Encode src into dest web-safely without padding.
+PROTOBUF_EXPORT void WebSafeBase64Escape(StringPiece src, std::string* dest);
+// Encode src into dest web-safely with padding.
+PROTOBUF_EXPORT void WebSafeBase64EscapeWithPadding(StringPiece src,
+                                                    std::string* dest);
+
+PROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc,
+                                  std::string* dest, bool do_padding);
+PROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc,
+                                         std::string* dest, bool do_padding);
+
+inline bool IsValidCodePoint(uint32_t code_point) {
+  return code_point < 0xD800 ||
+         (code_point >= 0xE000 && code_point <= 0x10FFFF);
+}
+
+static const int UTFmax = 4;
+// ----------------------------------------------------------------------
+// EncodeAsUTF8Char()
+//  Helper to append a Unicode code point to a string as UTF8, without bringing
+//  in any external dependencies. The output buffer must be as least 4 bytes
+//  large.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int EncodeAsUTF8Char(uint32_t code_point, char* output);
+
+// ----------------------------------------------------------------------
+// UTF8FirstLetterNumBytes()
+//   Length of the first UTF-8 character.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int UTF8FirstLetterNumBytes(const char* src, int len);
+
+// From google3/third_party/absl/strings/escaping.h
+
+// ----------------------------------------------------------------------
+// CleanStringLineEndings()
+//   Clean up a multi-line string to conform to Unix line endings.
+//   Reads from src and appends to dst, so usually dst should be empty.
+//
+//   If there is no line ending at the end of a non-empty string, it can
+//   be added automatically.
+//
+//   Four different types of input are correctly handled:
+//
+//     - Unix/Linux files: line ending is LF: pass through unchanged
+//
+//     - DOS/Windows files: line ending is CRLF: convert to LF
+//
+//     - Legacy Mac files: line ending is CR: convert to LF
+//
+//     - Garbled files: random line endings: convert gracefully
+//                      lonely CR, lonely LF, CRLF: convert to LF
+//
+//   @param src The multi-line string to convert
+//   @param dst The converted string is appended to this string
+//   @param auto_end_last_line Automatically terminate the last line
+//
+//   Limitations:
+//
+//     This does not do the right thing for CRCRLF files created by
+//     broken programs that do another Unix->DOS conversion on files
+//     that are already in CRLF format.  For this, a two-pass approach
+//     brute-force would be needed that
+//
+//       (1) determines the presence of LF (first one is ok)
+//       (2) if yes, removes any CR, else convert every CR to LF
+PROTOBUF_EXPORT void CleanStringLineEndings(const std::string& src,
+                                            std::string* dst,
+                                            bool auto_end_last_line);
+
+// Same as above, but transforms the argument in place.
+PROTOBUF_EXPORT void CleanStringLineEndings(std::string* str,
+                                            bool auto_end_last_line);
+
+namespace strings {
+inline bool EndsWith(StringPiece text, StringPiece suffix) {
+  return suffix.empty() ||
+      (text.size() >= suffix.size() &&
+       memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
+              suffix.size()) == 0);
+}
+}  // namespace strings
+
+namespace internal {
+
+// A locale-independent version of the standard strtod(), which always
+// uses a dot as the decimal separator.
+double NoLocaleStrtod(const char* str, char** endptr);
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
diff --git a/src/google/protobuf/stubs/strutil_unittest.cc b/src/google/protobuf/stubs/strutil_unittest.cc
new file mode 100644
index 0000000..0bb9558
--- /dev/null
+++ b/src/google/protobuf/stubs/strutil_unittest.cc
@@ -0,0 +1,884 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <locale.h>
+
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+#ifdef _WIN32
+#define snprintf _snprintf
+#endif
+
+namespace google {
+namespace protobuf {
+namespace {
+
+// TODO(kenton):  Copy strutil tests from google3?
+
+TEST(StringUtilityTest, ImmuneToLocales) {
+  // Remember the old locale.
+  char* old_locale_cstr = setlocale(LC_NUMERIC, nullptr);
+  ASSERT_TRUE(old_locale_cstr != nullptr);
+  std::string old_locale = old_locale_cstr;
+
+  // Set the locale to "C".
+  ASSERT_TRUE(setlocale(LC_NUMERIC, "C") != nullptr);
+
+  EXPECT_EQ("1.5", SimpleDtoa(1.5));
+  EXPECT_EQ("1.5", SimpleFtoa(1.5));
+
+  if (setlocale(LC_NUMERIC, "es_ES") == nullptr &&
+      setlocale(LC_NUMERIC, "es_ES.utf8") == nullptr) {
+    // Some systems may not have the desired locale available.
+    GOOGLE_LOG(WARNING)
+      << "Couldn't set locale to es_ES.  Skipping this test.";
+  } else {
+    EXPECT_EQ("1.5", SimpleDtoa(1.5));
+    EXPECT_EQ("1.5", SimpleFtoa(1.5));
+  }
+
+  // Return to original locale.
+  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* ciphertext;
+} 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* ciphertext;
+} base64_strings[] = {
+    // Some google quotes
+    // Ciphertext 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 cipher_length;
+    std::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);
+
+    cipher_length = strlen(base64_tests[i].ciphertext);
+
+    // 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, cipher_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].ciphertext);
+
+    // 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, cipher_length);
+    //    Is it still of the expected length?
+    EXPECT_EQ(encode_length, cipher_length);
+
+    //    And is the value still correct?  (i.e., not losing the last byte)
+    EXPECT_STREQ(encode_buffer, base64_tests[i].ciphertext);
+
+    // If we decode it back:
+    decode_str.clear();
+    EXPECT_TRUE(
+        Base64Unescape(StringPiece(encode_buffer, cipher_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.
+    std::string encoded("this junk should be ignored");
+    Base64Escape(
+        std::string(base64_tests[i].plaintext, base64_tests[i].plain_length),
+        &encoded);
+    EXPECT_EQ(encoded, std::string(encode_buffer, cipher_length));
+
+    std::string decoded("this junk should be ignored");
+    EXPECT_TRUE(
+        Base64Unescape(StringPiece(encode_buffer, cipher_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.
+      std::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].ciphertext, cipher_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, cipher_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, cipher_length, true);
+    //    Is it still of the expected length?
+    EXPECT_EQ(encode_length, cipher_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(), cipher_length);
+    EXPECT_STREQ(encoded.c_str(), websafe);
+
+    //    If we decode it back:
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer, cipher_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, cipher_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 = cipher_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, cipher_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, cipher_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, cipher_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';
+        cipher_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, cipher_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, cipher_length, false);
+    //    Is it still of the expected length?
+    EXPECT_EQ(encode_length, cipher_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
+    std::string plain(base64_tests[i].plaintext, base64_tests[i].plain_length);
+    encoded = "this junk should be ignored";
+    WebSafeBase64Escape(plain, &encoded);
+    EXPECT_EQ(encoded.size(), cipher_length);
+    EXPECT_STREQ(encoded.c_str(), websafe);
+
+    //    If we decode it back:
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer, cipher_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, cipher_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, cipher_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 cipher_length = strlen(base64_strings[i].ciphertext);
+    std::vector<char> buffer(cipher_length + 1);
+    int encode_length = WebSafeBase64Escape(unsigned_plaintext,
+                                                     plain_length,
+                                                     &buffer[0],
+                                                     buffer.size(),
+                                                     false);
+    EXPECT_EQ(cipher_length, encode_length);
+    EXPECT_EQ(
+        CalculateBase64EscapedLen(plain_length, false), encode_length);
+    buffer[ encode_length ] = '\0';
+    EXPECT_STREQ(base64_strings[i].ciphertext, &buffer[0]);
+  }
+
+  // Verify the behavior when decoding bad data
+  {
+    const char* bad_data = "ab-/";
+    std::string buf;
+    EXPECT_FALSE(Base64Unescape(StringPiece(bad_data), &buf));
+    EXPECT_TRUE(!WebSafeBase64Unescape(bad_data, &buf));
+    EXPECT_TRUE(buf.empty());
+  }
+}
+
+// Test StrCat of ints and longs of various sizes and signdedness.
+TEST(StrCat, Ints) {
+  const short s = -1;  // NOLINT(runtime/int)
+  const uint16_t us = 2;
+  const int i = -3;
+  const unsigned int ui = 4;
+  const long l = -5;                 // NOLINT(runtime/int)
+  const unsigned long ul = 6;        // NOLINT(runtime/int)
+  const long long ll = -7;           // NOLINT(runtime/int)
+  const unsigned long long ull = 8;  // NOLINT(runtime/int)
+  const ptrdiff_t ptrdiff = -9;
+  const size_t size = 10;
+  const intptr_t intptr = -12;
+  const uintptr_t uintptr = 13;
+  std::string answer;
+  answer = StrCat(s, us);
+  EXPECT_EQ(answer, "-12");
+  answer = StrCat(i, ui);
+  EXPECT_EQ(answer, "-34");
+  answer = StrCat(l, ul);
+  EXPECT_EQ(answer, "-56");
+  answer = StrCat(ll, ull);
+  EXPECT_EQ(answer, "-78");
+  answer = StrCat(ptrdiff, size);
+  EXPECT_EQ(answer, "-910");
+  answer = StrCat(ptrdiff, intptr);
+  EXPECT_EQ(answer, "-9-12");
+  answer = StrCat(uintptr, 0);
+  EXPECT_EQ(answer, "130");
+}
+
+class ReplaceChars
+    : public ::testing::TestWithParam<
+          std::tuple<std::string, std::string, const char*, char>> {};
+
+TEST_P(ReplaceChars, ReplacesAllOccurencesOfAnyCharInReplaceWithAReplaceChar) {
+  std::string expected = std::get<0>(GetParam());
+  std::string string_to_replace_in = std::get<1>(GetParam());
+  const char* what_to_replace = std::get<2>(GetParam());
+  char replacement = std::get<3>(GetParam());
+  ReplaceCharacters(&string_to_replace_in, what_to_replace, replacement);
+  ASSERT_EQ(expected, string_to_replace_in);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    Replace, ReplaceChars,
+    ::testing::Values(
+        std::make_tuple("", "", "", '_'),    // empty string should remain empty
+        std::make_tuple(" ", " ", "", '_'),  // no replacement string
+        std::make_tuple(" ", " ", "_-abcedf",
+                        '*'),  // replacement character not in string
+        std::make_tuple("replace", "Replace", "R",
+                        'r'),  // replace one character
+        std::make_tuple("not_spaces__", "not\nspaces\t ", " \t\r\n",
+                        '_'),  // replace some special characters
+        std::make_tuple("c++", "cxx", "x",
+                        '+'),  // same character multiple times
+        std::make_tuple("qvvvvvng v T", "queueing a T", "aeiou",
+                        'v')));  // replace all voewls
+
+class StripWs
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {};
+
+TEST_P(StripWs, AlwaysStripsLeadingAndTrailingWhitespace) {
+  std::string expected = std::get<0>(GetParam());
+  std::string string_to_strip = std::get<1>(GetParam());
+  StripWhitespace(&string_to_strip);
+  ASSERT_EQ(expected, string_to_strip);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    Strip, StripWs,
+    ::testing::Values(
+        std::make_tuple("", ""),   // empty string should remain empty
+        std::make_tuple("", " "),  // only ws should become empty
+        std::make_tuple("no whitespace",
+                        " no whitespace"),  // leading ws removed
+        std::make_tuple("no whitespace",
+                        "no whitespace "),  // trailing ws removed
+        std::make_tuple("no whitespace",
+                        " no whitespace "),  // same nb. of leading and trailing
+        std::make_tuple(
+            "no whitespace",
+            "  no whitespace "),  // different nb. of leading/trailing
+        std::make_tuple("no whitespace",
+                        " no whitespace  ")));  // more trailing than leading
+
+}  // anonymous namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/substitute.cc b/src/google/protobuf/stubs/substitute.cc
new file mode 100644
index 0000000..d301682
--- /dev/null
+++ b/src/google/protobuf/stubs/substitute.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+using internal::SubstituteArg;
+
+// Returns the number of args in arg_array which were passed explicitly
+// to Substitute().
+static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
+  int count = 0;
+  while (args_array[count] != nullptr && args_array[count]->size() != -1) {
+    ++count;
+  }
+  return count;
+}
+
+std::string Substitute(const std::string& format, const SubstituteArg& arg0,
+                       const SubstituteArg& arg1, const SubstituteArg& arg2,
+                       const SubstituteArg& arg3, const SubstituteArg& arg4,
+                       const SubstituteArg& arg5, const SubstituteArg& arg6,
+                       const SubstituteArg& arg7, const SubstituteArg& arg8,
+                       const SubstituteArg& arg9) {
+  std::string result;
+  SubstituteAndAppend(&result, format.c_str(), arg0, arg1, arg2, arg3, arg4,
+                      arg5, arg6, arg7, arg8, arg9);
+  return result;
+}
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const SubstituteArg& arg0, const SubstituteArg& arg1,
+                         const SubstituteArg& arg2, const SubstituteArg& arg3,
+                         const SubstituteArg& arg4, const SubstituteArg& arg5,
+                         const SubstituteArg& arg6, const SubstituteArg& arg7,
+                         const SubstituteArg& arg8, const SubstituteArg& arg9) {
+  const SubstituteArg* const args_array[] = {
+    &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, nullptr
+  };
+
+  // Determine total size needed.
+  int size = 0;
+  for (int i = 0; format[i] != '\0'; i++) {
+    if (format[i] == '$') {
+      if (ascii_isdigit(format[i+1])) {
+        int index = format[i+1] - '0';
+        if (args_array[index]->size() == -1) {
+          GOOGLE_LOG(DFATAL)
+            << "strings::Substitute format string invalid: asked for \"$"
+            << index << "\", but only " << CountSubstituteArgs(args_array)
+            << " args were given.  Full format string was: \""
+            << CEscape(format) << "\".";
+          return;
+        }
+        size += args_array[index]->size();
+        ++i;  // Skip next char.
+      } else if (format[i+1] == '$') {
+        ++size;
+        ++i;  // Skip next char.
+      } else {
+        GOOGLE_LOG(DFATAL)
+          << "Invalid strings::Substitute() format string: \""
+          << CEscape(format) << "\".";
+        return;
+      }
+    } else {
+      ++size;
+    }
+  }
+
+  if (size == 0) return;
+
+  // Build the string.
+  int original_size = output->size();
+  STLStringResizeUninitialized(output, original_size + size);
+  char* target = string_as_array(output) + original_size;
+  for (int i = 0; format[i] != '\0'; i++) {
+    if (format[i] == '$') {
+      if (ascii_isdigit(format[i+1])) {
+        unsigned int index = format[i+1] - '0';
+        assert(index < 10);
+        const SubstituteArg* src = args_array[index];
+        memcpy(target, src->data(), src->size());
+        target += src->size();
+        ++i;  // Skip next char.
+      } else if (format[i+1] == '$') {
+        *target++ = '$';
+        ++i;  // Skip next char.
+      }
+    } else {
+      *target++ = format[i];
+    }
+  }
+
+  GOOGLE_DCHECK_EQ(target - output->data(), output->size());
+}
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/substitute.h b/src/google/protobuf/stubs/substitute.h
new file mode 100644
index 0000000..0f851de
--- /dev/null
+++ b/src/google/protobuf/stubs/substitute.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.
+
+// Author: kenton@google.com (Kenton Varda)
+// from google3/strings/substitute.h
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <string>
+
+#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
+#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+// ----------------------------------------------------------------------
+// strings::Substitute()
+// strings::SubstituteAndAppend()
+//   Kind of like StringPrintf, but different.
+//
+//   Example:
+//     string GetMessage(string first_name, string last_name, int age) {
+//       return strings::Substitute("My name is $0 $1 and I am $2 years old.",
+//                                  first_name, last_name, age);
+//     }
+//
+//   Differences from StringPrintf:
+//   * The format string does not identify the types of arguments.
+//     Instead, the magic of C++ deals with this for us.  See below
+//     for a list of accepted types.
+//   * Substitutions in the format string are identified by a '$'
+//     followed by a digit.  So, you can use arguments out-of-order and
+//     use the same argument multiple times.
+//   * It's much faster than StringPrintf.
+//
+//   Supported types:
+//   * Strings (const char*, const string&)
+//     * Note that this means you do not have to add .c_str() to all of
+//       your strings.  In fact, you shouldn't; it will be slower.
+//   * int32, int64, uint32, uint64:  Formatted using SimpleItoa().
+//   * float, double:  Formatted using SimpleFtoa() and SimpleDtoa().
+//   * bool:  Printed as "true" or "false".
+//
+//   SubstituteAndAppend() is like Substitute() but appends the result to
+//   *output.  Example:
+//
+//     string str;
+//     strings::SubstituteAndAppend(&str,
+//                                  "My name is $0 $1 and I am $2 years old.",
+//                                  first_name, last_name, age);
+//
+//   Substitute() is significantly faster than StringPrintf().  For very
+//   large strings, it may be orders of magnitude faster.
+// ----------------------------------------------------------------------
+
+namespace internal {  // Implementation details.
+
+class SubstituteArg {
+ public:
+  inline SubstituteArg(const char* value)
+    : text_(value), size_(strlen(text_)) {}
+  inline SubstituteArg(const std::string& value)
+      : text_(value.data()), size_(value.size()) {}
+  inline SubstituteArg(const StringPiece value)
+      : text_(value.data()), size_(value.size()) {}
+
+  // Indicates that no argument was given.
+  inline explicit SubstituteArg()
+    : text_(nullptr), size_(-1) {}
+
+  // Primitives
+  // We don't overload for signed and unsigned char because if people are
+  // explicitly declaring their chars as signed or unsigned then they are
+  // probably actually using them as 8-bit integers and would probably
+  // prefer an integer representation.  But, we don't really know.  So, we
+  // make the caller decide what to do.
+  inline SubstituteArg(char value)
+    : text_(scratch_), size_(1) { scratch_[0] = value; }
+  inline SubstituteArg(short value)
+    : text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned short value)
+    : text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(int value)
+    : text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned int value)
+    : text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(long value)
+    : text_(FastLongToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned long value)
+    : text_(FastULongToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(long long value)
+    : text_(FastInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned long long value)
+    : text_(FastUInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(float value)
+    : text_(FloatToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(double value)
+    : text_(DoubleToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(bool value)
+    : text_(value ? "true" : "false"), size_(strlen(text_)) {}
+
+  inline const char* data() const { return text_; }
+  inline int size() const { return size_; }
+
+ private:
+  const char* text_;
+  int size_;
+  char scratch_[kFastToBufferSize];
+};
+
+}  // namespace internal
+
+PROTOBUF_EXPORT std::string Substitute(
+    const std::string& format,
+    const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg9 = internal::SubstituteArg());
+
+PROTOBUF_EXPORT void SubstituteAndAppend(
+    std::string* output, const char* format,
+    const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg9 = internal::SubstituteArg());
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
diff --git a/src/google/protobuf/stubs/template_util.h b/src/google/protobuf/stubs/template_util.h
new file mode 100644
index 0000000..feef904
--- /dev/null
+++ b/src/google/protobuf/stubs/template_util.h
@@ -0,0 +1,138 @@
+// Copyright 2005 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.
+
+// ----
+// Author: lar@google.com (Laramie Leavitt)
+//
+// Template metaprogramming utility functions.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems.  Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+//
+// The names chosen here reflect those used in tr1 and the boost::mpl
+// library, there are similar operations used in the Loki library as
+// well.  I prefer the boost names for 2 reasons:
+// 1.  I think that portions of the Boost libraries are more likely to
+// be included in the c++ standard.
+// 2.  It is not impossible that some of the boost libraries will be
+// included in our own build in the future.
+// Both of these outcomes means that we may be able to directly replace
+// some of these with boost equivalents.
+//
+#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+  char dummy[2];
+};
+
+// Identity metafunction.
+template <class T>
+struct identity_ {
+  typedef T type;
+};
+
+// integral_constant, defined in tr1, is a wrapper for an integer
+// value. We don't really need this generality; we could get away
+// with hardcoding the integer type to bool. We use the fully
+// general integer_constant for compatibility with tr1.
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+
+// Abbreviations: true_type and false_type are structs that represent boolean
+// true and false values. Also define the boost::mpl versions of those names,
+// true_ and false_.
+typedef integral_constant<bool, true>  true_type;
+typedef integral_constant<bool, false> false_type;
+typedef true_type  true_;
+typedef false_type false_;
+
+// if_ is a templatized conditional statement.
+// if_<cond, A, B> is a compile time evaluation of cond.
+// if_<>::type contains A if cond is true, B otherwise.
+template<bool cond, typename A, typename B>
+struct if_{
+  typedef A type;
+};
+
+template<typename A, typename B>
+struct if_<false, A, B> {
+  typedef B type;
+};
+
+
+// type_equals_ is a template type comparator, similar to Loki IsSameType.
+// type_equals_<A, B>::value is true iff "A" is the same type as "B".
+//
+// New code should prefer base::is_same, defined in base/type_traits.h.
+// It is functionally identical, but is_same is the standard spelling.
+template<typename A, typename B>
+struct type_equals_ : public false_ {
+};
+
+template<typename A>
+struct type_equals_<A, A> : public true_ {
+};
+
+// and_ is a template && operator.
+// and_<A, B>::value evaluates "A::value && B::value".
+template<typename A, typename B>
+struct and_ : public integral_constant<bool, (A::value && B::value)> {
+};
+
+// or_ is a template || operator.
+// or_<A, B>::value evaluates "A::value || B::value".
+template<typename A, typename B>
+struct or_ : public integral_constant<bool, (A::value || B::value)> {
+};
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
diff --git a/src/google/protobuf/stubs/template_util_unittest.cc b/src/google/protobuf/stubs/template_util_unittest.cc
new file mode 100644
index 0000000..b1745e2
--- /dev/null
+++ b/src/google/protobuf/stubs/template_util_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2005 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.
+
+// ----
+// Author: lar@google.com (Laramie Leavitt)
+//
+// These tests are really compile time tests.
+// If you try to step through this in a debugger
+// you will not see any evaluations, merely that
+// value is assigned true or false sequentially.
+
+#include <google/protobuf/stubs/template_util.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace GOOGLE_NAMESPACE = google::protobuf::internal;
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(TemplateUtilTest, TestSize) {
+  EXPECT_GT(sizeof(GOOGLE_NAMESPACE::big_), sizeof(GOOGLE_NAMESPACE::small_));
+}
+
+TEST(TemplateUtilTest, TestIntegralConstants) {
+  // test the built-in types.
+  EXPECT_TRUE(true_type::value);
+  EXPECT_FALSE(false_type::value);
+
+  typedef integral_constant<int, 1> one_type;
+  EXPECT_EQ(1, one_type::value);
+}
+
+TEST(TemplateUtilTest, TestTemplateIf) {
+  typedef if_<true, true_type, false_type>::type if_true;
+  EXPECT_TRUE(if_true::value);
+
+  typedef if_<false, true_type, false_type>::type if_false;
+  EXPECT_FALSE(if_false::value);
+}
+
+TEST(TemplateUtilTest, TestTemplateTypeEquals) {
+  // Check that the TemplateTypeEquals works correctly.
+  bool value = false;
+
+  // Test the same type is true.
+  value = type_equals_<int, int>::value;
+  EXPECT_TRUE(value);
+
+  // Test different types are false.
+  value = type_equals_<float, int>::value;
+  EXPECT_FALSE(value);
+
+  // Test type aliasing.
+  typedef const int foo;
+  value = type_equals_<const foo, const int>::value;
+  EXPECT_TRUE(value);
+}
+
+TEST(TemplateUtilTest, TestTemplateAndOr) {
+  // Check that the TemplateTypeEquals works correctly.
+  bool value = false;
+
+  // Yes && Yes == true.
+  value = and_<true_, true_>::value;
+  EXPECT_TRUE(value);
+  // Yes && No == false.
+  value = and_<true_, false_>::value;
+  EXPECT_FALSE(value);
+  // No && Yes == false.
+  value = and_<false_, true_>::value;
+  EXPECT_FALSE(value);
+  // No && No == false.
+  value = and_<false_, false_>::value;
+  EXPECT_FALSE(value);
+
+  // Yes || Yes == true.
+  value = or_<true_, true_>::value;
+  EXPECT_TRUE(value);
+  // Yes || No == true.
+  value = or_<true_, false_>::value;
+  EXPECT_TRUE(value);
+  // No || Yes == true.
+  value = or_<false_, true_>::value;
+  EXPECT_TRUE(value);
+  // No || No == false.
+  value = or_<false_, false_>::value;
+  EXPECT_FALSE(value);
+}
+
+TEST(TemplateUtilTest, TestIdentity) {
+  EXPECT_TRUE(
+      (type_equals_<GOOGLE_NAMESPACE::identity_<int>::type, int>::value));
+  EXPECT_TRUE(
+      (type_equals_<GOOGLE_NAMESPACE::identity_<void>::type, void>::value));
+}
+
+}  // anonymous namespace
+}  // namespace internal
+}  // 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..692cb82
--- /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_t kSecondsPerMinute = 60;
+static const int64_t kSecondsPerHour = 3600;
+static const int64_t kSecondsPerDay = kSecondsPerHour * 24;
+static const int64_t kSecondsPer400Years =
+    kSecondsPerDay * (400 * 365 + 400 / 4 - 3);
+// Seconds from 0001-01-01T00:00:00 to 1970-01-01T:00:00:00
+static const int64_t kSecondsFromEraToEpoch = 62135596800LL;
+// The range of timestamp values we support.
+static const int64_t kMinTime = -62135596800LL;  // 0001-01-01T00:00:00
+static const int64_t 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_t 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_t 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_t 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_t 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.day <= kDaysInMonth[time.month] + 1;
+  } else {
+    return time.day <= kDaysInMonth[time.month];
+  }
+}
+
+// Count the number of seconds elapsed from 0001-01-01T00:00:00 to the given
+// time.
+int64_t SecondsSinceCommonEra(const DateTime& time) {
+  int64_t 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.
+std::string FormatNanos(int32_t 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 nullptr 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 nullptr;
+  }
+  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 nullptr;
+  }
+}
+
+// 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_t* nanos) {
+  if (!ascii_isdigit(*data)) {
+    return nullptr;
+  }
+  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_t* offset) {
+  // Accept format "HH:MM". E.g., "08:00"
+  int hour;
+  if ((data = ParseInt(data, 2, 0, 23, &hour)) == nullptr) {
+    return nullptr;
+  }
+  if (*data++ != ':') {
+    return nullptr;
+  }
+  int minute;
+  if ((data = ParseInt(data, 2, 0, 59, &minute)) == nullptr) {
+    return nullptr;
+  }
+  *offset = (hour * 60 + minute) * 60;
+  return data;
+}
+}  // namespace
+
+bool SecondsToDateTime(int64_t seconds, DateTime* time) {
+  if (seconds < kMinTime || seconds > kMaxTime) {
+    return false;
+  }
+  // It's easier to calculate 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_t* seconds) {
+  if (!ValidateDateTime(time)) {
+    return false;
+  }
+  *seconds = SecondsSinceCommonEra(time) - kSecondsFromEraToEpoch;
+  return true;
+}
+
+void GetCurrentTime(int64_t* seconds, int32_t* nanos) {
+  // TODO(xiaofeng): Improve the accuracy of this implementation (or just
+  // remove this method from protobuf).
+  *seconds = time(nullptr);
+  *nanos = 0;
+}
+
+std::string FormatTime(int64_t seconds, int32_t nanos) {
+  DateTime time;
+  if (nanos < 0 || nanos > 999999999 || !SecondsToDateTime(seconds, &time)) {
+    return "InvalidTime";
+  }
+  std::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 std::string& value, int64_t* seconds, int32_t* 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)) == nullptr) {
+    return false;
+  }
+  // Expect '-'
+  if (*data++ != '-') return false;
+  // Parse month
+  if ((data = ParseInt(data, 2, 1, 12, &time.month)) == nullptr) {
+    return false;
+  }
+  // Expect '-'
+  if (*data++ != '-') return false;
+  // Parse day
+  if ((data = ParseInt(data, 2, 1, 31, &time.day)) == nullptr) {
+    return false;
+  }
+  // Expect 'T'
+  if (*data++ != 'T') return false;
+  // Parse hour
+  if ((data = ParseInt(data, 2, 0, 23, &time.hour)) == nullptr) {
+    return false;
+  }
+  // Expect ':'
+  if (*data++ != ':') return false;
+  // Parse minute
+  if ((data = ParseInt(data, 2, 0, 59, &time.minute)) == nullptr) {
+    return false;
+  }
+  // Expect ':'
+  if (*data++ != ':') return false;
+  // Parse second
+  if ((data = ParseInt(data, 2, 0, 59, &time.second)) == nullptr) {
+    return false;
+  }
+  if (!DateTimeToSeconds(time, seconds)) {
+    return false;
+  }
+  // Parse nanoseconds.
+  if (*data == '.') {
+    ++data;
+    // Parse nanoseconds.
+    if ((data = ParseNanos(data, nanos)) == nullptr) {
+      return false;
+    }
+  } else {
+    *nanos = 0;
+  }
+  // Parse UTC offsets.
+  if (*data == 'Z') {
+    ++data;
+  } else if (*data == '+') {
+    ++data;
+    int64_t offset;
+    if ((data = ParseTimezoneOffset(data, &offset)) == nullptr) {
+      return false;
+    }
+    *seconds -= offset;
+  } else if (*data == '-') {
+    ++data;
+    int64_t offset;
+    if ((data = ParseTimezoneOffset(data, &offset)) == nullptr) {
+      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..8b6e562
--- /dev/null
+++ b/src/google/protobuf/stubs/time.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_STUBS_TIME_H_
+#define GOOGLE_PROTOBUF_STUBS_TIME_H_
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_EXPORT SecondsToDateTime(int64_t 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 PROTOBUF_EXPORT DateTimeToSeconds(const DateTime& time, int64_t* seconds);
+
+void PROTOBUF_EXPORT GetCurrentTime(int64_t* seconds, int32_t* nanos);
+
+// Formats a time string in RFC3339 format.
+//
+// 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].
+std::string PROTOBUF_EXPORT FormatTime(int64_t seconds, int32_t 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 PROTOBUF_EXPORT ParseTime(const std::string& value, int64_t* seconds,
+                               int32_t* nanos);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..1ce0a1c
--- /dev/null
+++ b/src/google/protobuf/stubs/time_test.cc
@@ -0,0 +1,261 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#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 focus 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, WrongDays) {
+  int64 seconds;
+  DateTime time;
+  time.hour = 0;
+  time.minute = 0;
+  time.second = 0;
+  time.month = 2;
+
+  // Non-leap year.
+  time.year = 2015;
+  time.day = 29;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+
+  // Leap year.
+  time.year = 2016;
+  time.day = 29;
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  time.day = 30;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+
+  // Non-leap year.
+  time.year = 2100;
+  time.day = 29;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+
+  // Leap year.
+  time.year = 2400;
+  time.day = 29;
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  time.day = 30;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+
+  // Non-february
+  time.year = 2015;
+  time.month = 1;
+  time.day = 0;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+  time.day = 1;
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  time.day = 31;
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  time.day = 32;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+
+  // Bad month
+  time.year = 2015;
+  time.month = 0;
+  time.day = 1;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+  time.month = 13;
+  ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
+}
+
+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 formatted 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/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto
new file mode 100644
index 0000000..c7b9c48
--- /dev/null
+++ b/src/google/protobuf/test_messages_proto2.proto
@@ -0,0 +1,297 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 schema for proto2 messages.  This test schema is used by:
+//
+// - conformance tests
+//
+
+// LINT: ALLOW_GROUPS
+
+syntax = "proto2";
+
+package protobuf_test_messages.proto2;
+
+option java_package = "com.google.protobuf_test_messages.proto2";
+
+// This is the default, but we specify it here explicitly.
+option optimize_for = SPEED;
+
+option cc_enable_arenas = true;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+//
+// Also, crucially, all messages and enums in this file are eventually
+// submessages of this message.  So for example, a fuzz test of TestAllTypes
+// could trigger bugs that occur in any message type in this file.  We verify
+// this stays true in a unit test.
+message TestAllTypesProto2 {
+  message NestedMessage {
+    optional int32 a = 1;
+    optional TestAllTypesProto2 corecursive = 2;
+  }
+
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  optional int32 optional_int32 = 1;
+  optional int64 optional_int64 = 2;
+  optional uint32 optional_uint32 = 3;
+  optional uint64 optional_uint64 = 4;
+  optional sint32 optional_sint32 = 5;
+  optional sint64 optional_sint64 = 6;
+  optional fixed32 optional_fixed32 = 7;
+  optional fixed64 optional_fixed64 = 8;
+  optional sfixed32 optional_sfixed32 = 9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional float optional_float = 11;
+  optional double optional_double = 12;
+  optional bool optional_bool = 13;
+  optional string optional_string = 14;
+  optional bytes optional_bytes = 15;
+
+  optional NestedMessage optional_nested_message = 18;
+  optional ForeignMessageProto2 optional_foreign_message = 19;
+
+  optional NestedEnum optional_nested_enum = 21;
+  optional ForeignEnumProto2 optional_foreign_enum = 22;
+
+  optional string optional_string_piece = 24 [ctype = STRING_PIECE];
+  optional string optional_cord = 25 [ctype = CORD];
+
+  optional TestAllTypesProto2 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 ForeignMessageProto2 repeated_foreign_message = 49;
+
+  repeated NestedEnum repeated_nested_enum = 51;
+  repeated ForeignEnumProto2 repeated_foreign_enum = 52;
+
+  repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype = CORD];
+
+  // Packed
+  repeated int32 packed_int32 = 75 [packed = true];
+  repeated int64 packed_int64 = 76 [packed = true];
+  repeated uint32 packed_uint32 = 77 [packed = true];
+  repeated uint64 packed_uint64 = 78 [packed = true];
+  repeated sint32 packed_sint32 = 79 [packed = true];
+  repeated sint64 packed_sint64 = 80 [packed = true];
+  repeated fixed32 packed_fixed32 = 81 [packed = true];
+  repeated fixed64 packed_fixed64 = 82 [packed = true];
+  repeated sfixed32 packed_sfixed32 = 83 [packed = true];
+  repeated sfixed64 packed_sfixed64 = 84 [packed = true];
+  repeated float packed_float = 85 [packed = true];
+  repeated double packed_double = 86 [packed = true];
+  repeated bool packed_bool = 87 [packed = true];
+  repeated NestedEnum packed_nested_enum = 88 [packed = true];
+
+  // Unpacked
+  repeated int32 unpacked_int32 = 89 [packed = false];
+  repeated int64 unpacked_int64 = 90 [packed = false];
+  repeated uint32 unpacked_uint32 = 91 [packed = false];
+  repeated uint64 unpacked_uint64 = 92 [packed = false];
+  repeated sint32 unpacked_sint32 = 93 [packed = false];
+  repeated sint64 unpacked_sint64 = 94 [packed = false];
+  repeated fixed32 unpacked_fixed32 = 95 [packed = false];
+  repeated fixed64 unpacked_fixed64 = 96 [packed = false];
+  repeated sfixed32 unpacked_sfixed32 = 97 [packed = false];
+  repeated sfixed64 unpacked_sfixed64 = 98 [packed = false];
+  repeated float unpacked_float = 99 [packed = false];
+  repeated double unpacked_double = 100 [packed = false];
+  repeated bool unpacked_bool = 101 [packed = false];
+  repeated NestedEnum unpacked_nested_enum = 102 [packed = false];
+
+  // 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, ForeignMessageProto2> map_string_foreign_message = 72;
+  map<string, NestedEnum> map_string_nested_enum = 73;
+  map<string, ForeignEnumProto2> 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;
+    bool oneof_bool = 115;
+    uint64 oneof_uint64 = 116;
+    float oneof_float = 117;
+    double oneof_double = 118;
+    NestedEnum oneof_enum = 119;
+  }
+
+  // extensions
+  extensions 120 to 200;
+
+  // groups
+  optional group Data = 201 {
+    optional int32 group_int32 = 202;
+    optional uint32 group_uint32 = 203;
+  }
+
+  // default values
+  optional int32 default_int32 = 241 [ default = -123456789];
+  optional int64 default_int64 = 242 [ default = -9123456789123456789];
+  optional uint32 default_uint32 = 243 [ default = 2123456789];
+  optional uint64 default_uint64 = 244 [ default = 10123456789123456789];
+  optional sint32 default_sint32 = 245 [ default = -123456789];
+  optional sint64 default_sint64 = 246 [default = -9123456789123456789];
+  optional fixed32 default_fixed32 = 247 [ default = 2123456789];
+  optional fixed64 default_fixed64 = 248 [ default = 10123456789123456789];
+  optional sfixed32 default_sfixed32 = 249 [ default = -123456789];
+  optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789];
+  optional float default_float = 251 [ default = 9e9];
+  optional double default_double = 252 [ default = 7e22];
+  optional bool default_bool = 253 [ default = true];
+  optional string default_string = 254 [ default = "Rosebud"];
+  optional bytes default_bytes = 255 [ default = "joshua"];
+
+  // Test field-name-to-JSON-name convention.
+  // (protobuf says names can be any valid C/C++ identifier.)
+  optional int32 fieldname1 = 401;
+  optional int32 field_name2 = 402;
+  optional int32 _field_name3 = 403;
+  optional int32 field__name4_ = 404;
+  optional int32 field0name5 = 405;
+  optional int32 field_0_name6 = 406;
+  optional int32 fieldName7 = 407;
+  optional int32 FieldName8 = 408;
+  optional int32 field_Name9 = 409;
+  optional int32 Field_Name10 = 410;
+  optional int32 FIELD_NAME11 = 411;
+  optional int32 FIELD_name12 = 412;
+  optional int32 __field_name13 = 413;
+  optional int32 __Field_name14 = 414;
+  optional int32 field__name15 = 415;
+  optional int32 field__Name16 = 416;
+  optional int32 field_name17__ = 417;
+  optional int32 Field_name18__ = 418;
+
+  // Reserved for unknown fields test.
+  reserved 1000 to 9999;
+
+  // message_set test case.
+  message MessageSetCorrect {
+    option message_set_wire_format = true;
+
+    extensions 4 to max;
+  }
+
+  message MessageSetCorrectExtension1 {
+    extend MessageSetCorrect {
+      optional MessageSetCorrectExtension1 message_set_extension = 1547769;
+    }
+    optional string str = 25;
+  }
+
+  message MessageSetCorrectExtension2 {
+    extend MessageSetCorrect {
+      optional MessageSetCorrectExtension2 message_set_extension = 4135312;
+    }
+    optional int32 i = 9;
+  }
+}
+
+message ForeignMessageProto2 {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumProto2 {
+  FOREIGN_FOO = 0;
+  FOREIGN_BAR = 1;
+  FOREIGN_BAZ = 2;
+}
+
+extend TestAllTypesProto2 {
+  optional int32 extension_int32 = 120;
+}
+
+message UnknownToTestAllTypes {
+  optional int32 optional_int32 = 1001;
+  optional string optional_string = 1002;
+  optional ForeignMessageProto2 nested_message = 1003;
+  optional group OptionalGroup = 1004 {
+    optional int32 a = 1;
+  }
+  optional bool optional_bool = 1006;
+  repeated int32 repeated_int32 = 1011;
+}
+
+message NullHypothesisProto2 {
+}
+
+message EnumOnlyProto2 {
+  enum Bool {
+    kFalse = 0;
+    kTrue = 1;
+  }
+}
+
+message OneStringProto2 {
+  optional string data = 1;
+}
diff --git a/src/google/protobuf/test_messages_proto3.proto b/src/google/protobuf/test_messages_proto3.proto
new file mode 100644
index 0000000..1e1285e
--- /dev/null
+++ b/src/google/protobuf/test_messages_proto3.proto
@@ -0,0 +1,288 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 schema for proto3 messages.  This test schema is used by:
+//
+// - benchmarks
+// - fuzz tests
+// - conformance tests
+//
+
+syntax = "proto3";
+
+package protobuf_test_messages.proto3;
+
+option java_package = "com.google.protobuf_test_messages.proto3";
+option objc_class_prefix = "Proto3";
+
+// This is the default, but we specify it here explicitly.
+option optimize_for = SPEED;
+
+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";
+
+option cc_enable_arenas = true;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+//
+// Also, crucially, all messages and enums in this file are eventually
+// submessages of this message.  So for example, a fuzz test of TestAllTypes
+// could trigger bugs that occur in any message type in this file.  We verify
+// this stays true in a unit test.
+message TestAllTypesProto3 {
+  message NestedMessage {
+    int32 a = 1;
+    TestAllTypesProto3 corecursive = 2;
+  }
+
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  enum AliasedEnum {
+    option allow_alias = true;
+
+    ALIAS_FOO = 0;
+    ALIAS_BAR = 1;
+    ALIAS_BAZ = 2;
+    MOO = 2;
+    moo = 2;
+    bAz = 2;
+  }
+
+  // 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;
+  AliasedEnum optional_aliased_enum = 23;
+
+  string optional_string_piece = 24 [ctype = STRING_PIECE];
+  string optional_cord = 25 [ctype = CORD];
+
+  TestAllTypesProto3 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];
+
+  // Packed
+  repeated int32 packed_int32 = 75 [packed = true];
+  repeated int64 packed_int64 = 76 [packed = true];
+  repeated uint32 packed_uint32 = 77 [packed = true];
+  repeated uint64 packed_uint64 = 78 [packed = true];
+  repeated sint32 packed_sint32 = 79 [packed = true];
+  repeated sint64 packed_sint64 = 80 [packed = true];
+  repeated fixed32 packed_fixed32 = 81 [packed = true];
+  repeated fixed64 packed_fixed64 = 82 [packed = true];
+  repeated sfixed32 packed_sfixed32 = 83 [packed = true];
+  repeated sfixed64 packed_sfixed64 = 84 [packed = true];
+  repeated float packed_float = 85 [packed = true];
+  repeated double packed_double = 86 [packed = true];
+  repeated bool packed_bool = 87 [packed = true];
+  repeated NestedEnum packed_nested_enum = 88 [packed = true];
+
+  // Unpacked
+  repeated int32 unpacked_int32 = 89 [packed = false];
+  repeated int64 unpacked_int64 = 90 [packed = false];
+  repeated uint32 unpacked_uint32 = 91 [packed = false];
+  repeated uint64 unpacked_uint64 = 92 [packed = false];
+  repeated sint32 unpacked_sint32 = 93 [packed = false];
+  repeated sint64 unpacked_sint64 = 94 [packed = false];
+  repeated fixed32 unpacked_fixed32 = 95 [packed = false];
+  repeated fixed64 unpacked_fixed64 = 96 [packed = false];
+  repeated sfixed32 unpacked_sfixed32 = 97 [packed = false];
+  repeated sfixed64 unpacked_sfixed64 = 98 [packed = false];
+  repeated float unpacked_float = 99 [packed = false];
+  repeated double unpacked_double = 100 [packed = false];
+  repeated bool unpacked_bool = 101 [packed = false];
+  repeated NestedEnum unpacked_nested_enum = 102 [packed = false];
+
+  // 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;
+    bool oneof_bool = 115;
+    uint64 oneof_uint64 = 116;
+    float oneof_float = 117;
+    double oneof_double = 118;
+    NestedEnum oneof_enum = 119;
+    google.protobuf.NullValue oneof_null_value = 120;
+  }
+
+  // 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;
+  google.protobuf.NullValue optional_null_value = 307;
+
+  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;
+  repeated google.protobuf.ListValue repeated_list_value = 317;
+
+  // Test field-name-to-JSON-name convention.
+  // (protobuf says names can be any valid C/C++ identifier.)
+  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;
+  int32 __field_name13 = 413;
+  int32 __Field_name14 = 414;
+  int32 field__name15 = 415;
+  int32 field__Name16 = 416;
+  int32 field_name17__ = 417;
+  int32 Field_name18__ = 418;
+
+  // Reserved for testing unknown fields
+  reserved 501 to 510;
+}
+
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 0;
+  FOREIGN_BAR = 1;
+  FOREIGN_BAZ = 2;
+}
+
+message NullHypothesisProto3 {}
+
+message EnumOnlyProto3 {
+  enum Bool {
+    kFalse = 0;
+    kTrue = 1;
+  }
+}
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
new file mode 100644
index 0000000..795cb6a
--- /dev/null
+++ b/src/google/protobuf/test_util.cc
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifdef _WIN32
+// Verify that #including windows.h does not break anything (e.g. because
+// windows.h #defines GetMessage() as a macro).
+#include <windows.h>
+#endif
+
+#include <google/protobuf/test_util.h>
+
+namespace google {
+namespace protobuf {
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
new file mode 100644
index 0000000..b18d7b6
--- /dev/null
+++ b/src/google/protobuf/test_util.h
@@ -0,0 +1,1277 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_TEST_UTIL_H__
+
+#include <google/protobuf/unittest.pb.h>
+
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+// Must be included when the preprocessor symbols above are defined.
+#include <google/protobuf/test_util.inc>
+#undef UNITTEST
+#undef UNITTEST_IMPORT
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+// This file doesn't use these declarations, but some .cc files do.
+namespace unittest = ::protobuf_unittest;
+namespace unittest_import = ::protobuf_unittest_import;
+
+namespace TestUtil {
+
+class ReflectionTester {
+ public:
+  // base_descriptor must be a descriptor for TestAllTypes or
+  // TestAllExtensions.  In the former case, ReflectionTester fetches from
+  // it the FieldDescriptors needed to use the reflection interface.  In
+  // the latter case, ReflectionTester searches for extension fields in
+  // its file.
+  explicit ReflectionTester(const Descriptor* base_descriptor);
+
+  void SetAllFieldsViaReflection(Message* message);
+  void ModifyRepeatedFieldsViaReflection(Message* message);
+  void ExpectAllFieldsSetViaReflection(const Message& message);
+  void ExpectClearViaReflection(const Message& message);
+
+  void SetPackedFieldsViaReflection(Message* message);
+  void ExpectPackedFieldsSetViaReflection(const Message& message);
+
+  void RemoveLastRepeatedsViaReflection(Message* message);
+  void ReleaseLastRepeatedsViaReflection(Message* message,
+                                         bool expect_extensions_notnull);
+  void SwapRepeatedsViaReflection(Message* message);
+  void SetAllocatedOptionalMessageFieldsToNullViaReflection(Message* message);
+  static void SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+      Message* from_message, Message* to_message);
+
+  enum MessageReleaseState {
+    IS_NULL,
+    CAN_BE_NULL,
+    NOT_NULL,
+  };
+  void ExpectMessagesReleasedViaReflection(
+      Message* message, MessageReleaseState expected_release_state);
+
+  // Set and check functions for TestOneof2 messages. No need to construct
+  // the ReflectionTester by TestAllTypes nor TestAllExtensions.
+  static void SetOneofViaReflection(Message* message);
+  static void ExpectOneofSetViaReflection(const Message& message);
+
+ private:
+  const FieldDescriptor* F(const std::string& name);
+
+  const Descriptor* base_descriptor_;
+
+  const FieldDescriptor* group_a_;
+  const FieldDescriptor* repeated_group_a_;
+  const FieldDescriptor* nested_b_;
+  const FieldDescriptor* foreign_c_;
+  const FieldDescriptor* import_d_;
+  const FieldDescriptor* import_e_;
+
+  const EnumValueDescriptor* nested_foo_;
+  const EnumValueDescriptor* nested_bar_;
+  const EnumValueDescriptor* nested_baz_;
+  const EnumValueDescriptor* foreign_foo_;
+  const EnumValueDescriptor* foreign_bar_;
+  const EnumValueDescriptor* foreign_baz_;
+  const EnumValueDescriptor* import_foo_;
+  const EnumValueDescriptor* import_bar_;
+  const EnumValueDescriptor* import_baz_;
+
+  // We have to split this into three function otherwise it creates a stack
+  // frame so large that it triggers a warning.
+  void ExpectAllFieldsSetViaReflection1(const Message& message);
+  void ExpectAllFieldsSetViaReflection2(const Message& message);
+  void ExpectAllFieldsSetViaReflection3(const Message& message);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionTester);
+};
+
+inline TestUtil::ReflectionTester::ReflectionTester(
+    const Descriptor* base_descriptor)
+    : base_descriptor_(base_descriptor) {
+  const DescriptorPool* pool = base_descriptor->file()->pool();
+  std::string package = base_descriptor->file()->package();
+  const FieldDescriptor* import_descriptor =
+      pool->FindFieldByName(package + ".TestAllTypes.optional_import_message");
+  std::string import_package =
+      import_descriptor->message_type()->file()->package();
+
+  nested_b_ = pool->FindFieldByName(package + ".TestAllTypes.NestedMessage.bb");
+  foreign_c_ = pool->FindFieldByName(package + ".ForeignMessage.c");
+  import_d_ = pool->FindFieldByName(import_package + ".ImportMessage.d");
+  import_e_ = pool->FindFieldByName(import_package + ".PublicImportMessage.e");
+  nested_foo_ = pool->FindEnumValueByName(package + ".TestAllTypes.FOO");
+  nested_bar_ = pool->FindEnumValueByName(package + ".TestAllTypes.BAR");
+  nested_baz_ = pool->FindEnumValueByName(package + ".TestAllTypes.BAZ");
+  foreign_foo_ = pool->FindEnumValueByName(package + ".FOREIGN_FOO");
+  foreign_bar_ = pool->FindEnumValueByName(package + ".FOREIGN_BAR");
+  foreign_baz_ = pool->FindEnumValueByName(package + ".FOREIGN_BAZ");
+  import_foo_ = pool->FindEnumValueByName(import_package + ".IMPORT_FOO");
+  import_bar_ = pool->FindEnumValueByName(import_package + ".IMPORT_BAR");
+  import_baz_ = pool->FindEnumValueByName(import_package + ".IMPORT_BAZ");
+
+  if (base_descriptor_->name() == "TestAllExtensions") {
+    group_a_ = pool->FindFieldByName(package + ".OptionalGroup_extension.a");
+    repeated_group_a_ =
+        pool->FindFieldByName(package + ".RepeatedGroup_extension.a");
+  } else {
+    group_a_ = pool->FindFieldByName(package + ".TestAllTypes.OptionalGroup.a");
+    repeated_group_a_ =
+        pool->FindFieldByName(package + ".TestAllTypes.RepeatedGroup.a");
+  }
+
+  EXPECT_TRUE(group_a_ != nullptr);
+  EXPECT_TRUE(repeated_group_a_ != nullptr);
+  EXPECT_TRUE(nested_b_ != nullptr);
+  EXPECT_TRUE(foreign_c_ != nullptr);
+  EXPECT_TRUE(import_d_ != nullptr);
+  EXPECT_TRUE(import_e_ != nullptr);
+  EXPECT_TRUE(nested_foo_ != nullptr);
+  EXPECT_TRUE(nested_bar_ != nullptr);
+  EXPECT_TRUE(nested_baz_ != nullptr);
+  EXPECT_TRUE(foreign_foo_ != nullptr);
+  EXPECT_TRUE(foreign_bar_ != nullptr);
+  EXPECT_TRUE(foreign_baz_ != nullptr);
+  EXPECT_TRUE(import_foo_ != nullptr);
+  EXPECT_TRUE(import_bar_ != nullptr);
+  EXPECT_TRUE(import_baz_ != nullptr);
+}
+
+// Shorthand to get a FieldDescriptor for a field of TestAllTypes.
+inline const FieldDescriptor* TestUtil::ReflectionTester::F(
+    const std::string& name) {
+  const FieldDescriptor* result = nullptr;
+  if (base_descriptor_->name() == "TestAllExtensions" ||
+      base_descriptor_->name() == "TestPackedExtensions") {
+    result = base_descriptor_->file()->FindExtensionByName(name + "_extension");
+  } else {
+    result = base_descriptor_->FindFieldByName(name);
+  }
+  GOOGLE_CHECK(result != nullptr);
+  return result;
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ReflectionTester::SetAllFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message;
+
+  reflection->SetInt32(message, F("optional_int32"), 101);
+  reflection->SetInt64(message, F("optional_int64"), 102);
+  reflection->SetUInt32(message, F("optional_uint32"), 103);
+  reflection->SetUInt64(message, F("optional_uint64"), 104);
+  reflection->SetInt32(message, F("optional_sint32"), 105);
+  reflection->SetInt64(message, F("optional_sint64"), 106);
+  reflection->SetUInt32(message, F("optional_fixed32"), 107);
+  reflection->SetUInt64(message, F("optional_fixed64"), 108);
+  reflection->SetInt32(message, F("optional_sfixed32"), 109);
+  reflection->SetInt64(message, F("optional_sfixed64"), 110);
+  reflection->SetFloat(message, F("optional_float"), 111);
+  reflection->SetDouble(message, F("optional_double"), 112);
+  reflection->SetBool(message, F("optional_bool"), true);
+  reflection->SetString(message, F("optional_string"), "115");
+  reflection->SetString(message, F("optional_bytes"), "116");
+
+  sub_message = reflection->MutableMessage(message, F("optionalgroup"));
+  sub_message->GetReflection()->SetInt32(sub_message, group_a_, 117);
+  sub_message =
+      reflection->MutableMessage(message, F("optional_nested_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 118);
+  sub_message =
+      reflection->MutableMessage(message, F("optional_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 119);
+  sub_message =
+      reflection->MutableMessage(message, F("optional_import_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, import_d_, 120);
+
+  reflection->SetEnum(message, F("optional_nested_enum"), nested_baz_);
+  reflection->SetEnum(message, F("optional_foreign_enum"), foreign_baz_);
+  reflection->SetEnum(message, F("optional_import_enum"), import_baz_);
+
+  reflection->SetString(message, F("optional_string_piece"), "124");
+  reflection->SetString(message, F("optional_cord"), "125");
+
+  sub_message =
+      reflection->MutableMessage(message, F("optional_public_import_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, import_e_, 126);
+
+  sub_message = reflection->MutableMessage(message, F("optional_lazy_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 127);
+
+  sub_message = reflection->MutableMessage(
+      message, F("optional_unverified_lazy_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 128);
+
+  // -----------------------------------------------------------------
+
+  reflection->AddInt32(message, F("repeated_int32"), 201);
+  reflection->AddInt64(message, F("repeated_int64"), 202);
+  reflection->AddUInt32(message, F("repeated_uint32"), 203);
+  reflection->AddUInt64(message, F("repeated_uint64"), 204);
+  reflection->AddInt32(message, F("repeated_sint32"), 205);
+  reflection->AddInt64(message, F("repeated_sint64"), 206);
+  reflection->AddUInt32(message, F("repeated_fixed32"), 207);
+  reflection->AddUInt64(message, F("repeated_fixed64"), 208);
+  reflection->AddInt32(message, F("repeated_sfixed32"), 209);
+  reflection->AddInt64(message, F("repeated_sfixed64"), 210);
+  reflection->AddFloat(message, F("repeated_float"), 211);
+  reflection->AddDouble(message, F("repeated_double"), 212);
+  reflection->AddBool(message, F("repeated_bool"), true);
+  reflection->AddString(message, F("repeated_string"), "215");
+  reflection->AddString(message, F("repeated_bytes"), "216");
+
+  sub_message = reflection->AddMessage(message, F("repeatedgroup"));
+  sub_message->GetReflection()->SetInt32(sub_message, repeated_group_a_, 217);
+  sub_message = reflection->AddMessage(message, F("repeated_nested_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 218);
+  sub_message = reflection->AddMessage(message, F("repeated_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 219);
+  sub_message = reflection->AddMessage(message, F("repeated_import_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, import_d_, 220);
+  sub_message = reflection->AddMessage(message, F("repeated_lazy_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 227);
+
+  reflection->AddEnum(message, F("repeated_nested_enum"), nested_bar_);
+  reflection->AddEnum(message, F("repeated_foreign_enum"), foreign_bar_);
+  reflection->AddEnum(message, F("repeated_import_enum"), import_bar_);
+
+  reflection->AddString(message, F("repeated_string_piece"), "224");
+  reflection->AddString(message, F("repeated_cord"), "225");
+
+  // Add a second one of each field.
+  reflection->AddInt32(message, F("repeated_int32"), 301);
+  reflection->AddInt64(message, F("repeated_int64"), 302);
+  reflection->AddUInt32(message, F("repeated_uint32"), 303);
+  reflection->AddUInt64(message, F("repeated_uint64"), 304);
+  reflection->AddInt32(message, F("repeated_sint32"), 305);
+  reflection->AddInt64(message, F("repeated_sint64"), 306);
+  reflection->AddUInt32(message, F("repeated_fixed32"), 307);
+  reflection->AddUInt64(message, F("repeated_fixed64"), 308);
+  reflection->AddInt32(message, F("repeated_sfixed32"), 309);
+  reflection->AddInt64(message, F("repeated_sfixed64"), 310);
+  reflection->AddFloat(message, F("repeated_float"), 311);
+  reflection->AddDouble(message, F("repeated_double"), 312);
+  reflection->AddBool(message, F("repeated_bool"), false);
+  reflection->AddString(message, F("repeated_string"), "315");
+  reflection->AddString(message, F("repeated_bytes"), "316");
+
+  sub_message = reflection->AddMessage(message, F("repeatedgroup"));
+  sub_message->GetReflection()->SetInt32(sub_message, repeated_group_a_, 317);
+  sub_message = reflection->AddMessage(message, F("repeated_nested_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 318);
+  sub_message = reflection->AddMessage(message, F("repeated_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 319);
+  sub_message = reflection->AddMessage(message, F("repeated_import_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, import_d_, 320);
+  sub_message = reflection->AddMessage(message, F("repeated_lazy_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 327);
+
+  reflection->AddEnum(message, F("repeated_nested_enum"), nested_baz_);
+  reflection->AddEnum(message, F("repeated_foreign_enum"), foreign_baz_);
+  reflection->AddEnum(message, F("repeated_import_enum"), import_baz_);
+
+  reflection->AddString(message, F("repeated_string_piece"), "324");
+  reflection->AddString(message, F("repeated_cord"), "325");
+
+  // -----------------------------------------------------------------
+
+  reflection->SetInt32(message, F("default_int32"), 401);
+  reflection->SetInt64(message, F("default_int64"), 402);
+  reflection->SetUInt32(message, F("default_uint32"), 403);
+  reflection->SetUInt64(message, F("default_uint64"), 404);
+  reflection->SetInt32(message, F("default_sint32"), 405);
+  reflection->SetInt64(message, F("default_sint64"), 406);
+  reflection->SetUInt32(message, F("default_fixed32"), 407);
+  reflection->SetUInt64(message, F("default_fixed64"), 408);
+  reflection->SetInt32(message, F("default_sfixed32"), 409);
+  reflection->SetInt64(message, F("default_sfixed64"), 410);
+  reflection->SetFloat(message, F("default_float"), 411);
+  reflection->SetDouble(message, F("default_double"), 412);
+  reflection->SetBool(message, F("default_bool"), false);
+  reflection->SetString(message, F("default_string"), "415");
+  reflection->SetString(message, F("default_bytes"), "416");
+
+  reflection->SetEnum(message, F("default_nested_enum"), nested_foo_);
+  reflection->SetEnum(message, F("default_foreign_enum"), foreign_foo_);
+  reflection->SetEnum(message, F("default_import_enum"), import_foo_);
+
+  reflection->SetString(message, F("default_string_piece"), "424");
+  reflection->SetString(message, F("default_cord"), "425");
+
+  reflection->SetUInt32(message, F("oneof_uint32"), 601);
+  sub_message = reflection->MutableMessage(message, F("oneof_nested_message"));
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 602);
+  reflection->SetString(message, F("oneof_string"), "603");
+  reflection->SetString(message, F("oneof_bytes"), "604");
+}
+
+inline void TestUtil::ReflectionTester::SetOneofViaReflection(
+    Message* message) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = reflection->MutableMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+  sub_message->GetReflection()->SetInt64(
+      sub_message, sub_message->GetDescriptor()->FindFieldByName("moo_int"),
+      100);
+
+  reflection->SetString(message, descriptor->FindFieldByName("bar_cord"),
+                        "101");
+  reflection->SetInt32(message, descriptor->FindFieldByName("baz_int"), 102);
+  reflection->SetString(message, descriptor->FindFieldByName("baz_string"),
+                        "103");
+}
+
+inline void TestUtil::ReflectionTester::ExpectOneofSetViaReflection(
+    const Message& message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = message.GetReflection();
+  std::string scratch;
+  EXPECT_TRUE(reflection->HasField(
+      message, descriptor->FindFieldByName("foo_lazy_message")));
+  EXPECT_TRUE(
+      reflection->HasField(message, descriptor->FindFieldByName("bar_cord")));
+  EXPECT_TRUE(
+      reflection->HasField(message, descriptor->FindFieldByName("baz_int")));
+  EXPECT_TRUE(
+      reflection->HasField(message, descriptor->FindFieldByName("baz_string")));
+
+  const Message* sub_message = &reflection->GetMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_EQ(100, sub_message->GetReflection()->GetInt64(
+                     *sub_message,
+                     sub_message->GetDescriptor()->FindFieldByName("moo_int")));
+
+  EXPECT_EQ("101", reflection->GetString(
+                       message, descriptor->FindFieldByName("bar_cord")));
+  EXPECT_EQ("101",
+            reflection->GetStringReference(
+                message, descriptor->FindFieldByName("bar_cord"), &scratch));
+
+  EXPECT_EQ(102, reflection->GetInt32(message,
+                                      descriptor->FindFieldByName("baz_int")));
+
+  EXPECT_EQ("103", reflection->GetString(
+                       message, descriptor->FindFieldByName("baz_string")));
+  EXPECT_EQ("103",
+            reflection->GetStringReference(
+                message, descriptor->FindFieldByName("baz_string"), &scratch));
+}
+
+inline void TestUtil::ReflectionTester::SetPackedFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  reflection->AddInt32(message, F("packed_int32"), 601);
+  reflection->AddInt64(message, F("packed_int64"), 602);
+  reflection->AddUInt32(message, F("packed_uint32"), 603);
+  reflection->AddUInt64(message, F("packed_uint64"), 604);
+  reflection->AddInt32(message, F("packed_sint32"), 605);
+  reflection->AddInt64(message, F("packed_sint64"), 606);
+  reflection->AddUInt32(message, F("packed_fixed32"), 607);
+  reflection->AddUInt64(message, F("packed_fixed64"), 608);
+  reflection->AddInt32(message, F("packed_sfixed32"), 609);
+  reflection->AddInt64(message, F("packed_sfixed64"), 610);
+  reflection->AddFloat(message, F("packed_float"), 611);
+  reflection->AddDouble(message, F("packed_double"), 612);
+  reflection->AddBool(message, F("packed_bool"), true);
+  reflection->AddEnum(message, F("packed_enum"), foreign_bar_);
+
+  reflection->AddInt32(message, F("packed_int32"), 701);
+  reflection->AddInt64(message, F("packed_int64"), 702);
+  reflection->AddUInt32(message, F("packed_uint32"), 703);
+  reflection->AddUInt64(message, F("packed_uint64"), 704);
+  reflection->AddInt32(message, F("packed_sint32"), 705);
+  reflection->AddInt64(message, F("packed_sint64"), 706);
+  reflection->AddUInt32(message, F("packed_fixed32"), 707);
+  reflection->AddUInt64(message, F("packed_fixed64"), 708);
+  reflection->AddInt32(message, F("packed_sfixed32"), 709);
+  reflection->AddInt64(message, F("packed_sfixed64"), 710);
+  reflection->AddFloat(message, F("packed_float"), 711);
+  reflection->AddDouble(message, F("packed_double"), 712);
+  reflection->AddBool(message, F("packed_bool"), false);
+  reflection->AddEnum(message, F("packed_enum"), foreign_baz_);
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection(
+    const Message& message) {
+  // We have to split this into three function otherwise it creates a stack
+  // frame so large that it triggers a warning.
+  ExpectAllFieldsSetViaReflection1(message);
+  ExpectAllFieldsSetViaReflection2(message);
+  ExpectAllFieldsSetViaReflection3(message);
+}
+
+inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  std::string scratch;
+  const Message* sub_message;
+
+  EXPECT_TRUE(reflection->HasField(message, F("optional_int32")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_int64")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_uint32")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_uint64")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_sint32")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_sint64")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_fixed32")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_fixed64")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_sfixed32")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_sfixed64")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_float")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_double")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_bool")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_string")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_bytes")));
+
+  EXPECT_TRUE(reflection->HasField(message, F("optionalgroup")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_nested_message")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_message")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_import_message")));
+  EXPECT_TRUE(
+      reflection->HasField(message, F("optional_public_import_message")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_lazy_message")));
+  EXPECT_TRUE(
+      reflection->HasField(message, F("optional_unverified_lazy_message")));
+
+  sub_message = &reflection->GetMessage(message, F("optionalgroup"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, group_a_));
+  sub_message = &reflection->GetMessage(message, F("optional_nested_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+  sub_message = &reflection->GetMessage(message, F("optional_foreign_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, foreign_c_));
+  sub_message = &reflection->GetMessage(message, F("optional_import_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, import_d_));
+  sub_message =
+      &reflection->GetMessage(message, F("optional_public_import_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, import_e_));
+  sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+  sub_message =
+      &reflection->GetMessage(message, F("optional_unverified_lazy_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+
+  EXPECT_TRUE(reflection->HasField(message, F("optional_nested_enum")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_foreign_enum")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_import_enum")));
+
+  EXPECT_TRUE(reflection->HasField(message, F("optional_string_piece")));
+  EXPECT_TRUE(reflection->HasField(message, F("optional_cord")));
+
+  EXPECT_EQ(101, reflection->GetInt32(message, F("optional_int32")));
+  EXPECT_EQ(102, reflection->GetInt64(message, F("optional_int64")));
+  EXPECT_EQ(103, reflection->GetUInt32(message, F("optional_uint32")));
+  EXPECT_EQ(104, reflection->GetUInt64(message, F("optional_uint64")));
+  EXPECT_EQ(105, reflection->GetInt32(message, F("optional_sint32")));
+  EXPECT_EQ(106, reflection->GetInt64(message, F("optional_sint64")));
+  EXPECT_EQ(107, reflection->GetUInt32(message, F("optional_fixed32")));
+  EXPECT_EQ(108, reflection->GetUInt64(message, F("optional_fixed64")));
+  EXPECT_EQ(109, reflection->GetInt32(message, F("optional_sfixed32")));
+  EXPECT_EQ(110, reflection->GetInt64(message, F("optional_sfixed64")));
+  EXPECT_EQ(111, reflection->GetFloat(message, F("optional_float")));
+  EXPECT_EQ(112, reflection->GetDouble(message, F("optional_double")));
+  EXPECT_TRUE(reflection->GetBool(message, F("optional_bool")));
+  EXPECT_EQ("115", reflection->GetString(message, F("optional_string")));
+  EXPECT_EQ("116", reflection->GetString(message, F("optional_bytes")));
+
+  EXPECT_EQ("115", reflection->GetStringReference(message, F("optional_string"),
+                                                  &scratch));
+  EXPECT_EQ("116", reflection->GetStringReference(message, F("optional_bytes"),
+                                                  &scratch));
+
+  sub_message = &reflection->GetMessage(message, F("optionalgroup"));
+  EXPECT_EQ(117,
+            sub_message->GetReflection()->GetInt32(*sub_message, group_a_));
+  sub_message = &reflection->GetMessage(message, F("optional_nested_message"));
+  EXPECT_EQ(118,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  sub_message = &reflection->GetMessage(message, F("optional_foreign_message"));
+  EXPECT_EQ(119,
+            sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
+  sub_message = &reflection->GetMessage(message, F("optional_import_message"));
+  EXPECT_EQ(120,
+            sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+  sub_message =
+      &reflection->GetMessage(message, F("optional_public_import_message"));
+  EXPECT_EQ(126,
+            sub_message->GetReflection()->GetInt32(*sub_message, import_e_));
+  sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+  EXPECT_EQ(127,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  sub_message =
+      &reflection->GetMessage(message, F("optional_unverified_lazy_message"));
+  EXPECT_EQ(128,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+
+  EXPECT_EQ(nested_baz_,
+            reflection->GetEnum(message, F("optional_nested_enum")));
+  EXPECT_EQ(foreign_baz_,
+            reflection->GetEnum(message, F("optional_foreign_enum")));
+  EXPECT_EQ(import_baz_,
+            reflection->GetEnum(message, F("optional_import_enum")));
+
+  EXPECT_EQ("124", reflection->GetString(message, F("optional_string_piece")));
+  EXPECT_EQ("124", reflection->GetStringReference(
+                       message, F("optional_string_piece"), &scratch));
+
+  EXPECT_EQ("125", reflection->GetString(message, F("optional_cord")));
+  EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"),
+                                                  &scratch));
+
+  EXPECT_TRUE(reflection->HasField(message, F("oneof_bytes")));
+  EXPECT_EQ("604", reflection->GetString(message, F("oneof_bytes")));
+
+  if (base_descriptor_->name() == "TestAllTypes") {
+    EXPECT_FALSE(reflection->HasField(message, F("oneof_uint32")));
+    EXPECT_FALSE(reflection->HasField(message, F("oneof_string")));
+  } else {
+    EXPECT_TRUE(reflection->HasField(message, F("oneof_uint32")));
+    EXPECT_TRUE(reflection->HasField(message, F("oneof_string")));
+    EXPECT_EQ(601, reflection->GetUInt32(message, F("oneof_uint32")));
+    EXPECT_EQ("603", reflection->GetString(message, F("oneof_string")));
+    sub_message = &reflection->GetMessage(message, F("oneof_nested_message"));
+    EXPECT_EQ(602,
+              sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  }
+}
+
+inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  std::string scratch;
+  const Message* sub_message;
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_float")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_double")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_string")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_bytes")));
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeatedgroup")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_nested_message")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_foreign_message")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_import_message")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_lazy_message")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_nested_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_foreign_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_import_enum")));
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_string_piece")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("repeated_cord")));
+
+  EXPECT_EQ(201, reflection->GetRepeatedInt32(message, F("repeated_int32"), 0));
+  EXPECT_EQ(202, reflection->GetRepeatedInt64(message, F("repeated_int64"), 0));
+  EXPECT_EQ(203,
+            reflection->GetRepeatedUInt32(message, F("repeated_uint32"), 0));
+  EXPECT_EQ(204,
+            reflection->GetRepeatedUInt64(message, F("repeated_uint64"), 0));
+  EXPECT_EQ(205,
+            reflection->GetRepeatedInt32(message, F("repeated_sint32"), 0));
+  EXPECT_EQ(206,
+            reflection->GetRepeatedInt64(message, F("repeated_sint64"), 0));
+  EXPECT_EQ(207,
+            reflection->GetRepeatedUInt32(message, F("repeated_fixed32"), 0));
+  EXPECT_EQ(208,
+            reflection->GetRepeatedUInt64(message, F("repeated_fixed64"), 0));
+  EXPECT_EQ(209,
+            reflection->GetRepeatedInt32(message, F("repeated_sfixed32"), 0));
+  EXPECT_EQ(210,
+            reflection->GetRepeatedInt64(message, F("repeated_sfixed64"), 0));
+  EXPECT_EQ(211, reflection->GetRepeatedFloat(message, F("repeated_float"), 0));
+  EXPECT_EQ(212,
+            reflection->GetRepeatedDouble(message, F("repeated_double"), 0));
+  EXPECT_TRUE(reflection->GetRepeatedBool(message, F("repeated_bool"), 0));
+  EXPECT_EQ("215",
+            reflection->GetRepeatedString(message, F("repeated_string"), 0));
+  EXPECT_EQ("216",
+            reflection->GetRepeatedString(message, F("repeated_bytes"), 0));
+
+  EXPECT_EQ("215", reflection->GetRepeatedStringReference(
+                       message, F("repeated_string"), 0, &scratch));
+  EXPECT_EQ("216", reflection->GetRepeatedStringReference(
+                       message, F("repeated_bytes"), 0, &scratch));
+
+  sub_message = &reflection->GetRepeatedMessage(message, F("repeatedgroup"), 0);
+  EXPECT_EQ(217, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        repeated_group_a_));
+  sub_message =
+      &reflection->GetRepeatedMessage(message, F("repeated_nested_message"), 0);
+  EXPECT_EQ(218,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  sub_message = &reflection->GetRepeatedMessage(
+      message, F("repeated_foreign_message"), 0);
+  EXPECT_EQ(219,
+            sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
+  sub_message =
+      &reflection->GetRepeatedMessage(message, F("repeated_import_message"), 0);
+  EXPECT_EQ(220,
+            sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+  sub_message =
+      &reflection->GetRepeatedMessage(message, F("repeated_lazy_message"), 0);
+  EXPECT_EQ(227,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+
+  EXPECT_EQ(nested_bar_,
+            reflection->GetRepeatedEnum(message, F("repeated_nested_enum"), 0));
+  EXPECT_EQ(foreign_bar_, reflection->GetRepeatedEnum(
+                              message, F("repeated_foreign_enum"), 0));
+  EXPECT_EQ(import_bar_,
+            reflection->GetRepeatedEnum(message, F("repeated_import_enum"), 0));
+
+  EXPECT_EQ("224", reflection->GetRepeatedString(
+                       message, F("repeated_string_piece"), 0));
+  EXPECT_EQ("224", reflection->GetRepeatedStringReference(
+                       message, F("repeated_string_piece"), 0, &scratch));
+
+  EXPECT_EQ("225",
+            reflection->GetRepeatedString(message, F("repeated_cord"), 0));
+  EXPECT_EQ("225", reflection->GetRepeatedStringReference(
+                       message, F("repeated_cord"), 0, &scratch));
+
+  EXPECT_EQ(301, reflection->GetRepeatedInt32(message, F("repeated_int32"), 1));
+  EXPECT_EQ(302, reflection->GetRepeatedInt64(message, F("repeated_int64"), 1));
+  EXPECT_EQ(303,
+            reflection->GetRepeatedUInt32(message, F("repeated_uint32"), 1));
+  EXPECT_EQ(304,
+            reflection->GetRepeatedUInt64(message, F("repeated_uint64"), 1));
+  EXPECT_EQ(305,
+            reflection->GetRepeatedInt32(message, F("repeated_sint32"), 1));
+  EXPECT_EQ(306,
+            reflection->GetRepeatedInt64(message, F("repeated_sint64"), 1));
+  EXPECT_EQ(307,
+            reflection->GetRepeatedUInt32(message, F("repeated_fixed32"), 1));
+  EXPECT_EQ(308,
+            reflection->GetRepeatedUInt64(message, F("repeated_fixed64"), 1));
+  EXPECT_EQ(309,
+            reflection->GetRepeatedInt32(message, F("repeated_sfixed32"), 1));
+  EXPECT_EQ(310,
+            reflection->GetRepeatedInt64(message, F("repeated_sfixed64"), 1));
+  EXPECT_EQ(311, reflection->GetRepeatedFloat(message, F("repeated_float"), 1));
+  EXPECT_EQ(312,
+            reflection->GetRepeatedDouble(message, F("repeated_double"), 1));
+  EXPECT_FALSE(reflection->GetRepeatedBool(message, F("repeated_bool"), 1));
+  EXPECT_EQ("315",
+            reflection->GetRepeatedString(message, F("repeated_string"), 1));
+  EXPECT_EQ("316",
+            reflection->GetRepeatedString(message, F("repeated_bytes"), 1));
+
+  EXPECT_EQ("315", reflection->GetRepeatedStringReference(
+                       message, F("repeated_string"), 1, &scratch));
+  EXPECT_EQ("316", reflection->GetRepeatedStringReference(
+                       message, F("repeated_bytes"), 1, &scratch));
+
+  sub_message = &reflection->GetRepeatedMessage(message, F("repeatedgroup"), 1);
+  EXPECT_EQ(317, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        repeated_group_a_));
+  sub_message =
+      &reflection->GetRepeatedMessage(message, F("repeated_nested_message"), 1);
+  EXPECT_EQ(318,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  sub_message = &reflection->GetRepeatedMessage(
+      message, F("repeated_foreign_message"), 1);
+  EXPECT_EQ(319,
+            sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
+  sub_message =
+      &reflection->GetRepeatedMessage(message, F("repeated_import_message"), 1);
+  EXPECT_EQ(320,
+            sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+  sub_message =
+      &reflection->GetRepeatedMessage(message, F("repeated_lazy_message"), 1);
+  EXPECT_EQ(327,
+            sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+
+  EXPECT_EQ(nested_baz_,
+            reflection->GetRepeatedEnum(message, F("repeated_nested_enum"), 1));
+  EXPECT_EQ(foreign_baz_, reflection->GetRepeatedEnum(
+                              message, F("repeated_foreign_enum"), 1));
+  EXPECT_EQ(import_baz_,
+            reflection->GetRepeatedEnum(message, F("repeated_import_enum"), 1));
+
+  EXPECT_EQ("324", reflection->GetRepeatedString(
+                       message, F("repeated_string_piece"), 1));
+  EXPECT_EQ("324", reflection->GetRepeatedStringReference(
+                       message, F("repeated_string_piece"), 1, &scratch));
+
+  EXPECT_EQ("325",
+            reflection->GetRepeatedString(message, F("repeated_cord"), 1));
+  EXPECT_EQ("325", reflection->GetRepeatedStringReference(
+                       message, F("repeated_cord"), 1, &scratch));
+}
+
+inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection3(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  std::string scratch;
+
+  // -----------------------------------------------------------------
+
+  EXPECT_TRUE(reflection->HasField(message, F("default_int32")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_int64")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_uint32")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_uint64")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_sint32")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_sint64")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_fixed32")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_fixed64")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_sfixed32")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_sfixed64")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_float")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_double")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_bool")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_string")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_bytes")));
+
+  EXPECT_TRUE(reflection->HasField(message, F("default_nested_enum")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_foreign_enum")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_import_enum")));
+
+  EXPECT_TRUE(reflection->HasField(message, F("default_string_piece")));
+  EXPECT_TRUE(reflection->HasField(message, F("default_cord")));
+
+  EXPECT_EQ(401, reflection->GetInt32(message, F("default_int32")));
+  EXPECT_EQ(402, reflection->GetInt64(message, F("default_int64")));
+  EXPECT_EQ(403, reflection->GetUInt32(message, F("default_uint32")));
+  EXPECT_EQ(404, reflection->GetUInt64(message, F("default_uint64")));
+  EXPECT_EQ(405, reflection->GetInt32(message, F("default_sint32")));
+  EXPECT_EQ(406, reflection->GetInt64(message, F("default_sint64")));
+  EXPECT_EQ(407, reflection->GetUInt32(message, F("default_fixed32")));
+  EXPECT_EQ(408, reflection->GetUInt64(message, F("default_fixed64")));
+  EXPECT_EQ(409, reflection->GetInt32(message, F("default_sfixed32")));
+  EXPECT_EQ(410, reflection->GetInt64(message, F("default_sfixed64")));
+  EXPECT_EQ(411, reflection->GetFloat(message, F("default_float")));
+  EXPECT_EQ(412, reflection->GetDouble(message, F("default_double")));
+  EXPECT_FALSE(reflection->GetBool(message, F("default_bool")));
+  EXPECT_EQ("415", reflection->GetString(message, F("default_string")));
+  EXPECT_EQ("416", reflection->GetString(message, F("default_bytes")));
+
+  EXPECT_EQ("415", reflection->GetStringReference(message, F("default_string"),
+                                                  &scratch));
+  EXPECT_EQ("416", reflection->GetStringReference(message, F("default_bytes"),
+                                                  &scratch));
+
+  EXPECT_EQ(nested_foo_,
+            reflection->GetEnum(message, F("default_nested_enum")));
+  EXPECT_EQ(foreign_foo_,
+            reflection->GetEnum(message, F("default_foreign_enum")));
+  EXPECT_EQ(import_foo_,
+            reflection->GetEnum(message, F("default_import_enum")));
+
+  EXPECT_EQ("424", reflection->GetString(message, F("default_string_piece")));
+  EXPECT_EQ("424", reflection->GetStringReference(
+                       message, F("default_string_piece"), &scratch));
+
+  EXPECT_EQ("425", reflection->GetString(message, F("default_cord")));
+  EXPECT_EQ("425", reflection->GetStringReference(message, F("default_cord"),
+                                                  &scratch));
+}
+
+inline void TestUtil::ReflectionTester::ExpectPackedFieldsSetViaReflection(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_float")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_double")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("packed_enum")));
+
+  EXPECT_EQ(601, reflection->GetRepeatedInt32(message, F("packed_int32"), 0));
+  EXPECT_EQ(602, reflection->GetRepeatedInt64(message, F("packed_int64"), 0));
+  EXPECT_EQ(603, reflection->GetRepeatedUInt32(message, F("packed_uint32"), 0));
+  EXPECT_EQ(604, reflection->GetRepeatedUInt64(message, F("packed_uint64"), 0));
+  EXPECT_EQ(605, reflection->GetRepeatedInt32(message, F("packed_sint32"), 0));
+  EXPECT_EQ(606, reflection->GetRepeatedInt64(message, F("packed_sint64"), 0));
+  EXPECT_EQ(607,
+            reflection->GetRepeatedUInt32(message, F("packed_fixed32"), 0));
+  EXPECT_EQ(608,
+            reflection->GetRepeatedUInt64(message, F("packed_fixed64"), 0));
+  EXPECT_EQ(609,
+            reflection->GetRepeatedInt32(message, F("packed_sfixed32"), 0));
+  EXPECT_EQ(610,
+            reflection->GetRepeatedInt64(message, F("packed_sfixed64"), 0));
+  EXPECT_EQ(611, reflection->GetRepeatedFloat(message, F("packed_float"), 0));
+  EXPECT_EQ(612, reflection->GetRepeatedDouble(message, F("packed_double"), 0));
+  EXPECT_TRUE(reflection->GetRepeatedBool(message, F("packed_bool"), 0));
+  EXPECT_EQ(foreign_bar_,
+            reflection->GetRepeatedEnum(message, F("packed_enum"), 0));
+
+  EXPECT_EQ(701, reflection->GetRepeatedInt32(message, F("packed_int32"), 1));
+  EXPECT_EQ(702, reflection->GetRepeatedInt64(message, F("packed_int64"), 1));
+  EXPECT_EQ(703, reflection->GetRepeatedUInt32(message, F("packed_uint32"), 1));
+  EXPECT_EQ(704, reflection->GetRepeatedUInt64(message, F("packed_uint64"), 1));
+  EXPECT_EQ(705, reflection->GetRepeatedInt32(message, F("packed_sint32"), 1));
+  EXPECT_EQ(706, reflection->GetRepeatedInt64(message, F("packed_sint64"), 1));
+  EXPECT_EQ(707,
+            reflection->GetRepeatedUInt32(message, F("packed_fixed32"), 1));
+  EXPECT_EQ(708,
+            reflection->GetRepeatedUInt64(message, F("packed_fixed64"), 1));
+  EXPECT_EQ(709,
+            reflection->GetRepeatedInt32(message, F("packed_sfixed32"), 1));
+  EXPECT_EQ(710,
+            reflection->GetRepeatedInt64(message, F("packed_sfixed64"), 1));
+  EXPECT_EQ(711, reflection->GetRepeatedFloat(message, F("packed_float"), 1));
+  EXPECT_EQ(712, reflection->GetRepeatedDouble(message, F("packed_double"), 1));
+  EXPECT_FALSE(reflection->GetRepeatedBool(message, F("packed_bool"), 1));
+  EXPECT_EQ(foreign_baz_,
+            reflection->GetRepeatedEnum(message, F("packed_enum"), 1));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ReflectionTester::ExpectClearViaReflection(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  std::string scratch;
+  const Message* sub_message;
+
+  // has_blah() should initially be false for all optional fields.
+  EXPECT_FALSE(reflection->HasField(message, F("optional_int32")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_int64")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_uint32")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_uint64")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_sint32")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_sint64")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_fixed32")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_fixed64")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_sfixed32")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_sfixed64")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_float")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_double")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_bool")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_string")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_bytes")));
+
+  EXPECT_FALSE(reflection->HasField(message, F("optionalgroup")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_nested_message")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_foreign_message")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_import_message")));
+  EXPECT_FALSE(
+      reflection->HasField(message, F("optional_public_import_message")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_lazy_message")));
+  EXPECT_FALSE(
+      reflection->HasField(message, F("optional_unverified_lazy_message")));
+
+  EXPECT_FALSE(reflection->HasField(message, F("optional_nested_enum")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_foreign_enum")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_import_enum")));
+
+  EXPECT_FALSE(reflection->HasField(message, F("optional_string_piece")));
+  EXPECT_FALSE(reflection->HasField(message, F("optional_cord")));
+
+  // Optional fields without defaults are set to zero or something like it.
+  EXPECT_EQ(0, reflection->GetInt32(message, F("optional_int32")));
+  EXPECT_EQ(0, reflection->GetInt64(message, F("optional_int64")));
+  EXPECT_EQ(0, reflection->GetUInt32(message, F("optional_uint32")));
+  EXPECT_EQ(0, reflection->GetUInt64(message, F("optional_uint64")));
+  EXPECT_EQ(0, reflection->GetInt32(message, F("optional_sint32")));
+  EXPECT_EQ(0, reflection->GetInt64(message, F("optional_sint64")));
+  EXPECT_EQ(0, reflection->GetUInt32(message, F("optional_fixed32")));
+  EXPECT_EQ(0, reflection->GetUInt64(message, F("optional_fixed64")));
+  EXPECT_EQ(0, reflection->GetInt32(message, F("optional_sfixed32")));
+  EXPECT_EQ(0, reflection->GetInt64(message, F("optional_sfixed64")));
+  EXPECT_EQ(0, reflection->GetFloat(message, F("optional_float")));
+  EXPECT_EQ(0, reflection->GetDouble(message, F("optional_double")));
+  EXPECT_FALSE(reflection->GetBool(message, F("optional_bool")));
+  EXPECT_EQ("", reflection->GetString(message, F("optional_string")));
+  EXPECT_EQ("", reflection->GetString(message, F("optional_bytes")));
+
+  EXPECT_EQ("", reflection->GetStringReference(message, F("optional_string"),
+                                               &scratch));
+  EXPECT_EQ("", reflection->GetStringReference(message, F("optional_bytes"),
+                                               &scratch));
+
+  // Embedded messages should also be clear.
+  sub_message = &reflection->GetMessage(message, F("optionalgroup"));
+  EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, group_a_));
+  EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, group_a_));
+  sub_message = &reflection->GetMessage(message, F("optional_nested_message"));
+  EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+  EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  sub_message = &reflection->GetMessage(message, F("optional_foreign_message"));
+  EXPECT_FALSE(
+      sub_message->GetReflection()->HasField(*sub_message, foreign_c_));
+  EXPECT_EQ(0,
+            sub_message->GetReflection()->GetInt32(*sub_message, foreign_c_));
+  sub_message = &reflection->GetMessage(message, F("optional_import_message"));
+  EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, import_d_));
+  EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, import_d_));
+  sub_message =
+      &reflection->GetMessage(message, F("optional_public_import_message"));
+  EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, import_e_));
+  EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, import_e_));
+  sub_message = &reflection->GetMessage(message, F("optional_lazy_message"));
+  EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+  EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+  sub_message =
+      &reflection->GetMessage(message, F("optional_unverified_lazy_message"));
+  EXPECT_FALSE(sub_message->GetReflection()->HasField(*sub_message, nested_b_));
+  EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message, nested_b_));
+
+  // Enums without defaults are set to the first value in the enum.
+  EXPECT_EQ(nested_foo_,
+            reflection->GetEnum(message, F("optional_nested_enum")));
+  EXPECT_EQ(foreign_foo_,
+            reflection->GetEnum(message, F("optional_foreign_enum")));
+  EXPECT_EQ(import_foo_,
+            reflection->GetEnum(message, F("optional_import_enum")));
+
+  EXPECT_EQ("", reflection->GetString(message, F("optional_string_piece")));
+  EXPECT_EQ("", reflection->GetStringReference(
+                    message, F("optional_string_piece"), &scratch));
+
+  EXPECT_EQ("", reflection->GetString(message, F("optional_cord")));
+  EXPECT_EQ("", reflection->GetStringReference(message, F("optional_cord"),
+                                               &scratch));
+
+  // Repeated fields are empty.
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_uint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_uint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_sint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_sint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_fixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_fixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_sfixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_sfixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_float")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_double")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_bool")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_string")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_bytes")));
+
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeatedgroup")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_nested_message")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_foreign_message")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_import_message")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_lazy_message")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_nested_enum")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_foreign_enum")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_import_enum")));
+
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_string_piece")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_cord")));
+
+  // has_blah() should also be false for all default fields.
+  EXPECT_FALSE(reflection->HasField(message, F("default_int32")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_int64")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_uint32")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_uint64")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_sint32")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_sint64")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_fixed32")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_fixed64")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_sfixed32")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_sfixed64")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_float")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_double")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_bool")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_string")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_bytes")));
+
+  EXPECT_FALSE(reflection->HasField(message, F("default_nested_enum")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_foreign_enum")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_import_enum")));
+
+  EXPECT_FALSE(reflection->HasField(message, F("default_string_piece")));
+  EXPECT_FALSE(reflection->HasField(message, F("default_cord")));
+
+  // Fields with defaults have their default values (duh).
+  EXPECT_EQ(41, reflection->GetInt32(message, F("default_int32")));
+  EXPECT_EQ(42, reflection->GetInt64(message, F("default_int64")));
+  EXPECT_EQ(43, reflection->GetUInt32(message, F("default_uint32")));
+  EXPECT_EQ(44, reflection->GetUInt64(message, F("default_uint64")));
+  EXPECT_EQ(-45, reflection->GetInt32(message, F("default_sint32")));
+  EXPECT_EQ(46, reflection->GetInt64(message, F("default_sint64")));
+  EXPECT_EQ(47, reflection->GetUInt32(message, F("default_fixed32")));
+  EXPECT_EQ(48, reflection->GetUInt64(message, F("default_fixed64")));
+  EXPECT_EQ(49, reflection->GetInt32(message, F("default_sfixed32")));
+  EXPECT_EQ(-50, reflection->GetInt64(message, F("default_sfixed64")));
+  EXPECT_EQ(51.5, reflection->GetFloat(message, F("default_float")));
+  EXPECT_EQ(52e3, reflection->GetDouble(message, F("default_double")));
+  EXPECT_TRUE(reflection->GetBool(message, F("default_bool")));
+  EXPECT_EQ("hello", reflection->GetString(message, F("default_string")));
+  EXPECT_EQ("world", reflection->GetString(message, F("default_bytes")));
+
+  EXPECT_EQ("hello", reflection->GetStringReference(
+                         message, F("default_string"), &scratch));
+  EXPECT_EQ("world", reflection->GetStringReference(message, F("default_bytes"),
+                                                    &scratch));
+
+  EXPECT_EQ(nested_bar_,
+            reflection->GetEnum(message, F("default_nested_enum")));
+  EXPECT_EQ(foreign_bar_,
+            reflection->GetEnum(message, F("default_foreign_enum")));
+  EXPECT_EQ(import_bar_,
+            reflection->GetEnum(message, F("default_import_enum")));
+
+  EXPECT_EQ("abc", reflection->GetString(message, F("default_string_piece")));
+  EXPECT_EQ("abc", reflection->GetStringReference(
+                       message, F("default_string_piece"), &scratch));
+
+  EXPECT_EQ("123", reflection->GetString(message, F("default_cord")));
+  EXPECT_EQ("123", reflection->GetStringReference(message, F("default_cord"),
+                                                  &scratch));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message;
+
+  reflection->SetRepeatedInt32(message, F("repeated_int32"), 1, 501);
+  reflection->SetRepeatedInt64(message, F("repeated_int64"), 1, 502);
+  reflection->SetRepeatedUInt32(message, F("repeated_uint32"), 1, 503);
+  reflection->SetRepeatedUInt64(message, F("repeated_uint64"), 1, 504);
+  reflection->SetRepeatedInt32(message, F("repeated_sint32"), 1, 505);
+  reflection->SetRepeatedInt64(message, F("repeated_sint64"), 1, 506);
+  reflection->SetRepeatedUInt32(message, F("repeated_fixed32"), 1, 507);
+  reflection->SetRepeatedUInt64(message, F("repeated_fixed64"), 1, 508);
+  reflection->SetRepeatedInt32(message, F("repeated_sfixed32"), 1, 509);
+  reflection->SetRepeatedInt64(message, F("repeated_sfixed64"), 1, 510);
+  reflection->SetRepeatedFloat(message, F("repeated_float"), 1, 511);
+  reflection->SetRepeatedDouble(message, F("repeated_double"), 1, 512);
+  reflection->SetRepeatedBool(message, F("repeated_bool"), 1, true);
+  reflection->SetRepeatedString(message, F("repeated_string"), 1, "515");
+  reflection->SetRepeatedString(message, F("repeated_bytes"), 1, "516");
+
+  sub_message =
+      reflection->MutableRepeatedMessage(message, F("repeatedgroup"), 1);
+  sub_message->GetReflection()->SetInt32(sub_message, repeated_group_a_, 517);
+  sub_message = reflection->MutableRepeatedMessage(
+      message, F("repeated_nested_message"), 1);
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 518);
+  sub_message = reflection->MutableRepeatedMessage(
+      message, F("repeated_foreign_message"), 1);
+  sub_message->GetReflection()->SetInt32(sub_message, foreign_c_, 519);
+  sub_message = reflection->MutableRepeatedMessage(
+      message, F("repeated_import_message"), 1);
+  sub_message->GetReflection()->SetInt32(sub_message, import_d_, 520);
+  sub_message = reflection->MutableRepeatedMessage(
+      message, F("repeated_lazy_message"), 1);
+  sub_message->GetReflection()->SetInt32(sub_message, nested_b_, 527);
+
+  reflection->SetRepeatedEnum(message, F("repeated_nested_enum"), 1,
+                              nested_foo_);
+  reflection->SetRepeatedEnum(message, F("repeated_foreign_enum"), 1,
+                              foreign_foo_);
+  reflection->SetRepeatedEnum(message, F("repeated_import_enum"), 1,
+                              import_foo_);
+
+  reflection->SetRepeatedString(message, F("repeated_string_piece"), 1, "524");
+  reflection->SetRepeatedString(message, F("repeated_cord"), 1, "525");
+}
+
+inline void TestUtil::ReflectionTester::RemoveLastRepeatedsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+
+    reflection->RemoveLast(message, field);
+  }
+}
+
+inline void TestUtil::ReflectionTester::ReleaseLastRepeatedsViaReflection(
+    Message* message, bool expect_extensions_notnull) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    Message* released = reflection->ReleaseLast(message, field);
+    if (!field->is_extension() || expect_extensions_notnull) {
+      ASSERT_TRUE(released != nullptr)
+          << "ReleaseLast returned nullptr for: " << field->name();
+    }
+    delete released;
+  }
+}
+
+inline void TestUtil::ReflectionTester::SwapRepeatedsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+
+    reflection->SwapElements(message, field, 0, 1);
+  }
+}
+
+inline void TestUtil::ReflectionTester::
+    SetAllocatedOptionalMessageFieldsToNullViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*message, &fields);
+
+  for (int i = 0; i < fields.size(); ++i) {
+    const FieldDescriptor* field = fields[i];
+    if (!field->is_optional() ||
+        field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
+      continue;
+
+    reflection->SetAllocatedMessage(message, nullptr, field);
+  }
+}
+
+inline void TestUtil::ReflectionTester::
+    SetAllocatedOptionalMessageFieldsToMessageViaReflection(
+        Message* from_message, Message* to_message) {
+  EXPECT_EQ(from_message->GetDescriptor(), to_message->GetDescriptor());
+  const Reflection* from_reflection = from_message->GetReflection();
+  const Reflection* to_reflection = to_message->GetReflection();
+
+  std::vector<const FieldDescriptor*> fields;
+  from_reflection->ListFields(*from_message, &fields);
+
+  for (int i = 0; i < fields.size(); ++i) {
+    const FieldDescriptor* field = fields[i];
+    if (!field->is_optional() ||
+        field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)
+      continue;
+
+    Message* sub_message = from_reflection->ReleaseMessage(from_message, field);
+    to_reflection->SetAllocatedMessage(to_message, sub_message, field);
+  }
+}
+
+inline void TestUtil::ReflectionTester::ExpectMessagesReleasedViaReflection(
+    Message* message,
+    TestUtil::ReflectionTester::MessageReleaseState expected_release_state) {
+  const Reflection* reflection = message->GetReflection();
+
+  static const char* fields[] = {
+      "optionalgroup",
+      "optional_nested_message",
+      "optional_foreign_message",
+      "optional_import_message",
+  };
+  for (int i = 0; i < GOOGLE_ARRAYSIZE(fields); i++) {
+    Message* released = reflection->ReleaseMessage(message, F(fields[i]));
+    switch (expected_release_state) {
+      case IS_NULL:
+        EXPECT_TRUE(released == nullptr);
+        break;
+      case NOT_NULL:
+        EXPECT_TRUE(released != nullptr);
+        break;
+      case CAN_BE_NULL:
+        break;
+    }
+    delete released;
+    EXPECT_FALSE(reflection->HasField(*message, F(fields[i])));
+  }
+}
+
+// Check that the passed-in serialization is the canonical serialization we
+// expect for a TestFieldOrderings message filled in by
+// SetAllFieldsAndExtensions().
+inline void ExpectAllFieldsAndExtensionsInOrder(const std::string& serialized) {
+  // We set each field individually, serialize separately, and concatenate all
+  // the strings in canonical order to determine the expected serialization.
+  std::string expected;
+  unittest::TestFieldOrderings message;
+  message.set_my_int(1);  // Field 1.
+  message.AppendToString(&expected);
+  message.Clear();
+  message.SetExtension(unittest::my_extension_int, 23);  // Field 5.
+  message.AppendToString(&expected);
+  message.Clear();
+  message.set_my_string("foo");  // Field 11.
+  message.AppendToString(&expected);
+  message.Clear();
+  message.SetExtension(unittest::my_extension_string, "bar");  // Field 50.
+  message.AppendToString(&expected);
+  message.Clear();
+  message.set_my_float(1.0);  // Field 101.
+  message.AppendToString(&expected);
+  message.Clear();
+
+  // We don't EXPECT_EQ() since we don't want to print raw bytes to stdout.
+  EXPECT_TRUE(serialized == expected);
+}
+
+}  // namespace TestUtil
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_TEST_UTIL_H__
diff --git a/src/google/protobuf/test_util.inc b/src/google/protobuf/test_util.inc
new file mode 100644
index 0000000..8d44afa
--- /dev/null
+++ b/src/google/protobuf/test_util.inc
@@ -0,0 +1,2434 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 needs to be included as .inc as it depends on the namespaces
+// (unittest and unittest_import) being set up properly. It is also included
+// within an enclosing namespace and requires header files to be included
+// out of this file.
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+namespace TestUtil {
+
+// Set every field in the message to a unique value.
+inline void SetAllFields(UNITTEST::TestAllTypes* message);
+inline void SetOptionalFields(UNITTEST::TestAllTypes* message);
+inline void AddRepeatedFields1(UNITTEST::TestAllTypes* message);
+inline void AddRepeatedFields2(UNITTEST::TestAllTypes* message);
+inline void SetDefaultFields(UNITTEST::TestAllTypes* message);
+inline void SetOneofFields(UNITTEST::TestAllTypes* message);
+inline void SetAllExtensions(UNITTEST::TestAllExtensions* message);
+inline void SetOneofFields(UNITTEST::TestAllExtensions* message);
+inline void SetAllFieldsAndExtensions(UNITTEST::TestFieldOrderings* message);
+inline void SetPackedFields(UNITTEST::TestPackedTypes* message);
+inline void SetPackedExtensions(UNITTEST::TestPackedExtensions* message);
+inline void SetUnpackedFields(UNITTEST::TestUnpackedTypes* message);
+inline void SetOneof1(UNITTEST::TestOneof2* message);
+inline void SetOneof2(UNITTEST::TestOneof2* message);
+
+// Use the repeated versions of the set_*() accessors to modify all the
+// repeated fields of the message (which should already have been
+// initialized with Set*Fields()).  Set*Fields() itself only tests
+// the add_*() accessors.
+inline void ModifyRepeatedFields(UNITTEST::TestAllTypes* message);
+inline void ModifyRepeatedExtensions(UNITTEST::TestAllExtensions* message);
+
+// Check that all fields have the values that they should have after
+// Set*Fields() is called.
+inline void ExpectAllFieldsSet(const UNITTEST::TestAllTypes& message);
+inline void ExpectAllExtensionsSet(const UNITTEST::TestAllExtensions& message);
+inline void ExpectPackedFieldsSet(const UNITTEST::TestPackedTypes& message);
+inline void ExpectPackedExtensionsSet(
+    const UNITTEST::TestPackedExtensions& message);
+inline void ExpectUnpackedFieldsSet(const UNITTEST::TestUnpackedTypes& message);
+inline void ExpectUnpackedExtensionsSet(
+    const UNITTEST::TestUnpackedExtensions& message);
+inline void ExpectOneofSet1(const UNITTEST::TestOneof2& message);
+inline void ExpectOneofSet2(const UNITTEST::TestOneof2& message);
+
+// Expect that the message is modified as would be expected from
+// Modify*Fields().
+inline void ExpectRepeatedFieldsModified(const UNITTEST::TestAllTypes& message);
+inline void ExpectRepeatedExtensionsModified(
+    const UNITTEST::TestAllExtensions& message);
+
+// Check that all fields have their default values.
+inline void ExpectClear(const UNITTEST::TestAllTypes& message);
+inline void ExpectExtensionsClear(const UNITTEST::TestAllExtensions& message);
+inline void ExpectOneofClear(const UNITTEST::TestOneof2& message);
+
+// Check that all repeated fields have had their last elements removed.
+inline void ExpectLastRepeatedsRemoved(const UNITTEST::TestAllTypes& message);
+inline void ExpectLastRepeatedExtensionsRemoved(
+    const UNITTEST::TestAllExtensions& message);
+inline void ExpectLastRepeatedsReleased(const UNITTEST::TestAllTypes& message);
+inline void ExpectLastRepeatedExtensionsReleased(
+    const UNITTEST::TestAllExtensions& message);
+
+// Check that all repeated fields have had their first and last elements
+// swapped.
+inline void ExpectRepeatedsSwapped(const UNITTEST::TestAllTypes& message);
+inline void ExpectRepeatedExtensionsSwapped(
+    const UNITTEST::TestAllExtensions& message);
+
+inline void ExpectAtMostOneFieldSetInOneof(const UNITTEST::TestOneof2& message);
+
+}  // namespace TestUtil
+
+inline void TestUtil::SetAllFields(UNITTEST::TestAllTypes* message) {
+  SetOptionalFields(message);
+  AddRepeatedFields1(message);
+  AddRepeatedFields2(message);
+  SetDefaultFields(message);
+  SetOneofFields(message);
+}
+
+inline void TestUtil::SetOptionalFields(UNITTEST::TestAllTypes* message) {
+  message->set_optional_int32(101);
+  message->set_optional_int64(102);
+  message->set_optional_uint32(103);
+  message->set_optional_uint64(104);
+  message->set_optional_sint32(105);
+  message->set_optional_sint64(106);
+  message->set_optional_fixed32(107);
+  message->set_optional_fixed64(108);
+  message->set_optional_sfixed32(109);
+  message->set_optional_sfixed64(110);
+  message->set_optional_float(111);
+  message->set_optional_double(112);
+  message->set_optional_bool(true);
+  message->set_optional_string("115");
+  message->set_optional_bytes("116");
+
+  message->mutable_optionalgroup()->set_a(117);
+  message->mutable_optional_nested_message()->set_bb(118);
+  message->mutable_optional_foreign_message()->set_c(119);
+  message->mutable_optional_import_message()->set_d(120);
+  message->mutable_optional_public_import_message()->set_e(126);
+  message->mutable_optional_lazy_message()->set_bb(127);
+  message->mutable_optional_unverified_lazy_message()->set_bb(128);
+
+  message->set_optional_nested_enum(UNITTEST::TestAllTypes::BAZ);
+  message->set_optional_foreign_enum(UNITTEST::FOREIGN_BAZ);
+  message->set_optional_import_enum(UNITTEST_IMPORT::IMPORT_BAZ);
+
+  // StringPiece and Cord fields are only accessible via reflection in the
+  // open source release; see comments in compiler/cpp/string_field.cc.
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  message->GetReflection()->SetString(
+      message,
+      message->GetDescriptor()->FindFieldByName("optional_string_piece"),
+      "124");
+  message->GetReflection()->SetString(
+      message, message->GetDescriptor()->FindFieldByName("optional_cord"),
+      "125");
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::AddRepeatedFields1(UNITTEST::TestAllTypes* message) {
+  message->add_repeated_int32(201);
+  message->add_repeated_int64(202);
+  message->add_repeated_uint32(203);
+  message->add_repeated_uint64(204);
+  message->add_repeated_sint32(205);
+  message->add_repeated_sint64(206);
+  message->add_repeated_fixed32(207);
+  message->add_repeated_fixed64(208);
+  message->add_repeated_sfixed32(209);
+  message->add_repeated_sfixed64(210);
+  message->add_repeated_float(211);
+  message->add_repeated_double(212);
+  message->add_repeated_bool(true);
+  message->add_repeated_string("215");
+  message->add_repeated_bytes("216");
+
+  message->add_repeatedgroup()->set_a(217);
+  message->add_repeated_nested_message()->set_bb(218);
+  message->add_repeated_foreign_message()->set_c(219);
+  message->add_repeated_import_message()->set_d(220);
+  message->add_repeated_lazy_message()->set_bb(227);
+
+  message->add_repeated_nested_enum(UNITTEST::TestAllTypes::BAR);
+  message->add_repeated_foreign_enum(UNITTEST::FOREIGN_BAR);
+  message->add_repeated_import_enum(UNITTEST_IMPORT::IMPORT_BAR);
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  message->GetReflection()->AddString(
+      message,
+      message->GetDescriptor()->FindFieldByName("repeated_string_piece"),
+      "224");
+  message->GetReflection()->AddString(
+      message, message->GetDescriptor()->FindFieldByName("repeated_cord"),
+      "225");
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+
+inline void TestUtil::AddRepeatedFields2(UNITTEST::TestAllTypes* message) {
+  // Add a second one of each field.
+  message->add_repeated_int32(301);
+  message->add_repeated_int64(302);
+  message->add_repeated_uint32(303);
+  message->add_repeated_uint64(304);
+  message->add_repeated_sint32(305);
+  message->add_repeated_sint64(306);
+  message->add_repeated_fixed32(307);
+  message->add_repeated_fixed64(308);
+  message->add_repeated_sfixed32(309);
+  message->add_repeated_sfixed64(310);
+  message->add_repeated_float(311);
+  message->add_repeated_double(312);
+  message->add_repeated_bool(false);
+  message->add_repeated_string("315");
+  message->add_repeated_bytes("316");
+
+  message->add_repeatedgroup()->set_a(317);
+  message->add_repeated_nested_message()->set_bb(318);
+  message->add_repeated_foreign_message()->set_c(319);
+  message->add_repeated_import_message()->set_d(320);
+  message->add_repeated_lazy_message()->set_bb(327);
+
+  message->add_repeated_nested_enum(UNITTEST::TestAllTypes::BAZ);
+  message->add_repeated_foreign_enum(UNITTEST::FOREIGN_BAZ);
+  message->add_repeated_import_enum(UNITTEST_IMPORT::IMPORT_BAZ);
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  message->GetReflection()->AddString(
+      message,
+      message->GetDescriptor()->FindFieldByName("repeated_string_piece"),
+      "324");
+  message->GetReflection()->AddString(
+      message, message->GetDescriptor()->FindFieldByName("repeated_cord"),
+      "325");
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::SetDefaultFields(UNITTEST::TestAllTypes* message) {
+  message->set_default_int32(401);
+  message->set_default_int64(402);
+  message->set_default_uint32(403);
+  message->set_default_uint64(404);
+  message->set_default_sint32(405);
+  message->set_default_sint64(406);
+  message->set_default_fixed32(407);
+  message->set_default_fixed64(408);
+  message->set_default_sfixed32(409);
+  message->set_default_sfixed64(410);
+  message->set_default_float(411);
+  message->set_default_double(412);
+  message->set_default_bool(false);
+  message->set_default_string("415");
+  message->set_default_bytes("416");
+
+  message->set_default_nested_enum(UNITTEST::TestAllTypes::FOO);
+  message->set_default_foreign_enum(UNITTEST::FOREIGN_FOO);
+  message->set_default_import_enum(UNITTEST_IMPORT::IMPORT_FOO);
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  message->GetReflection()->SetString(
+      message,
+      message->GetDescriptor()->FindFieldByName("default_string_piece"), "424");
+  message->GetReflection()->SetString(
+      message, message->GetDescriptor()->FindFieldByName("default_cord"),
+      "425");
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ModifyRepeatedFields(UNITTEST::TestAllTypes* message) {
+  message->set_repeated_int32(1, 501);
+  message->set_repeated_int64(1, 502);
+  message->set_repeated_uint32(1, 503);
+  message->set_repeated_uint64(1, 504);
+  message->set_repeated_sint32(1, 505);
+  message->set_repeated_sint64(1, 506);
+  message->set_repeated_fixed32(1, 507);
+  message->set_repeated_fixed64(1, 508);
+  message->set_repeated_sfixed32(1, 509);
+  message->set_repeated_sfixed64(1, 510);
+  message->set_repeated_float(1, 511);
+  message->set_repeated_double(1, 512);
+  message->set_repeated_bool(1, true);
+  message->set_repeated_string(1, "515");
+  message->set_repeated_bytes(1, "516");
+
+  message->mutable_repeatedgroup(1)->set_a(517);
+  message->mutable_repeated_nested_message(1)->set_bb(518);
+  message->mutable_repeated_foreign_message(1)->set_c(519);
+  message->mutable_repeated_import_message(1)->set_d(520);
+  message->mutable_repeated_lazy_message(1)->set_bb(527);
+
+  message->set_repeated_nested_enum(1, UNITTEST::TestAllTypes::FOO);
+  message->set_repeated_foreign_enum(1, UNITTEST::FOREIGN_FOO);
+  message->set_repeated_import_enum(1, UNITTEST_IMPORT::IMPORT_FOO);
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  message->GetReflection()->SetRepeatedString(
+      message,
+      message->GetDescriptor()->FindFieldByName("repeated_string_piece"), 1,
+      "524");
+  message->GetReflection()->SetRepeatedString(
+      message, message->GetDescriptor()->FindFieldByName("repeated_cord"), 1,
+      "525");
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+}
+
+// ------------------------------------------------------------------
+inline void TestUtil::SetOneofFields(UNITTEST::TestAllTypes* message) {
+  message->set_oneof_uint32(601);
+  message->mutable_oneof_nested_message()->set_bb(602);
+  message->set_oneof_string("603");
+  message->set_oneof_bytes("604");
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectAllFieldsSet(
+    const UNITTEST::TestAllTypes& message) {
+  EXPECT_TRUE(message.has_optional_int32());
+  EXPECT_TRUE(message.has_optional_int64());
+  EXPECT_TRUE(message.has_optional_uint32());
+  EXPECT_TRUE(message.has_optional_uint64());
+  EXPECT_TRUE(message.has_optional_sint32());
+  EXPECT_TRUE(message.has_optional_sint64());
+  EXPECT_TRUE(message.has_optional_fixed32());
+  EXPECT_TRUE(message.has_optional_fixed64());
+  EXPECT_TRUE(message.has_optional_sfixed32());
+  EXPECT_TRUE(message.has_optional_sfixed64());
+  EXPECT_TRUE(message.has_optional_float());
+  EXPECT_TRUE(message.has_optional_double());
+  EXPECT_TRUE(message.has_optional_bool());
+  EXPECT_TRUE(message.has_optional_string());
+  EXPECT_TRUE(message.has_optional_bytes());
+
+  EXPECT_TRUE(message.has_optionalgroup());
+  EXPECT_TRUE(message.has_optional_nested_message());
+  EXPECT_TRUE(message.has_optional_foreign_message());
+  EXPECT_TRUE(message.has_optional_import_message());
+  EXPECT_TRUE(message.has_optional_public_import_message());
+  EXPECT_TRUE(message.has_optional_lazy_message());
+  EXPECT_TRUE(message.has_optional_unverified_lazy_message());
+
+  EXPECT_TRUE(message.optionalgroup().has_a());
+  EXPECT_TRUE(message.optional_nested_message().has_bb());
+  EXPECT_TRUE(message.optional_foreign_message().has_c());
+  EXPECT_TRUE(message.optional_import_message().has_d());
+  EXPECT_TRUE(message.optional_public_import_message().has_e());
+  EXPECT_TRUE(message.optional_lazy_message().has_bb());
+  EXPECT_TRUE(message.optional_unverified_lazy_message().has_bb());
+
+  EXPECT_TRUE(message.has_optional_nested_enum());
+  EXPECT_TRUE(message.has_optional_foreign_enum());
+  EXPECT_TRUE(message.has_optional_import_enum());
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  EXPECT_TRUE(message.has_optional_string_piece());
+  EXPECT_TRUE(message.has_optional_cord());
+#endif
+
+  EXPECT_EQ(101, message.optional_int32());
+  EXPECT_EQ(102, message.optional_int64());
+  EXPECT_EQ(103, message.optional_uint32());
+  EXPECT_EQ(104, message.optional_uint64());
+  EXPECT_EQ(105, message.optional_sint32());
+  EXPECT_EQ(106, message.optional_sint64());
+  EXPECT_EQ(107, message.optional_fixed32());
+  EXPECT_EQ(108, message.optional_fixed64());
+  EXPECT_EQ(109, message.optional_sfixed32());
+  EXPECT_EQ(110, message.optional_sfixed64());
+  EXPECT_EQ(111, message.optional_float());
+  EXPECT_EQ(112, message.optional_double());
+  EXPECT_TRUE(message.optional_bool());
+  EXPECT_EQ("115", message.optional_string());
+  EXPECT_EQ("116", message.optional_bytes());
+
+  EXPECT_EQ(117, message.optionalgroup().a());
+  EXPECT_EQ(118, message.optional_nested_message().bb());
+  EXPECT_EQ(119, message.optional_foreign_message().c());
+  EXPECT_EQ(120, message.optional_import_message().d());
+  EXPECT_EQ(126, message.optional_public_import_message().e());
+  EXPECT_EQ(127, message.optional_lazy_message().bb());
+  EXPECT_EQ(128, message.optional_unverified_lazy_message().bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, message.optional_nested_enum());
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.optional_foreign_enum());
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.optional_import_enum());
+
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, message.repeated_int32_size());
+  ASSERT_EQ(2, message.repeated_int64_size());
+  ASSERT_EQ(2, message.repeated_uint32_size());
+  ASSERT_EQ(2, message.repeated_uint64_size());
+  ASSERT_EQ(2, message.repeated_sint32_size());
+  ASSERT_EQ(2, message.repeated_sint64_size());
+  ASSERT_EQ(2, message.repeated_fixed32_size());
+  ASSERT_EQ(2, message.repeated_fixed64_size());
+  ASSERT_EQ(2, message.repeated_sfixed32_size());
+  ASSERT_EQ(2, message.repeated_sfixed64_size());
+  ASSERT_EQ(2, message.repeated_float_size());
+  ASSERT_EQ(2, message.repeated_double_size());
+  ASSERT_EQ(2, message.repeated_bool_size());
+  ASSERT_EQ(2, message.repeated_string_size());
+  ASSERT_EQ(2, message.repeated_bytes_size());
+
+  ASSERT_EQ(2, message.repeatedgroup_size());
+  ASSERT_EQ(2, message.repeated_nested_message_size());
+  ASSERT_EQ(2, message.repeated_foreign_message_size());
+  ASSERT_EQ(2, message.repeated_import_message_size());
+  ASSERT_EQ(2, message.repeated_lazy_message_size());
+  ASSERT_EQ(2, message.repeated_nested_enum_size());
+  ASSERT_EQ(2, message.repeated_foreign_enum_size());
+  ASSERT_EQ(2, message.repeated_import_enum_size());
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  ASSERT_EQ(2, message.repeated_string_piece_size());
+  ASSERT_EQ(2, message.repeated_cord_size());
+#endif
+
+  EXPECT_EQ(201, message.repeated_int32(0));
+  EXPECT_EQ(202, message.repeated_int64(0));
+  EXPECT_EQ(203, message.repeated_uint32(0));
+  EXPECT_EQ(204, message.repeated_uint64(0));
+  EXPECT_EQ(205, message.repeated_sint32(0));
+  EXPECT_EQ(206, message.repeated_sint64(0));
+  EXPECT_EQ(207, message.repeated_fixed32(0));
+  EXPECT_EQ(208, message.repeated_fixed64(0));
+  EXPECT_EQ(209, message.repeated_sfixed32(0));
+  EXPECT_EQ(210, message.repeated_sfixed64(0));
+  EXPECT_EQ(211, message.repeated_float(0));
+  EXPECT_EQ(212, message.repeated_double(0));
+  EXPECT_TRUE(message.repeated_bool(0));
+  EXPECT_EQ("215", message.repeated_string(0));
+  EXPECT_EQ("216", message.repeated_bytes(0));
+
+  EXPECT_EQ(217, message.repeatedgroup(0).a());
+  EXPECT_EQ(218, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+  EXPECT_EQ(227, message.repeated_lazy_message(0).bb());
+
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message.repeated_nested_enum(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeated_foreign_enum(0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR, message.repeated_import_enum(0));
+
+  EXPECT_EQ(301, message.repeated_int32(1));
+  EXPECT_EQ(302, message.repeated_int64(1));
+  EXPECT_EQ(303, message.repeated_uint32(1));
+  EXPECT_EQ(304, message.repeated_uint64(1));
+  EXPECT_EQ(305, message.repeated_sint32(1));
+  EXPECT_EQ(306, message.repeated_sint64(1));
+  EXPECT_EQ(307, message.repeated_fixed32(1));
+  EXPECT_EQ(308, message.repeated_fixed64(1));
+  EXPECT_EQ(309, message.repeated_sfixed32(1));
+  EXPECT_EQ(310, message.repeated_sfixed64(1));
+  EXPECT_EQ(311, message.repeated_float(1));
+  EXPECT_EQ(312, message.repeated_double(1));
+  EXPECT_FALSE(message.repeated_bool(1));
+  EXPECT_EQ("315", message.repeated_string(1));
+  EXPECT_EQ("316", message.repeated_bytes(1));
+
+  EXPECT_EQ(317, message.repeatedgroup(1).a());
+  EXPECT_EQ(318, message.repeated_nested_message(1).bb());
+  EXPECT_EQ(319, message.repeated_foreign_message(1).c());
+  EXPECT_EQ(320, message.repeated_import_message(1).d());
+  EXPECT_EQ(327, message.repeated_lazy_message(1).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, message.repeated_nested_enum(1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.repeated_foreign_enum(1));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.repeated_import_enum(1));
+
+
+  // -----------------------------------------------------------------
+
+  EXPECT_TRUE(message.has_default_int32());
+  EXPECT_TRUE(message.has_default_int64());
+  EXPECT_TRUE(message.has_default_uint32());
+  EXPECT_TRUE(message.has_default_uint64());
+  EXPECT_TRUE(message.has_default_sint32());
+  EXPECT_TRUE(message.has_default_sint64());
+  EXPECT_TRUE(message.has_default_fixed32());
+  EXPECT_TRUE(message.has_default_fixed64());
+  EXPECT_TRUE(message.has_default_sfixed32());
+  EXPECT_TRUE(message.has_default_sfixed64());
+  EXPECT_TRUE(message.has_default_float());
+  EXPECT_TRUE(message.has_default_double());
+  EXPECT_TRUE(message.has_default_bool());
+  EXPECT_TRUE(message.has_default_string());
+  EXPECT_TRUE(message.has_default_bytes());
+
+  EXPECT_TRUE(message.has_default_nested_enum());
+  EXPECT_TRUE(message.has_default_foreign_enum());
+  EXPECT_TRUE(message.has_default_import_enum());
+
+
+  EXPECT_EQ(401, message.default_int32());
+  EXPECT_EQ(402, message.default_int64());
+  EXPECT_EQ(403, message.default_uint32());
+  EXPECT_EQ(404, message.default_uint64());
+  EXPECT_EQ(405, message.default_sint32());
+  EXPECT_EQ(406, message.default_sint64());
+  EXPECT_EQ(407, message.default_fixed32());
+  EXPECT_EQ(408, message.default_fixed64());
+  EXPECT_EQ(409, message.default_sfixed32());
+  EXPECT_EQ(410, message.default_sfixed64());
+  EXPECT_EQ(411, message.default_float());
+  EXPECT_EQ(412, message.default_double());
+  EXPECT_FALSE(message.default_bool());
+  EXPECT_EQ("415", message.default_string());
+  EXPECT_EQ("416", message.default_bytes());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message.default_nested_enum());
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.default_foreign_enum());
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.default_import_enum());
+
+
+  EXPECT_FALSE(message.has_oneof_uint32());
+  EXPECT_FALSE(message.has_oneof_nested_message());
+  EXPECT_FALSE(message.has_oneof_string());
+  EXPECT_TRUE(message.has_oneof_bytes());
+
+  EXPECT_EQ("604", message.oneof_bytes());
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectClear(const UNITTEST::TestAllTypes& message) {
+  // has_blah() should initially be false for all optional fields.
+  EXPECT_FALSE(message.has_optional_int32());
+  EXPECT_FALSE(message.has_optional_int64());
+  EXPECT_FALSE(message.has_optional_uint32());
+  EXPECT_FALSE(message.has_optional_uint64());
+  EXPECT_FALSE(message.has_optional_sint32());
+  EXPECT_FALSE(message.has_optional_sint64());
+  EXPECT_FALSE(message.has_optional_fixed32());
+  EXPECT_FALSE(message.has_optional_fixed64());
+  EXPECT_FALSE(message.has_optional_sfixed32());
+  EXPECT_FALSE(message.has_optional_sfixed64());
+  EXPECT_FALSE(message.has_optional_float());
+  EXPECT_FALSE(message.has_optional_double());
+  EXPECT_FALSE(message.has_optional_bool());
+  EXPECT_FALSE(message.has_optional_string());
+  EXPECT_FALSE(message.has_optional_bytes());
+
+  EXPECT_FALSE(message.has_optionalgroup());
+  EXPECT_FALSE(message.has_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_foreign_message());
+  EXPECT_FALSE(message.has_optional_import_message());
+  EXPECT_FALSE(message.has_optional_public_import_message());
+  EXPECT_FALSE(message.has_optional_lazy_message());
+  EXPECT_FALSE(message.has_optional_unverified_lazy_message());
+
+  EXPECT_FALSE(message.has_optional_nested_enum());
+  EXPECT_FALSE(message.has_optional_foreign_enum());
+  EXPECT_FALSE(message.has_optional_import_enum());
+
+  EXPECT_FALSE(message.has_optional_string_piece());
+  EXPECT_FALSE(message.has_optional_cord());
+
+  // Optional fields without defaults are set to zero or something like it.
+  EXPECT_EQ(0, message.optional_int32());
+  EXPECT_EQ(0, message.optional_int64());
+  EXPECT_EQ(0, message.optional_uint32());
+  EXPECT_EQ(0, message.optional_uint64());
+  EXPECT_EQ(0, message.optional_sint32());
+  EXPECT_EQ(0, message.optional_sint64());
+  EXPECT_EQ(0, message.optional_fixed32());
+  EXPECT_EQ(0, message.optional_fixed64());
+  EXPECT_EQ(0, message.optional_sfixed32());
+  EXPECT_EQ(0, message.optional_sfixed64());
+  EXPECT_EQ(0, message.optional_float());
+  EXPECT_EQ(0, message.optional_double());
+  EXPECT_FALSE(message.optional_bool());
+  EXPECT_EQ("", message.optional_string());
+  EXPECT_EQ("", message.optional_bytes());
+
+  // Embedded messages should also be clear.
+  EXPECT_FALSE(message.optionalgroup().has_a());
+  EXPECT_FALSE(message.optional_nested_message().has_bb());
+  EXPECT_FALSE(message.optional_foreign_message().has_c());
+  EXPECT_FALSE(message.optional_import_message().has_d());
+  EXPECT_FALSE(message.optional_public_import_message().has_e());
+  EXPECT_FALSE(message.optional_lazy_message().has_bb());
+  EXPECT_FALSE(message.optional_unverified_lazy_message().has_bb());
+
+  EXPECT_EQ(0, message.optionalgroup().a());
+  EXPECT_EQ(0, message.optional_nested_message().bb());
+  EXPECT_EQ(0, message.optional_foreign_message().c());
+  EXPECT_EQ(0, message.optional_import_message().d());
+  EXPECT_EQ(0, message.optional_public_import_message().e());
+  EXPECT_EQ(0, message.optional_lazy_message().bb());
+  EXPECT_EQ(0, message.optional_unverified_lazy_message().bb());
+
+  // Enums without defaults are set to the first value in the enum.
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message.optional_nested_enum());
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.optional_foreign_enum());
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.optional_import_enum());
+
+
+  // Repeated fields are empty.
+  EXPECT_EQ(0, message.repeated_int32_size());
+  EXPECT_EQ(0, message.repeated_int64_size());
+  EXPECT_EQ(0, message.repeated_uint32_size());
+  EXPECT_EQ(0, message.repeated_uint64_size());
+  EXPECT_EQ(0, message.repeated_sint32_size());
+  EXPECT_EQ(0, message.repeated_sint64_size());
+  EXPECT_EQ(0, message.repeated_fixed32_size());
+  EXPECT_EQ(0, message.repeated_fixed64_size());
+  EXPECT_EQ(0, message.repeated_sfixed32_size());
+  EXPECT_EQ(0, message.repeated_sfixed64_size());
+  EXPECT_EQ(0, message.repeated_float_size());
+  EXPECT_EQ(0, message.repeated_double_size());
+  EXPECT_EQ(0, message.repeated_bool_size());
+  EXPECT_EQ(0, message.repeated_string_size());
+  EXPECT_EQ(0, message.repeated_bytes_size());
+
+  EXPECT_EQ(0, message.repeatedgroup_size());
+  EXPECT_EQ(0, message.repeated_nested_message_size());
+  EXPECT_EQ(0, message.repeated_foreign_message_size());
+  EXPECT_EQ(0, message.repeated_import_message_size());
+  EXPECT_EQ(0, message.repeated_lazy_message_size());
+  EXPECT_EQ(0, message.repeated_nested_enum_size());
+  EXPECT_EQ(0, message.repeated_foreign_enum_size());
+  EXPECT_EQ(0, message.repeated_import_enum_size());
+
+  EXPECT_EQ(0, message.repeated_string_piece_size());
+  EXPECT_EQ(0, message.repeated_cord_size());
+
+  // has_blah() should also be false for all default fields.
+  EXPECT_FALSE(message.has_default_int32());
+  EXPECT_FALSE(message.has_default_int64());
+  EXPECT_FALSE(message.has_default_uint32());
+  EXPECT_FALSE(message.has_default_uint64());
+  EXPECT_FALSE(message.has_default_sint32());
+  EXPECT_FALSE(message.has_default_sint64());
+  EXPECT_FALSE(message.has_default_fixed32());
+  EXPECT_FALSE(message.has_default_fixed64());
+  EXPECT_FALSE(message.has_default_sfixed32());
+  EXPECT_FALSE(message.has_default_sfixed64());
+  EXPECT_FALSE(message.has_default_float());
+  EXPECT_FALSE(message.has_default_double());
+  EXPECT_FALSE(message.has_default_bool());
+  EXPECT_FALSE(message.has_default_string());
+  EXPECT_FALSE(message.has_default_bytes());
+
+  EXPECT_FALSE(message.has_default_nested_enum());
+  EXPECT_FALSE(message.has_default_foreign_enum());
+  EXPECT_FALSE(message.has_default_import_enum());
+
+
+  // Fields with defaults have their default values (duh).
+  EXPECT_EQ(41, message.default_int32());
+  EXPECT_EQ(42, message.default_int64());
+  EXPECT_EQ(43, message.default_uint32());
+  EXPECT_EQ(44, message.default_uint64());
+  EXPECT_EQ(-45, message.default_sint32());
+  EXPECT_EQ(46, message.default_sint64());
+  EXPECT_EQ(47, message.default_fixed32());
+  EXPECT_EQ(48, message.default_fixed64());
+  EXPECT_EQ(49, message.default_sfixed32());
+  EXPECT_EQ(-50, message.default_sfixed64());
+  EXPECT_EQ(51.5, message.default_float());
+  EXPECT_EQ(52e3, message.default_double());
+  EXPECT_TRUE(message.default_bool());
+  EXPECT_EQ("hello", message.default_string());
+  EXPECT_EQ("world", message.default_bytes());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message.default_nested_enum());
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.default_foreign_enum());
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR, message.default_import_enum());
+
+
+  EXPECT_FALSE(message.has_oneof_uint32());
+  EXPECT_FALSE(message.has_oneof_nested_message());
+  EXPECT_FALSE(message.has_oneof_string());
+  EXPECT_FALSE(message.has_oneof_bytes());
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectRepeatedFieldsModified(
+    const UNITTEST::TestAllTypes& 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_EQ(2, message.repeated_int32_size());
+  ASSERT_EQ(2, message.repeated_int64_size());
+  ASSERT_EQ(2, message.repeated_uint32_size());
+  ASSERT_EQ(2, message.repeated_uint64_size());
+  ASSERT_EQ(2, message.repeated_sint32_size());
+  ASSERT_EQ(2, message.repeated_sint64_size());
+  ASSERT_EQ(2, message.repeated_fixed32_size());
+  ASSERT_EQ(2, message.repeated_fixed64_size());
+  ASSERT_EQ(2, message.repeated_sfixed32_size());
+  ASSERT_EQ(2, message.repeated_sfixed64_size());
+  ASSERT_EQ(2, message.repeated_float_size());
+  ASSERT_EQ(2, message.repeated_double_size());
+  ASSERT_EQ(2, message.repeated_bool_size());
+  ASSERT_EQ(2, message.repeated_string_size());
+  ASSERT_EQ(2, message.repeated_bytes_size());
+
+  ASSERT_EQ(2, message.repeatedgroup_size());
+  ASSERT_EQ(2, message.repeated_nested_message_size());
+  ASSERT_EQ(2, message.repeated_foreign_message_size());
+  ASSERT_EQ(2, message.repeated_import_message_size());
+  ASSERT_EQ(2, message.repeated_lazy_message_size());
+  ASSERT_EQ(2, message.repeated_nested_enum_size());
+  ASSERT_EQ(2, message.repeated_foreign_enum_size());
+  ASSERT_EQ(2, message.repeated_import_enum_size());
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  ASSERT_EQ(2, message.repeated_string_piece_size());
+  ASSERT_EQ(2, message.repeated_cord_size());
+#endif
+
+  EXPECT_EQ(201, message.repeated_int32(0));
+  EXPECT_EQ(202, message.repeated_int64(0));
+  EXPECT_EQ(203, message.repeated_uint32(0));
+  EXPECT_EQ(204, message.repeated_uint64(0));
+  EXPECT_EQ(205, message.repeated_sint32(0));
+  EXPECT_EQ(206, message.repeated_sint64(0));
+  EXPECT_EQ(207, message.repeated_fixed32(0));
+  EXPECT_EQ(208, message.repeated_fixed64(0));
+  EXPECT_EQ(209, message.repeated_sfixed32(0));
+  EXPECT_EQ(210, message.repeated_sfixed64(0));
+  EXPECT_EQ(211, message.repeated_float(0));
+  EXPECT_EQ(212, message.repeated_double(0));
+  EXPECT_TRUE(message.repeated_bool(0));
+  EXPECT_EQ("215", message.repeated_string(0));
+  EXPECT_EQ("216", message.repeated_bytes(0));
+
+  EXPECT_EQ(217, message.repeatedgroup(0).a());
+  EXPECT_EQ(218, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+  EXPECT_EQ(227, message.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message.repeated_nested_enum(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeated_foreign_enum(0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR, message.repeated_import_enum(0));
+
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(501, message.repeated_int32(1));
+  EXPECT_EQ(502, message.repeated_int64(1));
+  EXPECT_EQ(503, message.repeated_uint32(1));
+  EXPECT_EQ(504, message.repeated_uint64(1));
+  EXPECT_EQ(505, message.repeated_sint32(1));
+  EXPECT_EQ(506, message.repeated_sint64(1));
+  EXPECT_EQ(507, message.repeated_fixed32(1));
+  EXPECT_EQ(508, message.repeated_fixed64(1));
+  EXPECT_EQ(509, message.repeated_sfixed32(1));
+  EXPECT_EQ(510, message.repeated_sfixed64(1));
+  EXPECT_EQ(511, message.repeated_float(1));
+  EXPECT_EQ(512, message.repeated_double(1));
+  EXPECT_TRUE(message.repeated_bool(1));
+  EXPECT_EQ("515", message.repeated_string(1));
+  EXPECT_EQ("516", message.repeated_bytes(1));
+
+  EXPECT_EQ(517, message.repeatedgroup(1).a());
+  EXPECT_EQ(518, message.repeated_nested_message(1).bb());
+  EXPECT_EQ(519, message.repeated_foreign_message(1).c());
+  EXPECT_EQ(520, message.repeated_import_message(1).d());
+  EXPECT_EQ(527, message.repeated_lazy_message(1).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message.repeated_nested_enum(1));
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.repeated_foreign_enum(1));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.repeated_import_enum(1));
+
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::SetPackedFields(UNITTEST::TestPackedTypes* message) {
+  message->add_packed_int32(601);
+  message->add_packed_int64(602);
+  message->add_packed_uint32(603);
+  message->add_packed_uint64(604);
+  message->add_packed_sint32(605);
+  message->add_packed_sint64(606);
+  message->add_packed_fixed32(607);
+  message->add_packed_fixed64(608);
+  message->add_packed_sfixed32(609);
+  message->add_packed_sfixed64(610);
+  message->add_packed_float(611);
+  message->add_packed_double(612);
+  message->add_packed_bool(true);
+  message->add_packed_enum(UNITTEST::FOREIGN_BAR);
+  // add a second one of each field
+  message->add_packed_int32(701);
+  message->add_packed_int64(702);
+  message->add_packed_uint32(703);
+  message->add_packed_uint64(704);
+  message->add_packed_sint32(705);
+  message->add_packed_sint64(706);
+  message->add_packed_fixed32(707);
+  message->add_packed_fixed64(708);
+  message->add_packed_sfixed32(709);
+  message->add_packed_sfixed64(710);
+  message->add_packed_float(711);
+  message->add_packed_double(712);
+  message->add_packed_bool(false);
+  message->add_packed_enum(UNITTEST::FOREIGN_BAZ);
+}
+
+inline void TestUtil::SetUnpackedFields(UNITTEST::TestUnpackedTypes* message) {
+  // The values applied here must match those of SetPackedFields.
+
+  message->add_unpacked_int32(601);
+  message->add_unpacked_int64(602);
+  message->add_unpacked_uint32(603);
+  message->add_unpacked_uint64(604);
+  message->add_unpacked_sint32(605);
+  message->add_unpacked_sint64(606);
+  message->add_unpacked_fixed32(607);
+  message->add_unpacked_fixed64(608);
+  message->add_unpacked_sfixed32(609);
+  message->add_unpacked_sfixed64(610);
+  message->add_unpacked_float(611);
+  message->add_unpacked_double(612);
+  message->add_unpacked_bool(true);
+  message->add_unpacked_enum(UNITTEST::FOREIGN_BAR);
+  // add a second one of each field
+  message->add_unpacked_int32(701);
+  message->add_unpacked_int64(702);
+  message->add_unpacked_uint32(703);
+  message->add_unpacked_uint64(704);
+  message->add_unpacked_sint32(705);
+  message->add_unpacked_sint64(706);
+  message->add_unpacked_fixed32(707);
+  message->add_unpacked_fixed64(708);
+  message->add_unpacked_sfixed32(709);
+  message->add_unpacked_sfixed64(710);
+  message->add_unpacked_float(711);
+  message->add_unpacked_double(712);
+  message->add_unpacked_bool(false);
+  message->add_unpacked_enum(UNITTEST::FOREIGN_BAZ);
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectPackedFieldsSet(
+    const UNITTEST::TestPackedTypes& message) {
+  ASSERT_EQ(2, message.packed_int32_size());
+  ASSERT_EQ(2, message.packed_int64_size());
+  ASSERT_EQ(2, message.packed_uint32_size());
+  ASSERT_EQ(2, message.packed_uint64_size());
+  ASSERT_EQ(2, message.packed_sint32_size());
+  ASSERT_EQ(2, message.packed_sint64_size());
+  ASSERT_EQ(2, message.packed_fixed32_size());
+  ASSERT_EQ(2, message.packed_fixed64_size());
+  ASSERT_EQ(2, message.packed_sfixed32_size());
+  ASSERT_EQ(2, message.packed_sfixed64_size());
+  ASSERT_EQ(2, message.packed_float_size());
+  ASSERT_EQ(2, message.packed_double_size());
+  ASSERT_EQ(2, message.packed_bool_size());
+  ASSERT_EQ(2, message.packed_enum_size());
+
+  EXPECT_EQ(601, message.packed_int32(0));
+  EXPECT_EQ(602, message.packed_int64(0));
+  EXPECT_EQ(603, message.packed_uint32(0));
+  EXPECT_EQ(604, message.packed_uint64(0));
+  EXPECT_EQ(605, message.packed_sint32(0));
+  EXPECT_EQ(606, message.packed_sint64(0));
+  EXPECT_EQ(607, message.packed_fixed32(0));
+  EXPECT_EQ(608, message.packed_fixed64(0));
+  EXPECT_EQ(609, message.packed_sfixed32(0));
+  EXPECT_EQ(610, message.packed_sfixed64(0));
+  EXPECT_EQ(611, message.packed_float(0));
+  EXPECT_EQ(612, message.packed_double(0));
+  EXPECT_TRUE(message.packed_bool(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.packed_enum(0));
+
+  EXPECT_EQ(701, message.packed_int32(1));
+  EXPECT_EQ(702, message.packed_int64(1));
+  EXPECT_EQ(703, message.packed_uint32(1));
+  EXPECT_EQ(704, message.packed_uint64(1));
+  EXPECT_EQ(705, message.packed_sint32(1));
+  EXPECT_EQ(706, message.packed_sint64(1));
+  EXPECT_EQ(707, message.packed_fixed32(1));
+  EXPECT_EQ(708, message.packed_fixed64(1));
+  EXPECT_EQ(709, message.packed_sfixed32(1));
+  EXPECT_EQ(710, message.packed_sfixed64(1));
+  EXPECT_EQ(711, message.packed_float(1));
+  EXPECT_EQ(712, message.packed_double(1));
+  EXPECT_FALSE(message.packed_bool(1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.packed_enum(1));
+}
+
+inline void TestUtil::ExpectUnpackedFieldsSet(
+    const UNITTEST::TestUnpackedTypes& message) {
+  // The values expected here must match those of ExpectPackedFieldsSet.
+
+  ASSERT_EQ(2, message.unpacked_int32_size());
+  ASSERT_EQ(2, message.unpacked_int64_size());
+  ASSERT_EQ(2, message.unpacked_uint32_size());
+  ASSERT_EQ(2, message.unpacked_uint64_size());
+  ASSERT_EQ(2, message.unpacked_sint32_size());
+  ASSERT_EQ(2, message.unpacked_sint64_size());
+  ASSERT_EQ(2, message.unpacked_fixed32_size());
+  ASSERT_EQ(2, message.unpacked_fixed64_size());
+  ASSERT_EQ(2, message.unpacked_sfixed32_size());
+  ASSERT_EQ(2, message.unpacked_sfixed64_size());
+  ASSERT_EQ(2, message.unpacked_float_size());
+  ASSERT_EQ(2, message.unpacked_double_size());
+  ASSERT_EQ(2, message.unpacked_bool_size());
+  ASSERT_EQ(2, message.unpacked_enum_size());
+
+  EXPECT_EQ(601, message.unpacked_int32(0));
+  EXPECT_EQ(602, message.unpacked_int64(0));
+  EXPECT_EQ(603, message.unpacked_uint32(0));
+  EXPECT_EQ(604, message.unpacked_uint64(0));
+  EXPECT_EQ(605, message.unpacked_sint32(0));
+  EXPECT_EQ(606, message.unpacked_sint64(0));
+  EXPECT_EQ(607, message.unpacked_fixed32(0));
+  EXPECT_EQ(608, message.unpacked_fixed64(0));
+  EXPECT_EQ(609, message.unpacked_sfixed32(0));
+  EXPECT_EQ(610, message.unpacked_sfixed64(0));
+  EXPECT_EQ(611, message.unpacked_float(0));
+  EXPECT_EQ(612, message.unpacked_double(0));
+  EXPECT_TRUE(message.unpacked_bool(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.unpacked_enum(0));
+
+  EXPECT_EQ(701, message.unpacked_int32(1));
+  EXPECT_EQ(702, message.unpacked_int64(1));
+  EXPECT_EQ(703, message.unpacked_uint32(1));
+  EXPECT_EQ(704, message.unpacked_uint64(1));
+  EXPECT_EQ(705, message.unpacked_sint32(1));
+  EXPECT_EQ(706, message.unpacked_sint64(1));
+  EXPECT_EQ(707, message.unpacked_fixed32(1));
+  EXPECT_EQ(708, message.unpacked_fixed64(1));
+  EXPECT_EQ(709, message.unpacked_sfixed32(1));
+  EXPECT_EQ(710, message.unpacked_sfixed64(1));
+  EXPECT_EQ(711, message.unpacked_float(1));
+  EXPECT_EQ(712, message.unpacked_double(1));
+  EXPECT_FALSE(message.unpacked_bool(1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.unpacked_enum(1));
+}
+
+// ===================================================================
+// Extensions
+//
+// All this code is exactly equivalent to the above code except that it's
+// manipulating extension fields instead of normal ones.
+
+inline void TestUtil::SetAllExtensions(UNITTEST::TestAllExtensions* message) {
+  message->SetExtension(UNITTEST::optional_int32_extension, 101);
+  message->SetExtension(UNITTEST::optional_int64_extension, 102);
+  message->SetExtension(UNITTEST::optional_uint32_extension, 103);
+  message->SetExtension(UNITTEST::optional_uint64_extension, 104);
+  message->SetExtension(UNITTEST::optional_sint32_extension, 105);
+  message->SetExtension(UNITTEST::optional_sint64_extension, 106);
+  message->SetExtension(UNITTEST::optional_fixed32_extension, 107);
+  message->SetExtension(UNITTEST::optional_fixed64_extension, 108);
+  message->SetExtension(UNITTEST::optional_sfixed32_extension, 109);
+  message->SetExtension(UNITTEST::optional_sfixed64_extension, 110);
+  message->SetExtension(UNITTEST::optional_float_extension, 111);
+  message->SetExtension(UNITTEST::optional_double_extension, 112);
+  message->SetExtension(UNITTEST::optional_bool_extension, true);
+  message->SetExtension(UNITTEST::optional_string_extension, "115");
+  message->SetExtension(UNITTEST::optional_bytes_extension, "116");
+
+  message->MutableExtension(UNITTEST::optionalgroup_extension)->set_a(117);
+  message->MutableExtension(UNITTEST::optional_nested_message_extension)
+      ->set_bb(118);
+  message->MutableExtension(UNITTEST::optional_foreign_message_extension)
+      ->set_c(119);
+  message->MutableExtension(UNITTEST::optional_import_message_extension)
+      ->set_d(120);
+
+  message->SetExtension(UNITTEST::optional_nested_enum_extension,
+                        UNITTEST::TestAllTypes::BAZ);
+  message->SetExtension(UNITTEST::optional_foreign_enum_extension,
+                        UNITTEST::FOREIGN_BAZ);
+  message->SetExtension(UNITTEST::optional_import_enum_extension,
+                        UNITTEST_IMPORT::IMPORT_BAZ);
+
+  message->SetExtension(UNITTEST::optional_string_piece_extension, "124");
+  message->SetExtension(UNITTEST::optional_cord_extension, "125");
+
+  message->MutableExtension(UNITTEST::optional_public_import_message_extension)
+      ->set_e(126);
+  message->MutableExtension(UNITTEST::optional_lazy_message_extension)
+      ->set_bb(127);
+  message
+      ->MutableExtension(UNITTEST::optional_unverified_lazy_message_extension)
+      ->set_bb(128);
+
+  // -----------------------------------------------------------------
+
+  message->AddExtension(UNITTEST::repeated_int32_extension, 201);
+  message->AddExtension(UNITTEST::repeated_int64_extension, 202);
+  message->AddExtension(UNITTEST::repeated_uint32_extension, 203);
+  message->AddExtension(UNITTEST::repeated_uint64_extension, 204);
+  message->AddExtension(UNITTEST::repeated_sint32_extension, 205);
+  message->AddExtension(UNITTEST::repeated_sint64_extension, 206);
+  message->AddExtension(UNITTEST::repeated_fixed32_extension, 207);
+  message->AddExtension(UNITTEST::repeated_fixed64_extension, 208);
+  message->AddExtension(UNITTEST::repeated_sfixed32_extension, 209);
+  message->AddExtension(UNITTEST::repeated_sfixed64_extension, 210);
+  message->AddExtension(UNITTEST::repeated_float_extension, 211);
+  message->AddExtension(UNITTEST::repeated_double_extension, 212);
+  message->AddExtension(UNITTEST::repeated_bool_extension, true);
+  message->AddExtension(UNITTEST::repeated_string_extension, "215");
+  message->AddExtension(UNITTEST::repeated_bytes_extension, "216");
+
+  message->AddExtension(UNITTEST::repeatedgroup_extension)->set_a(217);
+  message->AddExtension(UNITTEST::repeated_nested_message_extension)
+      ->set_bb(218);
+  message->AddExtension(UNITTEST::repeated_foreign_message_extension)
+      ->set_c(219);
+  message->AddExtension(UNITTEST::repeated_import_message_extension)
+      ->set_d(220);
+  message->AddExtension(UNITTEST::repeated_lazy_message_extension)->set_bb(227);
+
+  message->AddExtension(UNITTEST::repeated_nested_enum_extension,
+                        UNITTEST::TestAllTypes::BAR);
+  message->AddExtension(UNITTEST::repeated_foreign_enum_extension,
+                        UNITTEST::FOREIGN_BAR);
+  message->AddExtension(UNITTEST::repeated_import_enum_extension,
+                        UNITTEST_IMPORT::IMPORT_BAR);
+
+  message->AddExtension(UNITTEST::repeated_string_piece_extension, "224");
+  message->AddExtension(UNITTEST::repeated_cord_extension, "225");
+
+  // Add a second one of each field.
+  message->AddExtension(UNITTEST::repeated_int32_extension, 301);
+  message->AddExtension(UNITTEST::repeated_int64_extension, 302);
+  message->AddExtension(UNITTEST::repeated_uint32_extension, 303);
+  message->AddExtension(UNITTEST::repeated_uint64_extension, 304);
+  message->AddExtension(UNITTEST::repeated_sint32_extension, 305);
+  message->AddExtension(UNITTEST::repeated_sint64_extension, 306);
+  message->AddExtension(UNITTEST::repeated_fixed32_extension, 307);
+  message->AddExtension(UNITTEST::repeated_fixed64_extension, 308);
+  message->AddExtension(UNITTEST::repeated_sfixed32_extension, 309);
+  message->AddExtension(UNITTEST::repeated_sfixed64_extension, 310);
+  message->AddExtension(UNITTEST::repeated_float_extension, 311);
+  message->AddExtension(UNITTEST::repeated_double_extension, 312);
+  message->AddExtension(UNITTEST::repeated_bool_extension, false);
+  message->AddExtension(UNITTEST::repeated_string_extension, "315");
+  message->AddExtension(UNITTEST::repeated_bytes_extension, "316");
+
+  message->AddExtension(UNITTEST::repeatedgroup_extension)->set_a(317);
+  message->AddExtension(UNITTEST::repeated_nested_message_extension)
+      ->set_bb(318);
+  message->AddExtension(UNITTEST::repeated_foreign_message_extension)
+      ->set_c(319);
+  message->AddExtension(UNITTEST::repeated_import_message_extension)
+      ->set_d(320);
+  message->AddExtension(UNITTEST::repeated_lazy_message_extension)->set_bb(327);
+
+  message->AddExtension(UNITTEST::repeated_nested_enum_extension,
+                        UNITTEST::TestAllTypes::BAZ);
+  message->AddExtension(UNITTEST::repeated_foreign_enum_extension,
+                        UNITTEST::FOREIGN_BAZ);
+  message->AddExtension(UNITTEST::repeated_import_enum_extension,
+                        UNITTEST_IMPORT::IMPORT_BAZ);
+
+  message->AddExtension(UNITTEST::repeated_string_piece_extension, "324");
+  message->AddExtension(UNITTEST::repeated_cord_extension, "325");
+
+  // -----------------------------------------------------------------
+
+  message->SetExtension(UNITTEST::default_int32_extension, 401);
+  message->SetExtension(UNITTEST::default_int64_extension, 402);
+  message->SetExtension(UNITTEST::default_uint32_extension, 403);
+  message->SetExtension(UNITTEST::default_uint64_extension, 404);
+  message->SetExtension(UNITTEST::default_sint32_extension, 405);
+  message->SetExtension(UNITTEST::default_sint64_extension, 406);
+  message->SetExtension(UNITTEST::default_fixed32_extension, 407);
+  message->SetExtension(UNITTEST::default_fixed64_extension, 408);
+  message->SetExtension(UNITTEST::default_sfixed32_extension, 409);
+  message->SetExtension(UNITTEST::default_sfixed64_extension, 410);
+  message->SetExtension(UNITTEST::default_float_extension, 411);
+  message->SetExtension(UNITTEST::default_double_extension, 412);
+  message->SetExtension(UNITTEST::default_bool_extension, false);
+  message->SetExtension(UNITTEST::default_string_extension, "415");
+  message->SetExtension(UNITTEST::default_bytes_extension, "416");
+
+  message->SetExtension(UNITTEST::default_nested_enum_extension,
+                        UNITTEST::TestAllTypes::FOO);
+  message->SetExtension(UNITTEST::default_foreign_enum_extension,
+                        UNITTEST::FOREIGN_FOO);
+  message->SetExtension(UNITTEST::default_import_enum_extension,
+                        UNITTEST_IMPORT::IMPORT_FOO);
+
+  message->SetExtension(UNITTEST::default_string_piece_extension, "424");
+  message->SetExtension(UNITTEST::default_cord_extension, "425");
+
+  SetOneofFields(message);
+}
+
+inline void TestUtil::SetOneofFields(UNITTEST::TestAllExtensions* message) {
+  message->SetExtension(UNITTEST::oneof_uint32_extension, 601);
+  message->MutableExtension(UNITTEST::oneof_nested_message_extension)
+      ->set_bb(602);
+  message->SetExtension(UNITTEST::oneof_string_extension, "603");
+  message->SetExtension(UNITTEST::oneof_bytes_extension, "604");
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::SetAllFieldsAndExtensions(
+    UNITTEST::TestFieldOrderings* message) {
+  GOOGLE_CHECK(message);
+  message->set_my_int(1);
+  message->set_my_string("foo");
+  message->set_my_float(1.0);
+  message->SetExtension(UNITTEST::my_extension_int, 23);
+  message->SetExtension(UNITTEST::my_extension_string, "bar");
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ModifyRepeatedExtensions(
+    UNITTEST::TestAllExtensions* message) {
+  message->SetExtension(UNITTEST::repeated_int32_extension, 1, 501);
+  message->SetExtension(UNITTEST::repeated_int64_extension, 1, 502);
+  message->SetExtension(UNITTEST::repeated_uint32_extension, 1, 503);
+  message->SetExtension(UNITTEST::repeated_uint64_extension, 1, 504);
+  message->SetExtension(UNITTEST::repeated_sint32_extension, 1, 505);
+  message->SetExtension(UNITTEST::repeated_sint64_extension, 1, 506);
+  message->SetExtension(UNITTEST::repeated_fixed32_extension, 1, 507);
+  message->SetExtension(UNITTEST::repeated_fixed64_extension, 1, 508);
+  message->SetExtension(UNITTEST::repeated_sfixed32_extension, 1, 509);
+  message->SetExtension(UNITTEST::repeated_sfixed64_extension, 1, 510);
+  message->SetExtension(UNITTEST::repeated_float_extension, 1, 511);
+  message->SetExtension(UNITTEST::repeated_double_extension, 1, 512);
+  message->SetExtension(UNITTEST::repeated_bool_extension, 1, true);
+  message->SetExtension(UNITTEST::repeated_string_extension, 1, "515");
+  message->SetExtension(UNITTEST::repeated_bytes_extension, 1, "516");
+
+  message->MutableExtension(UNITTEST::repeatedgroup_extension, 1)->set_a(517);
+  message->MutableExtension(UNITTEST::repeated_nested_message_extension, 1)
+      ->set_bb(518);
+  message->MutableExtension(UNITTEST::repeated_foreign_message_extension, 1)
+      ->set_c(519);
+  message->MutableExtension(UNITTEST::repeated_import_message_extension, 1)
+      ->set_d(520);
+  message->MutableExtension(UNITTEST::repeated_lazy_message_extension, 1)
+      ->set_bb(527);
+
+  message->SetExtension(UNITTEST::repeated_nested_enum_extension, 1,
+                        UNITTEST::TestAllTypes::FOO);
+  message->SetExtension(UNITTEST::repeated_foreign_enum_extension, 1,
+                        UNITTEST::FOREIGN_FOO);
+  message->SetExtension(UNITTEST::repeated_import_enum_extension, 1,
+                        UNITTEST_IMPORT::IMPORT_FOO);
+
+  message->SetExtension(UNITTEST::repeated_string_piece_extension, 1, "524");
+  message->SetExtension(UNITTEST::repeated_cord_extension, 1, "525");
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectAllExtensionsSet(
+    const UNITTEST::TestAllExtensions& message) {
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_int32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_int64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_uint32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_uint64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_sint32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_sint64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_fixed32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_fixed64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_sfixed32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_sfixed64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_float_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_double_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_bool_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_string_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_bytes_extension));
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optionalgroup_extension));
+  EXPECT_TRUE(
+      message.HasExtension(UNITTEST::optional_nested_message_extension));
+  EXPECT_TRUE(
+      message.HasExtension(UNITTEST::optional_foreign_message_extension));
+  EXPECT_TRUE(
+      message.HasExtension(UNITTEST::optional_import_message_extension));
+  EXPECT_TRUE(
+      message.HasExtension(UNITTEST::optional_public_import_message_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_lazy_message_extension));
+  EXPECT_TRUE(message.HasExtension(
+      UNITTEST::optional_unverified_lazy_message_extension));
+
+  EXPECT_TRUE(message.GetExtension(UNITTEST::optionalgroup_extension).has_a());
+  EXPECT_TRUE(message.GetExtension(UNITTEST::optional_nested_message_extension)
+                  .has_bb());
+  EXPECT_TRUE(message.GetExtension(UNITTEST::optional_foreign_message_extension)
+                  .has_c());
+  EXPECT_TRUE(message.GetExtension(UNITTEST::optional_import_message_extension)
+                  .has_d());
+  EXPECT_TRUE(
+      message.GetExtension(UNITTEST::optional_public_import_message_extension)
+          .has_e());
+  EXPECT_TRUE(
+      message.GetExtension(UNITTEST::optional_lazy_message_extension).has_bb());
+  EXPECT_TRUE(
+      message.GetExtension(UNITTEST::optional_unverified_lazy_message_extension)
+          .has_bb());
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_nested_enum_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_foreign_enum_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_import_enum_extension));
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_string_piece_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::optional_cord_extension));
+
+  EXPECT_EQ(101, message.GetExtension(UNITTEST::optional_int32_extension));
+  EXPECT_EQ(102, message.GetExtension(UNITTEST::optional_int64_extension));
+  EXPECT_EQ(103, message.GetExtension(UNITTEST::optional_uint32_extension));
+  EXPECT_EQ(104, message.GetExtension(UNITTEST::optional_uint64_extension));
+  EXPECT_EQ(105, message.GetExtension(UNITTEST::optional_sint32_extension));
+  EXPECT_EQ(106, message.GetExtension(UNITTEST::optional_sint64_extension));
+  EXPECT_EQ(107, message.GetExtension(UNITTEST::optional_fixed32_extension));
+  EXPECT_EQ(108, message.GetExtension(UNITTEST::optional_fixed64_extension));
+  EXPECT_EQ(109, message.GetExtension(UNITTEST::optional_sfixed32_extension));
+  EXPECT_EQ(110, message.GetExtension(UNITTEST::optional_sfixed64_extension));
+  EXPECT_EQ(111, message.GetExtension(UNITTEST::optional_float_extension));
+  EXPECT_EQ(112, message.GetExtension(UNITTEST::optional_double_extension));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::optional_bool_extension));
+  EXPECT_EQ("115", message.GetExtension(UNITTEST::optional_string_extension));
+  EXPECT_EQ("116", message.GetExtension(UNITTEST::optional_bytes_extension));
+
+  EXPECT_EQ(117, message.GetExtension(UNITTEST::optionalgroup_extension).a());
+  EXPECT_EQ(
+      118,
+      message.GetExtension(UNITTEST::optional_nested_message_extension).bb());
+  EXPECT_EQ(
+      119,
+      message.GetExtension(UNITTEST::optional_foreign_message_extension).c());
+  EXPECT_EQ(
+      120,
+      message.GetExtension(UNITTEST::optional_import_message_extension).d());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ,
+            message.GetExtension(UNITTEST::optional_nested_enum_extension));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            message.GetExtension(UNITTEST::optional_foreign_enum_extension));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ,
+            message.GetExtension(UNITTEST::optional_import_enum_extension));
+
+  EXPECT_EQ("124",
+            message.GetExtension(UNITTEST::optional_string_piece_extension));
+  EXPECT_EQ("125", message.GetExtension(UNITTEST::optional_cord_extension));
+  EXPECT_EQ(
+      126,
+      message.GetExtension(UNITTEST::optional_public_import_message_extension)
+          .e());
+  EXPECT_EQ(
+      127,
+      message.GetExtension(UNITTEST::optional_lazy_message_extension).bb());
+  EXPECT_EQ(
+      128,
+      message.GetExtension(UNITTEST::optional_unverified_lazy_message_extension)
+          .bb());
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_int32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_int64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_uint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_uint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_fixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_fixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sfixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sfixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_float_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_double_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_bool_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_string_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_bytes_extension));
+
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeatedgroup_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_nested_message_extension));
+  ASSERT_EQ(
+      2, message.ExtensionSize(UNITTEST::repeated_foreign_message_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_import_message_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_lazy_message_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_nested_enum_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_foreign_enum_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_import_enum_extension));
+
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_string_piece_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_cord_extension));
+
+  EXPECT_EQ(201, message.GetExtension(UNITTEST::repeated_int32_extension, 0));
+  EXPECT_EQ(202, message.GetExtension(UNITTEST::repeated_int64_extension, 0));
+  EXPECT_EQ(203, message.GetExtension(UNITTEST::repeated_uint32_extension, 0));
+  EXPECT_EQ(204, message.GetExtension(UNITTEST::repeated_uint64_extension, 0));
+  EXPECT_EQ(205, message.GetExtension(UNITTEST::repeated_sint32_extension, 0));
+  EXPECT_EQ(206, message.GetExtension(UNITTEST::repeated_sint64_extension, 0));
+  EXPECT_EQ(207, message.GetExtension(UNITTEST::repeated_fixed32_extension, 0));
+  EXPECT_EQ(208, message.GetExtension(UNITTEST::repeated_fixed64_extension, 0));
+  EXPECT_EQ(209,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 0));
+  EXPECT_EQ(210,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 0));
+  EXPECT_EQ(211, message.GetExtension(UNITTEST::repeated_float_extension, 0));
+  EXPECT_EQ(212, message.GetExtension(UNITTEST::repeated_double_extension, 0));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::repeated_bool_extension, 0));
+  EXPECT_EQ("215",
+            message.GetExtension(UNITTEST::repeated_string_extension, 0));
+  EXPECT_EQ("216", message.GetExtension(UNITTEST::repeated_bytes_extension, 0));
+
+  EXPECT_EQ(217,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 0).a());
+  EXPECT_EQ(218,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 0)
+                .bb());
+  EXPECT_EQ(
+      219, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 0)
+               .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 0).d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 0).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 0));
+
+  EXPECT_EQ("224",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 0));
+  EXPECT_EQ("225", message.GetExtension(UNITTEST::repeated_cord_extension, 0));
+
+  EXPECT_EQ(301, message.GetExtension(UNITTEST::repeated_int32_extension, 1));
+  EXPECT_EQ(302, message.GetExtension(UNITTEST::repeated_int64_extension, 1));
+  EXPECT_EQ(303, message.GetExtension(UNITTEST::repeated_uint32_extension, 1));
+  EXPECT_EQ(304, message.GetExtension(UNITTEST::repeated_uint64_extension, 1));
+  EXPECT_EQ(305, message.GetExtension(UNITTEST::repeated_sint32_extension, 1));
+  EXPECT_EQ(306, message.GetExtension(UNITTEST::repeated_sint64_extension, 1));
+  EXPECT_EQ(307, message.GetExtension(UNITTEST::repeated_fixed32_extension, 1));
+  EXPECT_EQ(308, message.GetExtension(UNITTEST::repeated_fixed64_extension, 1));
+  EXPECT_EQ(309,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 1));
+  EXPECT_EQ(310,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 1));
+  EXPECT_EQ(311, message.GetExtension(UNITTEST::repeated_float_extension, 1));
+  EXPECT_EQ(312, message.GetExtension(UNITTEST::repeated_double_extension, 1));
+  EXPECT_FALSE(message.GetExtension(UNITTEST::repeated_bool_extension, 1));
+  EXPECT_EQ("315",
+            message.GetExtension(UNITTEST::repeated_string_extension, 1));
+  EXPECT_EQ("316", message.GetExtension(UNITTEST::repeated_bytes_extension, 1));
+
+  EXPECT_EQ(317,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 1).a());
+  EXPECT_EQ(318,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 1)
+                .bb());
+  EXPECT_EQ(
+      319, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 1)
+               .c());
+  EXPECT_EQ(
+      320,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 1).d());
+  EXPECT_EQ(
+      327,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 1).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 1));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 1));
+
+  EXPECT_EQ("324",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 1));
+  EXPECT_EQ("325", message.GetExtension(UNITTEST::repeated_cord_extension, 1));
+
+  // -----------------------------------------------------------------
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_int32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_int64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_uint32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_uint64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_sint32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_sint64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_fixed32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_fixed64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_sfixed32_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_sfixed64_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_float_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_double_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_bool_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_string_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_bytes_extension));
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_nested_enum_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_foreign_enum_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_import_enum_extension));
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_string_piece_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::default_cord_extension));
+
+  EXPECT_EQ(401, message.GetExtension(UNITTEST::default_int32_extension));
+  EXPECT_EQ(402, message.GetExtension(UNITTEST::default_int64_extension));
+  EXPECT_EQ(403, message.GetExtension(UNITTEST::default_uint32_extension));
+  EXPECT_EQ(404, message.GetExtension(UNITTEST::default_uint64_extension));
+  EXPECT_EQ(405, message.GetExtension(UNITTEST::default_sint32_extension));
+  EXPECT_EQ(406, message.GetExtension(UNITTEST::default_sint64_extension));
+  EXPECT_EQ(407, message.GetExtension(UNITTEST::default_fixed32_extension));
+  EXPECT_EQ(408, message.GetExtension(UNITTEST::default_fixed64_extension));
+  EXPECT_EQ(409, message.GetExtension(UNITTEST::default_sfixed32_extension));
+  EXPECT_EQ(410, message.GetExtension(UNITTEST::default_sfixed64_extension));
+  EXPECT_EQ(411, message.GetExtension(UNITTEST::default_float_extension));
+  EXPECT_EQ(412, message.GetExtension(UNITTEST::default_double_extension));
+  EXPECT_FALSE(message.GetExtension(UNITTEST::default_bool_extension));
+  EXPECT_EQ("415", message.GetExtension(UNITTEST::default_string_extension));
+  EXPECT_EQ("416", message.GetExtension(UNITTEST::default_bytes_extension));
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO,
+            message.GetExtension(UNITTEST::default_nested_enum_extension));
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO,
+            message.GetExtension(UNITTEST::default_foreign_enum_extension));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO,
+            message.GetExtension(UNITTEST::default_import_enum_extension));
+
+  EXPECT_EQ("424",
+            message.GetExtension(UNITTEST::default_string_piece_extension));
+  EXPECT_EQ("425", message.GetExtension(UNITTEST::default_cord_extension));
+
+  EXPECT_TRUE(message.HasExtension(UNITTEST::oneof_uint32_extension));
+  EXPECT_TRUE(
+      message.GetExtension(UNITTEST::oneof_nested_message_extension).has_bb());
+  EXPECT_TRUE(message.HasExtension(UNITTEST::oneof_string_extension));
+  EXPECT_TRUE(message.HasExtension(UNITTEST::oneof_bytes_extension));
+
+  EXPECT_EQ(601, message.GetExtension(UNITTEST::oneof_uint32_extension));
+  EXPECT_EQ(
+      602, message.GetExtension(UNITTEST::oneof_nested_message_extension).bb());
+  EXPECT_EQ("603", message.GetExtension(UNITTEST::oneof_string_extension));
+  EXPECT_EQ("604", message.GetExtension(UNITTEST::oneof_bytes_extension));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectExtensionsClear(
+    const UNITTEST::TestAllExtensions& message) {
+  std::string serialized;
+  ASSERT_TRUE(message.SerializeToString(&serialized));
+  EXPECT_EQ("", serialized);
+  EXPECT_EQ(0, message.ByteSizeLong());
+
+  // has_blah() should initially be false for all optional fields.
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_int32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_int64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_uint32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_uint64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_sint32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_sint64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_fixed32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_fixed64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_sfixed32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_sfixed64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_float_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_double_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_bool_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_string_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_bytes_extension));
+
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optionalgroup_extension));
+  EXPECT_FALSE(
+      message.HasExtension(UNITTEST::optional_nested_message_extension));
+  EXPECT_FALSE(
+      message.HasExtension(UNITTEST::optional_foreign_message_extension));
+  EXPECT_FALSE(
+      message.HasExtension(UNITTEST::optional_import_message_extension));
+  EXPECT_FALSE(
+      message.HasExtension(UNITTEST::optional_public_import_message_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_lazy_message_extension));
+  EXPECT_FALSE(message.HasExtension(
+      UNITTEST::optional_unverified_lazy_message_extension));
+
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_nested_enum_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_foreign_enum_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_import_enum_extension));
+
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_string_piece_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::optional_cord_extension));
+
+  // Optional fields without defaults are set to zero or something like it.
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_int32_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_int64_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_uint32_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_uint64_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_sint32_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_sint64_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_fixed32_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_fixed64_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_sfixed32_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_sfixed64_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_float_extension));
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_double_extension));
+  EXPECT_FALSE(message.GetExtension(UNITTEST::optional_bool_extension));
+  EXPECT_EQ("", message.GetExtension(UNITTEST::optional_string_extension));
+  EXPECT_EQ("", message.GetExtension(UNITTEST::optional_bytes_extension));
+
+  // Embedded messages should also be clear.
+  EXPECT_FALSE(message.GetExtension(UNITTEST::optionalgroup_extension).has_a());
+  EXPECT_FALSE(message.GetExtension(UNITTEST::optional_nested_message_extension)
+                   .has_bb());
+  EXPECT_FALSE(
+      message.GetExtension(UNITTEST::optional_foreign_message_extension)
+          .has_c());
+  EXPECT_FALSE(message.GetExtension(UNITTEST::optional_import_message_extension)
+                   .has_d());
+  EXPECT_FALSE(
+      message.GetExtension(UNITTEST::optional_public_import_message_extension)
+          .has_e());
+  EXPECT_FALSE(
+      message.GetExtension(UNITTEST::optional_lazy_message_extension).has_bb());
+  EXPECT_FALSE(
+      message.GetExtension(UNITTEST::optional_unverified_lazy_message_extension)
+          .has_bb());
+
+  EXPECT_EQ(0, message.GetExtension(UNITTEST::optionalgroup_extension).a());
+  EXPECT_EQ(
+      0,
+      message.GetExtension(UNITTEST::optional_nested_message_extension).bb());
+  EXPECT_EQ(
+      0,
+      message.GetExtension(UNITTEST::optional_foreign_message_extension).c());
+  EXPECT_EQ(
+      0, message.GetExtension(UNITTEST::optional_import_message_extension).d());
+  EXPECT_EQ(
+      0,
+      message.GetExtension(UNITTEST::optional_public_import_message_extension)
+          .e());
+  EXPECT_EQ(
+      0, message.GetExtension(UNITTEST::optional_lazy_message_extension).bb());
+  EXPECT_EQ(
+      0,
+      message.GetExtension(UNITTEST::optional_unverified_lazy_message_extension)
+          .bb());
+
+  // Enums without defaults are set to the first value in the enum.
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO,
+            message.GetExtension(UNITTEST::optional_nested_enum_extension));
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO,
+            message.GetExtension(UNITTEST::optional_foreign_enum_extension));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO,
+            message.GetExtension(UNITTEST::optional_import_enum_extension));
+
+  EXPECT_EQ("",
+            message.GetExtension(UNITTEST::optional_string_piece_extension));
+  EXPECT_EQ("", message.GetExtension(UNITTEST::optional_cord_extension));
+
+  // Repeated fields are empty.
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_int32_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_int64_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_uint32_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_uint64_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_sint32_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_sint64_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_fixed32_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_fixed64_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_sfixed32_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_sfixed64_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_float_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_double_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_bool_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_string_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_bytes_extension));
+
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeatedgroup_extension));
+  EXPECT_EQ(0,
+            message.ExtensionSize(UNITTEST::repeated_nested_message_extension));
+  EXPECT_EQ(
+      0, message.ExtensionSize(UNITTEST::repeated_foreign_message_extension));
+  EXPECT_EQ(0,
+            message.ExtensionSize(UNITTEST::repeated_import_message_extension));
+  EXPECT_EQ(0,
+            message.ExtensionSize(UNITTEST::repeated_lazy_message_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_nested_enum_extension));
+  EXPECT_EQ(0,
+            message.ExtensionSize(UNITTEST::repeated_foreign_enum_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_import_enum_extension));
+
+  EXPECT_EQ(0,
+            message.ExtensionSize(UNITTEST::repeated_string_piece_extension));
+  EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_cord_extension));
+
+  // has_blah() should also be false for all default fields.
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_int32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_int64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_uint32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_uint64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_sint32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_sint64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_fixed32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_fixed64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_sfixed32_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_sfixed64_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_float_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_double_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_bool_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_string_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_bytes_extension));
+
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_nested_enum_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_foreign_enum_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_import_enum_extension));
+
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_string_piece_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::default_cord_extension));
+
+  // Fields with defaults have their default values (duh).
+  EXPECT_EQ(41, message.GetExtension(UNITTEST::default_int32_extension));
+  EXPECT_EQ(42, message.GetExtension(UNITTEST::default_int64_extension));
+  EXPECT_EQ(43, message.GetExtension(UNITTEST::default_uint32_extension));
+  EXPECT_EQ(44, message.GetExtension(UNITTEST::default_uint64_extension));
+  EXPECT_EQ(-45, message.GetExtension(UNITTEST::default_sint32_extension));
+  EXPECT_EQ(46, message.GetExtension(UNITTEST::default_sint64_extension));
+  EXPECT_EQ(47, message.GetExtension(UNITTEST::default_fixed32_extension));
+  EXPECT_EQ(48, message.GetExtension(UNITTEST::default_fixed64_extension));
+  EXPECT_EQ(49, message.GetExtension(UNITTEST::default_sfixed32_extension));
+  EXPECT_EQ(-50, message.GetExtension(UNITTEST::default_sfixed64_extension));
+  EXPECT_EQ(51.5, message.GetExtension(UNITTEST::default_float_extension));
+  EXPECT_EQ(52e3, message.GetExtension(UNITTEST::default_double_extension));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::default_bool_extension));
+  EXPECT_EQ("hello", message.GetExtension(UNITTEST::default_string_extension));
+  EXPECT_EQ("world", message.GetExtension(UNITTEST::default_bytes_extension));
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR,
+            message.GetExtension(UNITTEST::default_nested_enum_extension));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::default_foreign_enum_extension));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR,
+            message.GetExtension(UNITTEST::default_import_enum_extension));
+
+  EXPECT_EQ("abc",
+            message.GetExtension(UNITTEST::default_string_piece_extension));
+  EXPECT_EQ("123", message.GetExtension(UNITTEST::default_cord_extension));
+
+  EXPECT_FALSE(message.HasExtension(UNITTEST::oneof_uint32_extension));
+  EXPECT_FALSE(
+      message.GetExtension(UNITTEST::oneof_nested_message_extension).has_bb());
+  EXPECT_FALSE(message.HasExtension(UNITTEST::oneof_string_extension));
+  EXPECT_FALSE(message.HasExtension(UNITTEST::oneof_bytes_extension));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectRepeatedExtensionsModified(
+    const UNITTEST::TestAllExtensions& 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_EQ(2, message.ExtensionSize(UNITTEST::repeated_int32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_int64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_uint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_uint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_fixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_fixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sfixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sfixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_float_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_double_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_bool_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_string_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_bytes_extension));
+
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeatedgroup_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_nested_message_extension));
+  ASSERT_EQ(
+      2, message.ExtensionSize(UNITTEST::repeated_foreign_message_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_import_message_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_lazy_message_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_nested_enum_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_foreign_enum_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_import_enum_extension));
+
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_string_piece_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_cord_extension));
+
+  EXPECT_EQ(201, message.GetExtension(UNITTEST::repeated_int32_extension, 0));
+  EXPECT_EQ(202, message.GetExtension(UNITTEST::repeated_int64_extension, 0));
+  EXPECT_EQ(203, message.GetExtension(UNITTEST::repeated_uint32_extension, 0));
+  EXPECT_EQ(204, message.GetExtension(UNITTEST::repeated_uint64_extension, 0));
+  EXPECT_EQ(205, message.GetExtension(UNITTEST::repeated_sint32_extension, 0));
+  EXPECT_EQ(206, message.GetExtension(UNITTEST::repeated_sint64_extension, 0));
+  EXPECT_EQ(207, message.GetExtension(UNITTEST::repeated_fixed32_extension, 0));
+  EXPECT_EQ(208, message.GetExtension(UNITTEST::repeated_fixed64_extension, 0));
+  EXPECT_EQ(209,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 0));
+  EXPECT_EQ(210,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 0));
+  EXPECT_EQ(211, message.GetExtension(UNITTEST::repeated_float_extension, 0));
+  EXPECT_EQ(212, message.GetExtension(UNITTEST::repeated_double_extension, 0));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::repeated_bool_extension, 0));
+  EXPECT_EQ("215",
+            message.GetExtension(UNITTEST::repeated_string_extension, 0));
+  EXPECT_EQ("216", message.GetExtension(UNITTEST::repeated_bytes_extension, 0));
+
+  EXPECT_EQ(217,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 0).a());
+  EXPECT_EQ(218,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 0)
+                .bb());
+  EXPECT_EQ(
+      219, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 0)
+               .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 0).d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 0).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 0));
+
+  EXPECT_EQ("224",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 0));
+  EXPECT_EQ("225", message.GetExtension(UNITTEST::repeated_cord_extension, 0));
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(501, message.GetExtension(UNITTEST::repeated_int32_extension, 1));
+  EXPECT_EQ(502, message.GetExtension(UNITTEST::repeated_int64_extension, 1));
+  EXPECT_EQ(503, message.GetExtension(UNITTEST::repeated_uint32_extension, 1));
+  EXPECT_EQ(504, message.GetExtension(UNITTEST::repeated_uint64_extension, 1));
+  EXPECT_EQ(505, message.GetExtension(UNITTEST::repeated_sint32_extension, 1));
+  EXPECT_EQ(506, message.GetExtension(UNITTEST::repeated_sint64_extension, 1));
+  EXPECT_EQ(507, message.GetExtension(UNITTEST::repeated_fixed32_extension, 1));
+  EXPECT_EQ(508, message.GetExtension(UNITTEST::repeated_fixed64_extension, 1));
+  EXPECT_EQ(509,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 1));
+  EXPECT_EQ(510,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 1));
+  EXPECT_EQ(511, message.GetExtension(UNITTEST::repeated_float_extension, 1));
+  EXPECT_EQ(512, message.GetExtension(UNITTEST::repeated_double_extension, 1));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::repeated_bool_extension, 1));
+  EXPECT_EQ("515",
+            message.GetExtension(UNITTEST::repeated_string_extension, 1));
+  EXPECT_EQ("516", message.GetExtension(UNITTEST::repeated_bytes_extension, 1));
+
+  EXPECT_EQ(517,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 1).a());
+  EXPECT_EQ(518,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 1)
+                .bb());
+  EXPECT_EQ(
+      519, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 1)
+               .c());
+  EXPECT_EQ(
+      520,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 1).d());
+  EXPECT_EQ(
+      527,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 1).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::FOO,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 1));
+  EXPECT_EQ(UNITTEST::FOREIGN_FOO,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 1));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 1));
+
+  EXPECT_EQ("524",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 1));
+  EXPECT_EQ("525", message.GetExtension(UNITTEST::repeated_cord_extension, 1));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::SetPackedExtensions(
+    UNITTEST::TestPackedExtensions* message) {
+  message->AddExtension(UNITTEST::packed_int32_extension, 601);
+  message->AddExtension(UNITTEST::packed_int64_extension, 602);
+  message->AddExtension(UNITTEST::packed_uint32_extension, 603);
+  message->AddExtension(UNITTEST::packed_uint64_extension, 604);
+  message->AddExtension(UNITTEST::packed_sint32_extension, 605);
+  message->AddExtension(UNITTEST::packed_sint64_extension, 606);
+  message->AddExtension(UNITTEST::packed_fixed32_extension, 607);
+  message->AddExtension(UNITTEST::packed_fixed64_extension, 608);
+  message->AddExtension(UNITTEST::packed_sfixed32_extension, 609);
+  message->AddExtension(UNITTEST::packed_sfixed64_extension, 610);
+  message->AddExtension(UNITTEST::packed_float_extension, 611);
+  message->AddExtension(UNITTEST::packed_double_extension, 612);
+  message->AddExtension(UNITTEST::packed_bool_extension, true);
+  message->AddExtension(UNITTEST::packed_enum_extension, UNITTEST::FOREIGN_BAR);
+  // add a second one of each field
+  message->AddExtension(UNITTEST::packed_int32_extension, 701);
+  message->AddExtension(UNITTEST::packed_int64_extension, 702);
+  message->AddExtension(UNITTEST::packed_uint32_extension, 703);
+  message->AddExtension(UNITTEST::packed_uint64_extension, 704);
+  message->AddExtension(UNITTEST::packed_sint32_extension, 705);
+  message->AddExtension(UNITTEST::packed_sint64_extension, 706);
+  message->AddExtension(UNITTEST::packed_fixed32_extension, 707);
+  message->AddExtension(UNITTEST::packed_fixed64_extension, 708);
+  message->AddExtension(UNITTEST::packed_sfixed32_extension, 709);
+  message->AddExtension(UNITTEST::packed_sfixed64_extension, 710);
+  message->AddExtension(UNITTEST::packed_float_extension, 711);
+  message->AddExtension(UNITTEST::packed_double_extension, 712);
+  message->AddExtension(UNITTEST::packed_bool_extension, false);
+  message->AddExtension(UNITTEST::packed_enum_extension, UNITTEST::FOREIGN_BAZ);
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectPackedExtensionsSet(
+    const UNITTEST::TestPackedExtensions& message) {
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_int32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_int64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_uint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_uint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_sint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_sint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_fixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_fixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_sfixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_sfixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_float_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_double_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_bool_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::packed_enum_extension));
+
+  EXPECT_EQ(601, message.GetExtension(UNITTEST::packed_int32_extension, 0));
+  EXPECT_EQ(602, message.GetExtension(UNITTEST::packed_int64_extension, 0));
+  EXPECT_EQ(603, message.GetExtension(UNITTEST::packed_uint32_extension, 0));
+  EXPECT_EQ(604, message.GetExtension(UNITTEST::packed_uint64_extension, 0));
+  EXPECT_EQ(605, message.GetExtension(UNITTEST::packed_sint32_extension, 0));
+  EXPECT_EQ(606, message.GetExtension(UNITTEST::packed_sint64_extension, 0));
+  EXPECT_EQ(607, message.GetExtension(UNITTEST::packed_fixed32_extension, 0));
+  EXPECT_EQ(608, message.GetExtension(UNITTEST::packed_fixed64_extension, 0));
+  EXPECT_EQ(609, message.GetExtension(UNITTEST::packed_sfixed32_extension, 0));
+  EXPECT_EQ(610, message.GetExtension(UNITTEST::packed_sfixed64_extension, 0));
+  EXPECT_EQ(611, message.GetExtension(UNITTEST::packed_float_extension, 0));
+  EXPECT_EQ(612, message.GetExtension(UNITTEST::packed_double_extension, 0));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::packed_bool_extension, 0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::packed_enum_extension, 0));
+  EXPECT_EQ(701, message.GetExtension(UNITTEST::packed_int32_extension, 1));
+  EXPECT_EQ(702, message.GetExtension(UNITTEST::packed_int64_extension, 1));
+  EXPECT_EQ(703, message.GetExtension(UNITTEST::packed_uint32_extension, 1));
+  EXPECT_EQ(704, message.GetExtension(UNITTEST::packed_uint64_extension, 1));
+  EXPECT_EQ(705, message.GetExtension(UNITTEST::packed_sint32_extension, 1));
+  EXPECT_EQ(706, message.GetExtension(UNITTEST::packed_sint64_extension, 1));
+  EXPECT_EQ(707, message.GetExtension(UNITTEST::packed_fixed32_extension, 1));
+  EXPECT_EQ(708, message.GetExtension(UNITTEST::packed_fixed64_extension, 1));
+  EXPECT_EQ(709, message.GetExtension(UNITTEST::packed_sfixed32_extension, 1));
+  EXPECT_EQ(710, message.GetExtension(UNITTEST::packed_sfixed64_extension, 1));
+  EXPECT_EQ(711, message.GetExtension(UNITTEST::packed_float_extension, 1));
+  EXPECT_EQ(712, message.GetExtension(UNITTEST::packed_double_extension, 1));
+  EXPECT_FALSE(message.GetExtension(UNITTEST::packed_bool_extension, 1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            message.GetExtension(UNITTEST::packed_enum_extension, 1));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectUnpackedExtensionsSet(
+    const UNITTEST::TestUnpackedExtensions& message) {
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_int32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_int64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_uint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_uint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_sint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_sint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_fixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_fixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_sfixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_sfixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_float_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_double_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_bool_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::unpacked_enum_extension));
+
+  EXPECT_EQ(601, message.GetExtension(UNITTEST::unpacked_int32_extension, 0));
+  EXPECT_EQ(602, message.GetExtension(UNITTEST::unpacked_int64_extension, 0));
+  EXPECT_EQ(603, message.GetExtension(UNITTEST::unpacked_uint32_extension, 0));
+  EXPECT_EQ(604, message.GetExtension(UNITTEST::unpacked_uint64_extension, 0));
+  EXPECT_EQ(605, message.GetExtension(UNITTEST::unpacked_sint32_extension, 0));
+  EXPECT_EQ(606, message.GetExtension(UNITTEST::unpacked_sint64_extension, 0));
+  EXPECT_EQ(607, message.GetExtension(UNITTEST::unpacked_fixed32_extension, 0));
+  EXPECT_EQ(608, message.GetExtension(UNITTEST::unpacked_fixed64_extension, 0));
+  EXPECT_EQ(609,
+            message.GetExtension(UNITTEST::unpacked_sfixed32_extension, 0));
+  EXPECT_EQ(610,
+            message.GetExtension(UNITTEST::unpacked_sfixed64_extension, 0));
+  EXPECT_EQ(611, message.GetExtension(UNITTEST::unpacked_float_extension, 0));
+  EXPECT_EQ(612, message.GetExtension(UNITTEST::unpacked_double_extension, 0));
+  EXPECT_EQ(true, message.GetExtension(UNITTEST::unpacked_bool_extension, 0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::unpacked_enum_extension, 0));
+  EXPECT_EQ(701, message.GetExtension(UNITTEST::unpacked_int32_extension, 1));
+  EXPECT_EQ(702, message.GetExtension(UNITTEST::unpacked_int64_extension, 1));
+  EXPECT_EQ(703, message.GetExtension(UNITTEST::unpacked_uint32_extension, 1));
+  EXPECT_EQ(704, message.GetExtension(UNITTEST::unpacked_uint64_extension, 1));
+  EXPECT_EQ(705, message.GetExtension(UNITTEST::unpacked_sint32_extension, 1));
+  EXPECT_EQ(706, message.GetExtension(UNITTEST::unpacked_sint64_extension, 1));
+  EXPECT_EQ(707, message.GetExtension(UNITTEST::unpacked_fixed32_extension, 1));
+  EXPECT_EQ(708, message.GetExtension(UNITTEST::unpacked_fixed64_extension, 1));
+  EXPECT_EQ(709,
+            message.GetExtension(UNITTEST::unpacked_sfixed32_extension, 1));
+  EXPECT_EQ(710,
+            message.GetExtension(UNITTEST::unpacked_sfixed64_extension, 1));
+  EXPECT_EQ(711, message.GetExtension(UNITTEST::unpacked_float_extension, 1));
+  EXPECT_EQ(712, message.GetExtension(UNITTEST::unpacked_double_extension, 1));
+  EXPECT_EQ(false, message.GetExtension(UNITTEST::unpacked_bool_extension, 1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            message.GetExtension(UNITTEST::unpacked_enum_extension, 1));
+}
+
+// -------------------------------------------------------------------
+
+inline void TestUtil::ExpectLastRepeatedsRemoved(
+    const UNITTEST::TestAllTypes& message) {
+  ASSERT_EQ(1, message.repeated_int32_size());
+  ASSERT_EQ(1, message.repeated_int64_size());
+  ASSERT_EQ(1, message.repeated_uint32_size());
+  ASSERT_EQ(1, message.repeated_uint64_size());
+  ASSERT_EQ(1, message.repeated_sint32_size());
+  ASSERT_EQ(1, message.repeated_sint64_size());
+  ASSERT_EQ(1, message.repeated_fixed32_size());
+  ASSERT_EQ(1, message.repeated_fixed64_size());
+  ASSERT_EQ(1, message.repeated_sfixed32_size());
+  ASSERT_EQ(1, message.repeated_sfixed64_size());
+  ASSERT_EQ(1, message.repeated_float_size());
+  ASSERT_EQ(1, message.repeated_double_size());
+  ASSERT_EQ(1, message.repeated_bool_size());
+  ASSERT_EQ(1, message.repeated_string_size());
+  ASSERT_EQ(1, message.repeated_bytes_size());
+
+  ASSERT_EQ(1, message.repeatedgroup_size());
+  ASSERT_EQ(1, message.repeated_nested_message_size());
+  ASSERT_EQ(1, message.repeated_foreign_message_size());
+  ASSERT_EQ(1, message.repeated_import_message_size());
+  ASSERT_EQ(1, message.repeated_import_message_size());
+  ASSERT_EQ(1, message.repeated_nested_enum_size());
+  ASSERT_EQ(1, message.repeated_foreign_enum_size());
+  ASSERT_EQ(1, message.repeated_import_enum_size());
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  ASSERT_EQ(1, message.repeated_string_piece_size());
+  ASSERT_EQ(1, message.repeated_cord_size());
+#endif
+
+  // Test that the remaining element is the correct one.
+  EXPECT_EQ(201, message.repeated_int32(0));
+  EXPECT_EQ(202, message.repeated_int64(0));
+  EXPECT_EQ(203, message.repeated_uint32(0));
+  EXPECT_EQ(204, message.repeated_uint64(0));
+  EXPECT_EQ(205, message.repeated_sint32(0));
+  EXPECT_EQ(206, message.repeated_sint64(0));
+  EXPECT_EQ(207, message.repeated_fixed32(0));
+  EXPECT_EQ(208, message.repeated_fixed64(0));
+  EXPECT_EQ(209, message.repeated_sfixed32(0));
+  EXPECT_EQ(210, message.repeated_sfixed64(0));
+  EXPECT_EQ(211, message.repeated_float(0));
+  EXPECT_EQ(212, message.repeated_double(0));
+  EXPECT_TRUE(message.repeated_bool(0));
+  EXPECT_EQ("215", message.repeated_string(0));
+  EXPECT_EQ("216", message.repeated_bytes(0));
+
+  EXPECT_EQ(217, message.repeatedgroup(0).a());
+  EXPECT_EQ(218, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message.repeated_nested_enum(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeated_foreign_enum(0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR, message.repeated_import_enum(0));
+}
+
+inline void TestUtil::ExpectLastRepeatedExtensionsRemoved(
+    const UNITTEST::TestAllExtensions& message) {
+  // Test that one element was removed.
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_int32_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_int64_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_uint32_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_uint64_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_sint32_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_sint64_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_fixed32_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_fixed64_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_sfixed32_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_sfixed64_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_float_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_double_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_bool_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_string_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_bytes_extension));
+
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeatedgroup_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_nested_message_extension));
+  ASSERT_EQ(
+      1, message.ExtensionSize(UNITTEST::repeated_foreign_message_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_import_message_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_lazy_message_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_nested_enum_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_foreign_enum_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_import_enum_extension));
+
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_string_piece_extension));
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeated_cord_extension));
+
+  // Test that the remaining element is the correct one.
+  EXPECT_EQ(201, message.GetExtension(UNITTEST::repeated_int32_extension, 0));
+  EXPECT_EQ(202, message.GetExtension(UNITTEST::repeated_int64_extension, 0));
+  EXPECT_EQ(203, message.GetExtension(UNITTEST::repeated_uint32_extension, 0));
+  EXPECT_EQ(204, message.GetExtension(UNITTEST::repeated_uint64_extension, 0));
+  EXPECT_EQ(205, message.GetExtension(UNITTEST::repeated_sint32_extension, 0));
+  EXPECT_EQ(206, message.GetExtension(UNITTEST::repeated_sint64_extension, 0));
+  EXPECT_EQ(207, message.GetExtension(UNITTEST::repeated_fixed32_extension, 0));
+  EXPECT_EQ(208, message.GetExtension(UNITTEST::repeated_fixed64_extension, 0));
+  EXPECT_EQ(209,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 0));
+  EXPECT_EQ(210,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 0));
+  EXPECT_EQ(211, message.GetExtension(UNITTEST::repeated_float_extension, 0));
+  EXPECT_EQ(212, message.GetExtension(UNITTEST::repeated_double_extension, 0));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::repeated_bool_extension, 0));
+  EXPECT_EQ("215",
+            message.GetExtension(UNITTEST::repeated_string_extension, 0));
+  EXPECT_EQ("216", message.GetExtension(UNITTEST::repeated_bytes_extension, 0));
+
+  EXPECT_EQ(217,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 0).a());
+  EXPECT_EQ(218,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 0)
+                .bb());
+  EXPECT_EQ(
+      219, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 0)
+               .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 0).d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 0).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 0));
+
+  EXPECT_EQ("224",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 0));
+  EXPECT_EQ("225", message.GetExtension(UNITTEST::repeated_cord_extension, 0));
+}
+
+inline void TestUtil::ExpectLastRepeatedsReleased(
+    const UNITTEST::TestAllTypes& message) {
+  ASSERT_EQ(1, message.repeatedgroup_size());
+  ASSERT_EQ(1, message.repeated_nested_message_size());
+  ASSERT_EQ(1, message.repeated_foreign_message_size());
+  ASSERT_EQ(1, message.repeated_import_message_size());
+  ASSERT_EQ(1, message.repeated_import_message_size());
+
+  EXPECT_EQ(217, message.repeatedgroup(0).a());
+  EXPECT_EQ(218, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+}
+
+inline void TestUtil::ExpectLastRepeatedExtensionsReleased(
+    const UNITTEST::TestAllExtensions& message) {
+  ASSERT_EQ(1, message.ExtensionSize(UNITTEST::repeatedgroup_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_nested_message_extension));
+  ASSERT_EQ(
+      1, message.ExtensionSize(UNITTEST::repeated_foreign_message_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_import_message_extension));
+  ASSERT_EQ(1,
+            message.ExtensionSize(UNITTEST::repeated_lazy_message_extension));
+
+  EXPECT_EQ(217,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 0).a());
+  EXPECT_EQ(218,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 0)
+                .bb());
+  EXPECT_EQ(
+      219, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 0)
+               .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 0).d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 0).bb());
+}
+
+inline void TestUtil::ExpectRepeatedsSwapped(
+    const UNITTEST::TestAllTypes& message) {
+  ASSERT_EQ(2, message.repeated_int32_size());
+  ASSERT_EQ(2, message.repeated_int64_size());
+  ASSERT_EQ(2, message.repeated_uint32_size());
+  ASSERT_EQ(2, message.repeated_uint64_size());
+  ASSERT_EQ(2, message.repeated_sint32_size());
+  ASSERT_EQ(2, message.repeated_sint64_size());
+  ASSERT_EQ(2, message.repeated_fixed32_size());
+  ASSERT_EQ(2, message.repeated_fixed64_size());
+  ASSERT_EQ(2, message.repeated_sfixed32_size());
+  ASSERT_EQ(2, message.repeated_sfixed64_size());
+  ASSERT_EQ(2, message.repeated_float_size());
+  ASSERT_EQ(2, message.repeated_double_size());
+  ASSERT_EQ(2, message.repeated_bool_size());
+  ASSERT_EQ(2, message.repeated_string_size());
+  ASSERT_EQ(2, message.repeated_bytes_size());
+
+  ASSERT_EQ(2, message.repeatedgroup_size());
+  ASSERT_EQ(2, message.repeated_nested_message_size());
+  ASSERT_EQ(2, message.repeated_foreign_message_size());
+  ASSERT_EQ(2, message.repeated_import_message_size());
+  ASSERT_EQ(2, message.repeated_import_message_size());
+  ASSERT_EQ(2, message.repeated_nested_enum_size());
+  ASSERT_EQ(2, message.repeated_foreign_enum_size());
+  ASSERT_EQ(2, message.repeated_import_enum_size());
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+  ASSERT_EQ(2, message.repeated_string_piece_size());
+  ASSERT_EQ(2, message.repeated_cord_size());
+#endif
+
+  // Test that the first element and second element are flipped.
+  EXPECT_EQ(201, message.repeated_int32(1));
+  EXPECT_EQ(202, message.repeated_int64(1));
+  EXPECT_EQ(203, message.repeated_uint32(1));
+  EXPECT_EQ(204, message.repeated_uint64(1));
+  EXPECT_EQ(205, message.repeated_sint32(1));
+  EXPECT_EQ(206, message.repeated_sint64(1));
+  EXPECT_EQ(207, message.repeated_fixed32(1));
+  EXPECT_EQ(208, message.repeated_fixed64(1));
+  EXPECT_EQ(209, message.repeated_sfixed32(1));
+  EXPECT_EQ(210, message.repeated_sfixed64(1));
+  EXPECT_EQ(211, message.repeated_float(1));
+  EXPECT_EQ(212, message.repeated_double(1));
+  EXPECT_TRUE(message.repeated_bool(1));
+  EXPECT_EQ("215", message.repeated_string(1));
+  EXPECT_EQ("216", message.repeated_bytes(1));
+
+  EXPECT_EQ(217, message.repeatedgroup(1).a());
+  EXPECT_EQ(218, message.repeated_nested_message(1).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(1).c());
+  EXPECT_EQ(220, message.repeated_import_message(1).d());
+  EXPECT_EQ(220, message.repeated_import_message(1).d());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message.repeated_nested_enum(1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR, message.repeated_foreign_enum(1));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR, message.repeated_import_enum(1));
+
+  EXPECT_EQ(301, message.repeated_int32(0));
+  EXPECT_EQ(302, message.repeated_int64(0));
+  EXPECT_EQ(303, message.repeated_uint32(0));
+  EXPECT_EQ(304, message.repeated_uint64(0));
+  EXPECT_EQ(305, message.repeated_sint32(0));
+  EXPECT_EQ(306, message.repeated_sint64(0));
+  EXPECT_EQ(307, message.repeated_fixed32(0));
+  EXPECT_EQ(308, message.repeated_fixed64(0));
+  EXPECT_EQ(309, message.repeated_sfixed32(0));
+  EXPECT_EQ(310, message.repeated_sfixed64(0));
+  EXPECT_EQ(311, message.repeated_float(0));
+  EXPECT_EQ(312, message.repeated_double(0));
+  EXPECT_FALSE(message.repeated_bool(0));
+  EXPECT_EQ("315", message.repeated_string(0));
+  EXPECT_EQ("316", message.repeated_bytes(0));
+
+  EXPECT_EQ(317, message.repeatedgroup(0).a());
+  EXPECT_EQ(318, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(319, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(320, message.repeated_import_message(0).d());
+  EXPECT_EQ(320, message.repeated_import_message(0).d());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ, message.repeated_nested_enum(0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.repeated_foreign_enum(0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.repeated_import_enum(0));
+}
+
+inline void TestUtil::ExpectRepeatedExtensionsSwapped(
+    const UNITTEST::TestAllExtensions& message) {
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_int32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_int64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_uint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_uint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sint32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sint64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_fixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_fixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sfixed32_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_sfixed64_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_float_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_double_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_bool_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_string_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_bytes_extension));
+
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeatedgroup_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_nested_message_extension));
+  ASSERT_EQ(
+      2, message.ExtensionSize(UNITTEST::repeated_foreign_message_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_import_message_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_lazy_message_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_nested_enum_extension));
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_foreign_enum_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_import_enum_extension));
+
+  ASSERT_EQ(2,
+            message.ExtensionSize(UNITTEST::repeated_string_piece_extension));
+  ASSERT_EQ(2, message.ExtensionSize(UNITTEST::repeated_cord_extension));
+
+  EXPECT_EQ(201, message.GetExtension(UNITTEST::repeated_int32_extension, 1));
+  EXPECT_EQ(202, message.GetExtension(UNITTEST::repeated_int64_extension, 1));
+  EXPECT_EQ(203, message.GetExtension(UNITTEST::repeated_uint32_extension, 1));
+  EXPECT_EQ(204, message.GetExtension(UNITTEST::repeated_uint64_extension, 1));
+  EXPECT_EQ(205, message.GetExtension(UNITTEST::repeated_sint32_extension, 1));
+  EXPECT_EQ(206, message.GetExtension(UNITTEST::repeated_sint64_extension, 1));
+  EXPECT_EQ(207, message.GetExtension(UNITTEST::repeated_fixed32_extension, 1));
+  EXPECT_EQ(208, message.GetExtension(UNITTEST::repeated_fixed64_extension, 1));
+  EXPECT_EQ(209,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 1));
+  EXPECT_EQ(210,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 1));
+  EXPECT_EQ(211, message.GetExtension(UNITTEST::repeated_float_extension, 1));
+  EXPECT_EQ(212, message.GetExtension(UNITTEST::repeated_double_extension, 1));
+  EXPECT_TRUE(message.GetExtension(UNITTEST::repeated_bool_extension, 1));
+  EXPECT_EQ("215",
+            message.GetExtension(UNITTEST::repeated_string_extension, 1));
+  EXPECT_EQ("216", message.GetExtension(UNITTEST::repeated_bytes_extension, 1));
+
+  EXPECT_EQ(217,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 1).a());
+  EXPECT_EQ(218,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 1)
+                .bb());
+  EXPECT_EQ(
+      219, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 1)
+               .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 1).d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 1).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAR,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 1));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAR,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 1));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAR,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 1));
+
+  EXPECT_EQ("224",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 1));
+  EXPECT_EQ("225", message.GetExtension(UNITTEST::repeated_cord_extension, 1));
+
+  EXPECT_EQ(301, message.GetExtension(UNITTEST::repeated_int32_extension, 0));
+  EXPECT_EQ(302, message.GetExtension(UNITTEST::repeated_int64_extension, 0));
+  EXPECT_EQ(303, message.GetExtension(UNITTEST::repeated_uint32_extension, 0));
+  EXPECT_EQ(304, message.GetExtension(UNITTEST::repeated_uint64_extension, 0));
+  EXPECT_EQ(305, message.GetExtension(UNITTEST::repeated_sint32_extension, 0));
+  EXPECT_EQ(306, message.GetExtension(UNITTEST::repeated_sint64_extension, 0));
+  EXPECT_EQ(307, message.GetExtension(UNITTEST::repeated_fixed32_extension, 0));
+  EXPECT_EQ(308, message.GetExtension(UNITTEST::repeated_fixed64_extension, 0));
+  EXPECT_EQ(309,
+            message.GetExtension(UNITTEST::repeated_sfixed32_extension, 0));
+  EXPECT_EQ(310,
+            message.GetExtension(UNITTEST::repeated_sfixed64_extension, 0));
+  EXPECT_EQ(311, message.GetExtension(UNITTEST::repeated_float_extension, 0));
+  EXPECT_EQ(312, message.GetExtension(UNITTEST::repeated_double_extension, 0));
+  EXPECT_FALSE(message.GetExtension(UNITTEST::repeated_bool_extension, 0));
+  EXPECT_EQ("315",
+            message.GetExtension(UNITTEST::repeated_string_extension, 0));
+  EXPECT_EQ("316", message.GetExtension(UNITTEST::repeated_bytes_extension, 0));
+
+  EXPECT_EQ(317,
+            message.GetExtension(UNITTEST::repeatedgroup_extension, 0).a());
+  EXPECT_EQ(318,
+            message.GetExtension(UNITTEST::repeated_nested_message_extension, 0)
+                .bb());
+  EXPECT_EQ(
+      319, message.GetExtension(UNITTEST::repeated_foreign_message_extension, 0)
+               .c());
+  EXPECT_EQ(
+      320,
+      message.GetExtension(UNITTEST::repeated_import_message_extension, 0).d());
+  EXPECT_EQ(
+      327,
+      message.GetExtension(UNITTEST::repeated_lazy_message_extension, 0).bb());
+
+  EXPECT_EQ(UNITTEST::TestAllTypes::BAZ,
+            message.GetExtension(UNITTEST::repeated_nested_enum_extension, 0));
+  EXPECT_EQ(UNITTEST::FOREIGN_BAZ,
+            message.GetExtension(UNITTEST::repeated_foreign_enum_extension, 0));
+  EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ,
+            message.GetExtension(UNITTEST::repeated_import_enum_extension, 0));
+
+  EXPECT_EQ("324",
+            message.GetExtension(UNITTEST::repeated_string_piece_extension, 0));
+  EXPECT_EQ("325", message.GetExtension(UNITTEST::repeated_cord_extension, 0));
+}
+
+inline void TestUtil::SetOneof1(UNITTEST::TestOneof2* message) {
+  message->mutable_foo_lazy_message()->set_moo_int(100);
+  message->set_bar_string("101");
+  message->set_baz_int(102);
+  message->set_baz_string("103");
+}
+
+inline void TestUtil::SetOneof2(UNITTEST::TestOneof2* message) {
+  message->set_foo_int(200);
+  message->set_bar_enum(UNITTEST::TestOneof2::BAZ);
+  message->set_baz_int(202);
+  message->set_baz_string("203");
+}
+
+inline void TestUtil::ExpectOneofSet1(const UNITTEST::TestOneof2& message) {
+  ExpectAtMostOneFieldSetInOneof(message);
+
+  EXPECT_TRUE(message.has_foo_lazy_message());
+  EXPECT_TRUE(message.foo_lazy_message().has_moo_int());
+
+  EXPECT_TRUE(message.has_bar_string());
+  EXPECT_TRUE(message.has_baz_int());
+  EXPECT_TRUE(message.has_baz_string());
+
+  ASSERT_EQ(0, message.foo_lazy_message().corge_int_size());
+
+  EXPECT_EQ(100, message.foo_lazy_message().moo_int());
+  EXPECT_EQ("101", message.bar_string());
+  EXPECT_EQ(102, message.baz_int());
+  EXPECT_EQ("103", message.baz_string());
+}
+
+inline void TestUtil::ExpectOneofSet2(const UNITTEST::TestOneof2& message) {
+  ExpectAtMostOneFieldSetInOneof(message);
+
+  EXPECT_TRUE(message.has_foo_int());
+  EXPECT_TRUE(message.has_bar_enum());
+  EXPECT_TRUE(message.has_baz_int());
+  EXPECT_TRUE(message.has_baz_string());
+
+  EXPECT_EQ(200, message.foo_int());
+  EXPECT_EQ(UNITTEST::TestOneof2::BAZ, message.bar_enum());
+  EXPECT_EQ(202, message.baz_int());
+  EXPECT_EQ("203", message.baz_string());
+}
+
+inline void TestUtil::ExpectOneofClear(const UNITTEST::TestOneof2& message) {
+  EXPECT_FALSE(message.has_foo_int());
+  EXPECT_FALSE(message.has_foo_string());
+  EXPECT_FALSE(message.has_foo_bytes());
+  EXPECT_FALSE(message.has_foo_enum());
+  EXPECT_FALSE(message.has_foo_message());
+  EXPECT_FALSE(message.has_foogroup());
+  EXPECT_FALSE(message.has_foo_lazy_message());
+
+  EXPECT_FALSE(message.has_bar_int());
+  EXPECT_FALSE(message.has_bar_string());
+  EXPECT_FALSE(message.has_bar_bytes());
+  EXPECT_FALSE(message.has_bar_enum());
+
+  EXPECT_FALSE(message.has_baz_int());
+  EXPECT_FALSE(message.has_baz_string());
+
+  EXPECT_EQ(UNITTEST::TestOneof2::FOO_NOT_SET, message.foo_case());
+  EXPECT_EQ(UNITTEST::TestOneof2::BAR_NOT_SET, message.bar_case());
+}
+
+inline void TestUtil::ExpectAtMostOneFieldSetInOneof(
+    const UNITTEST::TestOneof2& message) {
+  int count = 0;
+  if (message.has_foo_int()) count++;
+  if (message.has_foo_string()) count++;
+  if (message.has_foo_bytes()) count++;
+  if (message.has_foo_enum()) count++;
+  if (message.has_foo_message()) count++;
+  if (message.has_foogroup()) count++;
+  if (message.has_foo_lazy_message()) count++;
+  EXPECT_LE(count, 1);
+  count = 0;
+  if (message.has_bar_int()) count++;
+  if (message.has_bar_string()) count++;
+  if (message.has_bar_bytes()) count++;
+  if (message.has_bar_enum()) count++;
+  EXPECT_TRUE(count == 0 || count == 1);
+}
+
+// ===================================================================
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/test_util2.h b/src/google/protobuf/test_util2.h
new file mode 100644
index 0000000..540af63
--- /dev/null
+++ b/src/google/protobuf/test_util2.h
@@ -0,0 +1,106 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_TEST_UTIL2_H__
+#define GOOGLE_PROTOBUF_TEST_UTIL2_H__
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/util/message_differencer.h>
+
+namespace google {
+namespace protobuf {
+namespace TestUtil {
+
+// Translate net/proto2/* -> google/protobuf/*
+inline std::string TranslatePathToOpensource(const std::string& google3_path) {
+  const std::string prefix = "net/proto2/";
+  GOOGLE_CHECK(google3_path.find(prefix) == 0) << google3_path;
+  std::string path = google3_path.substr(prefix.size());
+
+  path = StringReplace(path, "internal/", "", false);
+  path = StringReplace(path, "proto/", "", false);
+  path = StringReplace(path, "public/", "", false);
+  return "google/protobuf/" + path;
+}
+
+inline std::string MaybeTranslatePath(const std::string& google3_path) {
+  std::string path = google3_path;
+  path = TranslatePathToOpensource(path);
+  return path;
+}
+
+inline std::string TestSourceDir() {
+  return google::protobuf::TestSourceDir();
+}
+
+inline std::string GetTestDataPath(const std::string& google3_path) {
+  return TestSourceDir() + "/" + MaybeTranslatePath(google3_path);
+}
+
+// Checks the equality of "message" and serialized proto of type "ProtoType".
+// Do not directly compare two serialized protos.
+template <typename ProtoType>
+bool EqualsToSerialized(const ProtoType& message, const std::string& data) {
+  ProtoType other;
+  other.ParsePartialFromString(data);
+  return util::MessageDifferencer::Equals(message, other);
+}
+
+// Wraps io::ArrayInputStream while checking against bound. When a blocking
+// stream is used with bounded length, proto parsing must not access beyond the
+// bound. Otherwise, it can result in unintended block, then deadlock.
+class BoundedArrayInputStream : public io::ZeroCopyInputStream {
+ public:
+  BoundedArrayInputStream(const void* data, int size)
+      : stream_(data, size), bound_(size) {}
+  ~BoundedArrayInputStream() override {}
+
+  bool Next(const void** data, int* size) override {
+    GOOGLE_CHECK_LT(stream_.ByteCount(), bound_);
+    return stream_.Next(data, size);
+  }
+  void BackUp(int count) override { stream_.BackUp(count); }
+  bool Skip(int count) override { return stream_.Skip(count); }
+  int64_t ByteCount() const override { return stream_.ByteCount(); }
+
+ private:
+  io::ArrayInputStream stream_;
+  int bound_;
+};
+
+}  // namespace TestUtil
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_TEST_UTIL2_H__
diff --git a/src/google/protobuf/test_util_lite.cc b/src/google/protobuf/test_util_lite.cc
new file mode 100644
index 0000000..628f1a0
--- /dev/null
+++ b/src/google/protobuf/test_util_lite.cc
@@ -0,0 +1,1991 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/test_util_lite.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+
+void TestUtilLite::SetAllFields(unittest::TestAllTypesLite* message) {
+  message->set_optional_int32(101);
+  message->set_optional_int64(102);
+  message->set_optional_uint32(103);
+  message->set_optional_uint64(104);
+  message->set_optional_sint32(105);
+  message->set_optional_sint64(106);
+  message->set_optional_fixed32(107);
+  message->set_optional_fixed64(108);
+  message->set_optional_sfixed32(109);
+  message->set_optional_sfixed64(110);
+  message->set_optional_float(111);
+  message->set_optional_double(112);
+  message->set_optional_bool(true);
+  message->set_optional_string("115");
+  message->set_optional_bytes("116");
+
+  message->mutable_optionalgroup()->set_a(117);
+  message->mutable_optional_nested_message()->set_bb(118);
+  message->mutable_optional_foreign_message()->set_c(119);
+  message->mutable_optional_import_message()->set_d(120);
+  message->mutable_optional_public_import_message()->set_e(126);
+  message->mutable_optional_lazy_message()->set_bb(127);
+  message->mutable_optional_unverified_lazy_message()->set_bb(128);
+
+  message->set_optional_nested_enum(unittest::TestAllTypesLite::BAZ);
+  message->set_optional_foreign_enum(unittest::FOREIGN_LITE_BAZ);
+  message->set_optional_import_enum(unittest_import::IMPORT_LITE_BAZ);
+
+
+  // -----------------------------------------------------------------
+
+  message->add_repeated_int32(201);
+  message->add_repeated_int64(202);
+  message->add_repeated_uint32(203);
+  message->add_repeated_uint64(204);
+  message->add_repeated_sint32(205);
+  message->add_repeated_sint64(206);
+  message->add_repeated_fixed32(207);
+  message->add_repeated_fixed64(208);
+  message->add_repeated_sfixed32(209);
+  message->add_repeated_sfixed64(210);
+  message->add_repeated_float(211);
+  message->add_repeated_double(212);
+  message->add_repeated_bool(true);
+  message->add_repeated_string("215");
+  message->add_repeated_bytes("216");
+
+  message->add_repeatedgroup()->set_a(217);
+  message->add_repeated_nested_message()->set_bb(218);
+  message->add_repeated_foreign_message()->set_c(219);
+  message->add_repeated_import_message()->set_d(220);
+  message->add_repeated_lazy_message()->set_bb(227);
+
+  message->add_repeated_nested_enum(unittest::TestAllTypesLite::BAR);
+  message->add_repeated_foreign_enum(unittest::FOREIGN_LITE_BAR);
+  message->add_repeated_import_enum(unittest_import::IMPORT_LITE_BAR);
+
+
+  // Add a second one of each field.
+  message->add_repeated_int32(301);
+  message->add_repeated_int64(302);
+  message->add_repeated_uint32(303);
+  message->add_repeated_uint64(304);
+  message->add_repeated_sint32(305);
+  message->add_repeated_sint64(306);
+  message->add_repeated_fixed32(307);
+  message->add_repeated_fixed64(308);
+  message->add_repeated_sfixed32(309);
+  message->add_repeated_sfixed64(310);
+  message->add_repeated_float(311);
+  message->add_repeated_double(312);
+  message->add_repeated_bool(false);
+  message->add_repeated_string("315");
+  message->add_repeated_bytes("316");
+
+  message->add_repeatedgroup()->set_a(317);
+  message->add_repeated_nested_message()->set_bb(318);
+  message->add_repeated_foreign_message()->set_c(319);
+  message->add_repeated_import_message()->set_d(320);
+  message->add_repeated_lazy_message()->set_bb(327);
+
+  message->add_repeated_nested_enum(unittest::TestAllTypesLite::BAZ);
+  message->add_repeated_foreign_enum(unittest::FOREIGN_LITE_BAZ);
+  message->add_repeated_import_enum(unittest_import::IMPORT_LITE_BAZ);
+
+
+  // -----------------------------------------------------------------
+
+  message->set_default_int32(401);
+  message->set_default_int64(402);
+  message->set_default_uint32(403);
+  message->set_default_uint64(404);
+  message->set_default_sint32(405);
+  message->set_default_sint64(406);
+  message->set_default_fixed32(407);
+  message->set_default_fixed64(408);
+  message->set_default_sfixed32(409);
+  message->set_default_sfixed64(410);
+  message->set_default_float(411);
+  message->set_default_double(412);
+  message->set_default_bool(false);
+  message->set_default_string("415");
+  message->set_default_bytes("416");
+
+  message->set_default_nested_enum(unittest::TestAllTypesLite::FOO);
+  message->set_default_foreign_enum(unittest::FOREIGN_LITE_FOO);
+  message->set_default_import_enum(unittest_import::IMPORT_LITE_FOO);
+
+
+  message->set_oneof_uint32(601);
+  message->mutable_oneof_nested_message()->set_bb(602);
+  message->set_oneof_string("603");
+  message->set_oneof_bytes("604");
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ModifyRepeatedFields(unittest::TestAllTypesLite* message) {
+  message->set_repeated_int32(1, 501);
+  message->set_repeated_int64(1, 502);
+  message->set_repeated_uint32(1, 503);
+  message->set_repeated_uint64(1, 504);
+  message->set_repeated_sint32(1, 505);
+  message->set_repeated_sint64(1, 506);
+  message->set_repeated_fixed32(1, 507);
+  message->set_repeated_fixed64(1, 508);
+  message->set_repeated_sfixed32(1, 509);
+  message->set_repeated_sfixed64(1, 510);
+  message->set_repeated_float(1, 511);
+  message->set_repeated_double(1, 512);
+  message->set_repeated_bool(1, true);
+  message->set_repeated_string(1, "515");
+  message->set_repeated_bytes(1, "516");
+
+  message->mutable_repeatedgroup(1)->set_a(517);
+  message->mutable_repeated_nested_message(1)->set_bb(518);
+  message->mutable_repeated_foreign_message(1)->set_c(519);
+  message->mutable_repeated_import_message(1)->set_d(520);
+  message->mutable_repeated_lazy_message(1)->set_bb(527);
+
+  message->set_repeated_nested_enum(1, unittest::TestAllTypesLite::FOO);
+  message->set_repeated_foreign_enum(1, unittest::FOREIGN_LITE_FOO);
+  message->set_repeated_import_enum(1, unittest_import::IMPORT_LITE_FOO);
+
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectAllFieldsSet(
+    const unittest::TestAllTypesLite& message) {
+  EXPECT_TRUE(message.has_optional_int32());
+  EXPECT_TRUE(message.has_optional_int64());
+  EXPECT_TRUE(message.has_optional_uint32());
+  EXPECT_TRUE(message.has_optional_uint64());
+  EXPECT_TRUE(message.has_optional_sint32());
+  EXPECT_TRUE(message.has_optional_sint64());
+  EXPECT_TRUE(message.has_optional_fixed32());
+  EXPECT_TRUE(message.has_optional_fixed64());
+  EXPECT_TRUE(message.has_optional_sfixed32());
+  EXPECT_TRUE(message.has_optional_sfixed64());
+  EXPECT_TRUE(message.has_optional_float());
+  EXPECT_TRUE(message.has_optional_double());
+  EXPECT_TRUE(message.has_optional_bool());
+  EXPECT_TRUE(message.has_optional_string());
+  EXPECT_TRUE(message.has_optional_bytes());
+
+  EXPECT_TRUE(message.has_optionalgroup());
+  EXPECT_TRUE(message.has_optional_nested_message());
+  EXPECT_TRUE(message.has_optional_foreign_message());
+  EXPECT_TRUE(message.has_optional_import_message());
+  EXPECT_TRUE(message.has_optional_public_import_message());
+  EXPECT_TRUE(message.has_optional_lazy_message());
+  EXPECT_TRUE(message.has_optional_unverified_lazy_message());
+
+  EXPECT_TRUE(message.optionalgroup().has_a());
+  EXPECT_TRUE(message.optional_nested_message().has_bb());
+  EXPECT_TRUE(message.optional_foreign_message().has_c());
+  EXPECT_TRUE(message.optional_import_message().has_d());
+  EXPECT_TRUE(message.optional_public_import_message().has_e());
+  EXPECT_TRUE(message.optional_lazy_message().has_bb());
+  EXPECT_TRUE(message.optional_unverified_lazy_message().has_bb());
+
+  EXPECT_TRUE(message.has_optional_nested_enum());
+  EXPECT_TRUE(message.has_optional_foreign_enum());
+  EXPECT_TRUE(message.has_optional_import_enum());
+
+
+  EXPECT_EQ(101, message.optional_int32());
+  EXPECT_EQ(102, message.optional_int64());
+  EXPECT_EQ(103, message.optional_uint32());
+  EXPECT_EQ(104, message.optional_uint64());
+  EXPECT_EQ(105, message.optional_sint32());
+  EXPECT_EQ(106, message.optional_sint64());
+  EXPECT_EQ(107, message.optional_fixed32());
+  EXPECT_EQ(108, message.optional_fixed64());
+  EXPECT_EQ(109, message.optional_sfixed32());
+  EXPECT_EQ(110, message.optional_sfixed64());
+  EXPECT_EQ(111, message.optional_float());
+  EXPECT_EQ(112, message.optional_double());
+  EXPECT_EQ(true, message.optional_bool());
+  EXPECT_EQ("115", message.optional_string());
+  EXPECT_EQ("116", message.optional_bytes());
+
+  EXPECT_EQ(117, message.optionalgroup().a());
+  EXPECT_EQ(118, message.optional_nested_message().bb());
+  EXPECT_EQ(119, message.optional_foreign_message().c());
+  EXPECT_EQ(120, message.optional_import_message().d());
+  EXPECT_EQ(126, message.optional_public_import_message().e());
+  EXPECT_EQ(127, message.optional_lazy_message().bb());
+  EXPECT_EQ(128, message.optional_unverified_lazy_message().bb());
+
+  EXPECT_EQ(unittest::TestAllTypesLite::BAZ, message.optional_nested_enum());
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAZ, message.optional_foreign_enum());
+  EXPECT_EQ(unittest_import::IMPORT_LITE_BAZ, message.optional_import_enum());
+
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, message.repeated_int32_size());
+  ASSERT_EQ(2, message.repeated_int64_size());
+  ASSERT_EQ(2, message.repeated_uint32_size());
+  ASSERT_EQ(2, message.repeated_uint64_size());
+  ASSERT_EQ(2, message.repeated_sint32_size());
+  ASSERT_EQ(2, message.repeated_sint64_size());
+  ASSERT_EQ(2, message.repeated_fixed32_size());
+  ASSERT_EQ(2, message.repeated_fixed64_size());
+  ASSERT_EQ(2, message.repeated_sfixed32_size());
+  ASSERT_EQ(2, message.repeated_sfixed64_size());
+  ASSERT_EQ(2, message.repeated_float_size());
+  ASSERT_EQ(2, message.repeated_double_size());
+  ASSERT_EQ(2, message.repeated_bool_size());
+  ASSERT_EQ(2, message.repeated_string_size());
+  ASSERT_EQ(2, message.repeated_bytes_size());
+
+  ASSERT_EQ(2, message.repeatedgroup_size());
+  ASSERT_EQ(2, message.repeated_nested_message_size());
+  ASSERT_EQ(2, message.repeated_foreign_message_size());
+  ASSERT_EQ(2, message.repeated_import_message_size());
+  ASSERT_EQ(2, message.repeated_lazy_message_size());
+  ASSERT_EQ(2, message.repeated_nested_enum_size());
+  ASSERT_EQ(2, message.repeated_foreign_enum_size());
+  ASSERT_EQ(2, message.repeated_import_enum_size());
+
+
+  EXPECT_EQ(201, message.repeated_int32(0));
+  EXPECT_EQ(202, message.repeated_int64(0));
+  EXPECT_EQ(203, message.repeated_uint32(0));
+  EXPECT_EQ(204, message.repeated_uint64(0));
+  EXPECT_EQ(205, message.repeated_sint32(0));
+  EXPECT_EQ(206, message.repeated_sint64(0));
+  EXPECT_EQ(207, message.repeated_fixed32(0));
+  EXPECT_EQ(208, message.repeated_fixed64(0));
+  EXPECT_EQ(209, message.repeated_sfixed32(0));
+  EXPECT_EQ(210, message.repeated_sfixed64(0));
+  EXPECT_EQ(211, message.repeated_float(0));
+  EXPECT_EQ(212, message.repeated_double(0));
+  EXPECT_EQ(true, message.repeated_bool(0));
+  EXPECT_EQ("215", message.repeated_string(0));
+  EXPECT_EQ("216", message.repeated_bytes(0));
+
+  EXPECT_EQ(217, message.repeatedgroup(0).a());
+  EXPECT_EQ(218, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+  EXPECT_EQ(227, message.repeated_lazy_message(0).bb());
+
+
+  EXPECT_EQ(unittest::TestAllTypesLite::BAR, message.repeated_nested_enum(0));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR, message.repeated_foreign_enum(0));
+  EXPECT_EQ(unittest_import::IMPORT_LITE_BAR, message.repeated_import_enum(0));
+
+  EXPECT_EQ(301, message.repeated_int32(1));
+  EXPECT_EQ(302, message.repeated_int64(1));
+  EXPECT_EQ(303, message.repeated_uint32(1));
+  EXPECT_EQ(304, message.repeated_uint64(1));
+  EXPECT_EQ(305, message.repeated_sint32(1));
+  EXPECT_EQ(306, message.repeated_sint64(1));
+  EXPECT_EQ(307, message.repeated_fixed32(1));
+  EXPECT_EQ(308, message.repeated_fixed64(1));
+  EXPECT_EQ(309, message.repeated_sfixed32(1));
+  EXPECT_EQ(310, message.repeated_sfixed64(1));
+  EXPECT_EQ(311, message.repeated_float(1));
+  EXPECT_EQ(312, message.repeated_double(1));
+  EXPECT_EQ(false, message.repeated_bool(1));
+  EXPECT_EQ("315", message.repeated_string(1));
+  EXPECT_EQ("316", message.repeated_bytes(1));
+
+  EXPECT_EQ(317, message.repeatedgroup(1).a());
+  EXPECT_EQ(318, message.repeated_nested_message(1).bb());
+  EXPECT_EQ(319, message.repeated_foreign_message(1).c());
+  EXPECT_EQ(320, message.repeated_import_message(1).d());
+  EXPECT_EQ(327, message.repeated_lazy_message(1).bb());
+
+  EXPECT_EQ(unittest::TestAllTypesLite::BAZ, message.repeated_nested_enum(1));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAZ, message.repeated_foreign_enum(1));
+  EXPECT_EQ(unittest_import::IMPORT_LITE_BAZ, message.repeated_import_enum(1));
+
+
+  // -----------------------------------------------------------------
+
+  EXPECT_TRUE(message.has_default_int32());
+  EXPECT_TRUE(message.has_default_int64());
+  EXPECT_TRUE(message.has_default_uint32());
+  EXPECT_TRUE(message.has_default_uint64());
+  EXPECT_TRUE(message.has_default_sint32());
+  EXPECT_TRUE(message.has_default_sint64());
+  EXPECT_TRUE(message.has_default_fixed32());
+  EXPECT_TRUE(message.has_default_fixed64());
+  EXPECT_TRUE(message.has_default_sfixed32());
+  EXPECT_TRUE(message.has_default_sfixed64());
+  EXPECT_TRUE(message.has_default_float());
+  EXPECT_TRUE(message.has_default_double());
+  EXPECT_TRUE(message.has_default_bool());
+  EXPECT_TRUE(message.has_default_string());
+  EXPECT_TRUE(message.has_default_bytes());
+
+  EXPECT_TRUE(message.has_default_nested_enum());
+  EXPECT_TRUE(message.has_default_foreign_enum());
+  EXPECT_TRUE(message.has_default_import_enum());
+
+
+  EXPECT_EQ(401, message.default_int32());
+  EXPECT_EQ(402, message.default_int64());
+  EXPECT_EQ(403, message.default_uint32());
+  EXPECT_EQ(404, message.default_uint64());
+  EXPECT_EQ(405, message.default_sint32());
+  EXPECT_EQ(406, message.default_sint64());
+  EXPECT_EQ(407, message.default_fixed32());
+  EXPECT_EQ(408, message.default_fixed64());
+  EXPECT_EQ(409, message.default_sfixed32());
+  EXPECT_EQ(410, message.default_sfixed64());
+  EXPECT_EQ(411, message.default_float());
+  EXPECT_EQ(412, message.default_double());
+  EXPECT_EQ(false, message.default_bool());
+  EXPECT_EQ("415", message.default_string());
+  EXPECT_EQ("416", message.default_bytes());
+
+  EXPECT_EQ(unittest::TestAllTypesLite::FOO, message.default_nested_enum());
+  EXPECT_EQ(unittest::FOREIGN_LITE_FOO, message.default_foreign_enum());
+  EXPECT_EQ(unittest_import::IMPORT_LITE_FOO, message.default_import_enum());
+
+
+  EXPECT_FALSE(message.has_oneof_uint32());
+  EXPECT_FALSE(message.has_oneof_nested_message());
+  EXPECT_FALSE(message.has_oneof_string());
+  EXPECT_TRUE(message.has_oneof_bytes());
+
+  EXPECT_EQ("604", message.oneof_bytes());
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectClear(const unittest::TestAllTypesLite& message) {
+  // has_blah() should initially be false for all optional fields.
+  EXPECT_FALSE(message.has_optional_int32());
+  EXPECT_FALSE(message.has_optional_int64());
+  EXPECT_FALSE(message.has_optional_uint32());
+  EXPECT_FALSE(message.has_optional_uint64());
+  EXPECT_FALSE(message.has_optional_sint32());
+  EXPECT_FALSE(message.has_optional_sint64());
+  EXPECT_FALSE(message.has_optional_fixed32());
+  EXPECT_FALSE(message.has_optional_fixed64());
+  EXPECT_FALSE(message.has_optional_sfixed32());
+  EXPECT_FALSE(message.has_optional_sfixed64());
+  EXPECT_FALSE(message.has_optional_float());
+  EXPECT_FALSE(message.has_optional_double());
+  EXPECT_FALSE(message.has_optional_bool());
+  EXPECT_FALSE(message.has_optional_string());
+  EXPECT_FALSE(message.has_optional_bytes());
+
+  EXPECT_FALSE(message.has_optionalgroup());
+  EXPECT_FALSE(message.has_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_foreign_message());
+  EXPECT_FALSE(message.has_optional_import_message());
+  EXPECT_FALSE(message.has_optional_public_import_message());
+  EXPECT_FALSE(message.has_optional_lazy_message());
+  EXPECT_FALSE(message.has_optional_unverified_lazy_message());
+
+  EXPECT_FALSE(message.has_optional_nested_enum());
+  EXPECT_FALSE(message.has_optional_foreign_enum());
+  EXPECT_FALSE(message.has_optional_import_enum());
+
+
+  // Optional fields without defaults are set to zero or something like it.
+  EXPECT_EQ(0, message.optional_int32());
+  EXPECT_EQ(0, message.optional_int64());
+  EXPECT_EQ(0, message.optional_uint32());
+  EXPECT_EQ(0, message.optional_uint64());
+  EXPECT_EQ(0, message.optional_sint32());
+  EXPECT_EQ(0, message.optional_sint64());
+  EXPECT_EQ(0, message.optional_fixed32());
+  EXPECT_EQ(0, message.optional_fixed64());
+  EXPECT_EQ(0, message.optional_sfixed32());
+  EXPECT_EQ(0, message.optional_sfixed64());
+  EXPECT_EQ(0, message.optional_float());
+  EXPECT_EQ(0, message.optional_double());
+  EXPECT_EQ(false, message.optional_bool());
+  EXPECT_EQ("", message.optional_string());
+  EXPECT_EQ("", message.optional_bytes());
+
+  // Embedded messages should also be clear.
+  EXPECT_FALSE(message.optionalgroup().has_a());
+  EXPECT_FALSE(message.optional_nested_message().has_bb());
+  EXPECT_FALSE(message.optional_foreign_message().has_c());
+  EXPECT_FALSE(message.optional_import_message().has_d());
+  EXPECT_FALSE(message.optional_public_import_message().has_e());
+  EXPECT_FALSE(message.optional_lazy_message().has_bb());
+  EXPECT_FALSE(message.optional_unverified_lazy_message().has_bb());
+
+  EXPECT_EQ(0, message.optionalgroup().a());
+  EXPECT_EQ(0, message.optional_nested_message().bb());
+  EXPECT_EQ(0, message.optional_foreign_message().c());
+  EXPECT_EQ(0, message.optional_import_message().d());
+
+  // Enums without defaults are set to the first value in the enum.
+  EXPECT_EQ(unittest::TestAllTypesLite::FOO, message.optional_nested_enum());
+  EXPECT_EQ(unittest::FOREIGN_LITE_FOO, message.optional_foreign_enum());
+  EXPECT_EQ(unittest_import::IMPORT_LITE_FOO, message.optional_import_enum());
+
+
+  // Repeated fields are empty.
+  EXPECT_EQ(0, message.repeated_int32_size());
+  EXPECT_EQ(0, message.repeated_int64_size());
+  EXPECT_EQ(0, message.repeated_uint32_size());
+  EXPECT_EQ(0, message.repeated_uint64_size());
+  EXPECT_EQ(0, message.repeated_sint32_size());
+  EXPECT_EQ(0, message.repeated_sint64_size());
+  EXPECT_EQ(0, message.repeated_fixed32_size());
+  EXPECT_EQ(0, message.repeated_fixed64_size());
+  EXPECT_EQ(0, message.repeated_sfixed32_size());
+  EXPECT_EQ(0, message.repeated_sfixed64_size());
+  EXPECT_EQ(0, message.repeated_float_size());
+  EXPECT_EQ(0, message.repeated_double_size());
+  EXPECT_EQ(0, message.repeated_bool_size());
+  EXPECT_EQ(0, message.repeated_string_size());
+  EXPECT_EQ(0, message.repeated_bytes_size());
+
+  EXPECT_EQ(0, message.repeatedgroup_size());
+  EXPECT_EQ(0, message.repeated_nested_message_size());
+  EXPECT_EQ(0, message.repeated_foreign_message_size());
+  EXPECT_EQ(0, message.repeated_import_message_size());
+  EXPECT_EQ(0, message.repeated_lazy_message_size());
+  EXPECT_EQ(0, message.repeated_nested_enum_size());
+  EXPECT_EQ(0, message.repeated_foreign_enum_size());
+  EXPECT_EQ(0, message.repeated_import_enum_size());
+
+
+  // has_blah() should also be false for all default fields.
+  EXPECT_FALSE(message.has_default_int32());
+  EXPECT_FALSE(message.has_default_int64());
+  EXPECT_FALSE(message.has_default_uint32());
+  EXPECT_FALSE(message.has_default_uint64());
+  EXPECT_FALSE(message.has_default_sint32());
+  EXPECT_FALSE(message.has_default_sint64());
+  EXPECT_FALSE(message.has_default_fixed32());
+  EXPECT_FALSE(message.has_default_fixed64());
+  EXPECT_FALSE(message.has_default_sfixed32());
+  EXPECT_FALSE(message.has_default_sfixed64());
+  EXPECT_FALSE(message.has_default_float());
+  EXPECT_FALSE(message.has_default_double());
+  EXPECT_FALSE(message.has_default_bool());
+  EXPECT_FALSE(message.has_default_string());
+  EXPECT_FALSE(message.has_default_bytes());
+
+  EXPECT_FALSE(message.has_default_nested_enum());
+  EXPECT_FALSE(message.has_default_foreign_enum());
+  EXPECT_FALSE(message.has_default_import_enum());
+
+
+  // Fields with defaults have their default values (duh).
+  EXPECT_EQ(41, message.default_int32());
+  EXPECT_EQ(42, message.default_int64());
+  EXPECT_EQ(43, message.default_uint32());
+  EXPECT_EQ(44, message.default_uint64());
+  EXPECT_EQ(-45, message.default_sint32());
+  EXPECT_EQ(46, message.default_sint64());
+  EXPECT_EQ(47, message.default_fixed32());
+  EXPECT_EQ(48, message.default_fixed64());
+  EXPECT_EQ(49, message.default_sfixed32());
+  EXPECT_EQ(-50, message.default_sfixed64());
+  EXPECT_EQ(51.5, message.default_float());
+  EXPECT_EQ(52e3, message.default_double());
+  EXPECT_EQ(true, message.default_bool());
+  EXPECT_EQ("hello", message.default_string());
+  EXPECT_EQ("world", message.default_bytes());
+
+  EXPECT_EQ(unittest::TestAllTypesLite::BAR, message.default_nested_enum());
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR, message.default_foreign_enum());
+  EXPECT_EQ(unittest_import::IMPORT_LITE_BAR, message.default_import_enum());
+
+
+  EXPECT_FALSE(message.has_oneof_uint32());
+  EXPECT_FALSE(message.has_oneof_nested_message());
+  EXPECT_FALSE(message.has_oneof_string());
+  EXPECT_FALSE(message.has_oneof_bytes());
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectRepeatedFieldsModified(
+    const unittest::TestAllTypesLite& 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_EQ(2, message.repeated_int32_size());
+  ASSERT_EQ(2, message.repeated_int64_size());
+  ASSERT_EQ(2, message.repeated_uint32_size());
+  ASSERT_EQ(2, message.repeated_uint64_size());
+  ASSERT_EQ(2, message.repeated_sint32_size());
+  ASSERT_EQ(2, message.repeated_sint64_size());
+  ASSERT_EQ(2, message.repeated_fixed32_size());
+  ASSERT_EQ(2, message.repeated_fixed64_size());
+  ASSERT_EQ(2, message.repeated_sfixed32_size());
+  ASSERT_EQ(2, message.repeated_sfixed64_size());
+  ASSERT_EQ(2, message.repeated_float_size());
+  ASSERT_EQ(2, message.repeated_double_size());
+  ASSERT_EQ(2, message.repeated_bool_size());
+  ASSERT_EQ(2, message.repeated_string_size());
+  ASSERT_EQ(2, message.repeated_bytes_size());
+
+  ASSERT_EQ(2, message.repeatedgroup_size());
+  ASSERT_EQ(2, message.repeated_nested_message_size());
+  ASSERT_EQ(2, message.repeated_foreign_message_size());
+  ASSERT_EQ(2, message.repeated_import_message_size());
+  ASSERT_EQ(2, message.repeated_lazy_message_size());
+  ASSERT_EQ(2, message.repeated_nested_enum_size());
+  ASSERT_EQ(2, message.repeated_foreign_enum_size());
+  ASSERT_EQ(2, message.repeated_import_enum_size());
+
+
+  EXPECT_EQ(201, message.repeated_int32(0));
+  EXPECT_EQ(202, message.repeated_int64(0));
+  EXPECT_EQ(203, message.repeated_uint32(0));
+  EXPECT_EQ(204, message.repeated_uint64(0));
+  EXPECT_EQ(205, message.repeated_sint32(0));
+  EXPECT_EQ(206, message.repeated_sint64(0));
+  EXPECT_EQ(207, message.repeated_fixed32(0));
+  EXPECT_EQ(208, message.repeated_fixed64(0));
+  EXPECT_EQ(209, message.repeated_sfixed32(0));
+  EXPECT_EQ(210, message.repeated_sfixed64(0));
+  EXPECT_EQ(211, message.repeated_float(0));
+  EXPECT_EQ(212, message.repeated_double(0));
+  EXPECT_EQ(true, message.repeated_bool(0));
+  EXPECT_EQ("215", message.repeated_string(0));
+  EXPECT_EQ("216", message.repeated_bytes(0));
+
+  EXPECT_EQ(217, message.repeatedgroup(0).a());
+  EXPECT_EQ(218, message.repeated_nested_message(0).bb());
+  EXPECT_EQ(219, message.repeated_foreign_message(0).c());
+  EXPECT_EQ(220, message.repeated_import_message(0).d());
+  EXPECT_EQ(227, message.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(unittest::TestAllTypesLite::BAR, message.repeated_nested_enum(0));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR, message.repeated_foreign_enum(0));
+  EXPECT_EQ(unittest_import::IMPORT_LITE_BAR, message.repeated_import_enum(0));
+
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(501, message.repeated_int32(1));
+  EXPECT_EQ(502, message.repeated_int64(1));
+  EXPECT_EQ(503, message.repeated_uint32(1));
+  EXPECT_EQ(504, message.repeated_uint64(1));
+  EXPECT_EQ(505, message.repeated_sint32(1));
+  EXPECT_EQ(506, message.repeated_sint64(1));
+  EXPECT_EQ(507, message.repeated_fixed32(1));
+  EXPECT_EQ(508, message.repeated_fixed64(1));
+  EXPECT_EQ(509, message.repeated_sfixed32(1));
+  EXPECT_EQ(510, message.repeated_sfixed64(1));
+  EXPECT_EQ(511, message.repeated_float(1));
+  EXPECT_EQ(512, message.repeated_double(1));
+  EXPECT_EQ(true, message.repeated_bool(1));
+  EXPECT_EQ("515", message.repeated_string(1));
+  EXPECT_EQ("516", message.repeated_bytes(1));
+
+  EXPECT_EQ(517, message.repeatedgroup(1).a());
+  EXPECT_EQ(518, message.repeated_nested_message(1).bb());
+  EXPECT_EQ(519, message.repeated_foreign_message(1).c());
+  EXPECT_EQ(520, message.repeated_import_message(1).d());
+  EXPECT_EQ(527, message.repeated_lazy_message(1).bb());
+
+  EXPECT_EQ(unittest::TestAllTypesLite::FOO, message.repeated_nested_enum(1));
+  EXPECT_EQ(unittest::FOREIGN_LITE_FOO, message.repeated_foreign_enum(1));
+  EXPECT_EQ(unittest_import::IMPORT_LITE_FOO, message.repeated_import_enum(1));
+
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::SetPackedFields(unittest::TestPackedTypesLite* message) {
+  message->add_packed_int32(601);
+  message->add_packed_int64(602);
+  message->add_packed_uint32(603);
+  message->add_packed_uint64(604);
+  message->add_packed_sint32(605);
+  message->add_packed_sint64(606);
+  message->add_packed_fixed32(607);
+  message->add_packed_fixed64(608);
+  message->add_packed_sfixed32(609);
+  message->add_packed_sfixed64(610);
+  message->add_packed_float(611);
+  message->add_packed_double(612);
+  message->add_packed_bool(true);
+  message->add_packed_enum(unittest::FOREIGN_LITE_BAR);
+  // add a second one of each field
+  message->add_packed_int32(701);
+  message->add_packed_int64(702);
+  message->add_packed_uint32(703);
+  message->add_packed_uint64(704);
+  message->add_packed_sint32(705);
+  message->add_packed_sint64(706);
+  message->add_packed_fixed32(707);
+  message->add_packed_fixed64(708);
+  message->add_packed_sfixed32(709);
+  message->add_packed_sfixed64(710);
+  message->add_packed_float(711);
+  message->add_packed_double(712);
+  message->add_packed_bool(false);
+  message->add_packed_enum(unittest::FOREIGN_LITE_BAZ);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ModifyPackedFields(unittest::TestPackedTypesLite* message) {
+  message->set_packed_int32(1, 801);
+  message->set_packed_int64(1, 802);
+  message->set_packed_uint32(1, 803);
+  message->set_packed_uint64(1, 804);
+  message->set_packed_sint32(1, 805);
+  message->set_packed_sint64(1, 806);
+  message->set_packed_fixed32(1, 807);
+  message->set_packed_fixed64(1, 808);
+  message->set_packed_sfixed32(1, 809);
+  message->set_packed_sfixed64(1, 810);
+  message->set_packed_float(1, 811);
+  message->set_packed_double(1, 812);
+  message->set_packed_bool(1, true);
+  message->set_packed_enum(1, unittest::FOREIGN_LITE_FOO);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectPackedFieldsSet(
+    const unittest::TestPackedTypesLite& message) {
+  ASSERT_EQ(2, message.packed_int32_size());
+  ASSERT_EQ(2, message.packed_int64_size());
+  ASSERT_EQ(2, message.packed_uint32_size());
+  ASSERT_EQ(2, message.packed_uint64_size());
+  ASSERT_EQ(2, message.packed_sint32_size());
+  ASSERT_EQ(2, message.packed_sint64_size());
+  ASSERT_EQ(2, message.packed_fixed32_size());
+  ASSERT_EQ(2, message.packed_fixed64_size());
+  ASSERT_EQ(2, message.packed_sfixed32_size());
+  ASSERT_EQ(2, message.packed_sfixed64_size());
+  ASSERT_EQ(2, message.packed_float_size());
+  ASSERT_EQ(2, message.packed_double_size());
+  ASSERT_EQ(2, message.packed_bool_size());
+  ASSERT_EQ(2, message.packed_enum_size());
+
+  EXPECT_EQ(601, message.packed_int32(0));
+  EXPECT_EQ(602, message.packed_int64(0));
+  EXPECT_EQ(603, message.packed_uint32(0));
+  EXPECT_EQ(604, message.packed_uint64(0));
+  EXPECT_EQ(605, message.packed_sint32(0));
+  EXPECT_EQ(606, message.packed_sint64(0));
+  EXPECT_EQ(607, message.packed_fixed32(0));
+  EXPECT_EQ(608, message.packed_fixed64(0));
+  EXPECT_EQ(609, message.packed_sfixed32(0));
+  EXPECT_EQ(610, message.packed_sfixed64(0));
+  EXPECT_EQ(611, message.packed_float(0));
+  EXPECT_EQ(612, message.packed_double(0));
+  EXPECT_EQ(true, message.packed_bool(0));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR, message.packed_enum(0));
+
+  EXPECT_EQ(701, message.packed_int32(1));
+  EXPECT_EQ(702, message.packed_int64(1));
+  EXPECT_EQ(703, message.packed_uint32(1));
+  EXPECT_EQ(704, message.packed_uint64(1));
+  EXPECT_EQ(705, message.packed_sint32(1));
+  EXPECT_EQ(706, message.packed_sint64(1));
+  EXPECT_EQ(707, message.packed_fixed32(1));
+  EXPECT_EQ(708, message.packed_fixed64(1));
+  EXPECT_EQ(709, message.packed_sfixed32(1));
+  EXPECT_EQ(710, message.packed_sfixed64(1));
+  EXPECT_EQ(711, message.packed_float(1));
+  EXPECT_EQ(712, message.packed_double(1));
+  EXPECT_EQ(false, message.packed_bool(1));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAZ, message.packed_enum(1));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectPackedClear(
+    const unittest::TestPackedTypesLite& message) {
+  // Packed repeated fields are empty.
+  EXPECT_EQ(0, message.packed_int32_size());
+  EXPECT_EQ(0, message.packed_int64_size());
+  EXPECT_EQ(0, message.packed_uint32_size());
+  EXPECT_EQ(0, message.packed_uint64_size());
+  EXPECT_EQ(0, message.packed_sint32_size());
+  EXPECT_EQ(0, message.packed_sint64_size());
+  EXPECT_EQ(0, message.packed_fixed32_size());
+  EXPECT_EQ(0, message.packed_fixed64_size());
+  EXPECT_EQ(0, message.packed_sfixed32_size());
+  EXPECT_EQ(0, message.packed_sfixed64_size());
+  EXPECT_EQ(0, message.packed_float_size());
+  EXPECT_EQ(0, message.packed_double_size());
+  EXPECT_EQ(0, message.packed_bool_size());
+  EXPECT_EQ(0, message.packed_enum_size());
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectPackedFieldsModified(
+    const unittest::TestPackedTypesLite& message) {
+  // Do the same for packed repeated fields.
+  ASSERT_EQ(2, message.packed_int32_size());
+  ASSERT_EQ(2, message.packed_int64_size());
+  ASSERT_EQ(2, message.packed_uint32_size());
+  ASSERT_EQ(2, message.packed_uint64_size());
+  ASSERT_EQ(2, message.packed_sint32_size());
+  ASSERT_EQ(2, message.packed_sint64_size());
+  ASSERT_EQ(2, message.packed_fixed32_size());
+  ASSERT_EQ(2, message.packed_fixed64_size());
+  ASSERT_EQ(2, message.packed_sfixed32_size());
+  ASSERT_EQ(2, message.packed_sfixed64_size());
+  ASSERT_EQ(2, message.packed_float_size());
+  ASSERT_EQ(2, message.packed_double_size());
+  ASSERT_EQ(2, message.packed_bool_size());
+  ASSERT_EQ(2, message.packed_enum_size());
+
+  EXPECT_EQ(601, message.packed_int32(0));
+  EXPECT_EQ(602, message.packed_int64(0));
+  EXPECT_EQ(603, message.packed_uint32(0));
+  EXPECT_EQ(604, message.packed_uint64(0));
+  EXPECT_EQ(605, message.packed_sint32(0));
+  EXPECT_EQ(606, message.packed_sint64(0));
+  EXPECT_EQ(607, message.packed_fixed32(0));
+  EXPECT_EQ(608, message.packed_fixed64(0));
+  EXPECT_EQ(609, message.packed_sfixed32(0));
+  EXPECT_EQ(610, message.packed_sfixed64(0));
+  EXPECT_EQ(611, message.packed_float(0));
+  EXPECT_EQ(612, message.packed_double(0));
+  EXPECT_EQ(true, message.packed_bool(0));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR, message.packed_enum(0));
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(801, message.packed_int32(1));
+  EXPECT_EQ(802, message.packed_int64(1));
+  EXPECT_EQ(803, message.packed_uint32(1));
+  EXPECT_EQ(804, message.packed_uint64(1));
+  EXPECT_EQ(805, message.packed_sint32(1));
+  EXPECT_EQ(806, message.packed_sint64(1));
+  EXPECT_EQ(807, message.packed_fixed32(1));
+  EXPECT_EQ(808, message.packed_fixed64(1));
+  EXPECT_EQ(809, message.packed_sfixed32(1));
+  EXPECT_EQ(810, message.packed_sfixed64(1));
+  EXPECT_EQ(811, message.packed_float(1));
+  EXPECT_EQ(812, message.packed_double(1));
+  EXPECT_EQ(true, message.packed_bool(1));
+  EXPECT_EQ(unittest::FOREIGN_LITE_FOO, message.packed_enum(1));
+}
+
+// ===================================================================
+// Extensions
+//
+// All this code is exactly equivalent to the above code except that it's
+// manipulating extension fields instead of normal ones.
+//
+// I gave up on the 80-char limit here.  Sorry.
+
+void TestUtilLite::SetAllExtensions(unittest::TestAllExtensionsLite* message) {
+  message->SetExtension(unittest::optional_int32_extension_lite, 101);
+  message->SetExtension(unittest::optional_int64_extension_lite, 102);
+  message->SetExtension(unittest::optional_uint32_extension_lite, 103);
+  message->SetExtension(unittest::optional_uint64_extension_lite, 104);
+  message->SetExtension(unittest::optional_sint32_extension_lite, 105);
+  message->SetExtension(unittest::optional_sint64_extension_lite, 106);
+  message->SetExtension(unittest::optional_fixed32_extension_lite, 107);
+  message->SetExtension(unittest::optional_fixed64_extension_lite, 108);
+  message->SetExtension(unittest::optional_sfixed32_extension_lite, 109);
+  message->SetExtension(unittest::optional_sfixed64_extension_lite, 110);
+  message->SetExtension(unittest::optional_float_extension_lite, 111);
+  message->SetExtension(unittest::optional_double_extension_lite, 112);
+  message->SetExtension(unittest::optional_bool_extension_lite, true);
+  message->SetExtension(unittest::optional_string_extension_lite, "115");
+  message->SetExtension(unittest::optional_bytes_extension_lite, "116");
+
+  message->MutableExtension(unittest::optionalgroup_extension_lite)->set_a(117);
+  message->MutableExtension(unittest::optional_nested_message_extension_lite)
+      ->set_bb(118);
+  message->MutableExtension(unittest::optional_foreign_message_extension_lite)
+      ->set_c(119);
+  message->MutableExtension(unittest::optional_import_message_extension_lite)
+      ->set_d(120);
+  message
+      ->MutableExtension(
+          unittest::optional_public_import_message_extension_lite)
+      ->set_e(126);
+  message->MutableExtension(unittest::optional_lazy_message_extension_lite)
+      ->set_bb(127);
+  message
+      ->MutableExtension(
+          unittest::optional_unverified_lazy_message_extension_lite)
+      ->set_bb(128);
+
+  message->SetExtension(unittest::optional_nested_enum_extension_lite,
+                        unittest::TestAllTypesLite::BAZ);
+  message->SetExtension(unittest::optional_foreign_enum_extension_lite,
+                        unittest::FOREIGN_LITE_BAZ);
+  message->SetExtension(unittest::optional_import_enum_extension_lite,
+                        unittest_import::IMPORT_LITE_BAZ);
+
+
+  // -----------------------------------------------------------------
+
+  message->AddExtension(unittest::repeated_int32_extension_lite, 201);
+  message->AddExtension(unittest::repeated_int64_extension_lite, 202);
+  message->AddExtension(unittest::repeated_uint32_extension_lite, 203);
+  message->AddExtension(unittest::repeated_uint64_extension_lite, 204);
+  message->AddExtension(unittest::repeated_sint32_extension_lite, 205);
+  message->AddExtension(unittest::repeated_sint64_extension_lite, 206);
+  message->AddExtension(unittest::repeated_fixed32_extension_lite, 207);
+  message->AddExtension(unittest::repeated_fixed64_extension_lite, 208);
+  message->AddExtension(unittest::repeated_sfixed32_extension_lite, 209);
+  message->AddExtension(unittest::repeated_sfixed64_extension_lite, 210);
+  message->AddExtension(unittest::repeated_float_extension_lite, 211);
+  message->AddExtension(unittest::repeated_double_extension_lite, 212);
+  message->AddExtension(unittest::repeated_bool_extension_lite, true);
+  message->AddExtension(unittest::repeated_string_extension_lite, "215");
+  message->AddExtension(unittest::repeated_bytes_extension_lite, "216");
+
+  message->AddExtension(unittest::repeatedgroup_extension_lite)->set_a(217);
+  message->AddExtension(unittest::repeated_nested_message_extension_lite)
+      ->set_bb(218);
+  message->AddExtension(unittest::repeated_foreign_message_extension_lite)
+      ->set_c(219);
+  message->AddExtension(unittest::repeated_import_message_extension_lite)
+      ->set_d(220);
+  message->AddExtension(unittest::repeated_lazy_message_extension_lite)
+      ->set_bb(227);
+
+  message->AddExtension(unittest::repeated_nested_enum_extension_lite,
+                        unittest::TestAllTypesLite::BAR);
+  message->AddExtension(unittest::repeated_foreign_enum_extension_lite,
+                        unittest::FOREIGN_LITE_BAR);
+  message->AddExtension(unittest::repeated_import_enum_extension_lite,
+                        unittest_import::IMPORT_LITE_BAR);
+
+
+  // Add a second one of each field.
+  message->AddExtension(unittest::repeated_int32_extension_lite, 301);
+  message->AddExtension(unittest::repeated_int64_extension_lite, 302);
+  message->AddExtension(unittest::repeated_uint32_extension_lite, 303);
+  message->AddExtension(unittest::repeated_uint64_extension_lite, 304);
+  message->AddExtension(unittest::repeated_sint32_extension_lite, 305);
+  message->AddExtension(unittest::repeated_sint64_extension_lite, 306);
+  message->AddExtension(unittest::repeated_fixed32_extension_lite, 307);
+  message->AddExtension(unittest::repeated_fixed64_extension_lite, 308);
+  message->AddExtension(unittest::repeated_sfixed32_extension_lite, 309);
+  message->AddExtension(unittest::repeated_sfixed64_extension_lite, 310);
+  message->AddExtension(unittest::repeated_float_extension_lite, 311);
+  message->AddExtension(unittest::repeated_double_extension_lite, 312);
+  message->AddExtension(unittest::repeated_bool_extension_lite, false);
+  message->AddExtension(unittest::repeated_string_extension_lite, "315");
+  message->AddExtension(unittest::repeated_bytes_extension_lite, "316");
+
+  message->AddExtension(unittest::repeatedgroup_extension_lite)->set_a(317);
+  message->AddExtension(unittest::repeated_nested_message_extension_lite)
+      ->set_bb(318);
+  message->AddExtension(unittest::repeated_foreign_message_extension_lite)
+      ->set_c(319);
+  message->AddExtension(unittest::repeated_import_message_extension_lite)
+      ->set_d(320);
+  message->AddExtension(unittest::repeated_lazy_message_extension_lite)
+      ->set_bb(327);
+
+  message->AddExtension(unittest::repeated_nested_enum_extension_lite,
+                        unittest::TestAllTypesLite::BAZ);
+  message->AddExtension(unittest::repeated_foreign_enum_extension_lite,
+                        unittest::FOREIGN_LITE_BAZ);
+  message->AddExtension(unittest::repeated_import_enum_extension_lite,
+                        unittest_import::IMPORT_LITE_BAZ);
+
+
+  // -----------------------------------------------------------------
+
+  message->SetExtension(unittest::default_int32_extension_lite, 401);
+  message->SetExtension(unittest::default_int64_extension_lite, 402);
+  message->SetExtension(unittest::default_uint32_extension_lite, 403);
+  message->SetExtension(unittest::default_uint64_extension_lite, 404);
+  message->SetExtension(unittest::default_sint32_extension_lite, 405);
+  message->SetExtension(unittest::default_sint64_extension_lite, 406);
+  message->SetExtension(unittest::default_fixed32_extension_lite, 407);
+  message->SetExtension(unittest::default_fixed64_extension_lite, 408);
+  message->SetExtension(unittest::default_sfixed32_extension_lite, 409);
+  message->SetExtension(unittest::default_sfixed64_extension_lite, 410);
+  message->SetExtension(unittest::default_float_extension_lite, 411);
+  message->SetExtension(unittest::default_double_extension_lite, 412);
+  message->SetExtension(unittest::default_bool_extension_lite, false);
+  message->SetExtension(unittest::default_string_extension_lite, "415");
+  message->SetExtension(unittest::default_bytes_extension_lite, "416");
+
+  message->SetExtension(unittest::default_nested_enum_extension_lite,
+                        unittest::TestAllTypesLite::FOO);
+  message->SetExtension(unittest::default_foreign_enum_extension_lite,
+                        unittest::FOREIGN_LITE_FOO);
+  message->SetExtension(unittest::default_import_enum_extension_lite,
+                        unittest_import::IMPORT_LITE_FOO);
+
+
+  message->SetExtension(unittest::oneof_uint32_extension_lite, 601);
+  message->MutableExtension(unittest::oneof_nested_message_extension_lite)
+      ->set_bb(602);
+  ;
+  message->SetExtension(unittest::oneof_string_extension_lite, "603");
+  message->SetExtension(unittest::oneof_bytes_extension_lite, "604");
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ModifyRepeatedExtensions(
+    unittest::TestAllExtensionsLite* message) {
+  message->SetExtension(unittest::repeated_int32_extension_lite, 1, 501);
+  message->SetExtension(unittest::repeated_int64_extension_lite, 1, 502);
+  message->SetExtension(unittest::repeated_uint32_extension_lite, 1, 503);
+  message->SetExtension(unittest::repeated_uint64_extension_lite, 1, 504);
+  message->SetExtension(unittest::repeated_sint32_extension_lite, 1, 505);
+  message->SetExtension(unittest::repeated_sint64_extension_lite, 1, 506);
+  message->SetExtension(unittest::repeated_fixed32_extension_lite, 1, 507);
+  message->SetExtension(unittest::repeated_fixed64_extension_lite, 1, 508);
+  message->SetExtension(unittest::repeated_sfixed32_extension_lite, 1, 509);
+  message->SetExtension(unittest::repeated_sfixed64_extension_lite, 1, 510);
+  message->SetExtension(unittest::repeated_float_extension_lite, 1, 511);
+  message->SetExtension(unittest::repeated_double_extension_lite, 1, 512);
+  message->SetExtension(unittest::repeated_bool_extension_lite, 1, true);
+  message->SetExtension(unittest::repeated_string_extension_lite, 1, "515");
+  message->SetExtension(unittest::repeated_bytes_extension_lite, 1, "516");
+
+  message->MutableExtension(unittest::repeatedgroup_extension_lite, 1)
+      ->set_a(517);
+  message->MutableExtension(unittest::repeated_nested_message_extension_lite, 1)
+      ->set_bb(518);
+  message
+      ->MutableExtension(unittest::repeated_foreign_message_extension_lite, 1)
+      ->set_c(519);
+  message->MutableExtension(unittest::repeated_import_message_extension_lite, 1)
+      ->set_d(520);
+  message->MutableExtension(unittest::repeated_lazy_message_extension_lite, 1)
+      ->set_bb(527);
+
+  message->SetExtension(unittest::repeated_nested_enum_extension_lite, 1,
+                        unittest::TestAllTypesLite::FOO);
+  message->SetExtension(unittest::repeated_foreign_enum_extension_lite, 1,
+                        unittest::FOREIGN_LITE_FOO);
+  message->SetExtension(unittest::repeated_import_enum_extension_lite, 1,
+                        unittest_import::IMPORT_LITE_FOO);
+
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectAllExtensionsSet(
+    const unittest::TestAllExtensionsLite& message) {
+  EXPECT_TRUE(message.HasExtension(unittest::optional_int32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_int64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_uint32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_uint64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_sint32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_sint64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_fixed32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_fixed64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_sfixed32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_sfixed64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_float_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_double_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_bool_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::optional_bytes_extension_lite));
+
+  EXPECT_TRUE(message.HasExtension(unittest::optionalgroup_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_nested_message_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_foreign_message_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_import_message_extension_lite));
+  EXPECT_TRUE(message.HasExtension(
+      unittest::optional_public_import_message_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_lazy_message_extension_lite));
+  EXPECT_TRUE(message.HasExtension(
+      unittest::optional_unverified_lazy_message_extension_lite));
+
+  EXPECT_TRUE(
+      message.GetExtension(unittest::optionalgroup_extension_lite).has_a());
+  EXPECT_TRUE(
+      message.GetExtension(unittest::optional_nested_message_extension_lite)
+          .has_bb());
+  EXPECT_TRUE(
+      message.GetExtension(unittest::optional_foreign_message_extension_lite)
+          .has_c());
+  EXPECT_TRUE(
+      message.GetExtension(unittest::optional_import_message_extension_lite)
+          .has_d());
+  EXPECT_TRUE(
+      message
+          .GetExtension(unittest::optional_public_import_message_extension_lite)
+          .has_e());
+  EXPECT_TRUE(
+      message.GetExtension(unittest::optional_lazy_message_extension_lite)
+          .has_bb());
+  EXPECT_TRUE(message
+                  .GetExtension(
+                      unittest::optional_unverified_lazy_message_extension_lite)
+                  .has_bb());
+
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_nested_enum_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_foreign_enum_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::optional_import_enum_extension_lite));
+
+
+  EXPECT_EQ(101, message.GetExtension(unittest::optional_int32_extension_lite));
+  EXPECT_EQ(102, message.GetExtension(unittest::optional_int64_extension_lite));
+  EXPECT_EQ(103,
+            message.GetExtension(unittest::optional_uint32_extension_lite));
+  EXPECT_EQ(104,
+            message.GetExtension(unittest::optional_uint64_extension_lite));
+  EXPECT_EQ(105,
+            message.GetExtension(unittest::optional_sint32_extension_lite));
+  EXPECT_EQ(106,
+            message.GetExtension(unittest::optional_sint64_extension_lite));
+  EXPECT_EQ(107,
+            message.GetExtension(unittest::optional_fixed32_extension_lite));
+  EXPECT_EQ(108,
+            message.GetExtension(unittest::optional_fixed64_extension_lite));
+  EXPECT_EQ(109,
+            message.GetExtension(unittest::optional_sfixed32_extension_lite));
+  EXPECT_EQ(110,
+            message.GetExtension(unittest::optional_sfixed64_extension_lite));
+  EXPECT_EQ(111, message.GetExtension(unittest::optional_float_extension_lite));
+  EXPECT_EQ(112,
+            message.GetExtension(unittest::optional_double_extension_lite));
+  EXPECT_EQ(true, message.GetExtension(unittest::optional_bool_extension_lite));
+  EXPECT_EQ("115",
+            message.GetExtension(unittest::optional_string_extension_lite));
+  EXPECT_EQ("116",
+            message.GetExtension(unittest::optional_bytes_extension_lite));
+
+  EXPECT_EQ(117,
+            message.GetExtension(unittest::optionalgroup_extension_lite).a());
+  EXPECT_EQ(
+      118,
+      message.GetExtension(unittest::optional_nested_message_extension_lite)
+          .bb());
+  EXPECT_EQ(
+      119,
+      message.GetExtension(unittest::optional_foreign_message_extension_lite)
+          .c());
+  EXPECT_EQ(
+      120,
+      message.GetExtension(unittest::optional_import_message_extension_lite)
+          .d());
+  EXPECT_EQ(
+      126,
+      message
+          .GetExtension(unittest::optional_public_import_message_extension_lite)
+          .e());
+  EXPECT_EQ(127,
+            message.GetExtension(unittest::optional_lazy_message_extension_lite)
+                .bb());
+  EXPECT_EQ(128,
+            message
+                .GetExtension(
+                    unittest::optional_unverified_lazy_message_extension_lite)
+                .bb());
+
+  EXPECT_EQ(
+      unittest::TestAllTypesLite::BAZ,
+      message.GetExtension(unittest::optional_nested_enum_extension_lite));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_BAZ,
+      message.GetExtension(unittest::optional_foreign_enum_extension_lite));
+  EXPECT_EQ(
+      unittest_import::IMPORT_LITE_BAZ,
+      message.GetExtension(unittest::optional_import_enum_extension_lite));
+
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_int32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_int64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_uint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_uint64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sint64_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_fixed32_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_fixed64_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_sfixed32_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_sfixed64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_float_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_double_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_bool_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_string_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_bytes_extension_lite));
+
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeatedgroup_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(
+                   unittest::repeated_nested_message_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(
+                   unittest::repeated_foreign_message_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(
+                   unittest::repeated_import_message_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_import_enum_extension_lite));
+
+
+  EXPECT_EQ(201,
+            message.GetExtension(unittest::repeated_int32_extension_lite, 0));
+  EXPECT_EQ(202,
+            message.GetExtension(unittest::repeated_int64_extension_lite, 0));
+  EXPECT_EQ(203,
+            message.GetExtension(unittest::repeated_uint32_extension_lite, 0));
+  EXPECT_EQ(204,
+            message.GetExtension(unittest::repeated_uint64_extension_lite, 0));
+  EXPECT_EQ(205,
+            message.GetExtension(unittest::repeated_sint32_extension_lite, 0));
+  EXPECT_EQ(206,
+            message.GetExtension(unittest::repeated_sint64_extension_lite, 0));
+  EXPECT_EQ(207,
+            message.GetExtension(unittest::repeated_fixed32_extension_lite, 0));
+  EXPECT_EQ(208,
+            message.GetExtension(unittest::repeated_fixed64_extension_lite, 0));
+  EXPECT_EQ(
+      209, message.GetExtension(unittest::repeated_sfixed32_extension_lite, 0));
+  EXPECT_EQ(
+      210, message.GetExtension(unittest::repeated_sfixed64_extension_lite, 0));
+  EXPECT_EQ(211,
+            message.GetExtension(unittest::repeated_float_extension_lite, 0));
+  EXPECT_EQ(212,
+            message.GetExtension(unittest::repeated_double_extension_lite, 0));
+  EXPECT_EQ(true,
+            message.GetExtension(unittest::repeated_bool_extension_lite, 0));
+  EXPECT_EQ("215",
+            message.GetExtension(unittest::repeated_string_extension_lite, 0));
+  EXPECT_EQ("216",
+            message.GetExtension(unittest::repeated_bytes_extension_lite, 0));
+
+  EXPECT_EQ(
+      217, message.GetExtension(unittest::repeatedgroup_extension_lite, 0).a());
+  EXPECT_EQ(
+      218,
+      message.GetExtension(unittest::repeated_nested_message_extension_lite, 0)
+          .bb());
+  EXPECT_EQ(
+      219,
+      message.GetExtension(unittest::repeated_foreign_message_extension_lite, 0)
+          .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(unittest::repeated_import_message_extension_lite, 0)
+          .d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(unittest::repeated_lazy_message_extension_lite, 0)
+          .bb());
+
+  EXPECT_EQ(
+      unittest::TestAllTypesLite::BAR,
+      message.GetExtension(unittest::repeated_nested_enum_extension_lite, 0));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_BAR,
+      message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 0));
+  EXPECT_EQ(
+      unittest_import::IMPORT_LITE_BAR,
+      message.GetExtension(unittest::repeated_import_enum_extension_lite, 0));
+
+
+  EXPECT_EQ(301,
+            message.GetExtension(unittest::repeated_int32_extension_lite, 1));
+  EXPECT_EQ(302,
+            message.GetExtension(unittest::repeated_int64_extension_lite, 1));
+  EXPECT_EQ(303,
+            message.GetExtension(unittest::repeated_uint32_extension_lite, 1));
+  EXPECT_EQ(304,
+            message.GetExtension(unittest::repeated_uint64_extension_lite, 1));
+  EXPECT_EQ(305,
+            message.GetExtension(unittest::repeated_sint32_extension_lite, 1));
+  EXPECT_EQ(306,
+            message.GetExtension(unittest::repeated_sint64_extension_lite, 1));
+  EXPECT_EQ(307,
+            message.GetExtension(unittest::repeated_fixed32_extension_lite, 1));
+  EXPECT_EQ(308,
+            message.GetExtension(unittest::repeated_fixed64_extension_lite, 1));
+  EXPECT_EQ(
+      309, message.GetExtension(unittest::repeated_sfixed32_extension_lite, 1));
+  EXPECT_EQ(
+      310, message.GetExtension(unittest::repeated_sfixed64_extension_lite, 1));
+  EXPECT_EQ(311,
+            message.GetExtension(unittest::repeated_float_extension_lite, 1));
+  EXPECT_EQ(312,
+            message.GetExtension(unittest::repeated_double_extension_lite, 1));
+  EXPECT_EQ(false,
+            message.GetExtension(unittest::repeated_bool_extension_lite, 1));
+  EXPECT_EQ("315",
+            message.GetExtension(unittest::repeated_string_extension_lite, 1));
+  EXPECT_EQ("316",
+            message.GetExtension(unittest::repeated_bytes_extension_lite, 1));
+
+  EXPECT_EQ(
+      317, message.GetExtension(unittest::repeatedgroup_extension_lite, 1).a());
+  EXPECT_EQ(
+      318,
+      message.GetExtension(unittest::repeated_nested_message_extension_lite, 1)
+          .bb());
+  EXPECT_EQ(
+      319,
+      message.GetExtension(unittest::repeated_foreign_message_extension_lite, 1)
+          .c());
+  EXPECT_EQ(
+      320,
+      message.GetExtension(unittest::repeated_import_message_extension_lite, 1)
+          .d());
+  EXPECT_EQ(
+      327,
+      message.GetExtension(unittest::repeated_lazy_message_extension_lite, 1)
+          .bb());
+
+  EXPECT_EQ(
+      unittest::TestAllTypesLite::BAZ,
+      message.GetExtension(unittest::repeated_nested_enum_extension_lite, 1));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_BAZ,
+      message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 1));
+  EXPECT_EQ(
+      unittest_import::IMPORT_LITE_BAZ,
+      message.GetExtension(unittest::repeated_import_enum_extension_lite, 1));
+
+
+  // -----------------------------------------------------------------
+
+  EXPECT_TRUE(message.HasExtension(unittest::default_int32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_int64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_uint32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_uint64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_sint32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_sint64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_fixed32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_fixed64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_sfixed32_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_sfixed64_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_float_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_double_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_bool_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_string_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::default_bytes_extension_lite));
+
+  EXPECT_TRUE(
+      message.HasExtension(unittest::default_nested_enum_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::default_foreign_enum_extension_lite));
+  EXPECT_TRUE(
+      message.HasExtension(unittest::default_import_enum_extension_lite));
+
+
+  EXPECT_EQ(401, message.GetExtension(unittest::default_int32_extension_lite));
+  EXPECT_EQ(402, message.GetExtension(unittest::default_int64_extension_lite));
+  EXPECT_EQ(403, message.GetExtension(unittest::default_uint32_extension_lite));
+  EXPECT_EQ(404, message.GetExtension(unittest::default_uint64_extension_lite));
+  EXPECT_EQ(405, message.GetExtension(unittest::default_sint32_extension_lite));
+  EXPECT_EQ(406, message.GetExtension(unittest::default_sint64_extension_lite));
+  EXPECT_EQ(407,
+            message.GetExtension(unittest::default_fixed32_extension_lite));
+  EXPECT_EQ(408,
+            message.GetExtension(unittest::default_fixed64_extension_lite));
+  EXPECT_EQ(409,
+            message.GetExtension(unittest::default_sfixed32_extension_lite));
+  EXPECT_EQ(410,
+            message.GetExtension(unittest::default_sfixed64_extension_lite));
+  EXPECT_EQ(411, message.GetExtension(unittest::default_float_extension_lite));
+  EXPECT_EQ(412, message.GetExtension(unittest::default_double_extension_lite));
+  EXPECT_EQ(false, message.GetExtension(unittest::default_bool_extension_lite));
+  EXPECT_EQ("415",
+            message.GetExtension(unittest::default_string_extension_lite));
+  EXPECT_EQ("416",
+            message.GetExtension(unittest::default_bytes_extension_lite));
+
+  EXPECT_EQ(unittest::TestAllTypesLite::FOO,
+            message.GetExtension(unittest::default_nested_enum_extension_lite));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_FOO,
+      message.GetExtension(unittest::default_foreign_enum_extension_lite));
+  EXPECT_EQ(unittest_import::IMPORT_LITE_FOO,
+            message.GetExtension(unittest::default_import_enum_extension_lite));
+
+
+  EXPECT_TRUE(message.HasExtension(unittest::oneof_uint32_extension_lite));
+  EXPECT_TRUE(
+      message.GetExtension(unittest::oneof_nested_message_extension_lite)
+          .has_bb());
+  EXPECT_TRUE(message.HasExtension(unittest::oneof_string_extension_lite));
+  EXPECT_TRUE(message.HasExtension(unittest::oneof_bytes_extension_lite));
+
+  EXPECT_EQ(601, message.GetExtension(unittest::oneof_uint32_extension_lite));
+  EXPECT_EQ(
+      602,
+      message.GetExtension(unittest::oneof_nested_message_extension_lite).bb());
+  EXPECT_EQ("603", message.GetExtension(unittest::oneof_string_extension_lite));
+  EXPECT_EQ("604", message.GetExtension(unittest::oneof_bytes_extension_lite));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectExtensionsClear(
+    const unittest::TestAllExtensionsLite& message) {
+  std::string serialized;
+  ASSERT_TRUE(message.SerializeToString(&serialized));
+  EXPECT_EQ("", serialized);
+  EXPECT_EQ(0, message.ByteSizeLong());
+
+  // has_blah() should initially be false for all optional fields.
+  EXPECT_FALSE(message.HasExtension(unittest::optional_int32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_int64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_uint32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_uint64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_sint32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_sint64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_fixed32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_fixed64_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_sfixed32_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_sfixed64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_float_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_double_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_bool_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_string_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::optional_bytes_extension_lite));
+
+  EXPECT_FALSE(message.HasExtension(unittest::optionalgroup_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_nested_message_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_foreign_message_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_import_message_extension_lite));
+  EXPECT_FALSE(message.HasExtension(
+      unittest::optional_public_import_message_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_lazy_message_extension_lite));
+
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_nested_enum_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_foreign_enum_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::optional_import_enum_extension_lite));
+
+
+  // Optional fields without defaults are set to zero or something like it.
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_int32_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_int64_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_uint32_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_uint64_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_sint32_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_sint64_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_fixed32_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_fixed64_extension_lite));
+  EXPECT_EQ(0,
+            message.GetExtension(unittest::optional_sfixed32_extension_lite));
+  EXPECT_EQ(0,
+            message.GetExtension(unittest::optional_sfixed64_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_float_extension_lite));
+  EXPECT_EQ(0, message.GetExtension(unittest::optional_double_extension_lite));
+  EXPECT_EQ(false,
+            message.GetExtension(unittest::optional_bool_extension_lite));
+  EXPECT_EQ("", message.GetExtension(unittest::optional_string_extension_lite));
+  EXPECT_EQ("", message.GetExtension(unittest::optional_bytes_extension_lite));
+
+  // Embedded messages should also be clear.
+  EXPECT_FALSE(
+      message.GetExtension(unittest::optionalgroup_extension_lite).has_a());
+  EXPECT_FALSE(
+      message.GetExtension(unittest::optional_nested_message_extension_lite)
+          .has_bb());
+  EXPECT_FALSE(
+      message.GetExtension(unittest::optional_foreign_message_extension_lite)
+          .has_c());
+  EXPECT_FALSE(
+      message.GetExtension(unittest::optional_import_message_extension_lite)
+          .has_d());
+  EXPECT_FALSE(
+      message
+          .GetExtension(unittest::optional_public_import_message_extension_lite)
+          .has_e());
+  EXPECT_FALSE(
+      message.GetExtension(unittest::optional_lazy_message_extension_lite)
+          .has_bb());
+
+  EXPECT_EQ(0,
+            message.GetExtension(unittest::optionalgroup_extension_lite).a());
+  EXPECT_EQ(
+      0, message.GetExtension(unittest::optional_nested_message_extension_lite)
+             .bb());
+  EXPECT_EQ(
+      0, message.GetExtension(unittest::optional_foreign_message_extension_lite)
+             .c());
+  EXPECT_EQ(
+      0, message.GetExtension(unittest::optional_import_message_extension_lite)
+             .d());
+  EXPECT_EQ(0, message
+                   .GetExtension(
+                       unittest::optional_public_import_message_extension_lite)
+                   .e());
+  EXPECT_EQ(0,
+            message.GetExtension(unittest::optional_lazy_message_extension_lite)
+                .bb());
+
+  // Enums without defaults are set to the first value in the enum.
+  EXPECT_EQ(
+      unittest::TestAllTypesLite::FOO,
+      message.GetExtension(unittest::optional_nested_enum_extension_lite));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_FOO,
+      message.GetExtension(unittest::optional_foreign_enum_extension_lite));
+  EXPECT_EQ(
+      unittest_import::IMPORT_LITE_FOO,
+      message.GetExtension(unittest::optional_import_enum_extension_lite));
+
+
+  // Repeated fields are empty.
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_int32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_int64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_uint32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_uint64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_sint32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_sint64_extension_lite));
+  EXPECT_EQ(0,
+            message.ExtensionSize(unittest::repeated_fixed32_extension_lite));
+  EXPECT_EQ(0,
+            message.ExtensionSize(unittest::repeated_fixed64_extension_lite));
+  EXPECT_EQ(0,
+            message.ExtensionSize(unittest::repeated_sfixed32_extension_lite));
+  EXPECT_EQ(0,
+            message.ExtensionSize(unittest::repeated_sfixed64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_float_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_double_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_bool_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_string_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeated_bytes_extension_lite));
+
+  EXPECT_EQ(0, message.ExtensionSize(unittest::repeatedgroup_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(
+                   unittest::repeated_nested_message_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(
+                   unittest::repeated_foreign_message_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(
+                   unittest::repeated_import_message_extension_lite));
+  EXPECT_EQ(
+      0, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite));
+  EXPECT_EQ(
+      0, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite));
+  EXPECT_EQ(
+      0, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite));
+  EXPECT_EQ(
+      0, message.ExtensionSize(unittest::repeated_import_enum_extension_lite));
+
+
+  // has_blah() should also be false for all default fields.
+  EXPECT_FALSE(message.HasExtension(unittest::default_int32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_int64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_uint32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_uint64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_sint32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_sint64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_fixed32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_fixed64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_sfixed32_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_sfixed64_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_float_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_double_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_bool_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_string_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::default_bytes_extension_lite));
+
+  EXPECT_FALSE(
+      message.HasExtension(unittest::default_nested_enum_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::default_foreign_enum_extension_lite));
+  EXPECT_FALSE(
+      message.HasExtension(unittest::default_import_enum_extension_lite));
+
+
+  // Fields with defaults have their default values (duh).
+  EXPECT_EQ(41, message.GetExtension(unittest::default_int32_extension_lite));
+  EXPECT_EQ(42, message.GetExtension(unittest::default_int64_extension_lite));
+  EXPECT_EQ(43, message.GetExtension(unittest::default_uint32_extension_lite));
+  EXPECT_EQ(44, message.GetExtension(unittest::default_uint64_extension_lite));
+  EXPECT_EQ(-45, message.GetExtension(unittest::default_sint32_extension_lite));
+  EXPECT_EQ(46, message.GetExtension(unittest::default_sint64_extension_lite));
+  EXPECT_EQ(47, message.GetExtension(unittest::default_fixed32_extension_lite));
+  EXPECT_EQ(48, message.GetExtension(unittest::default_fixed64_extension_lite));
+  EXPECT_EQ(49,
+            message.GetExtension(unittest::default_sfixed32_extension_lite));
+  EXPECT_EQ(-50,
+            message.GetExtension(unittest::default_sfixed64_extension_lite));
+  EXPECT_EQ(51.5, message.GetExtension(unittest::default_float_extension_lite));
+  EXPECT_EQ(52e3,
+            message.GetExtension(unittest::default_double_extension_lite));
+  EXPECT_EQ(true, message.GetExtension(unittest::default_bool_extension_lite));
+  EXPECT_EQ("hello",
+            message.GetExtension(unittest::default_string_extension_lite));
+  EXPECT_EQ("world",
+            message.GetExtension(unittest::default_bytes_extension_lite));
+
+  EXPECT_EQ(unittest::TestAllTypesLite::BAR,
+            message.GetExtension(unittest::default_nested_enum_extension_lite));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_BAR,
+      message.GetExtension(unittest::default_foreign_enum_extension_lite));
+  EXPECT_EQ(unittest_import::IMPORT_LITE_BAR,
+            message.GetExtension(unittest::default_import_enum_extension_lite));
+
+
+  EXPECT_FALSE(message.HasExtension(unittest::oneof_uint32_extension_lite));
+  EXPECT_FALSE(
+      message.GetExtension(unittest::oneof_nested_message_extension_lite)
+          .has_bb());
+  EXPECT_FALSE(message.HasExtension(unittest::oneof_string_extension_lite));
+  EXPECT_FALSE(message.HasExtension(unittest::oneof_bytes_extension_lite));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectRepeatedExtensionsModified(
+    const unittest::TestAllExtensionsLite& 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_EQ(2, message.ExtensionSize(unittest::repeated_int32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_int64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_uint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_uint64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_sint64_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_fixed32_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_fixed64_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_sfixed32_extension_lite));
+  ASSERT_EQ(2,
+            message.ExtensionSize(unittest::repeated_sfixed64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_float_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_double_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_bool_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_string_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeated_bytes_extension_lite));
+
+  ASSERT_EQ(2, message.ExtensionSize(unittest::repeatedgroup_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(
+                   unittest::repeated_nested_message_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(
+                   unittest::repeated_foreign_message_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(
+                   unittest::repeated_import_message_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_lazy_message_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_nested_enum_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_foreign_enum_extension_lite));
+  ASSERT_EQ(
+      2, message.ExtensionSize(unittest::repeated_import_enum_extension_lite));
+
+
+  EXPECT_EQ(201,
+            message.GetExtension(unittest::repeated_int32_extension_lite, 0));
+  EXPECT_EQ(202,
+            message.GetExtension(unittest::repeated_int64_extension_lite, 0));
+  EXPECT_EQ(203,
+            message.GetExtension(unittest::repeated_uint32_extension_lite, 0));
+  EXPECT_EQ(204,
+            message.GetExtension(unittest::repeated_uint64_extension_lite, 0));
+  EXPECT_EQ(205,
+            message.GetExtension(unittest::repeated_sint32_extension_lite, 0));
+  EXPECT_EQ(206,
+            message.GetExtension(unittest::repeated_sint64_extension_lite, 0));
+  EXPECT_EQ(207,
+            message.GetExtension(unittest::repeated_fixed32_extension_lite, 0));
+  EXPECT_EQ(208,
+            message.GetExtension(unittest::repeated_fixed64_extension_lite, 0));
+  EXPECT_EQ(
+      209, message.GetExtension(unittest::repeated_sfixed32_extension_lite, 0));
+  EXPECT_EQ(
+      210, message.GetExtension(unittest::repeated_sfixed64_extension_lite, 0));
+  EXPECT_EQ(211,
+            message.GetExtension(unittest::repeated_float_extension_lite, 0));
+  EXPECT_EQ(212,
+            message.GetExtension(unittest::repeated_double_extension_lite, 0));
+  EXPECT_EQ(true,
+            message.GetExtension(unittest::repeated_bool_extension_lite, 0));
+  EXPECT_EQ("215",
+            message.GetExtension(unittest::repeated_string_extension_lite, 0));
+  EXPECT_EQ("216",
+            message.GetExtension(unittest::repeated_bytes_extension_lite, 0));
+
+  EXPECT_EQ(
+      217, message.GetExtension(unittest::repeatedgroup_extension_lite, 0).a());
+  EXPECT_EQ(
+      218,
+      message.GetExtension(unittest::repeated_nested_message_extension_lite, 0)
+          .bb());
+  EXPECT_EQ(
+      219,
+      message.GetExtension(unittest::repeated_foreign_message_extension_lite, 0)
+          .c());
+  EXPECT_EQ(
+      220,
+      message.GetExtension(unittest::repeated_import_message_extension_lite, 0)
+          .d());
+  EXPECT_EQ(
+      227,
+      message.GetExtension(unittest::repeated_lazy_message_extension_lite, 0)
+          .bb());
+
+  EXPECT_EQ(
+      unittest::TestAllTypesLite::BAR,
+      message.GetExtension(unittest::repeated_nested_enum_extension_lite, 0));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_BAR,
+      message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 0));
+  EXPECT_EQ(
+      unittest_import::IMPORT_LITE_BAR,
+      message.GetExtension(unittest::repeated_import_enum_extension_lite, 0));
+
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(501,
+            message.GetExtension(unittest::repeated_int32_extension_lite, 1));
+  EXPECT_EQ(502,
+            message.GetExtension(unittest::repeated_int64_extension_lite, 1));
+  EXPECT_EQ(503,
+            message.GetExtension(unittest::repeated_uint32_extension_lite, 1));
+  EXPECT_EQ(504,
+            message.GetExtension(unittest::repeated_uint64_extension_lite, 1));
+  EXPECT_EQ(505,
+            message.GetExtension(unittest::repeated_sint32_extension_lite, 1));
+  EXPECT_EQ(506,
+            message.GetExtension(unittest::repeated_sint64_extension_lite, 1));
+  EXPECT_EQ(507,
+            message.GetExtension(unittest::repeated_fixed32_extension_lite, 1));
+  EXPECT_EQ(508,
+            message.GetExtension(unittest::repeated_fixed64_extension_lite, 1));
+  EXPECT_EQ(
+      509, message.GetExtension(unittest::repeated_sfixed32_extension_lite, 1));
+  EXPECT_EQ(
+      510, message.GetExtension(unittest::repeated_sfixed64_extension_lite, 1));
+  EXPECT_EQ(511,
+            message.GetExtension(unittest::repeated_float_extension_lite, 1));
+  EXPECT_EQ(512,
+            message.GetExtension(unittest::repeated_double_extension_lite, 1));
+  EXPECT_EQ(true,
+            message.GetExtension(unittest::repeated_bool_extension_lite, 1));
+  EXPECT_EQ("515",
+            message.GetExtension(unittest::repeated_string_extension_lite, 1));
+  EXPECT_EQ("516",
+            message.GetExtension(unittest::repeated_bytes_extension_lite, 1));
+
+  EXPECT_EQ(
+      517, message.GetExtension(unittest::repeatedgroup_extension_lite, 1).a());
+  EXPECT_EQ(
+      518,
+      message.GetExtension(unittest::repeated_nested_message_extension_lite, 1)
+          .bb());
+  EXPECT_EQ(
+      519,
+      message.GetExtension(unittest::repeated_foreign_message_extension_lite, 1)
+          .c());
+  EXPECT_EQ(
+      520,
+      message.GetExtension(unittest::repeated_import_message_extension_lite, 1)
+          .d());
+  EXPECT_EQ(
+      527,
+      message.GetExtension(unittest::repeated_lazy_message_extension_lite, 1)
+          .bb());
+
+  EXPECT_EQ(
+      unittest::TestAllTypesLite::FOO,
+      message.GetExtension(unittest::repeated_nested_enum_extension_lite, 1));
+  EXPECT_EQ(
+      unittest::FOREIGN_LITE_FOO,
+      message.GetExtension(unittest::repeated_foreign_enum_extension_lite, 1));
+  EXPECT_EQ(
+      unittest_import::IMPORT_LITE_FOO,
+      message.GetExtension(unittest::repeated_import_enum_extension_lite, 1));
+
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::SetPackedExtensions(
+    unittest::TestPackedExtensionsLite* message) {
+  message->AddExtension(unittest::packed_int32_extension_lite, 601);
+  message->AddExtension(unittest::packed_int64_extension_lite, 602);
+  message->AddExtension(unittest::packed_uint32_extension_lite, 603);
+  message->AddExtension(unittest::packed_uint64_extension_lite, 604);
+  message->AddExtension(unittest::packed_sint32_extension_lite, 605);
+  message->AddExtension(unittest::packed_sint64_extension_lite, 606);
+  message->AddExtension(unittest::packed_fixed32_extension_lite, 607);
+  message->AddExtension(unittest::packed_fixed64_extension_lite, 608);
+  message->AddExtension(unittest::packed_sfixed32_extension_lite, 609);
+  message->AddExtension(unittest::packed_sfixed64_extension_lite, 610);
+  message->AddExtension(unittest::packed_float_extension_lite, 611);
+  message->AddExtension(unittest::packed_double_extension_lite, 612);
+  message->AddExtension(unittest::packed_bool_extension_lite, true);
+  message->AddExtension(unittest::packed_enum_extension_lite,
+                        unittest::FOREIGN_LITE_BAR);
+  // add a second one of each field
+  message->AddExtension(unittest::packed_int32_extension_lite, 701);
+  message->AddExtension(unittest::packed_int64_extension_lite, 702);
+  message->AddExtension(unittest::packed_uint32_extension_lite, 703);
+  message->AddExtension(unittest::packed_uint64_extension_lite, 704);
+  message->AddExtension(unittest::packed_sint32_extension_lite, 705);
+  message->AddExtension(unittest::packed_sint64_extension_lite, 706);
+  message->AddExtension(unittest::packed_fixed32_extension_lite, 707);
+  message->AddExtension(unittest::packed_fixed64_extension_lite, 708);
+  message->AddExtension(unittest::packed_sfixed32_extension_lite, 709);
+  message->AddExtension(unittest::packed_sfixed64_extension_lite, 710);
+  message->AddExtension(unittest::packed_float_extension_lite, 711);
+  message->AddExtension(unittest::packed_double_extension_lite, 712);
+  message->AddExtension(unittest::packed_bool_extension_lite, false);
+  message->AddExtension(unittest::packed_enum_extension_lite,
+                        unittest::FOREIGN_LITE_BAZ);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ModifyPackedExtensions(
+    unittest::TestPackedExtensionsLite* message) {
+  message->SetExtension(unittest::packed_int32_extension_lite, 1, 801);
+  message->SetExtension(unittest::packed_int64_extension_lite, 1, 802);
+  message->SetExtension(unittest::packed_uint32_extension_lite, 1, 803);
+  message->SetExtension(unittest::packed_uint64_extension_lite, 1, 804);
+  message->SetExtension(unittest::packed_sint32_extension_lite, 1, 805);
+  message->SetExtension(unittest::packed_sint64_extension_lite, 1, 806);
+  message->SetExtension(unittest::packed_fixed32_extension_lite, 1, 807);
+  message->SetExtension(unittest::packed_fixed64_extension_lite, 1, 808);
+  message->SetExtension(unittest::packed_sfixed32_extension_lite, 1, 809);
+  message->SetExtension(unittest::packed_sfixed64_extension_lite, 1, 810);
+  message->SetExtension(unittest::packed_float_extension_lite, 1, 811);
+  message->SetExtension(unittest::packed_double_extension_lite, 1, 812);
+  message->SetExtension(unittest::packed_bool_extension_lite, 1, true);
+  message->SetExtension(unittest::packed_enum_extension_lite, 1,
+                        unittest::FOREIGN_LITE_FOO);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectPackedExtensionsSet(
+    const unittest::TestPackedExtensionsLite& message) {
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_float_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_double_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_bool_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_enum_extension_lite));
+
+  EXPECT_EQ(601,
+            message.GetExtension(unittest::packed_int32_extension_lite, 0));
+  EXPECT_EQ(602,
+            message.GetExtension(unittest::packed_int64_extension_lite, 0));
+  EXPECT_EQ(603,
+            message.GetExtension(unittest::packed_uint32_extension_lite, 0));
+  EXPECT_EQ(604,
+            message.GetExtension(unittest::packed_uint64_extension_lite, 0));
+  EXPECT_EQ(605,
+            message.GetExtension(unittest::packed_sint32_extension_lite, 0));
+  EXPECT_EQ(606,
+            message.GetExtension(unittest::packed_sint64_extension_lite, 0));
+  EXPECT_EQ(607,
+            message.GetExtension(unittest::packed_fixed32_extension_lite, 0));
+  EXPECT_EQ(608,
+            message.GetExtension(unittest::packed_fixed64_extension_lite, 0));
+  EXPECT_EQ(609,
+            message.GetExtension(unittest::packed_sfixed32_extension_lite, 0));
+  EXPECT_EQ(610,
+            message.GetExtension(unittest::packed_sfixed64_extension_lite, 0));
+  EXPECT_EQ(611,
+            message.GetExtension(unittest::packed_float_extension_lite, 0));
+  EXPECT_EQ(612,
+            message.GetExtension(unittest::packed_double_extension_lite, 0));
+  EXPECT_EQ(true,
+            message.GetExtension(unittest::packed_bool_extension_lite, 0));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR,
+            message.GetExtension(unittest::packed_enum_extension_lite, 0));
+  EXPECT_EQ(701,
+            message.GetExtension(unittest::packed_int32_extension_lite, 1));
+  EXPECT_EQ(702,
+            message.GetExtension(unittest::packed_int64_extension_lite, 1));
+  EXPECT_EQ(703,
+            message.GetExtension(unittest::packed_uint32_extension_lite, 1));
+  EXPECT_EQ(704,
+            message.GetExtension(unittest::packed_uint64_extension_lite, 1));
+  EXPECT_EQ(705,
+            message.GetExtension(unittest::packed_sint32_extension_lite, 1));
+  EXPECT_EQ(706,
+            message.GetExtension(unittest::packed_sint64_extension_lite, 1));
+  EXPECT_EQ(707,
+            message.GetExtension(unittest::packed_fixed32_extension_lite, 1));
+  EXPECT_EQ(708,
+            message.GetExtension(unittest::packed_fixed64_extension_lite, 1));
+  EXPECT_EQ(709,
+            message.GetExtension(unittest::packed_sfixed32_extension_lite, 1));
+  EXPECT_EQ(710,
+            message.GetExtension(unittest::packed_sfixed64_extension_lite, 1));
+  EXPECT_EQ(711,
+            message.GetExtension(unittest::packed_float_extension_lite, 1));
+  EXPECT_EQ(712,
+            message.GetExtension(unittest::packed_double_extension_lite, 1));
+  EXPECT_EQ(false,
+            message.GetExtension(unittest::packed_bool_extension_lite, 1));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAZ,
+            message.GetExtension(unittest::packed_enum_extension_lite, 1));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectPackedExtensionsClear(
+    const unittest::TestPackedExtensionsLite& message) {
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_int32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_int64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_uint32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_uint64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sint32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sint64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_fixed32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_fixed64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sfixed32_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sfixed64_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_float_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_double_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_bool_extension_lite));
+  EXPECT_EQ(0, message.ExtensionSize(unittest::packed_enum_extension_lite));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtilLite::ExpectPackedExtensionsModified(
+    const unittest::TestPackedExtensionsLite& message) {
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed32_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed64_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_float_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_double_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_bool_extension_lite));
+  ASSERT_EQ(2, message.ExtensionSize(unittest::packed_enum_extension_lite));
+  EXPECT_EQ(601,
+            message.GetExtension(unittest::packed_int32_extension_lite, 0));
+  EXPECT_EQ(602,
+            message.GetExtension(unittest::packed_int64_extension_lite, 0));
+  EXPECT_EQ(603,
+            message.GetExtension(unittest::packed_uint32_extension_lite, 0));
+  EXPECT_EQ(604,
+            message.GetExtension(unittest::packed_uint64_extension_lite, 0));
+  EXPECT_EQ(605,
+            message.GetExtension(unittest::packed_sint32_extension_lite, 0));
+  EXPECT_EQ(606,
+            message.GetExtension(unittest::packed_sint64_extension_lite, 0));
+  EXPECT_EQ(607,
+            message.GetExtension(unittest::packed_fixed32_extension_lite, 0));
+  EXPECT_EQ(608,
+            message.GetExtension(unittest::packed_fixed64_extension_lite, 0));
+  EXPECT_EQ(609,
+            message.GetExtension(unittest::packed_sfixed32_extension_lite, 0));
+  EXPECT_EQ(610,
+            message.GetExtension(unittest::packed_sfixed64_extension_lite, 0));
+  EXPECT_EQ(611,
+            message.GetExtension(unittest::packed_float_extension_lite, 0));
+  EXPECT_EQ(612,
+            message.GetExtension(unittest::packed_double_extension_lite, 0));
+  EXPECT_EQ(true,
+            message.GetExtension(unittest::packed_bool_extension_lite, 0));
+  EXPECT_EQ(unittest::FOREIGN_LITE_BAR,
+            message.GetExtension(unittest::packed_enum_extension_lite, 0));
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(801,
+            message.GetExtension(unittest::packed_int32_extension_lite, 1));
+  EXPECT_EQ(802,
+            message.GetExtension(unittest::packed_int64_extension_lite, 1));
+  EXPECT_EQ(803,
+            message.GetExtension(unittest::packed_uint32_extension_lite, 1));
+  EXPECT_EQ(804,
+            message.GetExtension(unittest::packed_uint64_extension_lite, 1));
+  EXPECT_EQ(805,
+            message.GetExtension(unittest::packed_sint32_extension_lite, 1));
+  EXPECT_EQ(806,
+            message.GetExtension(unittest::packed_sint64_extension_lite, 1));
+  EXPECT_EQ(807,
+            message.GetExtension(unittest::packed_fixed32_extension_lite, 1));
+  EXPECT_EQ(808,
+            message.GetExtension(unittest::packed_fixed64_extension_lite, 1));
+  EXPECT_EQ(809,
+            message.GetExtension(unittest::packed_sfixed32_extension_lite, 1));
+  EXPECT_EQ(810,
+            message.GetExtension(unittest::packed_sfixed64_extension_lite, 1));
+  EXPECT_EQ(811,
+            message.GetExtension(unittest::packed_float_extension_lite, 1));
+  EXPECT_EQ(812,
+            message.GetExtension(unittest::packed_double_extension_lite, 1));
+  EXPECT_EQ(true,
+            message.GetExtension(unittest::packed_bool_extension_lite, 1));
+  EXPECT_EQ(unittest::FOREIGN_LITE_FOO,
+            message.GetExtension(unittest::packed_enum_extension_lite, 1));
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/test_util_lite.h b/src/google/protobuf/test_util_lite.h
new file mode 100644
index 0000000..34edf94
--- /dev/null
+++ b/src/google/protobuf/test_util_lite.h
@@ -0,0 +1,101 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_TEST_UTIL_LITE_H__
+#define GOOGLE_PROTOBUF_TEST_UTIL_LITE_H__
+
+#include <google/protobuf/unittest_lite.pb.h>
+
+namespace google {
+namespace protobuf {
+
+namespace unittest = protobuf_unittest;
+namespace unittest_import = protobuf_unittest_import;
+
+class TestUtilLite {
+ public:
+  // Set every field in the message to a unique value.
+  static void SetAllFields(unittest::TestAllTypesLite* message);
+  static void SetAllExtensions(unittest::TestAllExtensionsLite* message);
+  static void SetPackedFields(unittest::TestPackedTypesLite* message);
+  static void SetPackedExtensions(unittest::TestPackedExtensionsLite* message);
+
+  // Use the repeated versions of the set_*() accessors to modify all the
+  // 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);
+  static void ModifyRepeatedExtensions(
+      unittest::TestAllExtensionsLite* message);
+  static void ModifyPackedFields(unittest::TestPackedTypesLite* message);
+  static void ModifyPackedExtensions(
+      unittest::TestPackedExtensionsLite* message);
+
+  // Check that all fields have the values that they should have after
+  // Set*Fields() is called.
+  static void ExpectAllFieldsSet(const unittest::TestAllTypesLite& message);
+  static void ExpectAllExtensionsSet(
+      const unittest::TestAllExtensionsLite& message);
+  static void ExpectPackedFieldsSet(
+      const unittest::TestPackedTypesLite& message);
+  static void ExpectPackedExtensionsSet(
+      const unittest::TestPackedExtensionsLite& message);
+
+  // Expect that the message is modified as would be expected from
+  // Modify*Fields().
+  static void ExpectRepeatedFieldsModified(
+      const unittest::TestAllTypesLite& message);
+  static void ExpectRepeatedExtensionsModified(
+      const unittest::TestAllExtensionsLite& message);
+  static void ExpectPackedFieldsModified(
+      const unittest::TestPackedTypesLite& message);
+  static void ExpectPackedExtensionsModified(
+      const unittest::TestPackedExtensionsLite& message);
+
+  // Check that all fields have their default values.
+  static void ExpectClear(const unittest::TestAllTypesLite& message);
+  static void ExpectExtensionsClear(
+      const unittest::TestAllExtensionsLite& message);
+  static void ExpectPackedClear(const unittest::TestPackedTypesLite& message);
+  static void ExpectPackedExtensionsClear(
+      const unittest::TestPackedExtensionsLite& message);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TestUtilLite);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_TEST_UTIL_LITE_H__
diff --git a/src/google/protobuf/testdata/bad_utf8_string b/src/google/protobuf/testdata/bad_utf8_string
new file mode 100644
index 0000000..a1337ec
--- /dev/null
+++ b/src/google/protobuf/testdata/bad_utf8_string
@@ -0,0 +1 @@
+rÿ
\ No newline at end of file
diff --git a/src/google/protobuf/testdata/golden_message b/src/google/protobuf/testdata/golden_message
new file mode 100644
index 0000000..5825975
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message
Binary files differ
diff --git a/src/google/protobuf/testdata/golden_message_maps b/src/google/protobuf/testdata/golden_message_maps
new file mode 100644
index 0000000..c70a4d7
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_maps
Binary files differ
diff --git a/src/google/protobuf/testdata/golden_message_oneof_implemented b/src/google/protobuf/testdata/golden_message_oneof_implemented
new file mode 100644
index 0000000..794ca5e
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_oneof_implemented
Binary files differ
diff --git a/src/google/protobuf/testdata/golden_message_proto3 b/src/google/protobuf/testdata/golden_message_proto3
new file mode 100644
index 0000000..bd646a0
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_proto3
Binary files differ
diff --git a/src/google/protobuf/testdata/golden_packed_fields_message b/src/google/protobuf/testdata/golden_packed_fields_message
new file mode 100644
index 0000000..ee28d38
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_packed_fields_message
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/testdata/text_format_unittest_data.txt b/src/google/protobuf/testdata/text_format_unittest_data.txt
new file mode 100644
index 0000000..7a874b5
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data.txt
@@ -0,0 +1,134 @@
+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: "116"
+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"
+optional_public_import_message {
+  e: 126
+}
+optional_lazy_message {
+  bb: 127
+}
+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: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+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: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message {
+  bb: 227
+}
+repeated_lazy_message {
+  bb: 327
+}
+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: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_uint32: 601
+oneof_nested_message {
+  bb: 602
+}
+oneof_string: "603"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt b/src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt
new file mode 100644
index 0000000..86389c9
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt
@@ -0,0 +1,132 @@
+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: "116"
+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"
+optional_public_import_message {
+  e: 126
+}
+optional_lazy_message {
+  bb: 127
+}
+optional_unverified_lazy_message {
+  bb: 128
+}
+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: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+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: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message {
+  bb: 227
+}
+repeated_lazy_message {
+  bb: 327
+}
+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: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_data_pointy.txt b/src/google/protobuf/testdata/text_format_unittest_data_pointy.txt
new file mode 100644
index 0000000..788025c
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data_pointy.txt
@@ -0,0 +1,137 @@
+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: "116"
+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"
+optional_public_import_message <
+  e: 126
+>
+optional_lazy_message <
+  bb: 127
+>
+optional_unverified_lazy_message <
+  bb: 128
+>
+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: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+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: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message <
+  bb: 227
+>
+repeated_lazy_message <
+  bb: 327
+>
+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: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_uint32: 601
+oneof_nested_message <
+  bb: 602
+>
+oneof_string: "603"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt b/src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt
new file mode 100644
index 0000000..b2d3367
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt
@@ -0,0 +1,132 @@
+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: "116"
+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"
+optional_public_import_message <
+  e: 126
+>
+optional_lazy_message <
+  bb: 127
+>
+optional_unverified_lazy_message <
+  bb: 128
+>
+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: true
+repeated_bool: false
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "216"
+repeated_bytes: "316"
+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: BAR
+repeated_nested_enum: BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+repeated_lazy_message <
+  bb: 227
+>
+repeated_lazy_message <
+  bb: 327
+>
+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: "416"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
+oneof_bytes: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
new file mode 100644
index 0000000..5c3a03a
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
@@ -0,0 +1,137 @@
+[protobuf_unittest.optional_int32_extension]: 101
+[protobuf_unittest.optional_int64_extension]: 102
+[protobuf_unittest.optional_uint32_extension]: 103
+[protobuf_unittest.optional_uint64_extension]: 104
+[protobuf_unittest.optional_sint32_extension]: 105
+[protobuf_unittest.optional_sint64_extension]: 106
+[protobuf_unittest.optional_fixed32_extension]: 107
+[protobuf_unittest.optional_fixed64_extension]: 108
+[protobuf_unittest.optional_sfixed32_extension]: 109
+[protobuf_unittest.optional_sfixed64_extension]: 110
+[protobuf_unittest.optional_float_extension]: 111
+[protobuf_unittest.optional_double_extension]: 112
+[protobuf_unittest.optional_bool_extension]: true
+[protobuf_unittest.optional_string_extension]: "115"
+[protobuf_unittest.optional_bytes_extension]: "116"
+[protobuf_unittest.optionalgroup_extension] {
+  a: 117
+}
+[protobuf_unittest.optional_nested_message_extension] {
+  bb: 118
+}
+[protobuf_unittest.optional_foreign_message_extension] {
+  c: 119
+}
+[protobuf_unittest.optional_import_message_extension] {
+  d: 120
+}
+[protobuf_unittest.optional_nested_enum_extension]: BAZ
+[protobuf_unittest.optional_foreign_enum_extension]: FOREIGN_BAZ
+[protobuf_unittest.optional_import_enum_extension]: IMPORT_BAZ
+[protobuf_unittest.optional_string_piece_extension]: "124"
+[protobuf_unittest.optional_cord_extension]: "125"
+[protobuf_unittest.optional_public_import_message_extension] {
+  e: 126
+}
+[protobuf_unittest.optional_lazy_message_extension] {
+  bb: 127
+}
+[protobuf_unittest.optional_unverified_lazy_message_extension] {
+  bb: 128
+}
+[protobuf_unittest.repeated_int32_extension]: 201
+[protobuf_unittest.repeated_int32_extension]: 301
+[protobuf_unittest.repeated_int64_extension]: 202
+[protobuf_unittest.repeated_int64_extension]: 302
+[protobuf_unittest.repeated_uint32_extension]: 203
+[protobuf_unittest.repeated_uint32_extension]: 303
+[protobuf_unittest.repeated_uint64_extension]: 204
+[protobuf_unittest.repeated_uint64_extension]: 304
+[protobuf_unittest.repeated_sint32_extension]: 205
+[protobuf_unittest.repeated_sint32_extension]: 305
+[protobuf_unittest.repeated_sint64_extension]: 206
+[protobuf_unittest.repeated_sint64_extension]: 306
+[protobuf_unittest.repeated_fixed32_extension]: 207
+[protobuf_unittest.repeated_fixed32_extension]: 307
+[protobuf_unittest.repeated_fixed64_extension]: 208
+[protobuf_unittest.repeated_fixed64_extension]: 308
+[protobuf_unittest.repeated_sfixed32_extension]: 209
+[protobuf_unittest.repeated_sfixed32_extension]: 309
+[protobuf_unittest.repeated_sfixed64_extension]: 210
+[protobuf_unittest.repeated_sfixed64_extension]: 310
+[protobuf_unittest.repeated_float_extension]: 211
+[protobuf_unittest.repeated_float_extension]: 311
+[protobuf_unittest.repeated_double_extension]: 212
+[protobuf_unittest.repeated_double_extension]: 312
+[protobuf_unittest.repeated_bool_extension]: true
+[protobuf_unittest.repeated_bool_extension]: false
+[protobuf_unittest.repeated_string_extension]: "215"
+[protobuf_unittest.repeated_string_extension]: "315"
+[protobuf_unittest.repeated_bytes_extension]: "216"
+[protobuf_unittest.repeated_bytes_extension]: "316"
+[protobuf_unittest.repeatedgroup_extension] {
+  a: 217
+}
+[protobuf_unittest.repeatedgroup_extension] {
+  a: 317
+}
+[protobuf_unittest.repeated_nested_message_extension] {
+  bb: 218
+}
+[protobuf_unittest.repeated_nested_message_extension] {
+  bb: 318
+}
+[protobuf_unittest.repeated_foreign_message_extension] {
+  c: 219
+}
+[protobuf_unittest.repeated_foreign_message_extension] {
+  c: 319
+}
+[protobuf_unittest.repeated_import_message_extension] {
+  d: 220
+}
+[protobuf_unittest.repeated_import_message_extension] {
+  d: 320
+}
+[protobuf_unittest.repeated_nested_enum_extension]: BAR
+[protobuf_unittest.repeated_nested_enum_extension]: BAZ
+[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAR
+[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAZ
+[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAR
+[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAZ
+[protobuf_unittest.repeated_string_piece_extension]: "224"
+[protobuf_unittest.repeated_string_piece_extension]: "324"
+[protobuf_unittest.repeated_cord_extension]: "225"
+[protobuf_unittest.repeated_cord_extension]: "325"
+[protobuf_unittest.repeated_lazy_message_extension] {
+  bb: 227
+}
+[protobuf_unittest.repeated_lazy_message_extension] {
+  bb: 327
+}
+[protobuf_unittest.default_int32_extension]: 401
+[protobuf_unittest.default_int64_extension]: 402
+[protobuf_unittest.default_uint32_extension]: 403
+[protobuf_unittest.default_uint64_extension]: 404
+[protobuf_unittest.default_sint32_extension]: 405
+[protobuf_unittest.default_sint64_extension]: 406
+[protobuf_unittest.default_fixed32_extension]: 407
+[protobuf_unittest.default_fixed64_extension]: 408
+[protobuf_unittest.default_sfixed32_extension]: 409
+[protobuf_unittest.default_sfixed64_extension]: 410
+[protobuf_unittest.default_float_extension]: 411
+[protobuf_unittest.default_double_extension]: 412
+[protobuf_unittest.default_bool_extension]: false
+[protobuf_unittest.default_string_extension]: "415"
+[protobuf_unittest.default_bytes_extension]: "416"
+[protobuf_unittest.default_nested_enum_extension]: FOO
+[protobuf_unittest.default_foreign_enum_extension]: FOREIGN_FOO
+[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
+[protobuf_unittest.default_string_piece_extension]: "424"
+[protobuf_unittest.default_cord_extension]: "425"
+[protobuf_unittest.oneof_uint32_extension]: 601
+[protobuf_unittest.oneof_nested_message_extension] {
+  bb: 602
+}
+[protobuf_unittest.oneof_string_extension]: "603"
+[protobuf_unittest.oneof_bytes_extension]: "604"
diff --git a/src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt b/src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt
new file mode 100644
index 0000000..4233ca7
--- /dev/null
+++ b/src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt
@@ -0,0 +1,137 @@
+[protobuf_unittest.optional_int32_extension]: 101
+[protobuf_unittest.optional_int64_extension]: 102
+[protobuf_unittest.optional_uint32_extension]: 103
+[protobuf_unittest.optional_uint64_extension]: 104
+[protobuf_unittest.optional_sint32_extension]: 105
+[protobuf_unittest.optional_sint64_extension]: 106
+[protobuf_unittest.optional_fixed32_extension]: 107
+[protobuf_unittest.optional_fixed64_extension]: 108
+[protobuf_unittest.optional_sfixed32_extension]: 109
+[protobuf_unittest.optional_sfixed64_extension]: 110
+[protobuf_unittest.optional_float_extension]: 111
+[protobuf_unittest.optional_double_extension]: 112
+[protobuf_unittest.optional_bool_extension]: true
+[protobuf_unittest.optional_string_extension]: "115"
+[protobuf_unittest.optional_bytes_extension]: "116"
+[protobuf_unittest.optionalgroup_extension] <
+  a: 117
+>
+[protobuf_unittest.optional_nested_message_extension] <
+  bb: 118
+>
+[protobuf_unittest.optional_foreign_message_extension] <
+  c: 119
+>
+[protobuf_unittest.optional_import_message_extension] <
+  d: 120
+>
+[protobuf_unittest.optional_nested_enum_extension]: BAZ
+[protobuf_unittest.optional_foreign_enum_extension]: FOREIGN_BAZ
+[protobuf_unittest.optional_import_enum_extension]: IMPORT_BAZ
+[protobuf_unittest.optional_string_piece_extension]: "124"
+[protobuf_unittest.optional_cord_extension]: "125"
+[protobuf_unittest.optional_public_import_message_extension] <
+  e: 126
+>
+[protobuf_unittest.optional_lazy_message_extension] <
+  bb: 127
+>
+[protobuf_unittest.optional_unverified_lazy_message_extension] <
+  bb: 128
+>
+[protobuf_unittest.repeated_int32_extension]: 201
+[protobuf_unittest.repeated_int32_extension]: 301
+[protobuf_unittest.repeated_int64_extension]: 202
+[protobuf_unittest.repeated_int64_extension]: 302
+[protobuf_unittest.repeated_uint32_extension]: 203
+[protobuf_unittest.repeated_uint32_extension]: 303
+[protobuf_unittest.repeated_uint64_extension]: 204
+[protobuf_unittest.repeated_uint64_extension]: 304
+[protobuf_unittest.repeated_sint32_extension]: 205
+[protobuf_unittest.repeated_sint32_extension]: 305
+[protobuf_unittest.repeated_sint64_extension]: 206
+[protobuf_unittest.repeated_sint64_extension]: 306
+[protobuf_unittest.repeated_fixed32_extension]: 207
+[protobuf_unittest.repeated_fixed32_extension]: 307
+[protobuf_unittest.repeated_fixed64_extension]: 208
+[protobuf_unittest.repeated_fixed64_extension]: 308
+[protobuf_unittest.repeated_sfixed32_extension]: 209
+[protobuf_unittest.repeated_sfixed32_extension]: 309
+[protobuf_unittest.repeated_sfixed64_extension]: 210
+[protobuf_unittest.repeated_sfixed64_extension]: 310
+[protobuf_unittest.repeated_float_extension]: 211
+[protobuf_unittest.repeated_float_extension]: 311
+[protobuf_unittest.repeated_double_extension]: 212
+[protobuf_unittest.repeated_double_extension]: 312
+[protobuf_unittest.repeated_bool_extension]: true
+[protobuf_unittest.repeated_bool_extension]: false
+[protobuf_unittest.repeated_string_extension]: "215"
+[protobuf_unittest.repeated_string_extension]: "315"
+[protobuf_unittest.repeated_bytes_extension]: "216"
+[protobuf_unittest.repeated_bytes_extension]: "316"
+[protobuf_unittest.repeatedgroup_extension] <
+  a: 217
+>
+[protobuf_unittest.repeatedgroup_extension] <
+  a: 317
+>
+[protobuf_unittest.repeated_nested_message_extension] <
+  bb: 218
+>
+[protobuf_unittest.repeated_nested_message_extension] <
+  bb: 318
+>
+[protobuf_unittest.repeated_foreign_message_extension] <
+  c: 219
+>
+[protobuf_unittest.repeated_foreign_message_extension] <
+  c: 319
+>
+[protobuf_unittest.repeated_import_message_extension] <
+  d: 220
+>
+[protobuf_unittest.repeated_import_message_extension] <
+  d: 320
+>
+[protobuf_unittest.repeated_nested_enum_extension]: BAR
+[protobuf_unittest.repeated_nested_enum_extension]: BAZ
+[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAR
+[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAZ
+[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAR
+[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAZ
+[protobuf_unittest.repeated_string_piece_extension]: "224"
+[protobuf_unittest.repeated_string_piece_extension]: "324"
+[protobuf_unittest.repeated_cord_extension]: "225"
+[protobuf_unittest.repeated_cord_extension]: "325"
+[protobuf_unittest.repeated_lazy_message_extension] <
+  bb: 227
+>
+[protobuf_unittest.repeated_lazy_message_extension] <
+  bb: 327
+>
+[protobuf_unittest.default_int32_extension]: 401
+[protobuf_unittest.default_int64_extension]: 402
+[protobuf_unittest.default_uint32_extension]: 403
+[protobuf_unittest.default_uint64_extension]: 404
+[protobuf_unittest.default_sint32_extension]: 405
+[protobuf_unittest.default_sint64_extension]: 406
+[protobuf_unittest.default_fixed32_extension]: 407
+[protobuf_unittest.default_fixed64_extension]: 408
+[protobuf_unittest.default_sfixed32_extension]: 409
+[protobuf_unittest.default_sfixed64_extension]: 410
+[protobuf_unittest.default_float_extension]: 411
+[protobuf_unittest.default_double_extension]: 412
+[protobuf_unittest.default_bool_extension]: false
+[protobuf_unittest.default_string_extension]: "415"
+[protobuf_unittest.default_bytes_extension]: "416"
+[protobuf_unittest.default_nested_enum_extension]: FOO
+[protobuf_unittest.default_foreign_enum_extension]: FOREIGN_FOO
+[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
+[protobuf_unittest.default_string_piece_extension]: "424"
+[protobuf_unittest.default_cord_extension]: "425"
+[protobuf_unittest.oneof_uint32_extension]: 601
+[protobuf_unittest.oneof_nested_message_extension] <
+  bb: 602
+>
+[protobuf_unittest.oneof_string_extension]: "603"
+[protobuf_unittest.oneof_bytes_extension]: "604"
diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc
new file mode 100644
index 0000000..7b62887
--- /dev/null
+++ b/src/google/protobuf/testing/file.cc
@@ -0,0 +1,215 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// emulates google3/file/base/file.cc
+
+#include <google/protobuf/testing/file.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN  // yeah, right
+#include <windows.h>         // Find*File().  :(
+// #include <direct.h>
+#else
+#include <dirent.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _WIN32
+// Windows doesn't have symbolic links.
+#define lstat stat
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+#endif
+
+#ifdef _WIN32
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::chdir;
+using google::protobuf::io::win32::fopen;
+using google::protobuf::io::win32::mkdir;
+using google::protobuf::io::win32::stat;
+#endif
+
+bool File::Exists(const std::string& name) {
+  return access(name.c_str(), F_OK) == 0;
+}
+
+bool File::ReadFileToString(const std::string& name, std::string* output,
+                            bool text_mode) {
+  char buffer[1024];
+  FILE* file = fopen(name.c_str(), text_mode ? "rt" : "rb");
+  if (file == NULL) return false;
+
+  while (true) {
+    size_t n = fread(buffer, 1, sizeof(buffer), file);
+    if (n <= 0) break;
+    output->append(buffer, n);
+  }
+
+  int error = ferror(file);
+  if (fclose(file) != 0) return false;
+  return error == 0;
+}
+
+void File::ReadFileToStringOrDie(const std::string& name, std::string* output) {
+  GOOGLE_CHECK(ReadFileToString(name, output)) << "Could not read: " << name;
+}
+
+bool File::WriteStringToFile(const std::string& contents,
+                             const std::string& name) {
+  FILE* file = fopen(name.c_str(), "wb");
+  if (file == NULL) {
+    GOOGLE_LOG(ERROR) << "fopen(" << name << ", \"wb\"): " << strerror(errno);
+    return false;
+  }
+
+  if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
+    GOOGLE_LOG(ERROR) << "fwrite(" << name << "): " << strerror(errno);
+    fclose(file);
+    return false;
+  }
+
+  if (fclose(file) != 0) {
+    return false;
+  }
+  return true;
+}
+
+void File::WriteStringToFileOrDie(const std::string& contents,
+                                  const std::string& name) {
+  FILE* file = fopen(name.c_str(), "wb");
+  GOOGLE_CHECK(file != NULL)
+      << "fopen(" << name << ", \"wb\"): " << strerror(errno);
+  GOOGLE_CHECK_EQ(fwrite(contents.data(), 1, contents.size(), file),
+                  contents.size())
+      << "fwrite(" << name << "): " << strerror(errno);
+  GOOGLE_CHECK(fclose(file) == 0)
+      << "fclose(" << name << "): " << strerror(errno);
+}
+
+bool File::CreateDir(const std::string& name, int mode) {
+  if (!name.empty()) {
+    GOOGLE_CHECK_OK(name[name.size() - 1] != '.');
+  }
+  return mkdir(name.c_str(), mode) == 0;
+}
+
+bool File::RecursivelyCreateDir(const std::string& path, int mode) {
+  if (CreateDir(path, mode)) return true;
+
+  if (Exists(path)) return false;
+
+  // Try creating the parent.
+  std::string::size_type slashpos = path.find_last_of('/');
+  if (slashpos == std::string::npos) {
+    // No parent given.
+    return false;
+  }
+
+  return RecursivelyCreateDir(path.substr(0, slashpos), mode) &&
+         CreateDir(path, mode);
+}
+
+void File::DeleteRecursively(const std::string& name, void* dummy1,
+                             void* dummy2) {
+  if (name.empty()) return;
+
+  // We don't care too much about error checking here since this is only used
+  // in tests to delete temporary directories that are under /tmp anyway.
+
+#ifdef _MSC_VER
+  // This interface is so weird.
+  WIN32_FIND_DATAA find_data;
+  HANDLE find_handle = FindFirstFileA((name + "/*").c_str(), &find_data);
+  if (find_handle == INVALID_HANDLE_VALUE) {
+    // Just delete it, whatever it is.
+    DeleteFileA(name.c_str());
+    RemoveDirectoryA(name.c_str());
+    return;
+  }
+
+  do {
+    std::string entry_name = find_data.cFileName;
+    if (entry_name != "." && entry_name != "..") {
+      std::string path = name + "/" + entry_name;
+      if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+        DeleteRecursively(path, NULL, NULL);
+        RemoveDirectoryA(path.c_str());
+      } else {
+        DeleteFileA(path.c_str());
+      }
+    }
+  } while(FindNextFileA(find_handle, &find_data));
+  FindClose(find_handle);
+
+  RemoveDirectoryA(name.c_str());
+#else
+  // Use opendir()!  Yay!
+  // lstat = Don't follow symbolic links.
+  struct stat stats;
+  if (lstat(name.c_str(), &stats) != 0) return;
+
+  if (S_ISDIR(stats.st_mode)) {
+    DIR* dir = opendir(name.c_str());
+    if (dir != NULL) {
+      while (true) {
+        struct dirent* entry = readdir(dir);
+        if (entry == NULL) break;
+        std::string entry_name = entry->d_name;
+        if (entry_name != "." && entry_name != "..") {
+          DeleteRecursively(name + "/" + entry_name, NULL, NULL);
+        }
+      }
+    }
+
+    closedir(dir);
+    rmdir(name.c_str());
+
+  } else if (S_ISREG(stats.st_mode)) {
+    remove(name.c_str());
+  }
+#endif
+}
+
+bool File::ChangeWorkingDirectory(const std::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
new file mode 100644
index 0000000..f18f685
--- /dev/null
+++ b/src/google/protobuf/testing/file.h
@@ -0,0 +1,107 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// emulates google3/file/base/file.h
+
+#ifndef GOOGLE_PROTOBUF_TESTING_FILE_H__
+#define GOOGLE_PROTOBUF_TESTING_FILE_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+const int DEFAULT_FILE_MODE = 0777;
+
+// Protocol buffer code only uses a couple static methods of File, and only
+// in tests.
+class File {
+ public:
+  // Check if the file exists.
+  static bool Exists(const std::string& name);
+
+  // Read an entire file to a string.  Return true if successful, false
+  // otherwise.
+  static bool ReadFileToString(const std::string& name, std::string* output,
+                               bool text_mode = false);
+
+  // Same as above, but crash on failure.
+  static void ReadFileToStringOrDie(const std::string& name,
+                                    std::string* output);
+
+  // Create a file and write a string to it.
+  static bool WriteStringToFile(const std::string& contents,
+                                const std::string& name);
+
+  // Same as above, but crash on failure.
+  static void WriteStringToFileOrDie(const std::string& contents,
+                                     const std::string& name);
+
+  // Create a directory.
+  static bool CreateDir(const std::string& name, int mode);
+
+  // Create a directory and all parent directories if necessary.
+  static bool RecursivelyCreateDir(const std::string& path, int mode);
+
+  // If "name" is a file, we delete it.  If it is a directory, we
+  // call DeleteRecursively() for each file or directory (other than
+  // dot and double-dot) within it, and then delete the directory itself.
+  // The "dummy" parameters have a meaning in the original version of this
+  // method but they are not used anywhere in protocol buffers.
+  static void DeleteRecursively(const std::string& name, void* dummy1,
+                                void* dummy2);
+
+  // Change working directory to given directory.
+  static bool ChangeWorkingDirectory(const std::string& new_working_directory);
+
+  static bool GetContents(const std::string& name, std::string* output,
+                          bool /*is_default*/) {
+    return ReadFileToString(name, output);
+  }
+
+  static bool GetContentsAsText(const std::string& name, std::string* output,
+                                bool /*is_default*/) {
+    return ReadFileToString(name, output, true);
+  }
+
+  static bool SetContents(const std::string& name, const std::string& contents,
+                          bool /*is_default*/) {
+    return WriteStringToFile(contents, name);
+  }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(File);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_TESTING_FILE_H__
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
new file mode 100644
index 0000000..88343f9
--- /dev/null
+++ b/src/google/protobuf/testing/googletest.cc
@@ -0,0 +1,302 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)
+// emulates google3/testing/base/public/googletest.cc
+
+#include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+// #include <direct.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <iostream>
+#include <fstream>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _WIN32
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::dup2;
+using google::protobuf::io::win32::dup;
+using google::protobuf::io::win32::mkdir;
+using google::protobuf::io::win32::open;
+#endif
+
+#ifndef O_BINARY
+#ifdef _O_BINARY
+#define O_BINARY _O_BINARY
+#else
+#define O_BINARY 0     // If this isn't defined, the platform doesn't need it.
+#endif
+#endif
+
+std::string TestSourceDir() {
+#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+#ifdef GOOGLE_PROTOBUF_TEST_SOURCE_PATH
+  return GOOGLE_PROTOBUF_TEST_SOURCE_PATH;
+#else
+#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.
+  std::string prefix = ".";
+
+  // Keep looking further up the directory tree until we find
+  // src/.../descriptor.cc. It is important to look for a particular file,
+  // keeping in mind that with Bazel builds the directory structure under
+  // bazel-bin/ looks similar to the main directory tree in the Git repo.
+  while (!File::Exists(prefix + "/src/google/protobuf/descriptor.cc")) {
+    if (!File::Exists(prefix)) {
+      GOOGLE_LOG(FATAL)
+        << "Could not find protobuf source code.  Please run tests from "
+           "somewhere within the protobuf source package.";
+    }
+    prefix += "/..";
+  }
+  return prefix + "/src";
+#endif  // GOOGLE_PROTOBUF_TEST_SOURCE_PATH
+#else
+  return "third_party/protobuf/src";
+#endif  // GOOGLE_THIRD_PARTY_PROTOBUF
+}
+
+namespace {
+
+std::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 std::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.
+  char b[L_tmpnam + 1];     // HPUX multithread return 0 if s is 0
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+  std::string result = tmpnam(b);
+#pragma GCC diagnostic pop
+#ifdef _WIN32
+  // Avoid a trailing dot by changing it to an underscore. On Win32 the names of
+  // files and directories can, but should not, end with dot.
+  //
+  // In MS-DOS and FAT16 filesystem the filenames were 8dot3 style so it didn't
+  // make sense to have a name ending in dot without an extension, so the shell
+  // silently ignored trailing dots. To this day the Win32 API still maintains
+  // this behavior and silently ignores trailing dots in path arguments of
+  // functions such as CreateFile{A,W}. Even POSIX API function implementations
+  // seem to wrap the Win32 API functions (e.g. CreateDirectoryA) and behave
+  // this way.
+  // It's possible to avoid this behavior and create files / directories with
+  // trailing dots (using CreateFileW / CreateDirectoryW and prefixing the path
+  // with "\\?\") but these will be degenerate in the sense that you cannot
+  // chdir into such directories (or navigate into them with Windows Explorer)
+  // nor can you open such files with some programs (e.g. Notepad).
+  if (result[result.size() - 1] == '.') {
+    result[result.size() - 1] = '_';
+  }
+  // On Win32, tmpnam() returns a file prefixed with '\', but which is supposed
+  // to be used in the current working directory.  WTF?
+  if (HasPrefixString(result, "\\")) {
+    result.erase(0, 1);
+  }
+  // The Win32 API accepts forward slashes as a path delimiter as long as the
+  // path doesn't use the "\\?\" prefix.
+  // Let's avoid confusion and use only forward slashes.
+  result = StringReplace(result, "\\", "/", true);
+#endif  // _WIN32
+  return result;
+}
+
+// Creates a temporary directory on demand and deletes it when the process
+// quits.
+class TempDirDeleter {
+ public:
+  TempDirDeleter() {}
+  ~TempDirDeleter() {
+    if (!name_.empty()) {
+      File::DeleteRecursively(name_, NULL, NULL);
+    }
+  }
+
+  std::string GetTempDir() {
+    if (name_.empty()) {
+      name_ = GetTemporaryDirectoryName();
+      GOOGLE_CHECK(mkdir(name_.c_str(), 0777) == 0) << strerror(errno);
+
+      // Stick a file in the directory that tells people what this is, in case
+      // we abort and don't get a chance to delete it.
+      File::WriteStringToFileOrDie("", name_ + "/TEMP_DIR_FOR_PROTOBUF_TESTS");
+    }
+    return name_;
+  }
+
+ private:
+  std::string name_;
+};
+
+TempDirDeleter temp_dir_deleter_;
+
+}  // namespace
+
+std::string TestTempDir() { return temp_dir_deleter_.GetTempDir(); }
+
+// TODO(kenton):  Share duplicated code below.  Too busy/lazy for now.
+
+static std::string stdout_capture_filename_;
+static std::string stderr_capture_filename_;
+static int original_stdout_ = -1;
+static int original_stderr_ = -1;
+
+void CaptureTestStdout() {
+  GOOGLE_CHECK_EQ(original_stdout_, -1) << "Already capturing.";
+
+  stdout_capture_filename_ = TestTempDir() + "/captured_stdout";
+
+  int fd = open(stdout_capture_filename_.c_str(),
+                O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777);
+  GOOGLE_CHECK(fd >= 0) << "open: " << strerror(errno);
+
+  original_stdout_ = dup(1);
+  close(1);
+  dup2(fd, 1);
+  close(fd);
+}
+
+void CaptureTestStderr() {
+  GOOGLE_CHECK_EQ(original_stderr_, -1) << "Already capturing.";
+
+  stderr_capture_filename_ = TestTempDir() + "/captured_stderr";
+
+  int fd = open(stderr_capture_filename_.c_str(),
+                O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0777);
+  GOOGLE_CHECK(fd >= 0) << "open: " << strerror(errno);
+
+  original_stderr_ = dup(2);
+  close(2);
+  dup2(fd, 2);
+  close(fd);
+}
+
+std::string GetCapturedTestStdout() {
+  GOOGLE_CHECK_NE(original_stdout_, -1) << "Not capturing.";
+
+  close(1);
+  dup2(original_stdout_, 1);
+  original_stdout_ = -1;
+
+  std::string result;
+  File::ReadFileToStringOrDie(stdout_capture_filename_, &result);
+
+  remove(stdout_capture_filename_.c_str());
+
+  return result;
+}
+
+std::string GetCapturedTestStderr() {
+  GOOGLE_CHECK_NE(original_stderr_, -1) << "Not capturing.";
+
+  close(2);
+  dup2(original_stderr_, 2);
+  original_stderr_ = -1;
+
+  std::string result;
+  File::ReadFileToStringOrDie(stderr_capture_filename_, &result);
+
+  remove(stderr_capture_filename_.c_str());
+
+  return result;
+}
+
+ScopedMemoryLog* ScopedMemoryLog::active_log_ = NULL;
+
+ScopedMemoryLog::ScopedMemoryLog() {
+  GOOGLE_CHECK(active_log_ == NULL);
+  active_log_ = this;
+  old_handler_ = SetLogHandler(&HandleLog);
+}
+
+ScopedMemoryLog::~ScopedMemoryLog() {
+  SetLogHandler(old_handler_);
+  active_log_ = NULL;
+}
+
+const std::vector<std::string>& ScopedMemoryLog::GetMessages(LogLevel level) {
+  GOOGLE_CHECK(level == ERROR ||
+               level == WARNING);
+  return messages_[level];
+}
+
+void ScopedMemoryLog::HandleLog(LogLevel level, const char* filename, int line,
+                                const std::string& message) {
+  GOOGLE_CHECK(active_log_ != NULL);
+  if (level == ERROR || level == WARNING) {
+    active_log_->messages_[level].push_back(message);
+  }
+}
+
+namespace {
+
+// Force shutdown at process exit so that we can test for memory leaks.  To
+// actually check for leaks, I suggest using the heap checker included with
+// google-perftools.  Set it to "draconian" mode to ensure that every last
+// call to malloc() has a corresponding free().
+struct ForceShutdown {
+  ~ForceShutdown() {
+    ShutdownProtobufLibrary();
+    // Test to shutdown the library twice, which should succeed.
+    ShutdownProtobufLibrary();
+  }
+} force_shutdown;
+
+}  // namespace
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/testing/googletest.h b/src/google/protobuf/testing/googletest.h
new file mode 100644
index 0000000..6a0c694
--- /dev/null
+++ b/src/google/protobuf/testing/googletest.h
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// emulates google3/testing/base/public/googletest.h
+
+#ifndef GOOGLE_PROTOBUF_GOOGLETEST_H__
+#define GOOGLE_PROTOBUF_GOOGLETEST_H__
+
+#include <map>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <gmock/gmock.h>
+// Disable death tests if we use exceptions in CHECK().
+#if !PROTOBUF_USE_EXCEPTIONS && defined(GTEST_HAS_DEATH_TEST) && \
+    !GTEST_OS_WINDOWS
+#define PROTOBUF_HAS_DEATH_TEST
+#endif
+
+namespace google {
+namespace protobuf {
+
+// When running unittests, get the directory containing the source code.
+std::string TestSourceDir();
+
+// When running unittests, get a directory where temporary files may be
+// placed.
+std::string TestTempDir();
+
+// Capture all text written to stdout or stderr.
+void CaptureTestStdout();
+void CaptureTestStderr();
+
+// Stop capturing stdout or stderr and return the text captured.
+std::string GetCapturedTestStdout();
+std::string GetCapturedTestStderr();
+
+// For use with ScopedMemoryLog::GetMessages().  Inside Google the LogLevel
+// constants don't have the LOGLEVEL_ prefix, so the code that used
+// ScopedMemoryLog refers to LOGLEVEL_ERROR as just ERROR.
+#undef ERROR  // defend against promiscuous windows.h
+static const LogLevel ERROR = LOGLEVEL_ERROR;
+static const LogLevel WARNING = LOGLEVEL_WARNING;
+
+// Receives copies of all LOG(ERROR) messages while in scope.  Sample usage:
+//   {
+//     ScopedMemoryLog log;  // constructor registers object as a log sink
+//     SomeRoutineThatMayLogMessages();
+//     const vector<string>& warnings = log.GetMessages(ERROR);
+//   }  // destructor unregisters object as a log sink
+// This is a dummy implementation which covers only what is used by protocol
+// buffer unit tests.
+class ScopedMemoryLog {
+ public:
+  ScopedMemoryLog();
+  virtual ~ScopedMemoryLog();
+
+  // Fetches all messages with the given severity level.
+  const std::vector<std::string>& GetMessages(LogLevel error);
+
+ private:
+  std::map<LogLevel, std::vector<std::string> > messages_;
+  LogHandler* old_handler_;
+
+  static void HandleLog(LogLevel level, const char* filename, int line,
+                        const std::string& message);
+
+  static ScopedMemoryLog* active_log_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ScopedMemoryLog);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_GOOGLETEST_H__
diff --git a/src/google/protobuf/testing/zcgunzip.cc b/src/google/protobuf/testing/zcgunzip.cc
new file mode 100644
index 0000000..68f8172
--- /dev/null
+++ b/src/google/protobuf/testing/zcgunzip.cc
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2009 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: brianolson@google.com (Brian Olson)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Test program to verify that GzipInputStream is compatible with command line
+// gunzip or java.util.zip.GzipInputStream
+//
+// Reads gzip stream on standard input and writes decompressed data to standard
+// output.
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.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>
+
+using google::protobuf::io::FileInputStream;
+using google::protobuf::io::GzipInputStream;
+
+int main(int argc, const char** argv) {
+  FileInputStream fin(STDIN_FILENO);
+  GzipInputStream in(&fin);
+
+  while (true) {
+    const void* inptr;
+    int inlen;
+    bool ok;
+    ok = in.Next(&inptr, &inlen);
+    if (!ok) {
+      break;
+    }
+    if (inlen > 0) {
+      int err = write(STDOUT_FILENO, inptr, inlen);
+      if (err != inlen) {
+        fprintf(stderr, "write unexpectedly returned %d.\n", err);
+        return 1;
+      }
+    }
+  }
+
+  return 0;
+}
diff --git a/src/google/protobuf/testing/zcgzip.cc b/src/google/protobuf/testing/zcgzip.cc
new file mode 100644
index 0000000..808d058
--- /dev/null
+++ b/src/google/protobuf/testing/zcgzip.cc
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2009 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: brianolson@google.com (Brian Olson)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Test program to verify that GzipOutputStream is compatible with command line
+// gzip or java.util.zip.GzipOutputStream
+//
+// Reads data on standard input and writes compressed gzip stream to standard
+// output.
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.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>
+
+using google::protobuf::io::FileOutputStream;
+using google::protobuf::io::GzipOutputStream;
+
+int main(int argc, const char** argv) {
+  FileOutputStream fout(STDOUT_FILENO);
+  GzipOutputStream out(&fout);
+  int readlen;
+
+  while (true) {
+    void* outptr;
+    int outlen;
+    bool ok;
+    do {
+      ok = out.Next(&outptr, &outlen);
+      if (!ok) {
+        break;
+      }
+    } while (outlen <= 0);
+    readlen = read(STDIN_FILENO, outptr, outlen);
+    if (readlen <= 0) {
+      out.BackUp(outlen);
+      break;
+    }
+    if (readlen < outlen) {
+      out.BackUp(outlen - readlen);
+    }
+  }
+
+  return 0;
+}
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
new file mode 100644
index 0000000..05987d3
--- /dev/null
+++ b/src/google/protobuf/text_format.cc
@@ -0,0 +1,2746 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+
+#include <google/protobuf/text_format.h>
+
+#include <float.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <atomic>
+#include <climits>
+#include <cmath>
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+inline bool IsHexNumber(const std::string& str) {
+  return (str.length() >= 2 && str[0] == '0' &&
+          (str[1] == 'x' || str[1] == 'X'));
+}
+
+inline bool IsOctNumber(const std::string& str) {
+  return (str.length() >= 2 && str[0] == '0' &&
+          (str[1] >= '0' && str[1] < '8'));
+}
+
+}  // namespace
+
+namespace internal {
+const char kDebugStringSilentMarker[] = "";
+const char kDebugStringSilentMarkerForDetection[] = "\t ";
+
+// Controls insertion of kDebugStringSilentMarker.
+PROTOBUF_EXPORT std::atomic<bool> enable_debug_text_format_marker;
+}  // namespace internal
+
+std::string Message::DebugString() const {
+  std::string debug_string;
+
+  TextFormat::Printer printer;
+  printer.SetExpandAny(true);
+  printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load(
+      std::memory_order_relaxed));
+
+  printer.PrintToString(*this, &debug_string);
+
+  return debug_string;
+}
+
+std::string Message::ShortDebugString() const {
+  std::string debug_string;
+
+  TextFormat::Printer printer;
+  printer.SetSingleLineMode(true);
+  printer.SetExpandAny(true);
+  printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load(
+      std::memory_order_relaxed));
+
+  printer.PrintToString(*this, &debug_string);
+  // Single line mode currently might have an extra space at the end.
+  if (!debug_string.empty() && debug_string[debug_string.size() - 1] == ' ') {
+    debug_string.resize(debug_string.size() - 1);
+  }
+
+  return debug_string;
+}
+
+std::string Message::Utf8DebugString() const {
+  std::string debug_string;
+
+  TextFormat::Printer printer;
+  printer.SetUseUtf8StringEscaping(true);
+  printer.SetExpandAny(true);
+  printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load(
+      std::memory_order_relaxed));
+
+  printer.PrintToString(*this, &debug_string);
+
+  return debug_string;
+}
+
+void Message::PrintDebugString() const { printf("%s", DebugString().c_str()); }
+
+
+// ===========================================================================
+// Implementation of the parse information tree class.
+void TextFormat::ParseInfoTree::RecordLocation(
+    const FieldDescriptor* field, TextFormat::ParseLocationRange range) {
+  locations_[field].push_back(range);
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
+    const FieldDescriptor* field) {
+  // Owned by us in the map.
+  auto& vec = nested_[field];
+  vec.emplace_back(new TextFormat::ParseInfoTree());
+  return vec.back().get();
+}
+
+void CheckFieldIndex(const FieldDescriptor* field, int index) {
+  if (field == nullptr) {
+    return;
+  }
+
+  if (field->is_repeated() && index == -1) {
+    GOOGLE_LOG(DFATAL) << "Index must be in range of repeated field values. "
+                << "Field: " << field->name();
+  } else if (!field->is_repeated() && index != -1) {
+    GOOGLE_LOG(DFATAL) << "Index must be -1 for singular fields."
+                << "Field: " << field->name();
+  }
+}
+
+TextFormat::ParseLocationRange TextFormat::ParseInfoTree::GetLocationRange(
+    const FieldDescriptor* field, int index) const {
+  CheckFieldIndex(field, index);
+  if (index == -1) {
+    index = 0;
+  }
+
+  const std::vector<TextFormat::ParseLocationRange>* locations =
+      FindOrNull(locations_, field);
+  if (locations == nullptr ||
+      index >= static_cast<int64_t>(locations->size())) {
+    return TextFormat::ParseLocationRange();
+  }
+
+  return (*locations)[index];
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
+    const FieldDescriptor* field, int index) const {
+  CheckFieldIndex(field, index);
+  if (index == -1) {
+    index = 0;
+  }
+
+  auto it = nested_.find(field);
+  if (it == nested_.end() || index >= static_cast<int64_t>(it->second.size())) {
+    return nullptr;
+  }
+
+  return it->second[index].get();
+}
+
+namespace {
+// These functions implement the behavior of the "default" TextFormat::Finder,
+// they are defined as standalone to be called when finder_ is nullptr.
+const FieldDescriptor* DefaultFinderFindExtension(Message* message,
+                                                  const std::string& name) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  return descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
+                                                                  name);
+}
+
+const FieldDescriptor* DefaultFinderFindExtensionByNumber(
+    const Descriptor* descriptor, int number) {
+  return descriptor->file()->pool()->FindExtensionByNumber(descriptor, number);
+}
+
+const Descriptor* DefaultFinderFindAnyType(const Message& message,
+                                           const std::string& prefix,
+                                           const std::string& name) {
+  if (prefix != internal::kTypeGoogleApisComPrefix &&
+      prefix != internal::kTypeGoogleProdComPrefix) {
+    return nullptr;
+  }
+  return message.GetDescriptor()->file()->pool()->FindMessageTypeByName(name);
+}
+}  // namespace
+
+// ===========================================================================
+// Internal class for parsing an ASCII representation of a Protocol Message.
+// This class makes use of the Protocol Message compiler's tokenizer found
+// in //net/proto2/io/public/tokenizer.h. Note that class's Parse
+// method is *not* thread-safe and should only be used in a single thread at
+// a time.
+
+// Makes code slightly more readable.  The meaning of "DO(foo)" is
+// "Execute foo and fail if it fails.", where failure is indicated by
+// returning false. Borrowed from parser.cc (Thanks Kenton!).
+#define DO(STATEMENT) \
+  if (STATEMENT) {    \
+  } else {            \
+    return false;     \
+  }
+
+class TextFormat::Parser::ParserImpl {
+ public:
+  // Determines if repeated values for non-repeated fields and
+  // oneofs are permitted, e.g., the string "foo: 1 foo: 2" for a
+  // required/optional field named "foo", or "baz: 1 bar: 2"
+  // where "baz" and "bar" are members of the same oneof.
+  enum SingularOverwritePolicy {
+    ALLOW_SINGULAR_OVERWRITES = 0,   // the last value is retained
+    FORBID_SINGULAR_OVERWRITES = 1,  // an error is issued
+  };
+
+  ParserImpl(const Descriptor* root_message_type,
+             io::ZeroCopyInputStream* input_stream,
+             io::ErrorCollector* error_collector,
+             const TextFormat::Finder* finder, ParseInfoTree* parse_info_tree,
+             SingularOverwritePolicy singular_overwrite_policy,
+             bool allow_case_insensitive_field, bool allow_unknown_field,
+             bool allow_unknown_extension, bool allow_unknown_enum,
+             bool allow_field_number, bool allow_relaxed_whitespace,
+             bool allow_partial, int recursion_limit)
+      : error_collector_(error_collector),
+        finder_(finder),
+        parse_info_tree_(parse_info_tree),
+        tokenizer_error_collector_(this),
+        tokenizer_(input_stream, &tokenizer_error_collector_),
+        root_message_type_(root_message_type),
+        singular_overwrite_policy_(singular_overwrite_policy),
+        allow_case_insensitive_field_(allow_case_insensitive_field),
+        allow_unknown_field_(allow_unknown_field),
+        allow_unknown_extension_(allow_unknown_extension),
+        allow_unknown_enum_(allow_unknown_enum),
+        allow_field_number_(allow_field_number),
+        allow_partial_(allow_partial),
+        initial_recursion_limit_(recursion_limit),
+        recursion_limit_(recursion_limit),
+        had_silent_marker_(false),
+        had_errors_(false) {
+    // For backwards-compatibility with proto1, we need to allow the 'f' suffix
+    // for floats.
+    tokenizer_.set_allow_f_after_float(true);
+
+    // '#' starts a comment.
+    tokenizer_.set_comment_style(io::Tokenizer::SH_COMMENT_STYLE);
+
+    if (allow_relaxed_whitespace) {
+      tokenizer_.set_require_space_after_number(false);
+      tokenizer_.set_allow_multiline_strings(true);
+    }
+
+    // Consume the starting token.
+    tokenizer_.Next();
+  }
+  ~ParserImpl() {}
+
+  // Parses the ASCII representation specified in input and saves the
+  // information into the output pointer (a Message). Returns
+  // false if an error occurs (an error will also be logged to
+  // GOOGLE_LOG(ERROR)).
+  bool Parse(Message* output) {
+    // Consume fields until we cannot do so anymore.
+    while (true) {
+      if (LookingAtType(io::Tokenizer::TYPE_END)) {
+        // Ensures recursion limit properly unwinded, but only for success
+        // cases. This implicitly avoids the check when `Parse` returns false
+        // via `DO(...)`.
+        GOOGLE_DCHECK(had_errors_ || recursion_limit_ == initial_recursion_limit_)
+            << "Recursion limit at end of parse should be "
+            << initial_recursion_limit_ << ", but was " << recursion_limit_
+            << ". Difference of " << initial_recursion_limit_ - recursion_limit_
+            << " stack frames not accounted for stack unwind.";
+
+        return !had_errors_;
+      }
+
+      DO(ConsumeField(output));
+    }
+  }
+
+  bool ParseField(const FieldDescriptor* field, Message* output) {
+    bool suc;
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      suc = ConsumeFieldMessage(output, output->GetReflection(), field);
+    } else {
+      suc = ConsumeFieldValue(output, output->GetReflection(), field);
+    }
+    return suc && LookingAtType(io::Tokenizer::TYPE_END);
+  }
+
+  void ReportError(int line, int col, const std::string& message) {
+    had_errors_ = true;
+    if (error_collector_ == nullptr) {
+      if (line >= 0) {
+        GOOGLE_LOG(ERROR) << "Error parsing text-format "
+                   << root_message_type_->full_name() << ": " << (line + 1)
+                   << ":" << (col + 1) << ": " << message;
+      } else {
+        GOOGLE_LOG(ERROR) << "Error parsing text-format "
+                   << root_message_type_->full_name() << ": " << message;
+      }
+    } else {
+      error_collector_->AddError(line, col, message);
+    }
+  }
+
+  void ReportWarning(int line, int col, const std::string& message) {
+    if (error_collector_ == nullptr) {
+      if (line >= 0) {
+        GOOGLE_LOG(WARNING) << "Warning parsing text-format "
+                     << root_message_type_->full_name() << ": " << (line + 1)
+                     << ":" << (col + 1) << ": " << message;
+      } else {
+        GOOGLE_LOG(WARNING) << "Warning parsing text-format "
+                     << root_message_type_->full_name() << ": " << message;
+      }
+    } else {
+      error_collector_->AddWarning(line, col, message);
+    }
+  }
+
+ private:
+  static constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
+  static constexpr uint32_t kuint32max = std::numeric_limits<uint32_t>::max();
+  static constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+  static constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+  static constexpr uint64_t kuint64max = std::numeric_limits<uint64_t>::max();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl);
+
+  // Reports an error with the given message with information indicating
+  // the position (as derived from the current token).
+  void ReportError(const std::string& message) {
+    ReportError(tokenizer_.current().line, tokenizer_.current().column,
+                message);
+  }
+
+  // Reports a warning with the given message with information indicating
+  // the position (as derived from the current token).
+  void ReportWarning(const std::string& message) {
+    ReportWarning(tokenizer_.current().line, tokenizer_.current().column,
+                  message);
+  }
+
+  // Consumes the specified message with the given starting delimiter.
+  // This method checks to see that the end delimiter at the conclusion of
+  // the consumption matches the starting delimiter passed in here.
+  bool ConsumeMessage(Message* message, const std::string delimiter) {
+    while (!LookingAt(">") && !LookingAt("}")) {
+      DO(ConsumeField(message));
+    }
+
+    // Confirm that we have a valid ending delimiter.
+    DO(Consume(delimiter));
+    return true;
+  }
+
+  // Consume either "<" or "{".
+  bool ConsumeMessageDelimiter(std::string* delimiter) {
+    if (TryConsume("<")) {
+      *delimiter = ">";
+    } else {
+      DO(Consume("{"));
+      *delimiter = "}";
+    }
+    return true;
+  }
+
+
+  // Consumes the current field (as returned by the tokenizer) on the
+  // passed in message.
+  bool ConsumeField(Message* message) {
+    const Reflection* reflection = message->GetReflection();
+    const Descriptor* descriptor = message->GetDescriptor();
+
+    std::string field_name;
+    bool reserved_field = false;
+    const FieldDescriptor* field = nullptr;
+    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("[")) {
+      std::string full_type_name, prefix;
+      DO(ConsumeAnyTypeUrl(&full_type_name, &prefix));
+      std::string prefix_and_full_type_name =
+          StrCat(prefix, full_type_name);
+      DO(ConsumeBeforeWhitespace("]"));
+      TryConsumeWhitespace();
+      // ':' is optional between message labels and values.
+      if (TryConsumeBeforeWhitespace(":")) {
+        TryConsumeWhitespace();
+      }
+      std::string serialized_value;
+      const Descriptor* value_descriptor =
+          finder_ ? finder_->FindAnyType(*message, prefix, full_type_name)
+                  : DefaultFinderFindAnyType(*message, prefix, full_type_name);
+      if (value_descriptor == nullptr) {
+        ReportError("Could not find type \"" + prefix_and_full_type_name +
+                    "\" stored in google.protobuf.Any.");
+        return false;
+      }
+      DO(ConsumeAnyValue(value_descriptor, &serialized_value));
+      if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
+        // Fail if any_type_url_field has already been specified.
+        if ((!any_type_url_field->is_repeated() &&
+             reflection->HasField(*message, any_type_url_field)) ||
+            (!any_value_field->is_repeated() &&
+             reflection->HasField(*message, any_value_field))) {
+          ReportError("Non-repeated Any specified multiple times.");
+          return false;
+        }
+      }
+      reflection->SetString(message, any_type_url_field,
+                            std::move(prefix_and_full_type_name));
+      reflection->SetString(message, any_value_field,
+                            std::move(serialized_value));
+      return true;
+    }
+    if (TryConsume("[")) {
+      // Extension.
+      DO(ConsumeFullTypeName(&field_name));
+      DO(ConsumeBeforeWhitespace("]"));
+      TryConsumeWhitespace();
+
+      field = finder_ ? finder_->FindExtension(message, field_name)
+                      : DefaultFinderFindExtension(message, field_name);
+
+      if (field == nullptr) {
+        if (!allow_unknown_field_ && !allow_unknown_extension_) {
+          ReportError("Extension \"" + field_name +
+                      "\" is not defined or "
+                      "is not an extension of \"" +
+                      descriptor->full_name() + "\".");
+          return false;
+        } else {
+          ReportWarning("Ignoring extension \"" + field_name +
+                        "\" which is not defined or is not an extension of \"" +
+                        descriptor->full_name() + "\".");
+        }
+      }
+    } else {
+      DO(ConsumeIdentifierBeforeWhitespace(&field_name));
+      TryConsumeWhitespace();
+
+      int32_t field_number;
+      if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
+        if (descriptor->IsExtensionNumber(field_number)) {
+          field = finder_
+                      ? finder_->FindExtensionByNumber(descriptor, field_number)
+                      : DefaultFinderFindExtensionByNumber(descriptor,
+                                                           field_number);
+        } else if (descriptor->IsReservedNumber(field_number)) {
+          reserved_field = true;
+        } else {
+          field = descriptor->FindFieldByNumber(field_number);
+        }
+      } else {
+        field = descriptor->FindFieldByName(field_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 == nullptr) {
+          std::string lower_field_name = field_name;
+          LowerString(&lower_field_name);
+          field = descriptor->FindFieldByName(lower_field_name);
+          // If the case-insensitive match worked but the field is NOT a group,
+          if (field != nullptr &&
+              field->type() != FieldDescriptor::TYPE_GROUP) {
+            field = nullptr;
+          }
+        }
+        // Again, special-case group names as described above.
+        if (field != nullptr && field->type() == FieldDescriptor::TYPE_GROUP &&
+            field->message_type()->name() != field_name) {
+          field = nullptr;
+        }
+
+        if (field == nullptr && allow_case_insensitive_field_) {
+          std::string lower_field_name = field_name;
+          LowerString(&lower_field_name);
+          field = descriptor->FindFieldByLowercaseName(lower_field_name);
+        }
+
+        if (field == nullptr) {
+          reserved_field = descriptor->IsReservedName(field_name);
+        }
+      }
+
+      if (field == nullptr && !reserved_field) {
+        if (!allow_unknown_field_) {
+          ReportError("Message type \"" + descriptor->full_name() +
+                      "\" has no field named \"" + field_name + "\".");
+          return false;
+        } else {
+          ReportWarning("Message type \"" + descriptor->full_name() +
+                        "\" has no field named \"" + field_name + "\".");
+        }
+      }
+    }
+
+    // Skips unknown or reserved fields.
+    if (field == nullptr) {
+      GOOGLE_CHECK(allow_unknown_field_ || allow_unknown_extension_ || reserved_field);
+
+      // 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 (TryConsumeBeforeWhitespace(":")) {
+        TryConsumeWhitespace();
+        if (!LookingAt("{") && !LookingAt("<")) {
+          return SkipFieldValue();
+        }
+      }
+      return SkipFieldMessage();
+    }
+
+    if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
+      // Fail if the field is not repeated and it has already been specified.
+      if (!field->is_repeated() && reflection->HasField(*message, field)) {
+        ReportError("Non-repeated field \"" + field_name +
+                    "\" is specified multiple times.");
+        return false;
+      }
+      // Fail if the field is a member of a oneof and another member has already
+      // been specified.
+      const OneofDescriptor* oneof = field->containing_oneof();
+      if (oneof != nullptr && reflection->HasOneof(*message, oneof)) {
+        const FieldDescriptor* other_field =
+            reflection->GetOneofFieldDescriptor(*message, oneof);
+        ReportError("Field \"" + field_name +
+                    "\" is specified along with "
+                    "field \"" +
+                    other_field->name() +
+                    "\", another member "
+                    "of oneof \"" +
+                    oneof->name() + "\".");
+        return false;
+      }
+    }
+
+    // Perform special handling for embedded message types.
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // ':' is optional here.
+      bool consumed_semicolon = TryConsumeBeforeWhitespace(":");
+      if (consumed_semicolon) {
+        TryConsumeWhitespace();
+      }
+      if (consumed_semicolon && field->options().weak() &&
+          LookingAtType(io::Tokenizer::TYPE_STRING)) {
+        // we are getting a bytes string for a weak field.
+        std::string tmp;
+        DO(ConsumeString(&tmp));
+        MessageFactory* factory =
+            finder_ ? finder_->FindExtensionFactory(field) : nullptr;
+        reflection->MutableMessage(message, field, factory)
+            ->ParseFromString(tmp);
+        goto label_skip_parsing;
+      }
+    } else {
+      // ':' is required here.
+      DO(ConsumeBeforeWhitespace(":"));
+      TryConsumeWhitespace();
+    }
+
+    if (field->is_repeated() && TryConsume("[")) {
+      // Short repeated format, e.g.  "foo: [1, 2, 3]".
+      if (!TryConsume("]")) {
+        // "foo: []" is treated as empty.
+        while (true) {
+          if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+            // Perform special handling for embedded message types.
+            DO(ConsumeFieldMessage(message, reflection, field));
+          } else {
+            DO(ConsumeFieldValue(message, reflection, field));
+          }
+          if (TryConsume("]")) {
+            break;
+          }
+          DO(Consume(","));
+        }
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      DO(ConsumeFieldMessage(message, reflection, field));
+    } else {
+      DO(ConsumeFieldValue(message, reflection, field));
+    }
+  label_skip_parsing:
+    // For historical reasons, fields may optionally be separated by commas or
+    // semicolons.
+    TryConsume(";") || TryConsume(",");
+
+    if (field->options().deprecated()) {
+      ReportWarning("text format contains deprecated field \"" + field_name +
+                    "\"");
+    }
+
+    // If a parse info tree exists, add the location for the parsed
+    // field.
+    if (parse_info_tree_ != nullptr) {
+      int end_line = tokenizer_.previous().line;
+      int end_column = tokenizer_.previous().end_column;
+
+      RecordLocation(parse_info_tree_, field,
+                     ParseLocationRange(ParseLocation(start_line, start_column),
+                                        ParseLocation(end_line, end_column)));
+    }
+
+    return true;
+  }
+
+  // Skips the next field including the field's name and value.
+  bool SkipField() {
+    std::string field_name;
+    if (TryConsume("[")) {
+      // Extension name or type URL.
+      DO(ConsumeTypeUrlOrFullTypeName(&field_name));
+      DO(ConsumeBeforeWhitespace("]"));
+    } else {
+      DO(ConsumeIdentifierBeforeWhitespace(&field_name));
+    }
+    TryConsumeWhitespace();
+
+    // 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 (TryConsumeBeforeWhitespace(":")) {
+      TryConsumeWhitespace();
+      if (!LookingAt("{") && !LookingAt("<")) {
+        DO(SkipFieldValue());
+      } else {
+        DO(SkipFieldMessage());
+      }
+    } else {
+      DO(SkipFieldMessage());
+    }
+    // For historical reasons, fields may optionally be separated by commas or
+    // semicolons.
+    TryConsume(";") || TryConsume(",");
+    return true;
+  }
+
+  bool ConsumeFieldMessage(Message* message, const Reflection* reflection,
+                           const FieldDescriptor* field) {
+    if (--recursion_limit_ < 0) {
+      ReportError(
+          StrCat("Message is too deep, the parser exceeded the "
+                       "configured recursion limit of ",
+                       initial_recursion_limit_, "."));
+      return false;
+    }
+    // If the parse information tree is not nullptr, create a nested one
+    // for the nested message.
+    ParseInfoTree* parent = parse_info_tree_;
+    if (parent != nullptr) {
+      parse_info_tree_ = CreateNested(parent, field);
+    }
+
+    std::string delimiter;
+    DO(ConsumeMessageDelimiter(&delimiter));
+    MessageFactory* factory =
+        finder_ ? finder_->FindExtensionFactory(field) : nullptr;
+    if (field->is_repeated()) {
+      DO(ConsumeMessage(reflection->AddMessage(message, field, factory),
+                        delimiter));
+    } else {
+      DO(ConsumeMessage(reflection->MutableMessage(message, field, factory),
+                        delimiter));
+    }
+
+    ++recursion_limit_;
+
+    // Reset the parse information tree.
+    parse_info_tree_ = parent;
+    return true;
+  }
+
+  // Skips the whole body of a message including the beginning delimiter and
+  // the ending delimiter.
+  bool SkipFieldMessage() {
+    if (--recursion_limit_ < 0) {
+      ReportError(
+          StrCat("Message is too deep, the parser exceeded the "
+                       "configured recursion limit of ",
+                       initial_recursion_limit_, "."));
+      return false;
+    }
+
+    std::string delimiter;
+    DO(ConsumeMessageDelimiter(&delimiter));
+    while (!LookingAt(">") && !LookingAt("}")) {
+      DO(SkipField());
+    }
+    DO(Consume(delimiter));
+
+    ++recursion_limit_;
+    return true;
+  }
+
+  bool ConsumeFieldValue(Message* message, const Reflection* reflection,
+                         const FieldDescriptor* field) {
+// Define an easy to use macro for setting fields. This macro checks
+// to see if the field is repeated (in which case we need to use the Add
+// methods or not (in which case we need to use the Set methods).
+#define SET_FIELD(CPPTYPE, VALUE)                    \
+  if (field->is_repeated()) {                        \
+    reflection->Add##CPPTYPE(message, field, VALUE); \
+  } else {                                           \
+    reflection->Set##CPPTYPE(message, field, VALUE); \
+  }
+
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32: {
+        int64_t value;
+        DO(ConsumeSignedInteger(&value, kint32max));
+        SET_FIELD(Int32, static_cast<int32_t>(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        uint64_t value;
+        DO(ConsumeUnsignedInteger(&value, kuint32max));
+        SET_FIELD(UInt32, static_cast<uint32_t>(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_INT64: {
+        int64_t value;
+        DO(ConsumeSignedInteger(&value, kint64max));
+        SET_FIELD(Int64, value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        uint64_t value;
+        DO(ConsumeUnsignedInteger(&value, kuint64max));
+        SET_FIELD(UInt64, value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_FLOAT: {
+        double value;
+        DO(ConsumeDouble(&value));
+        SET_FIELD(Float, io::SafeDoubleToFloat(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_DOUBLE: {
+        double value;
+        DO(ConsumeDouble(&value));
+        SET_FIELD(Double, value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_STRING: {
+        std::string value;
+        DO(ConsumeString(&value));
+        SET_FIELD(String, std::move(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_BOOL: {
+        if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+          uint64_t value;
+          DO(ConsumeUnsignedInteger(&value, 1));
+          SET_FIELD(Bool, value);
+        } else {
+          std::string value;
+          DO(ConsumeIdentifier(&value));
+          if (value == "true" || value == "True" || value == "t") {
+            SET_FIELD(Bool, true);
+          } else if (value == "false" || value == "False" || value == "f") {
+            SET_FIELD(Bool, false);
+          } else {
+            ReportError("Invalid value for boolean field \"" + field->name() +
+                        "\". Value: \"" + value + "\".");
+            return false;
+          }
+        }
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        std::string value;
+        int64_t int_value = kint64max;
+        const EnumDescriptor* enum_type = field->enum_type();
+        const EnumValueDescriptor* enum_value = nullptr;
+
+        if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+          DO(ConsumeIdentifier(&value));
+          // Find the enumeration value.
+          enum_value = enum_type->FindValueByName(value);
+
+        } else if (LookingAt("-") ||
+                   LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+          DO(ConsumeSignedInteger(&int_value, kint32max));
+          value = StrCat(int_value);  // for error reporting
+          enum_value = enum_type->FindValueByNumber(int_value);
+        } else {
+          ReportError("Expected integer or identifier, got: " +
+                      tokenizer_.current().text);
+          return false;
+        }
+
+        if (enum_value == nullptr) {
+          if (int_value != kint64max &&
+              reflection->SupportsUnknownEnumValues()) {
+            SET_FIELD(EnumValue, int_value);
+            return true;
+          } else if (!allow_unknown_enum_) {
+            ReportError("Unknown enumeration value of \"" + value +
+                        "\" for "
+                        "field \"" +
+                        field->name() + "\".");
+            return false;
+          } else {
+            ReportWarning("Unknown enumeration value of \"" + value +
+                          "\" for "
+                          "field \"" +
+                          field->name() + "\".");
+            return true;
+          }
+        }
+
+        SET_FIELD(Enum, enum_value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        // We should never get here. Put here instead of a default
+        // so that if new types are added, we get a nice compiler warning.
+        GOOGLE_LOG(FATAL) << "Reached an unintended state: CPPTYPE_MESSAGE";
+        break;
+      }
+    }
+#undef SET_FIELD
+    return true;
+  }
+
+  bool SkipFieldValue() {
+    if (--recursion_limit_ < 0) {
+      ReportError(
+          StrCat("Message is too deep, the parser exceeded the "
+                       "configured recursion limit of ",
+                       initial_recursion_limit_, "."));
+      return false;
+    }
+
+    if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+        tokenizer_.Next();
+      }
+      ++recursion_limit_;
+      return true;
+    }
+    if (TryConsume("[")) {
+      while (true) {
+        if (!LookingAt("{") && !LookingAt("<")) {
+          DO(SkipFieldValue());
+        } else {
+          DO(SkipFieldMessage());
+        }
+        if (TryConsume("]")) {
+          break;
+        }
+        DO(Consume(","));
+      }
+      ++recursion_limit_;
+      return true;
+    }
+    // Possible field values other than string:
+    //   12345        => TYPE_INTEGER
+    //   -12345       => TYPE_SYMBOL + TYPE_INTEGER
+    //   1.2345       => TYPE_FLOAT
+    //   -1.2345      => TYPE_SYMBOL + TYPE_FLOAT
+    //   inf          => TYPE_IDENTIFIER
+    //   -inf         => TYPE_SYMBOL + TYPE_IDENTIFIER
+    //   TYPE_INTEGER => TYPE_IDENTIFIER
+    // Divides them into two group, one with TYPE_SYMBOL
+    // and the other without:
+    //   Group one:
+    //     12345        => TYPE_INTEGER
+    //     1.2345       => TYPE_FLOAT
+    //     inf          => TYPE_IDENTIFIER
+    //     TYPE_INTEGER => TYPE_IDENTIFIER
+    //   Group two:
+    //     -12345       => TYPE_SYMBOL + TYPE_INTEGER
+    //     -1.2345      => TYPE_SYMBOL + TYPE_FLOAT
+    //     -inf         => TYPE_SYMBOL + TYPE_IDENTIFIER
+    // As we can see, the field value consists of an optional '-' and one of
+    // TYPE_INTEGER, TYPE_FLOAT and TYPE_IDENTIFIER.
+    bool has_minus = TryConsume("-");
+    if (!LookingAtType(io::Tokenizer::TYPE_INTEGER) &&
+        !LookingAtType(io::Tokenizer::TYPE_FLOAT) &&
+        !LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      std::string text = tokenizer_.current().text;
+      ReportError("Cannot skip field value, unexpected token: " + text);
+      ++recursion_limit_;
+      return false;
+    }
+    // Combination of '-' and TYPE_IDENTIFIER may result in an invalid field
+    // value while other combinations all generate valid values.
+    // We check if the value of this combination is valid here.
+    // TYPE_IDENTIFIER after a '-' should be one of the float values listed
+    // below:
+    //   inf, inff, infinity, nan
+    if (has_minus && LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      std::string text = tokenizer_.current().text;
+      LowerString(&text);
+      if (text != "inf" &&
+          text != "infinity" && text != "nan") {
+        ReportError("Invalid float number: " + text);
+        ++recursion_limit_;
+        return false;
+      }
+    }
+    tokenizer_.Next();
+    ++recursion_limit_;
+    return true;
+  }
+
+  // Returns true if the current token's text is equal to that specified.
+  bool LookingAt(const std::string& text) {
+    return tokenizer_.current().text == text;
+  }
+
+  // Returns true if the current token's type is equal to that specified.
+  bool LookingAtType(io::Tokenizer::TokenType token_type) {
+    return tokenizer_.current().type == token_type;
+  }
+
+  // Consumes an identifier and saves its value in the identifier parameter.
+  // Returns false if the token is not of type IDENTIFIER.
+  bool ConsumeIdentifier(std::string* identifier) {
+    if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      *identifier = tokenizer_.current().text;
+      tokenizer_.Next();
+      return true;
+    }
+
+    // If allow_field_numer_ or allow_unknown_field_ is true, we should able
+    // to parse integer identifiers.
+    if ((allow_field_number_ || allow_unknown_field_ ||
+         allow_unknown_extension_) &&
+        LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      *identifier = tokenizer_.current().text;
+      tokenizer_.Next();
+      return true;
+    }
+
+    ReportError("Expected identifier, got: " + tokenizer_.current().text);
+    return false;
+  }
+
+  // Similar to `ConsumeIdentifier`, but any following whitespace token may
+  // be reported.
+  bool ConsumeIdentifierBeforeWhitespace(std::string* identifier) {
+    tokenizer_.set_report_whitespace(true);
+    bool result = ConsumeIdentifier(identifier);
+    tokenizer_.set_report_whitespace(false);
+    return result;
+  }
+
+  // Consume a string of form "<id1>.<id2>....<idN>".
+  bool ConsumeFullTypeName(std::string* name) {
+    DO(ConsumeIdentifier(name));
+    while (TryConsume(".")) {
+      std::string part;
+      DO(ConsumeIdentifier(&part));
+      *name += ".";
+      *name += part;
+    }
+    return true;
+  }
+
+  bool ConsumeTypeUrlOrFullTypeName(std::string* name) {
+    DO(ConsumeIdentifier(name));
+    while (true) {
+      std::string connector;
+      if (TryConsume(".")) {
+        connector = ".";
+      } else if (TryConsume("/")) {
+        connector = "/";
+      } else {
+        break;
+      }
+      std::string part;
+      DO(ConsumeIdentifier(&part));
+      *name += connector;
+      *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(std::string* text) {
+    if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      ReportError("Expected string, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    text->clear();
+    while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      io::Tokenizer::ParseStringAppend(tokenizer_.current().text, text);
+
+      tokenizer_.Next();
+    }
+
+    return true;
+  }
+
+  // Consumes a uint64_t and saves its value in the value parameter.
+  // Returns false if the token is not of type INTEGER.
+  bool ConsumeUnsignedInteger(uint64_t* value, uint64_t max_value) {
+    if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      ReportError("Expected integer, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    if (!io::Tokenizer::ParseInteger(tokenizer_.current().text, max_value,
+                                     value)) {
+      ReportError("Integer out of range (" + tokenizer_.current().text + ")");
+      return false;
+    }
+
+    tokenizer_.Next();
+    return true;
+  }
+
+  // Consumes an int64_t and saves its value in the value parameter.
+  // Note that since the tokenizer does not support negative numbers,
+  // we actually may consume an additional token (for the minus sign) in this
+  // method. Returns false if the token is not an integer
+  // (signed or otherwise).
+  bool ConsumeSignedInteger(int64_t* value, uint64_t max_value) {
+    bool negative = false;
+
+    if (TryConsume("-")) {
+      negative = true;
+      // Two's complement always allows one more negative integer than
+      // positive.
+      ++max_value;
+    }
+
+    uint64_t unsigned_value;
+
+    DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
+
+    if (negative) {
+      if ((static_cast<uint64_t>(kint64max) + 1) == unsigned_value) {
+        *value = kint64min;
+      } else {
+        *value = -static_cast<int64_t>(unsigned_value);
+      }
+    } else {
+      *value = static_cast<int64_t>(unsigned_value);
+    }
+
+    return true;
+  }
+
+  // Consumes a double and saves its value in the value parameter.
+  // Accepts decimal numbers only, rejects hex or oct numbers.
+  bool ConsumeUnsignedDecimalAsDouble(double* value, uint64_t max_value) {
+    if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      ReportError("Expected integer, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    const std::string& text = tokenizer_.current().text;
+    if (IsHexNumber(text) || IsOctNumber(text)) {
+      ReportError("Expect a decimal number, got: " + text);
+      return false;
+    }
+
+    uint64_t uint64_value;
+    if (io::Tokenizer::ParseInteger(text, max_value, &uint64_value)) {
+      *value = static_cast<double>(uint64_value);
+    } else {
+      // Uint64 overflow, attempt to parse as a double instead.
+      *value = io::Tokenizer::ParseFloat(text);
+    }
+
+    tokenizer_.Next();
+    return true;
+  }
+
+  // Consumes a double and saves its value in the value parameter.
+  // Note that since the tokenizer does not support negative numbers,
+  // we actually may consume an additional token (for the minus sign) in this
+  // method. Returns false if the token is not a double
+  // (signed or otherwise).
+  bool ConsumeDouble(double* value) {
+    bool negative = false;
+
+    if (TryConsume("-")) {
+      negative = true;
+    }
+
+    // A double can actually be an integer, according to the tokenizer.
+    // Therefore, we must check both cases here.
+    if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      // We have found an integer value for the double.
+      DO(ConsumeUnsignedDecimalAsDouble(value, kuint64max));
+    } else if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
+      // We have found a float value for the double.
+      *value = io::Tokenizer::ParseFloat(tokenizer_.current().text);
+
+      // Mark the current token as consumed.
+      tokenizer_.Next();
+    } else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      std::string text = tokenizer_.current().text;
+      LowerString(&text);
+      if (text == "inf" ||
+          text == "infinity") {
+        *value = std::numeric_limits<double>::infinity();
+        tokenizer_.Next();
+      } else if (text == "nan") {
+        *value = std::numeric_limits<double>::quiet_NaN();
+        tokenizer_.Next();
+      } else {
+        ReportError("Expected double, got: " + text);
+        return false;
+      }
+    } else {
+      ReportError("Expected double, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    if (negative) {
+      *value = -*value;
+    }
+
+    return true;
+  }
+
+  // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name"
+  // or "type.googleprod.com/full.type.Name"
+  bool ConsumeAnyTypeUrl(std::string* full_type_name, std::string* prefix) {
+    // TODO(saito) Extend Consume() to consume multiple tokens at once, so that
+    // this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
+    DO(ConsumeIdentifier(prefix));
+    while (TryConsume(".")) {
+      std::string url;
+      DO(ConsumeIdentifier(&url));
+      *prefix += "." + url;
+    }
+    DO(Consume("/"));
+    *prefix += "/";
+    DO(ConsumeFullTypeName(full_type_name));
+
+    return true;
+  }
+
+  // A helper function for reconstructing Any::value. Consumes a text of
+  // full_type_name, then serializes it into serialized_value.
+  bool ConsumeAnyValue(const Descriptor* value_descriptor,
+                       std::string* serialized_value) {
+    DynamicMessageFactory factory;
+    const Message* value_prototype = factory.GetPrototype(value_descriptor);
+    if (value_prototype == nullptr) {
+      return false;
+    }
+    std::unique_ptr<Message> value(value_prototype->New());
+    std::string sub_delimiter;
+    DO(ConsumeMessageDelimiter(&sub_delimiter));
+    DO(ConsumeMessage(value.get(), sub_delimiter));
+
+    if (allow_partial_) {
+      value->AppendPartialToString(serialized_value);
+    } else {
+      if (!value->IsInitialized()) {
+        ReportError(
+            "Value of type \"" + value_descriptor->full_name() +
+            "\" stored in google.protobuf.Any has missing required fields");
+        return false;
+      }
+      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.
+  bool Consume(const std::string& value) {
+    const std::string& current_value = tokenizer_.current().text;
+
+    if (current_value != value) {
+      ReportError("Expected \"" + value + "\", found \"" + current_value +
+                  "\".");
+      return false;
+    }
+
+    tokenizer_.Next();
+
+    return true;
+  }
+
+  // Similar to `Consume`, but the following token may be tokenized as
+  // TYPE_WHITESPACE.
+  bool ConsumeBeforeWhitespace(const std::string& value) {
+    // Report whitespace after this token, but only once.
+    tokenizer_.set_report_whitespace(true);
+    bool result = Consume(value);
+    tokenizer_.set_report_whitespace(false);
+    return result;
+  }
+
+  // Attempts to consume the supplied value. Returns false if a the
+  // token found does not match the value specified.
+  bool TryConsume(const std::string& value) {
+    if (tokenizer_.current().text == value) {
+      tokenizer_.Next();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  // Similar to `TryConsume`, but the following token may be tokenized as
+  // TYPE_WHITESPACE.
+  bool TryConsumeBeforeWhitespace(const std::string& value) {
+    // Report whitespace after this token, but only once.
+    tokenizer_.set_report_whitespace(true);
+    bool result = TryConsume(value);
+    tokenizer_.set_report_whitespace(false);
+    return result;
+  }
+
+  bool TryConsumeWhitespace() {
+    had_silent_marker_ = false;
+    if (LookingAtType(io::Tokenizer::TYPE_WHITESPACE)) {
+      if (tokenizer_.current().text ==
+          StrCat(" ", internal::kDebugStringSilentMarkerForDetection)) {
+        had_silent_marker_ = true;
+      }
+      tokenizer_.Next();
+      return true;
+    }
+    return false;
+  }
+
+  // An internal instance of the Tokenizer's error collector, used to
+  // collect any base-level parse errors and feed them to the ParserImpl.
+  class ParserErrorCollector : public io::ErrorCollector {
+   public:
+    explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser)
+        : parser_(parser) {}
+
+    ~ParserErrorCollector() override {}
+
+    void AddError(int line, int column, const std::string& message) override {
+      parser_->ReportError(line, column, message);
+    }
+
+    void AddWarning(int line, int column, const std::string& message) override {
+      parser_->ReportWarning(line, column, message);
+    }
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector);
+    TextFormat::Parser::ParserImpl* parser_;
+  };
+
+  io::ErrorCollector* error_collector_;
+  const TextFormat::Finder* finder_;
+  ParseInfoTree* parse_info_tree_;
+  ParserErrorCollector tokenizer_error_collector_;
+  io::Tokenizer tokenizer_;
+  const Descriptor* root_message_type_;
+  SingularOverwritePolicy singular_overwrite_policy_;
+  const bool allow_case_insensitive_field_;
+  const bool allow_unknown_field_;
+  const bool allow_unknown_extension_;
+  const bool allow_unknown_enum_;
+  const bool allow_field_number_;
+  const bool allow_partial_;
+  const int initial_recursion_limit_;
+  int recursion_limit_;
+  bool had_silent_marker_;
+  bool had_errors_;
+};
+
+// ===========================================================================
+// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted
+// from the Printer found in //net/proto2/io/public/printer.h
+class TextFormat::Printer::TextGenerator
+    : public TextFormat::BaseTextGenerator {
+ public:
+  explicit TextGenerator(io::ZeroCopyOutputStream* output,
+                         int initial_indent_level)
+      : output_(output),
+        buffer_(nullptr),
+        buffer_size_(0),
+        at_start_of_line_(true),
+        failed_(false),
+        insert_silent_marker_(false),
+        indent_level_(initial_indent_level),
+        initial_indent_level_(initial_indent_level) {}
+
+  explicit TextGenerator(io::ZeroCopyOutputStream* output,
+                         bool insert_silent_marker, int initial_indent_level)
+      : output_(output),
+        buffer_(nullptr),
+        buffer_size_(0),
+        at_start_of_line_(true),
+        failed_(false),
+        insert_silent_marker_(insert_silent_marker),
+        indent_level_(initial_indent_level),
+        initial_indent_level_(initial_indent_level) {}
+
+  ~TextGenerator() override {
+    // Only BackUp() if we're sure we've successfully called Next() at least
+    // once.
+    if (!failed_) {
+      output_->BackUp(buffer_size_);
+    }
+  }
+
+  // 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.
+  void Indent() override { ++indent_level_; }
+
+  // Reduces the current indent level by two spaces, or crashes if the indent
+  // level is zero.
+  void Outdent() override {
+    if (indent_level_ == 0 || indent_level_ < initial_indent_level_) {
+      GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
+      return;
+    }
+
+    --indent_level_;
+  }
+
+  size_t GetCurrentIndentationSize() const override {
+    return 2 * indent_level_;
+  }
+
+  // Print text to the output stream.
+  void Print(const char* text, size_t size) override {
+    if (indent_level_ > 0) {
+      size_t pos = 0;  // The number of bytes we've written so far.
+      for (size_t i = 0; i < size; i++) {
+        if (text[i] == '\n') {
+          // Saw newline.  If there is more text, we may need to insert an
+          // indent here.  So, write what we have so far, including the '\n'.
+          Write(text + pos, i - pos + 1);
+          pos = i + 1;
+
+          // Setting this true will cause the next Write() to insert an indent
+          // first.
+          at_start_of_line_ = true;
+        }
+      }
+      // Write the rest.
+      Write(text + pos, size - pos);
+    } else {
+      Write(text, size);
+      if (size > 0 && text[size - 1] == '\n') {
+        at_start_of_line_ = true;
+      }
+    }
+  }
+
+  // True if any write to the underlying stream failed.  (We don't just
+  // crash in this case because this is an I/O failure, not a programming
+  // error.)
+  bool failed() const { return failed_; }
+
+  void PrintMaybeWithMarker(StringPiece text) {
+    Print(text.data(), text.size());
+    if (ConsumeInsertSilentMarker()) {
+      PrintLiteral(internal::kDebugStringSilentMarker);
+    }
+  }
+
+  void PrintMaybeWithMarker(StringPiece text_head,
+                            StringPiece text_tail) {
+    Print(text_head.data(), text_head.size());
+    if (ConsumeInsertSilentMarker()) {
+      PrintLiteral(internal::kDebugStringSilentMarker);
+    }
+    Print(text_tail.data(), text_tail.size());
+  }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
+
+  void Write(const char* data, size_t size) {
+    if (failed_) return;
+    if (size == 0) return;
+
+    if (at_start_of_line_) {
+      // Insert an indent.
+      at_start_of_line_ = false;
+      WriteIndent();
+      if (failed_) return;
+    }
+
+    while (static_cast<int64_t>(size) > buffer_size_) {
+      // Data exceeds space in the buffer.  Copy what we can and request a
+      // new buffer.
+      if (buffer_size_ > 0) {
+        memcpy(buffer_, data, buffer_size_);
+        data += buffer_size_;
+        size -= buffer_size_;
+      }
+      void* void_buffer = nullptr;
+      failed_ = !output_->Next(&void_buffer, &buffer_size_);
+      if (failed_) return;
+      buffer_ = reinterpret_cast<char*>(void_buffer);
+    }
+
+    // Buffer is big enough to receive the data; copy it.
+    memcpy(buffer_, data, size);
+    buffer_ += size;
+    buffer_size_ -= size;
+  }
+
+  void WriteIndent() {
+    if (indent_level_ == 0) {
+      return;
+    }
+    GOOGLE_DCHECK(!failed_);
+    int size = GetCurrentIndentationSize();
+
+    while (size > buffer_size_) {
+      // Data exceeds space in the buffer. Write what we can and request a new
+      // buffer.
+      if (buffer_size_ > 0) {
+        memset(buffer_, ' ', buffer_size_);
+      }
+      size -= buffer_size_;
+      void* void_buffer;
+      failed_ = !output_->Next(&void_buffer, &buffer_size_);
+      if (failed_) return;
+      buffer_ = reinterpret_cast<char*>(void_buffer);
+    }
+
+    // Buffer is big enough to receive the data; copy it.
+    memset(buffer_, ' ', size);
+    buffer_ += size;
+    buffer_size_ -= size;
+  }
+
+  // Return the current value of insert_silent_marker_. If it is true, set it
+  // to false as we assume that a silent marker is inserted after a call to this
+  // function.
+  bool ConsumeInsertSilentMarker() {
+    if (insert_silent_marker_) {
+      insert_silent_marker_ = false;
+      return true;
+    }
+    return false;
+  }
+
+  io::ZeroCopyOutputStream* const output_;
+  char* buffer_;
+  int buffer_size_;
+  bool at_start_of_line_;
+  bool failed_;
+  // This flag is false when inserting silent marker is disabled or a silent
+  // marker has been inserted.
+  bool insert_silent_marker_;
+
+  int indent_level_;
+  int initial_indent_level_;
+};
+
+// ===========================================================================
+//  An internal field value printer that may insert a silent marker in
+//  DebugStrings.
+class TextFormat::Printer::DebugStringFieldValuePrinter
+    : public TextFormat::FastFieldValuePrinter {
+ public:
+  void PrintMessageStart(const Message& /*message*/, int /*field_index*/,
+                         int /*field_count*/, bool single_line_mode,
+                         BaseTextGenerator* generator) const override {
+    // This is safe as only TextGenerator is used with
+    // DebugStringFieldValuePrinter.
+    TextGenerator* text_generator = static_cast<TextGenerator*>(generator);
+    if (single_line_mode) {
+      text_generator->PrintMaybeWithMarker(" ", "{ ");
+    } else {
+      text_generator->PrintMaybeWithMarker(" ", "{\n");
+    }
+  }
+};
+
+// ===========================================================================
+//  An internal field value printer that escape UTF8 strings.
+class TextFormat::Printer::FastFieldValuePrinterUtf8Escaping
+    : public TextFormat::Printer::DebugStringFieldValuePrinter {
+ public:
+  void PrintString(const std::string& val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintLiteral("\"");
+    generator->PrintString(strings::Utf8SafeCEscape(val));
+    generator->PrintLiteral("\"");
+  }
+  void PrintBytes(const std::string& val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    return FastFieldValuePrinter::PrintString(val, generator);
+  }
+};
+
+// ===========================================================================
+// Implementation of the default Finder for extensions.
+TextFormat::Finder::~Finder() {}
+
+const FieldDescriptor* TextFormat::Finder::FindExtension(
+    Message* message, const std::string& name) const {
+  return DefaultFinderFindExtension(message, name);
+}
+
+const FieldDescriptor* TextFormat::Finder::FindExtensionByNumber(
+    const Descriptor* descriptor, int number) const {
+  return DefaultFinderFindExtensionByNumber(descriptor, number);
+}
+
+const Descriptor* TextFormat::Finder::FindAnyType(
+    const Message& message, const std::string& prefix,
+    const std::string& name) const {
+  return DefaultFinderFindAnyType(message, prefix, name);
+}
+
+MessageFactory* TextFormat::Finder::FindExtensionFactory(
+    const FieldDescriptor* /*field*/) const {
+  return nullptr;
+}
+
+// ===========================================================================
+
+TextFormat::Parser::Parser()
+    : error_collector_(nullptr),
+      finder_(nullptr),
+      parse_info_tree_(nullptr),
+      allow_partial_(false),
+      allow_case_insensitive_field_(false),
+      allow_unknown_field_(false),
+      allow_unknown_extension_(false),
+      allow_unknown_enum_(false),
+      allow_field_number_(false),
+      allow_relaxed_whitespace_(false),
+      allow_singular_overwrites_(false),
+      recursion_limit_(std::numeric_limits<int>::max()) {}
+
+TextFormat::Parser::~Parser() {}
+
+namespace {
+
+bool CheckParseInputSize(StringPiece input,
+                         io::ErrorCollector* error_collector) {
+  if (input.size() > INT_MAX) {
+    error_collector->AddError(
+        -1, 0,
+        StrCat(
+            "Input size too large: ", static_cast<int64_t>(input.size()),
+            " bytes", " > ", INT_MAX, " bytes."));
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
+                               Message* output) {
+  output->Clear();
+
+  ParserImpl::SingularOverwritePolicy overwrites_policy =
+      allow_singular_overwrites_ ? ParserImpl::ALLOW_SINGULAR_OVERWRITES
+                                 : ParserImpl::FORBID_SINGULAR_OVERWRITES;
+
+  ParserImpl parser(output->GetDescriptor(), input, error_collector_, finder_,
+                    parse_info_tree_, overwrites_policy,
+                    allow_case_insensitive_field_, allow_unknown_field_,
+                    allow_unknown_extension_, allow_unknown_enum_,
+                    allow_field_number_, allow_relaxed_whitespace_,
+                    allow_partial_, recursion_limit_);
+  return MergeUsingImpl(input, output, &parser);
+}
+
+bool TextFormat::Parser::ParseFromString(ConstStringParam input,
+                                         Message* output) {
+  DO(CheckParseInputSize(input, error_collector_));
+  io::ArrayInputStream input_stream(input.data(), input.size());
+  return Parse(&input_stream, output);
+}
+
+bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
+                               Message* output) {
+  ParserImpl parser(output->GetDescriptor(), input, error_collector_, finder_,
+                    parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+                    allow_case_insensitive_field_, allow_unknown_field_,
+                    allow_unknown_extension_, allow_unknown_enum_,
+                    allow_field_number_, allow_relaxed_whitespace_,
+                    allow_partial_, recursion_limit_);
+  return MergeUsingImpl(input, output, &parser);
+}
+
+bool TextFormat::Parser::MergeFromString(ConstStringParam input,
+                                         Message* output) {
+  DO(CheckParseInputSize(input, error_collector_));
+  io::ArrayInputStream input_stream(input.data(), input.size());
+  return Merge(&input_stream, output);
+}
+
+bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* /* input */,
+                                        Message* output,
+                                        ParserImpl* parser_impl) {
+  if (!parser_impl->Parse(output)) return false;
+  if (!allow_partial_ && !output->IsInitialized()) {
+    std::vector<std::string> missing_fields;
+    output->FindInitializationErrors(&missing_fields);
+    parser_impl->ReportError(-1, 0,
+                             "Message missing required fields: " +
+                                 Join(missing_fields, ", "));
+    return false;
+  }
+  return true;
+}
+
+bool TextFormat::Parser::ParseFieldValueFromString(const std::string& input,
+                                                   const FieldDescriptor* field,
+                                                   Message* output) {
+  io::ArrayInputStream input_stream(input.data(), input.size());
+  ParserImpl parser(
+      output->GetDescriptor(), &input_stream, error_collector_, finder_,
+      parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+      allow_case_insensitive_field_, allow_unknown_field_,
+      allow_unknown_extension_, allow_unknown_enum_, allow_field_number_,
+      allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
+  return parser.ParseField(field, output);
+}
+
+/* static */ bool TextFormat::Parse(io::ZeroCopyInputStream* input,
+                                    Message* output) {
+  return Parser().Parse(input, output);
+}
+
+/* static */ bool TextFormat::Merge(io::ZeroCopyInputStream* input,
+                                    Message* output) {
+  return Parser().Merge(input, output);
+}
+
+/* static */ bool TextFormat::ParseFromString(ConstStringParam input,
+                                              Message* output) {
+  return Parser().ParseFromString(input, output);
+}
+
+/* static */ bool TextFormat::MergeFromString(ConstStringParam input,
+                                              Message* output) {
+  return Parser().MergeFromString(input, output);
+}
+
+#undef DO
+
+// ===========================================================================
+
+TextFormat::BaseTextGenerator::~BaseTextGenerator() {}
+
+namespace {
+
+// A BaseTextGenerator that writes to a string.
+class StringBaseTextGenerator : public TextFormat::BaseTextGenerator {
+ public:
+  void Print(const char* text, size_t size) override {
+    output_.append(text, size);
+  }
+
+// Some compilers do not support ref-qualifiers even in C++11 mode.
+// Disable the optimization for now and revisit it later.
+#if 0  // LANG_CXX11
+  std::string Consume() && { return std::move(output_); }
+#else  // !LANG_CXX11
+  const std::string& Get() { return output_; }
+#endif  // LANG_CXX11
+
+ private:
+  std::string output_;
+};
+
+}  // namespace
+
+// The default implementation for FieldValuePrinter. We just delegate the
+// implementation to the default FastFieldValuePrinter to avoid duplicating the
+// logic.
+TextFormat::FieldValuePrinter::FieldValuePrinter() {}
+TextFormat::FieldValuePrinter::~FieldValuePrinter() {}
+
+#if 0  // LANG_CXX11
+#define FORWARD_IMPL(fn, ...)            \
+  StringBaseTextGenerator generator;     \
+  delegate_.fn(__VA_ARGS__, &generator); \
+  return std::move(generator).Consume()
+#else  // !LANG_CXX11
+#define FORWARD_IMPL(fn, ...)            \
+  StringBaseTextGenerator generator;     \
+  delegate_.fn(__VA_ARGS__, &generator); \
+  return generator.Get()
+#endif  // LANG_CXX11
+
+std::string TextFormat::FieldValuePrinter::PrintBool(bool val) const {
+  FORWARD_IMPL(PrintBool, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintInt32(int32_t val) const {
+  FORWARD_IMPL(PrintInt32, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintUInt32(uint32_t val) const {
+  FORWARD_IMPL(PrintUInt32, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintInt64(int64_t val) const {
+  FORWARD_IMPL(PrintInt64, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintUInt64(uint64_t val) const {
+  FORWARD_IMPL(PrintUInt64, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintFloat(float val) const {
+  FORWARD_IMPL(PrintFloat, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintDouble(double val) const {
+  FORWARD_IMPL(PrintDouble, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintString(
+    const std::string& val) const {
+  FORWARD_IMPL(PrintString, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintBytes(
+    const std::string& val) const {
+  return PrintString(val);
+}
+std::string TextFormat::FieldValuePrinter::PrintEnum(
+    int32_t val, const std::string& name) const {
+  FORWARD_IMPL(PrintEnum, val, name);
+}
+std::string TextFormat::FieldValuePrinter::PrintFieldName(
+    const Message& message, const Reflection* reflection,
+    const FieldDescriptor* field) const {
+  FORWARD_IMPL(PrintFieldName, message, reflection, field);
+}
+std::string TextFormat::FieldValuePrinter::PrintMessageStart(
+    const Message& message, int field_index, int field_count,
+    bool single_line_mode) const {
+  FORWARD_IMPL(PrintMessageStart, message, field_index, field_count,
+               single_line_mode);
+}
+std::string TextFormat::FieldValuePrinter::PrintMessageEnd(
+    const Message& message, int field_index, int field_count,
+    bool single_line_mode) const {
+  FORWARD_IMPL(PrintMessageEnd, message, field_index, field_count,
+               single_line_mode);
+}
+#undef FORWARD_IMPL
+
+TextFormat::FastFieldValuePrinter::FastFieldValuePrinter() {}
+TextFormat::FastFieldValuePrinter::~FastFieldValuePrinter() {}
+void TextFormat::FastFieldValuePrinter::PrintBool(
+    bool val, BaseTextGenerator* generator) const {
+  if (val) {
+    generator->PrintLiteral("true");
+  } else {
+    generator->PrintLiteral("false");
+  }
+}
+void TextFormat::FastFieldValuePrinter::PrintInt32(
+    int32_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintUInt32(
+    uint32_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintInt64(
+    int64_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintUInt64(
+    uint64_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintFloat(
+    float val, BaseTextGenerator* generator) const {
+  generator->PrintString(!std::isnan(val) ? SimpleFtoa(val) : "nan");
+}
+void TextFormat::FastFieldValuePrinter::PrintDouble(
+    double val, BaseTextGenerator* generator) const {
+  generator->PrintString(!std::isnan(val) ? SimpleDtoa(val) : "nan");
+}
+void TextFormat::FastFieldValuePrinter::PrintEnum(
+    int32_t /*val*/, const std::string& name,
+    BaseTextGenerator* generator) const {
+  generator->PrintString(name);
+}
+
+void TextFormat::FastFieldValuePrinter::PrintString(
+    const std::string& val, BaseTextGenerator* generator) const {
+  generator->PrintLiteral("\"");
+  generator->PrintString(CEscape(val));
+  generator->PrintLiteral("\"");
+}
+void TextFormat::FastFieldValuePrinter::PrintBytes(
+    const std::string& val, BaseTextGenerator* generator) const {
+  PrintString(val, generator);
+}
+void TextFormat::FastFieldValuePrinter::PrintFieldName(
+    const Message& message, int /*field_index*/, int /*field_count*/,
+    const Reflection* reflection, const FieldDescriptor* field,
+    BaseTextGenerator* generator) const {
+  PrintFieldName(message, reflection, field, generator);
+}
+void TextFormat::FastFieldValuePrinter::PrintFieldName(
+    const Message& /*message*/, const Reflection* /*reflection*/,
+    const FieldDescriptor* field, BaseTextGenerator* generator) const {
+  if (field->is_extension()) {
+    generator->PrintLiteral("[");
+    generator->PrintString(field->PrintableNameForExtension());
+    generator->PrintLiteral("]");
+  } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    // Groups must be serialized with their original capitalization.
+    generator->PrintString(field->message_type()->name());
+  } else {
+    generator->PrintString(field->name());
+  }
+}
+void TextFormat::FastFieldValuePrinter::PrintMessageStart(
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool single_line_mode, BaseTextGenerator* generator) const {
+  if (single_line_mode) {
+    generator->PrintLiteral(" { ");
+  } else {
+    generator->PrintLiteral(" {\n");
+  }
+}
+bool TextFormat::FastFieldValuePrinter::PrintMessageContent(
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool /*single_line_mode*/, BaseTextGenerator* /*generator*/) const {
+  return false;  // Use the default printing function.
+}
+void TextFormat::FastFieldValuePrinter::PrintMessageEnd(
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool single_line_mode, BaseTextGenerator* generator) const {
+  if (single_line_mode) {
+    generator->PrintLiteral("} ");
+  } else {
+    generator->PrintLiteral("}\n");
+  }
+}
+
+namespace {
+
+// A legacy compatibility wrapper. Takes ownership of the delegate.
+class FieldValuePrinterWrapper : public TextFormat::FastFieldValuePrinter {
+ public:
+  explicit FieldValuePrinterWrapper(
+      const TextFormat::FieldValuePrinter* delegate)
+      : delegate_(delegate) {}
+
+  void SetDelegate(const TextFormat::FieldValuePrinter* delegate) {
+    delegate_.reset(delegate);
+  }
+
+  void PrintBool(bool val,
+                 TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintBool(val));
+  }
+  void PrintInt32(int32_t val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintInt32(val));
+  }
+  void PrintUInt32(uint32_t val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintUInt32(val));
+  }
+  void PrintInt64(int64_t val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintInt64(val));
+  }
+  void PrintUInt64(uint64_t val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintUInt64(val));
+  }
+  void PrintFloat(float val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintFloat(val));
+  }
+  void PrintDouble(double val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintDouble(val));
+  }
+  void PrintString(const std::string& val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintString(val));
+  }
+  void PrintBytes(const std::string& val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintBytes(val));
+  }
+  void PrintEnum(int32_t val, const std::string& name,
+                 TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintEnum(val, name));
+  }
+  void PrintFieldName(const Message& message, int /*field_index*/,
+                      int /*field_count*/, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(
+        delegate_->PrintFieldName(message, reflection, field));
+  }
+  void PrintFieldName(const Message& message, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(
+        delegate_->PrintFieldName(message, reflection, field));
+  }
+  void PrintMessageStart(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintMessageStart(
+        message, field_index, field_count, single_line_mode));
+  }
+  void PrintMessageEnd(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintMessageEnd(
+        message, field_index, field_count, single_line_mode));
+  }
+
+ private:
+  std::unique_ptr<const TextFormat::FieldValuePrinter> delegate_;
+};
+
+}  // namespace
+
+const char* const TextFormat::Printer::kDoNotParse =
+    "DO NOT PARSE: fields may be stripped and missing.\n";
+
+TextFormat::Printer::Printer()
+    : initial_indent_level_(0),
+      single_line_mode_(false),
+      use_field_number_(false),
+      use_short_repeated_primitives_(false),
+      insert_silent_marker_(false),
+      hide_unknown_fields_(false),
+      print_message_fields_in_index_order_(false),
+      expand_any_(false),
+      truncate_string_field_longer_than_(0LL),
+      finder_(nullptr) {
+  SetUseUtf8StringEscaping(false);
+}
+
+void TextFormat::Printer::SetUseUtf8StringEscaping(bool as_utf8) {
+  SetDefaultFieldValuePrinter(as_utf8 ? new FastFieldValuePrinterUtf8Escaping()
+                                      : new DebugStringFieldValuePrinter());
+}
+
+void TextFormat::Printer::SetDefaultFieldValuePrinter(
+    const FieldValuePrinter* printer) {
+  default_field_value_printer_.reset(new FieldValuePrinterWrapper(printer));
+}
+
+void TextFormat::Printer::SetDefaultFieldValuePrinter(
+    const FastFieldValuePrinter* printer) {
+  default_field_value_printer_.reset(printer);
+}
+
+bool TextFormat::Printer::RegisterFieldValuePrinter(
+    const FieldDescriptor* field, const FieldValuePrinter* printer) {
+  if (field == nullptr || printer == nullptr) {
+    return false;
+  }
+  std::unique_ptr<FieldValuePrinterWrapper> wrapper(
+      new FieldValuePrinterWrapper(nullptr));
+  auto pair = custom_printers_.insert(std::make_pair(field, nullptr));
+  if (pair.second) {
+    wrapper->SetDelegate(printer);
+    pair.first->second = std::move(wrapper);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool TextFormat::Printer::RegisterFieldValuePrinter(
+    const FieldDescriptor* field, const FastFieldValuePrinter* printer) {
+  if (field == nullptr || printer == nullptr) {
+    return false;
+  }
+  auto pair = custom_printers_.insert(std::make_pair(field, nullptr));
+  if (pair.second) {
+    pair.first->second.reset(printer);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool TextFormat::Printer::RegisterMessagePrinter(
+    const Descriptor* descriptor, const MessagePrinter* printer) {
+  if (descriptor == nullptr || printer == nullptr) {
+    return false;
+  }
+  auto pair =
+      custom_message_printers_.insert(std::make_pair(descriptor, nullptr));
+  if (pair.second) {
+    pair.first->second.reset(printer);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool TextFormat::Printer::PrintToString(const Message& message,
+                                        std::string* output) const {
+  GOOGLE_DCHECK(output) << "output specified is nullptr";
+
+  output->clear();
+  io::StringOutputStream output_stream(output);
+
+  return Print(message, &output_stream);
+}
+
+bool TextFormat::Printer::PrintUnknownFieldsToString(
+    const UnknownFieldSet& unknown_fields, std::string* output) const {
+  GOOGLE_DCHECK(output) << "output specified is nullptr";
+
+  output->clear();
+  io::StringOutputStream output_stream(output);
+  return PrintUnknownFields(unknown_fields, &output_stream);
+}
+
+bool TextFormat::Printer::Print(const Message& message,
+                                io::ZeroCopyOutputStream* output) const {
+  TextGenerator generator(output, insert_silent_marker_, initial_indent_level_);
+
+  Print(message, &generator);
+
+  // Output false if the generator failed internally.
+  return !generator.failed();
+}
+
+// Maximum recursion depth for heuristically printing out length-delimited
+// unknown fields as messages.
+static constexpr int kUnknownFieldRecursionLimit = 10;
+
+bool TextFormat::Printer::PrintUnknownFields(
+    const UnknownFieldSet& unknown_fields,
+    io::ZeroCopyOutputStream* output) const {
+  TextGenerator generator(output, initial_indent_level_);
+
+  PrintUnknownFields(unknown_fields, &generator, kUnknownFieldRecursionLimit);
+
+  // Output false if the generator failed internally.
+  return !generator.failed();
+}
+
+namespace {
+// Comparison functor for sorting FieldDescriptors by field index.
+// Normal fields have higher precedence than extensions.
+struct FieldIndexSorter {
+  bool operator()(const FieldDescriptor* left,
+                  const FieldDescriptor* right) const {
+    if (left->is_extension() && right->is_extension()) {
+      return left->number() < right->number();
+    } else if (left->is_extension()) {
+      return false;
+    } else if (right->is_extension()) {
+      return true;
+    } else {
+      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 std::string& type_url = reflection->GetString(message, type_url_field);
+  std::string url_prefix;
+  std::string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &url_prefix, &full_type_name)) {
+    return false;
+  }
+
+  // Print the "value" in text.
+  const Descriptor* value_descriptor =
+      finder_ ? finder_->FindAnyType(message, url_prefix, full_type_name)
+              : DefaultFinderFindAnyType(message, url_prefix, full_type_name);
+  if (value_descriptor == nullptr) {
+    GOOGLE_LOG(WARNING) << "Can't print proto content: proto type " << type_url
+                 << " not found";
+    return false;
+  }
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> value_message(
+      factory.GetPrototype(value_descriptor)->New());
+  std::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->PrintLiteral("[");
+  generator->PrintString(type_url);
+  generator->PrintLiteral("]");
+  const FastFieldValuePrinter* printer = GetFieldPrinter(value_field);
+  printer->PrintMessageStart(message, -1, 0, single_line_mode_, generator);
+  generator->Indent();
+  Print(*value_message, generator);
+  generator->Outdent();
+  printer->PrintMessageEnd(message, -1, 0, single_line_mode_, generator);
+  return true;
+}
+
+void TextFormat::Printer::Print(const Message& message,
+                                TextGenerator* generator) const {
+  const Reflection* reflection = message.GetReflection();
+  if (!reflection) {
+    // This message does not provide any way to describe its structure.
+    // Parse it again in an UnknownFieldSet, and display this instead.
+    UnknownFieldSet unknown_fields;
+    {
+      std::string serialized = message.SerializeAsString();
+      io::ArrayInputStream input(serialized.data(), serialized.size());
+      unknown_fields.ParseFromZeroCopyStream(&input);
+    }
+    PrintUnknownFields(unknown_fields, generator, kUnknownFieldRecursionLimit);
+    return;
+  }
+  const Descriptor* descriptor = message.GetDescriptor();
+  auto itr = custom_message_printers_.find(descriptor);
+  if (itr != custom_message_printers_.end()) {
+    itr->second->Print(message, single_line_mode_, generator);
+    return;
+  }
+  if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ &&
+      PrintAny(message, generator)) {
+    return;
+  }
+  std::vector<const FieldDescriptor*> fields;
+  if (descriptor->options().map_entry()) {
+    fields.push_back(descriptor->field(0));
+    fields.push_back(descriptor->field(1));
+  } else {
+    reflection->ListFieldsOmitStripped(message, &fields);
+    if (reflection->IsMessageStripped(message.GetDescriptor())) {
+      generator->Print(kDoNotParse, std::strlen(kDoNotParse));
+    }
+  }
+
+  if (print_message_fields_in_index_order_) {
+    std::sort(fields.begin(), fields.end(), FieldIndexSorter());
+  }
+  for (const FieldDescriptor* field : fields) {
+    PrintField(message, reflection, field, generator);
+  }
+  if (!hide_unknown_fields_) {
+    PrintUnknownFields(reflection->GetUnknownFields(message), generator,
+                       kUnknownFieldRecursionLimit);
+  }
+}
+
+void TextFormat::Printer::PrintFieldValueToString(const Message& message,
+                                                  const FieldDescriptor* field,
+                                                  int index,
+                                                  std::string* output) const {
+  GOOGLE_DCHECK(output) << "output specified is nullptr";
+
+  output->clear();
+  io::StringOutputStream output_stream(output);
+  TextGenerator generator(&output_stream, initial_indent_level_);
+
+  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_t first = reflection->GetInt32(*a, field_);
+        int32_t second = reflection->GetInt32(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+        int64_t first = reflection->GetInt64(*a, field_);
+        int64_t second = reflection->GetInt64(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        uint32_t first = reflection->GetUInt32(*a, field_);
+        uint32_t second = reflection->GetUInt32(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        uint64_t first = reflection->GetUInt64(*a, field_);
+        uint64_t second = reflection->GetUInt64(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+        std::string first = reflection->GetString(*a, field_);
+        std::string second = reflection->GetString(*b, field_);
+        return first < second;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+        return true;
+    }
+  }
+
+ private:
+  const FieldDescriptor* field_;
+};
+
+namespace internal {
+class MapFieldPrinterHelper {
+ public:
+  // DynamicMapSorter::Sort cannot be used because it enforces syncing with
+  // repeated field.
+  static bool SortMap(const Message& message, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      std::vector<const Message*>* sorted_map_field);
+  static void CopyKey(const MapKey& key, Message* message,
+                      const FieldDescriptor* field_desc);
+  static void CopyValue(const MapValueRef& value, Message* message,
+                        const FieldDescriptor* field_desc);
+};
+
+// Returns true if elements contained in sorted_map_field need to be released.
+bool MapFieldPrinterHelper::SortMap(
+    const Message& message, const Reflection* reflection,
+    const FieldDescriptor* field,
+    std::vector<const Message*>* sorted_map_field) {
+  bool need_release = false;
+  const MapFieldBase& base = *reflection->GetMapData(message, field);
+
+  if (base.IsRepeatedFieldValid()) {
+    const RepeatedPtrField<Message>& map_field =
+        reflection->GetRepeatedPtrFieldInternal<Message>(message, field);
+    for (int i = 0; i < map_field.size(); ++i) {
+      sorted_map_field->push_back(
+          const_cast<RepeatedPtrField<Message>*>(&map_field)->Mutable(i));
+    }
+  } else {
+    // TODO(teboring): For performance, instead of creating map entry message
+    // for each element, just store map keys and sort them.
+    const Descriptor* map_entry_desc = field->message_type();
+    const Message* prototype =
+        reflection->GetMessageFactory()->GetPrototype(map_entry_desc);
+    for (MapIterator iter =
+             reflection->MapBegin(const_cast<Message*>(&message), field);
+         iter != reflection->MapEnd(const_cast<Message*>(&message), field);
+         ++iter) {
+      Message* map_entry_message = prototype->New();
+      CopyKey(iter.GetKey(), map_entry_message, map_entry_desc->field(0));
+      CopyValue(iter.GetValueRef(), map_entry_message,
+                map_entry_desc->field(1));
+      sorted_map_field->push_back(map_entry_message);
+    }
+    need_release = true;
+  }
+
+  MapEntryMessageComparator comparator(field->message_type());
+  std::stable_sort(sorted_map_field->begin(), sorted_map_field->end(),
+                   comparator);
+  return need_release;
+}
+
+void MapFieldPrinterHelper::CopyKey(const MapKey& key, Message* message,
+                                    const FieldDescriptor* field_desc) {
+  const Reflection* reflection = message->GetReflection();
+  switch (field_desc->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      GOOGLE_LOG(ERROR) << "Not supported.";
+      break;
+    case FieldDescriptor::CPPTYPE_STRING:
+      reflection->SetString(message, field_desc, key.GetStringValue());
+      return;
+    case FieldDescriptor::CPPTYPE_INT64:
+      reflection->SetInt64(message, field_desc, key.GetInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_INT32:
+      reflection->SetInt32(message, field_desc, key.GetInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      reflection->SetUInt64(message, field_desc, key.GetUInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      reflection->SetUInt32(message, field_desc, key.GetUInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      reflection->SetBool(message, field_desc, key.GetBoolValue());
+      return;
+  }
+}
+
+void MapFieldPrinterHelper::CopyValue(const MapValueRef& value,
+                                      Message* message,
+                                      const FieldDescriptor* field_desc) {
+  const Reflection* reflection = message->GetReflection();
+  switch (field_desc->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      reflection->SetDouble(message, field_desc, value.GetDoubleValue());
+      return;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      reflection->SetFloat(message, field_desc, value.GetFloatValue());
+      return;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      reflection->SetEnumValue(message, field_desc, value.GetEnumValue());
+      return;
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      Message* sub_message = value.GetMessageValue().New();
+      sub_message->CopyFrom(value.GetMessageValue());
+      reflection->SetAllocatedMessage(message, sub_message, field_desc);
+      return;
+    }
+    case FieldDescriptor::CPPTYPE_STRING:
+      reflection->SetString(message, field_desc, value.GetStringValue());
+      return;
+    case FieldDescriptor::CPPTYPE_INT64:
+      reflection->SetInt64(message, field_desc, value.GetInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_INT32:
+      reflection->SetInt32(message, field_desc, value.GetInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      reflection->SetUInt64(message, field_desc, value.GetUInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      reflection->SetUInt32(message, field_desc, value.GetUInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      reflection->SetBool(message, field_desc, value.GetBoolValue());
+      return;
+  }
+}
+}  // namespace internal
+
+void TextFormat::Printer::PrintField(const Message& message,
+                                     const Reflection* reflection,
+                                     const FieldDescriptor* field,
+                                     TextGenerator* generator) const {
+  if (use_short_repeated_primitives_ && field->is_repeated() &&
+      field->cpp_type() != FieldDescriptor::CPPTYPE_STRING &&
+      field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    PrintShortRepeatedField(message, reflection, field, generator);
+    return;
+  }
+
+  int count = 0;
+
+  if (field->is_repeated()) {
+    count = reflection->FieldSize(message, field);
+  } else if (reflection->HasField(message, field) ||
+             field->containing_type()->options().map_entry()) {
+    count = 1;
+  }
+
+  std::vector<const Message*> sorted_map_field;
+  bool need_release = false;
+  bool is_map = field->is_map();
+  if (is_map) {
+    need_release = internal::MapFieldPrinterHelper::SortMap(
+        message, reflection, field, &sorted_map_field);
+  }
+
+  for (int j = 0; j < count; ++j) {
+    const int field_index = field->is_repeated() ? j : -1;
+
+    PrintFieldName(message, field_index, count, reflection, field, generator);
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      const FastFieldValuePrinter* printer = GetFieldPrinter(field);
+      const Message& sub_message =
+          field->is_repeated()
+              ? (is_map ? *sorted_map_field[j]
+                        : reflection->GetRepeatedMessage(message, field, j))
+              : reflection->GetMessage(message, field);
+      printer->PrintMessageStart(sub_message, field_index, count,
+                                 single_line_mode_, generator);
+      generator->Indent();
+      if (!printer->PrintMessageContent(sub_message, field_index, count,
+                                        single_line_mode_, generator)) {
+        Print(sub_message, generator);
+      }
+      generator->Outdent();
+      printer->PrintMessageEnd(sub_message, field_index, count,
+                               single_line_mode_, generator);
+    } else {
+      generator->PrintMaybeWithMarker(": ");
+      // Write the field value.
+      PrintFieldValue(message, reflection, field, field_index, generator);
+      if (single_line_mode_) {
+        generator->PrintLiteral(" ");
+      } else {
+        generator->PrintLiteral("\n");
+      }
+    }
+  }
+
+  if (need_release) {
+    for (const Message* message_to_delete : sorted_map_field) {
+      delete message_to_delete;
+    }
+  }
+}
+
+void TextFormat::Printer::PrintShortRepeatedField(
+    const Message& message, const Reflection* reflection,
+    const FieldDescriptor* field, TextGenerator* generator) const {
+  // Print primitive repeated field in short form.
+  int size = reflection->FieldSize(message, field);
+  PrintFieldName(message, /*field_index=*/-1, /*field_count=*/size, reflection,
+                 field, generator);
+  generator->PrintMaybeWithMarker(": ", "[");
+  for (int i = 0; i < size; i++) {
+    if (i > 0) generator->PrintLiteral(", ");
+    PrintFieldValue(message, reflection, field, i, generator);
+  }
+  if (single_line_mode_) {
+    generator->PrintLiteral("] ");
+  } else {
+    generator->PrintLiteral("]\n");
+  }
+}
+
+void TextFormat::Printer::PrintFieldName(const Message& message,
+                                         int field_index, int field_count,
+                                         const Reflection* reflection,
+                                         const FieldDescriptor* field,
+                                         TextGenerator* generator) const {
+  // if use_field_number_ is true, prints field number instead
+  // of field name.
+  if (use_field_number_) {
+    generator->PrintString(StrCat(field->number()));
+    return;
+  }
+
+  const FastFieldValuePrinter* printer = GetFieldPrinter(field);
+  printer->PrintFieldName(message, field_index, field_count, reflection, field,
+                          generator);
+}
+
+void TextFormat::Printer::PrintFieldValue(const Message& message,
+                                          const Reflection* reflection,
+                                          const FieldDescriptor* field,
+                                          int index,
+                                          TextGenerator* generator) const {
+  GOOGLE_DCHECK(field->is_repeated() || (index == -1))
+      << "Index must be -1 for non-repeated fields";
+
+  const FastFieldValuePrinter* printer = GetFieldPrinter(field);
+
+  switch (field->cpp_type()) {
+#define OUTPUT_FIELD(CPPTYPE, METHOD)                                \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                           \
+    printer->Print##METHOD(                                          \
+        field->is_repeated()                                         \
+            ? reflection->GetRepeated##METHOD(message, field, index) \
+            : reflection->Get##METHOD(message, field),               \
+        generator);                                                  \
+    break
+
+    OUTPUT_FIELD(INT32, Int32);
+    OUTPUT_FIELD(INT64, Int64);
+    OUTPUT_FIELD(UINT32, UInt32);
+    OUTPUT_FIELD(UINT64, UInt64);
+    OUTPUT_FIELD(FLOAT, Float);
+    OUTPUT_FIELD(DOUBLE, Double);
+    OUTPUT_FIELD(BOOL, Bool);
+#undef OUTPUT_FIELD
+
+    case FieldDescriptor::CPPTYPE_STRING: {
+      std::string scratch;
+      const std::string& value =
+          field->is_repeated()
+              ? reflection->GetRepeatedStringReference(message, field, index,
+                                                       &scratch)
+              : reflection->GetStringReference(message, field, &scratch);
+      const std::string* value_to_print = &value;
+      std::string truncated_value;
+      if (truncate_string_field_longer_than_ > 0 &&
+          static_cast<size_t>(truncate_string_field_longer_than_) <
+              value.size()) {
+        truncated_value = value.substr(0, truncate_string_field_longer_than_) +
+                          "...<truncated>...";
+        value_to_print = &truncated_value;
+      }
+      if (field->type() == FieldDescriptor::TYPE_STRING) {
+        printer->PrintString(*value_to_print, generator);
+      } else {
+        GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
+        printer->PrintBytes(*value_to_print, generator);
+      }
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      int enum_value =
+          field->is_repeated()
+              ? reflection->GetRepeatedEnumValue(message, field, index)
+              : reflection->GetEnumValue(message, field);
+      const EnumValueDescriptor* enum_desc =
+          field->enum_type()->FindValueByNumber(enum_value);
+      if (enum_desc != nullptr) {
+        printer->PrintEnum(enum_value, enum_desc->name(), generator);
+      } else {
+        // Ordinarily, enum_desc should not be null, because proto2 has the
+        // invariant that set enum field values must be in-range, but with the
+        // new integer-based API for enums (or the RepeatedField<int> loophole),
+        // it is possible for the user to force an unknown integer value.  So we
+        // simply use the integer value itself as the enum value name in this
+        // case.
+        printer->PrintEnum(enum_value, StrCat(enum_value), generator);
+      }
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      Print(field->is_repeated()
+                ? reflection->GetRepeatedMessage(message, field, index)
+                : reflection->GetMessage(message, field),
+            generator);
+      break;
+  }
+}
+
+/* static */ bool TextFormat::Print(const Message& message,
+                                    io::ZeroCopyOutputStream* output) {
+  return Printer().Print(message, output);
+}
+
+/* static */ bool TextFormat::PrintUnknownFields(
+    const UnknownFieldSet& unknown_fields, io::ZeroCopyOutputStream* output) {
+  return Printer().PrintUnknownFields(unknown_fields, output);
+}
+
+/* static */ bool TextFormat::PrintToString(const Message& message,
+                                            std::string* output) {
+  return Printer().PrintToString(message, output);
+}
+
+/* static */ bool TextFormat::PrintUnknownFieldsToString(
+    const UnknownFieldSet& unknown_fields, std::string* output) {
+  return Printer().PrintUnknownFieldsToString(unknown_fields, output);
+}
+
+/* static */ void TextFormat::PrintFieldValueToString(
+    const Message& message, const FieldDescriptor* field, int index,
+    std::string* output) {
+  return Printer().PrintFieldValueToString(message, field, index, output);
+}
+
+/* static */ bool TextFormat::ParseFieldValueFromString(
+    const std::string& input, const FieldDescriptor* field, Message* message) {
+  return Parser().ParseFieldValueFromString(input, field, message);
+}
+
+void TextFormat::Printer::PrintUnknownFields(
+    const UnknownFieldSet& unknown_fields, TextGenerator* generator,
+    int recursion_budget) const {
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+    std::string field_number = StrCat(field.number());
+
+    switch (field.type()) {
+      case UnknownField::TYPE_VARINT:
+        generator->PrintString(field_number);
+        generator->PrintMaybeWithMarker(": ");
+        generator->PrintString(StrCat(field.varint()));
+        if (single_line_mode_) {
+          generator->PrintLiteral(" ");
+        } else {
+          generator->PrintLiteral("\n");
+        }
+        break;
+      case UnknownField::TYPE_FIXED32: {
+        generator->PrintString(field_number);
+        generator->PrintMaybeWithMarker(": ", "0x");
+        generator->PrintString(
+            StrCat(strings::Hex(field.fixed32(), strings::ZERO_PAD_8)));
+        if (single_line_mode_) {
+          generator->PrintLiteral(" ");
+        } else {
+          generator->PrintLiteral("\n");
+        }
+        break;
+      }
+      case UnknownField::TYPE_FIXED64: {
+        generator->PrintString(field_number);
+        generator->PrintMaybeWithMarker(": ", "0x");
+        generator->PrintString(
+            StrCat(strings::Hex(field.fixed64(), strings::ZERO_PAD_16)));
+        if (single_line_mode_) {
+          generator->PrintLiteral(" ");
+        } else {
+          generator->PrintLiteral("\n");
+        }
+        break;
+      }
+      case UnknownField::TYPE_LENGTH_DELIMITED: {
+        generator->PrintString(field_number);
+        const std::string& value = field.length_delimited();
+        // We create a CodedInputStream so that we can adhere to our recursion
+        // budget when we attempt to parse the data. UnknownFieldSet parsing is
+        // recursive because of groups.
+        io::CodedInputStream input_stream(
+            reinterpret_cast<const uint8_t*>(value.data()), value.size());
+        input_stream.SetRecursionLimit(recursion_budget);
+        UnknownFieldSet embedded_unknown_fields;
+        if (!value.empty() && recursion_budget > 0 &&
+            embedded_unknown_fields.ParseFromCodedStream(&input_stream)) {
+          // This field is parseable as a Message.
+          // So it is probably an embedded message.
+          if (single_line_mode_) {
+            generator->PrintMaybeWithMarker(" ", "{ ");
+          } else {
+            generator->PrintMaybeWithMarker(" ", "{\n");
+            generator->Indent();
+          }
+          PrintUnknownFields(embedded_unknown_fields, generator,
+                             recursion_budget - 1);
+          if (single_line_mode_) {
+            generator->PrintLiteral("} ");
+          } else {
+            generator->Outdent();
+            generator->PrintLiteral("}\n");
+          }
+        } else {
+          // This field is not parseable as a Message (or we ran out of
+          // recursion budget). So it is probably just a plain string.
+          generator->PrintMaybeWithMarker(": ", "\"");
+          generator->PrintString(CEscape(value));
+          if (single_line_mode_) {
+            generator->PrintLiteral("\" ");
+          } else {
+            generator->PrintLiteral("\"\n");
+          }
+        }
+        break;
+      }
+      case UnknownField::TYPE_GROUP:
+        generator->PrintString(field_number);
+        if (single_line_mode_) {
+          generator->PrintMaybeWithMarker(" ", "{ ");
+        } else {
+          generator->PrintMaybeWithMarker(" ", "{\n");
+          generator->Indent();
+        }
+        // For groups, we recurse without checking the budget. This is OK,
+        // because if the groups were too deeply nested then we would have
+        // already rejected the message when we originally parsed it.
+        PrintUnknownFields(field.group(), generator, recursion_budget - 1);
+        if (single_line_mode_) {
+          generator->PrintLiteral("} ");
+        } else {
+          generator->Outdent();
+          generator->PrintLiteral("}\n");
+        }
+        break;
+    }
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
new file mode 100644
index 0000000..e10bef7
--- /dev/null
+++ b/src/google/protobuf/text_format.h
@@ -0,0 +1,693 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Utilities for printing and parsing protocol messages in a human-readable,
+// text-based format.
+
+#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
+#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
+
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+PROTOBUF_EXPORT extern const char kDebugStringSilentMarker[1];
+PROTOBUF_EXPORT extern const char kDebugStringSilentMarkerForDetection[3];
+}  // namespace internal
+
+namespace io {
+class ErrorCollector;  // tokenizer.h
+}
+
+// This class implements protocol buffer text format, colloquially known as text
+// proto.  Printing and parsing protocol messages in text format is useful for
+// debugging and human editing of messages.
+//
+// This class is really a namespace that contains only static methods.
+class PROTOBUF_EXPORT TextFormat {
+ public:
+  // Outputs a textual representation of the given message to the given
+  // output stream. Returns false if printing fails.
+  static bool Print(const Message& message, io::ZeroCopyOutputStream* output);
+
+  // Print the fields in an UnknownFieldSet.  They are printed by tag number
+  // only.  Embedded messages are heuristically identified by attempting to
+  // parse them. Returns false if printing fails.
+  static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+                                 io::ZeroCopyOutputStream* output);
+
+  // Like Print(), but outputs directly to a string.
+  // Note: output will be cleared prior to printing, and will be left empty
+  // even if printing fails. Returns false if printing fails.
+  static bool PrintToString(const Message& message, std::string* output);
+
+  // Like PrintUnknownFields(), but outputs directly to a string. Returns
+  // false if printing fails.
+  static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
+                                         std::string* output);
+
+  // Outputs a textual representation of the value of the field supplied on
+  // the message supplied. For non-repeated fields, an index of -1 must
+  // be supplied. Note that this method will print the default value for a
+  // field if it is not set.
+  static void PrintFieldValueToString(const Message& message,
+                                      const FieldDescriptor* field, int index,
+                                      std::string* output);
+
+  class PROTOBUF_EXPORT BaseTextGenerator {
+   public:
+    virtual ~BaseTextGenerator();
+
+    virtual void Indent() {}
+    virtual void Outdent() {}
+    // Returns the current indentation size in characters.
+    virtual size_t GetCurrentIndentationSize() const { return 0; }
+
+    // Print text to the output stream.
+    virtual void Print(const char* text, size_t size) = 0;
+
+    void PrintString(const std::string& str) { Print(str.data(), str.size()); }
+
+    template <size_t n>
+    void PrintLiteral(const char (&text)[n]) {
+      Print(text, n - 1);  // n includes the terminating zero character.
+    }
+  };
+
+  // The default printer that converts scalar values from fields into their
+  // string representation.
+  // You can derive from this FastFieldValuePrinter if you want to have fields
+  // to be printed in a different way and register it at the Printer.
+  class PROTOBUF_EXPORT FastFieldValuePrinter {
+   public:
+    FastFieldValuePrinter();
+    virtual ~FastFieldValuePrinter();
+    virtual void PrintBool(bool val, BaseTextGenerator* generator) const;
+    virtual void PrintInt32(int32_t val, BaseTextGenerator* generator) const;
+    virtual void PrintUInt32(uint32_t val, BaseTextGenerator* generator) const;
+    virtual void PrintInt64(int64_t val, BaseTextGenerator* generator) const;
+    virtual void PrintUInt64(uint64_t val, BaseTextGenerator* generator) const;
+    virtual void PrintFloat(float val, BaseTextGenerator* generator) const;
+    virtual void PrintDouble(double val, BaseTextGenerator* generator) const;
+    virtual void PrintString(const std::string& val,
+                             BaseTextGenerator* generator) const;
+    virtual void PrintBytes(const std::string& val,
+                            BaseTextGenerator* generator) const;
+    virtual void PrintEnum(int32_t val, const std::string& name,
+                           BaseTextGenerator* generator) const;
+    virtual void PrintFieldName(const Message& message, int field_index,
+                                int field_count, const Reflection* reflection,
+                                const FieldDescriptor* field,
+                                BaseTextGenerator* generator) const;
+    virtual void PrintFieldName(const Message& message,
+                                const Reflection* reflection,
+                                const FieldDescriptor* field,
+                                BaseTextGenerator* generator) const;
+    virtual void PrintMessageStart(const Message& message, int field_index,
+                                   int field_count, bool single_line_mode,
+                                   BaseTextGenerator* generator) const;
+    // Allows to override the logic on how to print the content of a message.
+    // Return false to use the default printing logic. Note that it is legal for
+    // this function to print something and then return false to use the default
+    // content printing (although at that point it would behave similarly to
+    // PrintMessageStart).
+    virtual bool PrintMessageContent(const Message& message, int field_index,
+                                     int field_count, bool single_line_mode,
+                                     BaseTextGenerator* generator) const;
+    virtual void PrintMessageEnd(const Message& message, int field_index,
+                                 int field_count, bool single_line_mode,
+                                 BaseTextGenerator* generator) const;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastFieldValuePrinter);
+  };
+
+  // Deprecated: please use FastFieldValuePrinter instead.
+  class PROTOBUF_EXPORT FieldValuePrinter {
+   public:
+    FieldValuePrinter();
+    virtual ~FieldValuePrinter();
+    virtual std::string PrintBool(bool val) const;
+    virtual std::string PrintInt32(int32_t val) const;
+    virtual std::string PrintUInt32(uint32_t val) const;
+    virtual std::string PrintInt64(int64_t val) const;
+    virtual std::string PrintUInt64(uint64_t val) const;
+    virtual std::string PrintFloat(float val) const;
+    virtual std::string PrintDouble(double val) const;
+    virtual std::string PrintString(const std::string& val) const;
+    virtual std::string PrintBytes(const std::string& val) const;
+    virtual std::string PrintEnum(int32_t val, const std::string& name) const;
+    virtual std::string PrintFieldName(const Message& message,
+                                       const Reflection* reflection,
+                                       const FieldDescriptor* field) const;
+    virtual std::string PrintMessageStart(const Message& message,
+                                          int field_index, int field_count,
+                                          bool single_line_mode) const;
+    virtual std::string PrintMessageEnd(const Message& message, int field_index,
+                                        int field_count,
+                                        bool single_line_mode) const;
+
+   private:
+    FastFieldValuePrinter delegate_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldValuePrinter);
+  };
+
+  class PROTOBUF_EXPORT MessagePrinter {
+   public:
+    MessagePrinter() {}
+    virtual ~MessagePrinter() {}
+    virtual void Print(const Message& message, bool single_line_mode,
+                       BaseTextGenerator* generator) const = 0;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessagePrinter);
+  };
+
+  // Interface that Printers or Parsers can use to find extensions, or types
+  // referenced in Any messages.
+  class PROTOBUF_EXPORT Finder {
+   public:
+    virtual ~Finder();
+
+    // Try to find an extension of *message by fully-qualified field
+    // name.  Returns nullptr if no extension is known for this name or number.
+    // The base implementation uses the extensions already known by the message.
+    virtual const FieldDescriptor* FindExtension(Message* message,
+                                                 const std::string& name) const;
+
+    // Similar to FindExtension, but uses a Descriptor and the extension number
+    // instead of using a Message and the name when doing the look up.
+    virtual const FieldDescriptor* FindExtensionByNumber(
+        const Descriptor* descriptor, int number) const;
+
+    // Find the message type for an Any proto.
+    // Returns nullptr if no message is known for this name.
+    // The base implementation only accepts prefixes of type.googleprod.com/ or
+    // type.googleapis.com/, and searches the DescriptorPool of the parent
+    // message.
+    virtual const Descriptor* FindAnyType(const Message& message,
+                                          const std::string& prefix,
+                                          const std::string& name) const;
+
+    // Find the message factory for the given extension field. This can be used
+    // to generalize the Parser to add extension fields to a message in the same
+    // way as the "input" message for the Parser.
+    virtual MessageFactory* FindExtensionFactory(
+        const FieldDescriptor* field) const;
+  };
+
+  // Class for those users which require more fine-grained control over how
+  // a protobuffer message is printed out.
+  class PROTOBUF_EXPORT Printer {
+   public:
+    Printer();
+
+    // Like TextFormat::Print
+    bool Print(const Message& message, io::ZeroCopyOutputStream* output) const;
+    // Like TextFormat::PrintUnknownFields
+    bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+                            io::ZeroCopyOutputStream* output) const;
+    // Like TextFormat::PrintToString
+    bool PrintToString(const Message& message, std::string* output) const;
+    // Like TextFormat::PrintUnknownFieldsToString
+    bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
+                                    std::string* output) const;
+    // Like TextFormat::PrintFieldValueToString
+    void PrintFieldValueToString(const Message& message,
+                                 const FieldDescriptor* field, int index,
+                                 std::string* output) const;
+
+    // Adjust the initial indent level of all output.  Each indent level is
+    // equal to two spaces.
+    void SetInitialIndentLevel(int indent_level) {
+      initial_indent_level_ = indent_level;
+    }
+
+    // If printing in single line mode, then the entire message will be output
+    // on a single line with no line breaks.
+    void SetSingleLineMode(bool single_line_mode) {
+      single_line_mode_ = single_line_mode;
+    }
+
+    bool IsInSingleLineMode() const { return single_line_mode_; }
+
+    // If use_field_number is true, uses field number instead of field name.
+    void SetUseFieldNumber(bool use_field_number) {
+      use_field_number_ = use_field_number;
+    }
+
+    // Set true to print repeated primitives in a format like:
+    //   field_name: [1, 2, 3, 4]
+    // instead of printing each value on its own line.  Short format applies
+    // only to primitive values -- i.e. everything except strings and
+    // sub-messages/groups.
+    void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) {
+      use_short_repeated_primitives_ = use_short_repeated_primitives;
+    }
+
+    // Set true to output UTF-8 instead of ASCII.  The only difference
+    // is that bytes >= 0x80 in string fields will not be escaped,
+    // because they are assumed to be part of UTF-8 multi-byte
+    // sequences. This will change the default FastFieldValuePrinter.
+    void SetUseUtf8StringEscaping(bool as_utf8);
+
+    // Set the default FastFieldValuePrinter that is used for all fields that
+    // don't have a field-specific printer registered.
+    // Takes ownership of the printer.
+    void SetDefaultFieldValuePrinter(const FastFieldValuePrinter* printer);
+
+    PROTOBUF_DEPRECATED_MSG("Please use FastFieldValuePrinter")
+    void SetDefaultFieldValuePrinter(const FieldValuePrinter* printer);
+
+    // Sets whether we want to hide unknown fields or not.
+    // Usually unknown fields are printed in a generic way that includes the
+    // tag number of the field instead of field name. However, sometimes it
+    // is useful to be able to print the message without unknown fields (e.g.
+    // for the python protobuf version to maintain consistency between its pure
+    // python and c++ implementations).
+    void SetHideUnknownFields(bool hide) { hide_unknown_fields_ = hide; }
+
+    // If print_message_fields_in_index_order is true, fields of a proto message
+    // will be printed using the order defined in source code instead of the
+    // field number, extensions will be printed at the end of the message
+    // and their relative order is determined by the extension number.
+    // By default, use the field number order.
+    void SetPrintMessageFieldsInIndexOrder(
+        bool print_message_fields_in_index_order) {
+      print_message_fields_in_index_order_ =
+          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; }
+
+    // Set how parser finds message for Any payloads.
+    void SetFinder(const Finder* finder) { finder_ = finder; }
+
+    // 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_t truncate_string_field_longer_than) {
+      truncate_string_field_longer_than_ = truncate_string_field_longer_than;
+    }
+
+    // Register a custom field-specific FastFieldValuePrinter for fields
+    // with a particular FieldDescriptor.
+    // Returns "true" if the registration succeeded, or "false", if there is
+    // already a printer for that FieldDescriptor.
+    // Takes ownership of the printer on successful registration.
+    bool RegisterFieldValuePrinter(const FieldDescriptor* field,
+                                   const FastFieldValuePrinter* printer);
+
+    PROTOBUF_DEPRECATED_MSG("Please use FastFieldValuePrinter")
+    bool RegisterFieldValuePrinter(const FieldDescriptor* field,
+                                   const FieldValuePrinter* printer);
+
+    // Register a custom message-specific MessagePrinter for messages with a
+    // particular Descriptor.
+    // Returns "true" if the registration succeeded, or "false" if there is
+    // already a printer for that Descriptor.
+    bool RegisterMessagePrinter(const Descriptor* descriptor,
+                                const MessagePrinter* printer);
+
+   private:
+    friend std::string Message::DebugString() const;
+    friend std::string Message::ShortDebugString() const;
+    friend std::string Message::Utf8DebugString() const;
+
+    // Sets whether *DebugString should insert a silent marker.
+    void SetInsertSilentMarker(bool v) { insert_silent_marker_ = v; }
+
+    // Forward declaration of an internal class used to print the text
+    // output to the OutputStream (see text_format.cc for implementation).
+    class TextGenerator;
+
+    // Forward declaration of an internal class used to print field values for
+    // DebugString APIs (see text_format.cc for implementation).
+    class DebugStringFieldValuePrinter;
+
+    // Forward declaration of an internal class used to print UTF-8 escaped
+    // strings (see text_format.cc for implementation).
+    class FastFieldValuePrinterUtf8Escaping;
+
+    static const char* const kDoNotParse;
+
+    // Internal Print method, used for writing to the OutputStream via
+    // the TextGenerator class.
+    void Print(const Message& message, TextGenerator* generator) const;
+
+    // Print a single field.
+    void PrintField(const Message& message, const Reflection* reflection,
+                    const FieldDescriptor* field,
+                    TextGenerator* generator) const;
+
+    // Print a repeated primitive field in short form.
+    void PrintShortRepeatedField(const Message& message,
+                                 const Reflection* reflection,
+                                 const FieldDescriptor* field,
+                                 TextGenerator* generator) const;
+
+    // Print the name of a field -- i.e. everything that comes before the
+    // ':' for a single name/value pair.
+    void PrintFieldName(const Message& message, int field_index,
+                        int field_count, const Reflection* reflection,
+                        const FieldDescriptor* field,
+                        TextGenerator* generator) const;
+
+    // Outputs a textual representation of the value of the field supplied on
+    // the message supplied or the default value if not set.
+    void PrintFieldValue(const Message& message, const Reflection* reflection,
+                         const FieldDescriptor* field, int index,
+                         TextGenerator* generator) const;
+
+    // Print the fields in an UnknownFieldSet.  They are printed by tag number
+    // only.  Embedded messages are heuristically identified by attempting to
+    // parse them (subject to the recursion budget).
+    void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+                            TextGenerator* generator,
+                            int recursion_budget) const;
+
+    bool PrintAny(const Message& message, TextGenerator* generator) const;
+
+    const FastFieldValuePrinter* GetFieldPrinter(
+        const FieldDescriptor* field) const {
+      auto it = custom_printers_.find(field);
+      return it == custom_printers_.end() ? default_field_value_printer_.get()
+                                          : it->second.get();
+    }
+
+    int initial_indent_level_;
+    bool single_line_mode_;
+    bool use_field_number_;
+    bool use_short_repeated_primitives_;
+    bool insert_silent_marker_;
+    bool hide_unknown_fields_;
+    bool print_message_fields_in_index_order_;
+    bool expand_any_;
+    int64_t truncate_string_field_longer_than_;
+
+    std::unique_ptr<const FastFieldValuePrinter> default_field_value_printer_;
+    typedef std::map<const FieldDescriptor*,
+                     std::unique_ptr<const FastFieldValuePrinter>>
+        CustomPrinterMap;
+    CustomPrinterMap custom_printers_;
+
+    typedef std::map<const Descriptor*, std::unique_ptr<const MessagePrinter>>
+        CustomMessagePrinterMap;
+    CustomMessagePrinterMap custom_message_printers_;
+
+    const Finder* finder_;
+  };
+
+  // Parses a text-format protocol message from the given input stream to
+  // the given message object. This function parses the human-readable
+  // serialization format written by Print(). Returns true on success. The
+  // message is cleared first, even if the function fails -- See Merge() to
+  // avoid this behavior.
+  //
+  // Example input: "user {\n id: 123 extra { gender: MALE language: 'en' }\n}"
+  //
+  // One common use for this function is parsing handwritten strings in test
+  // code.
+  //
+  // If you would like to read a protocol buffer serialized in the
+  // (non-human-readable) binary wire format, see
+  // google::protobuf::MessageLite::ParseFromString().
+  static bool Parse(io::ZeroCopyInputStream* input, Message* output);
+  // Like Parse(), but reads directly from a string.
+  static bool ParseFromString(ConstStringParam input, Message* output);
+
+  // Like Parse(), but the data is merged into the given message, as if
+  // using Message::MergeFrom().
+  static bool Merge(io::ZeroCopyInputStream* input, Message* output);
+  // Like Merge(), but reads directly from a string.
+  static bool MergeFromString(ConstStringParam input, Message* output);
+
+  // Parse the given text as a single field value and store it into the
+  // given field of the given message. If the field is a repeated field,
+  // the new value will be added to the end
+  static bool ParseFieldValueFromString(const std::string& input,
+                                        const FieldDescriptor* field,
+                                        Message* message);
+
+  // A location in the parsed text.
+  struct ParseLocation {
+    int line;
+    int column;
+
+    ParseLocation() : line(-1), column(-1) {}
+    ParseLocation(int line_param, int column_param)
+        : line(line_param), column(column_param) {}
+  };
+
+  // A range of locations in the parsed text, including `start` and excluding
+  // `end`.
+  struct ParseLocationRange {
+    ParseLocation start;
+    ParseLocation end;
+    ParseLocationRange() : start(), end() {}
+    ParseLocationRange(ParseLocation start_param, ParseLocation end_param)
+        : start(start_param), end(end_param) {}
+  };
+
+  // Data structure which is populated with the locations of each field
+  // value parsed from the text.
+  class PROTOBUF_EXPORT ParseInfoTree {
+   public:
+    ParseInfoTree() = default;
+    ParseInfoTree(const ParseInfoTree&) = delete;
+    ParseInfoTree& operator=(const ParseInfoTree&) = delete;
+
+    // Returns the parse location range for index-th value of the field in
+    // the parsed text. If none exists, returns a location with start and end
+    // line -1. Index should be -1 for not-repeated fields.
+    ParseLocationRange GetLocationRange(const FieldDescriptor* field,
+                                        int index) const;
+
+    // Returns the starting parse location for index-th value of the field in
+    // the parsed text. If none exists, returns a location with line = -1. Index
+    // should be -1 for not-repeated fields.
+    ParseLocation GetLocation(const FieldDescriptor* field, int index) const {
+      return GetLocationRange(field, index).start;
+    }
+
+    // Returns the parse info tree for the given field, which must be a message
+    // type. The nested information tree is owned by the root tree and will be
+    // deleted when it is deleted.
+    ParseInfoTree* GetTreeForNested(const FieldDescriptor* field,
+                                    int index) const;
+
+   private:
+    // Allow the text format parser to record information into the tree.
+    friend class TextFormat;
+
+    // Records the starting and ending locations of a single value for a field.
+    void RecordLocation(const FieldDescriptor* field, ParseLocationRange range);
+
+    // Create and records a nested tree for a nested message field.
+    ParseInfoTree* CreateNested(const FieldDescriptor* field);
+
+    // Defines the map from the index-th field descriptor to its parse location.
+    typedef std::map<const FieldDescriptor*, std::vector<ParseLocationRange>>
+        LocationMap;
+
+    // Defines the map from the index-th field descriptor to the nested parse
+    // info tree.
+    typedef std::map<const FieldDescriptor*,
+                     std::vector<std::unique_ptr<ParseInfoTree>>>
+        NestedMap;
+
+    LocationMap locations_;
+    NestedMap nested_;
+  };
+
+  // For more control over parsing, use this class.
+  class PROTOBUF_EXPORT Parser {
+   public:
+    Parser();
+    ~Parser();
+
+    // Like TextFormat::Parse().
+    bool Parse(io::ZeroCopyInputStream* input, Message* output);
+    // Like TextFormat::ParseFromString().
+    bool ParseFromString(ConstStringParam input, Message* output);
+    // Like TextFormat::Merge().
+    bool Merge(io::ZeroCopyInputStream* input, Message* output);
+    // Like TextFormat::MergeFromString().
+    bool MergeFromString(ConstStringParam input, Message* output);
+
+    // Set where to report parse errors.  If nullptr (the default), errors will
+    // be printed to stderr.
+    void RecordErrorsTo(io::ErrorCollector* error_collector) {
+      error_collector_ = error_collector;
+    }
+
+    // Set how parser finds extensions.  If nullptr (the default), the
+    // parser will use the standard Reflection object associated with
+    // the message being parsed.
+    void SetFinder(const Finder* finder) { finder_ = finder; }
+
+    // Sets where location information about the parse will be written. If
+    // nullptr
+    // (the default), then no location will be written.
+    void WriteLocationsTo(ParseInfoTree* tree) { parse_info_tree_ = tree; }
+
+    // Normally parsing fails if, after parsing, output->IsInitialized()
+    // returns false.  Call AllowPartialMessage(true) to skip this check.
+    void AllowPartialMessage(bool allow) { allow_partial_ = allow; }
+
+    // Allow field names to be matched case-insensitively.
+    // This is not advisable if there are fields that only differ in case, or
+    // if you want to enforce writing in the canonical form.
+    // This is 'false' by default.
+    void AllowCaseInsensitiveField(bool allow) {
+      allow_case_insensitive_field_ = allow;
+    }
+
+    // Like TextFormat::ParseFieldValueFromString
+    bool ParseFieldValueFromString(const std::string& input,
+                                   const FieldDescriptor* field,
+                                   Message* output);
+
+    // When an unknown extension is met, parsing will fail if this option is
+    // set to false (the default). If true, unknown extensions will be ignored
+    // and a warning message will be generated.
+    // Beware! Setting this option true may hide some errors (e.g. spelling
+    // error on extension name).  This allows data loss; unlike binary format,
+    // text format cannot preserve unknown extensions.  Avoid using this option
+    // if possible.
+    void AllowUnknownExtension(bool allow) { allow_unknown_extension_ = allow; }
+
+    // When an unknown field is met, parsing will fail if this option is set
+    // to false (the default). If true, unknown fields will be ignored and
+    // a warning message will be generated.
+    // Beware! Setting this option true may hide some errors (e.g. spelling
+    // error on field name). This allows data loss; unlike binary format, text
+    // format cannot preserve unknown fields.  Avoid using this option
+    // if possible.
+    void AllowUnknownField(bool allow) { allow_unknown_field_ = allow; }
+
+
+    void AllowFieldNumber(bool allow) { allow_field_number_ = allow; }
+
+    // Sets maximum recursion depth which parser can use. This is effectively
+    // the maximum allowed nesting of proto messages.
+    void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
+
+   private:
+    // Forward declaration of an internal class used to parse text
+    // representations (see text_format.cc for implementation).
+    class ParserImpl;
+
+    // Like TextFormat::Merge().  The provided implementation is used
+    // to do the parsing.
+    bool MergeUsingImpl(io::ZeroCopyInputStream* input, Message* output,
+                        ParserImpl* parser_impl);
+
+    io::ErrorCollector* error_collector_;
+    const Finder* finder_;
+    ParseInfoTree* parse_info_tree_;
+    bool allow_partial_;
+    bool allow_case_insensitive_field_;
+    bool allow_unknown_field_;
+    bool allow_unknown_extension_;
+    bool allow_unknown_enum_;
+    bool allow_field_number_;
+    bool allow_relaxed_whitespace_;
+    bool allow_singular_overwrites_;
+    int recursion_limit_;
+  };
+
+
+ private:
+  // Hack: ParseInfoTree declares TextFormat as a friend which should extend
+  // the friendship to TextFormat::Parser::ParserImpl, but unfortunately some
+  // old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide
+  // helpers for ParserImpl to call methods of ParseInfoTree.
+  static inline void RecordLocation(ParseInfoTree* info_tree,
+                                    const FieldDescriptor* field,
+                                    ParseLocationRange location);
+  static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
+                                            const FieldDescriptor* field);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
+};
+
+inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
+                                       const FieldDescriptor* field,
+                                       ParseLocationRange location) {
+  info_tree->RecordLocation(field, location);
+}
+
+inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
+    ParseInfoTree* info_tree, const FieldDescriptor* field) {
+  return info_tree->CreateNested(field);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_TEXT_FORMAT_H__
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
new file mode 100644
index 0000000..126f2f3
--- /dev/null
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -0,0 +1,2280 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+
+#include <google/protobuf/text_format.h>
+
+#include <math.h>
+#include <stdlib.h>
+
+#include <atomic>
+#include <limits>
+#include <memory>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/map_unittest.pb.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/unittest_proto3.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/test_util2.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+// Controls insertion of DEBUG_STRING_SILENT_MARKER.
+extern PROTOBUF_EXPORT std::atomic<bool> enable_debug_text_format_marker;
+}  // namespace internal
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace text_format_unittest {
+
+using ::google::protobuf::internal::kDebugStringSilentMarker;
+
+// A basic string with different escapable characters for testing.
+const std::string kEscapeTestString =
+    "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+    "slashes \\ and  multiple   spaces";
+
+// A representation of the above string with all the characters escaped.
+const std::string kEscapeTestStringEscaped =
+    "\"\\\"A string with \\' characters \\n and \\r newlines "
+    "and \\t tabs and \\001 slashes \\\\ and  multiple   spaces\"";
+
+class TextFormatTest : public testing::Test {
+ public:
+  static void SetUpTestSuite() {
+    GOOGLE_CHECK_OK(File::GetContents(
+        TestUtil::GetTestDataPath(
+            "net/proto2/internal/"
+            "testdata/text_format_unittest_data_oneof_implemented.txt"),
+        &static_proto_text_format_, true));
+    CleanStringLineEndings(&static_proto_text_format_, false);
+  }
+
+  TextFormatTest() : proto_text_format_(static_proto_text_format_) {}
+
+ protected:
+  // Text format read from text_format_unittest_data.txt.
+  const std::string proto_text_format_;
+  unittest::TestAllTypes proto_;
+
+ private:
+  static std::string static_proto_text_format_;
+};
+std::string TextFormatTest::static_proto_text_format_;
+
+class TextFormatExtensionsTest : public testing::Test {
+ public:
+  static void SetUpTestSuite() {
+    GOOGLE_CHECK_OK(File::GetContents(
+        TestUtil::GetTestDataPath("net/proto2/internal/testdata/"
+                                  "text_format_unittest_extensions_data.txt"),
+        &static_proto_text_format_, true));
+    CleanStringLineEndings(&static_proto_text_format_, false);
+  }
+
+  TextFormatExtensionsTest() : proto_text_format_(static_proto_text_format_) {}
+
+ protected:
+  // Debug string read from text_format_unittest_data.txt.
+  const std::string proto_text_format_;
+  unittest::TestAllExtensions proto_;
+
+ private:
+  static std::string static_proto_text_format_;
+};
+std::string TextFormatExtensionsTest::static_proto_text_format_;
+
+TEST_F(TextFormatTest, Basic) {
+  TestUtil::SetAllFields(&proto_);
+  std::string actual_proto_text_format;
+  TextFormat::PrintToString(proto_, &actual_proto_text_format);
+  EXPECT_EQ(actual_proto_text_format, proto_text_format_);
+}
+
+TEST_F(TextFormatExtensionsTest, Extensions) {
+  TestUtil::SetAllExtensions(&proto_);
+  std::string actual_proto_text_format;
+  TextFormat::PrintToString(proto_, &actual_proto_text_format);
+  EXPECT_EQ(actual_proto_text_format, proto_text_format_);
+}
+
+TEST_F(TextFormatTest, ShortDebugString) {
+  proto_.set_optional_int32(1);
+  proto_.set_optional_string("hello");
+  proto_.mutable_optional_nested_message()->set_bb(2);
+  proto_.mutable_optional_foreign_message();
+
+  EXPECT_EQ(proto_.ShortDebugString(),
+            StrCat("optional_int32: ", kDebugStringSilentMarker,
+                         "1 "
+                         "optional_string: \"hello\" "
+                         "optional_nested_message { bb: 2 } "
+                         "optional_foreign_message { }"));
+}
+
+TEST_F(TextFormatTest, ShortPrimitiveRepeateds) {
+  proto_.set_optional_int32(123);
+  proto_.add_repeated_int32(456);
+  proto_.add_repeated_int32(789);
+  proto_.add_repeated_string("foo");
+  proto_.add_repeated_string("bar");
+  proto_.add_repeated_nested_message()->set_bb(2);
+  proto_.add_repeated_nested_message()->set_bb(3);
+  proto_.add_repeated_nested_enum(unittest::TestAllTypes::FOO);
+  proto_.add_repeated_nested_enum(unittest::TestAllTypes::BAR);
+
+  TextFormat::Printer printer;
+  printer.SetUseShortRepeatedPrimitives(true);
+  std::string text;
+  EXPECT_TRUE(printer.PrintToString(proto_, &text));
+
+  EXPECT_EQ(
+      "optional_int32: 123\n"
+      "repeated_int32: [456, 789]\n"
+      "repeated_string: \"foo\"\n"
+      "repeated_string: \"bar\"\n"
+      "repeated_nested_message {\n  bb: 2\n}\n"
+      "repeated_nested_message {\n  bb: 3\n}\n"
+      "repeated_nested_enum: [FOO, BAR]\n",
+      text);
+
+  // Verify that any existing data in the string is cleared when PrintToString()
+  // is called.
+  text = "just some data here...\n\nblah blah";
+  EXPECT_TRUE(printer.PrintToString(proto_, &text));
+
+  EXPECT_EQ(
+      "optional_int32: 123\n"
+      "repeated_int32: [456, 789]\n"
+      "repeated_string: \"foo\"\n"
+      "repeated_string: \"bar\"\n"
+      "repeated_nested_message {\n  bb: 2\n}\n"
+      "repeated_nested_message {\n  bb: 3\n}\n"
+      "repeated_nested_enum: [FOO, BAR]\n",
+      text);
+
+  // Try in single-line mode.
+  printer.SetSingleLineMode(true);
+  EXPECT_TRUE(printer.PrintToString(proto_, &text));
+
+  EXPECT_EQ(
+      "optional_int32: 123 "
+      "repeated_int32: [456, 789] "
+      "repeated_string: \"foo\" "
+      "repeated_string: \"bar\" "
+      "repeated_nested_message { bb: 2 } "
+      "repeated_nested_message { bb: 3 } "
+      "repeated_nested_enum: [FOO, BAR] ",
+      text);
+}
+
+
+TEST_F(TextFormatTest, StringEscape) {
+  // Set the string value to test.
+  proto_.set_optional_string(kEscapeTestString);
+
+  // Get the DebugString from the proto.
+  std::string debug_string = proto_.DebugString();
+  std::string utf8_debug_string = proto_.Utf8DebugString();
+
+  // Hardcode a correct value to test against.
+  std::string correct_string =
+      StrCat("optional_string: ", kDebugStringSilentMarker,
+                   kEscapeTestStringEscaped, "\n");
+
+  // Compare.
+  EXPECT_EQ(correct_string, debug_string);
+  // UTF-8 string is the same as non-UTF-8 because
+  // the protocol buffer contains no UTF-8 text.
+  EXPECT_EQ(correct_string, utf8_debug_string);
+
+  std::string expected_short_debug_string = StrCat(
+      "optional_string: ", kDebugStringSilentMarker, kEscapeTestStringEscaped);
+  EXPECT_EQ(expected_short_debug_string, proto_.ShortDebugString());
+}
+
+TEST_F(TextFormatTest, Utf8DebugString) {
+  // Set the string value to test.
+  proto_.set_optional_string("\350\260\267\346\255\214");
+  proto_.set_optional_bytes("\350\260\267\346\255\214");
+
+  // Get the DebugString from the proto.
+  std::string debug_string = proto_.DebugString();
+  std::string utf8_debug_string = proto_.Utf8DebugString();
+
+  // Hardcode a correct value to test against.
+  std::string correct_utf8_string =
+      StrCat("optional_string: ", kDebugStringSilentMarker,
+                   "\"\350\260\267\346\255\214\"\n"
+                   "optional_bytes: \"\\350\\260\\267\\346\\255\\214\"\n");
+  std::string correct_string =
+      StrCat("optional_string: ", kDebugStringSilentMarker,
+                   "\"\\350\\260\\267\\346\\255\\214\"\n"
+                   "optional_bytes: \"\\350\\260\\267\\346\\255\\214\"\n");
+
+  // Compare.
+  EXPECT_EQ(correct_utf8_string, utf8_debug_string);
+  EXPECT_EQ(correct_string, debug_string);
+}
+
+TEST_F(TextFormatTest, PrintUnknownFields) {
+  // Test printing of unknown fields in a message.
+
+  unittest::TestEmptyMessage message;
+  UnknownFieldSet* unknown_fields = message.mutable_unknown_fields();
+
+  unknown_fields->AddVarint(5, 1);
+  unknown_fields->AddFixed32(5, 2);
+  unknown_fields->AddFixed64(5, 3);
+  unknown_fields->AddLengthDelimited(5, "4");
+  unknown_fields->AddGroup(5)->AddVarint(10, 5);
+
+  unknown_fields->AddVarint(8, 1);
+  unknown_fields->AddVarint(8, 2);
+  unknown_fields->AddVarint(8, 3);
+
+  EXPECT_EQ(StrCat("5: ", kDebugStringSilentMarker,
+                         "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"),
+            message.DebugString());
+}
+
+TEST_F(TextFormatTest, PrintUnknownFieldsHidden) {
+  // Test printing of unknown fields in a message when suppressed.
+
+  unittest::OneString message;
+  message.set_data("data");
+  UnknownFieldSet* unknown_fields = message.mutable_unknown_fields();
+
+  unknown_fields->AddVarint(5, 1);
+  unknown_fields->AddFixed32(5, 2);
+  unknown_fields->AddFixed64(5, 3);
+  unknown_fields->AddLengthDelimited(5, "4");
+  unknown_fields->AddGroup(5)->AddVarint(10, 5);
+
+  unknown_fields->AddVarint(8, 1);
+  unknown_fields->AddVarint(8, 2);
+  unknown_fields->AddVarint(8, 3);
+
+  TextFormat::Printer printer;
+  printer.SetHideUnknownFields(true);
+  std::string output;
+  printer.PrintToString(message, &output);
+
+  EXPECT_EQ("data: \"data\"\n", output);
+}
+
+TEST_F(TextFormatTest, PrintUnknownMessage) {
+  // Test heuristic printing of messages in an UnknownFieldSet.
+
+  protobuf_unittest::TestAllTypes message;
+
+  // Cases which should not be interpreted as sub-messages.
+
+  // 'a' is a valid FIXED64 tag, so for the string to be parseable as a message
+  // it should be followed by 8 bytes.  Since this string only has two
+  // subsequent bytes, it should be treated as a string.
+  message.add_repeated_string("abc");
+
+  // 'd' happens to be a valid ENDGROUP tag.  So,
+  // UnknownFieldSet::MergeFromCodedStream() will successfully parse "def", but
+  // the ConsumedEntireMessage() check should fail.
+  message.add_repeated_string("def");
+
+  // A zero-length string should never be interpreted as a message even though
+  // it is technically valid as one.
+  message.add_repeated_string("");
+
+  // Case which should be interpreted as a sub-message.
+
+  // An actual nested message with content should always be interpreted as a
+  // nested message.
+  message.add_repeated_nested_message()->set_bb(123);
+
+  std::string data;
+  message.SerializeToString(&data);
+
+  std::string text;
+  UnknownFieldSet unknown_fields;
+  EXPECT_TRUE(unknown_fields.ParseFromString(data));
+  EXPECT_TRUE(TextFormat::PrintUnknownFieldsToString(unknown_fields, &text));
+  // Field 44 and 48 can be printed in any order.
+  EXPECT_THAT(text, testing::HasSubstr("44: \"abc\"\n"
+                                       "44: \"def\"\n"
+                                       "44: \"\"\n"));
+  EXPECT_THAT(text, testing::HasSubstr("48 {\n"
+                                       "  1: 123\n"
+                                       "}\n"));
+}
+
+TEST_F(TextFormatTest, PrintDeeplyNestedUnknownMessage) {
+  // Create a deeply nested message.
+  static constexpr int kNestingDepth = 25000;
+  static constexpr int kUnknownFieldNumber = 1;
+  std::vector<int> lengths;
+  lengths.reserve(kNestingDepth);
+  lengths.push_back(0);
+  for (int i = 0; i < kNestingDepth - 1; ++i) {
+    lengths.push_back(
+        internal::WireFormatLite::TagSize(
+            kUnknownFieldNumber, internal::WireFormatLite::TYPE_BYTES) +
+        internal::WireFormatLite::LengthDelimitedSize(lengths.back()));
+  }
+  std::string serialized;
+  {
+    io::StringOutputStream zero_copy_stream(&serialized);
+    io::CodedOutputStream coded_stream(&zero_copy_stream);
+    for (int i = kNestingDepth - 1; i >= 0; --i) {
+      internal::WireFormatLite::WriteTag(
+          kUnknownFieldNumber,
+          internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, &coded_stream);
+      coded_stream.WriteVarint32(lengths[i]);
+    }
+  }
+
+  // Parse the data and verify that we can print it without overflowing the
+  // stack.
+  unittest::TestEmptyMessage message;
+  ASSERT_TRUE(message.ParseFromString(serialized));
+  std::string text;
+  EXPECT_TRUE(TextFormat::PrintToString(message, &text));
+}
+
+TEST_F(TextFormatTest, PrintMessageWithIndent) {
+  // Test adding an initial indent to printing.
+
+  protobuf_unittest::TestAllTypes message;
+
+  message.add_repeated_string("abc");
+  message.add_repeated_string("def");
+  message.add_repeated_nested_message()->set_bb(123);
+
+  std::string text;
+  TextFormat::Printer printer;
+  printer.SetInitialIndentLevel(1);
+  EXPECT_TRUE(printer.PrintToString(message, &text));
+  EXPECT_EQ(
+      "  repeated_string: \"abc\"\n"
+      "  repeated_string: \"def\"\n"
+      "  repeated_nested_message {\n"
+      "    bb: 123\n"
+      "  }\n",
+      text);
+}
+
+TEST_F(TextFormatTest, PrintMessageSingleLine) {
+  // Test printing a message on a single line.
+
+  protobuf_unittest::TestAllTypes message;
+
+  message.add_repeated_string("abc");
+  message.add_repeated_string("def");
+  message.add_repeated_nested_message()->set_bb(123);
+
+  std::string text;
+  TextFormat::Printer printer;
+  printer.SetInitialIndentLevel(1);
+  printer.SetSingleLineMode(true);
+  EXPECT_TRUE(printer.PrintToString(message, &text));
+  EXPECT_EQ(
+      "  repeated_string: \"abc\" repeated_string: \"def\" "
+      "repeated_nested_message { bb: 123 } ",
+      text);
+}
+
+TEST_F(TextFormatTest, PrintBufferTooSmall) {
+  // Test printing a message to a buffer that is too small.
+
+  protobuf_unittest::TestAllTypes message;
+
+  message.add_repeated_string("abc");
+  message.add_repeated_string("def");
+
+  char buffer[1] = "";
+  io::ArrayOutputStream output_stream(buffer, 1);
+  EXPECT_FALSE(TextFormat::Print(message, &output_stream));
+  EXPECT_EQ(buffer[0], 'r');
+  EXPECT_EQ(output_stream.ByteCount(), 1);
+}
+
+// A printer that appends 'u' to all unsigned int32.
+class CustomUInt32FieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+  std::string PrintUInt32(uint32_t val) const override {
+    return StrCat(FieldValuePrinter::PrintUInt32(val), "u");
+  }
+};
+
+TEST_F(TextFormatTest, DefaultCustomFieldPrinter) {
+  protobuf_unittest::TestAllTypes message;
+
+  message.set_optional_uint32(42);
+  message.add_repeated_uint32(1);
+  message.add_repeated_uint32(2);
+  message.add_repeated_uint32(3);
+
+  TextFormat::Printer printer;
+  printer.SetDefaultFieldValuePrinter(new CustomUInt32FieldValuePrinter());
+  // Let's see if that works well together with the repeated primitives:
+  printer.SetUseShortRepeatedPrimitives(true);
+  std::string text;
+  printer.PrintToString(message, &text);
+  EXPECT_EQ("optional_uint32: 42u\nrepeated_uint32: [1u, 2u, 3u]\n", text);
+}
+
+class CustomInt32FieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+  std::string PrintInt32(int32_t val) const override {
+    return StrCat("value-is(", FieldValuePrinter::PrintInt32(val), ")");
+  }
+};
+
+TEST_F(TextFormatTest, FieldSpecificCustomPrinter) {
+  protobuf_unittest::TestAllTypes message;
+
+  message.set_optional_int32(42);  // This will be handled by our Printer.
+  message.add_repeated_int32(42);  // This will be printed as number.
+
+  TextFormat::Printer printer;
+  EXPECT_TRUE(printer.RegisterFieldValuePrinter(
+      message.GetDescriptor()->FindFieldByName("optional_int32"),
+      new CustomInt32FieldValuePrinter()));
+  std::string text;
+  printer.PrintToString(message, &text);
+  EXPECT_EQ("optional_int32: value-is(42)\nrepeated_int32: 42\n", text);
+}
+
+TEST_F(TextFormatTest, FieldSpecificCustomPrinterRegisterSameFieldTwice) {
+  protobuf_unittest::TestAllTypes message;
+  TextFormat::Printer printer;
+  const FieldDescriptor* const field =
+      message.GetDescriptor()->FindFieldByName("optional_int32");
+  ASSERT_TRUE(printer.RegisterFieldValuePrinter(
+      field, new CustomInt32FieldValuePrinter()));
+  const TextFormat::FieldValuePrinter* const rejected =
+      new CustomInt32FieldValuePrinter();
+  ASSERT_FALSE(printer.RegisterFieldValuePrinter(field, rejected));
+  delete rejected;
+}
+
+TEST_F(TextFormatTest, ErrorCasesRegisteringFieldValuePrinterShouldFail) {
+  protobuf_unittest::TestAllTypes message;
+  TextFormat::Printer printer;
+  // nullptr printer.
+  EXPECT_FALSE(printer.RegisterFieldValuePrinter(
+      message.GetDescriptor()->FindFieldByName("optional_int32"),
+      static_cast<const TextFormat::FieldValuePrinter*>(nullptr)));
+  EXPECT_FALSE(printer.RegisterFieldValuePrinter(
+      message.GetDescriptor()->FindFieldByName("optional_int32"),
+      static_cast<const TextFormat::FastFieldValuePrinter*>(nullptr)));
+  // Because registration fails, the ownership of this printer is never taken.
+  TextFormat::FieldValuePrinter my_field_printer;
+  // nullptr field
+  EXPECT_FALSE(printer.RegisterFieldValuePrinter(nullptr, &my_field_printer));
+}
+
+class CustomMessageFieldValuePrinter : public TextFormat::FieldValuePrinter {
+ public:
+  std::string PrintInt32(int32_t v) const override {
+    return StrCat(FieldValuePrinter::PrintInt32(v), "  # x",
+                        strings::Hex(v));
+  }
+
+  std::string PrintMessageStart(const Message& message, int field_index,
+                                int field_count,
+                                bool single_line_mode) const override {
+    if (single_line_mode) {
+      return " { ";
+    }
+    return StrCat(" {  # ", message.GetDescriptor()->name(), ": ",
+                        field_index, "\n");
+  }
+};
+
+TEST_F(TextFormatTest, CustomPrinterForComments) {
+  protobuf_unittest::TestAllTypes message;
+  message.mutable_optional_nested_message();
+  message.mutable_optional_import_message()->set_d(42);
+  message.add_repeated_nested_message();
+  message.add_repeated_nested_message();
+  message.add_repeated_import_message()->set_d(43);
+  message.add_repeated_import_message()->set_d(44);
+  TextFormat::Printer printer;
+  CustomMessageFieldValuePrinter my_field_printer;
+  printer.SetDefaultFieldValuePrinter(new CustomMessageFieldValuePrinter());
+  std::string text;
+  printer.PrintToString(message, &text);
+  EXPECT_EQ(
+      "optional_nested_message {  # NestedMessage: -1\n"
+      "}\n"
+      "optional_import_message {  # ImportMessage: -1\n"
+      "  d: 42  # x2a\n"
+      "}\n"
+      "repeated_nested_message {  # NestedMessage: 0\n"
+      "}\n"
+      "repeated_nested_message {  # NestedMessage: 1\n"
+      "}\n"
+      "repeated_import_message {  # ImportMessage: 0\n"
+      "  d: 43  # x2b\n"
+      "}\n"
+      "repeated_import_message {  # ImportMessage: 1\n"
+      "  d: 44  # x2c\n"
+      "}\n",
+      text);
+}
+
+class CustomMessageContentFieldValuePrinter
+    : public TextFormat::FastFieldValuePrinter {
+ public:
+  bool PrintMessageContent(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    if (message.ByteSizeLong() > 0) {
+      generator->PrintString(
+          strings::Substitute("# REDACTED, $0 bytes\n", message.ByteSizeLong()));
+    }
+    return true;
+  }
+};
+
+TEST_F(TextFormatTest, CustomPrinterForMessageContent) {
+  protobuf_unittest::TestAllTypes message;
+  message.mutable_optional_nested_message();
+  message.mutable_optional_import_message()->set_d(42);
+  message.add_repeated_nested_message();
+  message.add_repeated_nested_message();
+  message.add_repeated_import_message()->set_d(43);
+  message.add_repeated_import_message()->set_d(44);
+  TextFormat::Printer printer;
+  CustomMessageContentFieldValuePrinter my_field_printer;
+  printer.SetDefaultFieldValuePrinter(
+      new CustomMessageContentFieldValuePrinter());
+  std::string text;
+  printer.PrintToString(message, &text);
+  EXPECT_EQ(
+      "optional_nested_message {\n"
+      "}\n"
+      "optional_import_message {\n"
+      "  # REDACTED, 2 bytes\n"
+      "}\n"
+      "repeated_nested_message {\n"
+      "}\n"
+      "repeated_nested_message {\n"
+      "}\n"
+      "repeated_import_message {\n"
+      "  # REDACTED, 2 bytes\n"
+      "}\n"
+      "repeated_import_message {\n"
+      "  # REDACTED, 2 bytes\n"
+      "}\n",
+      text);
+}
+
+class CustomMultilineCommentPrinter : public TextFormat::FieldValuePrinter {
+ public:
+  std::string PrintMessageStart(const Message& message, int field_index,
+                                int field_count,
+                                bool single_line_comment) const override {
+    return StrCat(" {  # 1\n", "  # 2\n");
+  }
+};
+
+TEST_F(TextFormatTest, CustomPrinterForMultilineComments) {
+  protobuf_unittest::TestAllTypes message;
+  message.mutable_optional_nested_message();
+  message.mutable_optional_import_message()->set_d(42);
+  TextFormat::Printer printer;
+  CustomMessageFieldValuePrinter my_field_printer;
+  printer.SetDefaultFieldValuePrinter(new CustomMultilineCommentPrinter());
+  std::string text;
+  printer.PrintToString(message, &text);
+  EXPECT_EQ(
+      "optional_nested_message {  # 1\n"
+      "  # 2\n"
+      "}\n"
+      "optional_import_message {  # 1\n"
+      "  # 2\n"
+      "  d: 42\n"
+      "}\n",
+      text);
+}
+
+// Achieve effects similar to SetUseShortRepeatedPrimitives for messages, using
+// RegisterFieldValuePrinter. Use this to test the version of PrintFieldName
+// that accepts repeated field index and count.
+class CompactRepeatedFieldPrinter : public TextFormat::FastFieldValuePrinter {
+ public:
+  void PrintFieldName(const Message& message, int field_index, int field_count,
+                      const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      TextFormat::BaseTextGenerator* generator) const override {
+    if (field_index == 0 || field_index == -1) {
+      generator->PrintString(field->name());
+    }
+  }
+  // To prevent compiler complaining about Woverloaded-virtual
+  void PrintFieldName(const Message& message, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      TextFormat::BaseTextGenerator* generator) const override {
+  }
+  void PrintMessageStart(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    if (field_index == 0 || field_index == -1) {
+      if (single_line_mode) {
+        generator->PrintLiteral(" { ");
+      } else {
+        generator->PrintLiteral(" {\n");
+      }
+    }
+  }
+  void PrintMessageEnd(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    if (field_index == field_count - 1 || field_index == -1) {
+      if (single_line_mode) {
+        generator->PrintLiteral("} ");
+      } else {
+        generator->PrintLiteral("}\n");
+      }
+    }
+  }
+};
+
+TEST_F(TextFormatTest, CompactRepeatedFieldPrinter) {
+  TextFormat::Printer printer;
+  ASSERT_TRUE(printer.RegisterFieldValuePrinter(
+      unittest::TestAllTypes::default_instance()
+          .descriptor()
+          ->FindFieldByNumber(
+              unittest::TestAllTypes::kRepeatedNestedMessageFieldNumber),
+      new CompactRepeatedFieldPrinter));
+
+  protobuf_unittest::TestAllTypes message;
+  message.add_repeated_nested_message()->set_bb(1);
+  message.add_repeated_nested_message()->set_bb(2);
+  message.add_repeated_nested_message()->set_bb(3);
+
+  std::string text;
+  ASSERT_TRUE(printer.PrintToString(message, &text));
+  EXPECT_EQ(
+      "repeated_nested_message {\n"
+      "  bb: 1\n"
+      "  bb: 2\n"
+      "  bb: 3\n"
+      "}\n",
+      text);
+}
+
+// Print strings into multiple line, with indentation. Use this to test
+// BaseTextGenerator::Indent and BaseTextGenerator::Outdent.
+class MultilineStringPrinter : public TextFormat::FastFieldValuePrinter {
+ public:
+  void PrintString(const std::string& val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->Indent();
+    int last_pos = 0;
+    int newline_pos = val.find('\n');
+    while (newline_pos != std::string::npos) {
+      generator->PrintLiteral("\n");
+      TextFormat::FastFieldValuePrinter::PrintString(
+          val.substr(last_pos, newline_pos + 1 - last_pos), generator);
+      last_pos = newline_pos + 1;
+      newline_pos = val.find('\n', last_pos);
+    }
+    if (last_pos < val.size()) {
+      generator->PrintLiteral("\n");
+      TextFormat::FastFieldValuePrinter::PrintString(val.substr(last_pos),
+                                                     generator);
+    }
+    generator->Outdent();
+  }
+};
+
+TEST_F(TextFormatTest, MultilineStringPrinter) {
+  TextFormat::Printer printer;
+  ASSERT_TRUE(printer.RegisterFieldValuePrinter(
+      unittest::TestAllTypes::default_instance()
+          .descriptor()
+          ->FindFieldByNumber(
+              unittest::TestAllTypes::kOptionalStringFieldNumber),
+      new MultilineStringPrinter));
+
+  protobuf_unittest::TestAllTypes message;
+  message.set_optional_string("first line\nsecond line\nthird line");
+
+  std::string text;
+  ASSERT_TRUE(printer.PrintToString(message, &text));
+  EXPECT_EQ(
+      "optional_string: \n"
+      "  \"first line\\n\"\n"
+      "  \"second line\\n\"\n"
+      "  \"third line\"\n",
+      text);
+}
+
+class CustomNestedMessagePrinter : public TextFormat::MessagePrinter {
+ public:
+  CustomNestedMessagePrinter() {}
+  ~CustomNestedMessagePrinter() override {}
+  void Print(const Message& message, bool single_line_mode,
+             TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintLiteral("custom");
+  }
+};
+
+TEST_F(TextFormatTest, CustomMessagePrinter) {
+  TextFormat::Printer printer;
+  printer.RegisterMessagePrinter(
+      unittest::TestAllTypes::NestedMessage::default_instance().descriptor(),
+      new CustomNestedMessagePrinter);
+
+  unittest::TestAllTypes message;
+  std::string text;
+  EXPECT_TRUE(printer.PrintToString(message, &text));
+  EXPECT_EQ("", text);
+
+  message.mutable_optional_nested_message()->set_bb(1);
+  EXPECT_TRUE(printer.PrintToString(message, &text));
+  EXPECT_EQ("optional_nested_message {\n  custom}\n", text);
+}
+
+TEST_F(TextFormatTest, ParseBasic) {
+  io::ArrayInputStream input_stream(proto_text_format_.data(),
+                                    proto_text_format_.size());
+  TextFormat::Parse(&input_stream, &proto_);
+  TestUtil::ExpectAllFieldsSet(proto_);
+}
+
+TEST_F(TextFormatExtensionsTest, ParseExtensions) {
+  io::ArrayInputStream input_stream(proto_text_format_.data(),
+                                    proto_text_format_.size());
+  TextFormat::Parse(&input_stream, &proto_);
+  TestUtil::ExpectAllExtensionsSet(proto_);
+}
+
+TEST_F(TextFormatTest, ParseEnumFieldFromNumber) {
+  // Create a parse string with a numerical value for an enum field.
+  std::string parse_string =
+      strings::Substitute("optional_nested_enum: $0", unittest::TestAllTypes::BAZ);
+  EXPECT_TRUE(TextFormat::ParseFromString(parse_string, &proto_));
+  EXPECT_TRUE(proto_.has_optional_nested_enum());
+  EXPECT_EQ(unittest::TestAllTypes::BAZ, proto_.optional_nested_enum());
+}
+
+TEST_F(TextFormatTest, ParseEnumFieldFromNegativeNumber) {
+  ASSERT_LT(unittest::SPARSE_E, 0);
+  std::string parse_string =
+      strings::Substitute("sparse_enum: $0", unittest::SPARSE_E);
+  unittest::SparseEnumMessage proto;
+  EXPECT_TRUE(TextFormat::ParseFromString(parse_string, &proto));
+  EXPECT_TRUE(proto.has_sparse_enum());
+  EXPECT_EQ(unittest::SPARSE_E, proto.sparse_enum());
+}
+
+TEST_F(TextFormatTest, PrintUnknownEnumFieldProto3) {
+  proto3_unittest::TestAllTypes proto;
+
+  proto.add_repeated_nested_enum(
+      static_cast<proto3_unittest::TestAllTypes::NestedEnum>(10));
+  proto.add_repeated_nested_enum(
+      static_cast<proto3_unittest::TestAllTypes::NestedEnum>(-10));
+  proto.add_repeated_nested_enum(
+      static_cast<proto3_unittest::TestAllTypes::NestedEnum>(2147483647));
+  proto.add_repeated_nested_enum(
+      static_cast<proto3_unittest::TestAllTypes::NestedEnum>(-2147483648));
+
+  EXPECT_EQ(StrCat("repeated_nested_enum: ", kDebugStringSilentMarker,
+                         "10\n"
+                         "repeated_nested_enum: -10\n"
+                         "repeated_nested_enum: 2147483647\n"
+                         "repeated_nested_enum: -2147483648\n"),
+            proto.DebugString());
+}
+
+TEST_F(TextFormatTest, ParseUnknownEnumFieldProto3) {
+  proto3_unittest::TestAllTypes proto;
+  std::string parse_string =
+      "repeated_nested_enum: [10, -10, 2147483647, -2147483648]";
+  EXPECT_TRUE(TextFormat::ParseFromString(parse_string, &proto));
+  ASSERT_EQ(4, proto.repeated_nested_enum_size());
+  EXPECT_EQ(10, proto.repeated_nested_enum(0));
+  EXPECT_EQ(-10, proto.repeated_nested_enum(1));
+  EXPECT_EQ(2147483647, proto.repeated_nested_enum(2));
+  EXPECT_EQ(-2147483648, proto.repeated_nested_enum(3));
+}
+
+TEST_F(TextFormatTest, ParseStringEscape) {
+  // Create a parse string with escaped characters in it.
+  std::string parse_string =
+      "optional_string: " + kEscapeTestStringEscaped + "\n";
+
+  io::ArrayInputStream input_stream(parse_string.data(), parse_string.size());
+  TextFormat::Parse(&input_stream, &proto_);
+
+  // Compare.
+  EXPECT_EQ(kEscapeTestString, proto_.optional_string());
+}
+
+TEST_F(TextFormatTest, ParseConcatenatedString) {
+  // Create a parse string with multiple parts on one line.
+  std::string parse_string = "optional_string: \"foo\" \"bar\"\n";
+
+  io::ArrayInputStream input_stream1(parse_string.data(), parse_string.size());
+  TextFormat::Parse(&input_stream1, &proto_);
+
+  // Compare.
+  EXPECT_EQ("foobar", proto_.optional_string());
+
+  // Create a parse string with multiple parts on separate lines.
+  parse_string =
+      "optional_string: \"foo\"\n"
+      "\"bar\"\n";
+
+  io::ArrayInputStream input_stream2(parse_string.data(), parse_string.size());
+  TextFormat::Parse(&input_stream2, &proto_);
+
+  // Compare.
+  EXPECT_EQ("foobar", proto_.optional_string());
+}
+
+TEST_F(TextFormatTest, ParseFloatWithSuffix) {
+  // Test that we can parse a floating-point value with 'f' appended to the
+  // end.  This is needed for backwards-compatibility with proto1.
+
+  // Have it parse a float with the 'f' suffix.
+  std::string parse_string = "optional_float: 1.0f\n";
+
+  io::ArrayInputStream input_stream(parse_string.data(), parse_string.size());
+
+  TextFormat::Parse(&input_stream, &proto_);
+
+  // Compare.
+  EXPECT_EQ(1.0, proto_.optional_float());
+}
+
+TEST_F(TextFormatTest, ParseShortRepeatedForm) {
+  std::string parse_string =
+      // Mixed short-form and long-form are simply concatenated.
+      "repeated_int32: 1\n"
+      "repeated_int32: [456, 789]\n"
+      "repeated_nested_enum: [  FOO ,BAR, # comment\n"
+      "                         3]\n"
+      // Note that while the printer won't print repeated strings in short-form,
+      // the parser will accept them.
+      "repeated_string: [ \"foo\", 'bar' ]\n"
+      // Repeated message
+      "repeated_nested_message: [ { bb: 1 }, { bb : 2 }]\n"
+      // Repeated group
+      "RepeatedGroup [{ a: 3 },{ a: 4 }]\n";
+
+  ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto_));
+
+  ASSERT_EQ(3, proto_.repeated_int32_size());
+  EXPECT_EQ(1, proto_.repeated_int32(0));
+  EXPECT_EQ(456, proto_.repeated_int32(1));
+  EXPECT_EQ(789, proto_.repeated_int32(2));
+
+  ASSERT_EQ(3, proto_.repeated_nested_enum_size());
+  EXPECT_EQ(unittest::TestAllTypes::FOO, proto_.repeated_nested_enum(0));
+  EXPECT_EQ(unittest::TestAllTypes::BAR, proto_.repeated_nested_enum(1));
+  EXPECT_EQ(unittest::TestAllTypes::BAZ, proto_.repeated_nested_enum(2));
+
+  ASSERT_EQ(2, proto_.repeated_string_size());
+  EXPECT_EQ("foo", proto_.repeated_string(0));
+  EXPECT_EQ("bar", proto_.repeated_string(1));
+
+  ASSERT_EQ(2, proto_.repeated_nested_message_size());
+  EXPECT_EQ(1, proto_.repeated_nested_message(0).bb());
+  EXPECT_EQ(2, proto_.repeated_nested_message(1).bb());
+
+  ASSERT_EQ(2, proto_.repeatedgroup_size());
+  EXPECT_EQ(3, proto_.repeatedgroup(0).a());
+  EXPECT_EQ(4, proto_.repeatedgroup(1).a());
+}
+
+TEST_F(TextFormatTest, ParseShortRepeatedWithTrailingComma) {
+  std::string parse_string = "repeated_int32: [456,]\n";
+  ASSERT_FALSE(TextFormat::ParseFromString(parse_string, &proto_));
+  parse_string = "repeated_nested_enum: [  FOO , ]";
+  ASSERT_FALSE(TextFormat::ParseFromString(parse_string, &proto_));
+  parse_string = "repeated_string: [ \"foo\", ]";
+  ASSERT_FALSE(TextFormat::ParseFromString(parse_string, &proto_));
+  parse_string = "repeated_nested_message: [ { bb: 1 }, ]";
+  ASSERT_FALSE(TextFormat::ParseFromString(parse_string, &proto_));
+  parse_string = "RepeatedGroup [{ a: 3 },]\n";
+}
+
+TEST_F(TextFormatTest, ParseShortRepeatedEmpty) {
+  std::string parse_string =
+      "repeated_int32: []\n"
+      "repeated_nested_enum: []\n"
+      "repeated_string: []\n"
+      "repeated_nested_message: []\n"
+      "RepeatedGroup []\n";
+
+  ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto_));
+
+  EXPECT_EQ(0, proto_.repeated_int32_size());
+  EXPECT_EQ(0, proto_.repeated_nested_enum_size());
+  EXPECT_EQ(0, proto_.repeated_string_size());
+  EXPECT_EQ(0, proto_.repeated_nested_message_size());
+  EXPECT_EQ(0, proto_.repeatedgroup_size());
+}
+
+TEST_F(TextFormatTest, ParseShortRepeatedConcatenatedWithEmpty) {
+  std::string parse_string =
+      // Starting with empty [] should have no impact.
+      "repeated_int32: []\n"
+      "repeated_nested_enum: []\n"
+      "repeated_string: []\n"
+      "repeated_nested_message: []\n"
+      "RepeatedGroup []\n"
+      // Mixed short-form and long-form are simply concatenated.
+      "repeated_int32: 1\n"
+      "repeated_int32: [456, 789]\n"
+      "repeated_nested_enum: [  FOO ,BAR, # comment\n"
+      "                         3]\n"
+      // Note that while the printer won't print repeated strings in short-form,
+      // the parser will accept them.
+      "repeated_string: [ \"foo\", 'bar' ]\n"
+      // Repeated message
+      "repeated_nested_message: [ { bb: 1 }, { bb : 2 }]\n"
+      // Repeated group
+      "RepeatedGroup [{ a: 3 },{ a: 4 }]\n"
+      // Adding empty [] should have no impact.
+      "repeated_int32: []\n"
+      "repeated_nested_enum: []\n"
+      "repeated_string: []\n"
+      "repeated_nested_message: []\n"
+      "RepeatedGroup []\n";
+
+  ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto_));
+
+  ASSERT_EQ(3, proto_.repeated_int32_size());
+  EXPECT_EQ(1, proto_.repeated_int32(0));
+  EXPECT_EQ(456, proto_.repeated_int32(1));
+  EXPECT_EQ(789, proto_.repeated_int32(2));
+
+  ASSERT_EQ(3, proto_.repeated_nested_enum_size());
+  EXPECT_EQ(unittest::TestAllTypes::FOO, proto_.repeated_nested_enum(0));
+  EXPECT_EQ(unittest::TestAllTypes::BAR, proto_.repeated_nested_enum(1));
+  EXPECT_EQ(unittest::TestAllTypes::BAZ, proto_.repeated_nested_enum(2));
+
+  ASSERT_EQ(2, proto_.repeated_string_size());
+  EXPECT_EQ("foo", proto_.repeated_string(0));
+  EXPECT_EQ("bar", proto_.repeated_string(1));
+
+  ASSERT_EQ(2, proto_.repeated_nested_message_size());
+  EXPECT_EQ(1, proto_.repeated_nested_message(0).bb());
+  EXPECT_EQ(2, proto_.repeated_nested_message(1).bb());
+
+  ASSERT_EQ(2, proto_.repeatedgroup_size());
+  EXPECT_EQ(3, proto_.repeatedgroup(0).a());
+  EXPECT_EQ(4, proto_.repeatedgroup(1).a());
+}
+
+
+TEST_F(TextFormatTest, Comments) {
+  // Test that comments are ignored.
+
+  std::string parse_string =
+      "optional_int32: 1  # a comment\n"
+      "optional_int64: 2  # another comment";
+
+  io::ArrayInputStream input_stream(parse_string.data(), parse_string.size());
+
+  TextFormat::Parse(&input_stream, &proto_);
+
+  // Compare.
+  EXPECT_EQ(1, proto_.optional_int32());
+  EXPECT_EQ(2, proto_.optional_int64());
+}
+
+TEST_F(TextFormatTest, OptionalColon) {
+  // Test that we can place a ':' after the field name of a nested message,
+  // even though we don't have to.
+
+  std::string parse_string = "optional_nested_message: { bb: 1}\n";
+
+  io::ArrayInputStream input_stream(parse_string.data(), parse_string.size());
+
+  TextFormat::Parse(&input_stream, &proto_);
+
+  // Compare.
+  EXPECT_TRUE(proto_.has_optional_nested_message());
+  EXPECT_EQ(1, proto_.optional_nested_message().bb());
+}
+
+// Some platforms (e.g. Windows) insist on padding the exponent to three
+// digits when one or two would be just fine.
+static std::string RemoveRedundantZeros(std::string text) {
+  text = StringReplace(text, "e+0", "e+", true);
+  text = StringReplace(text, "e-0", "e-", true);
+  return text;
+}
+
+TEST_F(TextFormatTest, PrintExotic) {
+  unittest::TestAllTypes message;
+
+  message.add_repeated_int64(int64_t{-9223372036854775807} - 1);
+  message.add_repeated_uint64(uint64_t{18446744073709551615u});
+  message.add_repeated_double(123.456);
+  message.add_repeated_double(1.23e21);
+  message.add_repeated_double(1.23e-18);
+  message.add_repeated_double(std::numeric_limits<double>::infinity());
+  message.add_repeated_double(-std::numeric_limits<double>::infinity());
+  message.add_repeated_double(std::numeric_limits<double>::quiet_NaN());
+  message.add_repeated_double(-std::numeric_limits<double>::quiet_NaN());
+  message.add_repeated_double(std::numeric_limits<double>::signaling_NaN());
+  message.add_repeated_double(-std::numeric_limits<double>::signaling_NaN());
+  message.add_repeated_string(std::string("\000\001\a\b\f\n\r\t\v\\\'\"", 12));
+
+  // Fun story:  We used to use 1.23e22 instead of 1.23e21 above, but this
+  //   seemed to trigger an odd case on MinGW/GCC 3.4.5 where GCC's parsing of
+  //   the value differed from strtod()'s parsing.  That is to say, the
+  //   following assertion fails on MinGW:
+  //     assert(1.23e22 == strtod("1.23e22", nullptr));
+  //   As a result, SimpleDtoa() would print the value as
+  //   "1.2300000000000001e+22" to make sure strtod() produce the exact same
+  //   result.  Our goal is to test runtime parsing, not compile-time parsing,
+  //   so this wasn't our problem.  It was found that using 1.23e21 did not
+  //   have this problem, so we switched to that instead.
+
+  EXPECT_EQ(
+      StrCat("repeated_int64: ", kDebugStringSilentMarker,
+                   "-9223372036854775808\n"
+                   "repeated_uint64: 18446744073709551615\n"
+                   "repeated_double: 123.456\n"
+                   "repeated_double: 1.23e+21\n"
+                   "repeated_double: 1.23e-18\n"
+                   "repeated_double: inf\n"
+                   "repeated_double: -inf\n"
+                   "repeated_double: nan\n"
+                   "repeated_double: nan\n"
+                   "repeated_double: nan\n"
+                   "repeated_double: nan\n"
+                   "repeated_string: "
+                   "\"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\'\\\"\"\n"),
+      RemoveRedundantZeros(message.DebugString()));
+}
+
+TEST_F(TextFormatTest, PrintFloatPrecision) {
+  unittest::TestAllTypes message;
+
+  message.add_repeated_float(1.0);
+  message.add_repeated_float(1.2);
+  message.add_repeated_float(1.23);
+  message.add_repeated_float(1.234);
+  message.add_repeated_float(1.2345);
+  message.add_repeated_float(1.23456);
+  message.add_repeated_float(1.2e10);
+  message.add_repeated_float(1.23e10);
+  message.add_repeated_float(1.234e10);
+  message.add_repeated_float(1.2345e10);
+  message.add_repeated_float(1.23456e10);
+  message.add_repeated_double(1.2);
+  message.add_repeated_double(1.23);
+  message.add_repeated_double(1.234);
+  message.add_repeated_double(1.2345);
+  message.add_repeated_double(1.23456);
+  message.add_repeated_double(1.234567);
+  message.add_repeated_double(1.2345678);
+  message.add_repeated_double(1.23456789);
+  message.add_repeated_double(1.234567898);
+  message.add_repeated_double(1.2345678987);
+  message.add_repeated_double(1.23456789876);
+  message.add_repeated_double(1.234567898765);
+  message.add_repeated_double(1.2345678987654);
+  message.add_repeated_double(1.23456789876543);
+  message.add_repeated_double(1.2e100);
+  message.add_repeated_double(1.23e100);
+  message.add_repeated_double(1.234e100);
+  message.add_repeated_double(1.2345e100);
+  message.add_repeated_double(1.23456e100);
+  message.add_repeated_double(1.234567e100);
+  message.add_repeated_double(1.2345678e100);
+  message.add_repeated_double(1.23456789e100);
+  message.add_repeated_double(1.234567898e100);
+  message.add_repeated_double(1.2345678987e100);
+  message.add_repeated_double(1.23456789876e100);
+  message.add_repeated_double(1.234567898765e100);
+  message.add_repeated_double(1.2345678987654e100);
+  message.add_repeated_double(1.23456789876543e100);
+
+  EXPECT_EQ(StrCat("repeated_float: ", kDebugStringSilentMarker,
+                         "1\n"
+                         "repeated_float: 1.2\n"
+                         "repeated_float: 1.23\n"
+                         "repeated_float: 1.234\n"
+                         "repeated_float: 1.2345\n"
+                         "repeated_float: 1.23456\n"
+                         "repeated_float: 1.2e+10\n"
+                         "repeated_float: 1.23e+10\n"
+                         "repeated_float: 1.234e+10\n"
+                         "repeated_float: 1.2345e+10\n"
+                         "repeated_float: 1.23456e+10\n"
+                         "repeated_double: 1.2\n"
+                         "repeated_double: 1.23\n"
+                         "repeated_double: 1.234\n"
+                         "repeated_double: 1.2345\n"
+                         "repeated_double: 1.23456\n"
+                         "repeated_double: 1.234567\n"
+                         "repeated_double: 1.2345678\n"
+                         "repeated_double: 1.23456789\n"
+                         "repeated_double: 1.234567898\n"
+                         "repeated_double: 1.2345678987\n"
+                         "repeated_double: 1.23456789876\n"
+                         "repeated_double: 1.234567898765\n"
+                         "repeated_double: 1.2345678987654\n"
+                         "repeated_double: 1.23456789876543\n"
+                         "repeated_double: 1.2e+100\n"
+                         "repeated_double: 1.23e+100\n"
+                         "repeated_double: 1.234e+100\n"
+                         "repeated_double: 1.2345e+100\n"
+                         "repeated_double: 1.23456e+100\n"
+                         "repeated_double: 1.234567e+100\n"
+                         "repeated_double: 1.2345678e+100\n"
+                         "repeated_double: 1.23456789e+100\n"
+                         "repeated_double: 1.234567898e+100\n"
+                         "repeated_double: 1.2345678987e+100\n"
+                         "repeated_double: 1.23456789876e+100\n"
+                         "repeated_double: 1.234567898765e+100\n"
+                         "repeated_double: 1.2345678987654e+100\n"
+                         "repeated_double: 1.23456789876543e+100\n"),
+            RemoveRedundantZeros(message.DebugString()));
+}
+
+TEST_F(TextFormatTest, AllowPartial) {
+  unittest::TestRequired message;
+  TextFormat::Parser parser;
+  parser.AllowPartialMessage(true);
+  EXPECT_TRUE(parser.ParseFromString("a: 1", &message));
+  EXPECT_EQ(1, message.a());
+  EXPECT_FALSE(message.has_b());
+  EXPECT_FALSE(message.has_c());
+}
+
+TEST_F(TextFormatTest, ParseExotic) {
+  unittest::TestAllTypes message;
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "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: 1.23E17\n"
+      "repeated_double: 1.235E+22\n"
+      "repeated_double: 1.235e-18\n"
+      "repeated_double: 123.456789\n"
+      "repeated_double: inf\n"
+      "repeated_double: Infinity\n"
+      "repeated_double: -inf\n"
+      "repeated_double: -Infinity\n"
+      "repeated_double: nan\n"
+      "repeated_double: NaN\n"
+      "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\"\n",
+      &message));
+
+  ASSERT_EQ(2, message.repeated_int32_size());
+  EXPECT_EQ(-1, message.repeated_int32(0));
+  EXPECT_EQ(-2147483648, message.repeated_int32(1));
+
+  ASSERT_EQ(2, message.repeated_int64_size());
+  EXPECT_EQ(-1, message.repeated_int64(0));
+  EXPECT_EQ(int64_t{-9223372036854775807} - 1, message.repeated_int64(1));
+
+  ASSERT_EQ(2, message.repeated_uint32_size());
+  EXPECT_EQ(4294967295u, message.repeated_uint32(0));
+  EXPECT_EQ(2147483648u, message.repeated_uint32(1));
+
+  ASSERT_EQ(2, message.repeated_uint64_size());
+  EXPECT_EQ(uint64_t{18446744073709551615u}, message.repeated_uint64(0));
+  EXPECT_EQ(uint64_t{9223372036854775808u}, message.repeated_uint64(1));
+
+  ASSERT_EQ(13, message.repeated_double_size());
+  EXPECT_EQ(123.0, message.repeated_double(0));
+  EXPECT_EQ(123.5, message.repeated_double(1));
+  EXPECT_EQ(0.125, message.repeated_double(2));
+  EXPECT_EQ(1.23E17, message.repeated_double(3));
+  EXPECT_EQ(1.235E22, message.repeated_double(4));
+  EXPECT_EQ(1.235E-18, message.repeated_double(5));
+  EXPECT_EQ(123.456789, message.repeated_double(6));
+  EXPECT_EQ(message.repeated_double(7),
+            std::numeric_limits<double>::infinity());
+  EXPECT_EQ(message.repeated_double(8),
+            std::numeric_limits<double>::infinity());
+  EXPECT_EQ(message.repeated_double(9),
+            -std::numeric_limits<double>::infinity());
+  EXPECT_EQ(message.repeated_double(10),
+            -std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(std::isnan(message.repeated_double(11)));
+  EXPECT_TRUE(std::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.
+  ASSERT_EQ(1, message.repeated_string_size());
+  EXPECT_EQ(std::string("\000\001\a\b\f\n\r\t\v\\\'\"", 12),
+            message.repeated_string(0));
+
+  ASSERT_TRUE(
+      TextFormat::ParseFromString("repeated_float: 3.4028235e+38\n"
+                                  "repeated_float: -3.4028235e+38\n"
+                                  "repeated_float: 3.402823567797337e+38\n"
+                                  "repeated_float: -3.402823567797337e+38\n",
+                                  &message));
+  EXPECT_EQ(message.repeated_float(0), std::numeric_limits<float>::max());
+  EXPECT_EQ(message.repeated_float(1), -std::numeric_limits<float>::max());
+  EXPECT_EQ(message.repeated_float(2), std::numeric_limits<float>::infinity());
+  EXPECT_EQ(message.repeated_float(3), -std::numeric_limits<float>::infinity());
+
+}
+
+TEST_F(TextFormatTest, PrintFieldsInIndexOrder) {
+  protobuf_unittest::TestFieldOrderings message;
+  // Fields are listed in index order instead of field number.
+  message.set_my_string("str");  // Field number 11
+  message.set_my_int(12345);     // Field number 1
+  message.set_my_float(0.999);   // Field number 101
+  // Extensions are listed based on the order of extension number.
+  // Extension number 12.
+  message
+      .MutableExtension(
+          protobuf_unittest::TestExtensionOrderings2::test_ext_orderings2)
+      ->set_my_string("ext_str2");
+  // Extension number 13.
+  message
+      .MutableExtension(
+          protobuf_unittest::TestExtensionOrderings1::test_ext_orderings1)
+      ->set_my_string("ext_str1");
+  // Extension number 14.
+  message
+      .MutableExtension(protobuf_unittest::TestExtensionOrderings2::
+                            TestExtensionOrderings3::test_ext_orderings3)
+      ->set_my_string("ext_str3");
+  // Extension number 50.
+  *message.MutableExtension(protobuf_unittest::my_extension_string) = "ext_str0";
+
+  TextFormat::Printer printer;
+  std::string text;
+
+  // By default, print in field number order.
+  // my_int: 12345
+  // my_string: "str"
+  // [protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {
+  //   my_string: "ext_str2"
+  // }
+  // [protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {
+  //   my_string: "ext_str1"
+  // }
+  // [protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3.test_ext_orderings3]
+  // {
+  //   my_string: "ext_str3"
+  // }
+  // [protobuf_unittest.my_extension_string]: "ext_str0"
+  // my_float: 0.999
+  printer.PrintToString(message, &text);
+  EXPECT_EQ(
+      "my_int: 12345\nmy_string: "
+      "\"str\"\n[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] "
+      "{\n  my_string: "
+      "\"ext_str2\"\n}\n[protobuf_unittest.TestExtensionOrderings1.test_ext_"
+      "orderings1] {\n  my_string: "
+      "\"ext_str1\"\n}\n[protobuf_unittest.TestExtensionOrderings2."
+      "TestExtensionOrderings3.test_ext_orderings3] {\n  my_string: "
+      "\"ext_str3\"\n}\n[protobuf_unittest.my_extension_string]: "
+      "\"ext_str0\"\nmy_float: 0.999\n",
+      text);
+
+  // Print in index order.
+  // my_string: "str"
+  // my_int: 12345
+  // my_float: 0.999
+  // [protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {
+  //   my_string: "ext_str2"
+  // }
+  // [protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {
+  //   my_string: "ext_str1"
+  // }
+  // [protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3.test_ext_orderings3]
+  // {
+  //   my_string: "ext_str3"
+  // }
+  // [protobuf_unittest.my_extension_string]: "ext_str0"
+  printer.SetPrintMessageFieldsInIndexOrder(true);
+  printer.PrintToString(message, &text);
+  EXPECT_EQ(
+      "my_string: \"str\"\nmy_int: 12345\nmy_float: "
+      "0.999\n[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] "
+      "{\n  my_string: "
+      "\"ext_str2\"\n}\n[protobuf_unittest.TestExtensionOrderings1.test_ext_"
+      "orderings1] {\n  my_string: "
+      "\"ext_str1\"\n}\n[protobuf_unittest.TestExtensionOrderings2."
+      "TestExtensionOrderings3.test_ext_orderings3] {\n  my_string: "
+      "\"ext_str3\"\n}\n[protobuf_unittest.my_extension_string]: \"ext_str0\"\n",
+      text);
+}
+
+class TextFormatParserTest : public testing::Test {
+ protected:
+  void ExpectFailure(const std::string& input, const std::string& message,
+                     int line, int col) {
+    std::unique_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
+    ExpectFailure(input, message, line, col, proto.get());
+  }
+
+  void ExpectFailure(const std::string& input, const std::string& message,
+                     int line, int col, Message* proto) {
+    ExpectMessage(input, message, line, col, proto, false);
+  }
+
+  void ExpectMessage(const std::string& input, const std::string& message,
+                     int line, int col, Message* proto, bool expected_result) {
+    MockErrorCollector error_collector;
+    parser_.RecordErrorsTo(&error_collector);
+    EXPECT_EQ(expected_result, parser_.ParseFromString(input, proto))
+        << input << " -> " << proto->DebugString();
+    EXPECT_EQ(StrCat(line, ":", col, ": ", message, "\n"),
+              error_collector.text_);
+    parser_.RecordErrorsTo(nullptr);
+  }
+
+  void ExpectSuccessAndTree(const std::string& input, Message* proto,
+                            TextFormat::ParseInfoTree* info_tree) {
+    MockErrorCollector error_collector;
+    parser_.RecordErrorsTo(&error_collector);
+    parser_.WriteLocationsTo(info_tree);
+    EXPECT_TRUE(parser_.ParseFromString(input, proto));
+    parser_.WriteLocationsTo(nullptr);
+    parser_.RecordErrorsTo(nullptr);
+  }
+
+  void ExpectLocation(TextFormat::ParseInfoTree* tree, const Descriptor* d,
+                      const std::string& field_name, int index, int start_line,
+                      int start_column, int end_line, int end_column) {
+    TextFormat::ParseLocationRange range =
+        tree->GetLocationRange(d->FindFieldByName(field_name), index);
+    EXPECT_EQ(start_line, range.start.line);
+    EXPECT_EQ(start_column, range.start.column);
+    EXPECT_EQ(end_line, range.end.line);
+    EXPECT_EQ(end_column, range.end.column);
+    TextFormat::ParseLocation start_location =
+        tree->GetLocation(d->FindFieldByName(field_name), index);
+    EXPECT_EQ(start_line, start_location.line);
+    EXPECT_EQ(start_column, start_location.column);
+  }
+
+  // An error collector which simply concatenates all its errors into a big
+  // block of text which can be checked.
+  class MockErrorCollector : public io::ErrorCollector {
+   public:
+    MockErrorCollector() {}
+    ~MockErrorCollector() override {}
+
+    std::string text_;
+
+    // implements ErrorCollector -------------------------------------
+    void AddError(int line, int column, const std::string& message) override {
+      strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line + 1, column + 1,
+                                message);
+    }
+
+    void AddWarning(int line, int column, const std::string& message) override {
+      AddError(line, column, "WARNING:" + message);
+    }
+  };
+
+  TextFormat::Parser parser_;
+};
+
+TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
+  std::unique_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+  const Descriptor* d = message->GetDescriptor();
+
+  std::string stringData =
+      "optional_int32: 1\n"
+      "optional_int64: 2\n"
+      "  optional_double: 2.4\n"
+      "repeated_int32: 5\n"
+      "repeated_int32: 10\n"
+      "optional_nested_message <\n"
+      "  bb: 78\n"
+      ">\n"
+      "repeated_nested_message <\n"
+      "  bb: 79\n"
+      ">\n"
+      "repeated_nested_message <\n"
+      "  bb: 80\n"
+      ">";
+
+  TextFormat::ParseInfoTree tree;
+  ExpectSuccessAndTree(stringData, message.get(), &tree);
+
+  // Verify that the tree has the correct positions.
+  ExpectLocation(&tree, d, "optional_int32", -1, 0, 0, 0, 17);
+  ExpectLocation(&tree, d, "optional_int64", -1, 1, 0, 1, 17);
+  ExpectLocation(&tree, d, "optional_double", -1, 2, 2, 2, 22);
+
+  ExpectLocation(&tree, d, "repeated_int32", 0, 3, 0, 3, 17);
+  ExpectLocation(&tree, d, "repeated_int32", 1, 4, 0, 4, 18);
+
+  ExpectLocation(&tree, d, "optional_nested_message", -1, 5, 0, 7, 1);
+  ExpectLocation(&tree, d, "repeated_nested_message", 0, 8, 0, 10, 1);
+  ExpectLocation(&tree, d, "repeated_nested_message", 1, 11, 0, 13, 1);
+
+  // Check for fields not set. For an invalid field, the start and end locations
+  // returned should be -1, -1.
+  ExpectLocation(&tree, d, "repeated_int64", 0, -1, -1, -1, -1);
+  ExpectLocation(&tree, d, "repeated_int32", 6, -1, -1, -1, -1);
+  ExpectLocation(&tree, d, "some_unknown_field", -1, -1, -1, -1, -1);
+
+  // Verify inside the nested message.
+  const FieldDescriptor* nested_field =
+      d->FindFieldByName("optional_nested_message");
+
+  TextFormat::ParseInfoTree* nested_tree =
+      tree.GetTreeForNested(nested_field, -1);
+  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 6, 2, 6,
+                 8);
+
+  // Verify inside another nested message.
+  nested_field = d->FindFieldByName("repeated_nested_message");
+  nested_tree = tree.GetTreeForNested(nested_field, 0);
+  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 9, 2, 9,
+                 8);
+
+  nested_tree = tree.GetTreeForNested(nested_field, 1);
+  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 12, 2, 12,
+                 8);
+
+  // Verify a nullptr tree for an unknown nested field.
+  TextFormat::ParseInfoTree* unknown_nested_tree =
+      tree.GetTreeForNested(nested_field, 2);
+
+  EXPECT_EQ(nullptr, unknown_nested_tree);
+}
+
+TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
+  std::unique_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+  const Descriptor* d = message->GetDescriptor();
+
+#define EXPECT_FIELD(name, value, valuestring)                             \
+  EXPECT_TRUE(TextFormat::ParseFieldValueFromString(                       \
+      valuestring, d->FindFieldByName("optional_" #name), message.get())); \
+  EXPECT_EQ(value, message->optional_##name());                            \
+  EXPECT_TRUE(message->has_optional_##name());
+
+#define EXPECT_BOOL_FIELD(name, value, valuestring)                        \
+  EXPECT_TRUE(TextFormat::ParseFieldValueFromString(                       \
+      valuestring, d->FindFieldByName("optional_" #name), message.get())); \
+  EXPECT_TRUE(message->optional_##name() == value);                        \
+  EXPECT_TRUE(message->has_optional_##name());
+
+#define EXPECT_FLOAT_FIELD(name, value, valuestring)                       \
+  EXPECT_TRUE(TextFormat::ParseFieldValueFromString(                       \
+      valuestring, d->FindFieldByName("optional_" #name), message.get())); \
+  EXPECT_FLOAT_EQ(value, message->optional_##name());                      \
+  EXPECT_TRUE(message->has_optional_##name());
+
+#define EXPECT_DOUBLE_FIELD(name, value, valuestring)                      \
+  EXPECT_TRUE(TextFormat::ParseFieldValueFromString(                       \
+      valuestring, d->FindFieldByName("optional_" #name), message.get())); \
+  EXPECT_DOUBLE_EQ(value, message->optional_##name());                     \
+  EXPECT_TRUE(message->has_optional_##name());
+
+#define EXPECT_INVALID(name, valuestring)             \
+  EXPECT_FALSE(TextFormat::ParseFieldValueFromString( \
+      valuestring, d->FindFieldByName("optional_" #name), message.get()));
+
+  // int32
+  EXPECT_FIELD(int32, 1, "1");
+  EXPECT_FIELD(int32, -1, "-1");
+  EXPECT_FIELD(int32, 0x1234, "0x1234");
+  EXPECT_INVALID(int32, "a");
+  EXPECT_INVALID(int32, "999999999999999999999999999999999999");
+  EXPECT_INVALID(int32, "1,2");
+
+  // int64
+  EXPECT_FIELD(int64, 1, "1");
+  EXPECT_FIELD(int64, -1, "-1");
+  EXPECT_FIELD(int64, 0x1234567812345678LL, "0x1234567812345678");
+  EXPECT_INVALID(int64, "a");
+  EXPECT_INVALID(int64, "999999999999999999999999999999999999");
+  EXPECT_INVALID(int64, "1,2");
+
+  // uint64
+  EXPECT_FIELD(uint64, 1, "1");
+  EXPECT_FIELD(uint64, 0xf234567812345678ULL, "0xf234567812345678");
+  EXPECT_INVALID(uint64, "-1");
+  EXPECT_INVALID(uint64, "a");
+  EXPECT_INVALID(uint64, "999999999999999999999999999999999999");
+  EXPECT_INVALID(uint64, "1,2");
+
+  // fixed32
+  EXPECT_FIELD(fixed32, 1, "1");
+  EXPECT_FIELD(fixed32, 0x12345678, "0x12345678");
+  EXPECT_INVALID(fixed32, "-1");
+  EXPECT_INVALID(fixed32, "a");
+  EXPECT_INVALID(fixed32, "999999999999999999999999999999999999");
+  EXPECT_INVALID(fixed32, "1,2");
+
+  // fixed64
+  EXPECT_FIELD(fixed64, 1, "1");
+  EXPECT_FIELD(fixed64, 0x1234567812345678ULL, "0x1234567812345678");
+  EXPECT_INVALID(fixed64, "-1");
+  EXPECT_INVALID(fixed64, "a");
+  EXPECT_INVALID(fixed64, "999999999999999999999999999999999999");
+  EXPECT_INVALID(fixed64, "1,2");
+
+  // bool
+  EXPECT_BOOL_FIELD(bool, true, "true");
+  EXPECT_BOOL_FIELD(bool, false, "false");
+  EXPECT_BOOL_FIELD(bool, true, "1");
+  EXPECT_BOOL_FIELD(bool, true, "t");
+  EXPECT_BOOL_FIELD(bool, false, "0");
+  EXPECT_BOOL_FIELD(bool, false, "f");
+  EXPECT_FIELD(bool, true, "True");
+  EXPECT_FIELD(bool, false, "False");
+  EXPECT_INVALID(bool, "tRue");
+  EXPECT_INVALID(bool, "faLse");
+  EXPECT_INVALID(bool, "2");
+  EXPECT_INVALID(bool, "-0");
+  EXPECT_INVALID(bool, "on");
+  EXPECT_INVALID(bool, "a");
+
+  // float
+  EXPECT_FIELD(float, 1, "1");
+  EXPECT_FLOAT_FIELD(float, 1.5, "1.5");
+  EXPECT_FLOAT_FIELD(float, 1.5e3, "1.5e3");
+  EXPECT_FLOAT_FIELD(float, -4.55, "-4.55");
+  EXPECT_INVALID(float, "a");
+  EXPECT_INVALID(float, "1,2");
+
+  // double
+  EXPECT_FIELD(double, 1, "1");
+  EXPECT_FIELD(double, -1, "-1");
+  EXPECT_DOUBLE_FIELD(double, 2.3, "2.3");
+  EXPECT_DOUBLE_FIELD(double, 3e5, "3e5");
+  EXPECT_INVALID(double, "a");
+  EXPECT_INVALID(double, "1,2");
+  // Rejects hex and oct numbers for a double field.
+  EXPECT_INVALID(double, "0xf");
+  EXPECT_INVALID(double, "012");
+
+  // string
+  EXPECT_FIELD(string, "hello", "\"hello\"");
+  EXPECT_FIELD(string, "-1.87", "'-1.87'");
+  EXPECT_INVALID(string, "hello");  // without quote for value
+
+  // enum
+  EXPECT_FIELD(nested_enum, unittest::TestAllTypes::BAR, "BAR");
+  EXPECT_FIELD(nested_enum, unittest::TestAllTypes::BAZ,
+               StrCat(unittest::TestAllTypes::BAZ));
+  EXPECT_INVALID(nested_enum, "FOOBAR");
+
+  // message
+  EXPECT_TRUE(TextFormat::ParseFieldValueFromString(
+      "<bb:12>", d->FindFieldByName("optional_nested_message"), message.get()));
+  EXPECT_EQ(12, message->optional_nested_message().bb());
+  EXPECT_TRUE(message->has_optional_nested_message());
+  EXPECT_INVALID(nested_message, "any");
+
+#undef EXPECT_FIELD
+#undef EXPECT_BOOL_FIELD
+#undef EXPECT_FLOAT_FIELD
+#undef EXPECT_DOUBLE_FIELD
+#undef EXPECT_INVALID
+}
+
+TEST_F(TextFormatParserTest, InvalidToken) {
+  ExpectFailure("optional_bool: true\n-5\n", "Expected identifier, got: -", 2,
+                1);
+
+  ExpectFailure("optional_bool: true!\n", "Expected identifier, got: !", 1, 20);
+  ExpectFailure("\"some string\"", "Expected identifier, got: \"some string\"",
+                1, 1);
+}
+
+TEST_F(TextFormatParserTest, InvalidFieldName) {
+  ExpectFailure(
+      "invalid_field: somevalue\n",
+      "Message type \"protobuf_unittest.TestAllTypes\" has no field named "
+      "\"invalid_field\".",
+      1, 14);
+}
+
+TEST_F(TextFormatParserTest, InvalidCapitalization) {
+  // We require that group names be exactly as they appear in the .proto.
+  ExpectFailure(
+      "optionalgroup {\na: 15\n}\n",
+      "Message type \"protobuf_unittest.TestAllTypes\" has no field named "
+      "\"optionalgroup\".",
+      1, 15);
+  ExpectFailure(
+      "OPTIONALgroup {\na: 15\n}\n",
+      "Message type \"protobuf_unittest.TestAllTypes\" has no field named "
+      "\"OPTIONALgroup\".",
+      1, 15);
+  ExpectFailure(
+      "Optional_Double: 10.0\n",
+      "Message type \"protobuf_unittest.TestAllTypes\" has no field named "
+      "\"Optional_Double\".",
+      1, 16);
+}
+
+TEST_F(TextFormatParserTest, AllowIgnoreCapitalizationError) {
+  TextFormat::Parser parser;
+  protobuf_unittest::TestAllTypes proto;
+
+  // These fields have a mismatching case.
+  EXPECT_FALSE(parser.ParseFromString("Optional_Double: 10.0", &proto));
+  EXPECT_FALSE(parser.ParseFromString("oPtIoNaLgRoUp { a: 15 }", &proto));
+
+  // ... but are parsed correctly if we match case insensitive.
+  parser.AllowCaseInsensitiveField(true);
+  EXPECT_TRUE(parser.ParseFromString("Optional_Double: 10.0", &proto));
+  EXPECT_EQ(10.0, proto.optional_double());
+  EXPECT_TRUE(parser.ParseFromString("oPtIoNaLgRoUp { a: 15 }", &proto));
+  EXPECT_EQ(15, proto.optionalgroup().a());
+}
+
+TEST_F(TextFormatParserTest, InvalidFieldValues) {
+  // Invalid values for a double/float field.
+  ExpectFailure("optional_double: \"hello\"\n",
+                "Expected double, got: \"hello\"", 1, 18);
+  ExpectFailure("optional_double: true\n", "Expected double, got: true", 1, 18);
+  ExpectFailure("optional_double: !\n", "Expected double, got: !", 1, 18);
+  ExpectFailure("optional_double {\n  \n}\n", "Expected \":\", found \"{\".", 1,
+                17);
+
+  // Invalid values for a signed integer field.
+  ExpectFailure("optional_int32: \"hello\"\n",
+                "Expected integer, got: \"hello\"", 1, 17);
+  ExpectFailure("optional_int32: true\n", "Expected integer, got: true", 1, 17);
+  ExpectFailure("optional_int32: 4.5\n", "Expected integer, got: 4.5", 1, 17);
+  ExpectFailure("optional_int32: !\n", "Expected integer, got: !", 1, 17);
+  ExpectFailure("optional_int32 {\n \n}\n", "Expected \":\", found \"{\".", 1,
+                16);
+  ExpectFailure("optional_int32: 0x80000000\n",
+                "Integer out of range (0x80000000)", 1, 17);
+  ExpectFailure("optional_int64: 0x8000000000000000\n",
+                "Integer out of range (0x8000000000000000)", 1, 17);
+  ExpectFailure("optional_int32: -0x80000001\n",
+                "Integer out of range (0x80000001)", 1, 18);
+  ExpectFailure("optional_int64: -0x8000000000000001\n",
+                "Integer out of range (0x8000000000000001)", 1, 18);
+
+  // Invalid values for an unsigned integer field.
+  ExpectFailure("optional_uint64: \"hello\"\n",
+                "Expected integer, got: \"hello\"", 1, 18);
+  ExpectFailure("optional_uint64: true\n", "Expected integer, got: true", 1,
+                18);
+  ExpectFailure("optional_uint64: 4.5\n", "Expected integer, got: 4.5", 1, 18);
+  ExpectFailure("optional_uint64: -5\n", "Expected integer, got: -", 1, 18);
+  ExpectFailure("optional_uint64: !\n", "Expected integer, got: !", 1, 18);
+  ExpectFailure("optional_uint64 {\n \n}\n", "Expected \":\", found \"{\".", 1,
+                17);
+  ExpectFailure("optional_uint32: 0x100000000\n",
+                "Integer out of range (0x100000000)", 1, 18);
+  ExpectFailure("optional_uint64: 0x10000000000000000\n",
+                "Integer out of range (0x10000000000000000)", 1, 18);
+
+  // Invalid values for a boolean field.
+  ExpectFailure("optional_bool: \"hello\"\n",
+                "Expected identifier, got: \"hello\"", 1, 16);
+  ExpectFailure("optional_bool: 5\n", "Integer out of range (5)", 1, 16);
+  ExpectFailure("optional_bool: -7.5\n", "Expected identifier, got: -", 1, 16);
+  ExpectFailure("optional_bool: !\n", "Expected identifier, got: !", 1, 16);
+
+  ExpectFailure(
+      "optional_bool: meh\n",
+      "Invalid value for boolean field \"optional_bool\". Value: \"meh\".", 2,
+      1);
+
+  ExpectFailure("optional_bool {\n \n}\n", "Expected \":\", found \"{\".", 1,
+                15);
+
+  // Invalid values for a string field.
+  ExpectFailure("optional_string: true\n", "Expected string, got: true", 1, 18);
+  ExpectFailure("optional_string: 5\n", "Expected string, got: 5", 1, 18);
+  ExpectFailure("optional_string: -7.5\n", "Expected string, got: -", 1, 18);
+  ExpectFailure("optional_string: !\n", "Expected string, got: !", 1, 18);
+  ExpectFailure("optional_string {\n \n}\n", "Expected \":\", found \"{\".", 1,
+                17);
+
+  // Invalid values for an enumeration field.
+  ExpectFailure("optional_nested_enum: \"hello\"\n",
+                "Expected integer or identifier, got: \"hello\"", 1, 23);
+
+  // Valid token, but enum value is not defined.
+  ExpectFailure("optional_nested_enum: 5\n",
+                "Unknown enumeration value of \"5\" for field "
+                "\"optional_nested_enum\".",
+                2, 1);
+  // We consume the negative sign, so the error position starts one character
+  // later.
+  ExpectFailure("optional_nested_enum: -7.5\n", "Expected integer, got: 7.5", 1,
+                24);
+  ExpectFailure("optional_nested_enum: !\n",
+                "Expected integer or identifier, got: !", 1, 23);
+
+  ExpectFailure("optional_nested_enum: grah\n",
+                "Unknown enumeration value of \"grah\" for field "
+                "\"optional_nested_enum\".",
+                2, 1);
+
+  ExpectFailure("optional_nested_enum {\n \n}\n",
+                "Expected \":\", found \"{\".", 1, 22);
+}
+
+TEST_F(TextFormatParserTest, MessageDelimiters) {
+  // Non-matching delimiters.
+  ExpectFailure("OptionalGroup <\n \n}\n", "Expected \">\", found \"}\".", 3,
+                1);
+
+  // Invalid delimiters.
+  ExpectFailure("OptionalGroup [\n \n]\n", "Expected \"{\", found \"[\".", 1,
+                15);
+
+  // Unending message.
+  ExpectFailure("optional_nested_message {\n \nbb: 118\n",
+                "Expected identifier, got: ", 4, 1);
+}
+
+TEST_F(TextFormatParserTest, UnknownExtension) {
+  // Non-matching delimiters.
+  ExpectFailure("[blahblah]: 123",
+                "Extension \"blahblah\" is not defined or is not an "
+                "extension of \"protobuf_unittest.TestAllTypes\".",
+                1, 11);
+}
+
+TEST_F(TextFormatParserTest, MissingRequired) {
+  unittest::TestRequired message;
+  ExpectFailure("a: 1", "Message missing required fields: b, c", 0, 1,
+                &message);
+}
+
+TEST_F(TextFormatParserTest, ParseDuplicateRequired) {
+  unittest::TestRequired message;
+  ExpectFailure("a: 1 b: 2 c: 3 a: 1",
+                "Non-repeated field \"a\" is specified multiple times.", 1, 17,
+                &message);
+}
+
+TEST_F(TextFormatParserTest, ParseDuplicateOptional) {
+  unittest::ForeignMessage message;
+  ExpectFailure("c: 1 c: 2",
+                "Non-repeated field \"c\" is specified multiple times.", 1, 7,
+                &message);
+}
+
+TEST_F(TextFormatParserTest, MergeDuplicateRequired) {
+  unittest::TestRequired message;
+  TextFormat::Parser parser;
+  EXPECT_TRUE(parser.MergeFromString("a: 1 b: 2 c: 3 a: 4", &message));
+  EXPECT_EQ(4, message.a());
+}
+
+TEST_F(TextFormatParserTest, MergeDuplicateOptional) {
+  unittest::ForeignMessage message;
+  TextFormat::Parser parser;
+  EXPECT_TRUE(parser.MergeFromString("c: 1 c: 2", &message));
+  EXPECT_EQ(2, message.c());
+}
+
+TEST_F(TextFormatParserTest, ExplicitDelimiters) {
+  unittest::TestRequired message;
+  EXPECT_TRUE(TextFormat::ParseFromString("a:1,b:2;c:3", &message));
+  EXPECT_EQ(1, message.a());
+  EXPECT_EQ(2, message.b());
+  EXPECT_EQ(3, message.c());
+}
+
+TEST_F(TextFormatParserTest, PrintErrorsToStderr) {
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog log;
+    unittest::TestAllTypes proto;
+    EXPECT_FALSE(TextFormat::ParseFromString("no_such_field: 1", &proto));
+    errors = log.GetMessages(ERROR);
+  }
+
+  ASSERT_EQ(1, errors.size());
+  EXPECT_EQ(
+      "Error parsing text-format protobuf_unittest.TestAllTypes: "
+      "1:14: Message type \"protobuf_unittest.TestAllTypes\" has no field "
+      "named \"no_such_field\".",
+      errors[0]);
+}
+
+TEST_F(TextFormatParserTest, FailsOnTokenizationError) {
+  std::vector<std::string> errors;
+
+  {
+    ScopedMemoryLog log;
+    unittest::TestAllTypes proto;
+    EXPECT_FALSE(TextFormat::ParseFromString("\020", &proto));
+    errors = log.GetMessages(ERROR);
+  }
+
+  ASSERT_EQ(1, errors.size());
+  EXPECT_EQ(
+      "Error parsing text-format protobuf_unittest.TestAllTypes: "
+      "1:1: Invalid control characters encountered in text.",
+      errors[0]);
+}
+
+TEST_F(TextFormatParserTest, ParseDeprecatedField) {
+  unittest::TestDeprecatedFields message;
+  ExpectMessage("deprecated_int32: 42",
+                "WARNING:text format contains deprecated field "
+                "\"deprecated_int32\"",
+                1, 21, &message, true);
+}
+
+TEST_F(TextFormatParserTest, SetRecursionLimit) {
+  const char* format = "child: { $0 }";
+  std::string input;
+  for (int i = 0; i < 100; ++i) input = strings::Substitute(format, input);
+
+  unittest::NestedTestAllTypes message;
+  ExpectSuccessAndTree(input, &message, nullptr);
+
+  input = strings::Substitute(format, input);
+  parser_.SetRecursionLimit(100);
+  ExpectMessage(input,
+                "Message is too deep, the parser exceeded the configured "
+                "recursion limit of 100.",
+                1, 908, &message, false);
+
+  parser_.SetRecursionLimit(101);
+  ExpectSuccessAndTree(input, &message, nullptr);
+}
+
+TEST_F(TextFormatParserTest, SetRecursionLimitUnknownFieldValue) {
+  const char* format = "[$0]";
+  std::string input = "\"test_value\"";
+  for (int i = 0; i < 99; ++i) input = strings::Substitute(format, input);
+  std::string not_deep_input = StrCat("unknown_nested_array: ", input);
+
+  parser_.AllowUnknownField(true);
+  parser_.SetRecursionLimit(100);
+
+  unittest::NestedTestAllTypes message;
+  ExpectSuccessAndTree(not_deep_input, &message, nullptr);
+
+  input = strings::Substitute(format, input);
+  std::string deep_input = StrCat("unknown_nested_array: ", input);
+  ExpectMessage(
+      deep_input,
+      "WARNING:Message type \"protobuf_unittest.NestedTestAllTypes\" has no "
+      "field named \"unknown_nested_array\".\n1:123: Message is too deep, the "
+      "parser exceeded the configured recursion limit of 100.",
+      1, 21, &message, false);
+
+  parser_.SetRecursionLimit(101);
+  ExpectSuccessAndTree(deep_input, &message, nullptr);
+}
+
+TEST_F(TextFormatParserTest, SetRecursionLimitUnknownFieldMessage) {
+  const char* format = "unknown_child: { $0 }";
+  std::string input;
+  for (int i = 0; i < 100; ++i) input = strings::Substitute(format, input);
+
+  parser_.AllowUnknownField(true);
+  parser_.SetRecursionLimit(100);
+
+  unittest::NestedTestAllTypes message;
+  ExpectSuccessAndTree(input, &message, nullptr);
+
+  input = strings::Substitute(format, input);
+  ExpectMessage(
+      input,
+      "WARNING:Message type \"protobuf_unittest.NestedTestAllTypes\" has no "
+      "field named \"unknown_child\".\n1:1716: Message is too deep, the parser "
+      "exceeded the configured recursion limit of 100.",
+      1, 14, &message, false);
+
+  parser_.SetRecursionLimit(101);
+  ExpectSuccessAndTree(input, &message, nullptr);
+}
+
+TEST_F(TextFormatParserTest, ParseAnyFieldWithAdditionalWhiteSpaces) {
+  Any any;
+  std::string parse_string =
+      "[type.googleapis.com/protobuf_unittest.TestAllTypes] \t :  \t {\n"
+      "  optional_int32: 321\n"
+      "  optional_string: \"teststr0\"\n"
+      "}\n";
+
+  ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &any));
+
+  TextFormat::Printer printer;
+  printer.SetExpandAny(true);
+  std::string text;
+  ASSERT_TRUE(printer.PrintToString(any, &text));
+  EXPECT_EQ(text,
+            "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
+            "  optional_int32: 321\n"
+            "  optional_string: \"teststr0\"\n"
+            "}\n");
+}
+
+TEST_F(TextFormatParserTest, ParseExtensionFieldWithAdditionalWhiteSpaces) {
+  unittest::TestAllExtensions proto;
+  std::string parse_string =
+      "[protobuf_unittest.optional_int32_extension]   : \t 101\n"
+      "[protobuf_unittest.optional_int64_extension] \t : 102\n";
+
+  ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto));
+
+  TextFormat::Printer printer;
+  std::string text;
+  ASSERT_TRUE(printer.PrintToString(proto, &text));
+  EXPECT_EQ(text,
+            "[protobuf_unittest.optional_int32_extension]: 101\n"
+            "[protobuf_unittest.optional_int64_extension]: 102\n");
+}
+
+TEST_F(TextFormatParserTest, ParseNormalFieldWithAdditionalWhiteSpaces) {
+  unittest::TestAllTypes proto;
+  std::string parse_string =
+      "repeated_int32  : \t 1\n"
+      "repeated_int32: 2\n"
+      "repeated_nested_message: {\n"
+      "  bb: 3\n"
+      "}\n"
+      "repeated_nested_message  : \t {\n"
+      "  bb: 4\n"
+      "}\n"
+      "repeated_nested_message     {\n"
+      "  bb: 5\n"
+      "}\n";
+
+  ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto));
+
+  TextFormat::Printer printer;
+  std::string text;
+  ASSERT_TRUE(printer.PrintToString(proto, &text));
+  EXPECT_EQ(text,
+            "repeated_int32: 1\n"
+            "repeated_int32: 2\n"
+            "repeated_nested_message {\n"
+            "  bb: 3\n"
+            "}\n"
+            "repeated_nested_message {\n"
+            "  bb: 4\n"
+            "}\n"
+            "repeated_nested_message {\n"
+            "  bb: 5\n"
+            "}\n");
+}
+
+TEST_F(TextFormatParserTest, ParseSkippedFieldWithAdditionalWhiteSpaces) {
+  protobuf_unittest::TestAllTypes proto;
+  TextFormat::Parser parser;
+  parser.AllowUnknownField(true);
+  EXPECT_TRUE(
+      parser.ParseFromString("optional_int32: 321\n"
+                             "unknown_field1   : \t 12345\n"
+                             "[somewhere.unknown_extension1]   {\n"
+                             "  unknown_field2 \t :   12345\n"
+                             "}\n"
+                             "[somewhere.unknown_extension2]    : \t {\n"
+                             "  unknown_field3     \t :   12345\n"
+                             "  [somewhere.unknown_extension3]    \t :   {\n"
+                             "    unknown_field4:   10\n"
+                             "  }\n"
+                             "  [somewhere.unknown_extension4] \t {\n"
+                             "  }\n"
+                             "}\n",
+                             &proto));
+  std::string text;
+  TextFormat::Printer printer;
+  ASSERT_TRUE(printer.PrintToString(proto, &text));
+  EXPECT_EQ(text, "optional_int32: 321\n");
+}
+
+class TextFormatMessageSetTest : public testing::Test {
+ protected:
+  static const char proto_text_format_[];
+};
+const char TextFormatMessageSetTest::proto_text_format_[] =
+    "message_set {\n"
+    "  [protobuf_unittest.TestMessageSetExtension1] {\n"
+    "    i: 23\n"
+    "  }\n"
+    "  [protobuf_unittest.TestMessageSetExtension2] {\n"
+    "    str: \"foo\"\n"
+    "  }\n"
+    "}\n";
+
+TEST_F(TextFormatMessageSetTest, Serialize) {
+  protobuf_unittest::TestMessageSetContainer proto;
+  protobuf_unittest::TestMessageSetExtension1* item_a =
+      proto.mutable_message_set()->MutableExtension(
+          protobuf_unittest::TestMessageSetExtension1::message_set_extension);
+  item_a->set_i(23);
+  protobuf_unittest::TestMessageSetExtension2* item_b =
+      proto.mutable_message_set()->MutableExtension(
+          protobuf_unittest::TestMessageSetExtension2::message_set_extension);
+  item_b->set_str("foo");
+  std::string actual_proto_text_format;
+  TextFormat::PrintToString(proto, &actual_proto_text_format);
+  EXPECT_EQ(proto_text_format_, actual_proto_text_format);
+}
+
+TEST_F(TextFormatMessageSetTest, Deserialize) {
+  protobuf_unittest::TestMessageSetContainer proto;
+  ASSERT_TRUE(TextFormat::ParseFromString(proto_text_format_, &proto));
+  EXPECT_EQ(
+      23,
+      proto.message_set()
+          .GetExtension(
+              protobuf_unittest::TestMessageSetExtension1::message_set_extension)
+          .i());
+  EXPECT_EQ(
+      "foo",
+      proto.message_set()
+          .GetExtension(
+              protobuf_unittest::TestMessageSetExtension2::message_set_extension)
+          .str());
+
+  // Ensure that these are the only entries present.
+  std::vector<const FieldDescriptor*> descriptors;
+  proto.message_set().GetReflection()->ListFields(proto.message_set(),
+                                                  &descriptors);
+  EXPECT_EQ(2, descriptors.size());
+}
+
+TEST(TextFormatUnknownFieldTest, TestUnknownField) {
+  protobuf_unittest::TestAllTypes proto;
+  TextFormat::Parser parser;
+  // Unknown field is not permitted by default.
+  EXPECT_FALSE(parser.ParseFromString("unknown_field: 12345", &proto));
+  EXPECT_FALSE(parser.ParseFromString("12345678: 12345", &proto));
+
+  parser.AllowUnknownField(true);
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: 12345", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: -12345", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: 1.2345", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: -1.2345", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: 1.2345f", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: -1.2345f", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: inf", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: -inf", &proto));
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: TYPE_STRING", &proto));
+  EXPECT_TRUE(
+      parser.ParseFromString("unknown_field: \"string value\"", &proto));
+  // Invalid field value
+  EXPECT_FALSE(parser.ParseFromString("unknown_field: -TYPE_STRING", &proto));
+  // Two or more unknown fields
+  EXPECT_TRUE(
+      parser.ParseFromString("unknown_field1: TYPE_STRING\n"
+                             "unknown_field2: 12345",
+                             &proto));
+  // Unknown nested message
+  EXPECT_TRUE(
+      parser.ParseFromString("unknown_message1: {}\n"
+                             "unknown_message2 {\n"
+                             "  unknown_field: 12345\n"
+                             "}\n"
+                             "unknown_message3 <\n"
+                             "  unknown_nested_message {\n"
+                             "    unknown_field: 12345\n"
+                             "  }\n"
+                             ">",
+                             &proto));
+  // Unmatched delimiters for message body
+  EXPECT_FALSE(parser.ParseFromString("unknown_message: {>", &proto));
+  // Unknown extension
+  EXPECT_TRUE(
+      parser.ParseFromString("[somewhere.unknown_extension1]: 12345\n"
+                             "[somewhere.unknown_extension2] {\n"
+                             "  unknown_field: 12345\n"
+                             "}",
+                             &proto));
+  // Unknown fields between known fields
+  ASSERT_TRUE(
+      parser.ParseFromString("optional_int32: 1\n"
+                             "unknown_field: 12345\n"
+                             "optional_string: \"string\"\n"
+                             "unknown_message { unknown: 0 }\n"
+                             "optional_nested_message { bb: 2 }",
+                             &proto));
+  EXPECT_EQ(1, proto.optional_int32());
+  EXPECT_EQ("string", proto.optional_string());
+  EXPECT_EQ(2, proto.optional_nested_message().bb());
+
+  // Unknown field with numeric tag number instead of identifier.
+  EXPECT_TRUE(parser.ParseFromString("12345678: 12345", &proto));
+
+  // Nested unknown extensions.
+  EXPECT_TRUE(
+      parser.ParseFromString("[test.extension1] <\n"
+                             "  unknown_nested_message <\n"
+                             "    [test.extension2] <\n"
+                             "      unknown_field: 12345\n"
+                             "    >\n"
+                             "  >\n"
+                             ">",
+                             &proto));
+  EXPECT_TRUE(
+      parser.ParseFromString("[test.extension1] {\n"
+                             "  unknown_nested_message {\n"
+                             "    [test.extension2] {\n"
+                             "      unknown_field: 12345\n"
+                             "    }\n"
+                             "  }\n"
+                             "}",
+                             &proto));
+  EXPECT_TRUE(
+      parser.ParseFromString("[test.extension1] <\n"
+                             "  some_unknown_fields: <\n"
+                             "    unknown_field: 12345\n"
+                             "  >\n"
+                             ">",
+                             &proto));
+  EXPECT_TRUE(
+      parser.ParseFromString("[test.extension1] {\n"
+                             "  some_unknown_fields: {\n"
+                             "    unknown_field: 12345\n"
+                             "  }\n"
+                             "}",
+                             &proto));
+
+  // Unknown field with compact repetition.
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: [1, 2]", &proto));
+  // Unknown field with compact repetition of some unknown enum.
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: [VAL1, VAL2]", &proto));
+  // Unknown field with compact repetition with sub-message.
+  EXPECT_TRUE(parser.ParseFromString("unknown_field: [{a:1}, <b:2>]", &proto));
+}
+
+TEST(TextFormatUnknownFieldTest, TestAnyInUnknownField) {
+  protobuf_unittest::TestAllTypes proto;
+  TextFormat::Parser parser;
+  parser.AllowUnknownField(true);
+  EXPECT_TRUE(
+      parser.ParseFromString("unknown {\n"
+                             "  [type.googleapis.com/foo.bar] {\n"
+                             "  }\n"
+                             "}",
+                             &proto));
+}
+
+TEST(TextFormatUnknownFieldTest, TestUnknownExtension) {
+  protobuf_unittest::TestAllTypes proto;
+  TextFormat::Parser parser;
+  std::string message_with_ext =
+      "[test.extension1] {\n"
+      "  some_unknown_fields: {\n"
+      "    unknown_field: 12345\n"
+      "  }\n"
+      "}";
+  // Unknown extensions are not permitted by default.
+  EXPECT_FALSE(parser.ParseFromString(message_with_ext, &proto));
+  // AllowUnknownField implies AllowUnknownExtension.
+  parser.AllowUnknownField(true);
+  EXPECT_TRUE(parser.ParseFromString(message_with_ext, &proto));
+
+  parser.AllowUnknownField(false);
+  EXPECT_FALSE(parser.ParseFromString(message_with_ext, &proto));
+  parser.AllowUnknownExtension(true);
+  EXPECT_TRUE(parser.ParseFromString(message_with_ext, &proto));
+  // Unknown fields are still not accepted.
+  EXPECT_FALSE(parser.ParseFromString("unknown_field: 1", &proto));
+}
+
+TEST(TextFormatFloatingPointTest, PreservesNegative0) {
+  proto3_unittest::TestAllTypes in_message;
+  in_message.set_optional_float(-0.0f);
+  in_message.set_optional_double(-0.0);
+  TextFormat::Printer printer;
+  std::string serialized;
+  EXPECT_TRUE(printer.PrintToString(in_message, &serialized));
+  proto3_unittest::TestAllTypes out_message;
+  TextFormat::Parser parser;
+  EXPECT_TRUE(parser.ParseFromString(serialized, &out_message));
+  EXPECT_EQ(in_message.optional_float(), out_message.optional_float());
+  EXPECT_EQ(std::signbit(in_message.optional_float()),
+            std::signbit(out_message.optional_float()));
+  EXPECT_EQ(in_message.optional_double(), out_message.optional_double());
+  EXPECT_EQ(std::signbit(in_message.optional_double()),
+            std::signbit(out_message.optional_double()));
+}
+
+}  // namespace text_format_unittest
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
new file mode 100644
index 0000000..728a004
--- /dev/null
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -0,0 +1,307 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#include <google/protobuf/timestamp.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Timestamp::Timestamp(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.seconds_)*/int64_t{0}
+  , /*decltype(_impl_.nanos_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct TimestampDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR TimestampDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~TimestampDefaultTypeInternal() {}
+  union {
+    Timestamp _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 TimestampDefaultTypeInternal _Timestamp_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, _impl_.seconds_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, _impl_.nanos_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Timestamp)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Timestamp_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\037google/protobuf/timestamp.proto\022\017googl"
+  "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
+  "\022\r\n\005nanos\030\002 \001(\005B\205\001\n\023com.google.protobufB"
+  "\016TimestampProtoP\001Z2google.golang.org/pro"
+  "tobuf/types/known/timestamppb\370\001\001\242\002\003GPB\252\002"
+  "\036Google.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
+    false, false, 239, descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto,
+    "google/protobuf/timestamp.proto",
+    &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftimestamp_2eproto(&descriptor_table_google_2fprotobuf_2ftimestamp_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Timestamp::_Internal {
+ public:
+};
+
+Timestamp::Timestamp(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp)
+}
+Timestamp::Timestamp(const Timestamp& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Timestamp* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){}
+    , decltype(_impl_.nanos_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.seconds_, &from._impl_.seconds_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.nanos_) -
+    reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Timestamp)
+}
+
+inline void Timestamp::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){int64_t{0}}
+    , decltype(_impl_.nanos_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Timestamp::~Timestamp() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Timestamp)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Timestamp::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Timestamp::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Timestamp::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Timestamp)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  ::memset(&_impl_.seconds_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.nanos_) -
+      reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Timestamp::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int64 seconds = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.seconds_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 nanos = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _impl_.nanos_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Timestamp::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Timestamp)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Timestamp)
+  return target;
+}
+
+size_t Timestamp::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Timestamp)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Timestamp::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Timestamp::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Timestamp::GetClassData() const { return &_class_data_; }
+
+
+void Timestamp::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Timestamp*>(&to_msg);
+  auto& from = static_cast<const Timestamp&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Timestamp)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_seconds() != 0) {
+    _this->_internal_set_seconds(from._internal_seconds());
+  }
+  if (from._internal_nanos() != 0) {
+    _this->_internal_set_nanos(from._internal_nanos());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Timestamp::CopyFrom(const Timestamp& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Timestamp)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Timestamp::IsInitialized() const {
+  return true;
+}
+
+void Timestamp::InternalSwap(Timestamp* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Timestamp, _impl_.nanos_)
+      + sizeof(Timestamp::_impl_.nanos_)
+      - PROTOBUF_FIELD_OFFSET(Timestamp, _impl_.seconds_)>(
+          reinterpret_cast<char*>(&_impl_.seconds_),
+          reinterpret_cast<char*>(&other->_impl_.seconds_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Timestamp::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Timestamp*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Timestamp >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Timestamp >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
new file mode 100644
index 0000000..e437d11
--- /dev/null
+++ b/src/google/protobuf/timestamp.pb.h
@@ -0,0 +1,278 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftimestamp_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftimestamp_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ftimestamp_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ftimestamp_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Timestamp;
+struct TimestampDefaultTypeInternal;
+PROTOBUF_EXPORT extern TimestampDefaultTypeInternal _Timestamp_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Timestamp* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Timestamp>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Timestamp final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Timestamp) */ {
+ public:
+  inline Timestamp() : Timestamp(nullptr) {}
+  ~Timestamp() override;
+  explicit PROTOBUF_CONSTEXPR Timestamp(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Timestamp(const Timestamp& from);
+  Timestamp(Timestamp&& from) noexcept
+    : Timestamp() {
+    *this = ::std::move(from);
+  }
+
+  inline Timestamp& operator=(const Timestamp& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Timestamp& operator=(Timestamp&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Timestamp& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Timestamp* internal_default_instance() {
+    return reinterpret_cast<const Timestamp*>(
+               &_Timestamp_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Timestamp& a, Timestamp& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Timestamp* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Timestamp* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Timestamp* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Timestamp>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Timestamp& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Timestamp& from) {
+    Timestamp::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Timestamp* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Timestamp";
+  }
+  protected:
+  explicit Timestamp(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kSecondsFieldNumber = 1,
+    kNanosFieldNumber = 2,
+  };
+  // int64 seconds = 1;
+  void clear_seconds();
+  int64_t seconds() const;
+  void set_seconds(int64_t value);
+  private:
+  int64_t _internal_seconds() const;
+  void _internal_set_seconds(int64_t value);
+  public:
+
+  // int32 nanos = 2;
+  void clear_nanos();
+  int32_t nanos() const;
+  void set_nanos(int32_t value);
+  private:
+  int32_t _internal_nanos() const;
+  void _internal_set_nanos(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Timestamp)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int64_t seconds_;
+    int32_t nanos_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftimestamp_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Timestamp
+
+// int64 seconds = 1;
+inline void Timestamp::clear_seconds() {
+  _impl_.seconds_ = int64_t{0};
+}
+inline int64_t Timestamp::_internal_seconds() const {
+  return _impl_.seconds_;
+}
+inline int64_t Timestamp::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.seconds)
+  return _internal_seconds();
+}
+inline void Timestamp::_internal_set_seconds(int64_t value) {
+  
+  _impl_.seconds_ = value;
+}
+inline void Timestamp::set_seconds(int64_t value) {
+  _internal_set_seconds(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.seconds)
+}
+
+// int32 nanos = 2;
+inline void Timestamp::clear_nanos() {
+  _impl_.nanos_ = 0;
+}
+inline int32_t Timestamp::_internal_nanos() const {
+  return _impl_.nanos_;
+}
+inline int32_t Timestamp::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.nanos)
+  return _internal_nanos();
+}
+inline void Timestamp::_internal_set_nanos(int32_t value) {
+  
+  _impl_.nanos_ = value;
+}
+inline void Timestamp::set_nanos(int32_t value) {
+  _internal_set_nanos(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.nanos)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftimestamp_2eproto
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
new file mode 100644
index 0000000..3b2df6d
--- /dev/null
+++ b/src/google/protobuf/timestamp.proto
@@ -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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/timestamppb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// A Timestamp represents a point in time independent of any time zone or local
+// calendar, encoded as a count of seconds and fractions of seconds at
+// nanosecond resolution. The count is relative to an epoch at UTC midnight on
+// January 1, 1970, in the proleptic Gregorian calendar which extends the
+// Gregorian calendar backwards to year one.
+//
+// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
+// second table is needed for interpretation, using a [24-hour linear
+// smear](https://developers.google.com/time/smear).
+//
+// The 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](https://www.ietf.org/rfc/rfc3339.txt) date strings.
+//
+// # Examples
+//
+// 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 Java `Instant.now()`.
+//
+//     Instant now = Instant.now();
+//
+//     Timestamp timestamp =
+//         Timestamp.newBuilder().setSeconds(now.getEpochSecond())
+//             .setNanos(now.getNano()).build();
+//
+//
+// Example 6: Compute Timestamp from current time in Python.
+//
+//     timestamp = Timestamp()
+//     timestamp.GetCurrentTime()
+//
+// # JSON Mapping
+//
+// In JSON format, the Timestamp type is encoded as a string in the
+// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+// where {year} is always expressed using four digits while {month}, {day},
+// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+// is required. A proto3 JSON serializer should always use UTC (as indicated by
+// "Z") when printing the Timestamp type and a proto3 JSON parser should be
+// able to accept both UTC and other timezones (as indicated by an offset).
+//
+// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+// 01:30 UTC on January 15, 2017.
+//
+// In JavaScript, one can convert a Date object to this format using the
+// standard
+// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+// method. In Python, a standard `datetime.datetime` object can be converted
+// to this format using
+// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+// the Joda Time's [`ISODateTimeFormat.dateTime()`](
+// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
+// ) to obtain a formatter capable of generating timestamps in this format.
+//
+//
+message Timestamp {
+  // Represents seconds of UTC time since Unix epoch
+  // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+  // 9999-12-31T23:59:59Z inclusive.
+  int64 seconds = 1;
+
+  // Non-negative fractions of a second at nanosecond resolution. Negative
+  // second values with fractions must still have non-negative nanos values
+  // that count forward in time. Must be from 0 to 999,999,999
+  // inclusive.
+  int32 nanos = 2;
+}
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
new file mode 100644
index 0000000..e29bbb8
--- /dev/null
+++ b/src/google/protobuf/type.pb.cc
@@ -0,0 +1,2157 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#include <google/protobuf/type.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Type::Type(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.fields_)*/{}
+  , /*decltype(_impl_.oneofs_)*/{}
+  , /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.source_context_)*/nullptr
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct TypeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR TypeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~TypeDefaultTypeInternal() {}
+  union {
+    Type _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 TypeDefaultTypeInternal _Type_default_instance_;
+PROTOBUF_CONSTEXPR Field::Field(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.json_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.default_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.kind_)*/0
+  , /*decltype(_impl_.cardinality_)*/0
+  , /*decltype(_impl_.number_)*/0
+  , /*decltype(_impl_.oneof_index_)*/0
+  , /*decltype(_impl_.packed_)*/false
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FieldDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldDefaultTypeInternal() {}
+  union {
+    Field _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldDefaultTypeInternal _Field_default_instance_;
+PROTOBUF_CONSTEXPR Enum::Enum(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.enumvalue_)*/{}
+  , /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.source_context_)*/nullptr
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct EnumDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumDefaultTypeInternal() {}
+  union {
+    Enum _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDefaultTypeInternal _Enum_default_instance_;
+PROTOBUF_CONSTEXPR EnumValue::EnumValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.number_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct EnumValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumValueDefaultTypeInternal() {}
+  union {
+    EnumValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueDefaultTypeInternal _EnumValue_default_instance_;
+PROTOBUF_CONSTEXPR Option::Option(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.value_)*/nullptr
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct OptionDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR OptionDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~OptionDefaultTypeInternal() {}
+  union {
+    Option _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OptionDefaultTypeInternal _Option_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ftype_2eproto[5];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[3];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2ftype_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.fields_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.oneofs_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.source_context_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.kind_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.cardinality_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.oneof_index_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.packed_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.json_name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.default_value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.enumvalue_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.source_context_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _impl_.options_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, _impl_.value_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Type)},
+  { 12, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Field)},
+  { 28, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Enum)},
+  { 39, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValue)},
+  { 48, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Option)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Type_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Field_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Enum_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Option_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\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\001B{\n\023com.google.protob"
+  "ufB\tTypeProtoP\001Z-google.golang.org/proto"
+  "buf/types/known/typepb\370\001\001\242\002\003GPB\252\002\036Google"
+  ".Protobuf.WellKnownTypesb\006proto3"
+  ;
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2ftype_2eproto_deps[2] = {
+  &::descriptor_table_google_2fprotobuf_2fany_2eproto,
+  &::descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto,
+};
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ftype_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
+    false, false, 1592, descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
+    "google/protobuf/type.proto",
+    &descriptor_table_google_2fprotobuf_2ftype_2eproto_once, descriptor_table_google_2fprotobuf_2ftype_2eproto_deps, 2, 5,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftype_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ftype_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ftype_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2ftype_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftype_2eproto(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Kind_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[0];
+}
+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 (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr Field_Kind Field::TYPE_UNKNOWN;
+constexpr Field_Kind Field::TYPE_DOUBLE;
+constexpr Field_Kind Field::TYPE_FLOAT;
+constexpr Field_Kind Field::TYPE_INT64;
+constexpr Field_Kind Field::TYPE_UINT64;
+constexpr Field_Kind Field::TYPE_INT32;
+constexpr Field_Kind Field::TYPE_FIXED64;
+constexpr Field_Kind Field::TYPE_FIXED32;
+constexpr Field_Kind Field::TYPE_BOOL;
+constexpr Field_Kind Field::TYPE_STRING;
+constexpr Field_Kind Field::TYPE_GROUP;
+constexpr Field_Kind Field::TYPE_MESSAGE;
+constexpr Field_Kind Field::TYPE_BYTES;
+constexpr Field_Kind Field::TYPE_UINT32;
+constexpr Field_Kind Field::TYPE_ENUM;
+constexpr Field_Kind Field::TYPE_SFIXED32;
+constexpr Field_Kind Field::TYPE_SFIXED64;
+constexpr Field_Kind Field::TYPE_SINT32;
+constexpr Field_Kind Field::TYPE_SINT64;
+constexpr Field_Kind Field::Kind_MIN;
+constexpr Field_Kind Field::Kind_MAX;
+constexpr int Field::Kind_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Cardinality_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[1];
+}
+bool Field_Cardinality_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr Field_Cardinality Field::CARDINALITY_UNKNOWN;
+constexpr Field_Cardinality Field::CARDINALITY_OPTIONAL;
+constexpr Field_Cardinality Field::CARDINALITY_REQUIRED;
+constexpr Field_Cardinality Field::CARDINALITY_REPEATED;
+constexpr Field_Cardinality Field::Cardinality_MIN;
+constexpr Field_Cardinality Field::Cardinality_MAX;
+constexpr int Field::Cardinality_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Syntax_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[2];
+}
+bool Syntax_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// ===================================================================
+
+class Type::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context(const Type* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::SourceContext&
+Type::_Internal::source_context(const Type* msg) {
+  return *msg->_impl_.source_context_;
+}
+void Type::clear_source_context() {
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+}
+Type::Type(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Type)
+}
+Type::Type(const Type& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Type* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.fields_){from._impl_.fields_}
+    , decltype(_impl_.oneofs_){from._impl_.oneofs_}
+    , decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
+  }
+  _this->_impl_.syntax_ = from._impl_.syntax_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Type)
+}
+
+inline void Type::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.fields_){arena}
+    , decltype(_impl_.oneofs_){arena}
+    , decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Type::~Type() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Type)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Type::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.fields_.~RepeatedPtrField();
+  _impl_.oneofs_.~RepeatedPtrField();
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.source_context_;
+}
+
+void Type::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Type::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Type)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.fields_.Clear();
+  _impl_.oneofs_.Clear();
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+  _impl_.syntax_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Type::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Field fields = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_fields(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string oneofs = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_oneofs();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.oneofs"));
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.SourceContext source_context = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 48)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Type::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.Field fields = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_fields_size()); i < n; i++) {
+    const auto& repfield = this->_internal_fields(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated string oneofs = 3;
+  for (int i = 0, n = this->_internal_oneofs_size(); i < n; i++) {
+    const auto& s = this->_internal_oneofs(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.oneofs");
+    target = stream->WriteString(3, s, target);
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(5, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 6;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      6, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Type)
+  return target;
+}
+
+size_t Type::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Type)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Field fields = 2;
+  total_size += 1UL * this->_internal_fields_size();
+  for (const auto& msg : this->_impl_.fields_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated string oneofs = 3;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.oneofs_.size());
+  for (int i = 0, n = _impl_.oneofs_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.oneofs_.Get(i));
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.source_context_);
+  }
+
+  // .google.protobuf.Syntax syntax = 6;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Type::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Type::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Type::GetClassData() const { return &_class_data_; }
+
+
+void Type::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Type*>(&to_msg);
+  auto& from = static_cast<const Type&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Type)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.fields_.MergeFrom(from._impl_.fields_);
+  _this->_impl_.oneofs_.MergeFrom(from._impl_.oneofs_);
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
+        from._internal_source_context());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Type::CopyFrom(const Type& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Type)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Type::IsInitialized() const {
+  return true;
+}
+
+void Type::InternalSwap(Type* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.fields_.InternalSwap(&other->_impl_.fields_);
+  _impl_.oneofs_.InternalSwap(&other->_impl_.oneofs_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Type, _impl_.syntax_)
+      + sizeof(Type::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Type, _impl_.source_context_)>(
+          reinterpret_cast<char*>(&_impl_.source_context_),
+          reinterpret_cast<char*>(&other->_impl_.source_context_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Type::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[0]);
+}
+
+// ===================================================================
+
+class Field::_Internal {
+ public:
+};
+
+Field::Field(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Field)
+}
+Field::Field(const Field& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Field* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.type_url_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.kind_){}
+    , decltype(_impl_.cardinality_){}
+    , decltype(_impl_.number_){}
+    , decltype(_impl_.oneof_index_){}
+    , decltype(_impl_.packed_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_type_url().empty()) {
+    _this->_impl_.type_url_.Set(from._internal_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_json_name().empty()) {
+    _this->_impl_.json_name_.Set(from._internal_json_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_default_value().empty()) {
+    _this->_impl_.default_value_.Set(from._internal_default_value(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.kind_, &from._impl_.kind_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.packed_) -
+    reinterpret_cast<char*>(&_impl_.kind_)) + sizeof(_impl_.packed_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Field)
+}
+
+inline void Field::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.type_url_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.kind_){0}
+    , decltype(_impl_.cardinality_){0}
+    , decltype(_impl_.number_){0}
+    , decltype(_impl_.oneof_index_){0}
+    , decltype(_impl_.packed_){false}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Field::~Field() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Field)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Field::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  _impl_.type_url_.Destroy();
+  _impl_.json_name_.Destroy();
+  _impl_.default_value_.Destroy();
+}
+
+void Field::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Field::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Field)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.type_url_.ClearToEmpty();
+  _impl_.json_name_.ClearToEmpty();
+  _impl_.default_value_.ClearToEmpty();
+  ::memset(&_impl_.kind_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.packed_) -
+      reinterpret_cast<char*>(&_impl_.kind_)) + sizeof(_impl_.packed_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Field::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // .google.protobuf.Field.Kind kind = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_kind(static_cast<::PROTOBUF_NAMESPACE_ID::Field_Kind>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Field.Cardinality cardinality = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_cardinality(static_cast<::PROTOBUF_NAMESPACE_ID::Field_Cardinality>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 number = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // string name = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string type_url = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          auto str = _internal_mutable_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 oneof_index = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          _impl_.oneof_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // bool packed = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 64)) {
+          _impl_.packed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<74>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // string json_name = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
+          auto str = _internal_mutable_json_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.json_name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string default_value = 11;
+      case 11:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 90)) {
+          auto str = _internal_mutable_default_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.default_value"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Field::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Field)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // .google.protobuf.Field.Kind kind = 1;
+  if (this->_internal_kind() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      1, this->_internal_kind(), target);
+  }
+
+  // .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->_internal_cardinality() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      2, this->_internal_cardinality(), target);
+  }
+
+  // int32 number = 3;
+  if (this->_internal_number() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
+  }
+
+  // string name = 4;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.name");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_name(), target);
+  }
+
+  // string type_url = 6;
+  if (!this->_internal_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.type_url");
+    target = stream->WriteStringMaybeAliased(
+        6, this->_internal_type_url(), target);
+  }
+
+  // int32 oneof_index = 7;
+  if (this->_internal_oneof_index() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(7, this->_internal_oneof_index(), target);
+  }
+
+  // bool packed = 8;
+  if (this->_internal_packed() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(8, this->_internal_packed(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 9;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(9, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // string json_name = 10;
+  if (!this->_internal_json_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_json_name().data(), static_cast<int>(this->_internal_json_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.json_name");
+    target = stream->WriteStringMaybeAliased(
+        10, this->_internal_json_name(), target);
+  }
+
+  // string default_value = 11;
+  if (!this->_internal_default_value().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_default_value().data(), static_cast<int>(this->_internal_default_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.default_value");
+    target = stream->WriteStringMaybeAliased(
+        11, this->_internal_default_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
+  return target;
+}
+
+size_t Field::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Field)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Option options = 9;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 4;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string type_url = 6;
+  if (!this->_internal_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_type_url());
+  }
+
+  // string json_name = 10;
+  if (!this->_internal_json_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_json_name());
+  }
+
+  // string default_value = 11;
+  if (!this->_internal_default_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_default_value());
+  }
+
+  // .google.protobuf.Field.Kind kind = 1;
+  if (this->_internal_kind() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_kind());
+  }
+
+  // .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->_internal_cardinality() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_cardinality());
+  }
+
+  // int32 number = 3;
+  if (this->_internal_number() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+  }
+
+  // int32 oneof_index = 7;
+  if (this->_internal_oneof_index() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
+  }
+
+  // bool packed = 8;
+  if (this->_internal_packed() != 0) {
+    total_size += 1 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Field::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Field::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Field::GetClassData() const { return &_class_data_; }
+
+
+void Field::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Field*>(&to_msg);
+  auto& from = static_cast<const Field&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Field)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_type_url().empty()) {
+    _this->_internal_set_type_url(from._internal_type_url());
+  }
+  if (!from._internal_json_name().empty()) {
+    _this->_internal_set_json_name(from._internal_json_name());
+  }
+  if (!from._internal_default_value().empty()) {
+    _this->_internal_set_default_value(from._internal_default_value());
+  }
+  if (from._internal_kind() != 0) {
+    _this->_internal_set_kind(from._internal_kind());
+  }
+  if (from._internal_cardinality() != 0) {
+    _this->_internal_set_cardinality(from._internal_cardinality());
+  }
+  if (from._internal_number() != 0) {
+    _this->_internal_set_number(from._internal_number());
+  }
+  if (from._internal_oneof_index() != 0) {
+    _this->_internal_set_oneof_index(from._internal_oneof_index());
+  }
+  if (from._internal_packed() != 0) {
+    _this->_internal_set_packed(from._internal_packed());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Field::CopyFrom(const Field& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Field)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Field::IsInitialized() const {
+  return true;
+}
+
+void Field::InternalSwap(Field* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.type_url_, lhs_arena,
+      &other->_impl_.type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.json_name_, lhs_arena,
+      &other->_impl_.json_name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.default_value_, lhs_arena,
+      &other->_impl_.default_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Field, _impl_.packed_)
+      + sizeof(Field::_impl_.packed_)
+      - PROTOBUF_FIELD_OFFSET(Field, _impl_.kind_)>(
+          reinterpret_cast<char*>(&_impl_.kind_),
+          reinterpret_cast<char*>(&other->_impl_.kind_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Field::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[1]);
+}
+
+// ===================================================================
+
+class Enum::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context(const Enum* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::SourceContext&
+Enum::_Internal::source_context(const Enum* msg) {
+  return *msg->_impl_.source_context_;
+}
+void Enum::clear_source_context() {
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+}
+Enum::Enum(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Enum)
+}
+Enum::Enum(const Enum& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Enum* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.enumvalue_){from._impl_.enumvalue_}
+    , decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
+  }
+  _this->_impl_.syntax_ = from._impl_.syntax_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Enum)
+}
+
+inline void Enum::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.enumvalue_){arena}
+    , decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Enum::~Enum() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Enum)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Enum::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.enumvalue_.~RepeatedPtrField();
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.source_context_;
+}
+
+void Enum::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Enum::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Enum)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.enumvalue_.Clear();
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+  _impl_.syntax_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Enum::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Enum.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumValue enumvalue = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_enumvalue(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.SourceContext source_context = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Enum::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Enum.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enumvalue_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enumvalue(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.SourceContext source_context = 4;
+  if (this->_internal_has_source_context()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(4, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 5;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      5, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Enum)
+  return target;
+}
+
+size_t Enum::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Enum)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  total_size += 1UL * this->_internal_enumvalue_size();
+  for (const auto& msg : this->_impl_.enumvalue_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // .google.protobuf.SourceContext source_context = 4;
+  if (this->_internal_has_source_context()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.source_context_);
+  }
+
+  // .google.protobuf.Syntax syntax = 5;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Enum::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Enum::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Enum::GetClassData() const { return &_class_data_; }
+
+
+void Enum::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Enum*>(&to_msg);
+  auto& from = static_cast<const Enum&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Enum)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.enumvalue_.MergeFrom(from._impl_.enumvalue_);
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
+        from._internal_source_context());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Enum::CopyFrom(const Enum& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Enum)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Enum::IsInitialized() const {
+  return true;
+}
+
+void Enum::InternalSwap(Enum* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.enumvalue_.InternalSwap(&other->_impl_.enumvalue_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Enum, _impl_.syntax_)
+      + sizeof(Enum::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Enum, _impl_.source_context_)>(
+          reinterpret_cast<char*>(&_impl_.source_context_),
+          reinterpret_cast<char*>(&other->_impl_.source_context_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Enum::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[2]);
+}
+
+// ===================================================================
+
+class EnumValue::_Internal {
+ public:
+};
+
+EnumValue::EnumValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValue)
+}
+EnumValue::EnumValue(const EnumValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.number_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _this->_impl_.number_ = from._impl_.number_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValue)
+}
+
+inline void EnumValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.number_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+EnumValue::~EnumValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+}
+
+void EnumValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.number_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.EnumValue.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 number = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.EnumValue.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // int32 number = 2;
+  if (this->_internal_number() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
+  return target;
+}
+
+size_t EnumValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // int32 number = 2;
+  if (this->_internal_number() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValue::GetClassData() const { return &_class_data_; }
+
+
+void EnumValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumValue*>(&to_msg);
+  auto& from = static_cast<const EnumValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_number() != 0) {
+    _this->_internal_set_number(from._internal_number());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumValue::CopyFrom(const EnumValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValue::IsInitialized() const {
+  return true;
+}
+
+void EnumValue::InternalSwap(EnumValue* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.number_, other->_impl_.number_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[3]);
+}
+
+// ===================================================================
+
+class Option::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::Any& value(const Option* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::Any&
+Option::_Internal::value(const Option* msg) {
+  return *msg->_impl_.value_;
+}
+void Option::clear_value() {
+  if (GetArenaForAllocation() == nullptr && _impl_.value_ != nullptr) {
+    delete _impl_.value_;
+  }
+  _impl_.value_ = nullptr;
+}
+Option::Option(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Option)
+}
+Option::Option(const Option& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Option* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.value_){nullptr}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_value()) {
+    _this->_impl_.value_ = new ::PROTOBUF_NAMESPACE_ID::Any(*from._impl_.value_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Option)
+}
+
+inline void Option::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.value_){nullptr}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Option::~Option() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Option)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Option::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.value_;
+}
+
+void Option::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Option::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Option)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.name_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.value_ != nullptr) {
+    delete _impl_.value_;
+  }
+  _impl_.value_ = nullptr;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Option::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Option.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Any value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr = ctx->ParseMessage(_internal_mutable_value(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Option::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Option.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // .google.protobuf.Any value = 2;
+  if (this->_internal_has_value()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(2, _Internal::value(this),
+        _Internal::value(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
+  return target;
+}
+
+size_t Option::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Option)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // .google.protobuf.Any value = 2;
+  if (this->_internal_has_value()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.value_);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Option::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Option::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Option::GetClassData() const { return &_class_data_; }
+
+
+void Option::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Option*>(&to_msg);
+  auto& from = static_cast<const Option&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Option)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_has_value()) {
+    _this->_internal_mutable_value()->::PROTOBUF_NAMESPACE_ID::Any::MergeFrom(
+        from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Option::CopyFrom(const Option& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Option)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Option::IsInitialized() const {
+  return true;
+}
+
+void Option::InternalSwap(Option* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Option::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[4]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Type*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Type >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Type >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Field*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Field >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Field >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Enum*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Enum >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Enum >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Option*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Option >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Option >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
new file mode 100644
index 0000000..2267fb7
--- /dev/null
+++ b/src/google/protobuf/type.pb.h
@@ -0,0 +1,2571 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftype_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftype_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#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)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ftype_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ftype_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Enum;
+struct EnumDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumDefaultTypeInternal _Enum_default_instance_;
+class EnumValue;
+struct EnumValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumValueDefaultTypeInternal _EnumValue_default_instance_;
+class Field;
+struct FieldDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldDefaultTypeInternal _Field_default_instance_;
+class Option;
+struct OptionDefaultTypeInternal;
+PROTOBUF_EXPORT extern OptionDefaultTypeInternal _Option_default_instance_;
+class Type;
+struct TypeDefaultTypeInternal;
+PROTOBUF_EXPORT extern TypeDefaultTypeInternal _Type_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Enum* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Enum>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Field* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Field>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Option* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Option>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Type* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Type>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+enum Field_Kind : int {
+  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_ = std::numeric_limits<int32_t>::min(),
+  Field_Kind_Field_Kind_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool Field_Kind_IsValid(int value);
+constexpr Field_Kind Field_Kind_Kind_MIN = Field_Kind_TYPE_UNKNOWN;
+constexpr Field_Kind Field_Kind_Kind_MAX = Field_Kind_TYPE_SINT64;
+constexpr int Field_Kind_Kind_ARRAYSIZE = Field_Kind_Kind_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Kind_descriptor();
+template<typename T>
+inline const std::string& Field_Kind_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, Field_Kind>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function Field_Kind_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    Field_Kind_descriptor(), enum_t_value);
+}
+inline bool Field_Kind_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Field_Kind* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<Field_Kind>(
+    Field_Kind_descriptor(), name, value);
+}
+enum Field_Cardinality : int {
+  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_ = std::numeric_limits<int32_t>::min(),
+  Field_Cardinality_Field_Cardinality_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool Field_Cardinality_IsValid(int value);
+constexpr Field_Cardinality Field_Cardinality_Cardinality_MIN = Field_Cardinality_CARDINALITY_UNKNOWN;
+constexpr Field_Cardinality Field_Cardinality_Cardinality_MAX = Field_Cardinality_CARDINALITY_REPEATED;
+constexpr int Field_Cardinality_Cardinality_ARRAYSIZE = Field_Cardinality_Cardinality_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Cardinality_descriptor();
+template<typename T>
+inline const std::string& Field_Cardinality_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, Field_Cardinality>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function Field_Cardinality_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    Field_Cardinality_descriptor(), enum_t_value);
+}
+inline bool Field_Cardinality_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Field_Cardinality* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<Field_Cardinality>(
+    Field_Cardinality_descriptor(), name, value);
+}
+enum Syntax : int {
+  SYNTAX_PROTO2 = 0,
+  SYNTAX_PROTO3 = 1,
+  Syntax_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
+  Syntax_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool Syntax_IsValid(int value);
+constexpr Syntax Syntax_MIN = SYNTAX_PROTO2;
+constexpr Syntax Syntax_MAX = SYNTAX_PROTO3;
+constexpr int Syntax_ARRAYSIZE = Syntax_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Syntax_descriptor();
+template<typename T>
+inline const std::string& Syntax_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, Syntax>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function Syntax_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    Syntax_descriptor(), enum_t_value);
+}
+inline bool Syntax_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Syntax* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<Syntax>(
+    Syntax_descriptor(), name, value);
+}
+// ===================================================================
+
+class PROTOBUF_EXPORT Type final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Type) */ {
+ public:
+  inline Type() : Type(nullptr) {}
+  ~Type() override;
+  explicit PROTOBUF_CONSTEXPR Type(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Type(const Type& from);
+  Type(Type&& from) noexcept
+    : Type() {
+    *this = ::std::move(from);
+  }
+
+  inline Type& operator=(const Type& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Type& operator=(Type&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Type& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Type* internal_default_instance() {
+    return reinterpret_cast<const Type*>(
+               &_Type_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Type& a, Type& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Type* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Type* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Type* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Type>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Type& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Type& from) {
+    Type::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Type* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Type";
+  }
+  protected:
+  explicit Type(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFieldsFieldNumber = 2,
+    kOneofsFieldNumber = 3,
+    kOptionsFieldNumber = 4,
+    kNameFieldNumber = 1,
+    kSourceContextFieldNumber = 5,
+    kSyntaxFieldNumber = 6,
+  };
+  // repeated .google.protobuf.Field fields = 2;
+  int fields_size() const;
+  private:
+  int _internal_fields_size() const;
+  public:
+  void clear_fields();
+  ::PROTOBUF_NAMESPACE_ID::Field* mutable_fields(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >*
+      mutable_fields();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Field& _internal_fields(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Field* _internal_add_fields();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Field& fields(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Field* add_fields();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >&
+      fields() const;
+
+  // repeated string oneofs = 3;
+  int oneofs_size() const;
+  private:
+  int _internal_oneofs_size() const;
+  public:
+  void clear_oneofs();
+  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, 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(std::string&& value);
+  void add_oneofs(const char* value);
+  void add_oneofs(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& oneofs() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_oneofs();
+  private:
+  const std::string& _internal_oneofs(int index) const;
+  std::string* _internal_add_oneofs();
+  public:
+
+  // repeated .google.protobuf.Option options = 4;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // .google.protobuf.SourceContext source_context = 5;
+  bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
+  void clear_source_context();
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
+  void set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& _internal_source_context() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _internal_mutable_source_context();
+  public:
+  void unsafe_arena_set_allocated_source_context(
+      ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* unsafe_arena_release_source_context();
+
+  // .google.protobuf.Syntax syntax = 6;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Type)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field > fields_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> oneofs_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Field final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Field) */ {
+ public:
+  inline Field() : Field(nullptr) {}
+  ~Field() override;
+  explicit PROTOBUF_CONSTEXPR Field(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Field(const Field& from);
+  Field(Field&& from) noexcept
+    : Field() {
+    *this = ::std::move(from);
+  }
+
+  inline Field& operator=(const Field& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Field& operator=(Field&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Field& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Field* internal_default_instance() {
+    return reinterpret_cast<const Field*>(
+               &_Field_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(Field& a, Field& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Field* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Field* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Field* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Field>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Field& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Field& from) {
+    Field::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Field* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Field";
+  }
+  protected:
+  explicit Field(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef Field_Kind Kind;
+  static constexpr Kind TYPE_UNKNOWN =
+    Field_Kind_TYPE_UNKNOWN;
+  static constexpr Kind TYPE_DOUBLE =
+    Field_Kind_TYPE_DOUBLE;
+  static constexpr Kind TYPE_FLOAT =
+    Field_Kind_TYPE_FLOAT;
+  static constexpr Kind TYPE_INT64 =
+    Field_Kind_TYPE_INT64;
+  static constexpr Kind TYPE_UINT64 =
+    Field_Kind_TYPE_UINT64;
+  static constexpr Kind TYPE_INT32 =
+    Field_Kind_TYPE_INT32;
+  static constexpr Kind TYPE_FIXED64 =
+    Field_Kind_TYPE_FIXED64;
+  static constexpr Kind TYPE_FIXED32 =
+    Field_Kind_TYPE_FIXED32;
+  static constexpr Kind TYPE_BOOL =
+    Field_Kind_TYPE_BOOL;
+  static constexpr Kind TYPE_STRING =
+    Field_Kind_TYPE_STRING;
+  static constexpr Kind TYPE_GROUP =
+    Field_Kind_TYPE_GROUP;
+  static constexpr Kind TYPE_MESSAGE =
+    Field_Kind_TYPE_MESSAGE;
+  static constexpr Kind TYPE_BYTES =
+    Field_Kind_TYPE_BYTES;
+  static constexpr Kind TYPE_UINT32 =
+    Field_Kind_TYPE_UINT32;
+  static constexpr Kind TYPE_ENUM =
+    Field_Kind_TYPE_ENUM;
+  static constexpr Kind TYPE_SFIXED32 =
+    Field_Kind_TYPE_SFIXED32;
+  static constexpr Kind TYPE_SFIXED64 =
+    Field_Kind_TYPE_SFIXED64;
+  static constexpr Kind TYPE_SINT32 =
+    Field_Kind_TYPE_SINT32;
+  static constexpr Kind TYPE_SINT64 =
+    Field_Kind_TYPE_SINT64;
+  static inline bool Kind_IsValid(int value) {
+    return Field_Kind_IsValid(value);
+  }
+  static constexpr Kind Kind_MIN =
+    Field_Kind_Kind_MIN;
+  static constexpr Kind Kind_MAX =
+    Field_Kind_Kind_MAX;
+  static constexpr int Kind_ARRAYSIZE =
+    Field_Kind_Kind_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Kind_descriptor() {
+    return Field_Kind_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Kind_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Kind>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Kind_Name.");
+    return Field_Kind_Name(enum_t_value);
+  }
+  static inline bool Kind_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Kind* value) {
+    return Field_Kind_Parse(name, value);
+  }
+
+  typedef Field_Cardinality Cardinality;
+  static constexpr Cardinality CARDINALITY_UNKNOWN =
+    Field_Cardinality_CARDINALITY_UNKNOWN;
+  static constexpr Cardinality CARDINALITY_OPTIONAL =
+    Field_Cardinality_CARDINALITY_OPTIONAL;
+  static constexpr Cardinality CARDINALITY_REQUIRED =
+    Field_Cardinality_CARDINALITY_REQUIRED;
+  static constexpr Cardinality CARDINALITY_REPEATED =
+    Field_Cardinality_CARDINALITY_REPEATED;
+  static inline bool Cardinality_IsValid(int value) {
+    return Field_Cardinality_IsValid(value);
+  }
+  static constexpr Cardinality Cardinality_MIN =
+    Field_Cardinality_Cardinality_MIN;
+  static constexpr Cardinality Cardinality_MAX =
+    Field_Cardinality_Cardinality_MAX;
+  static constexpr int Cardinality_ARRAYSIZE =
+    Field_Cardinality_Cardinality_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Cardinality_descriptor() {
+    return Field_Cardinality_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Cardinality_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Cardinality>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Cardinality_Name.");
+    return Field_Cardinality_Name(enum_t_value);
+  }
+  static inline bool Cardinality_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Cardinality* value) {
+    return Field_Cardinality_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 9,
+    kNameFieldNumber = 4,
+    kTypeUrlFieldNumber = 6,
+    kJsonNameFieldNumber = 10,
+    kDefaultValueFieldNumber = 11,
+    kKindFieldNumber = 1,
+    kCardinalityFieldNumber = 2,
+    kNumberFieldNumber = 3,
+    kOneofIndexFieldNumber = 7,
+    kPackedFieldNumber = 8,
+  };
+  // repeated .google.protobuf.Option options = 9;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 4;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string type_url = 6;
+  void clear_type_url();
+  const std::string& type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_type_url();
+  PROTOBUF_NODISCARD std::string* release_type_url();
+  void set_allocated_type_url(std::string* type_url);
+  private:
+  const std::string& _internal_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_url(const std::string& value);
+  std::string* _internal_mutable_type_url();
+  public:
+
+  // string json_name = 10;
+  void clear_json_name();
+  const std::string& json_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_json_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_json_name();
+  PROTOBUF_NODISCARD std::string* release_json_name();
+  void set_allocated_json_name(std::string* json_name);
+  private:
+  const std::string& _internal_json_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_json_name(const std::string& value);
+  std::string* _internal_mutable_json_name();
+  public:
+
+  // string default_value = 11;
+  void clear_default_value();
+  const std::string& default_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_default_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_default_value();
+  PROTOBUF_NODISCARD std::string* release_default_value();
+  void set_allocated_default_value(std::string* default_value);
+  private:
+  const std::string& _internal_default_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_default_value(const std::string& value);
+  std::string* _internal_mutable_default_value();
+  public:
+
+  // .google.protobuf.Field.Kind kind = 1;
+  void clear_kind();
+  ::PROTOBUF_NAMESPACE_ID::Field_Kind kind() const;
+  void set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Field_Kind _internal_kind() const;
+  void _internal_set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value);
+  public:
+
+  // .google.protobuf.Field.Cardinality cardinality = 2;
+  void clear_cardinality();
+  ::PROTOBUF_NAMESPACE_ID::Field_Cardinality cardinality() const;
+  void set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Field_Cardinality _internal_cardinality() const;
+  void _internal_set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value);
+  public:
+
+  // int32 number = 3;
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // int32 oneof_index = 7;
+  void clear_oneof_index();
+  int32_t oneof_index() const;
+  void set_oneof_index(int32_t value);
+  private:
+  int32_t _internal_oneof_index() const;
+  void _internal_set_oneof_index(int32_t value);
+  public:
+
+  // bool packed = 8;
+  void clear_packed();
+  bool packed() const;
+  void set_packed(bool value);
+  private:
+  bool _internal_packed() const;
+  void _internal_set_packed(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Field)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_url_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr json_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr default_value_;
+    int kind_;
+    int cardinality_;
+    int32_t number_;
+    int32_t oneof_index_;
+    bool packed_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Enum final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Enum) */ {
+ public:
+  inline Enum() : Enum(nullptr) {}
+  ~Enum() override;
+  explicit PROTOBUF_CONSTEXPR Enum(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Enum(const Enum& from);
+  Enum(Enum&& from) noexcept
+    : Enum() {
+    *this = ::std::move(from);
+  }
+
+  inline Enum& operator=(const Enum& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Enum& operator=(Enum&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Enum& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Enum* internal_default_instance() {
+    return reinterpret_cast<const Enum*>(
+               &_Enum_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Enum& a, Enum& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Enum* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Enum* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Enum* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Enum>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Enum& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Enum& from) {
+    Enum::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Enum* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Enum";
+  }
+  protected:
+  explicit Enum(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kEnumvalueFieldNumber = 2,
+    kOptionsFieldNumber = 3,
+    kNameFieldNumber = 1,
+    kSourceContextFieldNumber = 4,
+    kSyntaxFieldNumber = 5,
+  };
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  int enumvalue_size() const;
+  private:
+  int _internal_enumvalue_size() const;
+  public:
+  void clear_enumvalue();
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* mutable_enumvalue(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >*
+      mutable_enumvalue();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValue& _internal_enumvalue(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* _internal_add_enumvalue();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValue& enumvalue(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* add_enumvalue();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >&
+      enumvalue() const;
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // .google.protobuf.SourceContext source_context = 4;
+  bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
+  void clear_source_context();
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
+  void set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& _internal_source_context() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _internal_mutable_source_context();
+  public:
+  void unsafe_arena_set_allocated_source_context(
+      ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* unsafe_arena_release_source_context();
+
+  // .google.protobuf.Syntax syntax = 5;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Enum)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue > enumvalue_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValue) */ {
+ public:
+  inline EnumValue() : EnumValue(nullptr) {}
+  ~EnumValue() override;
+  explicit PROTOBUF_CONSTEXPR EnumValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumValue(const EnumValue& from);
+  EnumValue(EnumValue&& from) noexcept
+    : EnumValue() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumValue& operator=(const EnumValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumValue& operator=(EnumValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumValue* internal_default_instance() {
+    return reinterpret_cast<const EnumValue*>(
+               &_EnumValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(EnumValue& a, EnumValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumValue& from) {
+    EnumValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValue";
+  }
+  protected:
+  explicit EnumValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 3,
+    kNameFieldNumber = 1,
+    kNumberFieldNumber = 2,
+  };
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // int32 number = 2;
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    int32_t number_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Option final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Option) */ {
+ public:
+  inline Option() : Option(nullptr) {}
+  ~Option() override;
+  explicit PROTOBUF_CONSTEXPR Option(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Option(const Option& from);
+  Option(Option&& from) noexcept
+    : Option() {
+    *this = ::std::move(from);
+  }
+
+  inline Option& operator=(const Option& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Option& operator=(Option&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Option& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Option* internal_default_instance() {
+    return reinterpret_cast<const Option*>(
+               &_Option_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    4;
+
+  friend void swap(Option& a, Option& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Option* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Option* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Option* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Option>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Option& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Option& from) {
+    Option::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Option* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Option";
+  }
+  protected:
+  explicit Option(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kValueFieldNumber = 2,
+  };
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // .google.protobuf.Any value = 2;
+  bool has_value() const;
+  private:
+  bool _internal_has_value() const;
+  public:
+  void clear_value();
+  const ::PROTOBUF_NAMESPACE_ID::Any& value() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::Any* release_value();
+  ::PROTOBUF_NAMESPACE_ID::Any* mutable_value();
+  void set_allocated_value(::PROTOBUF_NAMESPACE_ID::Any* value);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Any& _internal_value() const;
+  ::PROTOBUF_NAMESPACE_ID::Any* _internal_mutable_value();
+  public:
+  void unsafe_arena_set_allocated_value(
+      ::PROTOBUF_NAMESPACE_ID::Any* value);
+  ::PROTOBUF_NAMESPACE_ID::Any* unsafe_arena_release_value();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Option)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::Any* value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Type
+
+// string name = 1;
+inline void Type::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Type::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Type::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.name)
+}
+inline std::string* Type::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.name)
+  return _s;
+}
+inline const std::string& Type::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Type::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Type::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Type::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.name)
+  return _impl_.name_.Release();
+}
+inline void Type::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.name)
+}
+
+// repeated .google.protobuf.Field fields = 2;
+inline int Type::_internal_fields_size() const {
+  return _impl_.fields_.size();
+}
+inline int Type::fields_size() const {
+  return _internal_fields_size();
+}
+inline void Type::clear_fields() {
+  _impl_.fields_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field* Type::mutable_fields(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.fields)
+  return _impl_.fields_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >*
+Type::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.fields)
+  return &_impl_.fields_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Field& Type::_internal_fields(int index) const {
+  return _impl_.fields_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Field& Type::fields(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.fields)
+  return _internal_fields(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field* Type::_internal_add_fields() {
+  return _impl_.fields_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field* Type::add_fields() {
+  ::PROTOBUF_NAMESPACE_ID::Field* _add = _internal_add_fields();
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.fields)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >&
+Type::fields() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.fields)
+  return _impl_.fields_;
+}
+
+// repeated string oneofs = 3;
+inline int Type::_internal_oneofs_size() const {
+  return _impl_.oneofs_.size();
+}
+inline int Type::oneofs_size() const {
+  return _internal_oneofs_size();
+}
+inline void Type::clear_oneofs() {
+  _impl_.oneofs_.Clear();
+}
+inline std::string* Type::add_oneofs() {
+  std::string* _s = _internal_add_oneofs();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs)
+  return _s;
+}
+inline const std::string& Type::_internal_oneofs(int index) const {
+  return _impl_.oneofs_.Get(index);
+}
+inline const std::string& Type::oneofs(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.oneofs)
+  return _internal_oneofs(index);
+}
+inline std::string* Type::mutable_oneofs(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.oneofs)
+  return _impl_.oneofs_.Mutable(index);
+}
+inline void Type::set_oneofs(int index, const std::string& value) {
+  _impl_.oneofs_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.oneofs)
+}
+inline void Type::set_oneofs(int index, std::string&& value) {
+  _impl_.oneofs_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.oneofs)
+}
+inline void Type::set_oneofs(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.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) {
+  _impl_.oneofs_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs)
+}
+inline std::string* Type::_internal_add_oneofs() {
+  return _impl_.oneofs_.Add();
+}
+inline void Type::add_oneofs(const std::string& value) {
+  _impl_.oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(std::string&& value) {
+  _impl_.oneofs_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.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) {
+  _impl_.oneofs_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.Type.oneofs)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+Type::oneofs() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.oneofs)
+  return _impl_.oneofs_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+Type::mutable_oneofs() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.oneofs)
+  return &_impl_.oneofs_;
+}
+
+// repeated .google.protobuf.Option options = 4;
+inline int Type::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Type::options_size() const {
+  return _internal_options_size();
+}
+inline void Type::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Type::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Type::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Type::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Type::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Type::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Type::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Type::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.options)
+  return _impl_.options_;
+}
+
+// .google.protobuf.SourceContext source_context = 5;
+inline bool Type::_internal_has_source_context() const {
+  return this != internal_default_instance() && _impl_.source_context_ != nullptr;
+}
+inline bool Type::has_source_context() const {
+  return _internal_has_source_context();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Type::_internal_source_context() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext* p = _impl_.source_context_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceContext&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Type::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.source_context)
+  return _internal_source_context();
+}
+inline void Type::unsafe_arena_set_allocated_source_context(
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  _impl_.source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Type.source_context)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::release_source_context() {
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::unsafe_arena_release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context)
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::_internal_mutable_source_context() {
+  
+  if (_impl_.source_context_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(GetArenaForAllocation());
+    _impl_.source_context_ = p;
+  }
+  return _impl_.source_context_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::mutable_source_context() {
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _msg = _internal_mutable_source_context();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.source_context)
+  return _msg;
+}
+inline void Type::set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  if (source_context) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(source_context));
+    if (message_arena != submessage_arena) {
+      source_context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_context, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.source_context_ = source_context;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.source_context)
+}
+
+// .google.protobuf.Syntax syntax = 6;
+inline void Type::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Type::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Type::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.syntax)
+  return _internal_syntax();
+}
+inline void Type::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Type::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Field
+
+// .google.protobuf.Field.Kind kind = 1;
+inline void Field::clear_kind() {
+  _impl_.kind_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Kind Field::_internal_kind() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Field_Kind >(_impl_.kind_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Kind Field::kind() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.kind)
+  return _internal_kind();
+}
+inline void Field::_internal_set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value) {
+  
+  _impl_.kind_ = value;
+}
+inline void Field::set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value) {
+  _internal_set_kind(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.kind)
+}
+
+// .google.protobuf.Field.Cardinality cardinality = 2;
+inline void Field::clear_cardinality() {
+  _impl_.cardinality_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Cardinality Field::_internal_cardinality() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Field_Cardinality >(_impl_.cardinality_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Cardinality Field::cardinality() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.cardinality)
+  return _internal_cardinality();
+}
+inline void Field::_internal_set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value) {
+  
+  _impl_.cardinality_ = value;
+}
+inline void Field::set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value) {
+  _internal_set_cardinality(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.cardinality)
+}
+
+// int32 number = 3;
+inline void Field::clear_number() {
+  _impl_.number_ = 0;
+}
+inline int32_t Field::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t Field::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.number)
+  return _internal_number();
+}
+inline void Field::_internal_set_number(int32_t value) {
+  
+  _impl_.number_ = value;
+}
+inline void Field::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.number)
+}
+
+// string name = 4;
+inline void Field::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Field::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.name)
+}
+inline std::string* Field::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.name)
+  return _s;
+}
+inline const std::string& Field::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Field::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.name)
+  return _impl_.name_.Release();
+}
+inline void Field::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.name)
+}
+
+// string type_url = 6;
+inline void Field::clear_type_url() {
+  _impl_.type_url_.ClearToEmpty();
+}
+inline const std::string& Field::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.type_url)
+  return _internal_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.type_url)
+}
+inline std::string* Field::mutable_type_url() {
+  std::string* _s = _internal_mutable_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.type_url)
+  return _s;
+}
+inline const std::string& Field::_internal_type_url() const {
+  return _impl_.type_url_.Get();
+}
+inline void Field::_internal_set_type_url(const std::string& value) {
+  
+  _impl_.type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_type_url() {
+  
+  return _impl_.type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url)
+  return _impl_.type_url_.Release();
+}
+inline void Field::set_allocated_type_url(std::string* type_url) {
+  if (type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.type_url_.SetAllocated(type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_url_.IsDefault()) {
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.type_url)
+}
+
+// int32 oneof_index = 7;
+inline void Field::clear_oneof_index() {
+  _impl_.oneof_index_ = 0;
+}
+inline int32_t Field::_internal_oneof_index() const {
+  return _impl_.oneof_index_;
+}
+inline int32_t Field::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.oneof_index)
+  return _internal_oneof_index();
+}
+inline void Field::_internal_set_oneof_index(int32_t value) {
+  
+  _impl_.oneof_index_ = value;
+}
+inline void Field::set_oneof_index(int32_t value) {
+  _internal_set_oneof_index(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.oneof_index)
+}
+
+// bool packed = 8;
+inline void Field::clear_packed() {
+  _impl_.packed_ = false;
+}
+inline bool Field::_internal_packed() const {
+  return _impl_.packed_;
+}
+inline bool Field::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.packed)
+  return _internal_packed();
+}
+inline void Field::_internal_set_packed(bool value) {
+  
+  _impl_.packed_ = value;
+}
+inline void Field::set_packed(bool value) {
+  _internal_set_packed(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.packed)
+}
+
+// repeated .google.protobuf.Option options = 9;
+inline int Field::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Field::options_size() const {
+  return _internal_options_size();
+}
+inline void Field::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Field::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Field::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Field::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Field::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Field::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Field::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Field.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Field::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Field.options)
+  return _impl_.options_;
+}
+
+// string json_name = 10;
+inline void Field::clear_json_name() {
+  _impl_.json_name_.ClearToEmpty();
+}
+inline const std::string& Field::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.json_name)
+  return _internal_json_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_json_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.json_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.json_name)
+}
+inline std::string* Field::mutable_json_name() {
+  std::string* _s = _internal_mutable_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.json_name)
+  return _s;
+}
+inline const std::string& Field::_internal_json_name() const {
+  return _impl_.json_name_.Get();
+}
+inline void Field::_internal_set_json_name(const std::string& value) {
+  
+  _impl_.json_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_json_name() {
+  
+  return _impl_.json_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name)
+  return _impl_.json_name_.Release();
+}
+inline void Field::set_allocated_json_name(std::string* json_name) {
+  if (json_name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.json_name_.SetAllocated(json_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.json_name_.IsDefault()) {
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
+}
+
+// string default_value = 11;
+inline void Field::clear_default_value() {
+  _impl_.default_value_.ClearToEmpty();
+}
+inline const std::string& Field::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+  return _internal_default_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_default_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.default_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+inline std::string* Field::mutable_default_value() {
+  std::string* _s = _internal_mutable_default_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+  return _s;
+}
+inline const std::string& Field::_internal_default_value() const {
+  return _impl_.default_value_.Get();
+}
+inline void Field::_internal_set_default_value(const std::string& value) {
+  
+  _impl_.default_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_default_value() {
+  
+  return _impl_.default_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value)
+  return _impl_.default_value_.Release();
+}
+inline void Field::set_allocated_default_value(std::string* default_value) {
+  if (default_value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.default_value_.SetAllocated(default_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.default_value_.IsDefault()) {
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
+// -------------------------------------------------------------------
+
+// Enum
+
+// string name = 1;
+inline void Enum::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Enum::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Enum::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.name)
+}
+inline std::string* Enum::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.name)
+  return _s;
+}
+inline const std::string& Enum::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Enum::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Enum::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Enum::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.name)
+  return _impl_.name_.Release();
+}
+inline void Enum::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.name)
+}
+
+// repeated .google.protobuf.EnumValue enumvalue = 2;
+inline int Enum::_internal_enumvalue_size() const {
+  return _impl_.enumvalue_.size();
+}
+inline int Enum::enumvalue_size() const {
+  return _internal_enumvalue_size();
+}
+inline void Enum::clear_enumvalue() {
+  _impl_.enumvalue_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValue* Enum::mutable_enumvalue(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.enumvalue)
+  return _impl_.enumvalue_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >*
+Enum::mutable_enumvalue() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.enumvalue)
+  return &_impl_.enumvalue_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValue& Enum::_internal_enumvalue(int index) const {
+  return _impl_.enumvalue_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValue& Enum::enumvalue(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.enumvalue)
+  return _internal_enumvalue(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValue* Enum::_internal_add_enumvalue() {
+  return _impl_.enumvalue_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValue* Enum::add_enumvalue() {
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* _add = _internal_add_enumvalue();
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.enumvalue)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >&
+Enum::enumvalue() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue)
+  return _impl_.enumvalue_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int Enum::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Enum::options_size() const {
+  return _internal_options_size();
+}
+inline void Enum::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Enum::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Enum::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Enum::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Enum::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Enum::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Enum::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Enum::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.options)
+  return _impl_.options_;
+}
+
+// .google.protobuf.SourceContext source_context = 4;
+inline bool Enum::_internal_has_source_context() const {
+  return this != internal_default_instance() && _impl_.source_context_ != nullptr;
+}
+inline bool Enum::has_source_context() const {
+  return _internal_has_source_context();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Enum::_internal_source_context() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext* p = _impl_.source_context_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceContext&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Enum::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.source_context)
+  return _internal_source_context();
+}
+inline void Enum::unsafe_arena_set_allocated_source_context(
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  _impl_.source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Enum.source_context)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::release_source_context() {
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::unsafe_arena_release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context)
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::_internal_mutable_source_context() {
+  
+  if (_impl_.source_context_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(GetArenaForAllocation());
+    _impl_.source_context_ = p;
+  }
+  return _impl_.source_context_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::mutable_source_context() {
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _msg = _internal_mutable_source_context();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.source_context)
+  return _msg;
+}
+inline void Enum::set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  if (source_context) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(source_context));
+    if (message_arena != submessage_arena) {
+      source_context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_context, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.source_context_ = source_context;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.source_context)
+}
+
+// .google.protobuf.Syntax syntax = 5;
+inline void Enum::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Enum::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Enum::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.syntax)
+  return _internal_syntax();
+}
+inline void Enum::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Enum::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// EnumValue
+
+// string name = 1;
+inline void EnumValue::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& EnumValue::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void EnumValue::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.name)
+}
+inline std::string* EnumValue::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.name)
+  return _s;
+}
+inline const std::string& EnumValue::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void EnumValue::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* EnumValue::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* EnumValue::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name)
+  return _impl_.name_.Release();
+}
+inline void EnumValue::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValue.name)
+}
+
+// int32 number = 2;
+inline void EnumValue::clear_number() {
+  _impl_.number_ = 0;
+}
+inline int32_t EnumValue::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t EnumValue::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.number)
+  return _internal_number();
+}
+inline void EnumValue::_internal_set_number(int32_t value) {
+  
+  _impl_.number_ = value;
+}
+inline void EnumValue::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.number)
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int EnumValue::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int EnumValue::options_size() const {
+  return _internal_options_size();
+}
+inline void EnumValue::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* EnumValue::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+EnumValue::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValue.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& EnumValue::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& EnumValue::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* EnumValue::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* EnumValue::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValue.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+EnumValue::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options)
+  return _impl_.options_;
+}
+
+// -------------------------------------------------------------------
+
+// Option
+
+// string name = 1;
+inline void Option::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Option::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Option::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Option.name)
+}
+inline std::string* Option::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.name)
+  return _s;
+}
+inline const std::string& Option::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Option::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Option::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Option::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.name)
+  return _impl_.name_.Release();
+}
+inline void Option::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.name)
+}
+
+// .google.protobuf.Any value = 2;
+inline bool Option::_internal_has_value() const {
+  return this != internal_default_instance() && _impl_.value_ != nullptr;
+}
+inline bool Option::has_value() const {
+  return _internal_has_value();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Any& Option::_internal_value() const {
+  const ::PROTOBUF_NAMESPACE_ID::Any* p = _impl_.value_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Any&>(
+      ::PROTOBUF_NAMESPACE_ID::_Any_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Any& Option::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.value)
+  return _internal_value();
+}
+inline void Option::unsafe_arena_set_allocated_value(
+    ::PROTOBUF_NAMESPACE_ID::Any* value) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.value_);
+  }
+  _impl_.value_ = value;
+  if (value) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Option.value)
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::release_value() {
+  
+  ::PROTOBUF_NAMESPACE_ID::Any* temp = _impl_.value_;
+  _impl_.value_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::unsafe_arena_release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.value)
+  
+  ::PROTOBUF_NAMESPACE_ID::Any* temp = _impl_.value_;
+  _impl_.value_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::_internal_mutable_value() {
+  
+  if (_impl_.value_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Any>(GetArenaForAllocation());
+    _impl_.value_ = p;
+  }
+  return _impl_.value_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::mutable_value() {
+  ::PROTOBUF_NAMESPACE_ID::Any* _msg = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.value)
+  return _msg;
+}
+inline void Option::set_allocated_value(::PROTOBUF_NAMESPACE_ID::Any* value) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.value_);
+  }
+  if (value) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(value));
+    if (message_arena != submessage_arena) {
+      value = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, value, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.value_ = value;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.value)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::Field_Kind> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::Field_Kind>() {
+  return ::PROTOBUF_NAMESPACE_ID::Field_Kind_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::Field_Cardinality> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::Field_Cardinality>() {
+  return ::PROTOBUF_NAMESPACE_ID::Field_Cardinality_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::Syntax> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::Syntax>() {
+  return ::PROTOBUF_NAMESPACE_ID::Syntax_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftype_2eproto
diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto
new file mode 100644
index 0000000..d3f6a68
--- /dev/null
+++ b/src/google/protobuf/type.proto
@@ -0,0 +1,187 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/source_context.proto";
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TypeProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option go_package = "google.golang.org/protobuf/types/known/typepb";
+
+// 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 protobuf built-in options (options defined in
+  // descriptor.proto), this is the short name. For example, `"map_entry"`.
+  // For custom options, it should be the fully-qualified name. For example,
+  // `"google.api.http"`.
+  string name = 1;
+  // The option's value packed in an Any message. If the value is a primitive,
+  // the corresponding wrapper type defined in google/protobuf/wrappers.proto
+  // should be used. If the value is an enum, it should be stored as an int32
+  // value using the google.protobuf.Int32Value type.
+  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
new file mode 100644
index 0000000..f1b0bd0
--- /dev/null
+++ b/src/google/protobuf/unittest.proto
@@ -0,0 +1,1418 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// LINT: ALLOW_GROUPS, LEGACY_NAMES
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;     // auto-added
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest_import.proto";
+
+// 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.
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage                        optional_nested_message  = 18;
+  optional ForeignMessage                       optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  optional NestedEnum                           optional_nested_enum     = 21;
+  optional ForeignEnum                          optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnum    optional_import_enum     = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+  optional NestedMessage optional_unverified_lazy_message = 28 [unverified_lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+  repeated protobuf_unittest_import.ImportEnum    repeated_import_enum     = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum  default_nested_enum  = 81 [default = BAR        ];
+  optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+      default_import_enum = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+
+  // For oneof test
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// This proto includes a recursively nested message.
+message NestedTestAllTypes {
+  optional NestedTestAllTypes child = 1;
+  optional TestAllTypes payload = 2;
+  repeated NestedTestAllTypes repeated_child = 3;
+  optional NestedTestAllTypes lazy_child = 4 [lazy=true];
+  optional TestAllTypes eager_child = 5 [lazy=false];
+}
+
+message TestDeprecatedFields {
+  optional int32 deprecated_int32 = 1 [deprecated=true];
+  oneof oneof_fields {
+    int32 deprecated_int32_in_oneof = 2 [deprecated=true];
+  }
+}
+
+message TestDeprecatedMessage {
+  option deprecated = true;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  optional int32 c = 1;
+  optional int32 d = 2;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestReservedFields {
+  reserved 2, 15, 9 to 11;
+  reserved "bar", "baz";
+}
+
+message TestAllExtensions {
+  extensions 1 to max;
+}
+
+extend TestAllExtensions {
+  // Singular
+  optional    int32 optional_int32_extension    =  1;
+  optional    int64 optional_int64_extension    =  2;
+  optional   uint32 optional_uint32_extension   =  3;
+  optional   uint64 optional_uint64_extension   =  4;
+  optional   sint32 optional_sint32_extension   =  5;
+  optional   sint64 optional_sint64_extension   =  6;
+  optional  fixed32 optional_fixed32_extension  =  7;
+  optional  fixed64 optional_fixed64_extension  =  8;
+  optional sfixed32 optional_sfixed32_extension =  9;
+  optional sfixed64 optional_sfixed64_extension = 10;
+  optional    float optional_float_extension    = 11;
+  optional   double optional_double_extension   = 12;
+  optional     bool optional_bool_extension     = 13;
+  optional   string optional_string_extension   = 14;
+  optional    bytes optional_bytes_extension    = 15;
+
+  optional group OptionalGroup_extension = 16 {
+    optional int32 a = 17;
+  }
+
+  optional TestAllTypes.NestedMessage optional_nested_message_extension = 18;
+  optional ForeignMessage optional_foreign_message_extension = 19;
+  optional protobuf_unittest_import.ImportMessage
+    optional_import_message_extension = 20;
+
+  optional TestAllTypes.NestedEnum optional_nested_enum_extension = 21;
+  optional ForeignEnum optional_foreign_enum_extension = 22;
+  optional protobuf_unittest_import.ImportEnum
+    optional_import_enum_extension = 23;
+
+  optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE];
+  optional string optional_cord_extension = 25 [ctype=CORD];
+
+  optional protobuf_unittest_import.PublicImportMessage
+    optional_public_import_message_extension = 26;
+
+  optional TestAllTypes.NestedMessage
+    optional_lazy_message_extension = 27 [lazy=true];
+  optional TestAllTypes.NestedMessage
+    optional_unverified_lazy_message_extension = 28 [unverified_lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32_extension    = 31;
+  repeated    int64 repeated_int64_extension    = 32;
+  repeated   uint32 repeated_uint32_extension   = 33;
+  repeated   uint64 repeated_uint64_extension   = 34;
+  repeated   sint32 repeated_sint32_extension   = 35;
+  repeated   sint64 repeated_sint64_extension   = 36;
+  repeated  fixed32 repeated_fixed32_extension  = 37;
+  repeated  fixed64 repeated_fixed64_extension  = 38;
+  repeated sfixed32 repeated_sfixed32_extension = 39;
+  repeated sfixed64 repeated_sfixed64_extension = 40;
+  repeated    float repeated_float_extension    = 41;
+  repeated   double repeated_double_extension   = 42;
+  repeated     bool repeated_bool_extension     = 43;
+  repeated   string repeated_string_extension   = 44;
+  repeated    bytes repeated_bytes_extension    = 45;
+
+  repeated group RepeatedGroup_extension = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 48;
+  repeated ForeignMessage repeated_foreign_message_extension = 49;
+  repeated protobuf_unittest_import.ImportMessage
+    repeated_import_message_extension = 50;
+
+  repeated TestAllTypes.NestedEnum repeated_nested_enum_extension = 51;
+  repeated ForeignEnum repeated_foreign_enum_extension = 52;
+  repeated protobuf_unittest_import.ImportEnum
+    repeated_import_enum_extension = 53;
+
+  repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord_extension = 55 [ctype=CORD];
+
+  repeated TestAllTypes.NestedMessage
+    repeated_lazy_message_extension = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32_extension    = 61 [default =  41    ];
+  optional    int64 default_int64_extension    = 62 [default =  42    ];
+  optional   uint32 default_uint32_extension   = 63 [default =  43    ];
+  optional   uint64 default_uint64_extension   = 64 [default =  44    ];
+  optional   sint32 default_sint32_extension   = 65 [default = -45    ];
+  optional   sint64 default_sint64_extension   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32_extension  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64_extension  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32_extension = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64_extension = 70 [default = -50    ];
+  optional    float default_float_extension    = 71 [default =  51.5  ];
+  optional   double default_double_extension   = 72 [default =  52e3  ];
+  optional     bool default_bool_extension     = 73 [default = true   ];
+  optional   string default_string_extension   = 74 [default = "hello"];
+  optional    bytes default_bytes_extension    = 75 [default = "world"];
+
+  optional TestAllTypes.NestedEnum
+    default_nested_enum_extension = 81 [default = BAR];
+  optional ForeignEnum
+    default_foreign_enum_extension = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+    default_import_enum_extension = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece_extension = 84 [ctype=STRING_PIECE,
+                                                       default="abc"];
+  optional string default_cord_extension = 85 [ctype=CORD, default="123"];
+
+  // For oneof test
+  optional uint32 oneof_uint32_extension = 111;
+  optional TestAllTypes.NestedMessage oneof_nested_message_extension = 112;
+  optional string oneof_string_extension = 113;
+  optional bytes oneof_bytes_extension = 114;
+}
+
+message TestGroup {
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+  optional ForeignEnum optional_foreign_enum = 22;
+}
+
+message TestGroupExtension {
+  extensions 1 to max;
+}
+
+message TestNestedExtension {
+  extend TestAllExtensions {
+    // Check for bug where string extensions declared in tested scope did not
+    // compile.
+    optional string test = 1002 [default="test"];
+    // Used to test if generated extension name is correct when there are
+    // underscores.
+    optional string nested_string_extension = 1003;
+  }
+
+  extend TestGroupExtension {
+    optional group OptionalGroup_extension = 16 {
+      optional int32 a = 17;
+    }
+    optional ForeignEnum optional_foreign_enum_extension = 22;
+  }
+}
+
+message TestChildExtension {
+  optional string a = 1;
+  optional string b = 2;
+  optional TestAllExtensions optional_extension = 3;
+}
+
+// Emulates wireformat data of TestChildExtension with dynamic extension
+// (DynamicExtension).
+message TestChildExtensionData {
+  message NestedTestAllExtensionsData {
+    message NestedDynamicExtensions {
+      optional int32 a = 1;
+      optional int32 b = 2;
+    }
+    optional NestedDynamicExtensions dynamic = 409707008;
+  }
+  optional string a = 1;
+  optional string b = 2;
+  optional NestedTestAllExtensionsData optional_extension = 3;
+}
+
+message TestNestedChildExtension {
+  optional int32 a = 1;
+  optional TestChildExtension child = 2;
+}
+
+// Emulates wireformat data of TestNestedChildExtension with dynamic extension
+// (DynamicExtension).
+message TestNestedChildExtensionData {
+  optional int32 a = 1;
+  optional TestChildExtensionData child = 2;
+}
+
+// We have separate messages for testing required fields because it's
+// annoying to have to fill in required fields in TestProto in order to
+// do anything with it.  Note that we don't need to test every type of
+// required filed because the code output is basically identical to
+// optional fields for all types.
+message TestRequired {
+  required int32 a = 1;
+  optional int32 dummy2 = 2;
+  required int32 b = 3;
+
+  extend TestAllExtensions {
+    optional TestRequired single = 1000;
+    repeated TestRequired multi  = 1001;
+  }
+
+  // Pad the field count to 32 so that we can test that IsInitialized()
+  // properly checks multiple elements of has_bits_.
+  optional int32 dummy4  =  4;
+  optional int32 dummy5  =  5;
+  optional int32 dummy6  =  6;
+  optional int32 dummy7  =  7;
+  optional int32 dummy8  =  8;
+  optional int32 dummy9  =  9;
+  optional int32 dummy10 = 10;
+  optional int32 dummy11 = 11;
+  optional int32 dummy12 = 12;
+  optional int32 dummy13 = 13;
+  optional int32 dummy14 = 14;
+  optional int32 dummy15 = 15;
+  optional int32 dummy16 = 16;
+  optional int32 dummy17 = 17;
+  optional int32 dummy18 = 18;
+  optional int32 dummy19 = 19;
+  optional int32 dummy20 = 20;
+  optional int32 dummy21 = 21;
+  optional int32 dummy22 = 22;
+  optional int32 dummy23 = 23;
+  optional int32 dummy24 = 24;
+  optional int32 dummy25 = 25;
+  optional int32 dummy26 = 26;
+  optional int32 dummy27 = 27;
+  optional int32 dummy28 = 28;
+  optional int32 dummy29 = 29;
+  optional int32 dummy30 = 30;
+  optional int32 dummy31 = 31;
+  optional int32 dummy32 = 32;
+
+  required int32 c = 33;
+
+  // Add an optional child message to make this non-trivial for go/pdlazy.
+  optional ForeignMessage optional_foreign = 34;
+}
+
+message TestRequiredForeign {
+  optional TestRequired optional_message = 1;
+  repeated TestRequired repeated_message = 2;
+  optional int32 dummy = 3;
+}
+
+message TestRequiredMessage {
+  optional TestRequired optional_message = 1;
+  repeated TestRequired repeated_message = 2;
+  required TestRequired required_message = 3;
+}
+
+message TestNestedRequiredForeign {
+  optional TestNestedRequiredForeign child = 1;
+  optional TestRequiredForeign payload = 2;
+  optional int32 dummy = 3;
+}
+
+// Test that we can use NestedMessage from outside TestAllTypes.
+message TestForeignNested {
+  optional TestAllTypes.NestedMessage foreign_nested = 1;
+}
+
+// TestEmptyMessage is used to test unknown field support.
+message TestEmptyMessage {
+}
+
+// Like above, but declare all field numbers as potential extensions.  No
+// actual extensions should ever be defined for this type.
+message TestEmptyMessageWithExtensions {
+  extensions 1 to max;
+}
+
+// Needed for a Python test.
+message TestPickleNestedMessage {
+  message NestedMessage {
+    optional int32 bb = 1;
+    message NestedNestedMessage {
+      optional int32 cc = 1;
+    }
+  }
+}
+
+message TestMultipleExtensionRanges {
+  extensions 42;
+  extensions 4143 to 4243;
+  extensions 65536 to max;
+}
+
+// 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.
+  optional int32 a = 1;
+  optional int32 bb = 268435455;
+}
+
+message TestRecursiveMessage {
+  optional TestRecursiveMessage a = 1;
+  optional int32 i = 2;
+}
+
+// Test that mutual recursion works.
+message TestMutualRecursionA {
+  message SubMessage {
+    optional TestMutualRecursionB b = 1;
+  }
+  optional TestMutualRecursionB bb = 1;
+  optional group SubGroup = 2 {
+    optional SubMessage sub_message = 3;  // Needed because of bug in javatest
+    optional TestAllTypes not_in_this_scc = 4;
+  }
+}
+
+message TestMutualRecursionB {
+  optional TestMutualRecursionA a = 1;
+  optional int32 optional_int32 = 2;
+}
+
+message TestIsInitialized {
+  message SubMessage {
+    optional group SubGroup = 1 {
+      required int32 i = 2;
+    }
+  }
+  optional SubMessage sub_message = 1;
+}
+
+// Test that groups have disjoint field numbers from their siblings and
+// parents.  This is NOT possible in proto1; only google.protobuf.  When attempting
+// to compile with proto1, this will emit an error; so we only include it
+// in protobuf_unittest_proto.
+message TestDupFieldNumber {                        // NO_PROTO1
+  optional int32 a = 1;                             // NO_PROTO1
+  optional group Foo = 2 { optional int32 a = 1; }  // NO_PROTO1
+  optional group Bar = 3 { optional int32 a = 1; }  // NO_PROTO1
+}                                                   // NO_PROTO1
+
+// Additional messages for testing lazy fields.
+message TestEagerMessage {
+  optional TestAllTypes sub_message = 1 [lazy=false];
+}
+message TestLazyMessage {
+  optional TestAllTypes sub_message = 1 [lazy=true];
+}
+message TestEagerMaybeLazy {
+  message NestedMessage {
+    optional TestPackedTypes packed = 1;
+  }
+  optional TestAllTypes message_foo = 1;
+  optional TestAllTypes message_bar = 2;
+  optional NestedMessage message_baz = 3;
+}
+// Needed for a Python test.
+message TestNestedMessageHasBits {
+  message NestedMessage {
+    repeated int32 nestedmessage_repeated_int32 = 1;
+    repeated ForeignMessage nestedmessage_repeated_foreignmessage = 2;
+  }
+  optional NestedMessage optional_nested_message = 1;
+}
+
+
+// Test an enum that has multiple values with the same number.
+enum TestEnumWithDupValue {
+  option allow_alias = true;
+
+  FOO1 = 1;
+  BAR1 = 2;
+  BAZ = 3;
+  FOO2 = 1;
+  BAR2 = 2;
+}
+
+// Test an enum with large, unordered values.
+enum TestSparseEnum {
+  SPARSE_A = 123;
+  SPARSE_B = 62374;
+  SPARSE_C = 12589234;
+  SPARSE_D = -15;
+  SPARSE_E = -53452;
+  SPARSE_F = 0;
+  SPARSE_G = 2;
+}
+
+// Test message with CamelCase field names.  This violates Protocol Buffer
+// standard style.
+message TestCamelCaseFieldNames {
+  optional int32 PrimitiveField = 1;
+  optional string StringField = 2;
+  optional ForeignEnum EnumField = 3;
+  optional ForeignMessage MessageField = 4;
+  optional string StringPieceField = 5 [ctype=STRING_PIECE];
+  optional string CordField = 6 [ctype=CORD];
+
+  repeated int32 RepeatedPrimitiveField = 7;
+  repeated string RepeatedStringField = 8;
+  repeated ForeignEnum RepeatedEnumField = 9;
+  repeated ForeignMessage RepeatedMessageField = 10;
+  repeated string RepeatedStringPieceField = 11 [ctype=STRING_PIECE];
+  repeated string RepeatedCordField = 12 [ctype=CORD];
+}
+
+
+// We list fields out of order, to ensure that we're using field number and not
+// field index to determine serialization order.
+message TestFieldOrderings {
+  optional string my_string = 11;
+  extensions 2 to 10;
+  optional int64 my_int = 1;
+  extensions 12 to 100;
+  optional float my_float = 101;
+  message NestedMessage {
+    optional int64 oo = 2;
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  optional NestedMessage optional_nested_message  = 200;
+}
+
+extend TestFieldOrderings {
+  optional string my_extension_string = 50;
+  optional int32 my_extension_int = 5;
+}
+
+message TestExtensionOrderings1 {
+  extend TestFieldOrderings {
+    optional TestExtensionOrderings1 test_ext_orderings1 = 13;
+  }
+  optional string my_string = 1;
+}
+
+message TestExtensionOrderings2 {
+  extend TestFieldOrderings {
+    optional TestExtensionOrderings2 test_ext_orderings2 = 12;
+  }
+  message TestExtensionOrderings3 {
+    extend TestFieldOrderings {
+      optional TestExtensionOrderings3 test_ext_orderings3 = 14;
+    }
+    optional string my_string = 1;
+  }
+  optional string my_string = 1;
+}
+
+message TestExtremeDefaultValues {
+  optional bytes escaped_bytes = 1 [default = "\0\001\a\b\f\n\r\t\v\\\'\"\xfe"];
+  optional uint32 large_uint32 = 2 [default = 0xFFFFFFFF];
+  optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF];
+  optional  int32 small_int32  = 4 [default = -0x7FFFFFFF];
+  optional  int64 small_int64  = 5 [default = -0x7FFFFFFFFFFFFFFF];
+  optional  int32 really_small_int32 = 21 [default = -0x80000000];
+  optional  int64 really_small_int64 = 22 [default = -0x8000000000000000];
+
+  // The default value here is UTF-8 for "\u1234".  (We could also just type
+  // the UTF-8 text directly into this text file rather than escape it, but
+  // lots of people use editors that would be confused by this.)
+  optional string utf8_string = 6 [default = "\341\210\264"];
+
+  // Tests for single-precision floating-point values.
+  optional float zero_float = 7 [default = 0];
+  optional float one_float = 8 [default = 1];
+  optional float small_float = 9 [default = 1.5];
+  optional float negative_one_float = 10 [default = -1];
+  optional float negative_float = 11 [default = -1.5];
+  // Using exponents
+  optional float large_float = 12 [default = 2E8];
+  optional float small_negative_float = 13 [default = -8e-28];
+
+  // Text for nonfinite floating-point values.
+  optional double inf_double = 14 [default = inf];
+  optional double neg_inf_double = 15 [default = -inf];
+  optional double nan_double = 16 [default = nan];
+  optional float inf_float = 17 [default = inf];
+  optional float neg_inf_float = 18 [default = -inf];
+  optional float nan_float = 19 [default = nan];
+
+  // Tests for C++ trigraphs.
+  // Trigraphs should be escaped in C++ generated files, but they should not be
+  // escaped for other languages.
+  // Note that in .proto file, "\?" is a valid way to escape ? in string
+  // literals.
+  optional string cpp_trigraph = 20 [default = "? \? ?? \?? \??? ??/ ?\?-"];
+
+  // String defaults containing the character '\000'
+  optional string string_with_zero       = 23 [default = "hel\000lo"];
+  optional  bytes bytes_with_zero        = 24 [default = "wor\000ld"];
+  optional string string_piece_with_zero = 25 [ctype=STRING_PIECE,
+                                               default="ab\000c"];
+  optional string cord_with_zero         = 26 [ctype=CORD,
+                                               default="12\0003"];
+  optional string replacement_string     = 27 [default="${unknown}"];
+}
+
+message SparseEnumMessage {
+  optional TestSparseEnum sparse_enum = 1;
+}
+
+// Test String and Bytes: string is for valid UTF-8 strings
+message OneString {
+  optional string data = 1;
+}
+
+message MoreString {
+  repeated string data = 1;
+}
+
+message OneBytes {
+  optional bytes data = 1;
+}
+
+message MoreBytes {
+  repeated bytes data = 1;
+}
+
+message ManyOptionalString {
+  optional string str1 = 1;
+  optional string str2 = 2;
+  optional string str3 = 3;
+  optional string str4 = 4;
+  optional string str5 = 5;
+  optional string str6 = 6;
+  optional string str7 = 7;
+  optional string str8 = 8;
+  optional string str9 = 9;
+  optional string str10 = 10;
+  optional string str11 = 11;
+  optional string str12 = 12;
+  optional string str13 = 13;
+  optional string str14 = 14;
+  optional string str15 = 15;
+  optional string str16 = 16;
+  optional string str17 = 17;
+  optional string str18 = 18;
+  optional string str19 = 19;
+  optional string str20 = 20;
+  optional string str21 = 21;
+  optional string str22 = 22;
+  optional string str23 = 23;
+  optional string str24 = 24;
+  optional string str25 = 25;
+  optional string str26 = 26;
+  optional string str27 = 27;
+  optional string str28 = 28;
+  optional string str29 = 29;
+  optional string str30 = 30;
+  optional string str31 = 31;
+  optional string str32 = 32;
+}
+
+// Test int32, uint32, int64, uint64, and bool are all compatible
+message Int32Message {
+  optional int32 data = 1;
+}
+
+message Uint32Message {
+  optional uint32 data = 1;
+}
+
+message Int64Message {
+  optional int64 data = 1;
+}
+
+message Uint64Message {
+  optional uint64 data = 1;
+}
+
+message BoolMessage {
+  optional bool data = 1;
+}
+
+// Test oneofs.
+message TestOneof {
+  oneof foo {
+    int32 foo_int = 1;
+    string foo_string = 2;
+    TestAllTypes foo_message = 3;
+    group FooGroup = 4 {
+      optional int32 a = 5;
+      optional string b = 6;
+    }
+  }
+}
+
+message TestOneofBackwardsCompatible {
+  optional int32 foo_int = 1;
+  optional string foo_string = 2;
+  optional TestAllTypes foo_message = 3;
+  optional group FooGroup = 4 {
+    optional int32 a = 5;
+    optional string b = 6;
+  }
+}
+
+message TestOneof2 {
+  oneof foo {
+    int32 foo_int = 1;
+    string foo_string = 2;
+    string foo_cord = 3 [ctype=CORD];
+    string foo_string_piece = 4 [ctype=STRING_PIECE];
+    bytes foo_bytes = 5;
+    NestedEnum foo_enum = 6;
+    NestedMessage foo_message = 7;
+    group FooGroup = 8 {
+      optional int32 a = 9;
+      optional string b = 10;
+    }
+    NestedMessage foo_lazy_message = 11 [lazy=true];
+  }
+
+  oneof bar {
+    int32 bar_int = 12 [default = 5];
+    string bar_string = 13 [default = "STRING"];
+    string bar_cord = 14 [ctype=CORD, default = "CORD"];
+    string bar_string_piece = 15 [ctype=STRING_PIECE, default = "SPIECE"];
+    bytes bar_bytes = 16 [default = "BYTES"];
+    NestedEnum bar_enum = 17 [default = BAR];
+    string bar_string_with_empty_default = 20 [default = ""];
+    string bar_cord_with_empty_default = 21 [ctype=CORD, default = ""];
+    string bar_string_piece_with_empty_default = 22 [ctype=STRING_PIECE, default = ""];
+    bytes bar_bytes_with_empty_default = 23 [default = ""];
+  }
+
+  optional int32 baz_int = 18;
+  optional string baz_string = 19 [default = "BAZ"];
+
+  message NestedMessage {
+    optional int64 moo_int = 1;
+    repeated int32 corge_int = 2;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+}
+
+message TestRequiredOneof {
+  oneof foo {
+    int32 foo_int = 1;
+    string foo_string = 2;
+    NestedMessage foo_message = 3;
+  }
+  message NestedMessage {
+    required double required_double = 1;
+  }
+}
+
+
+// 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 TestPackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensions {
+  repeated    int32 packed_int32_extension    =  90 [packed = true];
+  repeated    int64 packed_int64_extension    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension =  99 [packed = true];
+  repeated    float packed_float_extension    = 100 [packed = true];
+  repeated   double packed_double_extension   = 101 [packed = true];
+  repeated     bool packed_bool_extension     = 102 [packed = true];
+  repeated ForeignEnum packed_enum_extension  = 103 [packed = true];
+}
+
+message TestUnpackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestUnpackedExtensions {
+  repeated    int32 unpacked_int32_extension    =  90 [packed = false];
+  repeated    int64 unpacked_int64_extension    =  91 [packed = false];
+  repeated   uint32 unpacked_uint32_extension   =  92 [packed = false];
+  repeated   uint64 unpacked_uint64_extension   =  93 [packed = false];
+  repeated   sint32 unpacked_sint32_extension   =  94 [packed = false];
+  repeated   sint64 unpacked_sint64_extension   =  95 [packed = false];
+  repeated  fixed32 unpacked_fixed32_extension  =  96 [packed = false];
+  repeated  fixed64 unpacked_fixed64_extension  =  97 [packed = false];
+  repeated sfixed32 unpacked_sfixed32_extension =  98 [packed = false];
+  repeated sfixed64 unpacked_sfixed64_extension =  99 [packed = false];
+  repeated    float unpacked_float_extension    = 100 [packed = false];
+  repeated   double unpacked_double_extension   = 101 [packed = false];
+  repeated     bool unpacked_bool_extension     = 102 [packed = false];
+  repeated ForeignEnum unpacked_enum_extension  = 103 [packed = false];
+}
+
+// Used by ExtensionSetTest/DynamicExtensions.  The test actually builds
+// a set of extensions to TestAllExtensions dynamically, based on the fields
+// of this message type.
+message TestDynamicExtensions {
+  enum DynamicEnumType {
+    DYNAMIC_FOO = 2200;
+    DYNAMIC_BAR = 2201;
+    DYNAMIC_BAZ = 2202;
+  }
+  message DynamicMessageType {
+    optional int32 dynamic_field = 2100;
+  }
+
+  optional fixed32 scalar_extension = 2000;
+  optional ForeignEnum enum_extension = 2001;
+  optional DynamicEnumType dynamic_enum_extension = 2002;
+
+  optional ForeignMessage message_extension = 2003;
+  optional DynamicMessageType dynamic_message_extension = 2004;
+
+  repeated string repeated_extension = 2005;
+  repeated sint32 packed_extension = 2006 [packed = true];
+}
+
+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;
+}
+
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+message TestParsingMerge {
+  // RepeatedFieldsGenerator defines matching field types as TestParsingMerge,
+  // except that all fields are repeated. In the tests, we will serialize the
+  // RepeatedFieldsGenerator to bytes, and parse the bytes to TestParsingMerge.
+  // Repeated fields in RepeatedFieldsGenerator are expected to be merged into
+  // the corresponding required/optional fields in TestParsingMerge.
+  message RepeatedFieldsGenerator {
+    repeated TestAllTypes field1 = 1;
+    repeated TestAllTypes field2 = 2;
+    repeated TestAllTypes field3 = 3;
+    repeated group Group1 = 10 {
+      optional TestAllTypes field1 = 11;
+    }
+    repeated group Group2 = 20 {
+      optional TestAllTypes field1 = 21;
+    }
+    repeated TestAllTypes ext1 = 1000;
+    repeated TestAllTypes ext2 = 1001;
+  }
+  required TestAllTypes required_all_types = 1;
+  optional TestAllTypes optional_all_types = 2;
+  repeated TestAllTypes repeated_all_types = 3;
+  optional group OptionalGroup = 10 {
+    optional TestAllTypes optional_group_all_types = 11;
+  }
+  repeated group RepeatedGroup = 20 {
+    optional TestAllTypes repeated_group_all_types = 21;
+  }
+  extensions 1000 to max;
+  extend TestParsingMerge {
+    optional TestAllTypes optional_ext = 1000;
+    repeated TestAllTypes repeated_ext = 1001;
+  }
+}
+
+// Test that the correct exception is thrown by parseFrom in a corner case
+// involving merging, extensions, and required fields.
+message TestMergeException {
+  optional TestAllExtensions all_extensions = 1;
+}
+
+message TestCommentInjectionMessage {
+  // */ <- This should not close the generated doc comment
+  optional string a = 1 [default="*/ <- Neither should this."];
+}
+
+// Used to check that the c++ code generator re-orders messages to reduce
+// padding.
+message TestMessageSize {
+  optional bool m1 = 1;
+  optional int64 m2 = 2;
+  optional bool m3 = 3;
+  optional string m4 = 4;
+  optional int32 m5 = 5;
+  optional int64 m6 = 6;
+}
+
+
+// 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 {}
+
+message TestJsonName {
+  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"];
+  optional int32 fieldname7 = 7;
+}
+
+message TestHugeFieldNumbers {
+  optional int32 optional_int32 = 536870000;
+  optional int32 fixed_32 = 536870001;
+  repeated int32 repeated_int32 = 536870002 [packed = false];
+  repeated int32 packed_int32 = 536870003 [packed = true];
+
+  optional ForeignEnum optional_enum = 536870004;
+  optional string optional_string = 536870005;
+  optional bytes optional_bytes = 536870006;
+  optional ForeignMessage optional_message = 536870007;
+
+  optional group OptionalGroup = 536870008 {
+    optional int32 group_a = 536870009;
+  }
+
+  map<string, string> string_string_map = 536870010;
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 536870011;
+    TestAllTypes oneof_test_all_types = 536870012;
+    string oneof_string = 536870013;
+    bytes oneof_bytes = 536870014;
+  }
+
+  extensions  536860000 to 536869999;
+}
+
+extend TestHugeFieldNumbers {
+  optional TestAllTypes test_all_types = 536860000;
+}
+
+message TestExtensionInsideTable {
+  optional int32 field1 = 1;
+  optional int32 field2 = 2;
+  optional int32 field3 = 3;
+  optional int32 field4 = 4;
+  extensions 5 to 5;
+  optional int32 field6 = 6;
+  optional int32 field7 = 7;
+  optional int32 field8 = 8;
+  optional int32 field9 = 9;
+  optional int32 field10 = 10;
+}
+
+extend TestExtensionInsideTable {
+  optional int32 test_extension_inside_table_extension = 5;
+}
+
+// NOTE(b/202996544): Intentionally nested to mirror go/glep.
+message TestNestedGroupExtensionOuter {
+  optional group Layer1OptionalGroup = 1 {
+    repeated group Layer2RepeatedGroup = 2 {
+      extensions 3
+        // NOTE: extension metadata is not supported due to targets such as
+        // `//third_party/protobuf_legacy_opensource/src:shell_scripts_test`,
+        // eee https://screenshot.googleplex.com/Axz2QD8nxjdpyFF
+        //[metadata = {
+        // NOTE: can't write type there due to some clever build gen code at
+        // http://google3/net/proto2/internal/BUILD;l=1247;rcl=411090862
+        // type: "protobuf_unittest.TestNestedGroupExtensionInnerExtension",
+        // name: "inner",
+        // }]
+        ;
+      optional string another_field = 6;
+    }
+    repeated group Layer2AnotherOptionalRepeatedGroup = 4 {
+      optional string but_why_tho = 5;
+    }
+  }
+}
+
+message TestNestedGroupExtensionInnerExtension {
+  optional string inner_name= 1;
+}
+
+extend TestNestedGroupExtensionOuter.Layer1OptionalGroup.Layer2RepeatedGroup {
+  optional TestNestedGroupExtensionInnerExtension inner = 3;
+}
+
+enum VeryLargeEnum {
+  ENUM_LABEL_DEFAULT = 0;
+  ENUM_LABEL_1 = 1;
+  ENUM_LABEL_2 = 2;
+  ENUM_LABEL_3 = 3;
+  ENUM_LABEL_4 = 4;
+  ENUM_LABEL_5 = 5;
+  ENUM_LABEL_6 = 6;
+  ENUM_LABEL_7 = 7;
+  ENUM_LABEL_8 = 8;
+  ENUM_LABEL_9 = 9;
+  ENUM_LABEL_10 = 10;
+  ENUM_LABEL_11 = 11;
+  ENUM_LABEL_12 = 12;
+  ENUM_LABEL_13 = 13;
+  ENUM_LABEL_14 = 14;
+  ENUM_LABEL_15 = 15;
+  ENUM_LABEL_16 = 16;
+  ENUM_LABEL_17 = 17;
+  ENUM_LABEL_18 = 18;
+  ENUM_LABEL_19 = 19;
+  ENUM_LABEL_20 = 20;
+  ENUM_LABEL_21 = 21;
+  ENUM_LABEL_22 = 22;
+  ENUM_LABEL_23 = 23;
+  ENUM_LABEL_24 = 24;
+  ENUM_LABEL_25 = 25;
+  ENUM_LABEL_26 = 26;
+  ENUM_LABEL_27 = 27;
+  ENUM_LABEL_28 = 28;
+  ENUM_LABEL_29 = 29;
+  ENUM_LABEL_30 = 30;
+  ENUM_LABEL_31 = 31;
+  ENUM_LABEL_32 = 32;
+  ENUM_LABEL_33 = 33;
+  ENUM_LABEL_34 = 34;
+  ENUM_LABEL_35 = 35;
+  ENUM_LABEL_36 = 36;
+  ENUM_LABEL_37 = 37;
+  ENUM_LABEL_38 = 38;
+  ENUM_LABEL_39 = 39;
+  ENUM_LABEL_40 = 40;
+  ENUM_LABEL_41 = 41;
+  ENUM_LABEL_42 = 42;
+  ENUM_LABEL_43 = 43;
+  ENUM_LABEL_44 = 44;
+  ENUM_LABEL_45 = 45;
+  ENUM_LABEL_46 = 46;
+  ENUM_LABEL_47 = 47;
+  ENUM_LABEL_48 = 48;
+  ENUM_LABEL_49 = 49;
+  ENUM_LABEL_50 = 50;
+  ENUM_LABEL_51 = 51;
+  ENUM_LABEL_52 = 52;
+  ENUM_LABEL_53 = 53;
+  ENUM_LABEL_54 = 54;
+  ENUM_LABEL_55 = 55;
+  ENUM_LABEL_56 = 56;
+  ENUM_LABEL_57 = 57;
+  ENUM_LABEL_58 = 58;
+  ENUM_LABEL_59 = 59;
+  ENUM_LABEL_60 = 60;
+  ENUM_LABEL_61 = 61;
+  ENUM_LABEL_62 = 62;
+  ENUM_LABEL_63 = 63;
+  ENUM_LABEL_64 = 64;
+  ENUM_LABEL_65 = 65;
+  ENUM_LABEL_66 = 66;
+  ENUM_LABEL_67 = 67;
+  ENUM_LABEL_68 = 68;
+  ENUM_LABEL_69 = 69;
+  ENUM_LABEL_70 = 70;
+  ENUM_LABEL_71 = 71;
+  ENUM_LABEL_72 = 72;
+  ENUM_LABEL_73 = 73;
+  ENUM_LABEL_74 = 74;
+  ENUM_LABEL_75 = 75;
+  ENUM_LABEL_76 = 76;
+  ENUM_LABEL_77 = 77;
+  ENUM_LABEL_78 = 78;
+  ENUM_LABEL_79 = 79;
+  ENUM_LABEL_80 = 80;
+  ENUM_LABEL_81 = 81;
+  ENUM_LABEL_82 = 82;
+  ENUM_LABEL_83 = 83;
+  ENUM_LABEL_84 = 84;
+  ENUM_LABEL_85 = 85;
+  ENUM_LABEL_86 = 86;
+  ENUM_LABEL_87 = 87;
+  ENUM_LABEL_88 = 88;
+  ENUM_LABEL_89 = 89;
+  ENUM_LABEL_90 = 90;
+  ENUM_LABEL_91 = 91;
+  ENUM_LABEL_92 = 92;
+  ENUM_LABEL_93 = 93;
+  ENUM_LABEL_94 = 94;
+  ENUM_LABEL_95 = 95;
+  ENUM_LABEL_96 = 96;
+  ENUM_LABEL_97 = 97;
+  ENUM_LABEL_98 = 98;
+  ENUM_LABEL_99 = 99;
+  ENUM_LABEL_100 = 100;
+};
+
+message TestExtensionRangeSerialize {
+  optional int32 foo_one = 1;
+
+  extensions 2 to 2;
+  extensions 3 to 4;
+
+  optional int32 foo_two = 6;
+  optional int32 foo_three = 7;
+
+  extensions 9 to 10;
+
+  optional int32 foo_four = 13;
+
+  extensions 15 to 15;
+  extensions 17 to 17;
+  extensions 19 to 19;
+
+  extend TestExtensionRangeSerialize {
+    optional int32 bar_one = 2;
+    optional int32 bar_two = 4;
+
+    optional int32 bar_three = 10;
+
+    optional int32 bar_four = 15;
+    optional int32 bar_five = 19;
+  }
+}
+
+message TestVerifyInt32Simple {
+    optional int32 optional_int32_1 = 1;
+    optional int32 optional_int32_2 = 2;
+    optional int32 optional_int32_63 = 63;
+    optional int32 optional_int32_64 = 64;
+}
+
+message TestVerifyInt32 {
+    optional int32 optional_int32_1 = 1;
+    optional int32 optional_int32_2 = 2;
+    optional int32 optional_int32_63 = 63;
+    optional int32 optional_int32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyMostlyInt32 {
+    optional int64 optional_int64_30 = 30;
+
+    optional int32 optional_int32_1 = 1;
+    optional int32 optional_int32_2 = 2;
+    optional int32 optional_int32_3 = 3;
+    optional int32 optional_int32_4 = 4;
+    optional int32 optional_int32_63 = 63;
+    optional int32 optional_int32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyMostlyInt32BigFieldNumber {
+    optional int64 optional_int64_30 = 30;
+    optional int32 optional_int32_300 = 300;
+
+    optional int32 optional_int32_1 = 1;
+    optional int32 optional_int32_2 = 2;
+    optional int32 optional_int32_3 = 3;
+    optional int32 optional_int32_4 = 4;
+    optional int32 optional_int32_63 = 63;
+    optional int32 optional_int32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyUint32Simple {
+    optional uint32 optional_uint32_1 = 1;
+    optional uint32 optional_uint32_2 = 2;
+    optional uint32 optional_uint32_63 = 63;
+    optional uint32 optional_uint32_64 = 64;
+}
+
+message TestVerifyUint32 {
+    optional uint32 optional_uint32_1 = 1;
+    optional uint32 optional_uint32_2 = 2;
+    optional uint32 optional_uint32_63 = 63;
+    optional uint32 optional_uint32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyOneUint32 {
+    optional uint32 optional_uint32_1 = 1;
+    optional int32 optional_int32_2 = 2;
+    optional int32 optional_int32_63 = 63;
+    optional int32 optional_int32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyOneInt32BigFieldNumber {
+    optional int32 optional_int32_65 = 65;
+
+    optional int64 optional_int64_1 = 1;
+    optional int64 optional_int64_2 = 2;
+    optional int64 optional_int64_63 = 63;
+    optional int64 optional_int64_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyInt32BigFieldNumber {
+    optional int32 optional_int32_1000 = 1000;
+    optional int32 optional_int32_65 = 65;
+
+    optional int32 optional_int32_1 = 1;
+    optional int32 optional_int32_2 = 2;
+    optional int32 optional_int32_63 = 63;
+    optional int32 optional_int32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyUint32BigFieldNumber {
+    optional uint32 optional_uint32_1000 = 1000;
+    optional uint32 optional_uint32_65 = 65;
+
+    optional uint32 optional_uint32_1 = 1;
+    optional uint32 optional_uint32_2 = 2;
+    optional uint32 optional_uint32_63 = 63;
+    optional uint32 optional_uint32_64 = 64;
+
+    optional TestAllTypes optional_all_types = 9;
+    repeated TestAllTypes repeated_all_types = 10;
+}
+
+message TestVerifyBigFieldNumberUint32 {
+  message Nested {
+    optional uint32 optional_uint32_5000 = 5000;
+    optional uint32 optional_uint32_1000 = 1000;
+    optional uint32 optional_uint32_66 = 66;
+    optional uint32 optional_uint32_65 = 65;
+
+    optional uint32 optional_uint32_1 = 1;
+    optional uint32 optional_uint32_2 = 2;
+    optional uint32 optional_uint32_63 = 63;
+    optional uint32 optional_uint32_64 = 64;
+
+    optional Nested optional_nested = 9;
+    repeated Nested repeated_nested = 10;
+  }
+  optional Nested optional_nested = 1;
+}
+
+
diff --git a/src/google/protobuf/unittest_arena.proto b/src/google/protobuf/unittest_arena.proto
new file mode 100644
index 0000000..7b31739
--- /dev/null
+++ b/src/google/protobuf/unittest_arena.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.
+
+syntax = "proto2";
+
+package proto2_arena_unittest;
+
+option cc_enable_arenas = true;
+
+message NestedMessage {
+  optional int32 d = 1;
+}
+
+message ArenaMessage {
+  repeated NestedMessage repeated_nested_message = 1;
+}
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
new file mode 100644
index 0000000..d741661
--- /dev/null
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -0,0 +1,466 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: benjy@google.com (Benjy Weinberger)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file used to test the "custom options" feature of google.protobuf.
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;    // auto-added
+option java_generic_services = true;  // auto-added
+option py_generic_services = true;
+
+// A custom file option (defined below).
+option (file_opt1) = 9876543210;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/descriptor.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.
+package protobuf_unittest;
+
+// Some simple test custom options of various types.
+
+extend google.protobuf.FileOptions {
+  optional uint64 file_opt1 = 7736974;
+}
+
+extend google.protobuf.MessageOptions {
+  optional int32 message_opt1 = 7739036;
+}
+
+extend google.protobuf.FieldOptions {
+  optional fixed64 field_opt1 = 7740936;
+  // This is useful for testing that we correctly register default values for
+  // extension options.
+  optional int32 field_opt2 = 7753913 [default = 42];
+}
+
+extend google.protobuf.OneofOptions {
+  optional int32 oneof_opt1 = 7740111;
+}
+
+extend google.protobuf.EnumOptions {
+  optional sfixed32 enum_opt1 = 7753576;
+}
+
+extend google.protobuf.EnumValueOptions {
+  optional int32 enum_value_opt1 = 1560678;
+}
+
+extend google.protobuf.ServiceOptions {
+  optional sint64 service_opt1 = 7887650;
+}
+
+enum MethodOpt1 {
+  METHODOPT1_VAL1 = 1;
+  METHODOPT1_VAL2 = 2;
+}
+
+extend google.protobuf.MethodOptions {
+  optional MethodOpt1 method_opt1 = 7890860;
+}
+
+// A test message with custom options at all possible locations (and also some
+// regular options, to make sure they interact nicely).
+message TestMessageWithCustomOptions {
+  option message_set_wire_format = false;
+  option (message_opt1) = -56;
+
+  optional string field1 = 1 [ctype = CORD, (field_opt1) = 8765432109];
+
+  oneof AnOneof {
+    option (oneof_opt1) = -99;
+
+    int32 oneof_field = 2;
+  }
+
+  map<string, string> map_field = 3 [(field_opt1) = 12345];
+
+  enum AnEnum {
+    option (enum_opt1) = -789;
+
+    ANENUM_VAL1 = 1;
+    ANENUM_VAL2 = 2 [(enum_value_opt1) = 123];
+  }
+}
+
+// A test RPC service with custom options at all possible locations (and also
+// some regular options, to make sure they interact nicely).
+message CustomOptionFooRequest {}
+
+message CustomOptionFooResponse {}
+
+message CustomOptionFooClientMessage {}
+
+message CustomOptionFooServerMessage {}
+
+service TestServiceWithCustomOptions {
+  option (service_opt1) = -9876543210;
+
+  rpc Foo(CustomOptionFooRequest) returns (CustomOptionFooResponse) {
+    option (method_opt1) = METHODOPT1_VAL2;
+  }
+}
+
+// Options of every possible field type, so we can test them all exhaustively.
+
+message DummyMessageContainingEnum {
+  enum TestEnumType {
+    TEST_OPTION_ENUM_TYPE1 = 22;
+    TEST_OPTION_ENUM_TYPE2 = -23;
+  }
+}
+
+message DummyMessageInvalidAsOptionType {}
+
+extend google.protobuf.MessageOptions {
+  optional bool bool_opt = 7706090;
+  optional int32 int32_opt = 7705709;
+  optional int64 int64_opt = 7705542;
+  optional uint32 uint32_opt = 7704880;
+  optional uint64 uint64_opt = 7702367;
+  optional sint32 sint32_opt = 7701568;
+  optional sint64 sint64_opt = 7700863;
+  optional fixed32 fixed32_opt = 7700307;
+  optional fixed64 fixed64_opt = 7700194;
+  optional sfixed32 sfixed32_opt = 7698645;
+  optional sfixed64 sfixed64_opt = 7685475;
+  optional float float_opt = 7675390;
+  optional double double_opt = 7673293;
+  optional string string_opt = 7673285;
+  optional bytes bytes_opt = 7673238;
+  optional DummyMessageContainingEnum.TestEnumType enum_opt = 7673233;
+  optional DummyMessageInvalidAsOptionType message_type_opt = 7665967;
+}
+
+message CustomOptionMinIntegerValues {
+  option (bool_opt) = false;
+  option (int32_opt) = -0x80000000;
+  option (int64_opt) = -0x8000000000000000;
+  option (uint32_opt) = 0;
+  option (uint64_opt) = 0;
+  option (sint32_opt) = -0x80000000;
+  option (sint64_opt) = -0x8000000000000000;
+  option (fixed32_opt) = 0;
+  option (fixed64_opt) = 0;
+  option (sfixed32_opt) = -0x80000000;
+  option (sfixed64_opt) = -0x8000000000000000;
+}
+
+message CustomOptionMaxIntegerValues {
+  option (bool_opt) = true;
+  option (int32_opt) = 0x7FFFFFFF;
+  option (int64_opt) = 0x7FFFFFFFFFFFFFFF;
+  option (uint32_opt) = 0xFFFFFFFF;
+  option (uint64_opt) = 0xFFFFFFFFFFFFFFFF;
+  option (sint32_opt) = 0x7FFFFFFF;
+  option (sint64_opt) = 0x7FFFFFFFFFFFFFFF;
+  option (fixed32_opt) = 0xFFFFFFFF;
+  option (fixed64_opt) = 0xFFFFFFFFFFFFFFFF;
+  option (sfixed32_opt) = 0x7FFFFFFF;
+  option (sfixed64_opt) = 0x7FFFFFFFFFFFFFFF;
+}
+
+message CustomOptionOtherValues {
+  option (int32_opt) = -100;  // To test sign-extension.
+  option (float_opt) = 12.3456789;
+  option (double_opt) = 1.234567890123456789;
+  option (string_opt) = "Hello, \"World\"";
+  option (bytes_opt) = "Hello\0World";
+  option (enum_opt) = TEST_OPTION_ENUM_TYPE2;
+}
+
+message SettingRealsFromPositiveInts {
+  option (float_opt) = 12;
+  option (double_opt) = 154;
+}
+
+message SettingRealsFromNegativeInts {
+  option (float_opt) = -12;
+  option (double_opt) = -154;
+}
+
+// Options of complex message types, themselves combined and extended in
+// various ways.
+
+message ComplexOptionType1 {
+  optional int32 foo = 1;
+  optional int32 foo2 = 2;
+  optional int32 foo3 = 3;
+  repeated int32 foo4 = 4;
+
+  extensions 100 to max;
+}
+
+message ComplexOptionType2 {
+  optional ComplexOptionType1 bar = 1;
+  optional int32 baz = 2;
+
+  message ComplexOptionType4 {
+    optional int32 waldo = 1;
+
+    extend google.protobuf.MessageOptions {
+      optional ComplexOptionType4 complex_opt4 = 7633546;
+    }
+  }
+
+  optional ComplexOptionType4 fred = 3;
+  repeated ComplexOptionType4 barney = 4;
+
+  extensions 100 to max;
+}
+
+message ComplexOptionType3 {
+  optional int32 moo = 1;
+
+  optional group ComplexOptionType5 = 2 {
+    optional int32 plugh = 3;
+  }
+}
+
+extend ComplexOptionType1 {
+  optional int32 mooo = 7663707;
+  optional ComplexOptionType3 corge = 7663442;
+}
+
+extend ComplexOptionType2 {
+  optional int32 grault = 7650927;
+  optional ComplexOptionType1 garply = 7649992;
+}
+
+extend google.protobuf.MessageOptions {
+  optional protobuf_unittest.ComplexOptionType1 complex_opt1 = 7646756;
+  optional ComplexOptionType2 complex_opt2 = 7636949;
+  optional ComplexOptionType3 complex_opt3 = 7636463;
+  optional group ComplexOpt6 = 7595468 {
+    optional int32 xyzzy = 7593951;
+  }
+}
+
+// Note that we try various different ways of naming the same extension.
+message VariousComplexOptions {
+  option (.protobuf_unittest.complex_opt1).foo = 42;
+  option (protobuf_unittest.complex_opt1).(.protobuf_unittest.mooo) = 324;
+  option (.protobuf_unittest.complex_opt1).(protobuf_unittest.corge).moo = 876;
+  option (protobuf_unittest.complex_opt1).foo4 = 99;
+  option (protobuf_unittest.complex_opt1).foo4 = 88;
+  option (complex_opt2).baz = 987;
+  option (complex_opt2).(grault) = 654;
+  option (complex_opt2).bar.foo = 743;
+  option (complex_opt2).bar.(mooo) = 1999;
+  option (complex_opt2).bar.(protobuf_unittest.corge).moo = 2008;
+  option (complex_opt2).(garply).foo = 741;
+  option (complex_opt2).(garply).(.protobuf_unittest.mooo) = 1998;
+  option (complex_opt2).(protobuf_unittest.garply).(corge).moo = 2121;
+  option (ComplexOptionType2.ComplexOptionType4.complex_opt4).waldo = 1971;
+  option (complex_opt2).fred.waldo = 321;
+  option (complex_opt2).barney = {
+    waldo: 101
+  };
+  option (complex_opt2).barney = {
+    waldo: 212
+  };
+  option (protobuf_unittest.complex_opt3).moo = 9;
+  option (complex_opt3).complexoptiontype5.plugh = 22;
+  option (complexopt6).xyzzy = 24;
+}
+
+// ------------------------------------------------------
+// Definitions for testing aggregate option parsing.
+// See descriptor_unittest.cc.
+
+message AggregateMessageSet {
+  option message_set_wire_format = true;
+
+  extensions 4 to max;
+}
+
+message AggregateMessageSetElement {
+  extend AggregateMessageSet {
+    optional AggregateMessageSetElement message_set_extension = 15447542;
+  }
+  optional string s = 1;
+}
+
+// A helper type used to test aggregate option parsing
+message Aggregate {
+  optional int32 i = 1;
+  optional string s = 2;
+
+  // A nested object
+  optional Aggregate sub = 3;
+
+  // To test the parsing of extensions inside aggregate values
+  optional google.protobuf.FileOptions file = 4;
+  extend google.protobuf.FileOptions {
+    optional Aggregate nested = 15476903;
+  }
+
+  // An embedded message set
+  optional AggregateMessageSet mset = 5;
+
+  // An any
+  optional google.protobuf.Any any = 6;
+}
+
+// Allow Aggregate to be used as an option at all possible locations
+// in the .proto grammar.
+extend google.protobuf.FileOptions {
+  optional Aggregate fileopt = 15478479;
+}
+extend google.protobuf.MessageOptions {
+  optional Aggregate msgopt = 15480088;
+}
+extend google.protobuf.FieldOptions {
+  optional Aggregate fieldopt = 15481374;
+}
+extend google.protobuf.EnumOptions {
+  optional Aggregate enumopt = 15483218;
+}
+extend google.protobuf.EnumValueOptions {
+  optional Aggregate enumvalopt = 15486921;
+}
+extend google.protobuf.ServiceOptions {
+  optional Aggregate serviceopt = 15497145;
+}
+extend google.protobuf.MethodOptions {
+  optional Aggregate methodopt = 15512713;
+}
+
+// Try using AggregateOption at different points in the proto grammar
+option (fileopt) = {
+  s: 'FileAnnotation'
+  // Also test the handling of comments
+  /* of both types */
+  i: 100
+
+  sub { s: 'NestedFileAnnotation' }
+
+  // Include a google.protobuf.FileOptions and recursively extend it with
+  // another fileopt.
+  file {
+    [protobuf_unittest.fileopt] { s: 'FileExtensionAnnotation' }
+  }
+
+  // A message set inside an option value
+  mset {
+    [protobuf_unittest.AggregateMessageSetElement.message_set_extension] {
+      s: 'EmbeddedMessageSetElement'
+    }
+  }
+
+  any {
+    [type.googleapis.com/protobuf_unittest.AggregateMessageSetElement] {
+      s: 'EmbeddedMessageSetElement'
+    }
+  }
+};
+
+message AggregateMessage {
+  option (msgopt) = {
+    i: 101
+    s: 'MessageAnnotation'
+  };
+
+  optional int32 fieldname = 1 [(fieldopt) = { s: 'FieldAnnotation' }];
+}
+
+service AggregateService {
+  option (serviceopt) = {
+    s: 'ServiceAnnotation'
+  };
+
+  rpc Method(AggregateMessage) returns (AggregateMessage) {
+    option (methodopt) = {
+      s: 'MethodAnnotation'
+    };
+  }
+}
+
+enum AggregateEnum {
+  option (enumopt) = {
+    s: 'EnumAnnotation'
+  };
+
+  VALUE = 1 [(enumvalopt) = { s: 'EnumValueAnnotation' }];
+}
+
+// Test custom options for nested type.
+message NestedOptionType {
+  message NestedMessage {
+    option (message_opt1) = 1001;
+
+    optional int32 nested_field = 1 [(field_opt1) = 1002];
+  }
+  enum NestedEnum {
+    option (enum_opt1) = 1003;
+
+    NESTED_ENUM_VALUE = 1 [(enum_value_opt1) = 1004];
+  }
+  extend google.protobuf.FileOptions {
+    optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
+  }
+}
+
+// Custom message option that has a required enum field.
+// WARNING: this is strongly discouraged!
+message OldOptionType {
+  enum TestEnum {
+    OLD_VALUE = 0;
+  }
+  required TestEnum value = 1;
+}
+
+// Updated version of the custom option above.
+message NewOptionType {
+  enum TestEnum {
+    OLD_VALUE = 0;
+    NEW_VALUE = 1;
+  }
+  required TestEnum value = 1;
+}
+
+extend google.protobuf.MessageOptions {
+  optional OldOptionType required_enum_opt = 106161807;
+}
+
+// Test message using the "required_enum_opt" option defined above.
+message TestMessageWithRequiredEnumOption {
+  option (required_enum_opt) = {
+    value: OLD_VALUE
+  };
+}
diff --git a/src/google/protobuf/unittest_drop_unknown_fields.proto b/src/google/protobuf/unittest_drop_unknown_fields.proto
new file mode 100644
index 0000000..a8a98ad
--- /dev/null
+++ b/src/google/protobuf/unittest_drop_unknown_fields.proto
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package unittest_drop_unknown_fields;
+
+option objc_class_prefix = "DropUnknowns";
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+message Foo {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
+}
+
+message FooWithExtraFields {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    MOO = 3;
+  }
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
+  int32 extra_int32_value = 3;
+}
diff --git a/src/google/protobuf/unittest_embed_optimize_for.proto b/src/google/protobuf/unittest_embed_optimize_for.proto
new file mode 100644
index 0000000..d8b0f9b
--- /dev/null
+++ b/src/google/protobuf/unittest_embed_optimize_for.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: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which imports a proto file that uses optimize_for = CODE_SIZE.
+
+syntax = "proto2";
+import "google/protobuf/unittest_optimize_for.proto";
+
+package protobuf_unittest;
+
+// We optimize for speed here, but we are importing a proto that is optimized
+// for code size.
+option optimize_for = SPEED;
+
+message TestEmbedOptimizedForSize {
+  // Test that embedding a message which has optimize_for = CODE_SIZE into
+  // one optimized for speed works.
+  optional TestOptimizedForSize optional_message = 1;
+  repeated TestOptimizedForSize repeated_message = 2;
+}
diff --git a/src/google/protobuf/unittest_empty.proto b/src/google/protobuf/unittest_empty.proto
new file mode 100644
index 0000000..36443e7
--- /dev/null
+++ b/src/google/protobuf/unittest_empty.proto
@@ -0,0 +1,38 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file intentionally left blank.  (At one point this wouldn't compile
+// correctly.)
+
+syntax = "proto2";
diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto
new file mode 100644
index 0000000..c700a27
--- /dev/null
+++ b/src/google/protobuf/unittest_enormous_descriptor.proto
@@ -0,0 +1,1048 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 that has an extremely large descriptor.  Used to test that
+// descriptors over 64k don't break language-specific limits in generated code,
+// such as the string literal length limit in Java.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+option java_package = "com.google.protobuf";
+
+// Avoid generating insanely long methods.
+option optimize_for = CODE_SIZE;
+
+message TestEnormousDescriptor {
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1 = 1 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_2 = 2 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_3 = 3 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_4 = 4 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_5 = 5 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_6 = 6 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_7 = 7 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_8 = 8 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_9 = 9 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_10 = 10 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_11 = 11 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_12 = 12 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_13 = 13 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_14 = 14 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_15 = 15 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_16 = 16 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_17 = 17 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_18 = 18 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_19 = 19 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_20 = 20 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_21 = 21 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_22 = 22 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_23 = 23 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_24 = 24 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_25 = 25 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_26 = 26 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_27 = 27 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_28 = 28 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_29 = 29 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_30 = 30 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_31 = 31 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_32 = 32 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_33 = 33 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_34 = 34 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_35 = 35 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_36 = 36 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_37 = 37 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_38 = 38 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_39 = 39 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_40 = 40 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_41 = 41 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_42 = 42 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_43 = 43 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_44 = 44 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_45 = 45 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_46 = 46 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_47 = 47 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_48 = 48 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_49 = 49 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_50 = 50 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_51 = 51 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_52 = 52 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_53 = 53 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_54 = 54 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_55 = 55 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_56 = 56 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_57 = 57 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_58 = 58 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_59 = 59 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_60 = 60 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_61 = 61 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_62 = 62 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_63 = 63 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_64 = 64 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_65 = 65 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_66 = 66 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_67 = 67 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_68 = 68 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_69 = 69 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_70 = 70 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_71 = 71 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_72 = 72 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_73 = 73 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_74 = 74 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_75 = 75 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_76 = 76 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_77 = 77 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_78 = 78 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_79 = 79 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_80 = 80 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_81 = 81 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_82 = 82 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_83 = 83 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_84 = 84 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_85 = 85 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_86 = 86 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_87 = 87 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_88 = 88 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_89 = 89 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_90 = 90 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_91 = 91 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_92 = 92 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_93 = 93 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_94 = 94 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_95 = 95 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_96 = 96 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_97 = 97 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_98 = 98 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_99 = 99 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_100 = 100 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_101 = 101 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_102 = 102 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_103 = 103 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_104 = 104 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_105 = 105 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_106 = 106 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_107 = 107 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_108 = 108 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_109 = 109 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_110 = 110 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_111 = 111 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_112 = 112 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_113 = 113 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_114 = 114 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_115 = 115 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_116 = 116 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_117 = 117 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_118 = 118 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_119 = 119 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_120 = 120 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_121 = 121 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_122 = 122 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_123 = 123 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_124 = 124 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_125 = 125 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_126 = 126 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_127 = 127 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_128 = 128 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_129 = 129 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_130 = 130 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_131 = 131 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_132 = 132 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_133 = 133 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_134 = 134 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_135 = 135 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_136 = 136 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_137 = 137 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_138 = 138 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_139 = 139 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_140 = 140 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_141 = 141 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_142 = 142 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_143 = 143 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_144 = 144 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_145 = 145 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_146 = 146 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_147 = 147 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_148 = 148 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_149 = 149 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_150 = 150 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_151 = 151 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_152 = 152 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_153 = 153 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_154 = 154 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_155 = 155 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_156 = 156 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_157 = 157 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_158 = 158 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_159 = 159 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_160 = 160 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_161 = 161 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_162 = 162 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_163 = 163 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_164 = 164 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_165 = 165 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_166 = 166 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_167 = 167 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_168 = 168 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_169 = 169 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_170 = 170 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_171 = 171 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_172 = 172 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_173 = 173 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_174 = 174 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_175 = 175 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_176 = 176 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_177 = 177 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_178 = 178 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_179 = 179 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_180 = 180 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_181 = 181 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_182 = 182 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_183 = 183 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_184 = 184 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_185 = 185 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_186 = 186 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_187 = 187 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_188 = 188 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_189 = 189 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_190 = 190 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_191 = 191 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_192 = 192 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_193 = 193 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_194 = 194 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_195 = 195 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_196 = 196 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_197 = 197 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_198 = 198 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_199 = 199 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_200 = 200 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_201 = 201 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_202 = 202 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_203 = 203 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_204 = 204 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_205 = 205 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_206 = 206 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_207 = 207 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_208 = 208 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_209 = 209 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_210 = 210 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_211 = 211 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_212 = 212 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_213 = 213 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_214 = 214 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_215 = 215 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_216 = 216 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_217 = 217 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_218 = 218 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_219 = 219 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_220 = 220 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_221 = 221 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_222 = 222 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_223 = 223 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_224 = 224 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_225 = 225 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_226 = 226 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_227 = 227 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_228 = 228 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_229 = 229 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_230 = 230 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_231 = 231 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_232 = 232 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_233 = 233 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_234 = 234 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_235 = 235 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_236 = 236 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_237 = 237 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_238 = 238 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_239 = 239 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_240 = 240 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_241 = 241 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_242 = 242 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_243 = 243 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_244 = 244 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_245 = 245 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_246 = 246 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_247 = 247 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_248 = 248 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_249 = 249 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_250 = 250 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_251 = 251 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_252 = 252 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_253 = 253 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_254 = 254 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_255 = 255 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_256 = 256 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_257 = 257 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_258 = 258 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_259 = 259 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_260 = 260 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_261 = 261 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_262 = 262 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_263 = 263 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_264 = 264 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_265 = 265 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_266 = 266 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_267 = 267 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_268 = 268 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_269 = 269 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_270 = 270 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_271 = 271 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_272 = 272 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_273 = 273 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_274 = 274 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_275 = 275 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_276 = 276 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_277 = 277 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_278 = 278 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_279 = 279 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_280 = 280 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_281 = 281 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_282 = 282 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_283 = 283 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_284 = 284 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_285 = 285 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_286 = 286 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_287 = 287 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_288 = 288 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_289 = 289 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_290 = 290 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_291 = 291 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_292 = 292 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_293 = 293 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_294 = 294 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_295 = 295 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_296 = 296 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_297 = 297 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_298 = 298 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_299 = 299 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_300 = 300 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_301 = 301 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_302 = 302 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_303 = 303 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_304 = 304 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_305 = 305 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_306 = 306 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_307 = 307 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_308 = 308 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_309 = 309 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_310 = 310 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_311 = 311 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_312 = 312 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_313 = 313 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_314 = 314 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_315 = 315 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_316 = 316 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_317 = 317 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_318 = 318 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_319 = 319 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_320 = 320 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_321 = 321 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_322 = 322 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_323 = 323 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_324 = 324 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_325 = 325 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_326 = 326 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_327 = 327 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_328 = 328 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_329 = 329 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_330 = 330 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_331 = 331 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_332 = 332 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_333 = 333 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_334 = 334 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_335 = 335 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_336 = 336 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_337 = 337 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_338 = 338 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_339 = 339 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_340 = 340 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_341 = 341 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_342 = 342 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_343 = 343 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_344 = 344 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_345 = 345 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_346 = 346 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_347 = 347 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_348 = 348 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_349 = 349 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_350 = 350 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_351 = 351 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_352 = 352 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_353 = 353 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_354 = 354 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_355 = 355 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_356 = 356 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_357 = 357 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_358 = 358 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_359 = 359 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_360 = 360 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_361 = 361 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_362 = 362 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_363 = 363 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_364 = 364 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_365 = 365 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_366 = 366 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_367 = 367 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_368 = 368 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_369 = 369 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_370 = 370 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_371 = 371 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_372 = 372 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_373 = 373 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_374 = 374 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_375 = 375 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_376 = 376 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_377 = 377 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_378 = 378 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_379 = 379 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_380 = 380 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_381 = 381 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_382 = 382 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_383 = 383 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_384 = 384 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_385 = 385 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_386 = 386 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_387 = 387 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_388 = 388 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_389 = 389 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_390 = 390 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_391 = 391 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_392 = 392 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_393 = 393 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_394 = 394 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_395 = 395 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_396 = 396 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_397 = 397 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_398 = 398 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_399 = 399 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_400 = 400 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_401 = 401 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_402 = 402 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_403 = 403 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_404 = 404 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_405 = 405 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_406 = 406 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_407 = 407 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_408 = 408 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_409 = 409 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_410 = 410 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_411 = 411 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_412 = 412 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_413 = 413 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_414 = 414 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_415 = 415 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_416 = 416 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_417 = 417 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_418 = 418 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_419 = 419 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_420 = 420 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_421 = 421 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_422 = 422 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_423 = 423 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_424 = 424 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_425 = 425 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_426 = 426 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_427 = 427 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_428 = 428 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_429 = 429 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_430 = 430 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_431 = 431 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_432 = 432 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_433 = 433 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_434 = 434 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_435 = 435 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_436 = 436 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_437 = 437 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_438 = 438 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_439 = 439 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_440 = 440 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_441 = 441 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_442 = 442 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_443 = 443 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_444 = 444 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_445 = 445 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_446 = 446 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_447 = 447 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_448 = 448 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_449 = 449 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_450 = 450 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_451 = 451 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_452 = 452 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_453 = 453 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_454 = 454 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_455 = 455 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_456 = 456 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_457 = 457 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_458 = 458 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_459 = 459 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_460 = 460 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_461 = 461 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_462 = 462 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_463 = 463 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_464 = 464 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_465 = 465 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_466 = 466 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_467 = 467 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_468 = 468 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_469 = 469 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_470 = 470 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_471 = 471 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_472 = 472 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_473 = 473 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_474 = 474 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_475 = 475 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_476 = 476 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_477 = 477 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_478 = 478 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_479 = 479 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_480 = 480 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_481 = 481 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_482 = 482 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_483 = 483 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_484 = 484 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_485 = 485 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_486 = 486 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_487 = 487 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_488 = 488 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_489 = 489 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_490 = 490 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_491 = 491 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_492 = 492 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_493 = 493 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_494 = 494 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_495 = 495 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_496 = 496 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_497 = 497 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_498 = 498 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_499 = 499 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_500 = 500 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_501 = 501 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_502 = 502 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_503 = 503 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_504 = 504 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_505 = 505 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_506 = 506 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_507 = 507 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_508 = 508 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_509 = 509 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_510 = 510 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_511 = 511 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_512 = 512 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_513 = 513 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_514 = 514 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_515 = 515 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_516 = 516 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_517 = 517 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_518 = 518 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_519 = 519 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_520 = 520 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_521 = 521 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_522 = 522 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_523 = 523 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_524 = 524 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_525 = 525 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_526 = 526 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_527 = 527 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_528 = 528 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_529 = 529 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_530 = 530 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_531 = 531 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_532 = 532 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_533 = 533 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_534 = 534 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_535 = 535 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_536 = 536 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_537 = 537 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_538 = 538 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_539 = 539 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_540 = 540 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_541 = 541 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_542 = 542 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_543 = 543 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_544 = 544 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_545 = 545 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_546 = 546 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_547 = 547 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_548 = 548 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_549 = 549 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_550 = 550 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_551 = 551 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_552 = 552 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_553 = 553 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_554 = 554 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_555 = 555 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_556 = 556 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_557 = 557 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_558 = 558 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_559 = 559 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_560 = 560 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_561 = 561 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_562 = 562 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_563 = 563 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_564 = 564 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_565 = 565 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_566 = 566 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_567 = 567 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_568 = 568 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_569 = 569 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_570 = 570 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_571 = 571 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_572 = 572 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_573 = 573 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_574 = 574 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_575 = 575 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_576 = 576 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_577 = 577 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_578 = 578 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_579 = 579 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_580 = 580 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_581 = 581 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_582 = 582 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_583 = 583 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_584 = 584 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_585 = 585 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_586 = 586 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_587 = 587 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_588 = 588 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_589 = 589 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_590 = 590 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_591 = 591 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_592 = 592 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_593 = 593 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_594 = 594 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_595 = 595 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_596 = 596 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_597 = 597 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_598 = 598 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_599 = 599 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_600 = 600 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_601 = 601 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_602 = 602 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_603 = 603 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_604 = 604 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_605 = 605 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_606 = 606 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_607 = 607 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_608 = 608 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_609 = 609 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_610 = 610 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_611 = 611 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_612 = 612 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_613 = 613 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_614 = 614 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_615 = 615 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_616 = 616 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_617 = 617 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_618 = 618 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_619 = 619 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_620 = 620 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_621 = 621 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_622 = 622 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_623 = 623 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_624 = 624 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_625 = 625 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_626 = 626 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_627 = 627 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_628 = 628 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_629 = 629 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_630 = 630 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_631 = 631 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_632 = 632 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_633 = 633 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_634 = 634 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_635 = 635 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_636 = 636 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_637 = 637 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_638 = 638 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_639 = 639 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_640 = 640 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_641 = 641 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_642 = 642 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_643 = 643 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_644 = 644 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_645 = 645 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_646 = 646 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_647 = 647 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_648 = 648 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_649 = 649 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_650 = 650 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_651 = 651 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_652 = 652 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_653 = 653 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_654 = 654 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_655 = 655 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_656 = 656 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_657 = 657 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_658 = 658 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_659 = 659 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_660 = 660 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_661 = 661 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_662 = 662 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_663 = 663 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_664 = 664 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_665 = 665 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_666 = 666 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_667 = 667 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_668 = 668 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_669 = 669 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_670 = 670 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_671 = 671 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_672 = 672 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_673 = 673 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_674 = 674 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_675 = 675 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_676 = 676 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_677 = 677 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_678 = 678 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_679 = 679 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_680 = 680 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_681 = 681 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_682 = 682 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_683 = 683 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_684 = 684 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_685 = 685 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_686 = 686 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_687 = 687 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_688 = 688 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_689 = 689 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_690 = 690 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_691 = 691 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_692 = 692 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_693 = 693 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_694 = 694 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_695 = 695 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_696 = 696 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_697 = 697 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_698 = 698 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_699 = 699 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_700 = 700 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_701 = 701 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_702 = 702 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_703 = 703 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_704 = 704 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_705 = 705 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_706 = 706 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_707 = 707 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_708 = 708 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_709 = 709 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_710 = 710 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_711 = 711 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_712 = 712 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_713 = 713 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_714 = 714 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_715 = 715 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_716 = 716 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_717 = 717 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_718 = 718 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_719 = 719 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_720 = 720 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_721 = 721 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_722 = 722 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_723 = 723 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_724 = 724 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_725 = 725 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_726 = 726 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_727 = 727 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_728 = 728 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_729 = 729 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_730 = 730 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_731 = 731 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_732 = 732 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_733 = 733 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_734 = 734 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_735 = 735 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_736 = 736 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_737 = 737 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_738 = 738 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_739 = 739 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_740 = 740 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_741 = 741 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_742 = 742 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_743 = 743 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_744 = 744 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_745 = 745 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_746 = 746 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_747 = 747 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_748 = 748 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_749 = 749 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_750 = 750 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_751 = 751 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_752 = 752 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_753 = 753 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_754 = 754 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_755 = 755 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_756 = 756 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_757 = 757 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_758 = 758 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_759 = 759 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_760 = 760 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_761 = 761 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_762 = 762 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_763 = 763 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_764 = 764 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_765 = 765 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_766 = 766 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_767 = 767 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_768 = 768 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_769 = 769 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_770 = 770 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_771 = 771 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_772 = 772 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_773 = 773 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_774 = 774 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_775 = 775 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_776 = 776 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_777 = 777 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_778 = 778 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_779 = 779 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_780 = 780 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_781 = 781 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_782 = 782 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_783 = 783 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_784 = 784 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_785 = 785 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_786 = 786 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_787 = 787 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_788 = 788 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_789 = 789 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_790 = 790 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_791 = 791 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_792 = 792 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_793 = 793 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_794 = 794 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_795 = 795 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_796 = 796 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_797 = 797 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_798 = 798 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_799 = 799 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_800 = 800 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_801 = 801 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_802 = 802 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_803 = 803 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_804 = 804 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_805 = 805 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_806 = 806 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_807 = 807 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_808 = 808 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_809 = 809 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_810 = 810 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_811 = 811 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_812 = 812 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_813 = 813 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_814 = 814 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_815 = 815 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_816 = 816 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_817 = 817 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_818 = 818 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_819 = 819 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_820 = 820 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_821 = 821 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_822 = 822 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_823 = 823 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_824 = 824 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_825 = 825 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_826 = 826 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_827 = 827 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_828 = 828 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_829 = 829 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_830 = 830 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_831 = 831 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_832 = 832 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_833 = 833 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_834 = 834 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_835 = 835 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_836 = 836 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_837 = 837 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_838 = 838 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_839 = 839 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_840 = 840 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_841 = 841 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_842 = 842 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_843 = 843 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_844 = 844 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_845 = 845 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_846 = 846 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_847 = 847 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_848 = 848 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_849 = 849 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_850 = 850 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_851 = 851 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_852 = 852 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_853 = 853 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_854 = 854 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_855 = 855 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_856 = 856 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_857 = 857 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_858 = 858 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_859 = 859 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_860 = 860 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_861 = 861 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_862 = 862 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_863 = 863 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_864 = 864 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_865 = 865 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_866 = 866 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_867 = 867 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_868 = 868 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_869 = 869 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_870 = 870 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_871 = 871 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_872 = 872 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_873 = 873 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_874 = 874 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_875 = 875 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_876 = 876 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_877 = 877 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_878 = 878 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_879 = 879 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_880 = 880 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_881 = 881 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_882 = 882 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_883 = 883 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_884 = 884 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_885 = 885 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_886 = 886 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_887 = 887 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_888 = 888 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_889 = 889 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_890 = 890 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_891 = 891 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_892 = 892 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_893 = 893 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_894 = 894 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_895 = 895 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_896 = 896 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_897 = 897 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_898 = 898 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_899 = 899 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_900 = 900 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_901 = 901 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_902 = 902 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_903 = 903 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_904 = 904 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_905 = 905 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_906 = 906 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_907 = 907 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_908 = 908 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_909 = 909 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_910 = 910 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_911 = 911 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_912 = 912 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_913 = 913 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_914 = 914 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_915 = 915 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_916 = 916 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_917 = 917 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_918 = 918 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_919 = 919 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_920 = 920 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_921 = 921 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_922 = 922 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_923 = 923 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_924 = 924 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_925 = 925 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_926 = 926 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_927 = 927 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_928 = 928 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_929 = 929 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_930 = 930 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_931 = 931 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_932 = 932 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_933 = 933 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_934 = 934 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_935 = 935 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_936 = 936 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_937 = 937 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_938 = 938 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_939 = 939 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_940 = 940 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_941 = 941 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_942 = 942 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_943 = 943 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_944 = 944 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_945 = 945 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_946 = 946 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_947 = 947 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_948 = 948 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_949 = 949 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_950 = 950 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_951 = 951 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_952 = 952 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_953 = 953 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_954 = 954 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_955 = 955 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_956 = 956 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_957 = 957 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_958 = 958 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_959 = 959 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_960 = 960 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_961 = 961 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_962 = 962 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_963 = 963 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_964 = 964 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_965 = 965 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_966 = 966 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_967 = 967 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_968 = 968 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_969 = 969 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_970 = 970 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_971 = 971 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_972 = 972 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_973 = 973 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_974 = 974 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_975 = 975 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_976 = 976 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_977 = 977 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_978 = 978 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_979 = 979 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_980 = 980 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_981 = 981 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_982 = 982 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_983 = 983 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_984 = 984 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_985 = 985 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_986 = 986 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_987 = 987 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_988 = 988 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_989 = 989 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_990 = 990 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_991 = 991 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_992 = 992 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_993 = 993 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_994 = 994 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_995 = 995 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_996 = 996 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_997 = 997 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_998 = 998 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_999 = 999 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000 = 1000 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+}
diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto
new file mode 100644
index 0000000..8d03e38
--- /dev/null
+++ b/src/google/protobuf/unittest_import.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.
+
+// 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.proto to test importing.
+
+syntax = "proto2";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// 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";
+
+// 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.proto";
+
+message ImportMessage {
+  optional int32 d = 1;
+}
+
+enum ImportEnum {
+  IMPORT_FOO = 7;
+  IMPORT_BAR = 8;
+  IMPORT_BAZ = 9;
+}
+
+
+// To use an enum in a map, it must has the first value as 0.
+enum ImportEnumForMap {
+  UNKNOWN = 0;
+  FOO = 1;
+  BAR = 2;
+}
diff --git a/src/google/protobuf/unittest_import_lite.proto b/src/google/protobuf/unittest_import_lite.proto
new file mode 100644
index 0000000..a7afa45
--- /dev/null
+++ b/src/google/protobuf/unittest_import_lite.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)
+//
+// This is like unittest_import.proto but with optimize_for = LITE_RUNTIME.
+
+syntax = "proto2";
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+import public "google/protobuf/unittest_import_public_lite.proto";
+
+message ImportMessageLite {
+  optional int32 d = 1;
+}
+
+enum ImportEnumLite {
+  IMPORT_LITE_FOO = 7;
+  IMPORT_LITE_BAR = 8;
+  IMPORT_LITE_BAZ = 9;
+}
diff --git a/src/google/protobuf/unittest_import_public.proto b/src/google/protobuf/unittest_import_public.proto
new file mode 100644
index 0000000..ffaf773
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public.proto
@@ -0,0 +1,41 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+syntax = "proto2";
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.test";
+
+message PublicImportMessage {
+  optional int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_import_public_lite.proto b/src/google/protobuf/unittest_import_public_lite.proto
new file mode 100644
index 0000000..33549c2
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public_lite.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+syntax = "proto2";
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+message PublicImportMessageLite {
+  optional int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_lazy_dependencies.proto b/src/google/protobuf/unittest_lazy_dependencies.proto
new file mode 100644
index 0000000..2f5efd2
--- /dev/null
+++ b/src/google/protobuf/unittest_lazy_dependencies.proto
@@ -0,0 +1,75 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: trafacz@google.com (Todd Rafacz)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+syntax = "proto2";
+
+import "google/protobuf/unittest_lazy_dependencies_custom_option.proto";
+
+// 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;
+
+// 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.lazy_imports;
+
+// 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 = "UnittestLazyImportsProto";
+
+// The following are used to test that the proto file
+// with the definition of the following field types is
+// not built when this proto file is built. Then test
+// that calling message_type() etc will build the correct
+// descriptor lazily and return it.
+
+message ImportedMessage {
+  optional LazyMessage lazy_message = 1;
+}
+
+message MessageCustomOption {
+}
+
+message MessageCustomOption2 {
+  option (lazy_enum_option) = LAZY_ENUM_0;
+}
diff --git a/src/google/protobuf/unittest_lazy_dependencies_custom_option.proto b/src/google/protobuf/unittest_lazy_dependencies_custom_option.proto
new file mode 100644
index 0000000..2243825
--- /dev/null
+++ b/src/google/protobuf/unittest_lazy_dependencies_custom_option.proto
@@ -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.
+
+// Author: trafacz@google.com (Todd Rafacz)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+syntax = "proto2";
+
+import "google/protobuf/unittest_lazy_dependencies_enum.proto";
+import "google/protobuf/descriptor.proto";
+
+// 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;
+
+// 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.lazy_imports;
+
+// 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 = "UnittestLazyImportsCustomOptionProto";
+
+message LazyMessage {
+  optional int32 a = 1;
+}
+
+extend google.protobuf.MessageOptions {
+  optional LazyEnum lazy_enum_option = 138596335 [default = LAZY_ENUM_1];
+}
diff --git a/src/google/protobuf/unittest_lazy_dependencies_enum.proto b/src/google/protobuf/unittest_lazy_dependencies_enum.proto
new file mode 100644
index 0000000..9be64d8
--- /dev/null
+++ b/src/google/protobuf/unittest_lazy_dependencies_enum.proto
@@ -0,0 +1,61 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: trafacz@google.com (Todd Rafacz)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;   // auto-added
+option java_generic_services = true; // auto-added
+option py_generic_services = true;   // auto-added
+option cc_enable_arenas = true;
+
+// 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.lazy_imports;
+
+// 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 = "UnittestLazyImportsEnumProto";
+
+enum LazyEnum {
+  LAZY_ENUM_0 = 0;
+  LAZY_ENUM_1 = 1;
+}
diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto
new file mode 100644
index 0000000..010d4a9
--- /dev/null
+++ b/src/google/protobuf/unittest_lite.proto
@@ -0,0 +1,520 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest.proto but with optimize_for = LITE_RUNTIME.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest_import_lite.proto";
+
+option cc_enable_arenas = true;
+option optimize_for = LITE_RUNTIME;
+option java_package = "com.google.protobuf";
+
+// Same as TestAllTypes but with the lite runtime.
+message TestAllTypesLite {
+  message NestedMessage {
+    optional int32 bb = 1;
+    optional int64 cc = 2;
+  }
+
+  message NestedMessage2 {
+    optional int32 dd = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional int32 optional_int32 = 1;
+  optional int64 optional_int64 = 2;
+  optional uint32 optional_uint32 = 3;
+  optional uint64 optional_uint64 = 4;
+  optional sint32 optional_sint32 = 5;
+  optional sint64 optional_sint64 = 6;
+  optional fixed32 optional_fixed32 = 7;
+  optional fixed64 optional_fixed64 = 8;
+  optional sfixed32 optional_sfixed32 = 9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional float optional_float = 11;
+  optional double optional_double = 12;
+  optional bool optional_bool = 13;
+  optional string optional_string = 14;
+  optional bytes optional_bytes = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage optional_nested_message = 18;
+  optional ForeignMessageLite optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessageLite optional_import_message =
+      20;
+
+  optional NestedEnum optional_nested_enum = 21;
+  optional ForeignEnumLite optional_foreign_enum = 22;
+  optional protobuf_unittest_import.ImportEnumLite optional_import_enum = 23;
+
+  optional string optional_string_piece = 24 [ctype = STRING_PIECE];
+  optional string optional_cord = 25 [ctype = CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessageLite
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_lazy_message = 27 [lazy = true];
+  optional NestedMessage optional_unverified_lazy_message = 28
+      [unverified_lazy = true];
+
+  // Repeated
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage repeated_nested_message = 48;
+  repeated ForeignMessageLite repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessageLite repeated_import_message =
+      50;
+
+  repeated NestedEnum repeated_nested_enum = 51;
+  repeated ForeignEnumLite repeated_foreign_enum = 52;
+  repeated protobuf_unittest_import.ImportEnumLite repeated_import_enum = 53;
+
+  repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype = CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy = true];
+
+  // Singular with defaults
+  optional int32 default_int32 = 61 [default = 41];
+  optional int64 default_int64 = 62 [default = 42];
+  optional uint32 default_uint32 = 63 [default = 43];
+  optional uint64 default_uint64 = 64 [default = 44];
+  optional sint32 default_sint32 = 65 [default = -45];
+  optional sint64 default_sint64 = 66 [default = 46];
+  optional fixed32 default_fixed32 = 67 [default = 47];
+  optional fixed64 default_fixed64 = 68 [default = 48];
+  optional sfixed32 default_sfixed32 = 69 [default = 49];
+  optional sfixed64 default_sfixed64 = 70 [default = -50];
+  optional float default_float = 71 [default = 51.5];
+  optional double default_double = 72 [default = 52e3];
+  optional bool default_bool = 73 [default = true];
+  optional string default_string = 74 [default = "hello"];
+  optional bytes default_bytes = 75 [default = "world"];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+  optional ForeignEnumLite default_foreign_enum = 82
+      [default = FOREIGN_LITE_BAR];
+  optional protobuf_unittest_import.ImportEnumLite default_import_enum = 83
+      [default = IMPORT_LITE_BAR];
+
+  optional string default_string_piece = 84
+      [ctype = STRING_PIECE, default = "abc"];
+  optional string default_cord = 85 [ctype = CORD, default = "123"];
+
+  // For oneof test
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+    NestedMessage oneof_lazy_nested_message = 115 [lazy = true];
+    NestedMessage2 oneof_nested_message2 = 117;
+  }
+
+  // Tests toString for non-repeated fields with a list suffix
+  optional int32 deceptively_named_list = 116;
+}
+
+message ForeignMessageLite {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumLite {
+  FOREIGN_LITE_FOO = 4;
+  FOREIGN_LITE_BAZ = 6;
+  FOREIGN_LITE_BAR = 5;
+}
+
+message TestPackedTypesLite {
+  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 ForeignEnumLite packed_enum = 103 [packed = true];
+}
+
+message TestAllExtensionsLite {
+  extensions 1 to max;
+}
+
+extend TestAllExtensionsLite {
+  // Singular
+  optional int32 optional_int32_extension_lite = 1;
+  optional int64 optional_int64_extension_lite = 2;
+  optional uint32 optional_uint32_extension_lite = 3;
+  optional uint64 optional_uint64_extension_lite = 4;
+  optional sint32 optional_sint32_extension_lite = 5;
+  optional sint64 optional_sint64_extension_lite = 6;
+  optional fixed32 optional_fixed32_extension_lite = 7;
+  optional fixed64 optional_fixed64_extension_lite = 8;
+  optional sfixed32 optional_sfixed32_extension_lite = 9;
+  optional sfixed64 optional_sfixed64_extension_lite = 10;
+  optional float optional_float_extension_lite = 11;
+  optional double optional_double_extension_lite = 12;
+  optional bool optional_bool_extension_lite = 13;
+  optional string optional_string_extension_lite = 14;
+  optional bytes optional_bytes_extension_lite = 15;
+
+  optional group OptionalGroup_extension_lite = 16 {
+    optional int32 a = 17;
+  }
+
+  optional TestAllTypesLite.NestedMessage
+      optional_nested_message_extension_lite = 18;
+  optional ForeignMessageLite optional_foreign_message_extension_lite = 19;
+  optional protobuf_unittest_import.ImportMessageLite
+      optional_import_message_extension_lite = 20;
+
+  optional TestAllTypesLite.NestedEnum optional_nested_enum_extension_lite = 21;
+  optional ForeignEnumLite optional_foreign_enum_extension_lite = 22;
+  optional protobuf_unittest_import.ImportEnumLite
+      optional_import_enum_extension_lite = 23;
+
+  optional string optional_string_piece_extension_lite = 24
+      [ctype = STRING_PIECE];
+  optional string optional_cord_extension_lite = 25 [ctype = CORD];
+
+  optional protobuf_unittest_import.PublicImportMessageLite
+      optional_public_import_message_extension_lite = 26;
+
+  optional TestAllTypesLite.NestedMessage optional_lazy_message_extension_lite =
+      27 [lazy = true];
+  optional TestAllTypesLite.NestedMessage
+      optional_unverified_lazy_message_extension_lite = 28
+      [unverified_lazy = true];
+
+  // Repeated
+  repeated int32 repeated_int32_extension_lite = 31;
+  repeated int64 repeated_int64_extension_lite = 32;
+  repeated uint32 repeated_uint32_extension_lite = 33;
+  repeated uint64 repeated_uint64_extension_lite = 34;
+  repeated sint32 repeated_sint32_extension_lite = 35;
+  repeated sint64 repeated_sint64_extension_lite = 36;
+  repeated fixed32 repeated_fixed32_extension_lite = 37;
+  repeated fixed64 repeated_fixed64_extension_lite = 38;
+  repeated sfixed32 repeated_sfixed32_extension_lite = 39;
+  repeated sfixed64 repeated_sfixed64_extension_lite = 40;
+  repeated float repeated_float_extension_lite = 41;
+  repeated double repeated_double_extension_lite = 42;
+  repeated bool repeated_bool_extension_lite = 43;
+  repeated string repeated_string_extension_lite = 44;
+  repeated bytes repeated_bytes_extension_lite = 45;
+
+  repeated group RepeatedGroup_extension_lite = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated TestAllTypesLite.NestedMessage
+      repeated_nested_message_extension_lite = 48;
+  repeated ForeignMessageLite repeated_foreign_message_extension_lite = 49;
+  repeated protobuf_unittest_import.ImportMessageLite
+      repeated_import_message_extension_lite = 50;
+
+  repeated TestAllTypesLite.NestedEnum repeated_nested_enum_extension_lite = 51;
+  repeated ForeignEnumLite repeated_foreign_enum_extension_lite = 52;
+  repeated protobuf_unittest_import.ImportEnumLite
+      repeated_import_enum_extension_lite = 53;
+
+  repeated string repeated_string_piece_extension_lite = 54
+      [ctype = STRING_PIECE];
+  repeated string repeated_cord_extension_lite = 55 [ctype = CORD];
+
+  repeated TestAllTypesLite.NestedMessage repeated_lazy_message_extension_lite =
+      57 [lazy = true];
+
+  // Singular with defaults
+  optional int32 default_int32_extension_lite = 61 [default = 41];
+  optional int64 default_int64_extension_lite = 62 [default = 42];
+  optional uint32 default_uint32_extension_lite = 63 [default = 43];
+  optional uint64 default_uint64_extension_lite = 64 [default = 44];
+  optional sint32 default_sint32_extension_lite = 65 [default = -45];
+  optional sint64 default_sint64_extension_lite = 66 [default = 46];
+  optional fixed32 default_fixed32_extension_lite = 67 [default = 47];
+  optional fixed64 default_fixed64_extension_lite = 68 [default = 48];
+  optional sfixed32 default_sfixed32_extension_lite = 69 [default = 49];
+  optional sfixed64 default_sfixed64_extension_lite = 70 [default = -50];
+  optional float default_float_extension_lite = 71 [default = 51.5];
+  optional double default_double_extension_lite = 72 [default = 52e3];
+  optional bool default_bool_extension_lite = 73 [default = true];
+  optional string default_string_extension_lite = 74 [default = "hello"];
+  optional bytes default_bytes_extension_lite = 75 [default = "world"];
+
+  optional TestAllTypesLite.NestedEnum default_nested_enum_extension_lite = 81
+      [default = BAR];
+  optional ForeignEnumLite default_foreign_enum_extension_lite = 82
+      [default = FOREIGN_LITE_BAR];
+  optional protobuf_unittest_import.ImportEnumLite
+      default_import_enum_extension_lite = 83 [default = IMPORT_LITE_BAR];
+
+  optional string default_string_piece_extension_lite = 84
+      [ctype = STRING_PIECE, default = "abc"];
+  optional string default_cord_extension_lite = 85
+      [ctype = CORD, default = "123"];
+
+  // For oneof test
+  optional uint32 oneof_uint32_extension_lite = 111;
+  optional TestAllTypesLite.NestedMessage oneof_nested_message_extension_lite =
+      112;
+  optional string oneof_string_extension_lite = 113;
+  optional bytes oneof_bytes_extension_lite = 114;
+}
+
+message TestPackedExtensionsLite {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensionsLite {
+  repeated int32 packed_int32_extension_lite = 90 [packed = true];
+  repeated int64 packed_int64_extension_lite = 91 [packed = true];
+  repeated uint32 packed_uint32_extension_lite = 92 [packed = true];
+  repeated uint64 packed_uint64_extension_lite = 93 [packed = true];
+  repeated sint32 packed_sint32_extension_lite = 94 [packed = true];
+  repeated sint64 packed_sint64_extension_lite = 95 [packed = true];
+  repeated fixed32 packed_fixed32_extension_lite = 96 [packed = true];
+  repeated fixed64 packed_fixed64_extension_lite = 97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension_lite = 98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension_lite = 99 [packed = true];
+  repeated float packed_float_extension_lite = 100 [packed = true];
+  repeated double packed_double_extension_lite = 101 [packed = true];
+  repeated bool packed_bool_extension_lite = 102 [packed = true];
+  repeated ForeignEnumLite packed_enum_extension_lite = 103 [packed = true];
+}
+
+message TestNestedExtensionLite {
+  extend TestAllExtensionsLite {
+    optional int32 nested_extension = 12345;
+  }
+}
+
+// Test that deprecated fields work.  We only verify that they compile (at one
+// point this failed).
+message TestDeprecatedLite {
+  optional int32 deprecated_field = 1 [deprecated = true];
+  required int32 deprecated_field2 = 2 [deprecated = true];
+  optional string deprecated_field3 = 3 [deprecated = true];
+  optional TestDeprecatedLite deprecated_field4 = 4 [deprecated = true];
+}
+
+// See the comments of the same type in unittest.proto.
+message TestParsingMergeLite {
+  message RepeatedFieldsGenerator {
+    repeated TestAllTypesLite field1 = 1;
+    repeated TestAllTypesLite field2 = 2;
+    repeated TestAllTypesLite field3 = 3;
+    repeated group Group1 = 10 {
+      optional TestAllTypesLite field1 = 11;
+    }
+    repeated group Group2 = 20 {
+      optional TestAllTypesLite field1 = 21;
+    }
+    repeated TestAllTypesLite ext1 = 1000;
+    repeated TestAllTypesLite ext2 = 1001;
+  }
+  required TestAllTypesLite required_all_types = 1;
+  optional TestAllTypesLite optional_all_types = 2;
+  repeated TestAllTypesLite repeated_all_types = 3;
+  optional group OptionalGroup = 10 {
+    optional TestAllTypesLite optional_group_all_types = 11;
+  }
+  repeated group RepeatedGroup = 20 {
+    optional TestAllTypesLite repeated_group_all_types = 21;
+  }
+  extensions 1000 to max;
+  extend TestParsingMergeLite {
+    optional TestAllTypesLite optional_ext = 1000;
+    repeated TestAllTypesLite repeated_ext = 1001;
+  }
+}
+
+// Test that the correct exception is thrown by parseFrom in a corner case
+// involving merging, extensions, and required fields.
+message TestMergeExceptionLite {
+  optional TestAllExtensionsLite all_extensions = 1;
+}
+
+// TestEmptyMessageLite is used to test unknown fields support in lite mode.
+message TestEmptyMessageLite {}
+
+// Like above, but declare all field numbers as potential extensions.  No
+// actual extensions should ever be defined for this type.
+message TestEmptyMessageWithExtensionsLite {
+  extensions 1 to max;
+}
+
+enum V1EnumLite {
+  V1_FIRST = 1;
+}
+
+enum V2EnumLite {
+  V2_FIRST = 1;
+  V2_SECOND = 2;
+}
+
+message V1MessageLite {
+  required int32 int_field = 1;
+  optional V1EnumLite enum_field = 2 [default = V1_FIRST];
+}
+
+message V2MessageLite {
+  required int32 int_field = 1;
+  optional V2EnumLite enum_field = 2 [default = V2_FIRST];
+}
+
+message TestHugeFieldNumbersLite {
+  optional int32 optional_int32 = 536870000;
+  optional int32 fixed_32 = 536870001;
+  repeated int32 repeated_int32 = 536870002 [packed = false];
+  repeated int32 packed_int32 = 536870003 [packed = true];
+
+  optional ForeignEnumLite optional_enum = 536870004;
+  optional string optional_string = 536870005;
+  optional bytes optional_bytes = 536870006;
+  optional ForeignMessageLite optional_message = 536870007;
+
+  optional group OptionalGroup = 536870008 {
+    optional int32 group_a = 536870009;
+  }
+
+  map<string, string> string_string_map = 536870010;
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 536870011;
+    TestAllTypesLite oneof_test_all_types = 536870012;
+    string oneof_string = 536870013;
+    bytes oneof_bytes = 536870014;
+  }
+
+  extensions 536860000 to 536869999;
+}
+
+extend TestHugeFieldNumbersLite {
+  optional TestAllTypesLite test_all_types_lite = 536860000;
+}
+
+message TestOneofParsingLite {
+  oneof oneof_field {
+    int32 oneof_int32 = 1;
+    TestAllTypesLite oneof_submessage = 2;
+    string oneof_string = 3;
+    bytes oneof_bytes = 4 [default = "default bytes"];
+    string oneof_string_cord = 5 [ctype = CORD, default = "default Cord"];
+    bytes oneof_bytes_cord = 6 [ctype = CORD];
+    string oneof_string_string_piece = 7 [ctype = STRING_PIECE];
+    bytes oneof_bytes_string_piece = 8
+        [ctype = STRING_PIECE, default = "default StringPiece"];
+    V2EnumLite oneof_enum = 9;
+  }
+}
+
+message TestMessageSetLite {
+  option message_set_wire_format = true;
+
+  extensions 100 to max;
+}
+
+// The following four messages are set up to test for wire compatibility between
+// packed and non-packed repeated fields. We use the field number 2048, because
+// that is large enough to require a 3-byte varint for the tag.
+message PackedInt32 {
+  repeated int32 repeated_int32 = 2048 [packed = true];
+}
+
+message NonPackedInt32 {
+  repeated int32 repeated_int32 = 2048;
+}
+
+message PackedFixed32 {
+  repeated fixed32 repeated_fixed32 = 2048 [packed = true];
+}
+
+message NonPackedFixed32 {
+  repeated fixed32 repeated_fixed32 = 2048;
+}
+
+// Test an enum that has multiple values with the same number.
+message DupEnum {
+  enum TestEnumWithDupValueLite {
+    option allow_alias = true;
+
+    FOO1 = 1;
+    BAR1 = 2;
+    BAZ = 3;
+    FOO2 = 1;
+    BAR2 = 2;
+  }
+}
+
+message RecursiveMessage {
+  optional RecursiveMessage recurse = 1;
+  optional bytes payload = 2;
+}
diff --git a/src/google/protobuf/unittest_lite_imports_nonlite.proto b/src/google/protobuf/unittest_lite_imports_nonlite.proto
new file mode 100644
index 0000000..8a47016
--- /dev/null
+++ b/src/google/protobuf/unittest_lite_imports_nonlite.proto
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// Tests that a "lite" message can import a regular message.
+
+syntax = "proto2";
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+message TestLiteImportsNonlite {
+  optional TestAllTypes message = 1;
+
+  // Verifies that transitive required fields generates valid code.
+  optional TestRequired message_with_required = 2;
+}
diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto
new file mode 100644
index 0000000..3294994
--- /dev/null
+++ b/src/google/protobuf/unittest_mset.proto
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// 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;
+
+message TestMessageSetContainer {
+  optional proto2_wireformat_unittest.TestMessageSet message_set = 1;
+}
+
+message NestedTestMessageSetContainer {
+  optional TestMessageSetContainer container = 1;
+  optional NestedTestMessageSetContainer child = 2;
+}
+
+message TestMessageSetExtension1 {
+  extend proto2_wireformat_unittest.TestMessageSet {
+    optional TestMessageSetExtension1 message_set_extension = 1545008;
+  }
+  optional int32 i = 15;
+  optional proto2_wireformat_unittest.TestMessageSet recursive = 16;
+  optional string test_aliasing = 17 [ctype = STRING_PIECE];
+}
+
+message TestMessageSetExtension2 {
+  extend proto2_wireformat_unittest.TestMessageSet {
+    optional TestMessageSetExtension2 message_set_extension = 1547769;
+  }
+  optional string str = 25;
+}
+
+message NestedTestInt {
+  optional fixed32 a = 1;
+  optional NestedTestInt child = 2;
+}
+
+message TestMessageSetExtension3 {
+  extend proto2_wireformat_unittest.TestMessageSet {
+    optional TestMessageSetExtension3 message_set_extension = 195273129;
+  }
+  optional NestedTestInt msg = 35;
+}
+
+// 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;
+// }
+
+// MessageSet wire format is equivalent to this.
+message RawMessageSet {
+  repeated group Item = 1 {
+    required int32 type_id = 2;
+    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_field_presence.proto b/src/google/protobuf/unittest_no_field_presence.proto
new file mode 100644
index 0000000..994afff
--- /dev/null
+++ b/src/google/protobuf/unittest_no_field_presence.proto
@@ -0,0 +1,138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A proto file used to test a message type with no explicit field presence.
+
+syntax = "proto3";
+
+// We want to test embedded proto2 messages, so include some proto2 types.
+import "google/protobuf/unittest.proto";
+
+package proto2_nofieldpresence_unittest;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+
+  // Singular
+  // TODO: remove 'optional' labels as soon as CL 69188077 is LGTM'd to make
+  // 'optional' optional.
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest.TestAllTypes         optional_proto2_message = 20;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+  // N.B.: proto2-enum-type fields not allowed, because their default values
+  // might not be zero.
+  //optional protobuf_unittest.ForeignEnum          optional_proto2_enum     = 23;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  NestedMessage optional_lazy_message = 30 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest.TestAllTypes         repeated_proto2_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    NestedEnum oneof_enum = 114;
+  }
+}
+
+message TestProto2Required {
+  protobuf_unittest.TestRequired proto2 = 1;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 0;
+  FOREIGN_BAR = 1;
+  FOREIGN_BAZ = 2;
+}
diff --git a/src/google/protobuf/unittest_no_generic_services.proto b/src/google/protobuf/unittest_no_generic_services.proto
new file mode 100644
index 0000000..57a0d16
--- /dev/null
+++ b/src/google/protobuf/unittest_no_generic_services.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.
+
+// Author: kenton@google.com (Kenton Varda)
+
+syntax = "proto2";
+
+package protobuf_unittest.no_generic_services_test;
+
+
+// *_generic_services are false by default.
+
+message TestMessage {
+  optional int32 a = 1;
+  extensions 1000 to max;
+}
+
+enum TestEnum { FOO = 1; }
+
+extend TestMessage {
+  optional int32 test_extension = 1000;
+}
+
+service TestService {
+  rpc Foo(TestMessage) returns (TestMessage);
+}
diff --git a/src/google/protobuf/unittest_optimize_for.proto b/src/google/protobuf/unittest_optimize_for.proto
new file mode 100644
index 0000000..ee9cc7b
--- /dev/null
+++ b/src/google/protobuf/unittest_optimize_for.proto
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which uses optimize_for = CODE_SIZE.
+
+syntax = "proto2";
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option optimize_for = CODE_SIZE;
+
+message TestOptimizedForSize {
+  optional int32 i = 1;
+  optional ForeignMessage msg = 19;
+
+  extensions 1000 to max;
+
+  extend TestOptimizedForSize {
+    optional int32 test_extension = 1234;
+    optional TestRequiredOptimizedForSize test_extension2 = 1235;
+  }
+
+  oneof foo {
+    int32 integer_field = 2;
+    string string_field = 3;
+  }
+}
+
+message TestRequiredOptimizedForSize {
+  required int32 x = 1;
+}
+
+message TestOptionalOptimizedForSize {
+  optional TestRequiredOptimizedForSize o = 1;
+}
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto
new file mode 100644
index 0000000..2f91332
--- /dev/null
+++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto3_preserve_unknown_enum_unittest;
+option objc_class_prefix = "UnknownEnums";
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+enum MyEnum {
+  FOO = 0;
+  BAR = 1;
+  BAZ = 2;
+}
+
+enum MyEnumPlusExtra {
+  E_FOO = 0;
+  E_BAR = 1;
+  E_BAZ = 2;
+  E_EXTRA = 3;
+}
+
+message MyMessage {
+  MyEnum e = 1;
+  repeated MyEnum repeated_e = 2;
+  repeated MyEnum repeated_packed_e = 3 [packed=true];
+  repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4;  // not packed
+  oneof o {
+    MyEnum oneof_e_1 = 5;
+    MyEnum oneof_e_2 = 6;
+  }
+}
+
+message MyMessagePlusExtra {
+  MyEnumPlusExtra e = 1;
+  repeated MyEnumPlusExtra repeated_e = 2;
+  repeated MyEnumPlusExtra repeated_packed_e = 3 [packed=true];
+  repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4 [packed=true];
+  oneof o {
+    MyEnumPlusExtra oneof_e_1 = 5;
+    MyEnumPlusExtra oneof_e_2 = 6;
+  }
+}
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum2.proto b/src/google/protobuf/unittest_preserve_unknown_enum2.proto
new file mode 100644
index 0000000..adf4296
--- /dev/null
+++ b/src/google/protobuf/unittest_preserve_unknown_enum2.proto
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package proto2_preserve_unknown_enum_unittest;
+
+enum MyEnum {
+  FOO = 0;
+  BAR = 1;
+  BAZ = 2;
+}
+
+message MyMessage {
+  optional MyEnum e = 1;
+  repeated MyEnum repeated_e = 2;
+  repeated MyEnum repeated_packed_e = 3 [packed=true];
+  repeated MyEnum repeated_packed_unexpected_e = 4;  // not packed
+  oneof o {
+    MyEnum oneof_e_1 = 5;
+    MyEnum oneof_e_2 = 6;
+  }
+}
diff --git a/src/google/protobuf/unittest_proto3.proto b/src/google/protobuf/unittest_proto3.proto
new file mode 100644
index 0000000..910f401
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3.proto
@@ -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.
+
+syntax = "proto3";
+
+package proto3_unittest;
+
+import "google/protobuf/unittest_import.proto";
+
+option optimize_for = SPEED;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  sint32 optional_sint32 = 5;
+  sint64 optional_sint64 = 6;
+  fixed32 optional_fixed32 = 7;
+  fixed64 optional_fixed64 = 8;
+  sfixed32 optional_sfixed32 = 9;
+  sfixed64 optional_sfixed64 = 10;
+  float optional_float = 11;
+  double optional_double = 12;
+  bool optional_bool = 13;
+  string optional_string = 14;
+  bytes optional_bytes = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  optional NestedMessage optional_nested_message = 18;
+  ForeignMessage optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message = 20;
+
+  NestedEnum optional_nested_enum = 21;
+  ForeignEnum optional_foreign_enum = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype = STRING_PIECE];
+  string optional_cord = 25 [ctype = CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage optional_public_import_message =
+      26;
+
+  NestedMessage optional_lazy_message = 27 [lazy = true];
+  NestedMessage optional_unverified_lazy_message = 28 [unverified_lazy = true];
+  protobuf_unittest_import.ImportMessage optional_lazy_import_message = 115
+      [lazy = true];
+
+  // Repeated
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage repeated_nested_message = 48;
+  repeated ForeignMessage repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50;
+
+  repeated NestedEnum repeated_nested_enum = 51;
+  repeated ForeignEnum repeated_foreign_enum = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype = CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy = true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated int32 packed_int32 = 90 [packed = true];
+  repeated int64 packed_int64 = 91 [packed = true];
+  repeated uint32 packed_uint32 = 92 [packed = true];
+  repeated uint64 packed_uint64 = 93 [packed = true];
+  repeated sint32 packed_sint32 = 94 [packed = true];
+  repeated sint64 packed_sint64 = 95 [packed = true];
+  repeated fixed32 packed_fixed32 = 96 [packed = true];
+  repeated fixed64 packed_fixed64 = 97 [packed = true];
+  repeated sfixed32 packed_sfixed32 = 98 [packed = true];
+  repeated sfixed64 packed_sfixed64 = 99 [packed = true];
+  repeated float packed_float = 100 [packed = true];
+  repeated double packed_double = 101 [packed = true];
+  repeated bool packed_bool = 102 [packed = true];
+  repeated ForeignEnum packed_enum = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated int32 repeated_int32 = 1 [packed = false];
+  repeated int64 repeated_int64 = 2 [packed = false];
+  repeated uint32 repeated_uint32 = 3 [packed = false];
+  repeated uint64 repeated_uint64 = 4 [packed = false];
+  repeated sint32 repeated_sint32 = 5 [packed = false];
+  repeated sint64 repeated_sint64 = 6 [packed = false];
+  repeated fixed32 repeated_fixed32 = 7 [packed = false];
+  repeated fixed64 repeated_fixed64 = 8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 = 9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated float repeated_float = 11 [packed = false];
+  repeated double repeated_double = 12 [packed = false];
+  repeated bool repeated_bool = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recursively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {}
+
+// TestMessageWithDummy is also used to test behavior of unknown fields.
+message TestMessageWithDummy {
+  // This field is only here for triggering copy-on-write; it's not intended to
+  // be serialized.
+  bool dummy = 536870911;
+}
+
+// Same layout as TestOneof2 in unittest.proto to test unknown enum value
+// parsing behavior in oneof.
+message TestOneof2 {
+  oneof foo {
+    NestedEnum foo_enum = 6;
+  }
+
+  enum NestedEnum {
+    UNKNOWN = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+}
diff --git a/src/google/protobuf/unittest_proto3_arena.proto b/src/google/protobuf/unittest_proto3_arena.proto
new file mode 100644
index 0000000..7dc6cd0
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_arena.proto
@@ -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.
+
+syntax = "proto3";
+
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest_import.proto";
+
+package proto3_arena_unittest;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  NestedMessage optional_lazy_message = 27 [lazy=true];
+  NestedMessage optional_unverified_lazy_message = 28 [unverified_lazy=true];
+  protobuf_unittest_import.ImportMessage optional_lazy_import_message = 115
+      [lazy = true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  // Optional
+  optional    int32 proto3_optional_int32    = 116;
+  optional    int64 proto3_optional_int64    = 117;
+  optional   uint32 proto3_optional_uint32   = 118;
+  optional   uint64 proto3_optional_uint64   = 119;
+  optional   sint32 proto3_optional_sint32   = 120;
+  optional   sint64 proto3_optional_sint64   = 121;
+  optional  fixed32 proto3_optional_fixed32  = 122;
+  optional  fixed64 proto3_optional_fixed64  = 123;
+  optional sfixed32 proto3_optional_sfixed32 = 124;
+  optional sfixed64 proto3_optional_sfixed64 = 125;
+  optional    float proto3_optional_float    = 126;
+  optional   double proto3_optional_double   = 127;
+  optional     bool proto3_optional_bool     = 128;
+  optional   string proto3_optional_string   = 129;
+  optional    bytes proto3_optional_bytes    = 130;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated    int32 repeated_int32    =  1 [packed = false];
+  repeated    int64 repeated_int64    =  2 [packed = false];
+  repeated   uint32 repeated_uint32   =  3 [packed = false];
+  repeated   uint64 repeated_uint64   =  4 [packed = false];
+  repeated   sint32 repeated_sint32   =  5 [packed = false];
+  repeated   sint64 repeated_sint64   =  6 [packed = false];
+  repeated  fixed32 repeated_fixed32  =  7 [packed = false];
+  repeated  fixed64 repeated_fixed64  =  8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 =  9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated    float repeated_float    = 11 [packed = false];
+  repeated   double repeated_double   = 12 [packed = false];
+  repeated     bool repeated_bool     = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recursively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+  repeated NestedTestAllTypes repeated_child = 3;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {
+}
+
+// Needed for a Python test.
+message TestPickleNestedMessage {
+  message NestedMessage {
+    int32 bb = 1;
+    message NestedNestedMessage {
+      int32 cc = 1;
+    }
+  }
+}
diff --git a/src/google/protobuf/unittest_proto3_arena_lite.proto b/src/google/protobuf/unittest_proto3_arena_lite.proto
new file mode 100644
index 0000000..0d4218b
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_arena_lite.proto
@@ -0,0 +1,205 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_arena_lite_unittest;
+
+import "google/protobuf/unittest_import.proto";
+
+option cc_enable_arenas = true;
+option optimize_for = LITE_RUNTIME;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  sint32 optional_sint32 = 5;
+  sint64 optional_sint64 = 6;
+  fixed32 optional_fixed32 = 7;
+  fixed64 optional_fixed64 = 8;
+  sfixed32 optional_sfixed32 = 9;
+  sfixed64 optional_sfixed64 = 10;
+  float optional_float = 11;
+  double optional_double = 12;
+  bool optional_bool = 13;
+  string optional_string = 14;
+  bytes optional_bytes = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  NestedMessage optional_nested_message = 18;
+  ForeignMessage optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message = 20;
+
+  NestedEnum optional_nested_enum = 21;
+  ForeignEnum optional_foreign_enum = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype = STRING_PIECE];
+  string optional_cord = 25 [ctype = CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage optional_public_import_message =
+      26;
+
+  NestedMessage optional_lazy_message = 27 [lazy = true];
+
+  // Repeated
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage repeated_nested_message = 48;
+  repeated ForeignMessage repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50;
+
+  repeated NestedEnum repeated_nested_enum = 51;
+  repeated ForeignEnum repeated_foreign_enum = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype = CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy = true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated int32 packed_int32 = 90 [packed = true];
+  repeated int64 packed_int64 = 91 [packed = true];
+  repeated uint32 packed_uint32 = 92 [packed = true];
+  repeated uint64 packed_uint64 = 93 [packed = true];
+  repeated sint32 packed_sint32 = 94 [packed = true];
+  repeated sint64 packed_sint64 = 95 [packed = true];
+  repeated fixed32 packed_fixed32 = 96 [packed = true];
+  repeated fixed64 packed_fixed64 = 97 [packed = true];
+  repeated sfixed32 packed_sfixed32 = 98 [packed = true];
+  repeated sfixed64 packed_sfixed64 = 99 [packed = true];
+  repeated float packed_float = 100 [packed = true];
+  repeated double packed_double = 101 [packed = true];
+  repeated bool packed_bool = 102 [packed = true];
+  repeated ForeignEnum packed_enum = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated int32 repeated_int32 = 1 [packed = false];
+  repeated int64 repeated_int64 = 2 [packed = false];
+  repeated uint32 repeated_uint32 = 3 [packed = false];
+  repeated uint64 repeated_uint64 = 4 [packed = false];
+  repeated sint32 repeated_sint32 = 5 [packed = false];
+  repeated sint64 repeated_sint64 = 6 [packed = false];
+  repeated fixed32 repeated_fixed32 = 7 [packed = false];
+  repeated fixed64 repeated_fixed64 = 8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 = 9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated float repeated_float = 11 [packed = false];
+  repeated double repeated_double = 12 [packed = false];
+  repeated bool repeated_bool = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recursively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {}
diff --git a/src/google/protobuf/unittest_proto3_lite.proto b/src/google/protobuf/unittest_proto3_lite.proto
new file mode 100644
index 0000000..837bb03
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_lite.proto
@@ -0,0 +1,204 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto3_lite_unittest;
+
+import "google/protobuf/unittest_import.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  sint32 optional_sint32 = 5;
+  sint64 optional_sint64 = 6;
+  fixed32 optional_fixed32 = 7;
+  fixed64 optional_fixed64 = 8;
+  sfixed32 optional_sfixed32 = 9;
+  sfixed64 optional_sfixed64 = 10;
+  float optional_float = 11;
+  double optional_double = 12;
+  bool optional_bool = 13;
+  string optional_string = 14;
+  bytes optional_bytes = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  NestedMessage optional_nested_message = 18;
+  ForeignMessage optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message = 20;
+
+  NestedEnum optional_nested_enum = 21;
+  ForeignEnum optional_foreign_enum = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype = STRING_PIECE];
+  string optional_cord = 25 [ctype = CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage optional_public_import_message =
+      26;
+
+  NestedMessage optional_lazy_message = 27 [lazy = true];
+
+  // Repeated
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage repeated_nested_message = 48;
+  repeated ForeignMessage repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50;
+
+  repeated NestedEnum repeated_nested_enum = 51;
+  repeated ForeignEnum repeated_foreign_enum = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype = CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy = true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated int32 packed_int32 = 90 [packed = true];
+  repeated int64 packed_int64 = 91 [packed = true];
+  repeated uint32 packed_uint32 = 92 [packed = true];
+  repeated uint64 packed_uint64 = 93 [packed = true];
+  repeated sint32 packed_sint32 = 94 [packed = true];
+  repeated sint64 packed_sint64 = 95 [packed = true];
+  repeated fixed32 packed_fixed32 = 96 [packed = true];
+  repeated fixed64 packed_fixed64 = 97 [packed = true];
+  repeated sfixed32 packed_sfixed32 = 98 [packed = true];
+  repeated sfixed64 packed_sfixed64 = 99 [packed = true];
+  repeated float packed_float = 100 [packed = true];
+  repeated double packed_double = 101 [packed = true];
+  repeated bool packed_bool = 102 [packed = true];
+  repeated ForeignEnum packed_enum = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated int32 repeated_int32 = 1 [packed = false];
+  repeated int64 repeated_int64 = 2 [packed = false];
+  repeated uint32 repeated_uint32 = 3 [packed = false];
+  repeated uint64 repeated_uint64 = 4 [packed = false];
+  repeated sint32 repeated_sint32 = 5 [packed = false];
+  repeated sint64 repeated_sint64 = 6 [packed = false];
+  repeated fixed32 repeated_fixed32 = 7 [packed = false];
+  repeated fixed64 repeated_fixed64 = 8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 = 9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated float repeated_float = 11 [packed = false];
+  repeated double repeated_double = 12 [packed = false];
+  repeated bool repeated_bool = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recursively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {}
diff --git a/src/google/protobuf/unittest_proto3_optional.proto b/src/google/protobuf/unittest_proto3_optional.proto
new file mode 100644
index 0000000..09d1718
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_optional.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 protobuf_unittest;
+
+import "google/protobuf/descriptor.proto";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.testing.proto";
+
+message TestProto3Optional {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    UNSPECIFIED = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  optional int32 optional_int32 = 1;
+  optional int64 optional_int64 = 2;
+  optional uint32 optional_uint32 = 3;
+  optional uint64 optional_uint64 = 4;
+  optional sint32 optional_sint32 = 5;
+  optional sint64 optional_sint64 = 6;
+  optional fixed32 optional_fixed32 = 7;
+  optional fixed64 optional_fixed64 = 8;
+  optional sfixed32 optional_sfixed32 = 9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional float optional_float = 11;
+  optional double optional_double = 12;
+  optional bool optional_bool = 13;
+  optional string optional_string = 14;
+  optional bytes optional_bytes = 15;
+  optional string optional_cord = 16 [ctype = CORD];
+
+  optional NestedMessage optional_nested_message = 18;
+  optional NestedMessage lazy_nested_message = 19 [lazy = true];
+  optional NestedEnum optional_nested_enum = 21;
+
+  // Add some non-optional fields to verify we can mix them.
+  int32 singular_int32 = 22;
+  int64 singular_int64 = 23;
+}
+
+message TestProto3OptionalMessage {
+  message NestedMessage {
+    string s = 1;
+  }
+
+  NestedMessage nested_message = 1;
+  optional NestedMessage optional_nested_message = 2;
+}
+
+message Proto3OptionalExtensions {
+  option (protobuf_unittest.Proto3OptionalExtensions.ext_no_optional) = 8;
+  option (protobuf_unittest.Proto3OptionalExtensions.ext_with_optional) = 16;
+
+  extend google.protobuf.MessageOptions {
+    int32 ext_no_optional = 355886728;
+    optional int32 ext_with_optional = 355886729;
+  }
+}
diff --git a/src/google/protobuf/unittest_well_known_types.proto b/src/google/protobuf/unittest_well_known_types.proto
new file mode 100644
index 0000000..c907524
--- /dev/null
+++ b/src/google/protobuf/unittest_well_known_types.proto
@@ -0,0 +1,114 @@
+syntax = "proto3";
+
+package protobuf_unittest;
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.test";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/api.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/source_context.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/type.proto";
+import "google/protobuf/wrappers.proto";
+
+// Test that we can include all well-known types.
+// Each wrapper type is included separately, as languages
+// map handle different wrappers in different ways.
+message TestWellKnownTypes {
+  google.protobuf.Any any_field = 1;
+  google.protobuf.Api api_field = 2;
+  google.protobuf.Duration duration_field = 3;
+  google.protobuf.Empty empty_field = 4;
+  google.protobuf.FieldMask field_mask_field = 5;
+  google.protobuf.SourceContext source_context_field = 6;
+  google.protobuf.Struct struct_field = 7;
+  google.protobuf.Timestamp timestamp_field = 8;
+  google.protobuf.Type type_field = 9;
+  google.protobuf.DoubleValue double_field = 10;
+  google.protobuf.FloatValue float_field = 11;
+  google.protobuf.Int64Value int64_field = 12;
+  google.protobuf.UInt64Value uint64_field = 13;
+  google.protobuf.Int32Value int32_field = 14;
+  google.protobuf.UInt32Value uint32_field = 15;
+  google.protobuf.BoolValue bool_field = 16;
+  google.protobuf.StringValue string_field = 17;
+  google.protobuf.BytesValue bytes_field = 18;
+  // Part of struct, but useful to be able to test separately
+  google.protobuf.Value value_field = 19;
+}
+
+// A repeated field for each well-known type.
+message RepeatedWellKnownTypes {
+  repeated google.protobuf.Any any_field = 1;
+  repeated google.protobuf.Api api_field = 2;
+  repeated google.protobuf.Duration duration_field = 3;
+  repeated google.protobuf.Empty empty_field = 4;
+  repeated google.protobuf.FieldMask field_mask_field = 5;
+  repeated google.protobuf.SourceContext source_context_field = 6;
+  repeated google.protobuf.Struct struct_field = 7;
+  repeated google.protobuf.Timestamp timestamp_field = 8;
+  repeated google.protobuf.Type type_field = 9;
+  // These don't actually make a lot of sense, but they're not prohibited...
+  repeated google.protobuf.DoubleValue double_field = 10;
+  repeated google.protobuf.FloatValue float_field = 11;
+  repeated google.protobuf.Int64Value int64_field = 12;
+  repeated google.protobuf.UInt64Value uint64_field = 13;
+  repeated google.protobuf.Int32Value int32_field = 14;
+  repeated google.protobuf.UInt32Value uint32_field = 15;
+  repeated google.protobuf.BoolValue bool_field = 16;
+  repeated google.protobuf.StringValue string_field = 17;
+  repeated google.protobuf.BytesValue bytes_field = 18;
+}
+
+message OneofWellKnownTypes {
+  oneof oneof_field {
+    google.protobuf.Any any_field = 1;
+    google.protobuf.Api api_field = 2;
+    google.protobuf.Duration duration_field = 3;
+    google.protobuf.Empty empty_field = 4;
+    google.protobuf.FieldMask field_mask_field = 5;
+    google.protobuf.SourceContext source_context_field = 6;
+    google.protobuf.Struct struct_field = 7;
+    google.protobuf.Timestamp timestamp_field = 8;
+    google.protobuf.Type type_field = 9;
+    google.protobuf.DoubleValue double_field = 10;
+    google.protobuf.FloatValue float_field = 11;
+    google.protobuf.Int64Value int64_field = 12;
+    google.protobuf.UInt64Value uint64_field = 13;
+    google.protobuf.Int32Value int32_field = 14;
+    google.protobuf.UInt32Value uint32_field = 15;
+    google.protobuf.BoolValue bool_field = 16;
+    google.protobuf.StringValue string_field = 17;
+    google.protobuf.BytesValue bytes_field = 18;
+  }
+}
+
+// A map field for each well-known type. We only
+// need to worry about the value part of the map being the
+// well-known types, as messages can't be map keys.
+message MapWellKnownTypes {
+  map<int32,google.protobuf.Any> any_field = 1;
+  map<int32,google.protobuf.Api> api_field = 2;
+  map<int32,google.protobuf.Duration> duration_field = 3;
+  map<int32,google.protobuf.Empty> empty_field = 4;
+  map<int32,google.protobuf.FieldMask> field_mask_field = 5;
+  map<int32,google.protobuf.SourceContext> source_context_field = 6;
+  map<int32,google.protobuf.Struct> struct_field = 7;
+  map<int32,google.protobuf.Timestamp> timestamp_field = 8;
+  map<int32,google.protobuf.Type> type_field = 9;
+  map<int32,google.protobuf.DoubleValue> double_field = 10;
+  map<int32,google.protobuf.FloatValue> float_field = 11;
+  map<int32,google.protobuf.Int64Value> int64_field = 12;
+  map<int32,google.protobuf.UInt64Value> uint64_field = 13;
+  map<int32,google.protobuf.Int32Value> int32_field = 14;
+  map<int32,google.protobuf.UInt32Value> uint32_field = 15;
+  map<int32,google.protobuf.BoolValue> bool_field = 16;
+  map<int32,google.protobuf.StringValue> string_field = 17;
+  map<int32,google.protobuf.BytesValue> bytes_field = 18;
+}
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
new file mode 100644
index 0000000..74c358e
--- /dev/null
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -0,0 +1,350 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/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>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_decl.h>
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+const UnknownFieldSet& UnknownFieldSet::default_instance() {
+  static auto instance = internal::OnShutdownDelete(new UnknownFieldSet());
+  return *instance;
+}
+
+void UnknownFieldSet::ClearFallback() {
+  GOOGLE_DCHECK(!fields_.empty());
+  int n = fields_.size();
+  do {
+    (fields_)[--n].Delete();
+  } while (n > 0);
+  fields_.clear();
+}
+
+void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) {
+  int other_field_count = other.field_count();
+  if (other_field_count > 0) {
+    fields_.reserve(fields_.size() + other_field_count);
+    for (int i = 0; i < other_field_count; i++) {
+      fields_.push_back((other.fields_)[i]);
+      fields_.back().DeepCopy((other.fields_)[i]);
+    }
+  }
+}
+
+void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
+  int other_field_count = other.field_count();
+  if (other_field_count > 0) {
+    fields_.reserve(fields_.size() + other_field_count);
+    for (int i = 0; i < other_field_count; i++) {
+      fields_.push_back((other.fields_)[i]);
+      fields_.back().DeepCopy((other.fields_)[i]);
+    }
+  }
+}
+
+// A specialized MergeFrom for performance when we are merging from an UFS that
+// is temporary and can be destroyed in the process.
+void UnknownFieldSet::MergeFromAndDestroy(UnknownFieldSet* other) {
+  if (fields_.empty()) {
+    fields_ = std::move(other->fields_);
+  } else {
+    fields_.insert(fields_.end(),
+                   std::make_move_iterator(other->fields_.begin()),
+                   std::make_move_iterator(other->fields_.end()));
+  }
+  other->fields_.clear();
+}
+
+void UnknownFieldSet::MergeToInternalMetadata(
+    const UnknownFieldSet& other, internal::InternalMetadata* metadata) {
+  metadata->mutable_unknown_fields<UnknownFieldSet>()->MergeFrom(other);
+}
+
+size_t UnknownFieldSet::SpaceUsedExcludingSelfLong() const {
+  if (fields_.empty()) return 0;
+
+  size_t total_size = sizeof(UnknownField) * fields_.capacity();
+
+  for (const UnknownField& field : fields_) {
+    switch (field.type()) {
+      case UnknownField::TYPE_LENGTH_DELIMITED:
+        total_size += sizeof(*field.data_.length_delimited_.string_value) +
+                      internal::StringSpaceUsedExcludingSelfLong(
+                          *field.data_.length_delimited_.string_value);
+        break;
+      case UnknownField::TYPE_GROUP:
+        total_size += field.data_.group_->SpaceUsedLong();
+        break;
+      default:
+        break;
+    }
+  }
+  return total_size;
+}
+
+size_t UnknownFieldSet::SpaceUsedLong() const {
+  return sizeof(*this) + SpaceUsedExcludingSelf();
+}
+
+void UnknownFieldSet::AddVarint(int number, uint64_t value) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_VARINT);
+  field.data_.varint_ = value;
+  fields_.push_back(field);
+}
+
+void UnknownFieldSet::AddFixed32(int number, uint32_t value) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_FIXED32);
+  field.data_.fixed32_ = value;
+  fields_.push_back(field);
+}
+
+void UnknownFieldSet::AddFixed64(int number, uint64_t value) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_FIXED64);
+  field.data_.fixed64_ = value;
+  fields_.push_back(field);
+}
+
+std::string* UnknownFieldSet::AddLengthDelimited(int number) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_LENGTH_DELIMITED);
+  field.data_.length_delimited_.string_value = new std::string;
+  fields_.push_back(field);
+  return field.data_.length_delimited_.string_value;
+}
+
+
+UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_GROUP);
+  field.data_.group_ = new UnknownFieldSet;
+  fields_.push_back(field);
+  return field.data_.group_;
+}
+
+void UnknownFieldSet::AddField(const UnknownField& field) {
+  fields_.push_back(field);
+  fields_.back().DeepCopy(field);
+}
+
+void UnknownFieldSet::DeleteSubrange(int start, int num) {
+  // Delete the specified fields.
+  for (int i = 0; i < num; ++i) {
+    (fields_)[i + start].Delete();
+  }
+  // Slide down the remaining fields.
+  for (size_t i = start + num; i < fields_.size(); ++i) {
+    (fields_)[i - num] = (fields_)[i];
+  }
+  // Pop off the # of deleted fields.
+  for (int i = 0; i < num; ++i) {
+    fields_.pop_back();
+  }
+}
+
+void UnknownFieldSet::DeleteByNumber(int number) {
+  size_t left = 0;  // The number of fields left after deletion.
+  for (size_t i = 0; i < fields_.size(); ++i) {
+    UnknownField* field = &(fields_)[i];
+    if (field->number() == number) {
+      field->Delete();
+    } else {
+      if (i != left) {
+        (fields_)[left] = (fields_)[i];
+      }
+      ++left;
+    }
+  }
+  fields_.resize(left);
+}
+
+bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
+  UnknownFieldSet other;
+  if (internal::WireFormat::SkipMessage(input, &other) &&
+      input->ConsumedEntireMessage()) {
+    MergeFromAndDestroy(&other);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) {
+  Clear();
+  return MergeFromCodedStream(input);
+}
+
+bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+  io::CodedInputStream coded_input(input);
+  return (ParseFromCodedStream(&coded_input) &&
+          coded_input.ConsumedEntireMessage());
+}
+
+bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
+  io::ArrayInputStream input(data, size);
+  return ParseFromZeroCopyStream(&input);
+}
+
+bool UnknownFieldSet::SerializeToString(std::string* output) const {
+  const size_t size =
+      google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(*this);
+  STLStringResizeUninitializedAmortized(output, size);
+  google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+      *this, reinterpret_cast<uint8_t*>(const_cast<char*>(output->data())));
+  return true;
+}
+
+bool UnknownFieldSet::SerializeToCodedStream(
+    io::CodedOutputStream* output) const {
+  google::protobuf::internal::WireFormat::SerializeUnknownFields(*this, output);
+  return !output->HadError();
+}
+void UnknownField::Delete() {
+  switch (type()) {
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      delete data_.length_delimited_.string_value;
+      break;
+    case UnknownField::TYPE_GROUP:
+      delete data_.group_;
+      break;
+    default:
+      break;
+  }
+}
+
+void UnknownField::DeepCopy(const UnknownField& other) {
+  (void)other;  // Parameter is used by Google-internal code.
+  switch (type()) {
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      data_.length_delimited_.string_value =
+          new std::string(*data_.length_delimited_.string_value);
+      break;
+    case UnknownField::TYPE_GROUP: {
+      UnknownFieldSet* group = new UnknownFieldSet();
+      group->InternalMergeFrom(*data_.group_);
+      data_.group_ = group;
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+
+uint8_t* UnknownField::InternalSerializeLengthDelimitedNoTag(
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+  const std::string& data = *data_.length_delimited_.string_value;
+  target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
+  target = stream->WriteRaw(data.data(), data.size(), target);
+  return target;
+}
+
+namespace internal {
+
+class UnknownFieldParserHelper {
+ public:
+  explicit UnknownFieldParserHelper(UnknownFieldSet* unknown)
+      : unknown_(unknown) {}
+
+  void AddVarint(uint32_t num, uint64_t value) {
+    unknown_->AddVarint(num, value);
+  }
+  void AddFixed64(uint32_t num, uint64_t value) {
+    unknown_->AddFixed64(num, value);
+  }
+  const char* ParseLengthDelimited(uint32_t num, const char* ptr,
+                                   ParseContext* ctx) {
+    std::string* s = unknown_->AddLengthDelimited(num);
+    int size = ReadSize(&ptr);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    return ctx->ReadString(ptr, size, s);
+  }
+  const char* ParseGroup(uint32_t num, const char* ptr, ParseContext* ctx) {
+    UnknownFieldParserHelper child(unknown_->AddGroup(num));
+    return ctx->ParseGroup(&child, ptr, num * 8 + 3);
+  }
+  void AddFixed32(uint32_t num, uint32_t value) {
+    unknown_->AddFixed32(num, value);
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return WireFormatParser(*this, ptr, ctx);
+  }
+
+ private:
+  UnknownFieldSet* unknown_;
+};
+
+const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
+                              ParseContext* ctx) {
+  UnknownFieldParserHelper field_parser(unknown);
+  return WireFormatParser(field_parser, ptr, ctx);
+}
+
+const char* UnknownFieldParse(uint64_t tag, UnknownFieldSet* unknown,
+                              const char* ptr, ParseContext* ctx) {
+  UnknownFieldParserHelper field_parser(unknown);
+  return FieldParser(tag, field_parser, ptr, ctx);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
new file mode 100644
index 0000000..9aa2cbb
--- /dev/null
+++ b/src/google/protobuf/unknown_field_set.h
@@ -0,0 +1,407 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+//
+// Contains classes used to keep track of unrecognized fields seen while
+// parsing a protocol message.
+
+#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
+#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
+
+
+#include <assert.h>
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+class InternalMetadata;           // metadata_lite.h
+class WireFormat;                 // wire_format.h
+class MessageSetFieldSkipperUsingCord;
+// extension_set_heavy.cc
+}  // namespace internal
+
+class Message;       // message.h
+class UnknownField;  // below
+
+// An UnknownFieldSet contains fields that were encountered while parsing a
+// message but were not defined by its type.  Keeping track of these can be
+// useful, especially in that they may be written if the message is serialized
+// again without being cleared in between.  This means that software which
+// simply receives messages and forwards them to other servers does not need
+// to be updated every time a new field is added to the message definition.
+//
+// To get the UnknownFieldSet attached to any message, call
+// Reflection::GetUnknownFields().
+//
+// This class is necessarily tied to the protocol buffer wire format, unlike
+// the Reflection interface which is independent of any serialization scheme.
+class PROTOBUF_EXPORT UnknownFieldSet {
+ public:
+  UnknownFieldSet();
+  ~UnknownFieldSet();
+
+  // Remove all fields.
+  inline void Clear();
+
+  // Remove all fields and deallocate internal data objects
+  void ClearAndFreeMemory();
+
+  // Is this set empty?
+  inline bool empty() const;
+
+  // Merge the contents of some other UnknownFieldSet with this one.
+  void MergeFrom(const UnknownFieldSet& other);
+
+  // Similar to above, but this function will destroy the contents of other.
+  void MergeFromAndDestroy(UnknownFieldSet* other);
+
+  // Merge the contents an UnknownFieldSet with the UnknownFieldSet in
+  // *metadata, if there is one.  If *metadata doesn't have an UnknownFieldSet
+  // then add one to it and make it be a copy of the first arg.
+  static void MergeToInternalMetadata(const UnknownFieldSet& other,
+                                      internal::InternalMetadata* metadata);
+
+  // Swaps the contents of some other UnknownFieldSet with this one.
+  inline void Swap(UnknownFieldSet* x);
+
+  // Computes (an estimate of) the total number of bytes currently used for
+  // storing the unknown fields in memory. Does NOT include
+  // sizeof(*this) in the calculation.
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+  // Version of SpaceUsed() including sizeof(*this).
+  size_t SpaceUsedLong() const;
+
+  int SpaceUsed() const { return internal::ToIntSize(SpaceUsedLong()); }
+
+  // Returns the number of fields present in the UnknownFieldSet.
+  inline int field_count() const;
+  // Get a field in the set, where 0 <= index < field_count().  The fields
+  // appear in the order in which they were added.
+  inline const UnknownField& field(int index) const;
+  // Get a mutable pointer to a field in the set, where
+  // 0 <= index < field_count().  The fields appear in the order in which
+  // they were added.
+  inline UnknownField* mutable_field(int index);
+
+  // Adding fields ---------------------------------------------------
+
+  void AddVarint(int number, uint64_t value);
+  void AddFixed32(int number, uint32_t value);
+  void AddFixed64(int number, uint64_t value);
+  void AddLengthDelimited(int number, const std::string& value);
+  std::string* AddLengthDelimited(int number);
+  UnknownFieldSet* AddGroup(int number);
+
+  // Adds an unknown field from another set.
+  void AddField(const UnknownField& field);
+
+  // Delete fields with indices in the range [start .. start+num-1].
+  // Caution: implementation moves all fields with indices [start+num .. ].
+  void DeleteSubrange(int start, int num);
+
+  // Delete all fields with a specific field number. The order of left fields
+  // is preserved.
+  // Caution: implementation moves all fields after the first deleted field.
+  void DeleteByNumber(int number);
+
+  // Parsing helpers -------------------------------------------------
+  // These work exactly like the similarly-named methods of Message.
+
+  bool MergeFromCodedStream(io::CodedInputStream* input);
+  bool ParseFromCodedStream(io::CodedInputStream* input);
+  bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
+  bool ParseFromArray(const void* data, int size);
+  inline bool ParseFromString(const std::string& data) {
+    return ParseFromArray(data.data(), static_cast<int>(data.size()));
+  }
+
+  // Merges this message's unknown field data (if any).  This works whether
+  // the message is a lite or full proto (for legacy reasons, lite and full
+  // return different types for MessageType::unknown_fields()).
+  template <typename MessageType>
+  bool MergeFromMessage(const MessageType& message);
+
+  // Serialization.
+  bool SerializeToString(std::string* output) const;
+  bool SerializeToCodedStream(io::CodedOutputStream* output) const;
+  static const UnknownFieldSet& default_instance();
+
+ private:
+  // For InternalMergeFrom
+  friend class UnknownField;
+  // Merges from other UnknownFieldSet. This method assumes, that this object
+  // is newly created and has no fields.
+  void InternalMergeFrom(const UnknownFieldSet& other);
+  void ClearFallback();
+
+  template <typename MessageType,
+            typename std::enable_if<
+                std::is_base_of<Message, MessageType>::value, int>::type = 0>
+  bool InternalMergeFromMessage(const MessageType& message) {
+    MergeFrom(message.GetReflection()->GetUnknownFields(message));
+    return true;
+  }
+
+  template <typename MessageType,
+            typename std::enable_if<
+                std::is_base_of<MessageLite, MessageType>::value &&
+                    !std::is_base_of<Message, MessageType>::value,
+                int>::type = 0>
+  bool InternalMergeFromMessage(const MessageType& message) {
+    const auto& unknown_fields = message.unknown_fields();
+    io::ArrayInputStream array_stream(unknown_fields.data(),
+                                      unknown_fields.size());
+    io::CodedInputStream coded_stream(&array_stream);
+    return MergeFromCodedStream(&coded_stream);
+  }
+
+  std::vector<UnknownField> fields_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
+};
+
+namespace internal {
+
+inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* unknown) {
+  unknown->AddVarint(num, val);
+}
+inline void WriteLengthDelimited(uint32_t num, StringPiece val,
+                                 UnknownFieldSet* unknown) {
+  unknown->AddLengthDelimited(num)->assign(val.data(), val.size());
+}
+
+PROTOBUF_EXPORT
+const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
+                              ParseContext* ctx);
+PROTOBUF_EXPORT
+const char* UnknownFieldParse(uint64_t tag, UnknownFieldSet* unknown,
+                              const char* ptr, ParseContext* ctx);
+
+}  // namespace internal
+
+// Represents one field in an UnknownFieldSet.
+class PROTOBUF_EXPORT UnknownField {
+ public:
+  enum Type {
+    TYPE_VARINT,
+    TYPE_FIXED32,
+    TYPE_FIXED64,
+    TYPE_LENGTH_DELIMITED,
+    TYPE_GROUP
+  };
+
+  // The field's field number, as seen on the wire.
+  inline int number() const;
+
+  // The field type.
+  inline Type type() const;
+
+  // Accessors -------------------------------------------------------
+  // Each method works only for UnknownFields of the corresponding type.
+
+  inline uint64_t varint() const;
+  inline uint32_t fixed32() const;
+  inline uint64_t fixed64() const;
+  inline const std::string& length_delimited() const;
+  inline const UnknownFieldSet& group() const;
+
+  inline void set_varint(uint64_t value);
+  inline void set_fixed32(uint32_t value);
+  inline void set_fixed64(uint64_t value);
+  inline void set_length_delimited(const std::string& value);
+  inline std::string* mutable_length_delimited();
+  inline UnknownFieldSet* mutable_group();
+
+  inline size_t GetLengthDelimitedSize() const;
+  uint8_t* InternalSerializeLengthDelimitedNoTag(
+      uint8_t* target, io::EpsCopyOutputStream* stream) const;
+
+
+  // If this UnknownField contains a pointer, delete it.
+  void Delete();
+
+  // Make a deep copy of any pointers in this UnknownField.
+  void DeepCopy(const UnknownField& other);
+
+  // Set the wire type of this UnknownField. Should only be used when this
+  // UnknownField is being created.
+  inline void SetType(Type type);
+
+  union LengthDelimited {
+    std::string* string_value;
+  };
+
+  uint32_t number_;
+  uint32_t type_;
+  union {
+    uint64_t varint_;
+    uint32_t fixed32_;
+    uint64_t fixed64_;
+    mutable union LengthDelimited length_delimited_;
+    UnknownFieldSet* group_;
+  } data_;
+};
+
+// ===================================================================
+// inline implementations
+
+inline UnknownFieldSet::UnknownFieldSet() {}
+
+inline UnknownFieldSet::~UnknownFieldSet() { Clear(); }
+
+inline void UnknownFieldSet::ClearAndFreeMemory() { Clear(); }
+
+inline void UnknownFieldSet::Clear() {
+  if (!fields_.empty()) {
+    ClearFallback();
+  }
+}
+
+inline bool UnknownFieldSet::empty() const { return fields_.empty(); }
+
+inline void UnknownFieldSet::Swap(UnknownFieldSet* x) {
+  fields_.swap(x->fields_);
+}
+
+inline int UnknownFieldSet::field_count() const {
+  return static_cast<int>(fields_.size());
+}
+inline const UnknownField& UnknownFieldSet::field(int index) const {
+  return (fields_)[static_cast<size_t>(index)];
+}
+inline UnknownField* UnknownFieldSet::mutable_field(int index) {
+  return &(fields_)[static_cast<size_t>(index)];
+}
+
+inline void UnknownFieldSet::AddLengthDelimited(int number,
+                                                const std::string& value) {
+  AddLengthDelimited(number)->assign(value);
+}
+
+
+
+
+inline int UnknownField::number() const { return static_cast<int>(number_); }
+inline UnknownField::Type UnknownField::type() const {
+  return static_cast<Type>(type_);
+}
+
+inline uint64_t UnknownField::varint() const {
+  assert(type() == TYPE_VARINT);
+  return data_.varint_;
+}
+inline uint32_t UnknownField::fixed32() const {
+  assert(type() == TYPE_FIXED32);
+  return data_.fixed32_;
+}
+inline uint64_t UnknownField::fixed64() const {
+  assert(type() == TYPE_FIXED64);
+  return data_.fixed64_;
+}
+inline const std::string& UnknownField::length_delimited() const {
+  assert(type() == TYPE_LENGTH_DELIMITED);
+  return *data_.length_delimited_.string_value;
+}
+inline const UnknownFieldSet& UnknownField::group() const {
+  assert(type() == TYPE_GROUP);
+  return *data_.group_;
+}
+
+inline void UnknownField::set_varint(uint64_t value) {
+  assert(type() == TYPE_VARINT);
+  data_.varint_ = value;
+}
+inline void UnknownField::set_fixed32(uint32_t value) {
+  assert(type() == TYPE_FIXED32);
+  data_.fixed32_ = value;
+}
+inline void UnknownField::set_fixed64(uint64_t value) {
+  assert(type() == TYPE_FIXED64);
+  data_.fixed64_ = value;
+}
+inline void UnknownField::set_length_delimited(const std::string& value) {
+  assert(type() == TYPE_LENGTH_DELIMITED);
+  data_.length_delimited_.string_value->assign(value);
+}
+inline std::string* UnknownField::mutable_length_delimited() {
+  assert(type() == TYPE_LENGTH_DELIMITED);
+  return data_.length_delimited_.string_value;
+}
+inline UnknownFieldSet* UnknownField::mutable_group() {
+  assert(type() == TYPE_GROUP);
+  return data_.group_;
+}
+template <typename MessageType>
+bool UnknownFieldSet::MergeFromMessage(const MessageType& message) {
+  // SFINAE will route to the right version.
+  return InternalMergeFromMessage(message);
+}
+
+
+inline size_t UnknownField::GetLengthDelimitedSize() const {
+  GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+  return data_.length_delimited_.string_value->size();
+}
+
+inline void UnknownField::SetType(Type type) {
+  type_ = type;
+}
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
new file mode 100644
index 0000000..7f9a598
--- /dev/null
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -0,0 +1,685 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 test is testing a lot more than just the UnknownFieldSet class.  It
+// tests handling of unknown fields throughout the system.
+
+#include <google/protobuf/unknown_field_set.h>
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_lite.pb.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/stubs/mutex.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+
+using internal::WireFormat;
+
+class UnknownFieldSetTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    descriptor_ = unittest::TestAllTypes::descriptor();
+    TestUtil::SetAllFields(&all_fields_);
+    all_fields_.SerializeToString(&all_fields_data_);
+    ASSERT_TRUE(empty_message_.ParseFromString(all_fields_data_));
+    unknown_fields_ = empty_message_.mutable_unknown_fields();
+  }
+
+  const UnknownField* GetField(const std::string& name) {
+    const FieldDescriptor* field = descriptor_->FindFieldByName(name);
+    if (field == nullptr) return nullptr;
+    for (int i = 0; i < unknown_fields_->field_count(); i++) {
+      if (unknown_fields_->field(i).number() == field->number()) {
+        return &unknown_fields_->field(i);
+      }
+    }
+    return nullptr;
+  }
+
+  // Constructs a protocol buffer which contains fields with all the same
+  // numbers as all_fields_data_ except that each field is some other wire
+  // type.
+  std::string GetBizarroData() {
+    unittest::TestEmptyMessage bizarro_message;
+    UnknownFieldSet* bizarro_unknown_fields =
+        bizarro_message.mutable_unknown_fields();
+    for (int i = 0; i < unknown_fields_->field_count(); i++) {
+      const UnknownField& unknown_field = unknown_fields_->field(i);
+      if (unknown_field.type() == UnknownField::TYPE_VARINT) {
+        bizarro_unknown_fields->AddFixed32(unknown_field.number(), 1);
+      } else {
+        bizarro_unknown_fields->AddVarint(unknown_field.number(), 1);
+      }
+    }
+
+    std::string data;
+    EXPECT_TRUE(bizarro_message.SerializeToString(&data));
+    return data;
+  }
+
+  const Descriptor* descriptor_;
+  unittest::TestAllTypes all_fields_;
+  std::string all_fields_data_;
+
+  // An empty message that has been parsed from all_fields_data_.  So, it has
+  // unknown fields of every type.
+  unittest::TestEmptyMessage empty_message_;
+  UnknownFieldSet* unknown_fields_;
+};
+
+namespace {
+
+TEST_F(UnknownFieldSetTest, AllFieldsPresent) {
+  // Verifies the following:
+  // --all unknown tags belong to TestAllTypes.
+  // --all fields in TestAllTypes is present in UnknownFieldSet except unset
+  //   oneof fields.
+  //
+  // Should handle repeated fields that may appear multiple times in
+  // UnknownFieldSet.
+
+  int non_oneof_count = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      non_oneof_count++;
+    }
+  }
+
+  std::unordered_set<uint32_t> unknown_tags;
+  for (int i = 0; i < unknown_fields_->field_count(); i++) {
+    unknown_tags.insert(unknown_fields_->field(i).number());
+  }
+
+  for (uint32_t t : unknown_tags) {
+    EXPECT_NE(descriptor_->FindFieldByNumber(t), nullptr);
+  }
+
+  EXPECT_EQ(non_oneof_count + descriptor_->oneof_decl_count(),
+            unknown_tags.size());
+}
+
+TEST_F(UnknownFieldSetTest, Varint) {
+  const UnknownField* field = GetField("optional_int32");
+  ASSERT_TRUE(field != nullptr);
+
+  ASSERT_EQ(UnknownField::TYPE_VARINT, field->type());
+  EXPECT_EQ(all_fields_.optional_int32(), field->varint());
+}
+
+TEST_F(UnknownFieldSetTest, Fixed32) {
+  const UnknownField* field = GetField("optional_fixed32");
+  ASSERT_TRUE(field != nullptr);
+
+  ASSERT_EQ(UnknownField::TYPE_FIXED32, field->type());
+  EXPECT_EQ(all_fields_.optional_fixed32(), field->fixed32());
+}
+
+TEST_F(UnknownFieldSetTest, Fixed64) {
+  const UnknownField* field = GetField("optional_fixed64");
+  ASSERT_TRUE(field != nullptr);
+
+  ASSERT_EQ(UnknownField::TYPE_FIXED64, field->type());
+  EXPECT_EQ(all_fields_.optional_fixed64(), field->fixed64());
+}
+
+TEST_F(UnknownFieldSetTest, LengthDelimited) {
+  const UnknownField* field = GetField("optional_string");
+  ASSERT_TRUE(field != nullptr);
+
+  ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED, field->type());
+  EXPECT_EQ(all_fields_.optional_string(), field->length_delimited());
+}
+
+TEST_F(UnknownFieldSetTest, Group) {
+  const UnknownField* field = GetField("optionalgroup");
+  ASSERT_TRUE(field != nullptr);
+
+  ASSERT_EQ(UnknownField::TYPE_GROUP, field->type());
+  ASSERT_EQ(1, field->group().field_count());
+
+  const UnknownField& nested_field = field->group().field(0);
+  const FieldDescriptor* nested_field_descriptor =
+      unittest::TestAllTypes::OptionalGroup::descriptor()->FindFieldByName("a");
+  ASSERT_TRUE(nested_field_descriptor != nullptr);
+
+  EXPECT_EQ(nested_field_descriptor->number(), nested_field.number());
+  ASSERT_EQ(UnknownField::TYPE_VARINT, nested_field.type());
+  EXPECT_EQ(all_fields_.optionalgroup().a(), nested_field.varint());
+}
+
+TEST_F(UnknownFieldSetTest, SerializeFastAndSlowAreEquivalent) {
+  int size =
+      WireFormat::ComputeUnknownFieldsSize(empty_message_.unknown_fields());
+  std::string slow_buffer;
+  std::string fast_buffer;
+  slow_buffer.resize(size);
+  fast_buffer.resize(size);
+
+  uint8_t* target =
+      reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&fast_buffer));
+  uint8_t* result = WireFormat::SerializeUnknownFieldsToArray(
+      empty_message_.unknown_fields(), target);
+  EXPECT_EQ(size, result - target);
+
+  {
+    io::ArrayOutputStream raw_stream(::google::protobuf::string_as_array(&slow_buffer), size,
+                                     1);
+    io::CodedOutputStream output_stream(&raw_stream);
+    WireFormat::SerializeUnknownFields(empty_message_.unknown_fields(),
+                                       &output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+  EXPECT_TRUE(fast_buffer == slow_buffer);
+}
+
+TEST_F(UnknownFieldSetTest, Serialize) {
+  // Check that serializing the UnknownFieldSet produces the original data
+  // again.
+
+  std::string data;
+  empty_message_.SerializeToString(&data);
+
+  // Don't use EXPECT_EQ because we don't want to dump raw binary data to
+  // stdout.
+  EXPECT_TRUE(data == all_fields_data_);
+}
+
+TEST_F(UnknownFieldSetTest, ParseViaReflection) {
+  // Make sure fields are properly parsed to the UnknownFieldSet when parsing
+  // via reflection.
+
+  unittest::TestEmptyMessage message;
+  io::ArrayInputStream raw_input(all_fields_data_.data(),
+                                 all_fields_data_.size());
+  io::CodedInputStream input(&raw_input);
+  ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message));
+
+  EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, SerializeViaReflection) {
+  // Make sure fields are properly written from the UnknownFieldSet when
+  // serializing via reflection.
+
+  std::string data;
+
+  {
+    io::StringOutputStream raw_output(&data);
+    io::CodedOutputStream output(&raw_output);
+    size_t size = WireFormat::ByteSize(empty_message_);
+    WireFormat::SerializeWithCachedSizes(empty_message_, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Don't use EXPECT_EQ because we don't want to dump raw binary data to
+  // stdout.
+  EXPECT_TRUE(data == all_fields_data_);
+}
+
+TEST_F(UnknownFieldSetTest, CopyFrom) {
+  unittest::TestEmptyMessage message;
+
+  message.CopyFrom(empty_message_);
+
+  EXPECT_EQ(empty_message_.DebugString(), message.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, Swap) {
+  unittest::TestEmptyMessage other_message;
+  ASSERT_TRUE(other_message.ParseFromString(GetBizarroData()));
+
+  EXPECT_GT(empty_message_.unknown_fields().field_count(), 0);
+  EXPECT_GT(other_message.unknown_fields().field_count(), 0);
+  const std::string debug_string = empty_message_.DebugString();
+  const std::string other_debug_string = other_message.DebugString();
+  EXPECT_NE(debug_string, other_debug_string);
+
+  empty_message_.Swap(&other_message);
+  EXPECT_EQ(debug_string, other_message.DebugString());
+  EXPECT_EQ(other_debug_string, empty_message_.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, SwapWithSelf) {
+  const std::string debug_string = empty_message_.DebugString();
+  EXPECT_GT(empty_message_.unknown_fields().field_count(), 0);
+
+  empty_message_.Swap(&empty_message_);
+  EXPECT_GT(empty_message_.unknown_fields().field_count(), 0);
+  EXPECT_EQ(debug_string, empty_message_.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, MergeFrom) {
+  unittest::TestEmptyMessage source, destination;
+
+  destination.mutable_unknown_fields()->AddVarint(1, 1);
+  destination.mutable_unknown_fields()->AddVarint(3, 2);
+  source.mutable_unknown_fields()->AddVarint(2, 3);
+  source.mutable_unknown_fields()->AddVarint(3, 4);
+
+  destination.MergeFrom(source);
+
+  std::string destination_text;
+  TextFormat::PrintToString(destination, &destination_text);
+  EXPECT_EQ(
+      // Note:  The ordering of fields here depends on the ordering of adds
+      //   and merging, above.
+      "1: 1\n"
+      "3: 2\n"
+      "2: 3\n"
+      "3: 4\n",
+      destination_text);
+}
+
+TEST_F(UnknownFieldSetTest, MergeFromMessage) {
+  unittest::TestEmptyMessage source, destination;
+
+  destination.mutable_unknown_fields()->AddVarint(1, 1);
+  destination.mutable_unknown_fields()->AddVarint(3, 2);
+  source.mutable_unknown_fields()->AddVarint(2, 3);
+  source.mutable_unknown_fields()->AddVarint(3, 4);
+
+  destination.mutable_unknown_fields()->MergeFromMessage(source);
+
+  std::string destination_text;
+  TextFormat::PrintToString(destination, &destination_text);
+  EXPECT_EQ(
+      // Note:  The ordering of fields here depends on the ordering of adds
+      //   and merging, above.
+      "1: 1\n"
+      "3: 2\n"
+      "2: 3\n"
+      "3: 4\n",
+      destination_text);
+}
+
+TEST_F(UnknownFieldSetTest, MergeFromMessageLite) {
+  unittest::TestAllTypesLite source;
+  unittest::TestEmptyMessageLite destination;
+
+  source.set_optional_fixed32(42);
+  destination.ParseFromString(source.SerializeAsString());
+
+  UnknownFieldSet unknown_field_set;
+  EXPECT_TRUE(unknown_field_set.MergeFromMessage(destination));
+  EXPECT_EQ(unknown_field_set.field_count(), 1);
+
+  const UnknownField& unknown_field = unknown_field_set.field(0);
+  EXPECT_EQ(unknown_field.number(), 7);
+  EXPECT_EQ(unknown_field.fixed32(), 42);
+}
+
+
+TEST_F(UnknownFieldSetTest, Clear) {
+  // Clear the set.
+  empty_message_.Clear();
+  EXPECT_EQ(0, unknown_fields_->field_count());
+}
+
+TEST_F(UnknownFieldSetTest, ClearAndFreeMemory) {
+  EXPECT_GT(unknown_fields_->field_count(), 0);
+  unknown_fields_->ClearAndFreeMemory();
+  EXPECT_EQ(0, unknown_fields_->field_count());
+  unknown_fields_->AddVarint(123456, 654321);
+  EXPECT_EQ(1, unknown_fields_->field_count());
+}
+
+TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) {
+  // Test mixing known and unknown fields when parsing.
+
+  unittest::TestEmptyMessage source;
+  source.mutable_unknown_fields()->AddVarint(123456, 654321);
+  std::string data;
+  ASSERT_TRUE(source.SerializeToString(&data));
+
+  unittest::TestAllTypes destination;
+  ASSERT_TRUE(destination.ParseFromString(all_fields_data_ + data));
+
+  TestUtil::ExpectAllFieldsSet(destination);
+  ASSERT_EQ(1, destination.unknown_fields().field_count());
+  ASSERT_EQ(UnknownField::TYPE_VARINT,
+            destination.unknown_fields().field(0).type());
+  EXPECT_EQ(654321, destination.unknown_fields().field(0).varint());
+}
+
+TEST_F(UnknownFieldSetTest, WrongTypeTreatedAsUnknown) {
+  // Test that fields of the wrong wire type are treated like unknown fields
+  // when parsing.
+
+  unittest::TestAllTypes all_types_message;
+  unittest::TestEmptyMessage empty_message;
+  std::string bizarro_data = GetBizarroData();
+  ASSERT_TRUE(all_types_message.ParseFromString(bizarro_data));
+  ASSERT_TRUE(empty_message.ParseFromString(bizarro_data));
+
+  // All fields should have been interpreted as unknown, so the debug strings
+  // should be the same.
+  EXPECT_EQ(empty_message.DebugString(), all_types_message.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, WrongTypeTreatedAsUnknownViaReflection) {
+  // Same as WrongTypeTreatedAsUnknown but via the reflection interface.
+
+  unittest::TestAllTypes all_types_message;
+  unittest::TestEmptyMessage empty_message;
+  std::string bizarro_data = GetBizarroData();
+  io::ArrayInputStream raw_input(bizarro_data.data(), bizarro_data.size());
+  io::CodedInputStream input(&raw_input);
+  ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &all_types_message));
+  ASSERT_TRUE(empty_message.ParseFromString(bizarro_data));
+
+  EXPECT_EQ(empty_message.DebugString(), all_types_message.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, UnknownExtensions) {
+  // Make sure fields are properly parsed to the UnknownFieldSet even when
+  // they are declared as extension numbers.
+
+  unittest::TestEmptyMessageWithExtensions message;
+  ASSERT_TRUE(message.ParseFromString(all_fields_data_));
+
+  EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, UnknownExtensionsReflection) {
+  // Same as UnknownExtensions except parsing via reflection.
+
+  unittest::TestEmptyMessageWithExtensions message;
+  io::ArrayInputStream raw_input(all_fields_data_.data(),
+                                 all_fields_data_.size());
+  io::CodedInputStream input(&raw_input);
+  ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message));
+
+  EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, WrongExtensionTypeTreatedAsUnknown) {
+  // Test that fields of the wrong wire type are treated like unknown fields
+  // when parsing extensions.
+
+  unittest::TestAllExtensions all_extensions_message;
+  unittest::TestEmptyMessage empty_message;
+  std::string bizarro_data = GetBizarroData();
+  ASSERT_TRUE(all_extensions_message.ParseFromString(bizarro_data));
+  ASSERT_TRUE(empty_message.ParseFromString(bizarro_data));
+
+  // All fields should have been interpreted as unknown, so the debug strings
+  // should be the same.
+  EXPECT_EQ(empty_message.DebugString(), all_extensions_message.DebugString());
+}
+
+TEST_F(UnknownFieldSetTest, UnknownEnumValue) {
+  using unittest::TestAllExtensions;
+  using unittest::TestAllTypes;
+  using unittest::TestEmptyMessage;
+
+  const FieldDescriptor* singular_field =
+      TestAllTypes::descriptor()->FindFieldByName("optional_nested_enum");
+  const FieldDescriptor* repeated_field =
+      TestAllTypes::descriptor()->FindFieldByName("repeated_nested_enum");
+  ASSERT_TRUE(singular_field != nullptr);
+  ASSERT_TRUE(repeated_field != nullptr);
+
+  std::string data;
+
+  {
+    TestEmptyMessage empty_message;
+    UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields();
+    unknown_fields->AddVarint(singular_field->number(), TestAllTypes::BAR);
+    unknown_fields->AddVarint(singular_field->number(), 5);  // not valid
+    unknown_fields->AddVarint(repeated_field->number(), TestAllTypes::FOO);
+    unknown_fields->AddVarint(repeated_field->number(), 4);  // not valid
+    unknown_fields->AddVarint(repeated_field->number(), TestAllTypes::BAZ);
+    unknown_fields->AddVarint(repeated_field->number(), 6);  // not valid
+    empty_message.SerializeToString(&data);
+  }
+
+  {
+    TestAllTypes message;
+    ASSERT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(TestAllTypes::BAR, message.optional_nested_enum());
+    ASSERT_EQ(2, message.repeated_nested_enum_size());
+    EXPECT_EQ(TestAllTypes::FOO, message.repeated_nested_enum(0));
+    EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(1));
+
+    const UnknownFieldSet& unknown_fields = message.unknown_fields();
+    ASSERT_EQ(3, unknown_fields.field_count());
+
+    EXPECT_EQ(singular_field->number(), unknown_fields.field(0).number());
+    ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(0).type());
+    EXPECT_EQ(5, unknown_fields.field(0).varint());
+
+    EXPECT_EQ(repeated_field->number(), unknown_fields.field(1).number());
+    ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(1).type());
+    EXPECT_EQ(4, unknown_fields.field(1).varint());
+
+    EXPECT_EQ(repeated_field->number(), unknown_fields.field(2).number());
+    ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(2).type());
+    EXPECT_EQ(6, unknown_fields.field(2).varint());
+  }
+
+  {
+    using unittest::optional_nested_enum_extension;
+    using unittest::repeated_nested_enum_extension;
+
+    TestAllExtensions message;
+    ASSERT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(TestAllTypes::BAR,
+              message.GetExtension(optional_nested_enum_extension));
+    ASSERT_EQ(2, message.ExtensionSize(repeated_nested_enum_extension));
+    EXPECT_EQ(TestAllTypes::FOO,
+              message.GetExtension(repeated_nested_enum_extension, 0));
+    EXPECT_EQ(TestAllTypes::BAZ,
+              message.GetExtension(repeated_nested_enum_extension, 1));
+
+    const UnknownFieldSet& unknown_fields = message.unknown_fields();
+    ASSERT_EQ(3, unknown_fields.field_count());
+
+    EXPECT_EQ(singular_field->number(), unknown_fields.field(0).number());
+    ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(0).type());
+    EXPECT_EQ(5, unknown_fields.field(0).varint());
+
+    EXPECT_EQ(repeated_field->number(), unknown_fields.field(1).number());
+    ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(1).type());
+    EXPECT_EQ(4, unknown_fields.field(1).varint());
+
+    EXPECT_EQ(repeated_field->number(), unknown_fields.field(2).number());
+    ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(2).type());
+    EXPECT_EQ(6, unknown_fields.field(2).varint());
+  }
+}
+
+TEST_F(UnknownFieldSetTest, SpaceUsedExcludingSelf) {
+  UnknownFieldSet empty;
+  empty.AddVarint(1, 0);
+  EXPECT_EQ(sizeof(UnknownField), empty.SpaceUsedExcludingSelf());
+}
+
+TEST_F(UnknownFieldSetTest, SpaceUsed) {
+  // Keep shadow vectors to avoid making assumptions about its capacity growth.
+  // We imitate the push back calls here to determine the expected capacity.
+  std::vector<UnknownField> shadow_vector, shadow_vector_group;
+  unittest::TestEmptyMessage empty_message;
+
+  // Make sure an unknown field set has zero space used until a field is
+  // actually added.
+  const size_t base = empty_message.SpaceUsedLong();
+  std::string* str = nullptr;
+  UnknownFieldSet* group = nullptr;
+  const auto total = [&] {
+    size_t result = base;
+    result += shadow_vector.capacity() * sizeof(UnknownField);
+    result += shadow_vector_group.capacity() * sizeof(UnknownField);
+    if (str != nullptr) {
+      result += sizeof(std::string);
+      static const size_t sso_capacity = std::string().capacity();
+      if (str->capacity() > sso_capacity) result += str->capacity();
+    }
+    if (group != nullptr) {
+      result += sizeof(UnknownFieldSet);
+    }
+    return result;
+  };
+
+  UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields();
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong());
+
+  // Make sure each thing we add to the set increases the SpaceUsedLong().
+  unknown_fields->AddVarint(1, 0);
+  shadow_vector.emplace_back();
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong()) << "Var";
+
+  str = unknown_fields->AddLengthDelimited(1);
+  shadow_vector.emplace_back();
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong()) << "Str";
+
+  str->assign(sizeof(std::string) + 1, 'x');
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong()) << "Str2";
+
+  group = unknown_fields->AddGroup(1);
+  shadow_vector.emplace_back();
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong()) << "Group";
+
+  group->AddVarint(1, 0);
+  shadow_vector_group.emplace_back();
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong()) << "Group2";
+
+  unknown_fields->AddVarint(1, 0);
+  shadow_vector.emplace_back();
+  EXPECT_EQ(total(), empty_message.SpaceUsedLong()) << "Var2";
+}
+
+
+TEST_F(UnknownFieldSetTest, Empty) {
+  UnknownFieldSet unknown_fields;
+  EXPECT_TRUE(unknown_fields.empty());
+  unknown_fields.AddVarint(6, 123);
+  EXPECT_FALSE(unknown_fields.empty());
+  unknown_fields.Clear();
+  EXPECT_TRUE(unknown_fields.empty());
+}
+
+TEST_F(UnknownFieldSetTest, DeleteSubrange) {
+  // Exhaustively test the deletion of every possible subrange in arrays of all
+  // sizes from 0 through 9.
+  for (int size = 0; size < 10; ++size) {
+    for (int num = 0; num <= size; ++num) {
+      for (int start = 0; start < size - num; ++start) {
+        // Create a set with "size" fields.
+        UnknownFieldSet unknown;
+        for (int i = 0; i < size; ++i) {
+          unknown.AddFixed32(i, i);
+        }
+        // Delete the specified subrange.
+        unknown.DeleteSubrange(start, num);
+        // Make sure the resulting field values are still correct.
+        EXPECT_EQ(size - num, unknown.field_count());
+        for (int i = 0; i < unknown.field_count(); ++i) {
+          if (i < start) {
+            EXPECT_EQ(i, unknown.field(i).fixed32());
+          } else {
+            EXPECT_EQ(i + num, unknown.field(i).fixed32());
+          }
+        }
+      }
+    }
+  }
+}
+
+void CheckDeleteByNumber(const std::vector<int>& field_numbers,
+                         int deleted_number,
+                         const std::vector<int>& expected_field_nubmers) {
+  UnknownFieldSet unknown_fields;
+  for (int i = 0; i < field_numbers.size(); ++i) {
+    unknown_fields.AddFixed32(field_numbers[i], i);
+  }
+  unknown_fields.DeleteByNumber(deleted_number);
+  ASSERT_EQ(expected_field_nubmers.size(), unknown_fields.field_count());
+  for (int i = 0; i < expected_field_nubmers.size(); ++i) {
+    EXPECT_EQ(expected_field_nubmers[i], unknown_fields.field(i).number());
+  }
+}
+
+#define MAKE_VECTOR(x) std::vector<int>(x, x + GOOGLE_ARRAYSIZE(x))
+TEST_F(UnknownFieldSetTest, DeleteByNumber) {
+  CheckDeleteByNumber(std::vector<int>(), 1, std::vector<int>());
+  static const int kTestFieldNumbers1[] = {1, 2, 3};
+  static const int kFieldNumberToDelete1 = 1;
+  static const int kExpectedFieldNumbers1[] = {2, 3};
+  CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers1), kFieldNumberToDelete1,
+                      MAKE_VECTOR(kExpectedFieldNumbers1));
+  static const int kTestFieldNumbers2[] = {1, 2, 3};
+  static const int kFieldNumberToDelete2 = 2;
+  static const int kExpectedFieldNumbers2[] = {1, 3};
+  CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers2), kFieldNumberToDelete2,
+                      MAKE_VECTOR(kExpectedFieldNumbers2));
+  static const int kTestFieldNumbers3[] = {1, 2, 3};
+  static const int kFieldNumberToDelete3 = 3;
+  static const int kExpectedFieldNumbers3[] = {1, 2};
+  CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers3), kFieldNumberToDelete3,
+                      MAKE_VECTOR(kExpectedFieldNumbers3));
+  static const int kTestFieldNumbers4[] = {1, 2, 1, 4, 1};
+  static const int kFieldNumberToDelete4 = 1;
+  static const int kExpectedFieldNumbers4[] = {2, 4};
+  CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers4), kFieldNumberToDelete4,
+                      MAKE_VECTOR(kExpectedFieldNumbers4));
+  static const int kTestFieldNumbers5[] = {1, 2, 3, 4, 5};
+  static const int kFieldNumberToDelete5 = 6;
+  static const int kExpectedFieldNumbers5[] = {1, 2, 3, 4, 5};
+  CheckDeleteByNumber(MAKE_VECTOR(kTestFieldNumbers5), kFieldNumberToDelete5,
+                      MAKE_VECTOR(kExpectedFieldNumbers5));
+}
+#undef MAKE_VECTOR
+
+}  // namespace
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/delimited_message_util.cc b/src/google/protobuf/util/delimited_message_util.cc
new file mode 100644
index 0000000..fdc633f
--- /dev/null
+++ b/src/google/protobuf/util/delimited_message_util.cc
@@ -0,0 +1,128 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Adapted from the patch of kenton@google.com (Kenton Varda)
+// See https://github.com/protocolbuffers/protobuf/pull/710 for details.
+
+#include <google/protobuf/util/delimited_message_util.h>
+#include <google/protobuf/io/coded_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+bool SerializeDelimitedToFileDescriptor(const MessageLite& message,
+                                        int file_descriptor) {
+  io::FileOutputStream output(file_descriptor);
+  return SerializeDelimitedToZeroCopyStream(message, &output);
+}
+
+bool SerializeDelimitedToOstream(const MessageLite& message,
+                                 std::ostream* output) {
+  {
+    io::OstreamOutputStream zero_copy_output(output);
+    if (!SerializeDelimitedToZeroCopyStream(message, &zero_copy_output))
+      return false;
+  }
+  return output->good();
+}
+
+bool ParseDelimitedFromZeroCopyStream(MessageLite* message,
+                                      io::ZeroCopyInputStream* input,
+                                      bool* clean_eof) {
+  io::CodedInputStream coded_input(input);
+  return ParseDelimitedFromCodedStream(message, &coded_input, clean_eof);
+}
+
+bool ParseDelimitedFromCodedStream(MessageLite* message,
+                                   io::CodedInputStream* input,
+                                   bool* clean_eof) {
+  if (clean_eof != nullptr) *clean_eof = false;
+  int start = input->CurrentPosition();
+
+  // Read the size.
+  uint32_t size;
+  if (!input->ReadVarint32(&size)) {
+    if (clean_eof != nullptr) *clean_eof = input->CurrentPosition() == start;
+    return false;
+  }
+
+  // Get the position after any size bytes have been read (and only the message
+  // itself remains).
+  int position_after_size = input->CurrentPosition();
+
+  // Tell the stream not to read beyond that size.
+  io::CodedInputStream::Limit limit = input->PushLimit(static_cast<int>(size));
+
+  // Parse the message.
+  if (!message->MergeFromCodedStream(input)) return false;
+  if (!input->ConsumedEntireMessage()) return false;
+  if (input->CurrentPosition() - position_after_size != static_cast<int>(size))
+    return false;
+
+  // Release the limit.
+  input->PopLimit(limit);
+
+  return true;
+}
+
+bool SerializeDelimitedToZeroCopyStream(const MessageLite& message,
+                                        io::ZeroCopyOutputStream* output) {
+  io::CodedOutputStream coded_output(output);
+  return SerializeDelimitedToCodedStream(message, &coded_output);
+}
+
+bool SerializeDelimitedToCodedStream(const MessageLite& message,
+                                     io::CodedOutputStream* output) {
+  // Write the size.
+  size_t size = message.ByteSizeLong();
+  if (size > INT_MAX) return false;
+
+  output->WriteVarint32(static_cast<uint32_t>(size));
+
+  // Write the content.
+  uint8_t* buffer =
+      output->GetDirectBufferForNBytesAndAdvance(static_cast<int>(size));
+  if (buffer != nullptr) {
+    // Optimization: The message fits in one buffer, so use the faster
+    // direct-to-array serialization path.
+    message.SerializeWithCachedSizesToArray(buffer);
+  } else {
+    // Slightly-slower path when the message is multiple buffers.
+    message.SerializeWithCachedSizes(output);
+    if (output->HadError()) return false;
+  }
+
+  return true;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/delimited_message_util.h b/src/google/protobuf/util/delimited_message_util.h
new file mode 100644
index 0000000..78625cf
--- /dev/null
+++ b/src/google/protobuf/util/delimited_message_util.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Adapted from the patch of kenton@google.com (Kenton Varda)
+// See https://github.com/protocolbuffers/protobuf/pull/710 for details.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_DELIMITED_MESSAGE_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_DELIMITED_MESSAGE_UTIL_H__
+
+
+#include <ostream>
+
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Write a single size-delimited message from the given stream. Delimited
+// format allows a single file or stream to contain multiple messages,
+// whereas normally writing multiple non-delimited messages to the same
+// stream would cause them to be merged. A delimited message is a varint
+// encoding the message size followed by a message of exactly that size.
+//
+// Note that if you want to *read* a delimited message from a file descriptor
+// or istream, you will need to construct an io::FileInputStream or
+// io::OstreamInputStream (implementations of io::ZeroCopyStream) and use the
+// utility function ParseDelimitedFromZeroCopyStream(). You must then
+// continue to use the same ZeroCopyInputStream to read all further data from
+// the stream until EOF. This is because these ZeroCopyInputStream
+// implementations are buffered: they read a big chunk of data at a time,
+// then parse it. As a result, they may read past the end of the delimited
+// message. There is no way for them to push the extra data back into the
+// underlying source, so instead you must keep using the same stream object.
+bool PROTOBUF_EXPORT SerializeDelimitedToFileDescriptor(
+    const MessageLite& message, int file_descriptor);
+
+bool PROTOBUF_EXPORT SerializeDelimitedToOstream(const MessageLite& message,
+                                                 std::ostream* output);
+
+// Read a single size-delimited message from the given stream. Delimited
+// format allows a single file or stream to contain multiple messages,
+// whereas normally parsing consumes the entire input. A delimited message
+// is a varint encoding the message size followed by a message of exactly
+// that size.
+//
+// If |clean_eof| is not NULL, then it will be set to indicate whether the
+// stream ended cleanly. That is, if the stream ends without this method
+// having read any data at all from it, then *clean_eof will be set true,
+// otherwise it will be set false. Note that these methods return false
+// on EOF, but they also return false on other errors, so |clean_eof| is
+// needed to distinguish a clean end from errors.
+bool PROTOBUF_EXPORT ParseDelimitedFromZeroCopyStream(
+    MessageLite* message, io::ZeroCopyInputStream* input, bool* clean_eof);
+
+bool PROTOBUF_EXPORT ParseDelimitedFromCodedStream(MessageLite* message,
+                                                   io::CodedInputStream* input,
+                                                   bool* clean_eof);
+
+// Write a single size-delimited message from the given stream. Delimited
+// format allows a single file or stream to contain multiple messages,
+// whereas normally writing multiple non-delimited messages to the same
+// stream would cause them to be merged. A delimited message is a varint
+// encoding the message size followed by a message of exactly that size.
+bool PROTOBUF_EXPORT SerializeDelimitedToZeroCopyStream(
+    const MessageLite& message, io::ZeroCopyOutputStream* output);
+
+bool PROTOBUF_EXPORT SerializeDelimitedToCodedStream(
+    const MessageLite& message, io::CodedOutputStream* output);
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_DELIMITED_MESSAGE_UTIL_H__
diff --git a/src/google/protobuf/util/delimited_message_util_test.cc b/src/google/protobuf/util/delimited_message_util_test.cc
new file mode 100644
index 0000000..9483a64
--- /dev/null
+++ b/src/google/protobuf/util/delimited_message_util_test.cc
@@ -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.
+
+// Adapted from the patch of kenton@google.com (Kenton Varda)
+// See https://github.com/protocolbuffers/protobuf/pull/710 for details.
+
+#include <google/protobuf/util/delimited_message_util.h>
+
+#include <sstream>
+
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+TEST(DelimitedMessageUtilTest, DelimitedMessages) {
+  std::stringstream stream;
+
+  {
+    protobuf_unittest::TestAllTypes message1;
+    TestUtil::SetAllFields(&message1);
+    EXPECT_TRUE(SerializeDelimitedToOstream(message1, &stream));
+
+    protobuf_unittest::TestPackedTypes message2;
+    TestUtil::SetPackedFields(&message2);
+    EXPECT_TRUE(SerializeDelimitedToOstream(message2, &stream));
+  }
+
+  {
+    bool clean_eof;
+    io::IstreamInputStream zstream(&stream);
+
+    protobuf_unittest::TestAllTypes message1;
+    clean_eof = true;
+    EXPECT_TRUE(ParseDelimitedFromZeroCopyStream(&message1,
+        &zstream, &clean_eof));
+    EXPECT_FALSE(clean_eof);
+    TestUtil::ExpectAllFieldsSet(message1);
+
+    protobuf_unittest::TestPackedTypes message2;
+    clean_eof = true;
+    EXPECT_TRUE(ParseDelimitedFromZeroCopyStream(&message2,
+        &zstream, &clean_eof));
+    EXPECT_FALSE(clean_eof);
+    TestUtil::ExpectPackedFieldsSet(message2);
+
+    clean_eof = false;
+    EXPECT_FALSE(ParseDelimitedFromZeroCopyStream(&message2,
+        &zstream, &clean_eof));
+    EXPECT_TRUE(clean_eof);
+  }
+}
+
+TEST(DelimitedMessageUtilTest, FailsAtEndOfStream) {
+  std::stringstream full_stream;
+  std::stringstream partial_stream;
+
+  {
+    protobuf_unittest::ForeignMessage message;
+    message.set_c(42);
+    message.set_d(24);
+    EXPECT_TRUE(SerializeDelimitedToOstream(message, &full_stream));
+
+    std::string full_output = full_stream.str();
+    ASSERT_GT(full_output.size(), size_t{2});
+    ASSERT_EQ(full_output[0], 4);
+
+    partial_stream << full_output[0] << full_output[1] << full_output[2];
+  }
+
+  {
+    bool clean_eof;
+    io::IstreamInputStream zstream(&partial_stream);
+
+    protobuf_unittest::ForeignMessage message;
+    clean_eof = true;
+    EXPECT_FALSE(ParseDelimitedFromZeroCopyStream(&message,
+        &zstream, &clean_eof));
+    EXPECT_FALSE(clean_eof);
+  }
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc
new file mode 100644
index 0000000..5d8e865
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator.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: ksroka@google.com (Krzysztof Sroka)
+
+#include <google/protobuf/util/field_comparator.h>
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+FieldComparator::FieldComparator() {}
+FieldComparator::~FieldComparator() {}
+
+SimpleFieldComparator::SimpleFieldComparator()
+    : float_comparison_(EXACT),
+      treat_nan_as_equal_(false),
+      has_default_tolerance_(false) {}
+
+SimpleFieldComparator::~SimpleFieldComparator() {}
+
+FieldComparator::ComparisonResult SimpleFieldComparator::SimpleCompare(
+    const Message& message_1, const Message& message_2,
+    const FieldDescriptor* field, int index_1, int index_2,
+    const util::FieldContext* /*field_context*/) {
+  const Reflection* reflection_1 = message_1.GetReflection();
+  const Reflection* reflection_2 = message_2.GetReflection();
+
+  switch (field->cpp_type()) {
+#define COMPARE_FIELD(METHOD)                                                 \
+  if (field->is_repeated()) {                                                 \
+    return ResultFromBoolean(Compare##METHOD(                                 \
+        *field, reflection_1->GetRepeated##METHOD(message_1, field, index_1), \
+        reflection_2->GetRepeated##METHOD(message_2, field, index_2)));       \
+  } else {                                                                    \
+    return ResultFromBoolean(                                                 \
+        Compare##METHOD(*field, reflection_1->Get##METHOD(message_1, field),  \
+                        reflection_2->Get##METHOD(message_2, field)));        \
+  }                                                                           \
+  break;  // Make sure no fall-through is introduced.
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      COMPARE_FIELD(Bool);
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      COMPARE_FIELD(Double);
+    case FieldDescriptor::CPPTYPE_ENUM:
+      COMPARE_FIELD(Enum);
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      COMPARE_FIELD(Float);
+    case FieldDescriptor::CPPTYPE_INT32:
+      COMPARE_FIELD(Int32);
+    case FieldDescriptor::CPPTYPE_INT64:
+      COMPARE_FIELD(Int64);
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->is_repeated()) {
+        // Allocate scratch strings to store the result if a conversion is
+        // needed.
+        std::string scratch1;
+        std::string scratch2;
+        return ResultFromBoolean(
+            CompareString(*field,
+                          reflection_1->GetRepeatedStringReference(
+                              message_1, field, index_1, &scratch1),
+                          reflection_2->GetRepeatedStringReference(
+                              message_2, field, index_2, &scratch2)));
+      } else {
+        // Allocate scratch strings to store the result if a conversion is
+        // needed.
+        std::string scratch1;
+        std::string scratch2;
+        return ResultFromBoolean(CompareString(
+            *field,
+            reflection_1->GetStringReference(message_1, field, &scratch1),
+            reflection_2->GetStringReference(message_2, field, &scratch2)));
+      }
+      break;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      COMPARE_FIELD(UInt32);
+    case FieldDescriptor::CPPTYPE_UINT64:
+      COMPARE_FIELD(UInt64);
+
+#undef COMPARE_FIELD
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return RECURSE;
+
+    default:
+      GOOGLE_LOG(FATAL) << "No comparison code for field " << field->full_name()
+                 << " of CppType = " << field->cpp_type();
+      return DIFFERENT;
+  }
+}
+
+bool SimpleFieldComparator::CompareWithDifferencer(
+    MessageDifferencer* differencer, const Message& message1,
+    const Message& message2, const util::FieldContext* field_context) {
+  return differencer->Compare(message1, message2,
+                              field_context->parent_fields());
+}
+
+void SimpleFieldComparator::SetDefaultFractionAndMargin(double fraction,
+                                                        double margin) {
+  default_tolerance_ = Tolerance(fraction, margin);
+  has_default_tolerance_ = true;
+}
+
+void SimpleFieldComparator::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 SimpleFieldComparator::CompareDouble(const FieldDescriptor& field,
+                                          double value_1, double value_2) {
+  return CompareDoubleOrFloat(field, value_1, value_2);
+}
+
+bool SimpleFieldComparator::CompareEnum(const FieldDescriptor& /*field*/,
+                                        const EnumValueDescriptor* value_1,
+                                        const EnumValueDescriptor* value_2) {
+  return value_1->number() == value_2->number();
+}
+
+bool SimpleFieldComparator::CompareFloat(const FieldDescriptor& field,
+                                         float value_1, float value_2) {
+  return CompareDoubleOrFloat(field, value_1, value_2);
+}
+
+template <typename T>
+bool SimpleFieldComparator::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_ && std::isnan(value_1) && std::isnan(value_2)) {
+      return true;
+    }
+    return false;
+  } else {
+    if (treat_nan_as_equal_ && std::isnan(value_1) && std::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 explicitly 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 SimpleFieldComparator::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..5706da3
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator.h
@@ -0,0 +1,288 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines classes for field comparison.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
+#define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
+
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class EnumValueDescriptor;
+class FieldDescriptor;
+
+namespace util {
+
+class FieldContext;
+class MessageDifferencer;
+
+// 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 PROTOBUF_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 Message& message_1,
+                                   const Message& message_2,
+                                   const FieldDescriptor* field, int index_1,
+                                   int index_2,
+                                   const util::FieldContext* field_context) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator);
+};
+
+// Basic implementation of FieldComparator.  Supports three modes of floating
+// point value comparison: exact, approximate using MathUtil::AlmostEqual
+// method, and arbitrarily precise using MathUtil::WithinFractionOrMargin.
+class PROTOBUF_EXPORT SimpleFieldComparator : 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 differentiate uses of AlmostEqual
+    //               and WithinFractionOrMargin.
+  };
+
+  // Creates new comparator with float comparison set to EXACT.
+  SimpleFieldComparator();
+
+  ~SimpleFieldComparator() override;
+
+  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);
+
+ protected:
+  // Returns the comparison result for the given field in two messages.
+  //
+  // This function is called directly by DefaultFieldComparator::Compare.
+  // Subclasses can call this function to compare fields they do not need to
+  // handle specially.
+  ComparisonResult SimpleCompare(const Message& message_1,
+                                 const Message& message_2,
+                                 const FieldDescriptor* field, int index_1,
+                                 int index_2,
+                                 const util::FieldContext* field_context);
+
+  // Compare using the provided message_differencer. For example, a subclass can
+  // use this method to compare some field in a certain way using the same
+  // message_differencer instance and the field context.
+  bool CompareWithDifferencer(MessageDifferencer* differencer,
+                              const Message& message1, const Message& message2,
+                              const util::FieldContext* field_context);
+
+  // Returns FieldComparator::SAME if boolean_result is true and
+  // FieldComparator::DIFFERENT otherwise.
+  ComparisonResult ResultFromBoolean(bool boolean_result) const;
+
+ 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 std::map<const FieldDescriptor*, Tolerance> ToleranceMap;
+
+  friend class MessageDifferencer;
+  // 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 FieldDescriptor& /* unused */, 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 FieldDescriptor& field, double value_1,
+                     double value_2);
+
+  bool CompareEnum(const FieldDescriptor& field,
+                   const EnumValueDescriptor* value_1,
+                   const EnumValueDescriptor* value_2);
+
+  // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
+  // CompareFloat.
+  bool CompareFloat(const FieldDescriptor& field, float value_1, float value_2);
+
+  bool CompareInt32(const FieldDescriptor& /* unused */, int32_t value_1,
+                    int32_t value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareInt64(const FieldDescriptor& /* unused */, int64_t value_1,
+                    int64_t value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareString(const FieldDescriptor& /* unused */,
+                     const std::string& value_1, const std::string& value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareUInt32(const FieldDescriptor& /* unused */, uint32_t value_1,
+                     uint32_t value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareUInt64(const FieldDescriptor& /* unused */, uint64_t value_1,
+                     uint64_t 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 FieldDescriptor& field, T value_1, T value_2);
+
+  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 floats 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(SimpleFieldComparator);
+};
+
+// Default field comparison: use the basic implementation of FieldComparator.
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+class PROTOBUF_EXPORT DefaultFieldComparator final
+    : public SimpleFieldComparator
+#else   // PROTOBUF_FUTURE_BREAKING_CHANGES
+class PROTOBUF_EXPORT DefaultFieldComparator : public SimpleFieldComparator
+#endif  // PROTOBUF_FUTURE_BREAKING_CHANGES
+{
+ public:
+  ComparisonResult Compare(const Message& message_1, const Message& message_2,
+                           const FieldDescriptor* field, int index_1,
+                           int index_2,
+                           const util::FieldContext* field_context) override {
+    return SimpleCompare(message_1, message_2, field, index_1, index_2,
+                         field_context);
+  }
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..b680277
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -0,0 +1,505 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <limits>
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+
+using protobuf_unittest::TestAllTypes;
+
+class DefaultFieldComparatorTest : public ::testing::Test {
+ protected:
+  void SetUp() override { 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, nullptr));
+}
+
+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, nullptr));
+}
+
+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, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_int32(-1);
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_int64(-1L);
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_uint32(2);
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_uint64(2L);
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_bool(false);
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_nested_enum(TestAllTypes::BAZ);
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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, nullptr));
+
+  message_2_.set_optional_string("bar");
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
+}
+
+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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+}
+
+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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+}
+
+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(std::numeric_limits<float>::quiet_NaN());
+  message_2_.set_optional_float(std::numeric_limits<float>::quiet_NaN());
+  message_1_.set_optional_double(std::numeric_limits<double>::quiet_NaN());
+  message_2_.set_optional_double(std::numeric_limits<double>::quiet_NaN());
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+}
+
+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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // +inf should be equal even though they are not technically within margin or
+  // fraction.
+  message_1_.set_optional_float(std::numeric_limits<float>::infinity());
+  message_2_.set_optional_float(std::numeric_limits<float>::infinity());
+  message_1_.set_optional_double(std::numeric_limits<double>::infinity());
+  message_2_.set_optional_double(std::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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // -inf should be equal even though they are not technically within margin or
+  // fraction.
+  message_1_.set_optional_float(-std::numeric_limits<float>::infinity());
+  message_2_.set_optional_float(-std::numeric_limits<float>::infinity());
+  message_1_.set_optional_double(-std::numeric_limits<double>::infinity());
+  message_2_.set_optional_double(-std::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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // Finite values and inf should not be equal, even for a positive fraction.
+  message_1_.set_optional_float(std::numeric_limits<float>::infinity());
+  message_2_.set_optional_float(0.0f);
+  message_1_.set_optional_double(std::numeric_limits<double>::infinity());
+  message_2_.set_optional_double(0.0);
+  comparator_.SetFractionAndMargin(field_float, 0.1, 0.0);
+  comparator_.SetFractionAndMargin(field_double, 0.1, 0.0);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+}
+
+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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  // 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,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+
+  // The field with an override should still be OK
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+
+  // 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,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
+}
+
+// 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, nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, 1, 1, nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, 1, 0, nullptr));
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // 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..700e590
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -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.
+
+#include <google/protobuf/util/field_mask_util.h>
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/stubs/map_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::FieldMask;
+
+std::string FieldMaskUtil::ToString(const FieldMask& mask) {
+  return Join(mask.paths(), ",");
+}
+
+void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
+  out->Clear();
+  std::vector<std::string> paths = Split(str, ",");
+  for (const std::string& path : paths) {
+    if (path.empty()) continue;
+    out->add_paths(path);
+  }
+}
+
+bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input,
+                                         std::string* output) {
+  output->clear();
+  bool after_underscore = false;
+  for (char input_char : input) {
+    if (input_char >= 'A' && input_char <= 'Z') {
+      // The field name must not contain uppercase letters.
+      return false;
+    }
+    if (after_underscore) {
+      if (input_char >= 'a' && input_char <= 'z') {
+        output->push_back(input_char + 'A' - 'a');
+        after_underscore = false;
+      } else {
+        // The character after a "_" must be a lowercase letter.
+        return false;
+      }
+    } else if (input_char == '_') {
+      after_underscore = true;
+    } else {
+      output->push_back(input_char);
+    }
+  }
+  if (after_underscore) {
+    // Trailing "_".
+    return false;
+  }
+  return true;
+}
+
+bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input,
+                                         std::string* output) {
+  output->clear();
+  for (const char c : input) {
+    if (c == '_') {
+      // The field name must not contain "_"s.
+      return false;
+    }
+    if (c >= 'A' && c <= 'Z') {
+      output->push_back('_');
+      output->push_back(c + 'a' - 'A');
+    } else {
+      output->push_back(c);
+    }
+  }
+  return true;
+}
+
+bool FieldMaskUtil::ToJsonString(const FieldMask& mask, std::string* out) {
+  out->clear();
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    const std::string& path = mask.paths(i);
+    std::string camelcase_path;
+    if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
+      return false;
+    }
+    if (i > 0) {
+      out->push_back(',');
+    }
+    out->append(camelcase_path);
+  }
+  return true;
+}
+
+bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
+  out->Clear();
+  std::vector<std::string> paths = Split(str, ",");
+  for (const std::string& path : paths) {
+    if (path.empty()) continue;
+    std::string snakecase_path;
+    if (!CamelCaseToSnakeCase(path, &snakecase_path)) {
+      return false;
+    }
+    out->add_paths(snakecase_path);
+  }
+  return true;
+}
+
+bool FieldMaskUtil::GetFieldDescriptors(
+    const Descriptor* descriptor, StringPiece path,
+    std::vector<const FieldDescriptor*>* field_descriptors) {
+  if (field_descriptors != nullptr) {
+    field_descriptors->clear();
+  }
+  std::vector<std::string> parts = Split(path, ".");
+  for (const std::string& field_name : parts) {
+    if (descriptor == nullptr) {
+      return false;
+    }
+    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
+    if (field == nullptr) {
+      return false;
+    }
+    if (field_descriptors != nullptr) {
+      field_descriptors->push_back(field);
+    }
+    if (!field->is_repeated() &&
+        field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      descriptor = field->message_type();
+    } else {
+      descriptor = nullptr;
+    }
+  }
+  return true;
+}
+
+void FieldMaskUtil::GetFieldMaskForAllFields(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 std::string& path);
+
+  // Remove a path from the tree.
+  // If the path is a sub-path of an existing field path in the tree, it means
+  // we need remove the existing field path and add all sub-paths except
+  // specified path. If the path matches an existing node in the tree, this node
+  // will be moved.
+  void RemovePath(const std::string& path, const Descriptor* descriptor);
+
+  // Calculate the intersection part of a field path with this tree and add
+  // the intersection field path into out.
+  void IntersectPath(const std::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);
+  }
+
+  // Add required field path of the message to this tree based on current tree
+  // structure. If a message is present in the tree, add the path of its
+  // required field to the tree. This is to make sure that after trimming a
+  // message with required fields are set, check IsInitialized() will not fail.
+  void AddRequiredFieldPath(const Descriptor* descriptor) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return;
+    }
+    AddRequiredFieldPath(&root_, descriptor);
+  }
+
+  // Trims all fields not specified by this tree from the given message.
+  // Returns true if the message is modified.
+  bool TrimMessage(Message* message) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return false;
+    }
+    return TrimMessage(&root_, message);
+  }
+
+ private:
+  struct Node {
+    Node() {}
+
+    ~Node() { ClearChildren(); }
+
+    void ClearChildren() {
+      for (std::map<std::string, Node*>::iterator it = children.begin();
+           it != children.end(); ++it) {
+        delete it->second;
+      }
+      children.clear();
+    }
+
+    std::map<std::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 std::string& prefix, const Node* node,
+                        FieldMask* out);
+
+  // Merge all leaf nodes of a sub-tree to another tree.
+  void MergeLeafNodesToTree(const std::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);
+
+  // Add required field path of the message to this tree based on current tree
+  // structure. If a message is present in the tree, add the path of its
+  // required field to the tree. This is to make sure that after trimming a
+  // message with required fields are set, check IsInitialized() will not fail.
+  void AddRequiredFieldPath(Node* node, const Descriptor* descriptor);
+
+  // Trims all fields not specified by this sub-tree from the given message.
+  // Returns true if the message is actually modified
+  bool TrimMessage(const Node* node, Message* message);
+
+  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 std::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 (std::map<std::string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    std::string current_path =
+        prefix.empty() ? it->first : prefix + "." + it->first;
+    MergeToFieldMask(current_path, it->second, out);
+  }
+}
+
+void FieldMaskTree::AddPath(const std::string& path) {
+  std::vector<std::string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  bool new_branch = false;
+  Node* node = &root_;
+  for (const std::string& node_name : parts) {
+    if (!new_branch && node != &root_ && node->children.empty()) {
+      // Path matches an existing leaf node. This means the path is already
+      // covered by this tree (for example, adding "foo.bar.baz" to a tree
+      // which already contains "foo.bar").
+      return;
+    }
+    Node*& child = node->children[node_name];
+    if (child == nullptr) {
+      new_branch = true;
+      child = new Node();
+    }
+    node = child;
+  }
+  if (!node->children.empty()) {
+    node->ClearChildren();
+  }
+}
+
+void FieldMaskTree::RemovePath(const std::string& path,
+                               const Descriptor* descriptor) {
+  if (root_.children.empty()) {
+    // Nothing to be removed from an empty tree. We shortcut it here so an empty
+    // tree won't be interpreted as a field mask containing all fields by the
+    // code below.
+    return;
+  }
+  std::vector<std::string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  std::vector<Node*> nodes(parts.size());
+  Node* node = &root_;
+  const Descriptor* current_descriptor = descriptor;
+  Node* new_branch_node = nullptr;
+  for (int i = 0; i < parts.size(); ++i) {
+    nodes[i] = node;
+    const FieldDescriptor* field_descriptor =
+        current_descriptor->FindFieldByName(parts[i]);
+    if (field_descriptor == nullptr ||
+        (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
+         i != parts.size() - 1)) {
+      // Invalid path.
+      if (new_branch_node != nullptr) {
+        // If add any new nodes, cleanup.
+        new_branch_node->ClearChildren();
+      }
+      return;
+    }
+
+    if (node->children.empty()) {
+      if (new_branch_node == nullptr) {
+        new_branch_node = node;
+      }
+      for (int j = 0; j < current_descriptor->field_count(); ++j) {
+        node->children[current_descriptor->field(j)->name()] = new Node();
+      }
+    }
+    if (ContainsKey(node->children, parts[i])) {
+      node = node->children[parts[i]];
+      if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        current_descriptor = field_descriptor->message_type();
+      }
+    } else {
+      // Path does not exist.
+      return;
+    }
+  }
+  // Remove path.
+  for (int i = parts.size() - 1; i >= 0; i--) {
+    delete nodes[i]->children[parts[i]];
+    nodes[i]->children.erase(parts[i]);
+    if (!nodes[i]->children.empty()) {
+      break;
+    }
+  }
+}
+
+void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) {
+  std::vector<std::string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  const Node* node = &root_;
+  for (const std::string& node_name : parts) {
+    if (node->children.empty()) {
+      if (node != &root_) {
+        out->AddPath(path);
+      }
+      return;
+    }
+    const Node* result = FindPtrOrNull(node->children, node_name);
+    if (result == nullptr) {
+      // 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 std::string& prefix,
+                                         const Node* node, FieldMaskTree* out) {
+  if (node->children.empty()) {
+    out->AddPath(prefix);
+  }
+  for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    std::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 (std::map<std::string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    const std::string& field_name = it->first;
+    const Node* child = it->second;
+    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
+    if (field == nullptr) {
+      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: {                                   \
+    if (source_reflection->HasField(source, field)) {                       \
+      destination_reflection->Set##Name(                                    \
+          destination, field, source_reflection->Get##Name(source, field)); \
+    } else {                                                                \
+      destination_reflection->ClearField(destination, 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;
+        }
+      }
+    }
+  }
+}
+
+void FieldMaskTree::AddRequiredFieldPath(Node* node,
+                                         const Descriptor* descriptor) {
+  const int32_t field_count = descriptor->field_count();
+  for (int index = 0; index < field_count; ++index) {
+    const FieldDescriptor* field = descriptor->field(index);
+    if (field->is_required()) {
+      const std::string& node_name = field->name();
+      Node*& child = node->children[node_name];
+      if (child == nullptr) {
+        // Add required field path to the tree
+        child = new Node();
+      } else if (child->children.empty()) {
+        // If the required field is in the tree and does not have any children,
+        // do nothing.
+        continue;
+      }
+      // Add required field in the children to the tree if the field is message.
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        AddRequiredFieldPath(child, field->message_type());
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      std::map<std::string, Node*>::const_iterator it =
+          node->children.find(field->name());
+      if (it != node->children.end()) {
+        // Add required fields in the children to the
+        // tree if the field is a message and present in the tree.
+        Node* child = it->second;
+        if (!child->children.empty()) {
+          AddRequiredFieldPath(child, field->message_type());
+        }
+      }
+    }
+  }
+}
+
+bool FieldMaskTree::TrimMessage(const Node* node, Message* message) {
+  GOOGLE_DCHECK(!node->children.empty());
+  const Reflection* reflection = message->GetReflection();
+  const Descriptor* descriptor = message->GetDescriptor();
+  const int32_t field_count = descriptor->field_count();
+  bool modified = false;
+  for (int index = 0; index < field_count; ++index) {
+    const FieldDescriptor* field = descriptor->field(index);
+    std::map<std::string, Node*>::const_iterator it =
+        node->children.find(field->name());
+    if (it == node->children.end()) {
+      if (field->is_repeated()) {
+        if (reflection->FieldSize(*message, field) != 0) {
+          modified = true;
+        }
+      } else {
+        if (reflection->HasField(*message, field)) {
+          modified = true;
+        }
+      }
+      reflection->ClearField(message, field);
+    } else {
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        Node* child = it->second;
+        if (!child->children.empty() && reflection->HasField(*message, field)) {
+          bool nestedMessageChanged =
+              TrimMessage(child, reflection->MutableMessage(message, field));
+          modified = nestedMessageChanged || modified;
+        }
+      }
+    }
+  }
+  return modified;
+}
+
+}  // 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);
+}
+
+void FieldMaskUtil::Subtract(const Descriptor* descriptor,
+                             const FieldMask& mask1, const FieldMask& mask2,
+                             FieldMask* out) {
+  if (mask1.paths().empty()) {
+    out->Clear();
+    return;
+  }
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask1);
+  for (int i = 0; i < mask2.paths_size(); ++i) {
+    tree.RemovePath(mask2.paths(i), descriptor);
+  }
+  out->Clear();
+  tree.MergeToFieldMask(out);
+}
+
+bool FieldMaskUtil::IsPathInFieldMask(StringPiece path,
+                                      const FieldMask& mask) {
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    const std::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);
+}
+
+bool FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* message) {
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  return tree.TrimMessage(GOOGLE_CHECK_NOTNULL(message));
+}
+
+bool FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* message,
+                                const TrimOptions& options) {
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  // If keep_required_fields is true, implicitly add required fields of
+  // a message present in the tree to prevent from trimming.
+  if (options.keep_required_fields()) {
+    tree.AddRequiredFieldPath(GOOGLE_CHECK_NOTNULL(message->GetDescriptor()));
+  }
+  return tree.TrimMessage(GOOGLE_CHECK_NOTNULL(message));
+}
+
+}  // 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..d51a332
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -0,0 +1,263 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines utilities for the FieldMask well known type.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
+
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+class PROTOBUF_EXPORT FieldMaskUtil {
+  typedef google::protobuf::FieldMask FieldMask;
+
+ public:
+  // Converts FieldMask to/from string, formatted by separating each path
+  // with a comma (e.g., "foo_bar,baz.quz").
+  static std::string ToString(const FieldMask& mask);
+  static void FromString(StringPiece str, FieldMask* out);
+
+  // Populates the FieldMask with the paths corresponding to the fields with the
+  // given numbers, after checking that all field numbers are valid.
+  template <typename T>
+  static void FromFieldNumbers(const std::vector<int64_t>& field_numbers,
+                               FieldMask* out) {
+    for (const auto field_number : field_numbers) {
+      const FieldDescriptor* field_desc =
+          T::descriptor()->FindFieldByNumber(field_number);
+      GOOGLE_CHECK(field_desc != nullptr)
+          << "Invalid field number for " << T::descriptor()->full_name() << ": "
+          << field_number;
+      AddPathToFieldMask<T>(field_desc->lowercase_name(), out);
+    }
+  }
+
+  // Converts FieldMask to/from string, formatted according to proto3 JSON
+  // spec for FieldMask (e.g., "fooBar,baz.quz"). If the field name is not
+  // style conforming (i.e., not snake_case when converted to string, or not
+  // camelCase when converted from string), the conversion will fail.
+  static bool ToJsonString(const FieldMask& mask, std::string* out);
+  static bool FromJsonString(StringPiece str, FieldMask* out);
+
+  // Get the descriptors of the fields which the given path from the message
+  // descriptor traverses, if field_descriptors is not null.
+  // Return false if the path is not valid, and the content of field_descriptors
+  // is unspecified.
+  static bool GetFieldDescriptors(
+      const Descriptor* descriptor, StringPiece path,
+      std::vector<const FieldDescriptor*>* field_descriptors);
+
+  // Checks whether the given path is valid for type T.
+  template <typename T>
+  static bool IsValidPath(StringPiece path) {
+    return GetFieldDescriptors(T::descriptor(), path, nullptr);
+  }
+
+  // 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 (!GetFieldDescriptors(T::descriptor(), mask.paths(i), nullptr)) {
+        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)) << path;
+    mask->add_paths(std::string(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 FieldMask GetFieldMaskForAllFields() {
+    FieldMask out;
+    GetFieldMaskForAllFields(T::descriptor(), &out);
+    return out;
+  }
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Use *out = GetFieldMaskForAllFields() instead")
+  static void GetFieldMaskForAllFields(FieldMask* out) {
+    GetFieldMaskForAllFields(T::descriptor(), out);
+  }
+  // This flavor takes the protobuf type descriptor as an argument.
+  // Useful when the type is not known at compile time.
+  static void GetFieldMaskForAllFields(const Descriptor* descriptor,
+                                       FieldMask* 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);
+
+  // Subtracts mask2 from mask1 base of type T.
+  template <typename T>
+  static void Subtract(const FieldMask& mask1, const FieldMask& mask2,
+                       FieldMask* out) {
+    Subtract(T::descriptor(), mask1, mask2, out);
+  }
+  // This flavor takes the protobuf type descriptor as an argument.
+  // Useful when the type is not known at compile time.
+  static void Subtract(const Descriptor* descriptor, 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.
+  // Also note that parent paths are not covered by explicit child path, i.e.
+  // "foo.bar" does NOT cover "foo", even if "bar" is the only child.
+  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);
+
+  class TrimOptions;
+  // Removes from 'message' any field that is not represented in the given
+  // FieldMask. If the FieldMask is empty, does nothing.
+  // Returns true if the message is modified.
+  static bool TrimMessage(const FieldMask& mask, Message* message);
+
+  // Removes from 'message' any field that is not represented in the given
+  // FieldMask with customized TrimOptions.
+  // If the FieldMask is empty, does nothing.
+  // Returns true if the message is modified.
+  static bool TrimMessage(const FieldMask& mask, Message* message,
+                          const TrimOptions& options);
+
+ private:
+  friend class SnakeCaseCamelCaseTest;
+  // Converts a field name from snake_case to camelCase:
+  //   1. Every character after "_" will be converted to uppercase.
+  //   2. All "_"s are removed.
+  // The conversion will fail if:
+  //   1. The field name contains uppercase letters.
+  //   2. Any character after a "_" is not a lowercase letter.
+  // If the conversion succeeds, it's guaranteed that the resulted
+  // camelCase name will yield the original snake_case name when
+  // converted using CamelCaseToSnakeCase().
+  //
+  // Note that the input can contain characters not allowed in C identifiers.
+  // For example, "foo_bar,baz_quz" will be converted to "fooBar,bazQuz"
+  // successfully.
+  static bool SnakeCaseToCamelCase(StringPiece input,
+                                   std::string* output);
+  // Converts a field name from camelCase to snake_case:
+  //   1. Every uppercase letter is converted to lowercase with an additional
+  //      preceding "_".
+  // The conversion will fail if:
+  //   1. The field name contains "_"s.
+  // If the conversion succeeds, it's guaranteed that the resulted
+  // snake_case name will yield the original camelCase name when
+  // converted using SnakeCaseToCamelCase().
+  //
+  // Note that the input can contain characters not allowed in C identifiers.
+  // For example, "fooBar,bazQuz" will be converted to "foo_bar,baz_quz"
+  // successfully.
+  static bool CamelCaseToSnakeCase(StringPiece input,
+                                   std::string* output);
+};
+
+class PROTOBUF_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_;
+};
+
+class PROTOBUF_EXPORT FieldMaskUtil::TrimOptions {
+ public:
+  TrimOptions() : keep_required_fields_(false) {}
+  // When trimming message fields, the default behavior is to trim required
+  // fields of the present message if they are not specified in the field mask.
+  // If you instead want to keep required fields of the present message even
+  // when they are not specified in the field mask, set this flag to true.
+  void set_keep_required_fields(bool value) { keep_required_fields_ = value; }
+  bool keep_required_fields() const { return keep_required_fields_; }
+
+ private:
+  bool keep_required_fields_;
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..bcad739
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util_test.cc
@@ -0,0 +1,836 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/field_mask_util.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <vector>
+
+#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+class SnakeCaseCamelCaseTest : public ::testing::Test {
+ protected:
+  std::string SnakeCaseToCamelCase(const std::string& input) {
+    std::string output;
+    if (FieldMaskUtil::SnakeCaseToCamelCase(input, &output)) {
+      return output;
+    } else {
+      return "#FAIL#";
+    }
+  }
+
+  std::string CamelCaseToSnakeCase(const std::string& input) {
+    std::string output;
+    if (FieldMaskUtil::CamelCaseToSnakeCase(input, &output)) {
+      return output;
+    } else {
+      return "#FAIL#";
+    }
+  }
+};
+
+namespace {
+
+TEST_F(SnakeCaseCamelCaseTest, SnakeToCamel) {
+  EXPECT_EQ("fooBar", SnakeCaseToCamelCase("foo_bar"));
+  EXPECT_EQ("FooBar", SnakeCaseToCamelCase("_foo_bar"));
+  EXPECT_EQ("foo3Bar", SnakeCaseToCamelCase("foo3_bar"));
+  // No uppercase letter is allowed.
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("Foo"));
+  // Any character after a "_" must be a lowercase letter.
+  //   1. "_" cannot be followed by another "_".
+  //   2. "_" cannot be followed by a digit.
+  //   3. "_" cannot appear as the last character.
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo__bar"));
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_3bar"));
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_bar_"));
+}
+
+TEST_F(SnakeCaseCamelCaseTest, CamelToSnake) {
+  EXPECT_EQ("foo_bar", CamelCaseToSnakeCase("fooBar"));
+  EXPECT_EQ("_foo_bar", CamelCaseToSnakeCase("FooBar"));
+  EXPECT_EQ("foo3_bar", CamelCaseToSnakeCase("foo3Bar"));
+  // "_"s are not allowed.
+  EXPECT_EQ("#FAIL#", CamelCaseToSnakeCase("foo_bar"));
+}
+
+TEST_F(SnakeCaseCamelCaseTest, RoundTripTest) {
+  // Enumerates all possible snake_case names and test that converting it to
+  // camelCase and then to snake_case again will yield the original name.
+  std::string name = "___abc123";
+  std::sort(name.begin(), name.end());
+  do {
+    std::string camelName = SnakeCaseToCamelCase(name);
+    if (camelName != "#FAIL#") {
+      EXPECT_EQ(name, CamelCaseToSnakeCase(camelName));
+    }
+  } while (std::next_permutation(name.begin(), name.end()));
+
+  // Enumerates all possible camelCase names and test that converting it to
+  // snake_case and then to camelCase again will yield the original name.
+  name = "abcABC123";
+  std::sort(name.begin(), name.end());
+  do {
+    std::string camelName = CamelCaseToSnakeCase(name);
+    if (camelName != "#FAIL#") {
+      EXPECT_EQ(name, SnakeCaseToCamelCase(camelName));
+    }
+  } while (std::next_permutation(name.begin(), name.end()));
+}
+
+using google::protobuf::FieldMask;
+using protobuf_unittest::NestedTestAllTypes;
+using protobuf_unittest::TestAllTypes;
+using protobuf_unittest::TestRequired;
+using protobuf_unittest::TestRequiredMessage;
+
+TEST(FieldMaskUtilTest, StringFormat) {
+  FieldMask mask;
+  EXPECT_EQ("", FieldMaskUtil::ToString(mask));
+  mask.add_paths("foo_bar");
+  EXPECT_EQ("foo_bar", FieldMaskUtil::ToString(mask));
+  mask.add_paths("baz_quz");
+  EXPECT_EQ("foo_bar,baz_quz", FieldMaskUtil::ToString(mask));
+
+  FieldMaskUtil::FromString("", &mask);
+  EXPECT_EQ(0, mask.paths_size());
+  FieldMaskUtil::FromString("fooBar", &mask);
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_EQ("fooBar", mask.paths(0));
+  FieldMaskUtil::FromString("fooBar,bazQuz", &mask);
+  EXPECT_EQ(2, mask.paths_size());
+  EXPECT_EQ("fooBar", mask.paths(0));
+  EXPECT_EQ("bazQuz", mask.paths(1));
+}
+
+TEST(FieldMaskUtilTest, JsonStringFormat) {
+  FieldMask mask;
+  std::string value;
+  EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value));
+  EXPECT_EQ("", value);
+  mask.add_paths("foo_bar");
+  EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value));
+  EXPECT_EQ("fooBar", value);
+  mask.add_paths("bar_quz");
+  EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value));
+  EXPECT_EQ("fooBar,barQuz", value);
+
+  FieldMaskUtil::FromJsonString("", &mask);
+  EXPECT_EQ(0, mask.paths_size());
+  FieldMaskUtil::FromJsonString("fooBar", &mask);
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_EQ("foo_bar", mask.paths(0));
+  FieldMaskUtil::FromJsonString("fooBar,bazQuz", &mask);
+  EXPECT_EQ(2, mask.paths_size());
+  EXPECT_EQ("foo_bar", mask.paths(0));
+  EXPECT_EQ("baz_quz", mask.paths(1));
+}
+
+TEST(FieldMaskUtilTest, FromFieldNumbers) {
+  FieldMask mask;
+  std::vector<int64_t> field_numbers = {
+      TestAllTypes::kOptionalInt64FieldNumber,
+      TestAllTypes::kOptionalBoolFieldNumber,
+      TestAllTypes::kRepeatedStringFieldNumber,
+  };
+  FieldMaskUtil::FromFieldNumbers<TestAllTypes>(field_numbers, &mask);
+  ASSERT_EQ(3, mask.paths_size());
+  EXPECT_EQ("optional_int64", mask.paths(0));
+  EXPECT_EQ("optional_bool", mask.paths(1));
+  EXPECT_EQ("repeated_string", mask.paths(2));
+}
+
+TEST(FieldMaskUtilTest, GetFieldDescriptors) {
+  std::vector<const FieldDescriptor*> field_descriptors;
+  EXPECT_TRUE(FieldMaskUtil::GetFieldDescriptors(
+      TestAllTypes::descriptor(), "optional_int32", &field_descriptors));
+  EXPECT_EQ(1, field_descriptors.size());
+  EXPECT_EQ("optional_int32", field_descriptors[0]->name());
+  EXPECT_FALSE(FieldMaskUtil::GetFieldDescriptors(
+      TestAllTypes::descriptor(), "optional_nonexist", nullptr));
+  EXPECT_TRUE(FieldMaskUtil::GetFieldDescriptors(TestAllTypes::descriptor(),
+                                                 "optional_nested_message.bb",
+                                                 &field_descriptors));
+  EXPECT_EQ(2, field_descriptors.size());
+  EXPECT_EQ("optional_nested_message", field_descriptors[0]->name());
+  EXPECT_EQ("bb", field_descriptors[1]->name());
+  EXPECT_FALSE(FieldMaskUtil::GetFieldDescriptors(
+      TestAllTypes::descriptor(), "optional_nested_message.nonexist", nullptr));
+  // FieldMask cannot be used to specify sub-fields of a repeated message.
+  EXPECT_FALSE(FieldMaskUtil::GetFieldDescriptors(
+      TestAllTypes::descriptor(), "repeated_nested_message.bb", nullptr));
+}
+
+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;
+  mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes::NestedMessage>();
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask));
+
+  mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>();
+  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, TestSubtract) {
+  FieldMask mask1, mask2, out;
+  // Normal case.
+  FieldMaskUtil::FromString(
+      "optional_int32,optional_uint64,optional_nested_message,optional_foreign_"
+      "message,repeated_int32,repeated_foreign_message,repeated_nested_message."
+      "bb",
+      &mask1);
+
+  FieldMaskUtil::FromString(
+      "optional_int32,optional_nested_message.bb,optional_foreign_message.c,"
+      "repeated_int32,repeated_nested_message.bb,repeated_foreign_message.f,"
+      "repeated_foreign_message.d,repeated_nested_message.bb,repeated_uint32",
+      &mask2);
+
+  FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out);
+  EXPECT_EQ(
+      "optional_foreign_message.d,optional_uint64,repeated_foreign_message.c",
+      FieldMaskUtil::ToString(out));
+
+  // mask1 is empty.
+  FieldMaskUtil::FromString("", &mask1);
+  FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out);
+  EXPECT_EQ("", FieldMaskUtil::ToString(out));
+
+  // mask1 is "optional_nested_message" and mask2 is
+  // "optional_nested_message.nonexist_field".
+  FieldMaskUtil::FromString("optional_nested_message", &mask1);
+  FieldMaskUtil::FromString("optional_nested_message.nonexist_field", &mask2);
+  FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out);
+  EXPECT_EQ("optional_nested_message", FieldMaskUtil::ToString(out));
+
+  // mask1 is "optional_nested_message" and mask2 is
+  // "optional_nested_message".
+  FieldMaskUtil::FromString("optional_nested_message", &mask1);
+  FieldMaskUtil::FromString("optional_nested_message", &mask2);
+  FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out);
+  EXPECT_EQ("", FieldMaskUtil::ToString(out));
+
+  // Regression test for b/72727550
+  FieldMaskUtil::FromString("optional_foreign_message.c", &mask1);
+  FieldMaskUtil::FromString("optional_foreign_message,optional_nested_message",
+                            &mask2);
+  FieldMaskUtil::Subtract<TestAllTypes>(mask1, mask2, &out);
+  EXPECT_EQ("", 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());         \
+    src.clear_##field_name();                                \
+    tmp.clear_##field_name();                                \
+    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));
+}
+
+TEST(FieldMaskUtilTest, TrimMessage) {
+#define TEST_TRIM_ONE_PRIMITIVE_FIELD(field_name)    \
+  {                                                  \
+    TestAllTypes msg;                                \
+    TestUtil::SetAllFields(&msg);                    \
+    TestAllTypes tmp;                                \
+    tmp.set_##field_name(msg.field_name());          \
+    FieldMask mask;                                  \
+    mask.add_paths(#field_name);                     \
+    FieldMaskUtil::TrimMessage(mask, &msg);          \
+    EXPECT_EQ(tmp.DebugString(), msg.DebugString()); \
+  }
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_int32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_int64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_uint32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_uint64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sint32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sint64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_fixed32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_fixed64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sfixed32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sfixed64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_float)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_double)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_bool)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_string)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_bytes)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_nested_enum)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_foreign_enum)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_import_enum)
+#undef TEST_TRIM_ONE_PRIMITIVE_FIELD
+
+#define TEST_TRIM_ONE_FIELD(field_name)              \
+  {                                                  \
+    TestAllTypes msg;                                \
+    TestUtil::SetAllFields(&msg);                    \
+    TestAllTypes tmp;                                \
+    *tmp.mutable_##field_name() = msg.field_name();  \
+    FieldMask mask;                                  \
+    mask.add_paths(#field_name);                     \
+    FieldMaskUtil::TrimMessage(mask, &msg);          \
+    EXPECT_EQ(tmp.DebugString(), msg.DebugString()); \
+  }
+  TEST_TRIM_ONE_FIELD(optional_nested_message)
+  TEST_TRIM_ONE_FIELD(optional_foreign_message)
+  TEST_TRIM_ONE_FIELD(optional_import_message)
+
+  TEST_TRIM_ONE_FIELD(repeated_int32)
+  TEST_TRIM_ONE_FIELD(repeated_int64)
+  TEST_TRIM_ONE_FIELD(repeated_uint32)
+  TEST_TRIM_ONE_FIELD(repeated_uint64)
+  TEST_TRIM_ONE_FIELD(repeated_sint32)
+  TEST_TRIM_ONE_FIELD(repeated_sint64)
+  TEST_TRIM_ONE_FIELD(repeated_fixed32)
+  TEST_TRIM_ONE_FIELD(repeated_fixed64)
+  TEST_TRIM_ONE_FIELD(repeated_sfixed32)
+  TEST_TRIM_ONE_FIELD(repeated_sfixed64)
+  TEST_TRIM_ONE_FIELD(repeated_float)
+  TEST_TRIM_ONE_FIELD(repeated_double)
+  TEST_TRIM_ONE_FIELD(repeated_bool)
+  TEST_TRIM_ONE_FIELD(repeated_string)
+  TEST_TRIM_ONE_FIELD(repeated_bytes)
+  TEST_TRIM_ONE_FIELD(repeated_nested_message)
+  TEST_TRIM_ONE_FIELD(repeated_foreign_message)
+  TEST_TRIM_ONE_FIELD(repeated_import_message)
+  TEST_TRIM_ONE_FIELD(repeated_nested_enum)
+  TEST_TRIM_ONE_FIELD(repeated_foreign_enum)
+  TEST_TRIM_ONE_FIELD(repeated_import_enum)
+#undef TEST_TRIM_ONE_FIELD
+
+  // Test trim nested fields.
+  NestedTestAllTypes nested_msg;
+  nested_msg.mutable_child()->mutable_payload()->set_optional_int32(1234);
+  nested_msg.mutable_child()
+      ->mutable_child()
+      ->mutable_payload()
+      ->set_optional_int32(5678);
+  NestedTestAllTypes trimmed_msg(nested_msg);
+  FieldMask mask;
+  FieldMaskUtil::FromString("child.payload", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(1234, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(0, trimmed_msg.child().child().payload().optional_int32());
+
+  trimmed_msg = nested_msg;
+  FieldMaskUtil::FromString("child.child.payload", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(0, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+  trimmed_msg = nested_msg;
+  FieldMaskUtil::FromString("child", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(1234, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+  trimmed_msg = nested_msg;
+  FieldMaskUtil::FromString("child.child", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(0, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+  // Verify than an empty FieldMask trims nothing
+  TestAllTypes all_types_msg;
+  TestUtil::SetAllFields(&all_types_msg);
+  TestAllTypes trimmed_all_types(all_types_msg);
+  FieldMask empty_mask;
+  FieldMaskUtil::TrimMessage(empty_mask, &trimmed_all_types);
+  EXPECT_EQ(trimmed_all_types.DebugString(), all_types_msg.DebugString());
+
+  // Test trim required fields with keep_required_fields is set true.
+  FieldMaskUtil::TrimOptions options;
+  TestRequired required_msg_1;
+  required_msg_1.set_a(1234);
+  required_msg_1.set_b(3456);
+  required_msg_1.set_c(5678);
+  TestRequired trimmed_required_msg_1(required_msg_1);
+  FieldMaskUtil::FromString("dummy2", &mask);
+  options.set_keep_required_fields(true);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_required_msg_1, options);
+  EXPECT_EQ(trimmed_required_msg_1.DebugString(), required_msg_1.DebugString());
+
+  // Test trim required fields with keep_required_fields is set false.
+  required_msg_1.clear_a();
+  required_msg_1.clear_b();
+  required_msg_1.clear_c();
+  options.set_keep_required_fields(false);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_required_msg_1, options);
+  EXPECT_EQ(trimmed_required_msg_1.DebugString(), required_msg_1.DebugString());
+
+  // Test trim required message with keep_required_fields is set true.
+  TestRequiredMessage required_msg_2;
+  required_msg_2.mutable_optional_message()->set_a(1234);
+  required_msg_2.mutable_optional_message()->set_b(3456);
+  required_msg_2.mutable_optional_message()->set_c(5678);
+  required_msg_2.mutable_required_message()->set_a(1234);
+  required_msg_2.mutable_required_message()->set_b(3456);
+  required_msg_2.mutable_required_message()->set_c(5678);
+  required_msg_2.mutable_required_message()->set_dummy2(7890);
+  TestRequired* repeated_msg = required_msg_2.add_repeated_message();
+  repeated_msg->set_a(1234);
+  repeated_msg->set_b(3456);
+  repeated_msg->set_c(5678);
+  TestRequiredMessage trimmed_required_msg_2(required_msg_2);
+  FieldMaskUtil::FromString("optional_message.dummy2", &mask);
+  options.set_keep_required_fields(true);
+  required_msg_2.clear_repeated_message();
+  required_msg_2.mutable_required_message()->clear_dummy2();
+  FieldMaskUtil::TrimMessage(mask, &trimmed_required_msg_2, options);
+  EXPECT_EQ(trimmed_required_msg_2.DebugString(), required_msg_2.DebugString());
+
+  FieldMaskUtil::FromString("required_message", &mask);
+  required_msg_2.mutable_required_message()->set_dummy2(7890);
+  trimmed_required_msg_2.mutable_required_message()->set_dummy2(7890);
+  required_msg_2.clear_optional_message();
+  FieldMaskUtil::TrimMessage(mask, &trimmed_required_msg_2, options);
+  EXPECT_EQ(trimmed_required_msg_2.DebugString(), required_msg_2.DebugString());
+
+  // Test trim required message with keep_required_fields is set false.
+  FieldMaskUtil::FromString("required_message.dummy2", &mask);
+  required_msg_2.mutable_required_message()->clear_a();
+  required_msg_2.mutable_required_message()->clear_b();
+  required_msg_2.mutable_required_message()->clear_c();
+  options.set_keep_required_fields(false);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_required_msg_2, options);
+  EXPECT_EQ(trimmed_required_msg_2.DebugString(), required_msg_2.DebugString());
+
+  // Verify that trimming an empty message has no effect. In particular, fields
+  // mentioned in the field mask should not be created or changed.
+  TestAllTypes empty_msg;
+  FieldMaskUtil::FromString(
+      "optional_int32,optional_bytes,optional_nested_message.bb", &mask);
+  FieldMaskUtil::TrimMessage(mask, &empty_msg);
+  EXPECT_FALSE(empty_msg.has_optional_int32());
+  EXPECT_FALSE(empty_msg.has_optional_bytes());
+  EXPECT_FALSE(empty_msg.has_optional_nested_message());
+
+  // Verify trimming of oneof fields. This should work as expected even if
+  // multiple elements of the same oneof are included in the FieldMask.
+  TestAllTypes oneof_msg;
+  oneof_msg.set_oneof_uint32(11);
+  FieldMaskUtil::FromString("oneof_uint32,oneof_nested_message.bb", &mask);
+  FieldMaskUtil::TrimMessage(mask, &oneof_msg);
+  EXPECT_EQ(11, oneof_msg.oneof_uint32());
+}
+
+TEST(FieldMaskUtilTest, TrimMessageReturnValue) {
+  FieldMask mask;
+  TestAllTypes trimed_msg;
+  TestAllTypes default_msg;
+
+  // Field mask on optional field.
+  FieldMaskUtil::FromString("optional_int32", &mask);
+
+  // Verify that if a message is updated by FieldMaskUtil::TrimMessage(), the
+  // function returns true.
+  // Test on primary field.
+  trimed_msg.set_optional_string("abc");
+  EXPECT_TRUE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.DebugString(), default_msg.DebugString());
+  trimed_msg.Clear();
+
+  // Test on repeated primary field.
+  trimed_msg.add_repeated_string("abc");
+  trimed_msg.add_repeated_string("def");
+  EXPECT_TRUE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.DebugString(), default_msg.DebugString());
+  trimed_msg.Clear();
+
+  // Test on nested message.
+  trimed_msg.mutable_optional_nested_message()->set_bb(123);
+  EXPECT_TRUE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.DebugString(), default_msg.DebugString());
+  trimed_msg.Clear();
+
+  // Test on repeated nested message.
+  trimed_msg.add_repeated_nested_message()->set_bb(123);
+  trimed_msg.add_repeated_nested_message()->set_bb(456);
+  EXPECT_TRUE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.DebugString(), default_msg.DebugString());
+  trimed_msg.Clear();
+
+  // Test on oneof field.
+  trimed_msg.set_oneof_uint32(123);
+  EXPECT_TRUE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.DebugString(), default_msg.DebugString());
+  trimed_msg.Clear();
+
+  // If there is no field set other then those whitelisted,
+  // FieldMaskUtil::TrimMessage() should return false.
+  trimed_msg.set_optional_int32(123);
+  EXPECT_FALSE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.optional_int32(), 123);
+  trimed_msg.Clear();
+
+  // Field mask on repeated field.
+  FieldMaskUtil::FromString("repeated_string", &mask);
+  trimed_msg.add_repeated_string("abc");
+  trimed_msg.add_repeated_string("def");
+  EXPECT_FALSE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.repeated_string(0), "abc");
+  EXPECT_EQ(trimed_msg.repeated_string(1), "def");
+  trimed_msg.Clear();
+
+  // Field mask on nested message.
+  FieldMaskUtil::FromString("optional_nested_message.bb", &mask);
+  trimed_msg.mutable_optional_nested_message()->set_bb(123);
+  EXPECT_FALSE(FieldMaskUtil::TrimMessage(mask, &trimed_msg));
+  EXPECT_EQ(trimed_msg.optional_nested_message().bb(), 123);
+  trimed_msg.Clear();
+
+  // TODO(b/32443320): field mask on repeated nested message is not yet
+  // supported.
+}
+
+
+}  // 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..8bded86
--- /dev/null
+++ b/src/google/protobuf/util/internal/constants.h
@@ -0,0 +1,101 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+
+// This file contains constants used by //net/proto2/util/converter.
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+// Prefix for type URLs.
+const char kTypeServiceBaseUrl[] = "type.googleapis.com";
+
+// Format string for RFC3339 timestamp formatting.
+const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S";
+
+// Same as above, but the year value is not zero-padded i.e. this accepts
+// timestamps like "1-01-0001T23:59:59Z" instead of "0001-01-0001T23:59:59Z".
+const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S";
+
+// Minimum seconds allowed in a google.protobuf.Timestamp value.
+const int64_t kTimestampMinSeconds = -62135596800LL;
+
+// Maximum seconds allowed in a google.protobuf.Timestamp value.
+const int64_t kTimestampMaxSeconds = 253402300799LL;
+
+// Minimum seconds allowed in a google.protobuf.Duration value.
+const int64_t kDurationMinSeconds = -315576000000LL;
+
+// Maximum seconds allowed in a google.protobuf.Duration value.
+const int64_t kDurationMaxSeconds = 315576000000LL;
+
+// Nano seconds in a second.
+const int32_t 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 string for google.protobuf.Any
+const char kAnyType[] = "google.protobuf.Any";
+
+// The protobuf option name of jspb.message_id;
+const char kOptionJspbMessageId[] = "jspb.message_id";
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..3e7aa84
--- /dev/null
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -0,0 +1,441 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cmath>
+#include <cstdint>
+#include <limits>
+
+#include <google/protobuf/struct.pb.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using util::Status;
+
+namespace {
+
+template <typename To, typename From>
+util::StatusOr<To> ValidateNumberConversion(To after, From before) {
+  if (after == before &&
+      MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) {
+    return after;
+  } else {
+    return util::InvalidArgumentError(
+        std::is_integral<From>::value       ? ValueAsString(before)
+        : std::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>
+util::StatusOr<To> NumberConvertAndCheck(From before) {
+  if (std::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>
+util::StatusOr<To> FloatingPointToIntConvertAndCheck(From before) {
+  if (std::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
+// For conversion between double and float only.
+util::StatusOr<double> FloatToDouble(float before) {
+  // Casting float to double should just work as double has more precision
+  // than float.
+  return static_cast<double>(before);
+}
+
+util::StatusOr<float> DoubleToFloat(double before) {
+  if (std::isnan(before)) {
+    return std::numeric_limits<float>::quiet_NaN();
+  } else if (!std::isfinite(before)) {
+    // Converting a double +inf/-inf to float should just work.
+    return static_cast<float>(before);
+  } else if (before > std::numeric_limits<float>::max() ||
+             before < -std::numeric_limits<float>::max()) {
+    // Some doubles are larger than the largest float, but after
+    // rounding they will be equal to the largest float.
+    // We can't just attempt the conversion because that has UB if
+    // the value really is out-of-range.
+    // Here we take advantage that 1/2-ing a large floating point
+    // will not lose precision.
+    double half_before = before * 0.5;
+    if (half_before < std::numeric_limits<float>::max() &&
+        half_before > -std::numeric_limits<float>::max()) {
+      const float half_fmax = std::numeric_limits<float>::max() * 0.5f;
+      // If after being cut in half, the value is less than the largest float,
+      // then it's safe to convert it to float.  Importantly, this conversion
+      // rounds in the same way that the original does.
+      float half_after = static_cast<float>(half_before);
+      if (half_after <= half_fmax && half_after >= -half_fmax) {
+        return half_after + half_after;
+      }
+    }
+    // Double value outside of the range of float.
+    return util::InvalidArgumentError(DoubleAsString(before));
+  } else {
+    return static_cast<float>(before);
+  }
+}
+
+}  // namespace
+
+util::StatusOr<int32_t> DataPiece::ToInt32() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<int32_t>(safe_strto32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int32_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int32_t, float>(float_);
+
+  return GenericConvert<int32_t>();
+}
+
+util::StatusOr<uint32_t> DataPiece::ToUint32() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<uint32_t>(safe_strtou32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint32_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint32_t, float>(float_);
+
+  return GenericConvert<uint32_t>();
+}
+
+util::StatusOr<int64_t> DataPiece::ToInt64() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<int64_t>(safe_strto64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int64_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int64_t, float>(float_);
+
+  return GenericConvert<int64_t>();
+}
+
+util::StatusOr<uint64_t> DataPiece::ToUint64() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<uint64_t>(safe_strtou64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint64_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint64_t, float>(float_);
+
+  return GenericConvert<uint64_t>();
+}
+
+util::StatusOr<double> DataPiece::ToDouble() const {
+  if (type_ == TYPE_FLOAT) {
+    return FloatToDouble(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();
+    util::StatusOr<double> value = StringToNumber<double>(safe_strtod);
+    if (value.ok() && !std::isfinite(value.value())) {
+      // safe_strtod converts out-of-range values to +inf/-inf, but we want
+      // to report them as errors.
+      return util::InvalidArgumentError(StrCat("\"", str_, "\""));
+    } else {
+      return value;
+    }
+  }
+  return GenericConvert<double>();
+}
+
+util::StatusOr<float> DataPiece::ToFloat() const {
+  if (type_ == TYPE_DOUBLE) {
+    return DoubleToFloat(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>();
+}
+
+util::StatusOr<bool> DataPiece::ToBool() const {
+  switch (type_) {
+    case TYPE_BOOL:
+      return bool_;
+    case TYPE_STRING:
+      return StringToNumber<bool>(safe_strtob);
+    default:
+      return util::InvalidArgumentError(
+          ValueAsStringOrDefault("Wrong type. Cannot convert to Bool."));
+  }
+}
+
+util::StatusOr<std::string> DataPiece::ToString() const {
+  switch (type_) {
+    case TYPE_STRING:
+      return std::string(str_);
+    case TYPE_BYTES: {
+      std::string base64;
+      Base64Escape(str_, &base64);
+      return base64;
+    }
+    default:
+      return util::InvalidArgumentError(
+          ValueAsStringOrDefault("Cannot convert to string."));
+  }
+}
+
+std::string DataPiece::ValueAsStringOrDefault(
+    StringPiece default_string) const {
+  switch (type_) {
+    case TYPE_INT32:
+      return StrCat(i32_);
+    case TYPE_INT64:
+      return StrCat(i64_);
+    case TYPE_UINT32:
+      return StrCat(u32_);
+    case TYPE_UINT64:
+      return StrCat(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: {
+      std::string base64;
+      WebSafeBase64Escape(str_, &base64);
+      return StrCat("\"", base64, "\"");
+    }
+    case TYPE_NULL:
+      return "null";
+    default:
+      return std::string(default_string);
+  }
+}
+
+util::StatusOr<std::string> DataPiece::ToBytes() const {
+  if (type_ == TYPE_BYTES) return str_.ToString();
+  if (type_ == TYPE_STRING) {
+    std::string decoded;
+    if (!DecodeBase64(str_, &decoded)) {
+      return util::InvalidArgumentError(
+          ValueAsStringOrDefault("Invalid data in input."));
+    }
+    return decoded;
+  } else {
+    return util::InvalidArgumentError(ValueAsStringOrDefault(
+        "Wrong type. Only String or Bytes can be converted to Bytes."));
+  }
+}
+
+util::StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type,
+                                      bool use_lower_camel_for_enums,
+                                      bool case_insensitive_enum_parsing,
+                                      bool ignore_unknown_enum_values,
+                                      bool* is_unknown_enum_value) const {
+  if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE;
+
+  if (type_ == TYPE_STRING) {
+    // First try the given value as a name.
+    std::string enum_name = std::string(str_);
+    const google::protobuf::EnumValue* value =
+        FindEnumValueByNameOrNull(enum_type, enum_name);
+    if (value != nullptr) return value->number();
+
+    // Check if int version of enum is sent as string.
+    util::StatusOr<int32_t> int_value = ToInt32();
+    if (int_value.ok()) {
+      if (const google::protobuf::EnumValue* enum_value =
+              FindEnumValueByNumberOrNull(enum_type, int_value.value())) {
+        return enum_value->number();
+      }
+    }
+
+    // Next try a normalized name.
+    bool should_normalize_enum =
+        case_insensitive_enum_parsing || use_lower_camel_for_enums;
+    if (should_normalize_enum) {
+      for (std::string::iterator it = enum_name.begin(); it != enum_name.end();
+           ++it) {
+        *it = *it == '-' ? '_' : ascii_toupper(*it);
+      }
+      value = FindEnumValueByNameOrNull(enum_type, enum_name);
+      if (value != nullptr) return value->number();
+    }
+
+    // If use_lower_camel_for_enums is true try with enum name without
+    // underscore. This will also accept camel case names as the enum_name has
+    // been normalized before.
+    if (use_lower_camel_for_enums) {
+      value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name);
+      if (value != nullptr) return value->number();
+    }
+
+    // If ignore_unknown_enum_values is true an unknown enum value is ignored.
+    if (ignore_unknown_enum_values) {
+      *is_unknown_enum_value = true;
+      if (enum_type->enumvalue_size() > 0) {
+        return enum_type->enumvalue(0).number();
+      }
+    }
+  } else {
+    // We don't need to check whether the value is actually declared in the
+    // enum because we preserve unknown enum values as well.
+    return ToInt32();
+  }
+  return util::InvalidArgumentError(
+      ValueAsStringOrDefault("Cannot find enum with given value."));
+}
+
+template <typename To>
+util::StatusOr<To> DataPiece::GenericConvert() const {
+  switch (type_) {
+    case TYPE_INT32:
+      return NumberConvertAndCheck<To, int32_t>(i32_);
+    case TYPE_INT64:
+      return NumberConvertAndCheck<To, int64_t>(i64_);
+    case TYPE_UINT32:
+      return NumberConvertAndCheck<To, uint32_t>(u32_);
+    case TYPE_UINT64:
+      return NumberConvertAndCheck<To, uint64_t>(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 util::InvalidArgumentError(ValueAsStringOrDefault(
+          "Wrong type. Bool, Enum, String and Cord not supported in "
+          "GenericConvert."));
+  }
+}
+
+template <typename To>
+util::StatusOr<To> DataPiece::StringToNumber(bool (*func)(StringPiece,
+                                                          To*)) const {
+  if (str_.size() > 0 && (str_[0] == ' ' || str_[str_.size() - 1] == ' ')) {
+    return util::InvalidArgumentError(StrCat("\"", str_, "\""));
+  }
+  To result;
+  if (func(str_, &result)) return result;
+  return util::InvalidArgumentError(
+      StrCat("\"", std::string(str_), "\""));
+}
+
+bool DataPiece::DecodeBase64(StringPiece src, std::string* dest) const {
+  // Try web-safe decode first, if it fails, try the non-web-safe decode.
+  if (WebSafeBase64Unescape(src, dest)) {
+    if (use_strict_base64_decoding_) {
+      // In strict mode, check if the escaped version gives us the same value as
+      // unescaped.
+      std::string encoded;
+      // WebSafeBase64Escape does no padding by default.
+      WebSafeBase64Escape(*dest, &encoded);
+      // Remove trailing padding '=' characters before comparison.
+      StringPiece src_no_padding = StringPiece(src).substr(
+          0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
+                                      : src.length());
+      return encoded == src_no_padding;
+    }
+    return true;
+  }
+
+  if (Base64Unescape(src, dest)) {
+    if (use_strict_base64_decoding_) {
+      std::string encoded;
+      Base64Escape(reinterpret_cast<const unsigned char*>(dest->data()),
+                         dest->length(), &encoded, false);
+      StringPiece src_no_padding = StringPiece(src).substr(
+          0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
+                                      : src.length());
+      return encoded == src_no_padding;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+void DataPiece::InternalCopy(const DataPiece& other) {
+  type_ = other.type_;
+  use_strict_base64_decoding_ = other.use_strict_base64_decoding_;
+  switch (type_) {
+    case TYPE_INT32:
+    case TYPE_INT64:
+    case TYPE_UINT32:
+    case TYPE_UINT64:
+    case TYPE_DOUBLE:
+    case TYPE_FLOAT:
+    case TYPE_BOOL:
+    case TYPE_ENUM:
+    case TYPE_NULL:
+    case TYPE_BYTES:
+    case TYPE_STRING: {
+      str_ = other.str_;
+      break;
+    }
+  }
+}
+
+}  // 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..6d08349
--- /dev/null
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -0,0 +1,219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
+
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+class ProtoWriter;
+
+// 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 responsibility to guarantee
+// that the underlying storage is still valid when the DataPiece is accessed.
+class PROTOBUF_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_t value)
+      : type_(TYPE_INT32), i32_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const int64_t value)
+      : type_(TYPE_INT64), i64_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const uint32_t value)
+      : type_(TYPE_UINT32), u32_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const uint64_t value)
+      : type_(TYPE_UINT64), u64_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const double value)
+      : type_(TYPE_DOUBLE),
+        double_(value),
+        use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const float value)
+      : type_(TYPE_FLOAT), float_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const bool value)
+      : type_(TYPE_BOOL), bool_(value), use_strict_base64_decoding_(false) {}
+  DataPiece(StringPiece value, bool use_strict_base64_decoding)
+      : type_(TYPE_STRING),
+        str_(value),
+        use_strict_base64_decoding_(use_strict_base64_decoding) {}
+  // Constructor for bytes. The second parameter is not used.
+  DataPiece(StringPiece value, bool /*dummy*/, bool use_strict_base64_decoding)
+      : type_(TYPE_BYTES),
+        str_(value),
+        use_strict_base64_decoding_(use_strict_base64_decoding) {}
+
+  DataPiece(const DataPiece& r) : type_(r.type_) { InternalCopy(r); }
+
+  DataPiece& operator=(const DataPiece& x) {
+    InternalCopy(x);
+    return *this;
+  }
+
+  static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); }
+
+  virtual ~DataPiece() {
+  }
+
+  // Accessors
+  Type type() const { return type_; }
+
+  bool use_strict_base64_decoding() { return use_strict_base64_decoding_; }
+
+  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_t> ToInt32() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a uint32.
+  util::StatusOr<uint32_t> ToUint32() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into an int64.
+  util::StatusOr<int64_t> ToInt64() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a uint64.
+  util::StatusOr<uint64_t> 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<std::string> ToString() const;
+
+  // Tries to convert the value contained in this datapiece to string. If the
+  // conversion fails, it returns the default_string.
+  std::string ValueAsStringOrDefault(StringPiece default_string) const;
+
+  util::StatusOr<std::string> ToBytes() const;
+
+ private:
+  friend class ProtoWriter;
+
+  // Disallow implicit constructor.
+  DataPiece();
+
+  // Helper to create NULL or ENUM types.
+  DataPiece(Type type, int32_t val)
+      : type_(type), i32_(val), use_strict_base64_decoding_(false) {}
+
+  // Same as the ToEnum() method above but with additional flag to ignore
+  // unknown enum values.
+  util::StatusOr<int> ToEnum(const google::protobuf::Enum* enum_type,
+                             bool use_lower_camel_for_enums,
+                             bool case_insensitive_enum_parsing,
+                             bool ignore_unknown_enum_values,
+                             bool* is_unknown_enum_value) const;
+
+  // For numeric conversion between
+  //     int32, int64, uint32, uint64, double, float and bool
+  template <typename To>
+  util::StatusOr<To> GenericConvert() const;
+
+  // For conversion from string to
+  //     int32, int64, uint32, uint64, double, float and bool
+  template <typename To>
+  util::StatusOr<To> StringToNumber(bool (*func)(StringPiece, To*)) const;
+
+  // Decodes a base64 string. Returns true on success.
+  bool DecodeBase64(StringPiece src, std::string* dest) const;
+
+  // Helper function to initialize this DataPiece with 'other'.
+  void InternalCopy(const DataPiece& other);
+
+  // Data type for this piece of data.
+  Type type_;
+
+  // Stored piece of data.
+  union {
+    int32_t i32_;
+    int64_t i64_;
+    uint32_t u32_;
+    uint64_t u64_;
+    double double_;
+    float float_;
+    bool bool_;
+    StringPiece str_;
+  };
+
+  // Uses a stricter version of base64 decoding for byte fields.
+  bool use_strict_base64_decoding_;
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..7f61cda
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -0,0 +1,642 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <unordered_map>
+
+#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 {
+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,
+            util::StatusOr<T> (DataPiece::*converter_fn)() const,
+            T default_value) {
+  if (value.empty()) return default_value;
+  util::StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
+  return result.ok() ? result.value() : 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_(nullptr),
+      root_(nullptr),
+      suppress_empty_list_(false),
+      preserve_proto_field_names_(false),
+      use_ints_for_enums_(false),
+      ow_(ow) {}
+
+DefaultValueObjectWriter::~DefaultValueObjectWriter() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(
+    StringPiece name, bool value) {
+  if (current_ == nullptr) {
+    ow_->RenderBool(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
+    StringPiece name, int32_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderInt32(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
+    StringPiece name, uint32_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderUint32(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
+    StringPiece name, int64_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderInt64(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
+    StringPiece name, uint64_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderUint64(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
+    StringPiece name, double value) {
+  if (current_ == nullptr) {
+    ow_->RenderDouble(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
+    StringPiece name, float value) {
+  if (current_ == nullptr) {
+    ow_->RenderBool(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
+    StringPiece name, StringPiece value) {
+  if (current_ == nullptr) {
+    ow_->RenderString(name, value);
+  } else {
+    // Since StringPiece is essentially a pointer, takes a copy of "value" to
+    // avoid ownership issues.
+    string_values_.emplace_back(new std::string(value));
+    RenderDataPiece(name, DataPiece(*string_values_.back(), true));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
+    StringPiece name, StringPiece value) {
+  if (current_ == nullptr) {
+    ow_->RenderBytes(name, value);
+  } else {
+    // Since StringPiece is essentially a pointer, takes a copy of "value" to
+    // avoid ownership issues.
+    string_values_.emplace_back(new std::string(value));
+    RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
+    StringPiece name) {
+  if (current_ == nullptr) {
+    ow_->RenderNull(name);
+  } else {
+    RenderDataPiece(name, DataPiece::NullData());
+  }
+  return this;
+}
+
+void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
+    FieldScrubCallBack field_scrub_callback) {
+  field_scrub_callback_ = std::move(field_scrub_callback);
+}
+
+DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
+    const std::string& name, const google::protobuf::Type* type, NodeKind kind,
+    const DataPiece& data, bool is_placeholder,
+    const std::vector<std::string>& path, bool suppress_empty_list,
+    bool preserve_proto_field_names, bool use_ints_for_enums,
+    FieldScrubCallBack field_scrub_callback) {
+  return new Node(name, type, kind, data, is_placeholder, path,
+                  suppress_empty_list, preserve_proto_field_names,
+                  use_ints_for_enums, std::move(field_scrub_callback));
+}
+
+DefaultValueObjectWriter::Node::Node(
+    const std::string& name, const google::protobuf::Type* type, NodeKind kind,
+    const DataPiece& data, bool is_placeholder,
+    const std::vector<std::string>& path, bool suppress_empty_list,
+    bool preserve_proto_field_names, bool use_ints_for_enums,
+    FieldScrubCallBack field_scrub_callback)
+    : name_(name),
+      type_(type),
+      kind_(kind),
+      is_any_(false),
+      data_(data),
+      is_placeholder_(is_placeholder),
+      path_(path),
+      suppress_empty_list_(suppress_empty_list),
+      preserve_proto_field_names_(preserve_proto_field_names),
+      use_ints_for_enums_(use_ints_for_enums),
+      field_scrub_callback_(std::move(field_scrub_callback)) {}
+
+DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
+    StringPiece name) {
+  if (name.empty() || kind_ != OBJECT) {
+    return nullptr;
+  }
+  for (Node* child : children_) {
+    if (child->name() == name) {
+      return child;
+    }
+  }
+  return nullptr;
+}
+
+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) {
+    // Suppress empty lists if requested.
+    if (suppress_empty_list_ && is_placeholder_) return;
+
+    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 (Node* child : children_) {
+    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::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.value();
+    }
+    break;
+  }
+  return nullptr;
+}
+
+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_ == nullptr || type_->name() == kAnyType ||
+      type_->name() == kStructType || type_->name() == kTimestampType ||
+      type_->name() == kDurationType || type_->name() == kStructValueType) {
+    return;
+  }
+  std::vector<Node*> new_children;
+  std::unordered_map<std::string, int> orig_children_map;
+
+  // Creates a map of child nodes to speed up lookup.
+  for (int i = 0; i < children_.size(); ++i) {
+    InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
+  }
+
+  for (int i = 0; i < type_->fields_size(); ++i) {
+    const google::protobuf::Field& field = type_->fields(i);
+
+    // This code is checking if the field to be added to the tree should be
+    // scrubbed or not by calling the field_scrub_callback_ callback function.
+    std::vector<std::string> path;
+    if (!path_.empty()) {
+      path.insert(path.begin(), path_.begin(), path_.end());
+    }
+    path.push_back(field.name());
+    if (field_scrub_callback_ && field_scrub_callback_(path, &field)) {
+      continue;
+    }
+
+    std::unordered_map<std::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] = nullptr;
+      continue;
+    }
+
+    const google::protobuf::Type* field_type = nullptr;
+    bool is_map = false;
+    NodeKind kind = PRIMITIVE;
+
+    if (field.kind() == google::protobuf::Field::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.value();
+        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_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
+    // primitive value.
+    if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;
+
+    // If the child field is of primitive type, sets its data to the default
+    // value of its type.
+    std::unique_ptr<Node> child(
+        new Node(preserve_proto_field_names_ ? field.name() : field.json_name(),
+                 field_type, kind,
+                 kind == PRIMITIVE ? CreateDefaultDataPieceForField(
+                                         field, typeinfo, use_ints_for_enums_)
+                                   : DataPiece::NullData(),
+                 true, path, suppress_empty_list_, preserve_proto_field_names_,
+                 use_ints_for_enums_, field_scrub_callback_));
+    new_children.push_back(child.release());
+  }
+  // Adds all leftover nodes in children_ to the beginning of new_child.
+  for (int i = 0; i < children_.size(); ++i) {
+    if (children_[i] == nullptr) {
+      continue;
+    }
+    new_children.insert(new_children.begin(), children_[i]);
+    children_[i] = nullptr;
+  }
+  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 != nullptr && node->is_any() && node->type() != nullptr &&
+      node->type()->name() != kAnyType && node->number_of_children() == 1) {
+    node->PopulateChildren(typeinfo_);
+  }
+}
+
+DataPiece DefaultValueObjectWriter::FindEnumDefault(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo,
+    bool use_ints_for_enums) {
+  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();
+  }
+  if (!field.default_value().empty()) {
+    if (!use_ints_for_enums) {
+      return DataPiece(field.default_value(), true);
+    } else {
+      const std::string& enum_default_value_name = field.default_value();
+      for (int enum_index = 0; enum_index < enum_type->enumvalue_size();
+           ++enum_index) {
+        auto& enum_value = enum_type->enumvalue(enum_index);
+        if (enum_value.name() == enum_default_value_name)
+          return DataPiece(enum_value.number());
+      }
+      GOOGLE_LOG(WARNING) << "Could not find enum value '" << enum_default_value_name
+                   << "' 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
+             ? (use_ints_for_enums
+                    ? DataPiece(enum_type->enumvalue(0).number())
+                    : DataPiece(enum_type->enumvalue(0).name(), true))
+             : DataPiece::NullData();
+}
+
+DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo,
+    bool use_ints_for_enums) {
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      return DataPiece(ConvertTo<double>(
+          field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      return DataPiece(ConvertTo<float>(
+          field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
+    }
+    case google::protobuf::Field::TYPE_INT64:
+    case google::protobuf::Field::TYPE_SINT64:
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      return DataPiece(ConvertTo<int64_t>(
+          field.default_value(), &DataPiece::ToInt64, static_cast<int64_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_UINT64:
+    case google::protobuf::Field::TYPE_FIXED64: {
+      return DataPiece(ConvertTo<uint64_t>(field.default_value(),
+                                           &DataPiece::ToUint64,
+                                           static_cast<uint64_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_INT32:
+    case google::protobuf::Field::TYPE_SINT32:
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      return DataPiece(ConvertTo<int32_t>(
+          field.default_value(), &DataPiece::ToInt32, static_cast<int32_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_BOOL: {
+      return DataPiece(
+          ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      return DataPiece(field.default_value(), true);
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      return DataPiece(field.default_value(), false, true);
+    }
+    case google::protobuf::Field::TYPE_UINT32:
+    case google::protobuf::Field::TYPE_FIXED32: {
+      return DataPiece(ConvertTo<uint32_t>(field.default_value(),
+                                           &DataPiece::ToUint32,
+                                           static_cast<uint32_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      return FindEnumDefault(field, typeinfo, use_ints_for_enums);
+    }
+    default: {
+      return DataPiece::NullData();
+    }
+  }
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
+    StringPiece name) {
+  if (current_ == nullptr) {
+    std::vector<std::string> path;
+    root_.reset(CreateNewNode(std::string(name), &type_, OBJECT,
+                              DataPiece::NullData(), false, path,
+                              suppress_empty_list_, preserve_proto_field_names_,
+                              use_ints_for_enums_, field_scrub_callback_));
+    root_->PopulateChildren(typeinfo_);
+    current_ = root_.get();
+    return this;
+  }
+  MaybePopulateChildrenOfAny(current_);
+  Node* child = current_->FindChild(name);
+  if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) {
+    // 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.
+    std::unique_ptr<Node> node(
+        CreateNewNode(std::string(name),
+                      ((current_->kind() == LIST || current_->kind() == MAP)
+                           ? current_->type()
+                           : nullptr),
+                      OBJECT, DataPiece::NullData(), false,
+                      child == nullptr ? current_->path() : child->path(),
+                      suppress_empty_list_, preserve_proto_field_names_,
+                      use_ints_for_enums_, field_scrub_callback_));
+    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_ == nullptr) {
+    std::vector<std::string> path;
+    root_.reset(CreateNewNode(std::string(name), &type_, LIST,
+                              DataPiece::NullData(), false, path,
+                              suppress_empty_list_, preserve_proto_field_names_,
+                              use_ints_for_enums_, field_scrub_callback_));
+    current_ = root_.get();
+    return this;
+  }
+  MaybePopulateChildrenOfAny(current_);
+  Node* child = current_->FindChild(name);
+  if (child == nullptr || child->kind() != LIST) {
+    std::unique_ptr<Node> node(CreateNewNode(
+        std::string(name), nullptr, LIST, DataPiece::NullData(), false,
+        child == nullptr ? current_->path() : child->path(),
+        suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
+        field_scrub_callback_));
+    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(nullptr);
+  current_ = nullptr;
+}
+
+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_);
+  if (current_->type() != nullptr && current_->type()->name() == kAnyType &&
+      name == "@type") {
+    util::StatusOr<std::string> data_string = data.ToString();
+    if (data_string.ok()) {
+      const std::string& string_value = data_string.value();
+      // 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.value());
+      }
+      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() != nullptr) {
+        current_->PopulateChildren(typeinfo_);
+      }
+    }
+  }
+  Node* child = current_->FindChild(name);
+  if (child == nullptr || child->kind() != PRIMITIVE) {
+    // No children are found, creates a new child.
+    std::unique_ptr<Node> node(
+        CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false,
+                      child == nullptr ? current_->path() : child->path(),
+                      suppress_empty_list_, preserve_proto_field_names_,
+                      use_ints_for_enums_, field_scrub_callback_));
+    current_->AddChild(node.release());
+  } else {
+    child->set_data(data);
+    child->set_is_placeholder(false);
+  }
+}
+
+}  // 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..a9e1673
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -0,0 +1,332 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <stack>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
+ public:
+  // A Callback function to check whether a field needs to be scrubbed.
+  //
+  // Returns true if the field should not be present in the output. Returns
+  // false otherwise.
+  //
+  // The 'path' parameter is a vector of path to the field from root. For
+  // example: if a nested field "a.b.c" (b is the parent message field of c and
+  // a is the parent message field of b), then the vector should contain { "a",
+  // "b", "c" }.
+  //
+  // The Field* should point to the google::protobuf::Field of "c".
+  typedef std::function<bool(
+      const std::vector<std::string>& /*path of the field*/,
+      const google::protobuf::Field* /*field*/)>
+      FieldScrubCallBack;
+
+  DefaultValueObjectWriter(TypeResolver* type_resolver,
+                           const google::protobuf::Type& type,
+                           ObjectWriter* ow);
+
+  ~DefaultValueObjectWriter() override;
+
+  // ObjectWriter methods.
+  DefaultValueObjectWriter* StartObject(StringPiece name) override;
+
+  DefaultValueObjectWriter* EndObject() override;
+
+  DefaultValueObjectWriter* StartList(StringPiece name) override;
+
+  DefaultValueObjectWriter* EndList() override;
+
+  DefaultValueObjectWriter* RenderBool(StringPiece name,
+                                       bool value) override;
+
+  DefaultValueObjectWriter* RenderInt32(StringPiece name,
+                                        int32_t value) override;
+
+  DefaultValueObjectWriter* RenderUint32(StringPiece name,
+                                         uint32_t value) override;
+
+  DefaultValueObjectWriter* RenderInt64(StringPiece name,
+                                        int64_t value) override;
+
+  DefaultValueObjectWriter* RenderUint64(StringPiece name,
+                                         uint64_t value) override;
+
+  DefaultValueObjectWriter* RenderDouble(StringPiece name,
+                                         double value) override;
+
+  DefaultValueObjectWriter* RenderFloat(StringPiece name,
+                                        float value) override;
+
+  DefaultValueObjectWriter* RenderString(StringPiece name,
+                                         StringPiece value) override;
+  DefaultValueObjectWriter* RenderBytes(StringPiece name,
+                                        StringPiece value) override;
+
+  DefaultValueObjectWriter* RenderNull(StringPiece name) override;
+
+  // Register the callback for scrubbing of fields.
+  void RegisterFieldScrubCallBack(FieldScrubCallBack field_scrub_callback);
+
+  // If set to true, empty lists are suppressed from output when default values
+  // are written.
+  void set_suppress_empty_list(bool value) { suppress_empty_list_ = value; }
+
+  // If set to true, original proto field names are used
+  void set_preserve_proto_field_names(bool value) {
+    preserve_proto_field_names_ = value;
+  }
+
+  // If set to true, enums are rendered as ints from output when default values
+  // are written.
+  void set_print_enums_as_ints(bool value) { use_ints_for_enums_ = value; }
+
+ protected:
+  enum NodeKind {
+    PRIMITIVE = 0,
+    OBJECT = 1,
+    LIST = 2,
+    MAP = 3,
+  };
+
+  // "Node" represents a node in the tree that holds the input of
+  // DefaultValueObjectWriter.
+  class PROTOBUF_EXPORT Node {
+   public:
+    Node(const std::string& name, const google::protobuf::Type* type,
+         NodeKind kind, const DataPiece& data, bool is_placeholder,
+         const std::vector<std::string>& path, bool suppress_empty_list,
+         bool preserve_proto_field_names, bool use_ints_for_enums,
+         FieldScrubCallBack field_scrub_callback);
+    virtual ~Node() {
+      for (int i = 0; i < children_.size(); ++i) {
+        delete children_[i];
+      }
+    }
+
+    // Adds a child to this node. Takes ownership of this child.
+    void AddChild(Node* child) { children_.push_back(child); }
+
+    // Finds the child given its name.
+    Node* FindChild(StringPiece name);
+
+    // Populates children of this Node based on its type. If there are already
+    // children created, they will be merged to the result. Caller should pass
+    // in TypeInfo for looking up types of the children.
+    virtual 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.
+    virtual void WriteTo(ObjectWriter* ow);
+
+    // Accessors
+    const std::string& name() const { return name_; }
+
+    const std::vector<std::string>& path() const { return path_; }
+
+    const google::protobuf::Type* type() const { return type_; }
+
+    void set_type(const google::protobuf::Type* type) { type_ = type; }
+
+    NodeKind kind() const { return kind_; }
+
+    int number_of_children() const { return children_.size(); }
+
+    void set_data(const DataPiece& data) { data_ = data; }
+
+    bool is_any() const { return is_any_; }
+
+    void set_is_any(bool is_any) { is_any_ = is_any; }
+
+    void set_is_placeholder(bool is_placeholder) {
+      is_placeholder_ = is_placeholder;
+    }
+
+   protected:
+    // 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& found_type, const TypeInfo* typeinfo);
+
+    // Calls WriteTo() on every child in children_.
+    void WriteChildren(ObjectWriter* ow);
+
+    // The name of this node.
+    std::string name_;
+    // google::protobuf::Type of this node. Owned by TypeInfo.
+    const google::protobuf::Type* type_;
+    // The kind of this node.
+    NodeKind kind_;
+    // Whether this is a node for "Any".
+    bool is_any_;
+    // The data of this node when it is a leaf node.
+    DataPiece data_;
+    // Children of this node.
+    std::vector<Node*> children_;
+    // Whether this node is a placeholder for an object or list automatically
+    // generated when creating the parent node. Should be set to false after
+    // the parent node's StartObject()/StartList() method is called with this
+    // node's name.
+    bool is_placeholder_;
+
+    // Path of the field of this node
+    std::vector<std::string> path_;
+
+    // Whether to suppress empty list output.
+    bool suppress_empty_list_;
+
+    // Whether to preserve original proto field names
+    bool preserve_proto_field_names_;
+
+    // Whether to always print enums as ints
+    bool use_ints_for_enums_;
+
+    // Function for determining whether a field needs to be scrubbed or not.
+    FieldScrubCallBack field_scrub_callback_;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
+  };
+
+  // Creates a new Node and returns it. Caller owns memory of returned object.
+  virtual Node* CreateNewNode(const std::string& name,
+                              const google::protobuf::Type* type, NodeKind kind,
+                              const DataPiece& data, bool is_placeholder,
+                              const std::vector<std::string>& path,
+                              bool suppress_empty_list,
+                              bool preserve_proto_field_names,
+                              bool use_ints_for_enums,
+                              FieldScrubCallBack field_scrub_callback);
+
+  // Creates a DataPiece containing the default value of the type of the field.
+  static DataPiece CreateDefaultDataPieceForField(
+      const google::protobuf::Field& field, const TypeInfo* typeinfo) {
+    return CreateDefaultDataPieceForField(field, typeinfo, false);
+  }
+
+  // Same as the above but with a flag to use ints instead of enum names.
+  static DataPiece CreateDefaultDataPieceForField(
+      const google::protobuf::Field& field, const TypeInfo* typeinfo,
+      bool use_ints_for_enums);
+
+ protected:
+  // Returns a pointer to current Node in tree.
+  Node* current() { return current_; }
+
+ private:
+  // 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
+  // nullptr.
+  void WriteRoot();
+
+  // 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,
+                                   bool use_ints_for_enums);
+
+  // 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.
+  std::vector<std::unique_ptr<std::string>> string_values_;
+
+  // The current Node. Owned by its parents.
+  Node* current_;
+  // The root Node.
+  std::unique_ptr<Node> root_;
+  // The stack to hold the path of Nodes from current_ to root_;
+  std::stack<Node*> stack_;
+
+  // Whether to suppress output of empty lists.
+  bool suppress_empty_list_;
+
+  // Whether to preserve original proto field names
+  bool preserve_proto_field_names_;
+
+  // Whether to always print enums as ints
+  bool use_ints_for_enums_;
+
+  // Function for determining whether a field needs to be scrubbed or not.
+  FieldScrubCallBack field_scrub_callback_;
+
+  ObjectWriter* ow_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultValueObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..96b14db
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -0,0 +1,191 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/constants.h>
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+namespace testing {
+
+using proto_util_converter::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(
+        std::string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(),
+        &mock_));
+  }
+
+  ~BaseDefaultValueObjectWriterTest() override {}
+
+  TypeInfoTestHelper helper_;
+  MockObjectWriter mock_;
+  ExpectingObjectWriter expects_;
+  std::unique_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()) {}
+  ~DefaultValueObjectWriterTest() override {}
+};
+
+INSTANTIATE_TEST_SUITE_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();
+}
+
+
+class DefaultValueObjectWriterSuppressListTest
+    : public BaseDefaultValueObjectWriterTest {
+ protected:
+  DefaultValueObjectWriterSuppressListTest()
+      : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {
+    testing_->set_suppress_empty_list(true);
+  }
+  ~DefaultValueObjectWriterSuppressListTest() override {}
+};
+
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         DefaultValueObjectWriterSuppressListTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
+
+TEST_P(DefaultValueObjectWriterSuppressListTest, Empty) {
+  // Set expectation. Empty lists should be suppressed.
+  expects_.StartObject("")
+      ->RenderDouble("doubleValue", 0.0)
+      ->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();
+}
+}  // 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..8c9c501
--- /dev/null
+++ b/src/google/protobuf/util/internal/error_listener.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INTERNAL_ERROR_LISTENER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
+
+#include <algorithm>
+#include <memory>
+#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/stubs/strutil.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// Interface for error listener.
+class PROTOBUF_EXPORT ErrorListener {
+ public:
+  virtual ~ErrorListener() {}
+
+  // Reports an invalid name at the given location.
+  virtual void InvalidName(const LocationTrackerInterface& loc,
+                           StringPiece invalid_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 PROTOBUF_EXPORT NoopErrorListener : public ErrorListener {
+ public:
+  NoopErrorListener() {}
+  ~NoopErrorListener() override {}
+
+  void InvalidName(const LocationTrackerInterface& /*loc*/,
+                   StringPiece /* invalid_name */,
+                   StringPiece /* message */) override {}
+
+  void InvalidValue(const LocationTrackerInterface& /*loc*/,
+                    StringPiece /* type_name */,
+                    StringPiece /* value */) override {}
+
+  void MissingField(const LocationTrackerInterface& /* loc */,
+                    StringPiece /* missing_name */) override {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener);
+};
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..76fe2b6
--- /dev/null
+++ b/src/google/protobuf/util/internal/expecting_objectwriter.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_EXPECTING_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_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 <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/object_writer.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using testing::Eq;
+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_METHOD(ObjectWriter*, StartObject, (StringPiece), (override));
+  MOCK_METHOD(ObjectWriter*, EndObject, (), (override));
+  MOCK_METHOD(ObjectWriter*, StartList, (StringPiece), (override));
+  MOCK_METHOD(ObjectWriter*, EndList, (), (override));
+  MOCK_METHOD(ObjectWriter*, RenderBool, (StringPiece, bool), (override));
+  MOCK_METHOD(ObjectWriter*, RenderInt32, (StringPiece, int32_t),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderUint32, (StringPiece, uint32_t),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderInt64, (StringPiece, int64_t),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderUint64, (StringPiece, uint64_t),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderDouble, (StringPiece, double),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderFloat, (StringPiece, float),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderString,
+              (StringPiece, StringPiece), (override));
+  MOCK_METHOD(ObjectWriter*, RenderBytes, (StringPiece, StringPiece),
+              (override));
+  MOCK_METHOD(ObjectWriter*, RenderNull, (StringPiece), (override));
+};
+
+class ExpectingObjectWriter : public ObjectWriter {
+ public:
+  explicit ExpectingObjectWriter(MockObjectWriter* mock) : mock_(mock) {}
+
+  ObjectWriter* StartObject(StringPiece name) override {
+    (name.empty() ? EXPECT_CALL(*mock_, StartObject(IsEmpty()))
+                  : EXPECT_CALL(*mock_, StartObject(Eq(std::string(name)))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* EndObject() override {
+    EXPECT_CALL(*mock_, EndObject())
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* StartList(StringPiece name) override {
+    (name.empty() ? EXPECT_CALL(*mock_, StartList(IsEmpty()))
+                  : EXPECT_CALL(*mock_, StartList(Eq(std::string(name)))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* EndList() override {
+    EXPECT_CALL(*mock_, EndList())
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderBool(StringPiece name, bool value) override {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderBool(IsEmpty(), TypedEq<bool>(value)))
+         : EXPECT_CALL(*mock_,
+                       RenderBool(Eq(std::string(name)), TypedEq<bool>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderInt32(StringPiece name, int32_t value) override {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderInt32(IsEmpty(), TypedEq<int32_t>(value)))
+         : EXPECT_CALL(*mock_, RenderInt32(Eq(std::string(name)),
+                                           TypedEq<int32_t>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderUint32(StringPiece name, uint32_t value) override {
+    (name.empty() ? EXPECT_CALL(*mock_, RenderUint32(IsEmpty(),
+                                                     TypedEq<uint32_t>(value)))
+                  : EXPECT_CALL(*mock_, RenderUint32(Eq(std::string(name)),
+                                                     TypedEq<uint32_t>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderInt64(StringPiece name, int64_t value) override {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderInt64(IsEmpty(), TypedEq<int64_t>(value)))
+         : EXPECT_CALL(*mock_, RenderInt64(Eq(std::string(name)),
+                                           TypedEq<int64_t>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderUint64(StringPiece name, uint64_t value) override {
+    (name.empty() ? EXPECT_CALL(*mock_, RenderUint64(IsEmpty(),
+                                                     TypedEq<uint64_t>(value)))
+                  : EXPECT_CALL(*mock_, RenderUint64(Eq(std::string(name)),
+                                                     TypedEq<uint64_t>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderDouble(StringPiece name, double value) override {
+    (name.empty()
+         ? EXPECT_CALL(*mock_,
+                       RenderDouble(IsEmpty(), NanSensitiveDoubleEq(value)))
+         : EXPECT_CALL(*mock_, RenderDouble(Eq(std::string(name)),
+                                            NanSensitiveDoubleEq(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderFloat(StringPiece name, float value) override {
+    (name.empty()
+         ? EXPECT_CALL(*mock_,
+                       RenderFloat(IsEmpty(), NanSensitiveFloatEq(value)))
+         : EXPECT_CALL(*mock_, RenderFloat(Eq(std::string(name)),
+                                           NanSensitiveFloatEq(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderString(StringPiece name,
+                             StringPiece value) override {
+    (name.empty() ? EXPECT_CALL(*mock_, RenderString(IsEmpty(),
+                                                     TypedEq<StringPiece>(
+                                                         std::string(value))))
+                  : EXPECT_CALL(*mock_, RenderString(Eq(std::string(name)),
+                                                     TypedEq<StringPiece>(
+                                                         std::string(value)))))
+        .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(Eq(std::string(name)),
+                                   TypedEq<StringPiece>(value.ToString()))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  ObjectWriter* RenderNull(StringPiece name) override {
+    (name.empty() ? EXPECT_CALL(*mock_, RenderNull(IsEmpty()))
+                  : EXPECT_CALL(*mock_, RenderNull(Eq(std::string(name))))
+                        .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_INTERNAL_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..521bf48
--- /dev/null
+++ b/src/google/protobuf/util/internal/field_mask_utility.cc
@@ -0,0 +1,218 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/field_mask_utility.h>
+
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+
+// Appends a FieldMask path segment to a prefix.
+std::string AppendPathSegmentToPrefix(StringPiece prefix,
+                                      StringPiece segment) {
+  if (prefix.empty()) {
+    return std::string(segment);
+  }
+  if (segment.empty()) {
+    return std::string(prefix);
+  }
+  // If the segment is a map key, appends it to the prefix without the ".".
+  if (HasPrefixString(segment, "[\"")) {
+    return StrCat(prefix, segment);
+  }
+  return StrCat(prefix, ".", segment);
+}
+
+}  // namespace
+
+std::string ConvertFieldMaskPath(const StringPiece path,
+                                 ConverterCallback converter) {
+  std::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) {
+  std::stack<std::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::InvalidArgumentError(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::InvalidArgumentError(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::InvalidArgumentError(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);
+    std::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 character 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(
+          path_sink(AppendPathSegmentToPrefix(current_prefix, segment)));
+    }
+
+    // Removes the last prefix after seeing a ')'.
+    if (i < length && paths[i] == ')') {
+      if (prefix.empty()) {
+        return util::InvalidArgumentError(
+            StrCat("Invalid FieldMask '", paths,
+                         "'. Cannot find matching '(' for all ')'."));
+      }
+      prefix.pop();
+    }
+    previous_position = i + 1;
+  }
+  if (in_map_key) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid FieldMask '", paths,
+                     "'. Cannot find matching ']' for all '['."));
+  }
+  if (!prefix.empty()) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid FieldMask '", paths,
+                     "'. Cannot find matching ')' for all '('."));
+  }
+  return util::Status();
+}
+
+}  // 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..1882333
--- /dev/null
+++ b/src/google/protobuf/util/internal/field_mask_utility.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.
+
+// FieldMask related utility methods.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+typedef std::function<std::string(StringPiece)> ConverterCallback;
+typedef std::function<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.
+std::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_INTERNAL_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..e4fa8cf
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_escaping.cc
@@ -0,0 +1,372 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+
+#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 surrogate code unit (either
+// high-surrogate or low-surrogate).
+inline bool IsSurrogate(uint32_t 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 a valid
+// unicode code point (i.e. in the range 0 <= cp <= kMaxCodePoint).
+inline bool IsValidCodePoint(uint32_t cp) {
+  return cp <= JsonEscaping::kMaxCodePoint;
+}
+
+// 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_t ToLowSurrogate(uint32_t 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_t ToHighSurrogate(uint32_t 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_t* 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_t>(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_t ch = static_cast<uint8_t>(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_t 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, 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_t cp, char* buffer) {
+  uint16_t low = ToLowSurrogate(cp);
+  uint16_t 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_t 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_t 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 = StringPiece(buffer + 4, 2);
+      return sp;
+    }
+    buffer[4] = (cp & 0x3f) | 0x80;
+    cp >>= 6;
+    if (cp <= 0x0f) {
+      buffer[3] = cp | 0xe0;
+      sp = StringPiece(buffer + 3, 3);
+      return sp;
+    }
+    buffer[3] = (cp & 0x3f) | 0x80;
+    buffer[2] = ((cp >> 6) & 0x07) | 0xf0;
+    sp = StringPiece(buffer + 2, 4);
+  }
+  return sp;
+}
+
+}  // namespace
+
+void JsonEscaping::Escape(strings::ByteSource* input,
+                          strings::ByteSink* output) {
+  char buffer[12] = "\\udead\\ubee";
+  uint32_t 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.
+  }
+}
+
+void JsonEscaping::Escape(StringPiece input, strings::ByteSink* output) {
+  const size_t len = input.length();
+  const char* p = input.data();
+
+  bool can_skip_escaping = true;
+  for (int i = 0; i < len; i++) {
+    char c = p[i];
+    if (c < 0x20 || c >= 0x7F || c == '"' || c == '<' || c == '>' ||
+        c == '\\') {
+      can_skip_escaping = false;
+      break;
+    }
+  }
+
+  if (can_skip_escaping) {
+    output->Append(input.data(), input.length());
+  } else {
+    strings::ArrayByteSource source(input);
+    Escape(&source, output);
+  }
+}
+
+}  // 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..7d54f22
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_escaping.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_INTERNAL_JSON_ESCAPING_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
+
+#include <cstdint>
+
+#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 constexpr uint16_t 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 constexpr uint16_t 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 constexpr uint16_t 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 constexpr uint16_t kMaxLowSurrogate = 0xdfff;
+
+  // The minimum value of a unicode supplementary code point.
+  // See http://www.unicode.org/glossary/#supplementary_code_point
+  static constexpr uint32_t kMinSupplementaryCodePoint = 0x010000;
+
+  // The minimum value of a unicode code point.
+  // See http://www.unicode.org/glossary/#code_point
+  static constexpr uint32_t kMinCodePoint = 0x000000;
+
+  // The maximum value of a unicode code point.
+  // See http://www.unicode.org/glossary/#code_point
+  static constexpr uint32_t kMaxCodePoint = 0x10ffff;
+
+  JsonEscaping() {}
+  virtual ~JsonEscaping() {}
+
+  // Escape the given ByteSource to the given ByteSink.
+  static void Escape(strings::ByteSource* input, strings::ByteSink* output);
+
+  // Escape the given ByteSource to the given ByteSink.
+  // This is optimized for the case where the string is all printable 7-bit
+  // ASCII and does not contain a few other characters (such as quotes).
+  static void Escape(StringPiece input, strings::ByteSink* output);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JsonEscaping);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
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..1a86f00
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter.cc
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cmath>
+#include <cstdint>
+#include <limits>
+
+#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/stubs/strutil.h>
+#include <google/protobuf/util/internal/json_escaping.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+JsonObjectWriter::~JsonObjectWriter() {
+  if (element_ && !element_->is_root()) {
+    GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed.";
+  }
+}
+
+JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) {
+  WritePrefix(name);
+  WriteChar('{');
+  PushObject();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::EndObject() {
+  Pop();
+  WriteChar('}');
+  if (element() && element()->is_root()) NewLine();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) {
+  WritePrefix(name);
+  WriteChar('[');
+  PushArray();
+  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_t value) {
+  return RenderSimple(name, StrCat(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name,
+                                                 uint32_t value) {
+  return RenderSimple(name, StrCat(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name,
+                                                int64_t value) {
+  WritePrefix(name);
+  WriteChar('"');
+  WriteRawString(StrCat(value));
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
+                                                 uint64_t value) {
+  WritePrefix(name);
+  WriteChar('"');
+  WriteRawString(StrCat(value));
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
+                                                 double value) {
+  if (std::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 (std::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('"');
+  JsonEscaping::Escape(value, &sink_);
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name,
+                                                StringPiece value) {
+  WritePrefix(name);
+  std::string base64;
+
+  if (use_websafe_base64_for_bytes_)
+    WebSafeBase64EscapeWithPadding(std::string(value), &base64);
+  else
+    Base64Escape(value, &base64);
+
+  WriteChar('"');
+  // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes
+  //              directly to the stream, rather than first putting them
+  //              into a string and then writing them to the stream.
+  stream_->WriteRaw(base64.data(), base64.size());
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderNull(StringPiece name) {
+  return RenderSimple(name, "null");
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderNullAsEmpty(StringPiece name) {
+  return RenderSimple(name, "");
+}
+
+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() || element()->is_json_object()) {
+    WriteChar('"');
+    if (!name.empty()) {
+      JsonEscaping::Escape(name, &sink_);
+    }
+    WriteRawString("\":");
+    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..cb7dff6
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter.h
@@ -0,0 +1,278 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+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 PROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter {
+ public:
+  JsonObjectWriter(StringPiece indent_string, io::CodedOutputStream* out)
+      : element_(new Element(/*parent=*/nullptr, /*is_json_object=*/false)),
+        stream_(out),
+        sink_(out),
+        indent_string_(indent_string),
+        indent_char_('\0'),
+        indent_count_(0),
+        use_websafe_base64_for_bytes_(false) {
+    // See if we have a trivial sequence of indent characters.
+    if (!indent_string.empty()) {
+      indent_char_ = indent_string[0];
+      indent_count_ = indent_string.length();
+      for (int i = 1; i < indent_string.length(); i++) {
+        if (indent_char_ != indent_string_[i]) {
+          indent_char_ = '\0';
+          indent_count_ = 0;
+          break;
+        }
+      }
+    }
+  }
+  ~JsonObjectWriter() override;
+
+  // ObjectWriter methods.
+  JsonObjectWriter* StartObject(StringPiece name) override;
+  JsonObjectWriter* EndObject() override;
+  JsonObjectWriter* StartList(StringPiece name) override;
+  JsonObjectWriter* EndList() override;
+  JsonObjectWriter* RenderBool(StringPiece name, bool value) override;
+  JsonObjectWriter* RenderInt32(StringPiece name, int32_t value) override;
+  JsonObjectWriter* RenderUint32(StringPiece name,
+                                 uint32_t value) override;
+  JsonObjectWriter* RenderInt64(StringPiece name, int64_t value) override;
+  JsonObjectWriter* RenderUint64(StringPiece name,
+                                 uint64_t value) override;
+  JsonObjectWriter* RenderDouble(StringPiece name, double value) override;
+  JsonObjectWriter* RenderFloat(StringPiece name, float value) override;
+  JsonObjectWriter* RenderString(StringPiece name,
+                                 StringPiece value) override;
+  JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value) override;
+  JsonObjectWriter* RenderNull(StringPiece name) override;
+  virtual JsonObjectWriter* RenderNullAsEmpty(StringPiece name);
+
+  void set_use_websafe_base64_for_bytes(bool value) {
+    use_websafe_base64_for_bytes_ = value;
+  }
+
+ protected:
+  class PROTOBUF_EXPORT Element : public BaseElement {
+   public:
+    Element(Element* parent, bool is_json_object)
+        : BaseElement(parent),
+          is_first_(true),
+          is_json_object_(is_json_object) {}
+
+    // 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;
+    }
+
+    // Whether we are currently rendering inside a JSON object (i.e., between
+    // StartObject() and EndObject()).
+    bool is_json_object() const { return is_json_object_; }
+
+   private:
+    bool is_first_;
+    bool is_json_object_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element);
+  };
+
+  Element* element() override { return element_.get(); }
+
+ private:
+  class PROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink {
+   public:
+    explicit ByteSinkWrapper(io::CodedOutputStream* stream) : stream_(stream) {}
+    ~ByteSinkWrapper() override {}
+
+    // ByteSink methods.
+    void Append(const char* bytes, size_t n) override {
+      stream_->WriteRaw(bytes, n);
+    }
+
+   private:
+    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,
+                                 StringPiece value) {
+    WritePrefix(name);
+    WriteRawString(value);
+    return this;
+  }
+
+  // Pushes a new JSON array element to the stack.
+  void PushArray() {
+    element_.reset(new Element(element_.release(), /*is_json_object=*/false));
+  }
+
+  // Pushes a new JSON object element to the stack.
+  void PushObject() {
+    element_.reset(new Element(element_.release(), /*is_json_object=*/true));
+  }
+
+  // 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()) {
+      size_t len = sizeof('\n') + (indent_string_.size() * element()->level());
+
+      // Take the slow-path if we don't have sufficient characters remaining in
+      // our buffer or we have a non-trivial indent string which would prevent
+      // us from using memset.
+      uint8_t* out = nullptr;
+      if (indent_count_ > 0) {
+        out = stream_->GetDirectBufferForNBytesAndAdvance(len);
+      }
+
+      if (out != nullptr) {
+        out[0] = '\n';
+        memset(&out[1], indent_char_, len - 1);
+      } else {
+        // Slow path, no contiguous output buffer available.
+        WriteChar('\n');
+        for (int i = 0; i < element()->level(); i++) {
+          stream_->WriteRaw(indent_string_.c_str(), indent_string_.length());
+        }
+      }
+    }
+  }
+
+  // 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)); }
+
+  // Writes a string to the output.
+  void WriteRawString(StringPiece s) {
+    stream_->WriteRaw(s.data(), s.length());
+  }
+
+  std::unique_ptr<Element> element_;
+  io::CodedOutputStream* stream_;
+  ByteSinkWrapper sink_;
+  const std::string indent_string_;
+
+  // For the common case of indent being a single character repeated.
+  char indent_char_;
+  int indent_count_;
+
+  // Whether to use regular or websafe base64 encoding for byte fields. Defaults
+  // to regular base64 encoding.
+  bool use_websafe_base64_for_bytes_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..8acf2c5
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc
@@ -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.
+
+#include <google/protobuf/util/internal/json_objectwriter.h>
+
+#include <cstdint>
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/util/internal/utility.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using io::CodedOutputStream;
+using io::StringOutputStream;
+
+class JsonObjectWriterTest : public ::testing::Test {
+ protected:
+  JsonObjectWriterTest()
+      : str_stream_(new StringOutputStream(&output_)),
+        out_stream_(new CodedOutputStream(str_stream_)),
+        ow_(nullptr) {}
+
+  ~JsonObjectWriterTest() override { delete ow_; }
+
+  std::string CloseStreamAndGetString() {
+    delete out_stream_;
+    delete str_stream_;
+    return output_;
+  }
+
+  std::string output_;
+  StringOutputStream* const str_stream_;
+  CodedOutputStream* const out_stream_;
+  JsonObjectWriter* ow_;
+};
+
+TEST_F(JsonObjectWriterTest, EmptyRootObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")->EndObject();
+  EXPECT_EQ("{}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, EmptyObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderString("test", "value")
+      ->StartObject("empty")
+      ->EndObject()
+      ->EndObject();
+  EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, EmptyRootList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartList("")->EndList();
+  EXPECT_EQ("[]", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, EmptyList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderString("test", "value")
+      ->StartList("empty")
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, EmptyObjectKey) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")->RenderString("", "value")->EndObject();
+  EXPECT_EQ("{\"\":\"value\"}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, ObjectInObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->StartObject("nested")
+      ->RenderString("field", "value")
+      ->EndObject()
+      ->EndObject();
+  EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, ListInObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->StartList("nested")
+      ->RenderString("", "value")
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ("{\"nested\":[\"value\"]}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, ObjectInList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartList("")
+      ->StartObject("")
+      ->RenderString("field", "value")
+      ->EndObject()
+      ->EndList();
+  EXPECT_EQ("[{\"field\":\"value\"}]", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, ListInList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartList("")
+      ->StartList("")
+      ->RenderString("", "value")
+      ->EndList()
+      ->EndList();
+  EXPECT_EQ("[[\"value\"]]", CloseStreamAndGetString());
+}
+
+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_t>::min())
+      ->RenderInt64("long", std::numeric_limits<int64_t>::min())
+      ->RenderBytes("bytes", "abracadabra")
+      ->RenderString("string", "string")
+      ->RenderBytes("emptybytes", "")
+      ->RenderString("emptystring", std::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\":\"\"}",
+      CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) {
+  std::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=\"}", CloseStreamAndGetString());
+}
+
+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",
+      CloseStreamAndGetString());
+}
+
+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",
+      CloseStreamAndGetString());
+}
+
+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",
+      CloseStreamAndGetString());
+}
+
+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",
+      CloseStreamAndGetString());
+}
+
+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\"}",
+            CloseStreamAndGetString());
+}
+
+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\"}",
+      CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderBytes("bytes", "\x03\xef\xc0")
+      ->EndObject();
+
+  // Test that we get regular (non websafe) base64 encoding on byte fields by
+  // default.
+  EXPECT_EQ("{\"bytes\":\"A+/A\"}", CloseStreamAndGetString());
+}
+
+TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->set_use_websafe_base64_for_bytes(true);
+  ow_->StartObject("")
+      ->RenderBytes("bytes", "\x03\xef\xc0\x10")
+      ->EndObject();
+
+  // Test that we get websafe base64 encoding when explicitly asked.
+  EXPECT_EQ("{\"bytes\":\"A-_AEA==\"}", CloseStreamAndGetString());
+}
+
+}  // 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..5c34dbc
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -0,0 +1,995 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cmath>
+#include <memory>
+#include <stack>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/json_escaping.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+namespace converter {
+
+// Number of digits in an escaped UTF-16 code unit ('\\' 'u' X X X X)
+static const int kUnicodeEscapedLength = 6;
+
+static const int kDefaultMaxRecursionDepth = 100;
+
+// These cannot be constexpr for portability with VS2015.
+static const StringPiece kKeywordTrue = "true";
+static const StringPiece kKeywordFalse = "false";
+static const StringPiece kKeywordNull = "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');
+}
+
+// Indicates a character may not be part of an unquoted key.
+inline bool IsKeySeparator(char c) {
+  return (ascii_isspace(c) || c == '"' || c == '\'' || c == '{' ||
+          c == '}' || c == '[' || c == ']' || c == ':' || c == ',');
+}
+
+inline void ReplaceInvalidCodePoints(StringPiece str,
+                                     const std::string& replacement,
+                                     std::string* dst) {
+  while (!str.empty()) {
+    int n_valid_bytes = internal::UTF8SpnStructurallyValid(str);
+    StringPiece valid_part = str.substr(0, n_valid_bytes);
+    StrAppend(dst, valid_part);
+
+    if (n_valid_bytes == str.size()) {
+      break;
+    }
+
+    // Append replacement value.
+    StrAppend(dst, replacement);
+
+    // Move past valid bytes + one invalid byte.
+    str.remove_prefix(n_valid_bytes + 1);
+  }
+}
+
+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;
+}
+
+// Same as 'ConsumeKey', but allows a widened set of key characters.
+static bool ConsumeKeyPermissive(StringPiece* input,
+                                 StringPiece* key) {
+  if (input->empty() || !IsLetter((*input)[0])) return false;
+  int len = 1;
+  for (; len < input->size(); ++len) {
+    if (IsKeySeparator((*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),
+      seen_non_whitespace_(false),
+      allow_no_root_element_(false),
+      parsed_(),
+      parsed_storage_(),
+      string_open_(0),
+      chunk_storage_(),
+      coerce_to_utf8_(false),
+      utf8_replacement_character_(" "),
+      allow_empty_null_(false),
+      allow_permissive_key_naming_(false),
+      loose_float_number_conversion_(false),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  // 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_);
+    StrAppend(&chunk_storage_, json);
+    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.
+    StrAppend(&leftover_, chunk.substr(n));
+    return status;
+  } else {
+    leftover_.assign(chunk.data(), chunk.size());
+    return util::Status();
+  }
+}
+
+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();
+  }
+
+  // Lifetime needs to last until RunParser returns, so keep this variable
+  // outside of the coerce_to_utf8 block.
+  std::unique_ptr<std::string> scratch;
+
+  bool is_valid_utf8 = internal::IsStructurallyValidUTF8(leftover_);
+  if (coerce_to_utf8_ && !is_valid_utf8) {
+    scratch.reset(new std::string);
+    scratch->reserve(leftover_.size() * utf8_replacement_character_.size());
+    ReplaceInvalidCodePoints(leftover_, utf8_replacement_character_,
+                             scratch.get());
+    p_ = json_ = *scratch;
+  } else {
+    p_ = json_ = leftover_;
+    if (!is_valid_utf8) {
+      return ReportFailure("Encountered non UTF-8 code points.",
+                           ParseErrorType::NON_UTF_8);
+    }
+  }
+
+  // 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.",
+                        ParseErrorType::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();
+
+  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.",
+          ParseErrorType::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_ = std::string(p_);
+  }
+  return util::Status();
+}
+
+bool JsonStreamParser::IsInputAllWhiteSpaces(TokenType type) {
+  // Conclude the whole input is full of white spaces by:
+  // - it is at the finishing stage
+  // - we have run out of the input data
+  // - haven't seen non-whitespace char so far
+  if (finishing_ && p_.empty() && type == UNKNOWN && !seen_non_whitespace_) {
+    return true;
+  }
+  return false;
+}
+
+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:
+        if (allow_no_root_element_ && IsInputAllWhiteSpaces(t)) {
+          return util::Status();
+        }
+        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::InternalError(StrCat("Unknown parse type: ", type));
+        break;
+    }
+    if (!result.ok()) {
+      // If we were cancelled, save our state and try again later.
+      if (!finishing_ && util::IsCancelled(result)) {
+        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()) {
+          StrAppend(&key_storage_, key_);
+          key_ = StringPiece(key_storage_);
+        }
+        result = util::Status();
+      }
+      return result;
+    }
+  }
+  return util::Status();
+}
+
+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.", ParseErrorType::EXPECTED_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() < kKeywordFalse.length()) {
+        return util::CancelledError("");
+      }
+
+      if (allow_empty_null_ && IsEmptyNullAllowed(type)) {
+        return ParseEmptyNull();
+      }
+      return ReportFailure("Unexpected token.",
+                           ParseErrorType::UNEXPECTED_TOKEN);
+    }
+  }
+}
+
+util::Status JsonStreamParser::ParseString() {
+  util::Status result = ParseStringHelper();
+  if (result.ok()) {
+    ow_->RenderString(key_, parsed_);
+    key_ = StringPiece();
+    parsed_ = StringPiece();
+    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);
+      }
+      // 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::CancelledError("");
+        }
+        return ReportFailure("Closing quote expected in string.",
+                             ParseErrorType::EXPECTED_CLOSING_QUOTE);
+      }
+      // 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);
+        }
+        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();
+    }
+    // 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::CancelledError("");
+  }
+  // End of string reached without a closing quote, report an error.
+  string_open_ = 0;
+  return ReportFailure("Closing quote expected in string.",
+                       ParseErrorType::EXPECTED_CLOSING_QUOTE);
+}
+
+// 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::CancelledError("");
+    }
+    return ReportFailure("Illegal hex string.",
+                         ParseErrorType::ILLEGAL_HEX_STRING);
+  }
+  GOOGLE_DCHECK_EQ('\\', p_.data()[0]);
+  GOOGLE_DCHECK_EQ('u', p_.data()[1]);
+  uint32_t code = 0;
+  for (int i = 2; i < kUnicodeEscapedLength; ++i) {
+    if (!isxdigit(p_.data()[i])) {
+      return ReportFailure("Invalid escape sequence.",
+                           ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+    }
+    code = (code << 4) + hex_digit_to_int(p_.data()[i]);
+  }
+  if (code >= JsonEscaping::kMinHighSurrogate &&
+      code <= JsonEscaping::kMaxHighSurrogate) {
+    if (p_.length() < 2 * kUnicodeEscapedLength) {
+      if (!finishing_) {
+        return util::CancelledError("");
+      }
+      if (!coerce_to_utf8_) {
+        return ReportFailure("Missing low surrogate.",
+                             ParseErrorType::MISSING_LOW_SURROGATE);
+      }
+    } else if (p_.data()[kUnicodeEscapedLength] == '\\' &&
+               p_.data()[kUnicodeEscapedLength + 1] == 'u') {
+      uint32_t low_code = 0;
+      for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength;
+           ++i) {
+        if (!isxdigit(p_.data()[i])) {
+          return ReportFailure("Invalid escape sequence.",
+                               ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+        }
+        low_code = (low_code << 4) + hex_digit_to_int(p_.data()[i]);
+      }
+      if (low_code >= JsonEscaping::kMinLowSurrogate &&
+          low_code <= JsonEscaping::kMaxLowSurrogate) {
+        // Convert UTF-16 surrogate pair to 21-bit Unicode codepoint.
+        code = (((code & 0x3FF) << 10) | (low_code & 0x3FF)) +
+               JsonEscaping::kMinSupplementaryCodePoint;
+        // Advance past the first code unit escape.
+        p_.remove_prefix(kUnicodeEscapedLength);
+      } else if (!coerce_to_utf8_) {
+        return ReportFailure("Invalid low surrogate.",
+                             ParseErrorType::INVALID_LOW_SURROGATE);
+      }
+    } else if (!coerce_to_utf8_) {
+      return ReportFailure("Missing low surrogate.",
+                           ParseErrorType::MISSING_LOW_SURROGATE);
+    }
+  }
+  if (!coerce_to_utf8_ && !IsValidCodePoint(code)) {
+    return ReportFailure("Invalid unicode code point.",
+                         ParseErrorType::INVALID_UNICODE);
+  }
+  char buf[UTFmax];
+  int len = EncodeAsUTF8Char(code, buf);
+  // Advance past the [final] code unit escape.
+  p_.remove_prefix(kUnicodeEscapedLength);
+  parsed_storage_.append(buf, len);
+  return util::Status();
+}
+
+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_ = StringPiece();
+        break;
+
+      case NumberResult::INT:
+        ow_->RenderInt64(key_, number.int_val);
+        key_ = StringPiece();
+        break;
+
+      case NumberResult::UINT:
+        ow_->RenderUint64(key_, number.uint_val);
+        key_ = StringPiece();
+        break;
+
+      default:
+        return ReportFailure("Unable to parse number.",
+                             ParseErrorType::UNABLE_TO_PARSE_NUMBER);
+    }
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseDoubleHelper(const std::string& number,
+                                                 NumberResult* result) {
+  if (!safe_strtod(number, &result->double_val)) {
+    return ReportFailure("Unable to parse number.",
+                         ParseErrorType::UNABLE_TO_PARSE_NUMBER);
+  }
+  if (!loose_float_number_conversion_ && !std::isfinite(result->double_val)) {
+    return ReportFailure("Number exceeds the range of double.",
+                         ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE);
+  }
+  result->type = NumberResult::DOUBLE;
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) {
+  const char* data = p_.data();
+  int length = p_.length();
+
+  // Look for the first non-numeric character, or the end of the string.
+  int index = 0;
+  bool floating = false;
+  bool negative = data[index] == '-';
+  // Find the first character that cannot be part of the number. Along the way
+  // detect if the number needs to be parsed as a double.
+  // Note that this restricts numbers to the JSON specification, so for example
+  // we do not support hex or octal notations.
+  for (; index < length; ++index) {
+    char c = data[index];
+    if (isdigit(c)) continue;
+    if (c == '.' || c == 'e' || c == 'E') {
+      floating = true;
+      continue;
+    }
+    if (c == '+' || c == '-' || c == 'x') continue;
+    // Not a valid number character, break out.
+    break;
+  }
+
+  // If the entire input is a valid number, and we may have more content in the
+  // future, we abort for now and resume when we know more.
+  if (index == length && !finishing_) {
+    return util::CancelledError("");
+  }
+
+  // Create a string containing just the number, so we can use safe_strtoX
+  std::string number = std::string(p_.substr(0, index));
+
+  // Floating point number, parse as a double.
+  if (floating) {
+    util::Status status = ParseDoubleHelper(number, result);
+    if (status.ok()) {
+      p_.remove_prefix(index);
+    }
+    return status;
+  }
+
+  // Positive non-floating point number, parse as a uint64_t.
+  if (!negative) {
+    // Octal/Hex numbers are not valid JSON values.
+    if (number.length() >= 2 && number[0] == '0') {
+      return ReportFailure(
+          "Octal/hex numbers are not valid JSON values.",
+          ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+    }
+    if (safe_strtou64(number, &result->uint_val)) {
+      result->type = NumberResult::UINT;
+      p_.remove_prefix(index);
+      return util::Status();
+    } else {
+      // If the value is too large, parse it as double.
+      util::Status status = ParseDoubleHelper(number, result);
+      if (status.ok()) {
+        p_.remove_prefix(index);
+      }
+      return status;
+    }
+  }
+
+  // Octal/Hex numbers are not valid JSON values.
+  if (number.length() >= 3 && number[1] == '0') {
+    return ReportFailure(
+        "Octal/hex numbers are not valid JSON values.",
+        ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+  }
+  // Negative non-floating point number, parse as an int64_t.
+  if (safe_strto64(number, &result->int_val)) {
+    result->type = NumberResult::INT;
+    p_.remove_prefix(index);
+    return util::Status();
+  } else {
+    // If the value is too large, parse it as double.
+    util::Status status = ParseDoubleHelper(number, result);
+    if (status.ok()) {
+      p_.remove_prefix(index);
+    }
+    return status;
+  }
+}
+
+util::Status JsonStreamParser::HandleBeginObject() {
+  GOOGLE_DCHECK_EQ('{', *p_.data());
+  Advance();
+  ow_->StartObject(key_);
+  auto status = IncrementRecursionDepth(key_);
+  if (!status.ok()) {
+    return status;
+  }
+  key_ = StringPiece();
+  stack_.push(ENTRY);
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseObjectMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected , or } after key:value pair.",
+                         ParseErrorType::EXPECTED_COMMA_OR_BRACES);
+  }
+
+  // Object is complete, advance past the comma and render the EndObject.
+  if (type == END_OBJECT) {
+    Advance();
+    ow_->EndObject();
+    --recursion_depth_;
+    return util::Status();
+  }
+  // Found a comma, advance past it and get ready for an entry.
+  if (type == VALUE_SEPARATOR) {
+    Advance();
+    stack_.push(ENTRY);
+    return util::Status();
+  }
+  // Illegal token after key:value pair.
+  return ReportFailure("Expected , or } after key:value pair.",
+                       ParseErrorType::EXPECTED_COMMA_OR_BRACES);
+}
+
+util::Status JsonStreamParser::ParseEntry(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected an object key or }.",
+                         ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+
+  // Close the object and return. This allows for trailing commas.
+  if (type == END_OBJECT) {
+    ow_->EndObject();
+    Advance();
+    --recursion_depth_;
+    return util::Status();
+  }
+
+  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_ = StringPiece();
+    }
+  } else if (type == BEGIN_KEY) {
+    // Key is a bare key (back compat), create a StringPiece pointing to it.
+    result = ParseKey();
+  } else if (type == BEGIN_NULL || type == BEGIN_TRUE || type == BEGIN_FALSE) {
+    // Key may be a bare key that begins with a reserved word.
+    result = ParseKey();
+    if (result.ok() && (key_ == kKeywordNull || key_ == kKeywordTrue ||
+                        key_ == kKeywordFalse)) {
+      result = ReportFailure("Expected an object key or }.",
+                             ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+    }
+  } else {
+    // Unknown key type, report an error.
+    result = ReportFailure("Expected an object key or }.",
+                           ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+  // 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.",
+                         ParseErrorType::EXPECTED_COLON);
+  }
+  if (type == ENTRY_SEPARATOR) {
+    Advance();
+    stack_.push(VALUE);
+    return util::Status();
+  }
+  return ReportFailure("Expected : between key:value pair.",
+                       ParseErrorType::EXPECTED_COLON);
+}
+
+util::Status JsonStreamParser::HandleBeginArray() {
+  GOOGLE_DCHECK_EQ('[', *p_.data());
+  Advance();
+  ow_->StartList(key_);
+  key_ = StringPiece();
+  stack_.push(ARRAY_VALUE);
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseArrayValue(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected a value or ] within an array.",
+                         ParseErrorType::EXPECTED_VALUE_OR_BRACKET);
+  }
+
+  if (type == END_ARRAY) {
+    ow_->EndList();
+    Advance();
+    return util::Status();
+  }
+
+  // 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. Also, the parsing of
+  // empty-null array value is relying on this ARRAY_MID token.
+  stack_.push(ARRAY_MID);
+  util::Status result = ParseValue(type);
+  if (util::IsCancelled(result)) {
+    // 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.",
+                         ParseErrorType::EXPECTED_COMMA_OR_BRACKET);
+  }
+
+  if (type == END_ARRAY) {
+    ow_->EndList();
+    Advance();
+    return util::Status();
+  }
+
+  // Found a comma, advance past it and expect an array value next.
+  if (type == VALUE_SEPARATOR) {
+    Advance();
+    stack_.push(ARRAY_VALUE);
+    return util::Status();
+  }
+  // Illegal token after array value.
+  return ReportFailure("Expected , or ] after array value.",
+                       ParseErrorType::EXPECTED_COMMA_OR_BRACKET);
+}
+
+util::Status JsonStreamParser::ParseTrue() {
+  ow_->RenderBool(key_, true);
+  key_ = StringPiece();
+  p_.remove_prefix(kKeywordTrue.length());
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseFalse() {
+  ow_->RenderBool(key_, false);
+  key_ = StringPiece();
+  p_.remove_prefix(kKeywordFalse.length());
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseNull() {
+  ow_->RenderNull(key_);
+  key_ = StringPiece();
+  p_.remove_prefix(kKeywordNull.length());
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseEmptyNull() {
+  ow_->RenderNull(key_);
+  key_ = StringPiece();
+  return util::Status();
+}
+
+bool JsonStreamParser::IsEmptyNullAllowed(TokenType type) {
+  if (stack_.empty()) return false;
+  return (stack_.top() == ARRAY_MID && type == VALUE_SEPARATOR) ||
+         stack_.top() == OBJ_MID;
+}
+
+util::Status JsonStreamParser::ReportFailure(StringPiece message,
+                                             ParseErrorType parse_code) {
+  (void)parse_code;  // Parameter is used in Google-internal code.
+  static const int kContextLength = 20;
+  const char* p_start = p_.data();
+  const char* json_start = json_.data();
+  const char* begin = std::max(p_start - kContextLength, json_start);
+  const char* end =
+      std::min(p_start + kContextLength, json_start + json_.size());
+  StringPiece segment(begin, end - begin);
+  std::string location(p_start - begin, ' ');
+  location.push_back('^');
+  auto status = util::InvalidArgumentError(
+      StrCat(message, "\n", segment, "\n", location));
+  return status;
+}
+
+util::Status JsonStreamParser::ReportUnknown(StringPiece message,
+                                             ParseErrorType parse_code) {
+  // If we aren't finishing the parse, cancel parsing and try later.
+  if (!finishing_) {
+    return util::CancelledError("");
+  }
+  if (p_.empty()) {
+    return ReportFailure(StrCat("Unexpected end of string. ", message),
+                         parse_code);
+  }
+  return ReportFailure(message, parse_code);
+}
+
+util::Status JsonStreamParser::IncrementRecursionDepth(
+    StringPiece key) const {
+  if (++recursion_depth_ > max_recursion_depth_) {
+    return util::InvalidArgumentError(StrCat(
+        "Message too deep. Max recursion depth reached for key '", key, "'"));
+  }
+  return util::Status();
+}
+
+void JsonStreamParser::SkipWhitespace() {
+  while (!p_.empty() && ascii_isspace(*p_.data())) {
+    Advance();
+  }
+  if (!p_.empty() && !ascii_isspace(*p_.data())) {
+    seen_non_whitespace_ = true;
+  }
+}
+
+void JsonStreamParser::Advance() {
+  // Advance by moving one UTF8 character while making sure we don't go beyond
+  // the length of StringPiece.
+  p_.remove_prefix(std::min<int>(
+      p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length())));
+}
+
+util::Status JsonStreamParser::ParseKey() {
+  StringPiece original = p_;
+
+  if (allow_permissive_key_naming_) {
+    if (!ConsumeKeyPermissive(&p_, &key_)) {
+      return ReportFailure("Invalid key or variable name.",
+                           ParseErrorType::INVALID_KEY_OR_VARIABLE_NAME);
+    }
+  } else {
+    if (!ConsumeKey(&p_, &key_)) {
+      return ReportFailure("Invalid key or variable name.",
+                           ParseErrorType::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::CancelledError("");
+  }
+  // Since we aren't using the key storage, clear it out.
+  key_storage_.clear();
+  return util::Status();
+}
+
+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();
+  StringPiece data_view = StringPiece(data, size);
+  if (*data == '\"' || *data == '\'') return BEGIN_STRING;
+  if (*data == '-' || ('0' <= *data && *data <= '9')) {
+    return BEGIN_NUMBER;
+  }
+  if (size >= kKeywordTrue.length() &&
+      HasPrefixString(data_view, kKeywordTrue)) {
+    return BEGIN_TRUE;
+  }
+  if (size >= kKeywordFalse.length() &&
+      HasPrefixString(data_view, kKeywordFalse)) {
+    return BEGIN_FALSE;
+  }
+  if (size >= kKeywordNull.length() &&
+      HasPrefixString(data_view, kKeywordNull)) {
+    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..09f17ad
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser.h
@@ -0,0 +1,350 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INTERNAL_JSON_STREAM_PARSER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
+
+#include <cstdint>
+#include <stack>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+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 PROTOBUF_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. If the returned
+  // status is non-ok, the status might contain a payload ParseErrorType with
+  // type_url kParseErrorTypeUrl and a payload containing string snippet of the
+  // error with type_url kParseErrorSnippetUrl.
+  util::Status Parse(StringPiece json);
+
+
+  // Finish parsing the JSON string. If the returned status is non-ok, the
+  // status might contain a payload ParseErrorType with type_url
+  // kParseErrorTypeUrl and a payload containing string snippet of the error
+  // with type_url kParseErrorSnippetUrl.
+  util::Status FinishParse();
+
+
+  // Sets the max recursion depth of JSON message to be deserialized. JSON
+  // messages over this depth will fail to be deserialized.
+  // Default value is 100.
+  void set_max_recursion_depth(int max_depth) {
+    max_recursion_depth_ = max_depth;
+  }
+
+  // Denotes the cause of error.
+  enum ParseErrorType {
+    UNKNOWN_PARSE_ERROR,
+    OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES,
+    EXPECTED_COLON,
+    EXPECTED_COMMA_OR_BRACKET,
+    EXPECTED_VALUE,
+    EXPECTED_COMMA_OR_BRACES,
+    EXPECTED_OBJECT_KEY_OR_BRACES,
+    EXPECTED_VALUE_OR_BRACKET,
+    INVALID_KEY_OR_VARIABLE_NAME,
+    NON_UTF_8,
+    PARSING_TERMINATED_BEFORE_END_OF_INPUT,
+    UNEXPECTED_TOKEN,
+    EXPECTED_CLOSING_QUOTE,
+    ILLEGAL_HEX_STRING,
+    INVALID_ESCAPE_SEQUENCE,
+    MISSING_LOW_SURROGATE,
+    INVALID_LOW_SURROGATE,
+    INVALID_UNICODE,
+    UNABLE_TO_PARSE_NUMBER,
+    NUMBER_EXCEEDS_RANGE_DOUBLE
+  };
+
+ private:
+  friend class JsonStreamParserTest;
+  // Return the current recursion depth.
+  int recursion_depth() { return recursion_depth_; }
+
+  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_t int_val;
+      uint64_t uint_val;
+    };
+  };
+
+  // Parses a single chunk of JSON, returning an error if the JSON was invalid.
+  util::Status ParseChunk(StringPiece chunk);
+
+  // 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);
+
+  // Parse a number as double into a NumberResult.
+  util::Status ParseDoubleHelper(const std::string& number,
+                                 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();
+  util::Status ParseEmptyNull();
+
+  // Whether an empty-null is allowed in the current state.
+  bool IsEmptyNullAllowed(TokenType type);
+
+  // Whether the whole input is all whitespaces.
+  bool IsInputAllWhiteSpaces(TokenType type);
+
+  // Report a failure as a util::Status.
+  util::Status ReportFailure(StringPiece message,
+                             ParseErrorType parse_code);
+
+  // 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,
+                             ParseErrorType parse_code);
+
+  // Helper function to check recursion depth and increment it. It will return
+  // OkStatus() if the current depth is allowed. Otherwise an error is returned.
+  // key is used for error reporting.
+  util::Status IncrementRecursionDepth(StringPiece key) const;
+
+  // 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.
+  std::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.
+  std::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_;
+
+  // Whether non whitespace tokens have been seen during parsing.
+  // It is used to handle the case of a pure whitespace stream input.
+  bool seen_non_whitespace_;
+
+  // The JsonStreamParser requires a root element by default and it will raise
+  // error if the root element is missing. If `allow_no_root_element_` is true,
+  // the JsonStreamParser can also handle this case.
+  bool allow_no_root_element_;
+
+  // 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.
+  std::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().
+  std::string chunk_storage_;
+
+  // Whether to allow non UTF-8 encoded input and replace invalid code points.
+  bool coerce_to_utf8_;
+
+  // Replacement character for invalid UTF-8 code points.
+  std::string utf8_replacement_character_;
+
+  // Whether allows empty string represented null array value or object entry
+  // value.
+  bool allow_empty_null_;
+
+  // Whether unquoted object keys can contain embedded non-alphanumeric
+  // characters when this is unambiguous for parsing.
+  bool allow_permissive_key_naming_;
+
+  // Whether allows out-of-range floating point numbers or reject them.
+  bool loose_float_number_conversion_;
+
+  // Tracks current recursion depth.
+  mutable int recursion_depth_;
+
+  // Maximum allowed recursion depth.
+  int max_recursion_depth_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonStreamParser);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..40157a2
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc
@@ -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.
+
+#include <google/protobuf/util/internal/json_stream_parser.h>
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/expecting_objectwriter.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/stubs/status.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using ParseErrorType =
+    ::google::protobuf::util::converter::JsonStreamParser::ParseErrorType;
+
+
+// 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.
+//
+// It is verified that expected calls to the mocked objects are in sequence.
+class JsonStreamParserTest : public ::testing::Test {
+ protected:
+  JsonStreamParserTest() : mock_(), ow_(&mock_) {}
+  ~JsonStreamParserTest() override {}
+
+  util::Status RunTest(StringPiece json, int split,
+                       std::function<void(JsonStreamParser*)> setup) {
+    JsonStreamParser parser(&mock_);
+    setup(&parser);
+
+    // 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();
+      }
+    }
+    if (result.ok()) {
+      EXPECT_EQ(parser.recursion_depth(), 0);
+    }
+    return result;
+  }
+
+  void DoTest(
+      StringPiece json, int split,
+      std::function<void(JsonStreamParser*)> setup = [](JsonStreamParser* p) {
+      }) {
+    util::Status result = RunTest(json, split, setup);
+    if (!result.ok()) {
+      GOOGLE_LOG(WARNING) << result;
+    }
+    EXPECT_TRUE(result.ok());
+  }
+
+  void DoErrorTest(
+      StringPiece json, int split, StringPiece error_prefix,
+      std::function<void(JsonStreamParser*)> setup = [](JsonStreamParser* p) {
+      }) {
+    util::Status result = RunTest(json, split, setup);
+    EXPECT_TRUE(util::IsInvalidArgument(result));
+    StringPiece error_message(result.message());
+    EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size()));
+  }
+
+  void DoErrorTest(
+      StringPiece json, int split, StringPiece error_prefix,
+      ParseErrorType expected_parse_error_type,
+      std::function<void(JsonStreamParser*)> setup = [](JsonStreamParser* p) {
+      }) {
+    util::Status result = RunTest(json, split, setup);
+    EXPECT_TRUE(util::IsInvalidArgument(result));
+    StringPiece error_message(result.message());
+    EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size()));
+  }
+
+
+#ifndef _MSC_VER
+  // TODO(xiaofeng): We have to disable InSequence check for MSVC because it
+  // causes stack overflow due to its use of a linked list that is destructed
+  // recursively.
+  ::testing::InSequence in_sequence_;
+#endif  // !_MSC_VER
+  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("", int64_t{-79497823553162765});
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleUnsignedInt) {
+  StringPiece str = "11779497823553162765";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderUint64("", uint64_t{11779497823553162765u});
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) {
+  StringPiece str = "01234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.",
+                ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+  }
+  str = "-01234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.",
+                ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+  }
+}
+
+TEST_F(JsonStreamParserTest, HexNumberIsInvalid) {
+  StringPiece str = "0x1234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.",
+                ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+  }
+  str = "-0x1234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.",
+                ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+  }
+  str = "12x34";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Unable to parse number.",
+                ParseErrorType::UNABLE_TO_PARSE_NUMBER);
+  }
+}
+
+// - single and double quoted strings
+TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) {
+  StringPiece str = "\"\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "");
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, EmptySingleQuotedString) {
+  StringPiece str = "''";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "");
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleDoubleQuotedString) {
+  StringPiece str = "\"Some String\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "Some String");
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleSingleQuotedString) {
+  StringPiece str = "'Another String'";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "Another String");
+    DoTest(str, i);
+  }
+}
+
+// - string key, unquoted key, numeric key
+TEST_F(JsonStreamParserTest, ObjectKeyTypes) {
+  StringPiece str =
+      "{'s': true, \"d\": false, key: null, snake_key: [], camelKey: {}}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")
+        ->RenderBool("s", true)
+        ->RenderBool("d", false)
+        ->RenderNull("key")
+        ->StartList("snake_key")
+        ->EndList()
+        ->StartObject("camelKey")
+        ->EndObject()
+        ->EndObject();
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnquotedObjectKeyWithReservedPrefxes) {
+  StringPiece str = "{ nullkey: \"a\", truekey: \"b\", falsekey: \"c\"}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")
+        ->RenderString("nullkey", "a")
+        ->RenderString("truekey", "b")
+        ->RenderString("falsekey", "c")
+        ->EndObject();
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnquotedObjectKeyWithReservedKeyword) {
+  StringPiece str = "{ null: \"a\", true: \"b\", false: \"c\"}";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Expected an object key or }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnquotedObjectKeyWithEmbeddedNonAlphanumeric) {
+  StringPiece str = "{ foo-bar-baz: \"a\"}";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Expected : between key:value pair.",
+                ParseErrorType::EXPECTED_COLON);
+  }
+}
+
+
+// - array containing primitive values (true, false, null, num, string)
+TEST_F(JsonStreamParserTest, ArrayPrimitiveValues) {
+  StringPiece str = "[true, false, null, 'one', \"two\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderBool("", true)
+        ->RenderBool("", false)
+        ->RenderNull("")
+        ->RenderString("", "one")
+        ->RenderString("", "two")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - array containing array, object
+TEST_F(JsonStreamParserTest, ArrayComplexValues) {
+  StringPiece str =
+      "[[22, -127, 45.3, -1056.4, 11779497823553162765], {'key': true}]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->StartList("")
+        ->RenderUint64("", 22)
+        ->RenderInt64("", -127)
+        ->RenderDouble("", 45.3)
+        ->RenderDouble("", -1056.4)
+        ->RenderUint64("", uint64_t{11779497823553162765u})
+        ->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", uint64_t{11779497823553162765u})
+        ->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.",
+                ParseErrorType::NON_UTF_8);
+  }
+  json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}";
+  for (int i = 0; i <= json.length(); ++i) {
+    DoErrorTest(json, i, "Encountered non UTF-8 code points.",
+                ParseErrorType::NON_UTF_8);
+  }
+  DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points.",
+              ParseErrorType::NON_UTF_8);
+}
+
+// - unicode handling in strings
+TEST_F(JsonStreamParserTest, UnicodeEscaping) {
+  StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - unicode UTF-16 surrogate pair handling in strings
+TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) {
+  StringPiece str =
+      "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderString("",
+                       "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0"
+                       "\x9F\x90\x9D\xF0\x9F\x8D\xAF")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+
+TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) {
+  // A low surrogate alone.
+  StringPiece str = "[\"\\ude36\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid unicode code point.",
+                ParseErrorType::INVALID_UNICODE);
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) {
+  // A high surrogate alone.
+  StringPiece str = "[\"\\ud83d\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Missing low surrogate.",
+                ParseErrorType::MISSING_LOW_SURROGATE);
+  }
+  // A high surrogate with some trailing characters.
+  str = "[\"\\ud83d|ude36\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Missing low surrogate.",
+                ParseErrorType::MISSING_LOW_SURROGATE);
+  }
+  // A high surrogate with half a low surrogate.
+  str = "[\"\\ud83d\\ude--\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.",
+                ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+  }
+  // Two high surrogates.
+  str = "[\"\\ud83d\\ud83d\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid low surrogate.",
+                ParseErrorType::INVALID_LOW_SURROGATE);
+  }
+}
+
+// - ascii escaping (\b, \f, \n, \r, \t, \v)
+TEST_F(JsonStreamParserTest, AsciiEscaping) {
+  StringPiece str =
+      "[\"\\b\", \"\\ning\", \"test\\f\", \"\\r\\t\", \"test\\\\\\ving\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderString("", "\b")
+        ->RenderString("", "\ning")
+        ->RenderString("", "test\f")
+        ->RenderString("", "\r\t")
+        ->RenderString("", "test\\\ving")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - trailing commas, we support a single trailing comma but no internal commas.
+TEST_F(JsonStreamParserTest, TrailingCommas) {
+  StringPiece str = "[['a',true,], {b: null,},]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->StartList("")
+        ->RenderString("", "a")
+        ->RenderBool("", true)
+        ->EndList()
+        ->StartObject("")
+        ->RenderNull("b")
+        ->EndObject()
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// Negative tests
+
+// illegal literals
+TEST_F(JsonStreamParserTest, ExtraTextAfterTrue) {
+  StringPiece str = "truee";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderBool("", true);
+    DoErrorTest(str, i, "Parsing terminated before end of input.",
+                ParseErrorType::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.",
+                ParseErrorType::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.",
+                ParseErrorType::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.", ParseErrorType::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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+// 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.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+// 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.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnterminatedObject) {
+  StringPiece str = "{";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Unexpected end of string.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+
+// 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.",
+                ParseErrorType::EXPECTED_COMMA_OR_BRACES);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_COMMA_OR_BRACKET);
+  }
+}
+
+// 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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_COLON);
+  }
+}
+
+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.",
+                ParseErrorType::EXPECTED_COLON);
+  }
+}
+
+TEST_F(JsonStreamParserTest, EndOfTextAfterKeyInObject) {
+  StringPiece str = "{key";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Unexpected end of string.",
+                ParseErrorType::EXPECTED_COLON);
+  }
+}
+
+TEST_F(JsonStreamParserTest, MissingValueAfterColonInObject) {
+  StringPiece str = "{key:}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Unexpected token.", ParseErrorType::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.",
+                ParseErrorType::EXPECTED_COMMA_OR_BRACES);
+  }
+}
+
+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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+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.",
+                ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT);
+  }
+}
+
+TEST_F(JsonStreamParserTest, PositiveNumberTooBigIsDouble) {
+  StringPiece str = "18446744073709551616";  // 2^64
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderDouble("", 18446744073709552000.0);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, NegativeNumberTooBigIsDouble) {
+  StringPiece str = "-18446744073709551616";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderDouble("", -18446744073709551616.0);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, DoubleTooBig) {
+  StringPiece str = "[1.89769e+308]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Number exceeds the range of double.",
+                ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE);
+  }
+  str = "[-1.89769e+308]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Number exceeds the range of double.",
+                ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE);
+  }
+}
+
+
+// invalid bare backslash.
+TEST_F(JsonStreamParserTest, UnfinishedEscape) {
+  StringPiece str = "\"\\";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Closing quote expected in string.",
+                ParseErrorType::EXPECTED_CLOSING_QUOTE);
+  }
+}
+
+// invalid bare backslash u.
+TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) {
+  StringPiece str = "\"\\u";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Illegal hex string.",
+                ParseErrorType::ILLEGAL_HEX_STRING);
+  }
+}
+
+// invalid unicode sequence.
+TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) {
+  StringPiece str = "\"\\u12";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Illegal hex string.",
+                ParseErrorType::ILLEGAL_HEX_STRING);
+  }
+}
+
+// invalid unicode sequence (valid in modern EcmaScript but not in JSON).
+TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) {
+  StringPiece str = "\"\\u{1f36f}\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.",
+                ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+  }
+}
+
+
+TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) {
+  StringPiece str = "\"\\u12$4hello";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.",
+                ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+  }
+}
+
+// invalid unicode sequence in low half surrogate: g is not a hex digit.
+TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) {
+  StringPiece str = "\"\\ud800\\udcfg\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.",
+                ParseErrorType::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 }.",
+                ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+}
+
+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.", ParseErrorType::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.",
+                ParseErrorType::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.",
+                ParseErrorType::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.",
+                ParseErrorType::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.", ParseErrorType::EXPECTED_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.",
+                ParseErrorType::EXPECTED_VALUE_OR_BRACKET);
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnknownCharactersInObject) {
+  StringPiece str = "{'key': *&#25}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected a value.", ParseErrorType::EXPECTED_VALUE);
+  }
+}
+
+TEST_F(JsonStreamParserTest, DeepNestJsonNotExceedLimit) {
+  int count = 99;
+  std::string str;
+  for (int i = 0; i < count; ++i) {
+    StrAppend(&str, "{'a':");
+  }
+  StrAppend(&str, "{'nest64':'v1', 'nest64': false, 'nest64': ['v2']}");
+  for (int i = 0; i < count; ++i) {
+    StrAppend(&str, "}");
+  }
+  ow_.StartObject("");
+  for (int i = 0; i < count; ++i) {
+    ow_.StartObject("a");
+  }
+  ow_.RenderString("nest64", "v1")
+      ->RenderBool("nest64", false)
+      ->StartList("nest64")
+      ->RenderString("", "v2")
+      ->EndList();
+  for (int i = 0; i < count; ++i) {
+    ow_.EndObject();
+  }
+  ow_.EndObject();
+  DoTest(str, 0);
+}
+
+TEST_F(JsonStreamParserTest, DeepNestJsonExceedLimit) {
+  int count = 98;
+  std::string str;
+  for (int i = 0; i < count; ++i) {
+    StrAppend(&str, "{'a':");
+  }
+  // Supports trailing commas.
+  StrAppend(&str,
+                  "{'nest11' : [{'nest12' : null,},],"
+                  "'nest21' : {'nest22' : {'nest23' : false}}}");
+  for (int i = 0; i < count; ++i) {
+    StrAppend(&str, "}");
+  }
+  DoErrorTest(str, 0,
+              "Message too deep. Max recursion depth reached for key 'nest22'");
+}
+
+}  // 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..68fefcc
--- /dev/null
+++ b/src/google/protobuf/util/internal/location_tracker.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_EXPORT LocationTrackerInterface {
+ public:
+  virtual ~LocationTrackerInterface() {}
+
+  // Returns the object location as human readable string.
+  virtual std::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
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..3fbdd88
--- /dev/null
+++ b/src/google/protobuf/util/internal/mock_error_listener.h
@@ -0,0 +1,68 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_MOCK_ERROR_LISTENER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_MOCK_ERROR_LISTENER_H__
+
+#include <gmock/gmock.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class MockErrorListener : public ErrorListener {
+ public:
+  MockErrorListener() {}
+  ~MockErrorListener() override {}
+
+  MOCK_METHOD(void, InvalidName,
+              (const LocationTrackerInterface& loc,
+               StringPiece unknown_name, StringPiece message),
+              (override));
+  MOCK_METHOD(void, InvalidValue,
+              (const LocationTrackerInterface& loc, StringPiece type_name,
+               StringPiece value),
+              (override));
+  MOCK_METHOD(void, MissingField,
+              (const LocationTrackerInterface& loc,
+               StringPiece missing_name),
+              (override));
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..47821e6
--- /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_INTERNAL_OBJECT_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_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() {}
+
+  ~ObjectLocationTracker() override {}
+
+  // Returns empty because nothing is tracked.
+  std::string ToString() const override { return ""; }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectLocationTracker);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..fc7672e
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_source.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_UTIL_INTERNAL_OBJECT_SOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_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
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..4dabd37
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_writer.cc
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/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().value());
+      break;
+    }
+    case DataPiece::TYPE_INT64: {
+      ow->RenderInt64(name, data.ToInt64().value());
+      break;
+    }
+    case DataPiece::TYPE_UINT32: {
+      ow->RenderUint32(name, data.ToUint32().value());
+      break;
+    }
+    case DataPiece::TYPE_UINT64: {
+      ow->RenderUint64(name, data.ToUint64().value());
+      break;
+    }
+    case DataPiece::TYPE_DOUBLE: {
+      ow->RenderDouble(name, data.ToDouble().value());
+      break;
+    }
+    case DataPiece::TYPE_FLOAT: {
+      ow->RenderFloat(name, data.ToFloat().value());
+      break;
+    }
+    case DataPiece::TYPE_BOOL: {
+      ow->RenderBool(name, data.ToBool().value());
+      break;
+    }
+    case DataPiece::TYPE_STRING: {
+      ow->RenderString(name, data.ToString().value());
+      break;
+    }
+    case DataPiece::TYPE_BYTES: {
+      ow->RenderBytes(name, data.ToBytes().value());
+      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..bc4095b
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -0,0 +1,151 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INTERNAL_OBJECT_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_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_t value) = 0;
+
+  // Renders an 32-bit unsigned integer value.
+  virtual ObjectWriter* RenderUint32(StringPiece name,
+                                     uint32_t value) = 0;
+
+  // Renders a 64-bit integer value.
+  virtual ObjectWriter* RenderInt64(StringPiece name, int64_t value) = 0;
+
+  // Renders an 64-bit unsigned integer value.
+  virtual ObjectWriter* RenderUint64(StringPiece name,
+                                     uint64_t value) = 0;
+
+
+  // Renders a double value.
+  virtual ObjectWriter* RenderDouble(StringPiece name, double value) = 0;
+  // Renders a float value.
+  virtual ObjectWriter* RenderFloat(StringPiece name, float value) = 0;
+
+  // Renders a StringPiece value. This is for rendering strings.
+  virtual ObjectWriter* RenderString(StringPiece name,
+                                     StringPiece value) = 0;
+
+  // Renders a bytes value.
+  virtual ObjectWriter* RenderBytes(StringPiece name, StringPiece value) = 0;
+
+  // Renders a Null value.
+  virtual ObjectWriter* RenderNull(StringPiece name) = 0;
+
+
+  // Renders a DataPiece object to a ObjectWriter.
+  static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
+                                ObjectWriter* ow);
+
+
+  // Indicates whether this ObjectWriter has completed writing the root message,
+  // usually this means writing of one complete object. Subclasses must override
+  // this behavior appropriately.
+  virtual bool done() { return false; }
+
+  void set_use_strict_base64_decoding(bool value) {
+    use_strict_base64_decoding_ = value;
+  }
+
+  bool use_strict_base64_decoding() const {
+    return use_strict_base64_decoding_;
+  }
+
+ protected:
+  ObjectWriter() : use_strict_base64_decoding_(true) {}
+
+ private:
+  // If set to true, we use the stricter version of base64 decoding for byte
+  // fields by making sure decoded version encodes back to the original string.
+  bool use_strict_base64_decoding_;
+
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..afa5e2e
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -0,0 +1,827 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <functional>
+#include <stack>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using io::CodedOutputStream;
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
+
+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),
+      ignore_unknown_fields_(false),
+      ignore_unknown_enum_values_(false),
+      use_lower_camel_for_enums_(false),
+      case_insensitive_enum_parsing_(true),
+      use_json_name_in_missing_fields_(false),
+      element_(nullptr),
+      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),
+      ignore_unknown_fields_(false),
+      ignore_unknown_enum_values_(false),
+      use_lower_camel_for_enums_(false),
+      case_insensitive_enum_parsing_(true),
+      use_json_name_in_missing_fields_(false),
+      element_(nullptr),
+      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_ == nullptr) 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().
+  std::unique_ptr<BaseElement> element(
+      static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+  while (element != nullptr) {
+    element.reset(element->pop<BaseElement>());
+  }
+}
+
+namespace {
+
+// Writes an INT32 field, including tag to the stream.
+inline util::Status WriteInt32(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<int32_t> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteInt32(field_number, i32.value(), stream);
+  }
+  return i32.status();
+}
+
+// writes an SFIXED32 field, including tag, to the stream.
+inline util::Status WriteSFixed32(int field_number, const DataPiece& data,
+                                  CodedOutputStream* stream) {
+  util::StatusOr<int32_t> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSFixed32(field_number, i32.value(), stream);
+  }
+  return i32.status();
+}
+
+// Writes an SINT32 field, including tag, to the stream.
+inline util::Status WriteSInt32(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<int32_t> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSInt32(field_number, i32.value(), stream);
+  }
+  return i32.status();
+}
+
+// Writes a FIXED32 field, including tag, to the stream.
+inline util::Status WriteFixed32(int field_number, const DataPiece& data,
+                                 CodedOutputStream* stream) {
+  util::StatusOr<uint32_t> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteFixed32(field_number, u32.value(), stream);
+  }
+  return u32.status();
+}
+
+// Writes a UINT32 field, including tag, to the stream.
+inline util::Status WriteUInt32(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<uint32_t> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteUInt32(field_number, u32.value(), stream);
+  }
+  return u32.status();
+}
+
+// Writes an INT64 field, including tag, to the stream.
+inline util::Status WriteInt64(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<int64_t> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteInt64(field_number, i64.value(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SFIXED64 field, including tag, to the stream.
+inline util::Status WriteSFixed64(int field_number, const DataPiece& data,
+                                  CodedOutputStream* stream) {
+  util::StatusOr<int64_t> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSFixed64(field_number, i64.value(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SINT64 field, including tag, to the stream.
+inline util::Status WriteSInt64(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<int64_t> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSInt64(field_number, i64.value(), stream);
+  }
+  return i64.status();
+}
+
+// Writes a FIXED64 field, including tag, to the stream.
+inline util::Status WriteFixed64(int field_number, const DataPiece& data,
+                                 CodedOutputStream* stream) {
+  util::StatusOr<uint64_t> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteFixed64(field_number, u64.value(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a UINT64 field, including tag, to the stream.
+inline util::Status WriteUInt64(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<uint64_t> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteUInt64(field_number, u64.value(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a DOUBLE field, including tag, to the stream.
+inline util::Status WriteDouble(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<double> d = data.ToDouble();
+  if (d.ok()) {
+    WireFormatLite::WriteDouble(field_number, d.value(), stream);
+  }
+  return d.status();
+}
+
+// Writes a FLOAT field, including tag, to the stream.
+inline util::Status WriteFloat(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<float> f = data.ToFloat();
+  if (f.ok()) {
+    WireFormatLite::WriteFloat(field_number, f.value(), stream);
+  }
+  return f.status();
+}
+
+// Writes a BOOL field, including tag, to the stream.
+inline util::Status WriteBool(int field_number, const DataPiece& data,
+                              CodedOutputStream* stream) {
+  util::StatusOr<bool> b = data.ToBool();
+  if (b.ok()) {
+    WireFormatLite::WriteBool(field_number, b.value(), stream);
+  }
+  return b.status();
+}
+
+// Writes a BYTES field, including tag, to the stream.
+inline util::Status WriteBytes(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<std::string> c = data.ToBytes();
+  if (c.ok()) {
+    WireFormatLite::WriteBytes(field_number, c.value(), stream);
+  }
+  return c.status();
+}
+
+// Writes a STRING field, including tag, to the stream.
+inline util::Status WriteString(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<std::string> s = data.ToString();
+  if (s.ok()) {
+    WireFormatLite::WriteString(field_number, s.value(), stream);
+  }
+  return s.status();
+}
+
+// Given a google::protobuf::Type, returns the set of all required fields.
+std::unordered_set<const google::protobuf::Field*> GetRequiredFields(
+    const google::protobuf::Type& type) {
+  std::unordered_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_REQUIRED) {
+      required.insert(&field);
+    }
+  }
+  return required;
+}
+
+}  // namespace
+
+ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
+                                        const google::protobuf::Type& type,
+                                        ProtoWriter* enclosing)
+    : BaseElement(nullptr),
+      ow_(enclosing),
+      parent_field_(nullptr),
+      typeinfo_(typeinfo),
+      proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
+      type_(type),
+      size_index_(-1),
+      array_index_(-1),
+      // oneof_indices_ values are 1-indexed (0 means not present).
+      oneof_indices_(type.oneofs_size() + 1) {
+  if (!proto3_) {
+    required_fields_ = GetRequiredFields(type_);
+  }
+}
+
+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_),
+      proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
+      type_(type),
+      size_index_(!is_list &&
+                          field->kind() == google::protobuf::Field::TYPE_MESSAGE
+                      ? ow_->size_insert_.size()
+                      : -1),
+      array_index_(is_list ? 0 : -1),
+      // oneof_indices_ values are 1-indexed (0 means not present).
+      oneof_indices_(type_.oneofs_size() + 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 if (!proto3_) {
+      // For required fields tracking.
+      this->parent()->RegisterField(field);
+    }
+
+    if (field->kind() == google::protobuf::Field::TYPE_MESSAGE) {
+      if (!proto3_) {
+        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() {
+  if (!proto3_) {
+    // Calls the registered error listener for any required field(s) not yet
+    // seen.
+    for (std::unordered_set<const google::protobuf::Field*>::iterator it =
+             required_fields_.begin();
+         it != required_fields_.end(); ++it) {
+      ow_->MissingField(ow_->use_json_name_in_missing_fields_
+                            ? (*it)->json_name()
+                            : (*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 != nullptr; 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_REQUIRED) {
+    required_fields_.erase(field);
+  }
+}
+
+std::string ProtoWriter::ProtoElement::ToString() const {
+  std::string loc = "";
+
+  // first populate a stack with the nodes since we need to process them
+  // from root to leaf when generating the string location
+  const ProtoWriter::ProtoElement* now = this;
+  std::stack<const ProtoWriter::ProtoElement*> element_stack;
+  while (now->parent() != nullptr) {
+    element_stack.push(now);
+    now = now->parent();
+  }
+
+  // now pop each node from the stack and append to the location string
+  while (!element_stack.empty()) {
+    now = element_stack.top();
+    element_stack.pop();
+
+    if (!ow_->IsRepeated(*(now->parent_field_)) ||
+        now->parent()->parent_field_ != now->parent_field_) {
+      std::string name = now->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), "\"]");
+      }
+    }
+
+    int array_index_now = now->array_index_;
+    if (ow_->IsRepeated(*(now->parent_field_)) && array_index_now > 0) {
+      StrAppend(&loc, "[", array_index_now - 1, "]");
+    }
+  }
+
+  return loc;
+}
+
+bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32_t index) {
+  return oneof_indices_[index];
+}
+
+void ProtoWriter::ProtoElement::TakeOneofIndex(int32_t index) {
+  oneof_indices_[index] = true;
+}
+
+void ProtoWriter::InvalidName(StringPiece unknown_name,
+                              StringPiece message) {
+  listener_->InvalidName(location(), 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_ == nullptr) {
+    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 = BeginNamed(name, false);
+
+  if (field == nullptr) 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 == nullptr) {
+    ++invalid_depth_;
+    InvalidName(name, StrCat("Missing descriptor for field: ",
+                                   field->type_url()));
+    return this;
+  }
+
+  return StartObjectField(*field, *type);
+}
+
+
+ProtoWriter* ProtoWriter::EndObject() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+    return this;
+  }
+
+  if (element_ != nullptr) {
+    element_.reset(element_->pop());
+  }
+
+
+  // If ending the root element,
+  // then serialize the full message with calculated sizes.
+  if (element_ == nullptr) {
+    WriteRootMessage();
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartList(
+    StringPiece name) {
+
+  const google::protobuf::Field* field = BeginNamed(name, true);
+
+  if (field == nullptr) return this;
+
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == nullptr) {
+    ++invalid_depth_;
+    InvalidName(name, StrCat("Missing descriptor for field: ",
+                                   field->type_url()));
+    return this;
+  }
+
+  return StartListField(*field, *type);
+}
+
+
+ProtoWriter* ProtoWriter::EndList() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+  } else if (element_ != nullptr) {
+    element_.reset(element_->pop());
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& data) {
+  util::Status status;
+  if (invalid_depth_ > 0) return this;
+
+  const google::protobuf::Field* field = Lookup(name);
+
+  if (field == nullptr) return this;
+
+  if (!ValidOneof(*field, name)) return this;
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == nullptr) {
+    InvalidName(name, StrCat("Missing descriptor for field: ",
+                                   field->type_url()));
+    return this;
+  }
+
+  return RenderPrimitiveField(*field, *type, data);
+}
+
+bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
+                             StringPiece unnormalized_name) {
+  if (element_ == nullptr) 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_REPEATED;
+}
+
+ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field,
+                                           const google::protobuf::Type& type) {
+    WriteTag(field);
+  element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field,
+                                         const google::protobuf::Type& type) {
+  element_.reset(new ProtoElement(element_.release(), &field, type, true));
+  return this;
+}
+
+util::Status ProtoWriter::WriteEnum(int field_number, const DataPiece& data,
+                                    const google::protobuf::Enum* enum_type,
+                                    CodedOutputStream* stream,
+                                    bool use_lower_camel_for_enums,
+                                    bool case_insensitive_enum_parsing,
+                                    bool ignore_unknown_values) {
+  bool is_unknown_enum_value = false;
+  util::StatusOr<int> e = data.ToEnum(
+      enum_type, use_lower_camel_for_enums, case_insensitive_enum_parsing,
+      ignore_unknown_values, &is_unknown_enum_value);
+  if (e.ok() && !is_unknown_enum_value) {
+    WireFormatLite::WriteEnum(field_number, e.value(), stream);
+  }
+  return e.status();
+}
+
+ProtoWriter* ProtoWriter::RenderPrimitiveField(
+    const google::protobuf::Field& field, const google::protobuf::Type& type,
+    const DataPiece& data) {
+  util::Status status;
+
+  // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
+  // error location reporting and required field accounting.
+  //
+  // For proto3, since there is no required field tracking, we only need to
+  // push ProtoElement for error cases.
+  if (!element_->proto3()) {
+    element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  }
+
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_INT32: {
+      status = WriteInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      status = WriteSFixed32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT32: {
+      status = WriteSInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED32: {
+      status = WriteFixed32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT32: {
+      status = WriteUInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT64: {
+      status = WriteInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      status = WriteSFixed64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT64: {
+      status = WriteSInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED64: {
+      status = WriteFixed64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT64: {
+      status = WriteUInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      status = WriteDouble(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      status = WriteFloat(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_BOOL: {
+      status = WriteBool(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      status = WriteBytes(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      status = WriteString(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      status = WriteEnum(
+          field.number(), data, typeinfo_->GetEnumByTypeUrl(field.type_url()),
+          stream_.get(), use_lower_camel_for_enums_,
+          case_insensitive_enum_parsing_, ignore_unknown_enum_values_);
+      break;
+    }
+    default:  // TYPE_GROUP, TYPE_MESSAGE, TYPE_UNKNOWN.
+      status = util::InvalidArgumentError(data.ValueAsStringOrDefault(""));
+  }
+
+  if (!status.ok()) {
+    // Push a ProtoElement for location reporting purposes.
+    if (element_->proto3()) {
+      element_.reset(new ProtoElement(element_.release(), &field, type, false));
+    }
+    InvalidValue(field.type_url().empty()
+                     ? google::protobuf::Field_Kind_Name(field.kind())
+                     : field.type_url(),
+                 status.message());
+    element_.reset(element()->pop());
+    return this;
+  }
+
+  if (!element_->proto3()) element_.reset(element()->pop());
+
+  return this;
+}
+
+const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
+                                                       bool is_list) {
+  if (invalid_depth_ > 0) {
+    ++invalid_depth_;
+    return nullptr;
+  }
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == nullptr) {
+    ++invalid_depth_;
+    // InvalidName() already called in Lookup().
+    return nullptr;
+  }
+  if (is_list && !IsRepeated(*field)) {
+    ++invalid_depth_;
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return nullptr;
+  }
+  return field;
+}
+
+const google::protobuf::Field* ProtoWriter::Lookup(
+    StringPiece unnormalized_name) {
+  ProtoElement* e = element();
+  if (e == nullptr) {
+    InvalidName(unnormalized_name, "Root element must be a message.");
+    return nullptr;
+  }
+  if (unnormalized_name.empty()) {
+    // Objects in repeated field inherit the same field descriptor.
+    if (e->parent_field() == nullptr) {
+      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 nullptr;
+    }
+    return e->parent_field();
+  }
+  const google::protobuf::Field* field =
+      typeinfo_->FindField(&e->type(), unnormalized_name);
+  if (field == nullptr && !ignore_unknown_fields_) {
+    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::TYPE_MESSAGE ||
+           field->kind() == google::protobuf::Field::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(nullptr);
+  const void* data;
+  int length;
+  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_t insert_buffer[10];
+      uint8_t* 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..a7cf6ac
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -0,0 +1,389 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INTERNAL_PROTO_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
+
+#include <cstdint>
+#include <deque>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.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/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.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/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+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 PROTOBUF_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);
+  ~ProtoWriter() override;
+
+  // ObjectWriter methods.
+  ProtoWriter* StartObject(StringPiece name) override;
+  ProtoWriter* EndObject() override;
+  ProtoWriter* StartList(StringPiece name) override;
+  ProtoWriter* EndList() override;
+  ProtoWriter* RenderBool(StringPiece name, bool value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderInt32(StringPiece name, int32_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderUint32(StringPiece name, uint32_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderInt64(StringPiece name, int64_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderUint64(StringPiece name, uint64_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderDouble(StringPiece name, double value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderFloat(StringPiece name, float value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderString(StringPiece name,
+                            StringPiece value) override {
+    return RenderDataPiece(name,
+                           DataPiece(value, use_strict_base64_decoding()));
+  }
+
+  ProtoWriter* RenderBytes(StringPiece name, StringPiece value) override {
+    return RenderDataPiece(
+        name, DataPiece(value, false, use_strict_base64_decoding()));
+  }
+
+  ProtoWriter* RenderNull(StringPiece name) override {
+    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& data);
+
+
+  // Returns the location tracker to use for tracking locations for errors.
+  const LocationTrackerInterface& location() {
+    return element_ != nullptr ? *element_ : *tracker_;
+  }
+
+  // When true, we finished writing to output a complete message.
+  bool done() override { return done_; }
+
+  // Returns the proto stream object.
+  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_; }
+
+  void set_ignore_unknown_fields(bool ignore_unknown_fields) {
+    ignore_unknown_fields_ = ignore_unknown_fields;
+  }
+
+  bool ignore_unknown_fields() { return ignore_unknown_fields_; }
+
+  void set_ignore_unknown_enum_values(bool ignore_unknown_enum_values) {
+    ignore_unknown_enum_values_ = ignore_unknown_enum_values;
+  }
+
+  void set_use_lower_camel_for_enums(bool use_lower_camel_for_enums) {
+    use_lower_camel_for_enums_ = use_lower_camel_for_enums;
+  }
+
+  void set_case_insensitive_enum_parsing(bool case_insensitive_enum_parsing) {
+    case_insensitive_enum_parsing_ = case_insensitive_enum_parsing;
+  }
+
+  void set_use_json_name_in_missing_fields(
+      bool use_json_name_in_missing_fields) {
+    use_json_name_in_missing_fields_ = use_json_name_in_missing_fields;
+  }
+
+ protected:
+  class PROTOBUF_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);
+
+    ~ProtoElement() override {}
+
+    // 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 nullptr 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.
+    std::string ToString() const override;
+
+    ProtoElement* parent() const override {
+      return static_cast<ProtoElement*>(BaseElement::parent());
+    }
+
+    // Returns true if the index is already taken by a preceding oneof input.
+    bool IsOneofIndexTaken(int32_t index);
+
+    // Marks the oneof 'index' as taken. Future inputs to this oneof will
+    // generate an error.
+    void TakeOneofIndex(int32_t index);
+
+    bool proto3() { return proto3_; }
+
+   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 nullptr if and only if this element is the root element.
+    const google::protobuf::Field* parent_field_;
+
+    // TypeInfo to lookup types.
+    const TypeInfo* typeinfo_;
+
+    // Whether the type_ is proto3 or not.
+    bool proto3_;
+
+    // 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::unordered_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.
+    std::vector<bool> 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);
+
+  ProtoElement* element() override { 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 when ignore_unknown_names_ is false or if multiple matching
+  // extensions are found.
+  const google::protobuf::Field* Lookup(StringPiece name);
+
+  // Lookup the field type in the type descriptor. Returns nullptr if the type
+  // is not known.
+  const google::protobuf::Type* LookupType(
+      const google::protobuf::Field* field);
+
+  // Write serialized output to the final output ByteSink, inserting all
+  // the size information for nested messages that are missing from the
+  // intermediate Cord buffer.
+  void WriteRootMessage();
+
+  // Helper method to write proto tags based on the given field.
+  void WriteTag(const google::protobuf::Field& field);
+
+
+  // Returns true if the field for type_ can be set as a oneof. If field is not
+  // a oneof type, this function does nothing and returns true.
+  // If another field for this oneof is already set, this function returns
+  // false. It also calls the appropriate error callback.
+  // unnormalized_name is used for error string.
+  bool ValidOneof(const google::protobuf::Field& field,
+                  StringPiece unnormalized_name);
+
+  // Returns true if the field is repeated.
+  bool IsRepeated(const google::protobuf::Field& field);
+
+  // Starts an object given the field and the enclosing type.
+  ProtoWriter* StartObjectField(const google::protobuf::Field& field,
+                                const google::protobuf::Type& type);
+
+  // Starts a list given the field and the enclosing type.
+  ProtoWriter* StartListField(const google::protobuf::Field& field,
+                              const google::protobuf::Type& type);
+
+  // Renders a primitive field given the field and the enclosing type.
+  ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field,
+                                    const google::protobuf::Type& type,
+                                    const DataPiece& data);
+
+ private:
+  // Writes an ENUM field, including tag, to the stream.
+  static util::Status WriteEnum(int field_number, const DataPiece& data,
+                                const google::protobuf::Enum* enum_type,
+                                io::CodedOutputStream* stream,
+                                bool use_lower_camel_for_enums,
+                                bool case_insensitive_enum_parsing,
+                                bool ignore_unknown_values);
+
+  // 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_;
+
+  // If true, don't report unknown field names to the listener.
+  bool ignore_unknown_fields_;
+
+  // If true, don't report unknown enum values to the listener.
+  bool ignore_unknown_enum_values_;
+
+  // If true, check if enum name in camel case or without underscore matches the
+  // field name.
+  bool use_lower_camel_for_enums_;
+
+  // If true, check if enum name in UPPER_CASE matches the field name.
+  bool case_insensitive_enum_parsing_;
+
+  // If true, use the json name in missing fields errors.
+  bool use_json_name_in_missing_fields_;
+
+  // 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.
+  std::unique_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_;
+  std::string buffer_;
+  io::StringOutputStream adapter_;
+  std::unique_ptr<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_;
+  std::unique_ptr<LocationTrackerInterface> tracker_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..cf6c99a
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -0,0 +1,1114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <unordered_map>
+#include <utility>
+
+#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.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormat;
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
+
+namespace {
+
+static int kDefaultMaxRecursionDepth = 64;
+
+// Finds a field with the given number. nullptr 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. nullptr if none found.
+const google::protobuf::EnumValue* FindEnumValueByNumber(
+    const google::protobuf::Enum& tech_enum, int number);
+
+// Utility function to format nanos.
+const std::string FormatNanos(uint32_t nanos, bool with_trailing_zeros);
+
+util::StatusOr<std::string> MapKeyDefaultValueAsString(
+    const google::protobuf::Field& field) {
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_BOOL:
+      return std::string("false");
+    case google::protobuf::Field::TYPE_INT32:
+    case google::protobuf::Field::TYPE_INT64:
+    case google::protobuf::Field::TYPE_UINT32:
+    case google::protobuf::Field::TYPE_UINT64:
+    case google::protobuf::Field::TYPE_SINT32:
+    case google::protobuf::Field::TYPE_SINT64:
+    case google::protobuf::Field::TYPE_SFIXED32:
+    case google::protobuf::Field::TYPE_SFIXED64:
+    case google::protobuf::Field::TYPE_FIXED32:
+    case google::protobuf::Field::TYPE_FIXED64:
+      return std::string("0");
+    case google::protobuf::Field::TYPE_STRING:
+      return std::string();
+    default:
+      return util::InternalError("Invalid map key type.");
+  }
+}
+}  // namespace
+
+
+ProtoStreamObjectSource::ProtoStreamObjectSource(
+    io::CodedInputStream* stream, TypeResolver* type_resolver,
+    const google::protobuf::Type& type, const RenderOptions& render_options)
+    : stream_(stream),
+      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      type_(type),
+      render_options_(render_options),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
+}
+
+ProtoStreamObjectSource::ProtoStreamObjectSource(
+    io::CodedInputStream* stream, const TypeInfo* typeinfo,
+    const google::protobuf::Type& type, const RenderOptions& render_options)
+    : stream_(stream),
+      typeinfo_(typeinfo),
+      own_typeinfo_(false),
+      type_(type),
+      render_options_(render_options),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
+}
+
+ProtoStreamObjectSource::~ProtoStreamObjectSource() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+}
+
+util::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_t 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 != nullptr) {
+    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 = nullptr;
+    }
+  }
+  return field;
+}
+
+util::Status ProtoStreamObjectSource::WriteMessage(
+    const google::protobuf::Type& type, StringPiece name,
+    const uint32_t end_tag, bool include_start_and_end,
+    ObjectWriter* ow) const {
+
+  const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
+  if (type_renderer != nullptr) {
+    return (*type_renderer)(this, type, name, ow);
+  }
+
+  const google::protobuf::Field* field = nullptr;
+  std::string field_name;
+  // last_tag set to dummy value that is different from tag.
+  uint32_t tag = stream_->ReadTag(), last_tag = tag + 1;
+  UnknownFieldSet unknown_fields;
+
+
+  if (include_start_and_end) {
+    ow->StartObject(name);
+  }
+  while (tag != end_tag && tag != 0) {
+    if (tag != last_tag) {  // Update field only if tag is changed.
+      last_tag = tag;
+      field = FindAndVerifyField(type, tag);
+      if (field != nullptr) {
+        if (render_options_.preserve_proto_field_names) {
+          field_name = field->name();
+        } else {
+          field_name = field->json_name();
+        }
+      }
+    }
+    if (field == nullptr) {
+      // If we didn't find a field, skip this unknown tag.
+      // TODO(wpoon): Check return boolean value.
+      WireFormat::SkipField(
+          stream_, tag,
+                                                nullptr);
+      tag = stream_->ReadTag();
+      continue;
+    }
+
+    if (field->cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) {
+      if (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 util::Status();
+}
+
+util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderList(
+    const google::protobuf::Field* field, StringPiece name,
+    uint32_t list_tag, ObjectWriter* ow) const {
+  uint32_t 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;
+}
+
+util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderMap(
+    const google::protobuf::Field* field, StringPiece /* name */,
+    uint32_t list_tag, ObjectWriter* ow) const {
+  const google::protobuf::Type* field_type =
+      typeinfo_->GetTypeByTypeUrl(field->type_url());
+  uint32_t tag_to_return = 0;
+  do {
+    // Render map entry message type.
+    uint32_t buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    std::string map_key;
+    for (uint32_t tag = stream_->ReadTag(); tag != 0;
+         tag = stream_->ReadTag()) {
+      const google::protobuf::Field* map_entry_field =
+          FindAndVerifyField(*field_type, tag);
+      if (map_entry_field == nullptr) {
+        WireFormat::SkipField(stream_, tag, nullptr);
+        continue;
+      }
+      // Map field numbers are key = 1 and value = 2
+      if (map_entry_field->number() == 1) {
+        map_key = ReadFieldValueAsString(*map_entry_field);
+      } else if (map_entry_field->number() == 2) {
+        if (map_key.empty()) {
+          // An absent map key is treated as the default.
+          const google::protobuf::Field* key_field =
+              FindFieldByNumber(*field_type, 1);
+          if (key_field == nullptr) {
+            // The Type info for this map entry is incorrect. It should always
+            // have a field named "key" and with field number 1.
+            return util::InternalError("Invalid map entry.");
+          }
+          ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field));
+        }
+        RETURN_IF_ERROR(RenderField(map_entry_field, map_key, ow));
+      } else {
+        // The Type info for this map entry is incorrect. It should contain
+        // exactly two fields with field number 1 and 2.
+        return util::InternalError("Invalid map entry.");
+      }
+    }
+    stream_->PopLimit(old_limit);
+  } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+  return tag_to_return;
+}
+
+util::Status ProtoStreamObjectSource::RenderPacked(
+    const google::protobuf::Field* field, ObjectWriter* ow) const {
+  uint32_t 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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderTimestamp(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  std::pair<int64_t, int32_t> p = os->ReadSecondsAndNanos(type);
+  int64_t seconds = p.first;
+  int32_t nanos = p.second;
+  if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) {
+    return util::InternalError(StrCat(
+        "Timestamp seconds exceeds limit for field: ", field_name));
+  }
+
+  if (nanos < 0 || nanos >= kNanosPerSecond) {
+    return util::InternalError(
+        StrCat("Timestamp nanos exceeds limit for field: ", field_name));
+  }
+
+  ow->RenderString(field_name,
+                   ::google::protobuf::internal::FormatTime(seconds, nanos));
+
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderDuration(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  std::pair<int64_t, int32_t> p = os->ReadSecondsAndNanos(type);
+  int64_t seconds = p.first;
+  int32_t nanos = p.second;
+  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) {
+    return util::InternalError(
+        StrCat("Duration seconds exceeds limit for field: ", field_name));
+  }
+
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    return util::InternalError(
+        StrCat("Duration nanos exceeds limit for field: ", field_name));
+  }
+
+  std::string sign = "";
+  if (seconds < 0) {
+    if (nanos > 0) {
+      return util::InternalError(
+          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;
+  }
+  std::string formatted_duration = StringPrintf(
+      "%s%lld%ss", sign.c_str(), static_cast<long long>(seconds),  // NOLINT
+      FormatNanos(
+          nanos,
+          false
+          )
+          .c_str());
+  ow->RenderString(field_name, formatted_duration);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderDouble(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t 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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderFloat(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t 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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderInt64(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t 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_t>(buffer64));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderUInt64(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t 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_t>(buffer64));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderInt32(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t 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_t>(buffer32));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderUInt32(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t 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_t>(buffer32));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderBool(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t 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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderString(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32;
+  std::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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderBytes(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32;
+  std::string str;
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadString(&str, buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderBytes(field_name, str);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderStruct(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  const google::protobuf::Field* field = nullptr;
+  uint32_t tag = os->stream_->ReadTag();
+  ow->StartObject(field_name);
+  while (tag != 0) {
+    field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      tag = os->stream_->ReadTag();
+      continue;
+    }
+    // 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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderStructValue(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  const google::protobuf::Field* field = nullptr;
+  for (uint32_t tag = os->stream_->ReadTag(); tag != 0;
+       tag = os->stream_->ReadTag()) {
+    field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      continue;
+    }
+    RETURN_IF_ERROR(os->RenderField(field, field_name, ow));
+  }
+  return util::Status();
+}
+
+// TODO(skarvaje): Avoid code duplication of for loops and SkipField logic.
+util::Status ProtoStreamObjectSource::RenderStructListValue(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+
+  // Render empty list when we find empty ListValue message.
+  if (tag == 0) {
+    ow->StartList(field_name);
+    ow->EndList();
+    return util::Status();
+  }
+
+  while (tag != 0) {
+    const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      tag = os->stream_->ReadTag();
+      continue;
+    }
+    ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow));
+  }
+  return util::Status();
+}
+
+util::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_t tag;
+  std::string type_url;
+  std::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 == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      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_t 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_t 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();
+  }
+
+  // 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::InternalError("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::InternalError(resolved_type.status().message());
+  }
+  // nested_type cannot be null at this time.
+  const google::protobuf::Type* nested_type = resolved_type.value();
+
+  io::ArrayInputStream zero_copy_stream(value.data(), value.size());
+  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,
+                                    os->render_options_);
+
+  // 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;
+}
+
+util::Status ProtoStreamObjectSource::RenderFieldMask(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  std::string combined;
+  uint32_t buffer32;
+  uint32_t paths_field_tag = 0;
+  for (uint32_t 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 != nullptr && field->number() == 1 &&
+          field->name() == "paths") {
+        paths_field_tag = tag;
+      }
+    }
+    if (paths_field_tag != tag) {
+      return util::InternalError("Invalid FieldMask, unexpected field.");
+    }
+    std::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 util::Status();
+}
+
+
+std::unordered_map<std::string, ProtoStreamObjectSource::TypeRenderer>*
+    ProtoStreamObjectSource::renderers_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag source_renderers_init_;
+
+
+void ProtoStreamObjectSource::InitRendererMap() {
+  renderers_ = new std::unordered_map<std::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_ = nullptr;
+}
+
+// static
+ProtoStreamObjectSource::TypeRenderer*
+ProtoStreamObjectSource::FindTypeRenderer(const std::string& type_url) {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(source_renderers_init_,
+                                             InitRendererMap);
+  return FindOrNull(*renderers_, type_url);
+}
+
+util::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::TYPE_MESSAGE) {
+    uint32_t 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 == nullptr) {
+      return util::InternalError(
+          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());
+
+    RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name));
+    if (type_renderer != nullptr) {
+      RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
+    } else {
+      RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
+    }
+    --recursion_depth_;
+
+    if (!stream_->ConsumedEntireMessage()) {
+      return util::InvalidArgumentError(
+          "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 util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderNonMessageField(
+    const google::protobuf::Field* field, StringPiece field_name,
+    ObjectWriter* ow) const {
+  // Temporary buffers of different types.
+  uint32_t buffer32 = 0;
+  uint64_t buffer64 = 0;
+  std::string strbuffer;
+  switch (field->kind()) {
+    case google::protobuf::Field::TYPE_BOOL: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderBool(field_name, buffer64 != 0);
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderInt32(field_name, bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderUint32(field_name, bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderInt32(field_name, bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED32: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderUint32(field_name, bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED64: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderFloat(field_name, bit_cast<float>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderDouble(field_name, bit_cast<double>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::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. Unknown enum values
+      // are printed as integers.
+      if (en != nullptr) {
+        const google::protobuf::EnumValue* enum_value =
+            FindEnumValueByNumber(*en, buffer32);
+        if (enum_value != nullptr) {
+          if (render_options_.use_ints_for_enums) {
+            ow->RenderInt32(field_name, buffer32);
+          } else if (render_options_.use_lower_camel_for_enums) {
+            ow->RenderString(field_name,
+                             EnumValueNameToLowerCamelCase(enum_value->name()));
+          } else {
+            ow->RenderString(field_name, enum_value->name());
+          }
+        } else {
+            ow->RenderInt32(field_name, buffer32);
+        }
+      } else {
+          ow->RenderInt32(field_name, buffer32);
+      }
+      break;
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      stream_->ReadVarint32(&buffer32);  // string size.
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderString(field_name, strbuffer);
+      break;
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      stream_->ReadVarint32(&buffer32);  // bytes size.
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderBytes(field_name, strbuffer);
+      break;
+    }
+    default:
+      break;
+  }
+  return util::Status();
+}
+
+// TODO(skarvaje): Fix this to avoid code duplication.
+const std::string ProtoStreamObjectSource::ReadFieldValueAsString(
+    const google::protobuf::Field& field) const {
+  std::string result;
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_BOOL: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = buffer64 != 0 ? "true" : "false";
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT32: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = StrCat(bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT64: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = StrCat(bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT32: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = StrCat(bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT64: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = StrCat(bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT32: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = StrCat(WireFormatLite::ZigZagDecode32(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT64: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = StrCat(WireFormatLite::ZigZagDecode64(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      uint32_t buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = StrCat(bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      uint64_t buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = StrCat(bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED32: {
+      uint32_t buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = StrCat(bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED64: {
+      uint64_t buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = StrCat(bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      uint32_t buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = SimpleFtoa(bit_cast<float>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      uint64_t buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = SimpleDtoa(bit_cast<double>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      uint32_t 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 != nullptr) {
+        const google::protobuf::EnumValue* enum_value =
+            FindEnumValueByNumber(*en, buffer32);
+        if (enum_value != nullptr) {
+          result = enum_value->name();
+        }
+      }
+      break;
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);  // string size.
+      stream_->ReadString(&result, buffer32);
+      break;
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      uint32_t 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());
+  return field.kind() == google::protobuf::Field::TYPE_MESSAGE &&
+         util::converter::IsMap(field, *field_type);
+}
+
+std::pair<int64_t, int32_t> ProtoStreamObjectSource::ReadSecondsAndNanos(
+    const google::protobuf::Type& type) const {
+  uint64_t seconds = 0;
+  uint32_t nanos = 0;
+  uint32_t tag = 0;
+  int64_t signed_seconds = 0;
+  int32_t signed_nanos = 0;
+
+  for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
+    const google::protobuf::Field* field = FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(stream_, tag, nullptr);
+      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_t>(seconds);
+    } else if (field->number() == 2) {
+      // read nanos
+      stream_->ReadVarint32(&nanos);
+      signed_nanos = bit_cast<int32_t>(nanos);
+    }
+  }
+  return std::pair<int64_t, int32_t>(signed_seconds, signed_nanos);
+}
+
+util::Status ProtoStreamObjectSource::IncrementRecursionDepth(
+    StringPiece type_name, StringPiece field_name) const {
+  if (++recursion_depth_ > max_recursion_depth_) {
+    return util::InvalidArgumentError(
+        StrCat("Message too deep. Max recursion depth reached for type '",
+                     type_name, "', field '", field_name, "'"));
+  }
+  return util::Status();
+}
+
+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 nullptr;
+}
+
+// TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable()
+// using tech Field.
+bool IsPackable(const google::protobuf::Field& field) {
+  return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED &&
+         FieldDescriptor::IsTypePackable(
+             static_cast<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 nullptr;
+}
+
+// TODO(skarvaje): Look into optimizing this by not doing computation on
+// double.
+const std::string FormatNanos(uint32_t nanos, bool with_trailing_zeros) {
+  if (nanos == 0) {
+    return with_trailing_zeros ? ".000" : "";
+  }
+
+  const int precision = (nanos % 1000 != 0)      ? 9
+                        : (nanos % 1000000 != 0) ? 6
+                                                 : 3;
+  std::string formatted = StringPrintf(
+      "%.*f", precision, 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..8ed2ca9
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -0,0 +1,329 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
+
+#include <cstdint>
+#include <functional>
+#include <string>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/status.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.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/hash.h>
+#include <google/protobuf/stubs/status.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+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 PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
+ public:
+
+  struct RenderOptions {
+    RenderOptions() = default;
+    RenderOptions(const RenderOptions&) = default;
+
+    // Sets whether or not to use lowerCamelCase casing for enum values. If set
+    // to false, enum values are output without any case conversions.
+    //
+    // For example, if we have an enum:
+    // enum Type {
+    //   ACTION_AND_ADVENTURE = 1;
+    // }
+    // Type type = 20;
+    //
+    // And this option is set to true. Then the rendered "type" field will have
+    // the string "actionAndAdventure".
+    // {
+    //   ...
+    //   "type": "actionAndAdventure",
+    //   ...
+    // }
+    //
+    // If set to false, the rendered "type" field will have the string
+    // "ACTION_AND_ADVENTURE".
+    // {
+    //   ...
+    //   "type": "ACTION_AND_ADVENTURE",
+    //   ...
+    // }
+    bool use_lower_camel_for_enums = false;
+
+    // Sets whether to always output enums as ints, by default this is off, and
+    // enums are rendered as strings.
+    bool use_ints_for_enums = false;
+
+    // Whether to preserve proto field names
+    bool preserve_proto_field_names = false;
+
+  };
+
+  ProtoStreamObjectSource(io::CodedInputStream* stream,
+                          TypeResolver* type_resolver,
+                          const google::protobuf::Type& type)
+      : ProtoStreamObjectSource(stream, type_resolver, type, RenderOptions()) {}
+  ProtoStreamObjectSource(io::CodedInputStream* stream,
+                          TypeResolver* type_resolver,
+                          const google::protobuf::Type& type,
+                          const RenderOptions& render_options);
+
+  ~ProtoStreamObjectSource() override;
+
+  util::Status NamedWriteTo(StringPiece name,
+                            ObjectWriter* ow) const override;
+
+  // Sets the max recursion depth of proto message to be deserialized. Proto
+  // messages over this depth will fail to be deserialized.
+  // Default value is 64.
+  void set_max_recursion_depth(int max_depth) {
+    max_recursion_depth_ = max_depth;
+  }
+
+ protected:
+  // Writes a proto2 Message to the ObjectWriter. When the given end_tag is
+  // found this method will complete, allowing it to be used for parsing both
+  // nested messages (end with 0) and nested groups (end with group end tag).
+  // The include_start_and_end parameter allows this method to be called when
+  // already inside of an object, and skip calling StartObject and EndObject.
+  virtual util::Status WriteMessage(const google::protobuf::Type& type,
+                                    StringPiece name,
+                                    const uint32_t end_tag,
+                                    bool include_start_and_end,
+                                    ObjectWriter* ow) const;
+
+  // 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.
+  virtual util::StatusOr<uint32_t> RenderList(
+      const google::protobuf::Field* field, StringPiece name,
+      uint32_t list_tag, ObjectWriter* ow) const;
+
+  // Looks up a field and verify its consistency with wire type in tag.
+  const google::protobuf::Field* FindAndVerifyField(
+      const google::protobuf::Type& type, uint32_t tag) const;
+
+  // Renders a field value to the ObjectWriter.
+  virtual util::Status RenderField(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 std::string ReadFieldValueAsString(
+      const google::protobuf::Field& field) const;
+
+
+  // Returns the input stream.
+  io::CodedInputStream* stream() const { return stream_; }
+
+ private:
+  ProtoStreamObjectSource(io::CodedInputStream* stream,
+                          const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type,
+                          const RenderOptions& render_options);
+  // Function that renders a well known type with a modified behavior.
+  typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*,
+                                       const google::protobuf::Type&,
+                                       StringPiece, ObjectWriter*);
+
+  // TODO(skarvaje): Mark these methods as non-const as they modify internal
+  // state (stream_).
+  //
+  // 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_t> RenderMap(const google::protobuf::Field* field,
+                                     StringPiece name, uint32_t 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 std::unordered_map<std::string, TypeRenderer>* renderers_;
+  static void InitRendererMap();
+  static void DeleteRendererMap();
+  static TypeRenderer* FindTypeRenderer(const std::string& type_url);
+
+  // 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;
+
+
+  // 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_t, int32_t> ReadSecondsAndNanos(
+      const google::protobuf::Type& type) const;
+
+  // Helper function to check recursion depth and increment it. It will return
+  // OkStatus() if the current depth is allowed. Otherwise an error is returned.
+  // type_name and field_name are used for error reporting.
+  util::Status IncrementRecursionDepth(StringPiece type_name,
+                                       StringPiece field_name) const;
+
+  // Input stream to read from. Ownership rests with the caller.
+  mutable 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_;
+
+
+  const RenderOptions render_options_;
+
+  // Tracks current recursion depth.
+  mutable int recursion_depth_;
+
+  // Maximum allowed recursion depth.
+  int max_recursion_depth_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..e16db78
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -0,0 +1,1165 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <memory>
+#include <sstream>
+
+#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/anys.pb.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/testdata/maps.pb.h>
+#include <google/protobuf/util/internal/testdata/proto3.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>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using ::google::protobuf::Any;
+using io::ArrayInputStream;
+using io::CodedInputStream;
+using proto_util_converter::testing::AnyM;
+using proto_util_converter::testing::AnyOut;
+using proto_util_converter::testing::Author;
+using proto_util_converter::testing::BadAuthor;
+using proto_util_converter::testing::BadNestedBook;
+using proto_util_converter::testing::Book;
+using proto_util_converter::testing::Book_Label;
+using proto_util_converter::testing::Cyclic;
+using proto_util_converter::testing::FieldMaskTest;
+using proto_util_converter::testing::MapOut;
+using proto_util_converter::testing::MapOutWireFormat;
+using proto_util_converter::testing::NestedBook;
+using proto_util_converter::testing::NestedFieldMask;
+using proto_util_converter::testing::PackedPrimitive;
+using proto_util_converter::testing::Primitive;
+using proto_util_converter::testing::Proto3Message;
+using proto_util_converter::testing::StructType;
+using proto_util_converter::testing::TimestampDuration;
+using ::testing::_;
+
+
+namespace {
+std::string GetTypeUrl(const Descriptor* descriptor) {
+  return std::string(kTypeServiceBaseUrl) + "/" + descriptor->full_name();
+}
+}  // namespace
+
+class ProtostreamObjectSourceTest
+    : public ::testing::TestWithParam<testing::TypeInfoSource> {
+ protected:
+  ProtostreamObjectSourceTest()
+      : helper_(GetParam()),
+        mock_(),
+        ow_(&mock_),
+        use_lower_camel_for_enums_(false),
+        use_ints_for_enums_(false),
+        use_preserve_proto_field_names_(false),
+        add_trailing_zeros_(false),
+        render_unknown_enum_values_(true) {
+    helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor());
+  }
+
+  ~ProtostreamObjectSourceTest() override {}
+
+  void DoTest(const Message& msg, const Descriptor* descriptor) {
+    util::Status status = ExecuteTest(msg, descriptor);
+    EXPECT_EQ(util::Status(), status);
+  }
+
+  util::Status ExecuteTest(const Message& msg, const Descriptor* descriptor) {
+    std::ostringstream oss;
+    msg.SerializePartialToOstream(&oss);
+    std::string proto = oss.str();
+    ArrayInputStream arr_stream(proto.data(), proto.size());
+    CodedInputStream in_stream(&arr_stream);
+
+    ProtoStreamObjectSource::RenderOptions render_options;
+    render_options.use_lower_camel_for_enums = use_lower_camel_for_enums_;
+    render_options.use_ints_for_enums = use_ints_for_enums_;
+    render_options.preserve_proto_field_names = use_preserve_proto_field_names_;
+    std::unique_ptr<ProtoStreamObjectSource> os(helper_.NewProtoSource(
+        &in_stream, GetTypeUrl(descriptor), render_options));
+    os->set_max_recursion_depth(64);
+    return os->WriteTo(&mock_);
+  }
+
+  void PrepareExpectingObjectWriterForRepeatedPrimitive() {
+    ow_.StartObject("")
+        ->StartList("repFix32")
+        ->RenderUint32("", bit_cast<uint32_t>(3201))
+        ->RenderUint32("", bit_cast<uint32_t>(0))
+        ->RenderUint32("", bit_cast<uint32_t>(3202))
+        ->EndList()
+        ->StartList("repU32")
+        ->RenderUint32("", bit_cast<uint32_t>(3203))
+        ->RenderUint32("", bit_cast<uint32_t>(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_t>(int64_t{6401}))
+        ->RenderUint64("", bit_cast<uint64_t>(int64_t{0}))
+        ->EndList()
+        ->StartList("repU64")
+        ->RenderUint64("", bit_cast<uint64_t>(int64_t{0}))
+        ->RenderUint64("", bit_cast<uint64_t>(int64_t{6402}))
+        ->RenderUint64("", bit_cast<uint64_t>(int64_t{6403}))
+        ->EndList()
+        ->StartList("repI64")
+        ->RenderInt64("", 6404L)
+        ->RenderInt64("", 0L)
+        ->EndList()
+        ->StartList("repSf64")
+        ->RenderInt64("", 0L)
+        ->RenderInt64("", 6405L)
+        ->RenderInt64("", 6406L)
+        ->EndList()
+        ->StartList("repS64")
+        ->RenderInt64("", 6407L)
+        ->RenderInt64("", 0L)
+        ->EndList()
+        ->StartList("repFloat")
+        ->RenderFloat("", 0.0f)
+        ->RenderFloat("", 32.1f)
+        ->RenderFloat("", 32.2f)
+        ->EndList()
+        ->StartList("repDouble")
+        ->RenderDouble("", 64.1L)
+        ->RenderDouble("", 0.0L)
+        ->EndList()
+        ->StartList("repBool")
+        ->RenderBool("", true)
+        ->RenderBool("", false)
+        ->EndList()
+        ->EndObject();
+  }
+
+  Primitive PrepareRepeatedPrimitive() {
+    Primitive primitive;
+    primitive.add_rep_fix32(3201);
+    primitive.add_rep_fix32(0);
+    primitive.add_rep_fix32(3202);
+    primitive.add_rep_u32(3203);
+    primitive.add_rep_u32(0);
+    primitive.add_rep_i32(0);
+    primitive.add_rep_i32(3204);
+    primitive.add_rep_i32(3205);
+    primitive.add_rep_sf32(3206);
+    primitive.add_rep_sf32(0);
+    primitive.add_rep_s32(0);
+    primitive.add_rep_s32(3207);
+    primitive.add_rep_s32(3208);
+    primitive.add_rep_fix64(6401L);
+    primitive.add_rep_fix64(0L);
+    primitive.add_rep_u64(0L);
+    primitive.add_rep_u64(6402L);
+    primitive.add_rep_u64(6403L);
+    primitive.add_rep_i64(6404L);
+    primitive.add_rep_i64(0L);
+    primitive.add_rep_sf64(0L);
+    primitive.add_rep_sf64(6405L);
+    primitive.add_rep_sf64(6406L);
+    primitive.add_rep_s64(6407L);
+    primitive.add_rep_s64(0L);
+    primitive.add_rep_float(0.0f);
+    primitive.add_rep_float(32.1f);
+    primitive.add_rep_float(32.2f);
+    primitive.add_rep_double(64.1L);
+    primitive.add_rep_double(0.0);
+    primitive.add_rep_bool(true);
+    primitive.add_rep_bool(false);
+
+    PrepareExpectingObjectWriterForRepeatedPrimitive();
+    return primitive;
+  }
+
+  PackedPrimitive PreparePackedPrimitive() {
+    PackedPrimitive primitive;
+    primitive.add_rep_fix32(3201);
+    primitive.add_rep_fix32(0);
+    primitive.add_rep_fix32(3202);
+    primitive.add_rep_u32(3203);
+    primitive.add_rep_u32(0);
+    primitive.add_rep_i32(0);
+    primitive.add_rep_i32(3204);
+    primitive.add_rep_i32(3205);
+    primitive.add_rep_sf32(3206);
+    primitive.add_rep_sf32(0);
+    primitive.add_rep_s32(0);
+    primitive.add_rep_s32(3207);
+    primitive.add_rep_s32(3208);
+    primitive.add_rep_fix64(6401L);
+    primitive.add_rep_fix64(0L);
+    primitive.add_rep_u64(0L);
+    primitive.add_rep_u64(6402L);
+    primitive.add_rep_u64(6403L);
+    primitive.add_rep_i64(6404L);
+    primitive.add_rep_i64(0L);
+    primitive.add_rep_sf64(0L);
+    primitive.add_rep_sf64(6405L);
+    primitive.add_rep_sf64(6406L);
+    primitive.add_rep_s64(6407L);
+    primitive.add_rep_s64(0L);
+    primitive.add_rep_float(0.0f);
+    primitive.add_rep_float(32.1f);
+    primitive.add_rep_float(32.2f);
+    primitive.add_rep_double(64.1L);
+    primitive.add_rep_double(0.0);
+    primitive.add_rep_bool(true);
+    primitive.add_rep_bool(false);
+
+    PrepareExpectingObjectWriterForRepeatedPrimitive();
+    return primitive;
+  }
+
+  void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; }
+
+  void UseIntsForEnums() { use_ints_for_enums_ = true; }
+
+  void UsePreserveProtoFieldNames() { use_preserve_proto_field_names_ = true; }
+
+  void AddTrailingZeros() { add_trailing_zeros_ = true; }
+
+  void SetRenderUnknownEnumValues(bool value) {
+    render_unknown_enum_values_ = value;
+  }
+
+  testing::TypeInfoTestHelper helper_;
+
+  ::testing::NiceMock<MockObjectWriter> mock_;
+  ExpectingObjectWriter ow_;
+  bool use_lower_camel_for_enums_;
+  bool use_ints_for_enums_;
+  bool use_preserve_proto_field_names_;
+  bool add_trailing_zeros_;
+  bool render_unknown_enum_values_;
+};
+
+INSTANTIATE_TEST_SUITE_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_t>(3201))
+      ->RenderUint32("u32", bit_cast<uint32_t>(3202))
+      ->RenderInt32("i32", 3203)
+      ->RenderInt32("sf32", 3204)
+      ->RenderInt32("s32", 3205)
+      ->RenderUint64("fix64", bit_cast<uint64_t>(int64_t{6401}))
+      ->RenderUint64("u64", bit_cast<uint64_t>(int64_t{6402}))
+      ->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_t>('j'))
+      ->RenderUint64("", static_cast<uint64_t>('o'))
+      ->RenderUint64("", static_cast<uint64_t>('h'))
+      ->RenderUint64("", static_cast<uint64_t>('n'))
+      ->EndList()
+      ->RenderString("pseudonym", "phil")
+      ->RenderString("pseudonym", "bob")
+      ->EndObject();
+  // Protostream created with Author, but parsed with BadAuthor.
+  DoTest(author, BadAuthor::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) {
+  Book* book = new Book();
+  book->set_length(250);
+  book->set_published(2014L);
+  NestedBook nested;
+  nested.set_allocated_book(book);
+
+  ow_.StartObject("")
+      ->StartList("book")
+      ->RenderUint32("", 24)  // tag for field length (3 << 3)
+      ->RenderUint32("", 250)
+      ->RenderUint32("", 32)  // tag for field published (4 << 3)
+      ->RenderUint32("", 2014)
+      ->EndList()
+      ->EndObject();
+  // Protostream created with NestedBook, but parsed with BadNestedBook.
+  DoTest(nested, BadNestedBook::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) {
+  BadNestedBook nested;
+  nested.add_book(1);
+  nested.add_book(2);
+  nested.add_book(3);
+  nested.add_book(4);
+  nested.add_book(5);
+  nested.add_book(6);
+  nested.add_book(7);
+
+  ow_.StartObject("")->StartObject("book")->EndObject()->EndObject();
+  // Protostream created with BadNestedBook, but parsed with NestedBook.
+  DoTest(nested, NestedBook::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest,
+       LongRepeatedListDoesNotBreakIntoMultipleJsonLists) {
+  Book book;
+
+  int repeat = 10000;
+  for (int i = 0; i < repeat; ++i) {
+    Book_Label* label = book.add_labels();
+    label->set_key(StrCat("i", i));
+    label->set_value(StrCat("v", i));
+  }
+
+  // Make sure StartList and EndList are called exactly once (see b/18227499 for
+  // problems when this doesn't happen)
+  EXPECT_CALL(mock_, StartList(_)).Times(1);
+  EXPECT_CALL(mock_, EndList()).Times(1);
+
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputMacroCase) {
+  Book book;
+  book.set_type(Book::ACTION_AND_ADVENTURE);
+
+  UseLowerCamelForEnums();
+
+  ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputSnakeCase) {
+  Book book;
+  book.set_type(Book::arts_and_photography);
+
+  UseLowerCamelForEnums();
+
+  ow_.StartObject("")->RenderString("type", "artsAndPhotography")->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputWithNumber) {
+  Book book;
+  book.set_type(Book::I18N_Tech);
+
+  UseLowerCamelForEnums();
+
+  ow_.StartObject("")->RenderString("type", "i18nTech")->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) {
+  Book book;
+  book.set_type(Book::ACTION_AND_ADVENTURE);
+  ow_.StartObject("")
+      ->RenderString("type", "ACTION_AND_ADVENTURE")
+      ->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) {
+  Book book;
+  book.set_type(Book::ACTION_AND_ADVENTURE);
+
+  UseIntsForEnums();
+
+  ow_.StartObject("")->RenderInt32("type", 3)->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, UsePreserveProtoFieldNames) {
+  Book book;
+  book.set_snake_field("foo");
+
+  UsePreserveProtoFieldNames();
+
+  ow_.StartObject("")->RenderString("snake_field", "foo")->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest,
+       UnknownEnumAreDroppedWhenRenderUnknownEnumValuesIsUnset) {
+  Proto3Message message;
+  message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));
+
+  SetRenderUnknownEnumValues(false);
+
+  // Unknown enum values are not output.
+  ow_.StartObject("")->EndObject();
+  DoTest(message, Proto3Message::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest,
+       UnknownEnumAreOutputWhenRenderUnknownEnumValuesIsSet) {
+  Proto3Message message;
+  message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));
+
+  SetRenderUnknownEnumValues(true);
+
+  // Unknown enum values are output.
+  ow_.StartObject("")->RenderInt32("enumValue", 1234)->EndObject();
+  DoTest(message, Proto3Message::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) {
+  Cyclic cyclic;
+  cyclic.set_m_int(123);
+
+  Book* book = cyclic.mutable_m_book();
+  book->set_title("book title");
+  Cyclic* current = cyclic.mutable_m_cyclic();
+  Author* current_author = cyclic.add_m_author();
+  for (int i = 0; i < 63; ++i) {
+    Author* next = current_author->add_friend_();
+    next->set_id(i);
+    next->set_name(StrCat("author_name_", i));
+    next->set_alive(true);
+    current_author = next;
+  }
+
+  // Recursive message with depth (65) > max (max is 64).
+  for (int i = 0; i < 64; ++i) {
+    Cyclic* next = current->mutable_m_cyclic();
+    next->set_m_str(StrCat("count_", i));
+    current = next;
+  }
+
+  util::Status status = ExecuteTest(cyclic, Cyclic::descriptor());
+  EXPECT_TRUE(util::IsInvalidArgument(status));
+}
+
+class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceMapsTest() {
+    helper_.ResetTypeInfo(MapOut::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceMapsTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
+
+// Tests JSON map.
+//
+// This is the example expected output.
+// {
+//   "map1": {
+//     "key1": {
+//       "foo": "foovalue"
+//     },
+//     "key2": {
+//       "foo": "barvalue"
+//     }
+//   },
+//   "map2": {
+//     "nestedself": {
+//       "map1": {
+//         "nested_key1": {
+//           "foo": "nested_foo"
+//         }
+//       },
+//       "bar": "nested_bar_string"
+//     }
+//   },
+//   "map3": {
+//     "111": "one one one"
+//   },
+//   "bar": "top bar"
+// }
+TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) {
+  MapOut out;
+  (*out.mutable_map1())["key1"].set_foo("foovalue");
+  (*out.mutable_map1())["key2"].set_foo("barvalue");
+
+  MapOut* nested_value = &(*out.mutable_map2())["nestedself"];
+  (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo");
+  nested_value->set_bar("nested_bar_string");
+
+  (*out.mutable_map3())[111] = "one one one";
+
+  out.set_bar("top bar");
+
+  ow_.StartObject("")
+      ->StartObject("map1")
+      ->StartObject("key1")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->StartObject("key2")
+      ->RenderString("foo", "barvalue")
+      ->EndObject()
+      ->StartObject("map2")
+      ->StartObject("nestedself")
+      ->StartObject("map1")
+      ->StartObject("nested_key1")
+      ->RenderString("foo", "nested_foo")
+      ->EndObject()
+      ->EndObject()
+      ->RenderString("bar", "nested_bar_string")
+      ->EndObject()
+      ->EndObject()
+      ->StartObject("map3")
+      ->RenderString("111", "one one one")
+      ->EndObject()
+      ->EndObject()
+      ->RenderString("bar", "top bar")
+      ->EndObject();
+
+  DoTest(out, MapOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) {
+  // MapOutWireFormat has the same wire representation with MapOut but uses
+  // repeated message fields to represent map fields so we can intentionally
+  // leave out the key field or the value field of a map entry.
+  MapOutWireFormat out;
+  // Create some map entries without keys. They will be rendered with the
+  // default values ("" for strings, "0" for integers, etc.).
+  // {
+  //   "map1": {
+  //     "": {
+  //       "foo": "foovalue"
+  //     }
+  //   },
+  //   "map2": {
+  //     "": {
+  //       "map1": {
+  //         "nested_key1": {
+  //           "foo": "nested_foo"
+  //         }
+  //       }
+  //     }
+  //   },
+  //   "map3": {
+  //     "0": "one one one"
+  //   },
+  //   "map4": {
+  //     "false": "bool"
+  //   }
+  // }
+  out.add_map1()->mutable_value()->set_foo("foovalue");
+  MapOut* nested = out.add_map2()->mutable_value();
+  (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo");
+  out.add_map3()->set_value("one one one");
+  out.add_map4()->set_value("bool");
+
+  ow_.StartObject("")
+      ->StartObject("map1")
+      ->StartObject("")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->StartObject("map2")
+      ->StartObject("")
+      ->StartObject("map1")
+      ->StartObject("nested_key1")
+      ->RenderString("foo", "nested_foo")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->StartObject("map3")
+      ->RenderString("0", "one one one")
+      ->EndObject()
+      ->StartObject("map4")
+      ->RenderString("false", "bool")
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, MapOut::descriptor());
+}
+
+class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceAnysTest() {
+    helper_.ResetTypeInfo({AnyOut::descriptor(), Book::descriptor(),
+                           google::protobuf::Any::descriptor()});
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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.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/proto_util_converter.testing.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, LowerCamelEnumOutputSnakeCase) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  Book book;
+  book.set_type(Book::arts_and_photography);
+  any->PackFrom(book);
+
+  UseLowerCamelForEnums();
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type",
+                     "type.googleapis.com/proto_util_converter.testing.Book")
+      ->RenderString("type", "artsAndPhotography")
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, UseIntsForEnumsTest) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  Book book;
+  book.set_type(Book::ACTION_AND_ADVENTURE);
+  any->PackFrom(book);
+
+  UseIntsForEnums();
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type",
+                     "type.googleapis.com/proto_util_converter.testing.Book")
+      ->RenderInt32("type", 3)
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, UsePreserveProtoFieldNames) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  Book book;
+  book.set_snake_field("foo");
+  any->PackFrom(book);
+
+  UsePreserveProtoFieldNames();
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type",
+                     "type.googleapis.com/proto_util_converter.testing.Book")
+      ->RenderString("snake_field", "foo")
+      ->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/proto_util_converter.testing.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/proto_util_converter.testing.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/proto_util_converter.testing.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/proto_util_converter.testing.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("");
+
+  util::Status status = ExecuteTest(out, AnyOut::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+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("");
+
+  util::Status status = ExecuteTest(out, AnyOut::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+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("");
+
+  util::Status status = ExecuteTest(out, AnyOut::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceStructTest() {
+    helper_.ResetTypeInfo(StructType::descriptor(),
+                          google::protobuf::Struct::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceFieldMaskTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) {
+  FieldMaskTest out;
+  out.set_id("1");
+  out.mutable_single_mask()->add_paths("path1");
+  out.mutable_single_mask()->add_paths("snake_case_path2");
+  ::google::protobuf::FieldMask* mask = out.add_repeated_mask();
+  mask->add_paths("path3");
+  mask = out.add_repeated_mask();
+  mask->add_paths("snake_case_path4");
+  mask->add_paths("path5");
+  NestedFieldMask* nested = out.add_nested_mask();
+  nested->set_data("data");
+  nested->mutable_single_mask()->add_paths("nested.path1");
+  nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2");
+  mask = nested->add_repeated_mask();
+  mask->add_paths("nested_field.path3");
+  mask->add_paths("nested.snake_case_path4");
+  mask = nested->add_repeated_mask();
+  mask->add_paths("nested.path5");
+  mask = nested->add_repeated_mask();
+  mask->add_paths(
+      "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case."
+      "map_field[\"map_key_sho\\\"uld_be_ignored\"]");
+
+  ow_.StartObject("")
+      ->RenderString("id", "1")
+      ->RenderString("singleMask", "path1,snakeCasePath2")
+      ->StartList("repeatedMask")
+      ->RenderString("", "path3")
+      ->RenderString("", "snakeCasePath4,path5")
+      ->EndList()
+      ->StartList("nestedMask")
+      ->StartObject("")
+      ->RenderString("data", "data")
+      ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2")
+      ->StartList("repeatedMask")
+      ->RenderString("", "nestedField.path3,nested.snakeCasePath4")
+      ->RenderString("", "nested.path5")
+      ->RenderString("",
+                     "snakeCase.mapField[\"map_key_should_be_ignored\"]."
+                     "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_"
+                     "ignored\"]")
+      ->EndList()
+      ->EndObject()
+      ->EndList()
+      ->EndObject();
+
+  DoTest(out, FieldMaskTest::descriptor());
+}
+
+class ProtostreamObjectSourceTimestampTest
+    : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceTimestampTest() {
+    helper_.ResetTypeInfo(TimestampDuration::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceTimestampTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) {
+  TimestampDuration out;
+  google::protobuf::Timestamp* ts = out.mutable_ts();
+  // Min allowed seconds - 1
+  ts->set_seconds(kTimestampMinSeconds - 1);
+  ow_.StartObject("");
+
+  util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) {
+  TimestampDuration out;
+  google::protobuf::Timestamp* ts = out.mutable_ts();
+  // Max allowed seconds + 1
+  ts->set_seconds(kTimestampMaxSeconds + 1);
+  ow_.StartObject("");
+
+  util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) {
+  TimestampDuration out;
+  google::protobuf::Duration* dur = out.mutable_dur();
+  // Min allowed seconds - 1
+  dur->set_seconds(kDurationMinSeconds - 1);
+  ow_.StartObject("");
+
+  util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) {
+  TimestampDuration out;
+  google::protobuf::Duration* dur = out.mutable_dur();
+  // Min allowed seconds + 1
+  dur->set_seconds(kDurationMaxSeconds + 1);
+  ow_.StartObject("");
+
+  util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_TRUE(util::IsInternal(status));
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, TimestampDurationDefaultValue) {
+  TimestampDuration out;
+  out.mutable_ts()->set_seconds(0);
+  out.mutable_dur()->set_seconds(0);
+
+  ow_.StartObject("")
+      ->RenderString("ts", "1970-01-01T00:00:00Z")
+      ->RenderString("dur", "0s")
+      ->EndObject();
+
+  DoTest(out, TimestampDuration::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..ecb219e
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -0,0 +1,1401 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <functional>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using util::Status;
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
+using std::placeholders::_1;
+
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    TypeResolver* type_resolver, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener,
+    const ProtoStreamObjectWriter::Options& options)
+    : ProtoWriter(type_resolver, type, output, listener),
+      master_type_(type),
+      current_(nullptr),
+      options_(options) {
+  set_ignore_unknown_fields(options_.ignore_unknown_fields);
+  set_ignore_unknown_enum_values(options_.ignore_unknown_enum_values);
+  set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums);
+  set_case_insensitive_enum_parsing(options_.case_insensitive_enum_parsing);
+  set_use_json_name_in_missing_fields(options.use_json_name_in_missing_fields);
+}
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    const TypeInfo* typeinfo, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener,
+    const ProtoStreamObjectWriter::Options& options)
+    : ProtoWriter(typeinfo, type, output, listener),
+      master_type_(type),
+      current_(nullptr),
+      options_(options) {
+  set_ignore_unknown_fields(options_.ignore_unknown_fields);
+  set_use_lower_camel_for_enums(options.use_lower_camel_for_enums);
+  set_case_insensitive_enum_parsing(options_.case_insensitive_enum_parsing);
+  set_use_json_name_in_missing_fields(options.use_json_name_in_missing_fields);
+}
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    const TypeInfo* typeinfo, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener)
+    : ProtoWriter(typeinfo, type, output, listener),
+      master_type_(type),
+      current_(nullptr),
+      options_(ProtoStreamObjectWriter::Options::Defaults()) {}
+
+ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
+  if (current_ == nullptr) 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().
+  std::unique_ptr<BaseElement> element(
+      static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
+  while (element != nullptr) {
+    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 != std::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_t* 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_t i_nanos = 0;
+  // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
+  // "0." + s_nanos.ToString() seconds. An int32_t 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, &i_nanos)) {
+    return util::InvalidArgumentError(parse_failure_message);
+  }
+  if (i_nanos > kNanosPerSecond || i_nanos < 0) {
+    return util::InvalidArgumentError(exceeded_limit_message);
+  }
+  // s_nanos should only have digits. No whitespace.
+  if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
+    return util::InvalidArgumentError(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_t scale = num_leading_zeros + s_nanos.size();
+    // 'conversion' converts i_nanos into nanoseconds.
+    // conversion = kNanosPerSecond / static_cast<int32_t>(std::pow(10, scale))
+    // For efficiency, we precompute the conversion factor.
+    int32_t 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 util::InvalidArgumentError(exceeded_limit_message);
+    }
+    *nanos = i_nanos * conversion;
+  }
+
+  return Status();
+}
+
+}  // namespace
+
+ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
+    : parent_(parent),
+      ow_(),
+      invalid_(false),
+      data_(),
+      output_(&data_),
+      depth_(0),
+      is_well_known_type_(false),
+      well_known_type_render_(nullptr) {}
+
+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, which happens when we have data before the "@type"
+  // field.
+  if (ow_ == nullptr) {
+    // Save data before the "@type" field for later replay.
+    uninterpreted_events_.push_back(Event(Event::START_OBJECT, name));
+  } else if (is_well_known_type_ && depth_ == 1) {
+    // For well-known types, the only other field besides "@type" should be a
+    // "value" field.
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    ow_->StartObject("");
+  } else {
+    // Forward the call to the child writer if:
+    //   1. the type is not a well-known type.
+    //   2. or, we are in a nested Any, Struct, or Value object.
+    ow_->StartObject(name);
+  }
+}
+
+bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
+  --depth_;
+  if (ow_ == nullptr) {
+    if (depth_ >= 0) {
+      // Save data before the "@type" field for later replay.
+      uninterpreted_events_.push_back(Event(Event::END_OBJECT));
+    }
+  } else if (depth_ >= 0 || !is_well_known_type_) {
+    // As long as depth_ >= 0, we know we haven't reached the end of Any.
+    // Propagate these EndObject() calls to the contained ow_. For regular
+    // message types, we propagate the end of Any as well.
+    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_;
+  if (ow_ == nullptr) {
+    // Save data before the "@type" field for later replay.
+    uninterpreted_events_.push_back(Event(Event::START_LIST, name));
+  } else if (is_well_known_type_ && depth_ == 1) {
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    ow_->StartList("");
+  } else {
+    ow_->StartList(name);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::EndList() {
+  --depth_;
+  if (depth_ < 0) {
+    GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
+    depth_ = 0;
+  }
+  if (ow_ == nullptr) {
+    // Save data before the "@type" field for later replay.
+    uninterpreted_events_.push_back(Event(Event::END_LIST));
+  } else {
+    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_ == nullptr && name == "@type") {
+    StartAny(value);
+  } else if (ow_ == nullptr) {
+    // Save data before the "@type" field.
+    uninterpreted_events_.push_back(Event(name, value));
+  } else if (depth_ == 0 && is_well_known_type_) {
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    if (well_known_type_render_ == nullptr) {
+      // Only Any and Struct don't have a special type render but both of
+      // them expect a JSON object (i.e., a StartObject() call).
+      if (value.type() != DataPiece::TYPE_NULL && !invalid_) {
+        parent_->InvalidValue("Any", "Expect a JSON object.");
+        invalid_ = true;
+      }
+    } else {
+      ow_->ProtoWriter::StartObject("");
+      Status status = (*well_known_type_render_)(ow_.get(), value);
+      if (!status.ok()) ow_->InvalidValue("Any", status.message());
+      ow_->ProtoWriter::EndObject();
+    }
+  } else {
+    ow_->RenderDataPiece(name, value);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
+  // Figure out the type url. This is a copy-paste from WriteString but we also
+  // need the value, so we can't just call through to that.
+  if (value.type() == DataPiece::TYPE_STRING) {
+    type_url_ = std::string(value.str());
+  } else {
+    util::StatusOr<std::string> s = value.ToString();
+    if (!s.ok()) {
+      parent_->InvalidValue("String", s.status().message());
+      invalid_ = true;
+      return;
+    }
+    type_url_ = s.value();
+  }
+  // Resolve the type url, and report an error if we failed to resolve it.
+  util::StatusOr<const google::protobuf::Type*> resolved_type =
+      parent_->typeinfo()->ResolveTypeUrl(type_url_);
+  if (!resolved_type.ok()) {
+    parent_->InvalidValue("Any", resolved_type.status().message());
+    invalid_ = true;
+    return;
+  }
+  // At this point, type is never null.
+  const google::protobuf::Type* type = resolved_type.value();
+
+  well_known_type_render_ = FindTypeRenderer(type_url_);
+  if (well_known_type_render_ != nullptr ||
+      // Explicitly list Any and Struct here because they don't have a
+      // custom renderer.
+      type->name() == kAnyType || type->name() == kStructType) {
+    is_well_known_type_ = true;
+  }
+
+  // Create our object writer and initialize it with the first StartObject
+  // call.
+  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
+                                        parent_->listener(),
+                                        parent_->options_));
+
+  // Don't call StartObject() for well-known types yet. Depending on the
+  // type of actual data, we may not need to call StartObject(). For
+  // example:
+  // {
+  //   "@type": "type.googleapis.com/google.protobuf.Value",
+  //   "value": [1, 2, 3],
+  // }
+  // With the above JSON representation, we will only call StartList() on the
+  // contained ow_.
+  if (!is_well_known_type_) {
+    ow_->StartObject("");
+  }
+
+  // Now we know the proto type and can interpret all data fields we gathered
+  // before the "@type" field.
+  for (int i = 0; i < uninterpreted_events_.size(); ++i) {
+    uninterpreted_events_[i].Replay(this);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
+  if (ow_ == nullptr) {
+    if (uninterpreted_events_.empty()) {
+      // We never got any content, so just return immediately, which is
+      // equivalent to writing an empty Any.
+      return;
+    } else {
+      // There are uninterpreted data, but we never got a "@type" field.
+      if (!invalid_) {
+        parent_->InvalidValue("Any",
+                              StrCat("Missing @type for any field in ",
+                                           parent_->master_type_.name()));
+        invalid_ = true;
+      }
+      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());
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::Event::Replay(
+    AnyWriter* writer) const {
+  switch (type_) {
+    case START_OBJECT:
+      writer->StartObject(name_);
+      break;
+    case END_OBJECT:
+      writer->EndObject();
+      break;
+    case START_LIST:
+      writer->StartList(name_);
+      break;
+    case END_LIST:
+      writer->EndList();
+      break;
+    case RENDER_DATA_PIECE:
+      writer->RenderDataPiece(name_, value_);
+      break;
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() {
+  // DataPiece only contains a string reference. To make sure the referenced
+  // string value stays valid, we make a copy of the string value and update
+  // DataPiece to reference our own copy.
+  if (value_.type() == DataPiece::TYPE_STRING) {
+    StrAppend(&value_storage_, value_.str());
+    value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding());
+  } else if (value_.type() == DataPiece::TYPE_BYTES) {
+    value_storage_ = value_.ToBytes().value();
+    value_ =
+        DataPiece(value_storage_, true, value_.use_strict_base64_decoding());
+  }
+}
+
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
+    : BaseElement(nullptr),
+      ow_(enclosing),
+      any_(),
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type_ == ANY) {
+    any_.reset(new AnyWriter(ow_));
+  }
+  if (item_type == MAP) {
+    map_keys_.reset(new std::unordered_set<std::string>);
+  }
+}
+
+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_));
+  }
+  if (item_type == MAP) {
+    map_keys_.reset(new std::unordered_set<std::string>);
+  }
+}
+
+bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
+    StringPiece map_key) {
+  return InsertIfNotPresent(map_keys_.get(), std::string(map_key));
+}
+
+
+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_ == nullptr) {
+    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/protocolbuffers/protobuf/blob/main/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/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto
+      // Also start the map field "fields" within the struct.
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      InvalidValue(kStructListValueType,
+                   "Cannot start root message with ListValue.");
+    }
+
+    return this;
+  }
+
+  // Send all ANY events to AnyWriter.
+  if (current_->IsAny()) {
+    current_->any()->StartObject(name);
+    return this;
+  }
+
+  // If we are within a map, we render name as keys and send StartObject to the
+  // value field.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Map is a repeated field of message type with a "key" and a "value" field.
+    // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
+    // message MapFieldEntry {
+    //   key_type key = 1;
+    //   value_type value = 2;
+    // }
+    //
+    // repeated MapFieldEntry map_field = N;
+    //
+    // That means, we render the following element within a list (hence no
+    // name):
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    Push("value", IsAny(*Lookup("value")) ? Item::ANY : 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() != nullptr && 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() != nullptr && 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 == nullptr) return this;
+
+  // Legacy JSON map is a list of key value pairs. Starts a map entry object.
+  if (options_.use_legacy_json_map_format && name.empty()) {
+    Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
+    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;
+  }
+
+  if (options_.disable_implicit_message_list) {
+    // If the incoming object is repeated, the top-level object on stack should
+    // be list. Report an error otherwise.
+    if (IsRepeated(*field) && !current_->is_list()) {
+      IncrementInvalidDepth();
+
+      if (!options_.suppress_implicit_message_list_error) {
+        InvalidValue(
+            field->name(),
+            "Starting an object in a repeated field but the parent object "
+            "is not a list");
+      }
+      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 (field->kind() != google::protobuf::Field::TYPE_GROUP &&
+      field->kind() != google::protobuf::Field::TYPE_MESSAGE) {
+    IncrementInvalidDepth();
+    if (!options_.suppress_object_to_scalar_error) {
+      InvalidValue(field->name(), "Starting an object on a scalar field");
+    }
+
+    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_ == nullptr) 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_ == nullptr) {
+    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/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto
+      //
+      // Render
+      // "<name>": {
+      //   "list_value": {
+      //     "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("list_value", Item::MESSAGE, true, false);
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      // We got a StartList with google.protobuf.ListValue master type. This
+      // means we have to start the "values" within google.protobuf.ListValue.
+      //
+      // Render
+      // "<name>": {
+      //   "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    // Send the event to ProtoWriter so proper errors can be reported.
+    //
+    // Render a regular list:
+    // "<name>": [
+    ProtoWriter::StartList(name);
+    current_.reset(new Item(this, Item::MESSAGE, false, true));
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->StartList(name);
+    return this;
+  }
+
+  // If the top of stack is a map, we are starting a list value within a map.
+  // Since map does not allow repeated values, this can only happen when the map
+  // value is of a special type that renders a list in JSON.  These can be one
+  // of 3 cases:
+  // i. We are rendering a list value within google.protobuf.Struct
+  // ii. We are rendering a list value within google.protobuf.Value
+  // iii. We are rendering a list value with type google.protobuf.ListValue.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Start the repeated map entry object.
+    // Render
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    Push("value", Item::MESSAGE, true, false);
+
+    // Make sure we are valid after pushing all above items.
+    if (invalid_depth() > 0) return this;
+
+    // case i and ii above. Start "list_value" field within g.p.Value
+    if (element() != nullptr && element()->parent_field() != nullptr) {
+      // 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() != nullptr && element()->parent_field() != nullptr) {
+      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 == nullptr) {
+    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)) {
+    if (options_.use_legacy_json_map_format) {
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+    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_ == nullptr) return this;
+
+  if (current_->IsAny()) {
+    current_->any()->EndList();
+    return this;
+  }
+
+  Pop();
+  return this;
+}
+
+Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
+                                                  const DataPiece& data) {
+  std::string struct_field_name;
+  switch (data.type()) {
+    case DataPiece::TYPE_INT32: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<int32_t> int_value = data.ToInt32();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_UINT32: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<uint32_t> int_value = data.ToUint32();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_INT64: {
+      // If the option to treat integers as strings is set, then render them as
+      // strings. Otherwise, fallback to rendering them as double.
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<int64_t> int_value = data.ToInt64();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value", DataPiece(StrCat(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_UINT64: {
+      // If the option to treat integers as strings is set, then render them as
+      // strings. Otherwise, fallback to rendering them as double.
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<uint64_t> int_value = data.ToUint64();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value", DataPiece(StrCat(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_FLOAT: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<float> float_value = data.ToFloat();
+        if (float_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(float_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_DOUBLE: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<double> double_value = data.ToDouble();
+        if (double_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(double_value.value()), true));
+          return Status();
+        }
+      }
+      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 util::InvalidArgumentError(
+          "Invalid struct data type. Only number, string, boolean or  null "
+          "values are supported.");
+    }
+  }
+  ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
+  return Status();
+}
+
+Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
+                                                const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid data type for timestamp, value is ",
+                     data.ValueAsStringOrDefault("")));
+  }
+
+  StringPiece value(data.str());
+
+  int64_t seconds;
+  int32_t nanos;
+  if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
+                                               &nanos)) {
+    return util::InvalidArgumentError(StrCat("Invalid time format: ", value));
+  }
+
+
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
+  return Status();
+}
+
+static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
+                                              StringPiece path) {
+  ow->ProtoWriter::RenderDataPiece(
+      "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
+  return Status();
+}
+
+Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
+                                                const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return util::InvalidArgumentError(
+        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.
+  return DecodeCompactFieldMaskPaths(data.str(),
+                                     std::bind(&RenderOneFieldPath, ow, _1));
+}
+
+Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
+                                               const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid data type for duration, value is ",
+                     data.ValueAsStringOrDefault("")));
+  }
+
+  StringPiece value(data.str());
+
+  if (!HasSuffixString(value, "s")) {
+    return util::InvalidArgumentError(
+        "Illegal duration format; duration must end with 's'");
+  }
+  value = value.substr(0, value.size() - 1);
+  int sign = 1;
+  if (HasPrefixString(value, "-")) {
+    sign = -1;
+    value = value.substr(1);
+  }
+
+  StringPiece s_secs, s_nanos;
+  SplitSecondsAndNanos(value, &s_secs, &s_nanos);
+  uint64_t unsigned_seconds;
+  if (!safe_strtou64(s_secs, &unsigned_seconds)) {
+    return util::InvalidArgumentError(
+        "Invalid duration format, failed to parse seconds");
+  }
+
+  int32_t 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_t seconds = sign * unsigned_seconds;
+  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
+      nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    return util::InvalidArgumentError("Duration value exceeds limits");
+  }
+
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
+  return Status();
+}
+
+Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
+                                                  const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  ow->ProtoWriter::RenderDataPiece("value", data);
+  return Status();
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& data) {
+  Status status;
+  if (invalid_depth() > 0) return this;
+
+  if (current_ == nullptr) {
+    const TypeRenderer* type_renderer =
+        FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
+    if (type_renderer == nullptr) {
+      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.message()));
+    }
+    ProtoWriter::EndObject();
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->RenderDataPiece(name, data);
+    return this;
+  }
+
+  const google::protobuf::Field* field = nullptr;
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) return this;
+
+    field = Lookup("value");
+    if (field == nullptr) {
+      GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
+      return this;
+    }
+
+    if (options_.ignore_null_value_map_entry) {
+      // If we are rendering explicit null values and the backend proto field is
+      // not of the google.protobuf.NullType type, interpret null as absence.
+      if (data.type() == DataPiece::TYPE_NULL &&
+          field->type_url() != kStructNullValueTypeUrl) {
+        return this;
+      }
+    }
+
+    // Render an item in repeated map list.
+    // { "key": "<name>", "value":
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+
+    const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+    if (type_renderer != nullptr) {
+      // 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.message()));
+      }
+      Pop();
+      return this;
+    }
+
+    // If we are rendering explicit null values and the backend proto field is
+    // not of the google.protobuf.NullType type, we do nothing.
+    if (data.type() == DataPiece::TYPE_NULL &&
+        field->type_url() != kStructNullValueTypeUrl) {
+      Pop();
+      return this;
+    }
+
+    // Render the map value as a primitive type.
+    ProtoWriter::RenderDataPiece("value", data);
+    Pop();
+    return this;
+  }
+
+  field = Lookup(name);
+  if (field == nullptr) 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 != nullptr) {
+    // Pass through null value only for google.protobuf.Value. For other
+    // types we ignore null value just like for regular field types.
+    if (data.type() != DataPiece::TYPE_NULL ||
+        field->type_url() == kStructValueTypeUrl) {
+      Push(name, Item::MESSAGE, false, false);
+      status = (*type_renderer)(this, data);
+      if (!status.ok()) {
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.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;
+  }
+
+  if (IsRepeated(*field) && !current_->is_list()) {
+    if (options_.disable_implicit_scalar_list) {
+      if (!options_.suppress_implicit_scalar_list_error) {
+        InvalidValue(
+            field->name(),
+            "Starting an primitive in a repeated field but the parent field "
+            "is not a list");
+      }
+
+      return this;
+    }
+  }
+
+  ProtoWriter::RenderDataPiece(name, data);
+  return this;
+}
+
+// Map of functions that are responsible for rendering well known type
+// represented by the key.
+std::unordered_map<std::string, ProtoStreamObjectWriter::TypeRenderer>*
+    ProtoStreamObjectWriter::renderers_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag writer_renderers_init_;
+
+void ProtoStreamObjectWriter::InitRendererMap() {
+  renderers_ = new std::unordered_map<std::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_ = nullptr;
+}
+
+ProtoStreamObjectWriter::TypeRenderer*
+ProtoStreamObjectWriter::FindTypeRenderer(const std::string& type_url) {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(writer_renderers_init_,
+                                             InitRendererMap);
+  return FindOrNull(*renderers_, type_url);
+}
+
+bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
+  if (current_ == nullptr) 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_ != nullptr && current_->is_placeholder()) {
+    PopOneElement();
+  }
+  if (current_ != nullptr) {
+    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::TYPE_MESSAGE ||
+      field.cardinality() != google::protobuf::Field::CARDINALITY_REPEATED) {
+    return false;
+  }
+  const google::protobuf::Type* field_type =
+      typeinfo()->GetTypeByTypeUrl(field.type_url());
+
+  return converter::IsMap(field, *field_type);
+}
+
+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..ce2517f
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
+
+#include <deque>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.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/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.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/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/hash.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+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 PROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
+ public:
+  // Options that control ProtoStreamObjectWriter class's behavior.
+  struct Options {
+    // Treats numeric inputs in google.protobuf.Struct as strings. Normally,
+    // numeric values are returned in double field "number_value" of
+    // google.protobuf.Struct. However, this can cause precision loss for
+    // int64/uint64/double inputs. This option is provided for cases that want
+    // to preserve number precision.
+    //
+    // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double
+    // as well.
+    bool struct_integers_as_strings;
+
+    // Not treat unknown fields as an error. If there is an unknown fields,
+    // just ignore it and continue to process the rest. Note that this doesn't
+    // apply to unknown enum values.
+    bool ignore_unknown_fields;
+
+    // Ignore unknown enum values.
+    bool ignore_unknown_enum_values;
+
+    // If true, check if enum name in camel case or without underscore matches
+    // the field name.
+    bool use_lower_camel_for_enums;
+
+    // If true, check if enum name in UPPER_CASE matches the field name.
+    bool case_insensitive_enum_parsing;
+
+    // If true, skips rendering the map entry if map value is null unless the
+    // value type is google.protobuf.NullType.
+    bool ignore_null_value_map_entry;
+
+    // If true, accepts repeated key/value pair for a map proto field.
+    bool use_legacy_json_map_format;
+
+    // If true, disable implicitly creating message list.
+    bool disable_implicit_message_list;
+
+    // If true, suppress the error of implicitly creating message list when it
+    // is disabled.
+    bool suppress_implicit_message_list_error;
+
+    // If true, disable implicitly creating scalar list.
+    bool disable_implicit_scalar_list;
+
+    // If true, suppress the error of implicitly creating scalar list when it
+    // is disabled.
+    bool suppress_implicit_scalar_list_error;
+
+    // If true, suppress the error of rendering scalar field if the source is an
+    // object.
+    bool suppress_object_to_scalar_error;
+
+    // If true, use the json name in missing fields errors.
+    bool use_json_name_in_missing_fields;
+
+    Options()
+        : struct_integers_as_strings(false),
+          ignore_unknown_fields(false),
+          ignore_unknown_enum_values(false),
+          use_lower_camel_for_enums(false),
+          case_insensitive_enum_parsing(false),
+          ignore_null_value_map_entry(false),
+          use_legacy_json_map_format(false),
+          disable_implicit_message_list(false),
+          suppress_implicit_message_list_error(false),
+          disable_implicit_scalar_list(false),
+          suppress_implicit_scalar_list_error(false),
+          suppress_object_to_scalar_error(false),
+          use_json_name_in_missing_fields(false) {}
+
+    // Default instance of Options with all options set to defaults.
+    static const Options& Defaults() {
+      static Options defaults;
+      return defaults;
+    }
+  };
+
+  // Constructor. Does not take ownership of any parameter passed in.
+  ProtoStreamObjectWriter(TypeResolver* type_resolver,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener,
+                          const ProtoStreamObjectWriter::Options& options =
+                              ProtoStreamObjectWriter::Options::Defaults());
+  ~ProtoStreamObjectWriter() override;
+
+  // ObjectWriter methods.
+  ProtoStreamObjectWriter* StartObject(StringPiece name) override;
+  ProtoStreamObjectWriter* EndObject() override;
+  ProtoStreamObjectWriter* StartList(StringPiece name) override;
+  ProtoStreamObjectWriter* EndList() override;
+
+  // Renders a DataPiece 'value' into a field whose wire type is determined
+  // from the given field 'name'.
+  ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
+                                           const DataPiece& data) override;
+
+ 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 PROTOBUF_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:
+    // Before the "@type" field is encountered, we store all incoming data
+    // into this Event struct and replay them after we get the "@type" field.
+    class PROTOBUF_EXPORT Event {
+     public:
+      enum Type {
+        START_OBJECT = 0,
+        END_OBJECT = 1,
+        START_LIST = 2,
+        END_LIST = 3,
+        RENDER_DATA_PIECE = 4,
+      };
+
+      // Constructor for END_OBJECT and END_LIST events.
+      explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {}
+
+      // Constructor for START_OBJECT and START_LIST events.
+      explicit Event(Type type, StringPiece name)
+          : type_(type), name_(name), value_(DataPiece::NullData()) {}
+
+      // Constructor for RENDER_DATA_PIECE events.
+      explicit Event(StringPiece name, const DataPiece& value)
+          : type_(RENDER_DATA_PIECE), name_(name), value_(value) {
+        DeepCopy();
+      }
+
+      Event(const Event& other)
+          : type_(other.type_), name_(other.name_), value_(other.value_) {
+        DeepCopy();
+      }
+
+      Event& operator=(const Event& other) {
+        type_ = other.type_;
+        name_ = other.name_;
+        value_ = other.value_;
+        DeepCopy();
+        return *this;
+      }
+
+      void Replay(AnyWriter* writer) const;
+
+     private:
+      void DeepCopy();
+
+      Type type_;
+      std::string name_;
+      DataPiece value_;
+      std::string value_storage_;
+    };
+
+    // 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.
+    std::unique_ptr<ProtoStreamObjectWriter> ow_;
+
+    // The type_url_ that this Any represents.
+    std::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.
+    std::string data_;
+    strings::StringByteSink output_;
+
+    // The depth within the Any, so we can track when we're done.
+    int depth_;
+
+    // True if the type is a well-known type. Well-known types in Any
+    // has a special formatting:
+    // {
+    //   "@type": "type.googleapis.com/google.protobuf.XXX",
+    //   "value": <JSON representation of the type>,
+    // }
+    bool is_well_known_type_;
+    TypeRenderer* well_known_type_render_;
+
+    // Store data before the "@type" field.
+    std::vector<Event> uninterpreted_events_;
+  };
+
+  // Represents an item in a stack of items used to keep state between
+  // ObjectWrier events.
+  class PROTOBUF_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);
+
+    ~Item() override {}
+
+    // 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(); }
+
+    Item* parent() const override {
+      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.
+    std::unique_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.
+    std::unique_ptr<std::unordered_set<std::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);
+
+  ProtoStreamObjectWriter(const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener,
+                          const ProtoStreamObjectWriter::Options& options);
+
+  // Returns true if the field is a map.
+  inline bool IsMap(const google::protobuf::Field& field);
+
+  // Returns true if the field is an any.
+  inline bool IsAny(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.Struct.
+  inline bool IsStruct(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.Value.
+  inline bool IsStructValue(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.ListValue.
+  inline 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& data);
+
+  // Renders google.protobuf.Timestamp value.
+  static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
+                                      const DataPiece& data);
+
+  // Renders google.protobuf.FieldMask value.
+  static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
+                                      const DataPiece& data);
+
+  // Renders google.protobuf.Duration value.
+  static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
+                                     const DataPiece& data);
+
+  // Renders wrapper message types for primitive types in
+  // google/protobuf/wrappers.proto.
+  static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
+                                        const DataPiece& data);
+
+  static void InitRendererMap();
+  static void DeleteRendererMap();
+  static TypeRenderer* FindTypeRenderer(const std::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 auxiliary 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 std::unordered_map<std::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.
+  std::unique_ptr<Item> current_;
+
+  // Reference to the options that control this class's behavior.
+  const ProtoStreamObjectWriter::Options options_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..3348999
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -0,0 +1,3032 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/type.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/message.h>
+#include <google/protobuf/util/internal/mock_error_listener.h>
+#include <google/protobuf/util/internal/testdata/anys.pb.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/testdata/maps.pb.h>
+#include <google/protobuf/util/internal/testdata/oneofs.pb.h>
+#include <google/protobuf/util/internal/testdata/proto3.pb.h>
+#include <google/protobuf/util/internal/testdata/struct.pb.h>
+#include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h>
+#include <google/protobuf/util/internal/testdata/wrappers.pb.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/util/type_resolver_util.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+using proto_util_converter::testing::AnyM;
+using proto_util_converter::testing::AnyOut;
+using proto_util_converter::testing::Author;
+using proto_util_converter::testing::Book;
+using proto_util_converter::testing::FieldMaskTest;
+using proto_util_converter::testing::Int32Wrapper;
+using proto_util_converter::testing::MapIn;
+using proto_util_converter::testing::Primitive;
+using proto_util_converter::testing::Proto3Message;
+using proto_util_converter::testing::Publisher;
+using proto_util_converter::testing::StructType;
+using proto_util_converter::testing::TestJsonName1;
+using proto_util_converter::testing::TestJsonName2;
+using proto_util_converter::testing::TimestampDuration;
+using proto_util_converter::testing::ValueWrapper;
+using proto_util_converter::testing::oneofs::OneOfsRequest;
+using strings::GrowingArrayByteSink;
+using ::testing::_;
+using ::testing::Args;
+
+
+namespace {
+std::string GetTypeUrl(const Descriptor* descriptor) {
+  return std::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_() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(descriptor);
+    ResetTypeInfo(descriptors);
+  }
+
+  explicit BaseProtoStreamObjectWriterTest(
+      std::vector<const Descriptor*> descriptors)
+      : helper_(GetParam()),
+        listener_(),
+        output_(new GrowingArrayByteSink(1000)),
+        ow_() {
+    ResetTypeInfo(descriptors);
+  }
+
+  void ResetTypeInfo(std::vector<const Descriptor*> descriptors) {
+    GOOGLE_CHECK(!descriptors.empty()) << "Must have at least one descriptor!";
+    helper_.ResetTypeInfo(descriptors);
+    ow_.reset(helper_.NewProtoWriter(GetTypeUrl(descriptors[0]), output_.get(),
+                                     &listener_, options_));
+  }
+
+  void ResetTypeInfo(const Descriptor* descriptor) {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(descriptor);
+    ResetTypeInfo(descriptors);
+  }
+
+  ~BaseProtoStreamObjectWriterTest() override {}
+
+  void CheckOutput(const Message& expected, int expected_length) {
+    size_t nbytes;
+    std::unique_ptr<char[]> buffer(output_->GetBuffer(&nbytes));
+    if (expected_length >= 0) {
+      EXPECT_EQ(expected_length, nbytes);
+    }
+    std::string str(buffer.get(), nbytes);
+
+    std::stringbuf str_buf(str, std::ios_base::in);
+    std::istream istream(&str_buf);
+    std::unique_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); }
+
+  testing::TypeInfoTestHelper helper_;
+  MockErrorListener listener_;
+  std::unique_ptr<GrowingArrayByteSink> output_;
+  std::unique_ptr<ProtoStreamObjectWriter> ow_;
+  ProtoStreamObjectWriter::Options options_;
+};
+
+MATCHER_P(HasObjectLocation, expected,
+          "Verifies the expected object location") {
+  std::string actual = std::get<0>(arg).ToString();
+  if (actual == expected) return true;
+  *result_listener << "actual location is: " << actual;
+  return false;
+}
+
+class ProtoStreamObjectWriterTest : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterTest()
+      : BaseProtoStreamObjectWriterTest(Book::descriptor()) {}
+
+  void ResetProtoWriter() { ResetTypeInfo(Book::descriptor()); }
+
+  ~ProtoStreamObjectWriterTest() override {}
+};
+
+INSTANTIATE_TEST_SUITE_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) {
+  std::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 that two messages can have different fields mapped to the same JSON
+// name. See: https://github.com/protocolbuffers/protobuf/issues/1415
+TEST_P(ProtoStreamObjectWriterTest, ConflictingJsonName) {
+  ResetTypeInfo(TestJsonName1::descriptor());
+  TestJsonName1 message1;
+  message1.set_one_value(12345);
+  ow_->StartObject("")->RenderInt32("value", 12345)->EndObject();
+  CheckOutput(message1);
+
+  ResetTypeInfo(TestJsonName2::descriptor());
+  TestJsonName2 message2;
+  message2.set_another_value(12345);
+  ow_->StartObject("")->RenderInt32("value", 12345)->EndObject();
+  CheckOutput(message2);
+}
+
+
+TEST_P(ProtoStreamObjectWriterTest, IntEnumValuesAreAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::KIDS);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "2")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithDifferentCaseIsRejected) {
+  Book book;
+  book.set_title("Some Book");
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.case_insensitive_enum_parsing = false;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "action_and_adventure")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithSameCaseIsAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.case_insensitive_enum_parsing = false;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "ACTION_AND_ADVENTURE")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithDifferentCaseIsAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.case_insensitive_enum_parsing = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "action_AND_adventure")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithoutUnderscoreAreAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.use_lower_camel_for_enums = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "ACTIONANDADVENTURE")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, EnumValuesInCamelCaseAreAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.use_lower_camel_for_enums = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "actionAndAdventure")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       EnumValuesInCamelCaseRemoveDashAndUnderscoreAreAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.use_lower_camel_for_enums = true;
+  options_.case_insensitive_enum_parsing = false;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "action-And_Adventure")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       EnumValuesInCamelCaseWithNameNotUppercaseAreAccepted) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_type(proto_util_converter::testing::Book::arts_and_photography);
+  Author* robert = book.mutable_author();
+  robert->set_name("robert");
+
+  options_.use_lower_camel_for_enums = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderString("type", "artsAndPhotography")
+      ->StartObject("author")
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) {
+  Primitive full;
+  full.set_fix32(101);
+  full.set_u32(102);
+  full.set_i32(-103);
+  full.set_sf32(-104);
+  full.set_s32(-105);
+  full.set_fix64(40000000001L);
+  full.set_u64(40000000002L);
+  full.set_i64(-40000000003L);
+  full.set_sf64(-40000000004L);
+  full.set_s64(-40000000005L);
+  full.set_str("string1");
+  full.set_bytes("Some Bytes");
+  full.set_float_(3.14f);
+  full.set_double_(-4.05L);
+  full.set_bool_(true);
+  full.add_rep_fix32(201);
+  full.add_rep_u32(202);
+  full.add_rep_i32(-203);
+  full.add_rep_sf32(-204);
+  full.add_rep_s32(-205);
+  full.add_rep_fix64(80000000001L);
+  full.add_rep_u64(80000000002L);
+  full.add_rep_i64(-80000000003L);
+  full.add_rep_sf64(-80000000004L);
+  full.add_rep_s64(-80000000005L);
+  full.add_rep_str("string2");
+  full.add_rep_bytes("More Bytes");
+  full.add_rep_float(6.14f);
+  full.add_rep_double(-8.05L);
+  full.add_rep_bool(false);
+
+  ResetTypeInfo(Primitive::descriptor());
+
+  ow_->StartObject("")
+      ->RenderString("fix32", "101")
+      ->RenderString("u32", "102")
+      ->RenderString("i32", "-103")
+      ->RenderString("sf32", "-104")
+      ->RenderString("s32", "-105")
+      ->RenderString("fix64", "40000000001")
+      ->RenderString("u64", "40000000002")
+      ->RenderString("i64", "-40000000003")
+      ->RenderString("sf64", "-40000000004")
+      ->RenderString("s64", "-40000000005")
+      ->RenderString("str", "string1")
+      ->RenderString("bytes", "U29tZSBCeXRlcw==")  // "Some Bytes"
+      ->RenderString("float", "3.14")
+      ->RenderString("double", "-4.05")
+      ->RenderString("bool", "true")
+      ->StartList("rep_fix32")
+      ->RenderString("", "201")
+      ->EndList()
+      ->StartList("rep_u32")
+      ->RenderString("", "202")
+      ->EndList()
+      ->StartList("rep_i32")
+      ->RenderString("", "-203")
+      ->EndList()
+      ->StartList("rep_sf32")
+      ->RenderString("", "-204")
+      ->EndList()
+      ->StartList("rep_s32")
+      ->RenderString("", "-205")
+      ->EndList()
+      ->StartList("rep_fix64")
+      ->RenderString("", "80000000001")
+      ->EndList()
+      ->StartList("rep_u64")
+      ->RenderString("", "80000000002")
+      ->EndList()
+      ->StartList("rep_i64")
+      ->RenderString("", "-80000000003")
+      ->EndList()
+      ->StartList("rep_sf64")
+      ->RenderString("", "-80000000004")
+      ->EndList()
+      ->StartList("rep_s64")
+      ->RenderString("", "-80000000005")
+      ->EndList()
+      ->StartList("rep_str")
+      ->RenderString("", "string2")
+      ->EndList()
+      ->StartList("rep_bytes")
+      ->RenderString("", "TW9yZSBCeXRlcw==")  // "More Bytes"
+      ->EndList()
+      ->StartList("rep_float")
+      ->RenderString("", "6.14")
+      ->EndList()
+      ->StartList("rep_double")
+      ->RenderString("", "-8.05")
+      ->EndList()
+      ->StartList("rep_bool")
+      ->RenderString("", "false")
+      ->EndList()
+      ->EndObject();
+  CheckOutput(full);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, InfinityInputTest) {
+  Primitive full;
+  full.set_double_(std::numeric_limits<double>::infinity());
+  full.set_float_(std::numeric_limits<float>::infinity());
+  full.set_str("-Infinity");
+
+  ResetTypeInfo(Primitive::descriptor());
+
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"),
+                                      StringPiece("\"Infinity\"")))
+      .With(Args<0>(HasObjectLocation("i32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"),
+                                      StringPiece("\"Infinity\"")))
+      .With(Args<0>(HasObjectLocation("u32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_SFIXED64"),
+                                      StringPiece("\"-Infinity\"")))
+      .With(Args<0>(HasObjectLocation("sf64")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_BOOL"),
+                                      StringPiece("\"Infinity\"")))
+      .With(Args<0>(HasObjectLocation("bool")));
+
+  ow_->StartObject("")
+      ->RenderString("double", "Infinity")
+      ->RenderString("float", "Infinity")
+      ->RenderString("i32", "Infinity")
+      ->RenderString("u32", "Infinity")
+      ->RenderString("sf64", "-Infinity")
+      ->RenderString("str", "-Infinity")
+      ->RenderString("bool", "Infinity")
+      ->EndObject();
+  CheckOutput(full);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NaNInputTest) {
+  Primitive full;
+  full.set_double_(std::numeric_limits<double>::quiet_NaN());
+  full.set_float_(std::numeric_limits<float>::quiet_NaN());
+  full.set_str("NaN");
+
+  ResetTypeInfo(Primitive::descriptor());
+
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("i32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("u32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_SFIXED64"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("sf64")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_BOOL"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("bool")));
+
+  ow_->StartObject("")
+      ->RenderString("double", "NaN")
+      ->RenderString("float", "NaN")
+      ->RenderString("i32", "NaN")
+      ->RenderString("u32", "NaN")
+      ->RenderString("sf64", "NaN")
+      ->RenderString("str", "NaN")
+      ->RenderString("bool", "NaN")
+      ->EndObject();
+
+  CheckOutput(full);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ImplicitPrimitiveList) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("The Author");
+  author->add_pseudonym("first");
+  author->add_pseudonym("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "The Author")
+      ->RenderString("pseudonym", "first")
+      ->RenderString("pseudonym", "second")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       LastWriteWinsOnNonRepeatedPrimitiveFieldWithDuplicates) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "first")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ExplicitPrimitiveList) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("The Author");
+  author->add_pseudonym("first");
+  author->add_pseudonym("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "The Author")
+      ->StartList("pseudonym")
+      ->RenderString("", "first")
+      ->RenderString("", "second")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitPrimitiveList) {
+  Book expected;
+  expected.set_allocated_author(new Author());
+
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("name"),
+                  StringPiece(
+                      "Proto field is not repeating, cannot start list.")))
+      .With(Args<0>(HasObjectLocation("author")));
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->StartList("name")
+      ->RenderString("", "first")
+      ->RenderString("", "second")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ImplicitMessageList) {
+  Book expected;
+  Author* outer = expected.mutable_author();
+  outer->set_name("outer");
+  outer->set_alive(true);
+  Author* first = outer->add_friend_();
+  first->set_name("first");
+  Author* second = outer->add_friend_();
+  second->set_name("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "outer")
+      ->RenderBool("alive", true)
+      ->StartObject("friend")
+      ->RenderString("name", "first")
+      ->EndObject()
+      ->StartObject("friend")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, DisableImplicitMessageList) {
+  options_.disable_implicit_message_list = true;
+  options_.suppress_implicit_message_list_error = true;
+  ResetProtoWriter();
+
+  Book expected;
+  // The repeated friend field of the author is empty.
+  expected.mutable_author();
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->StartObject("friend")
+      ->RenderString("name", "first")
+      ->EndObject()
+      ->StartObject("friend")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       DisableImplicitMessageListWithoutErrorSuppressed) {
+  options_.disable_implicit_message_list = true;
+  ResetProtoWriter();
+
+  Book expected;
+  // The repeated friend field of the author is empty.
+  expected.mutable_author();
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("friend"),
+          StringPiece(
+              "Starting an object in a repeated field but the parent object "
+              "is not a list")))
+      .With(Args<0>(HasObjectLocation("author")))
+      .Times(2);
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->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, IgnoreUnknownFieldAtRoot) {
+  Book empty;
+
+  options_.ignore_unknown_fields = true;
+  ResetProtoWriter();
+
+  EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderString("unknown", "Nope!")->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownFieldAtAuthorFriend) {
+  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");
+
+  options_.ignore_unknown_fields = true;
+  ResetProtoWriter();
+
+  EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0);
+  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, IgnoreUnknownObjectAtRoot) {
+  Book empty;
+
+  options_.ignore_unknown_fields = true;
+  ResetProtoWriter();
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"),
+                                     StringPiece("Cannot find field.")))
+      .Times(0);
+  ow_->StartObject("")->StartObject("unknown")->EndObject()->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownObjectAtAuthor) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("William");
+  author->add_pseudonym("Bill");
+
+  options_.ignore_unknown_fields = true;
+  ResetProtoWriter();
+
+  EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "William")
+      ->StartObject("wife")
+      ->RenderString("name", "Hilary")
+      ->EndObject()
+      ->RenderString("pseudonym", "Bill")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownListAtRoot) {
+  Book empty;
+
+  options_.ignore_unknown_fields = true;
+  ResetProtoWriter();
+
+  EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0);
+  ow_->StartObject("")->StartList("unknown")->EndList()->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownListAtPublisher) {
+  Book expected;
+  expected.set_title("Brainwashing");
+  Publisher* publisher = expected.mutable_publisher();
+  publisher->set_name("propaganda");
+
+  options_.ignore_unknown_fields = true;
+  ResetProtoWriter();
+
+  EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("publisher")
+      ->RenderString("name", "propaganda")
+      ->StartList("alliance")
+      ->EndList()
+      ->EndObject()
+      ->RenderString("title", "Brainwashing")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       IgnoreUnknownFieldsDontIgnoreUnknownEnumValues) {
+  ResetTypeInfo(Proto3Message::descriptor());
+
+  Proto3Message expected;
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece(
+                       "type.googleapis.com/"
+                       "proto_util_converter.testing.Proto3Message.NestedEnum"),
+                   StringPiece("\"someunknownvalueyouwillneverknow\"")))
+      .With(Args<0>(HasObjectLocation("enum_value")));
+  ow_->StartObject("")
+      ->RenderString("enumValue", "someunknownvalueyouwillneverknow")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, AcceptUnknownEnumValue) {
+  ResetTypeInfo(Proto3Message::descriptor());
+
+  Proto3Message expected;
+  expected.set_enum_value(static_cast<Proto3Message::NestedEnum>(12345));
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderInt32("enumValue", 12345)->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() {
+    std::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_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterTimestampDurationTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampYearNotZeroPadded) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(-61665654145);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "15-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampYearZeroPadded) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(-61665654145);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "0015-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampWithPositiveOffset) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-23T11:47:35.033155+08:10")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampWithNegativeOffset) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-22T19:47:35.033155-07:50")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset1) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2016-03-07T15:14:23+")));
+
+  ow_->StartObject("")->RenderString("ts", "2016-03-07T15:14:23+")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset2) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2016-03-07T15:14:23+08-10")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2016-03-07T15:14:23+08-10")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset3) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2016-03-07T15:14:23+24:10")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2016-03-07T15:14:23+24:10")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset4) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2016-03-07T15:14:23+04:60")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2016-03-07T15:14:23+04:60")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: ")));
+
+  ow_->StartObject("")->RenderString("ts", "")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: Z")));
+
+  ow_->StartObject("")->RenderString("ts", "Z")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "1970-01-01T00:00:00.ABZ")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "1970-01-01T00:00:00.ABZ")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "-8031-10-18T00:00:00.000Z")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "-8031-10-18T00:00:00.000Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2015-11-23T03:37:35.033155   Z")));
+
+  ow_->StartObject("")
+      // Whitespace in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033155   Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2015-11-23T03:37:35.033155 1234Z")));
+
+  ow_->StartObject("")
+      // Whitespace in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "2015-11-23T03:37:35.033abc155Z")));
+
+  ow_->StartObject("")
+      // Non-numeric characters in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError8) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece("Field 'ts', Invalid time format: "
+                      "0-12-31T23:59:59.000Z")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "0-12-31T23:59:59.000Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) {
+  TimestampDuration duration;
+  google::protobuf::Duration* dur = duration.mutable_dur();
+  dur->set_seconds(1448216930);
+  dur->set_nanos(132262000);
+
+  ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece(
+              "Field 'dur', Illegal duration format; duration must "
+              "end with 's'")));
+
+  ow_->StartObject("")->RenderString("dur", "")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError2) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece(
+              "Field 'dur', Invalid duration format, failed to parse "
+              "seconds")));
+
+  ow_->StartObject("")->RenderString("dur", "s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece("Field 'dur', Invalid duration format, failed to "
+                            "parse nano seconds")));
+
+  ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError4) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece("Field 'dur', Duration value exceeds limits")));
+
+  ow_->StartObject("")->RenderString("dur", "315576000002s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece("Field 'dur', Duration value exceeds limits")));
+
+  ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       MismatchedTimestampTypeInput) {
+  TimestampDuration timestamp;
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece(
+              "Field 'ts', Invalid data type for timestamp, value is 1")))
+      .With(Args<0>(HasObjectLocation("ts")));
+  ow_->StartObject("")->RenderInt32("ts", 1)->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 1")))
+      .With(Args<0>(HasObjectLocation("dur")));
+  ow_->StartObject("")->RenderInt32("dur", 1)->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, TimestampAcceptsNull) {
+  TimestampDuration timestamp;
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderNull("ts")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, DurationAcceptsNull) {
+  TimestampDuration duration;
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderNull("dur")->EndObject();
+  CheckOutput(duration);
+}
+
+class ProtoStreamObjectWriterStructTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterStructTest() { ResetProtoWriter(); }
+
+  // Resets ProtoWriter with current set of options and other state.
+  void ResetProtoWriter() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(StructType::descriptor());
+    descriptors.push_back(google::protobuf::Struct::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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, StructAcceptsNull) {
+  StructType struct_type;
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+
+  ow_->StartObject("")->RenderNull("object")->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, StructValuePreservesNull) {
+  StructType struct_type;
+  (*struct_type.mutable_object()->mutable_fields())["key"].set_null_value(
+      google::protobuf::NULL_VALUE);
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderNull("key")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece("gBike"),
+                          StringPiece(
+                              "Repeated map key: 'gBike' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderString("gBike", "v1")
+      ->RenderString("gBike", "v2")
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderString("k1", "v1")
+      ->StartList("k1")
+      ->RenderString("", "v2")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->StartObject("k1")
+      ->RenderString("sub_k1", "v1")
+      ->EndObject()
+      ->StartObject("k1")
+      ->RenderString("sub_k2", "v2")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) {
+  StructType struct_type;
+  google::protobuf::Struct* s = struct_type.mutable_object();
+  s->mutable_fields()->operator[]("k1").set_string_value("123");
+  s->mutable_fields()->operator[]("k2").set_bool_value(true);
+  s->mutable_fields()->operator[]("k3").set_string_value("-222222222");
+  s->mutable_fields()->operator[]("k4").set_string_value("33333333");
+
+  options_.struct_integers_as_strings = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderDouble("k1", 123)
+      ->RenderBool("k2", true)
+      ->RenderInt64("k3", -222222222)
+      ->RenderUint64("k4", 33333333)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, Struct32BitIntsAndFloatsTest) {
+  StructType struct_type;
+  google::protobuf::Struct* s = struct_type.mutable_object();
+  s->mutable_fields()->operator[]("k1").set_number_value(1.5);
+  s->mutable_fields()->operator[]("k2").set_number_value(100);
+  s->mutable_fields()->operator[]("k3").set_number_value(100);
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderFloat("k1", 1.5)
+      ->RenderInt32("k2", 100)
+      ->RenderUint32("k3", 100)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest,
+       Struct32BitIntsAndFloatsAsStringsTest) {
+  StructType struct_type;
+  google::protobuf::Struct* s = struct_type.mutable_object();
+  s->mutable_fields()->operator[]("k1").set_string_value("1.5");
+  s->mutable_fields()->operator[]("k2").set_string_value("100");
+  s->mutable_fields()->operator[]("k3").set_string_value("100");
+
+  options_.struct_integers_as_strings = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderFloat("k1", 1.5)
+      ->RenderInt32("k2", 100)
+      ->RenderUint32("k3", 100)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, ValuePreservesNull) {
+  ValueWrapper value;
+  value.mutable_value()->set_null_value(google::protobuf::NULL_VALUE);
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderNull("value")->EndObject();
+  CheckOutput(value);
+}
+
+class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterMapTest() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(MapIn::descriptor());
+    descriptors.push_back(google::protobuf::DoubleValue::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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, MapAcceptsNullValue) {
+  // Null should not be a valid map value.
+  // See http://go/proto3-json-spec#heading=h.r2ddatp7y4vi
+  // This test is added for backward compatibility.
+  MapIn mm;
+  (*mm.mutable_map_input())["a"] = "b";
+  (*mm.mutable_map_input())["x"] = "";
+  ow_->StartObject("")
+      ->StartObject("map_input")
+      ->RenderString("a", "b")
+      ->RenderNull("x")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(mm);
+}
+
+TEST_P(ProtoStreamObjectWriterMapTest, MapShouldIgnoreNullValueEntry) {
+  options_.ignore_null_value_map_entry = true;
+  ResetTypeInfo(MapIn::descriptor());
+  MapIn mm;
+  (*mm.mutable_map_input())["a"] = "b";
+  ow_->StartObject("")
+      ->StartObject("map_input")
+      ->RenderString("a", "b")
+      ->RenderNull("x")
+      ->EndObject()
+      ->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();
+}
+
+TEST_P(ProtoStreamObjectWriterMapTest, AnyInMap) {
+  MapIn mm;
+  google::protobuf::DoubleValue d;
+  d.set_value(40.2);
+  (*mm.mutable_map_any())["foo"].PackFrom(d);
+  ow_->StartObject("")
+      ->StartObject("map_any")
+      ->StartObject("foo")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue")
+      ->RenderDouble("value", 40.2)
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(mm);
+}
+
+class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterAnyTest() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(AnyOut::descriptor());
+    descriptors.push_back(Book::descriptor());
+    descriptors.push_back(google::protobuf::Any::descriptor());
+    descriptors.push_back(google::protobuf::DoubleValue::descriptor());
+    descriptors.push_back(google::protobuf::FieldMask::descriptor());
+    descriptors.push_back(google::protobuf::Int32Value::descriptor());
+    descriptors.push_back(google::protobuf::Struct::descriptor());
+    descriptors.push_back(google::protobuf::Timestamp::descriptor());
+    descriptors.push_back(google::protobuf::Value::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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/proto_util_converter.testing.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/proto_util_converter.testing.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out, 112);
+}
+
+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/proto_util_converter.testing.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/proto_util_converter.testing.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out, 156);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, TypeUrlAtEnd) {
+  Book book;
+  book.set_title("C++");
+  book.set_length(1234);
+  book.set_content("Hello World!");
+
+  ::google::protobuf::Any any;
+  any.PackFrom(book);
+
+  ::google::protobuf::Any outer_any;
+  outer_any.PackFrom(any);
+
+  AnyOut out;
+  out.mutable_any()->PackFrom(outer_any);
+
+  // Put the @type field at the end of each Any message. Parsers should
+  // be able to accept that.
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->StartObject("value")
+      ->StartObject("value")
+      ->RenderString("title", "C++")
+      ->RenderInt32("length", 1234)
+      ->RenderBytes("content", "Hello World!")
+      ->RenderString("@type",
+                     "type.googleapis.com/proto_util_converter.testing.Book")
+      ->EndObject()
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->EndObject()
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Same as TypeUrlAtEnd, but use temporary string values to make sure we don't
+// mistakenly store StringPiece objects pointing to invalid memory.
+TEST_P(ProtoStreamObjectWriterAnyTest, TypeUrlAtEndWithTemporaryStrings) {
+  Book book;
+  book.set_title("C++");
+  book.set_length(1234);
+  book.set_content("Hello World!");
+
+  ::google::protobuf::Any any;
+  any.PackFrom(book);
+
+  ::google::protobuf::Any outer_any;
+  outer_any.PackFrom(any);
+
+  AnyOut out;
+  out.mutable_any()->PackFrom(outer_any);
+
+  std::string name, value;
+  // Put the @type field at the end of each Any message. Parsers should
+  // be able to accept that.
+  ow_->StartObject("")->StartObject("any");
+  {
+    ow_->StartObject("value");
+    {
+      ow_->StartObject("value");
+      {
+        name = "title";
+        value = "C++";
+        ow_->RenderString(name, value);
+        name = "length";
+        ow_->RenderInt32(name, 1234);
+        name = "content";
+        value = "Hello World!";
+        ow_->RenderBytes(name, value);
+        name = "@type";
+        value = "type.googleapis.com/proto_util_converter.testing.Book";
+        ow_->RenderString(name, value);
+      }
+      ow_->EndObject();
+
+      name = "@type";
+      value = "type.googleapis.com/google.protobuf.Any";
+      ow_->RenderString(name, value);
+    }
+    ow_->EndObject();
+
+    name = "@type";
+    value = "type.googleapis.com/google.protobuf.Any";
+    ow_->RenderString(name, value);
+  }
+  ow_->EndObject()->EndObject();
+  CheckOutput(out);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) {
+  AnyOut out;
+  out.mutable_any();
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+
+  ow_->StartObject("")->StartObject("any")->EndObject()->EndObject();
+
+  CheckOutput(out, 2);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) {
+  AnyOut any;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_, StringPiece("Any"),
+                   StringPiece("Missing @type for any field in "
+                                     "proto_util_converter.testing.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 @type for any field in "
+                                     "proto_util_converter.testing.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 @type for any field in "
+                                     "proto_util_converter.testing.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, AnyIncorrectInputTypeFails) {
+  AnyOut any;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Any"),
+                   StringPiece("1")));
+  ow_->StartObject("")->RenderInt32("any", 1)->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyAcceptsNull) {
+  AnyOut any;
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderNull("any")->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) {
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
+                                      StringPiece("Invalid time format: ")));
+
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "value": "abc"
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedPrimitiveValue) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  ::google::protobuf::Value value;
+  value.set_string_value("abc");
+  any->PackFrom(value);
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->RenderString("value", "abc")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "value": {
+//       "foo": "abc"
+//     }
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedObjectValue) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  ::google::protobuf::Value value;
+  (*value.mutable_struct_value()->mutable_fields())["foo"].set_string_value(
+      "abc");
+  any->PackFrom(value);
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartObject("value")
+      ->RenderString("foo", "abc")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "value": ["hello"],
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedArrayValue) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  ::google::protobuf::Value value;
+  value.mutable_list_value()->add_values()->set_string_value("hello");
+  any->PackFrom(value);
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartList("value")
+      ->RenderString("", "hello")
+      ->EndList()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "not_value": ""
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest,
+       AnyWellKnownTypesNoValueFieldForPrimitive) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Any"),
+          StringPiece("Expect a \"value\" field for well-known types.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Value");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->RenderString("not_value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "not_value": {}
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForObject) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Any"),
+          StringPiece("Expect a \"value\" field for well-known types.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Value");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartObject("not_value")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "not_value": [],
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForArray) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Any"),
+          StringPiece("Expect a \"value\" field for well-known types.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Value");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartList("not_value")
+      ->EndList()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Struct",
+//     "value": "",
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForStruct) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("Any"),
+                           StringPiece("Expect a JSON object.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Struct");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Struct")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Any",
+//     "value": "",
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("Any"),
+                           StringPiece("Expect a JSON object.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Any",
+//     "value": null
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyInAnyAcceptsNull) {
+  AnyOut out;
+  google::protobuf::Any empty;
+  out.mutable_any()->PackFrom(empty);
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->RenderNull("value")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Timestamp",
+//     "value": null
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, TimestampInAnyAcceptsNull) {
+  AnyOut out;
+  google::protobuf::Timestamp empty;
+  out.mutable_any()->PackFrom(empty);
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp")
+      ->RenderNull("value")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Duration",
+//     "value": null
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, DurationInAnyAcceptsNull) {
+  AnyOut out;
+  google::protobuf::Duration empty;
+  out.mutable_any()->PackFrom(empty);
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Duration")
+      ->RenderNull("value")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.FieldMask",
+//     "value": null
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, FieldMaskInAnyAcceptsNull) {
+  AnyOut out;
+  google::protobuf::FieldMask empty;
+  out.mutable_any()->PackFrom(empty);
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.FieldMask")
+      ->RenderNull("value")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Int32Value",
+//     "value": null
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, WrapperInAnyAcceptsNull) {
+  AnyOut out;
+  google::protobuf::Int32Value empty;
+  out.mutable_any()->PackFrom(empty);
+
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Int32Value")
+      ->RenderNull("value")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+class ProtoStreamObjectWriterFieldMaskTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterFieldMaskTest() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(FieldMaskTest::descriptor());
+    descriptors.push_back(google::protobuf::FieldMask::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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, MultipleMasksInCompactForm) {
+  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);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, FieldMaskAcceptsNull) {
+  FieldMaskTest expected;
+  EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderNull("single_mask")->EndObject();
+  CheckOutput(expected);
+}
+
+class ProtoStreamObjectWriterWrappersTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterWrappersTest() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(Int32Wrapper::descriptor());
+    descriptors.push_back(google::protobuf::Int32Value::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterWrappersTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterWrappersTest, WrapperAcceptsNull) {
+  Int32Wrapper wrapper;
+  EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0);
+  ow_->StartObject("")->RenderNull("int32")->EndObject();
+  CheckOutput(wrapper);
+}
+
+class ProtoStreamObjectWriterOneOfsTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterOneOfsTest() {
+    std::vector<const Descriptor*> descriptors;
+    descriptors.push_back(OneOfsRequest::descriptor());
+    descriptors.push_back(google::protobuf::Struct::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_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'")));
+
+  // JSON:
+  // { "anyData":
+  //    { "@type":
+  //       "type.googleapis.com/proto_util_converter.testing.oneofs.OneOfsRequest",
+  //     "strData": "blah",
+  //     "intData": 123
+  //    }
+  // }
+  ow_->StartObject("");
+  ow_->StartObject("anyData");
+  ow_->RenderString(
+      "@type",
+      "type.googleapis.com/proto_util_converter.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..f6f7c89
--- /dev/null
+++ b/src/google/protobuf/util/internal/structured_objectwriter.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_INTERNAL_STRUCTURED_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
+
+#include <memory>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/object_writer.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter {
+ public:
+  ~StructuredObjectWriter() override {}
+
+ 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 PROTOBUF_EXPORT BaseElement {
+   public:
+    // Takes ownership of the parent Element.
+    explicit BaseElement(BaseElement* parent)
+        : parent_(parent),
+          level_(parent == nullptr ? 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_ == nullptr; }
+
+    // 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.
+    std::unique_ptr<BaseElement> parent_;
+
+    // Number of hops to the root Element.
+    // The root Element has nullptr 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
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..b6fc3f6
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/anys.proto
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto_util_converter.testing;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+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 AnyTestCases {
+  AnyWrapper empty_any = 1;
+  AnyWrapper type_only_any = 2;
+  AnyWrapper wrapper_any = 3;
+  AnyWrapper any_with_timestamp_value = 4;
+  AnyWrapper any_with_duration_value = 5;
+  AnyWrapper any_with_struct_value = 6;
+  AnyWrapper recursive_any = 7;
+  AnyWrapper any_with_message_value = 8;
+  AnyWrapper any_with_nested_message = 9;
+  AnyWrapper any_with_message_with_wrapper_type = 10;
+  AnyWrapper any_with_message_with_timestamp = 11;
+  AnyWrapper any_with_message_containing_map = 12;
+  AnyWrapper any_with_message_containing_struct = 13;
+  AnyWrapper any_with_message_containing_repeated_message = 14;
+  AnyWrapper recursive_any_with_type_field_at_end = 15;
+  AnyWrapper repeated_any = 16;
+  AnyWrapper empty_any_with_null_type_url = 17;
+  AnyWrapper any_with_empty = 18;
+  AnyWrapper any_with_default_timestamp = 19;
+
+  google.protobuf.Any top_level_any = 50;
+  google.protobuf.Any top_level_any_with_type_field_at_end = 51;
+  google.protobuf.Any top_level_any_with_pivot_one = 52;
+  google.protobuf.Any top_level_any_with_pivot_two = 53;
+  google.protobuf.Any top_level_any_unordered = 54;
+}
+
+message AnyWrapper {
+  google.protobuf.Any any = 1;
+}
+
+// Hack to make sure the types we put into the any are included in the types.
+// Real solution is to add these types to the service config.
+message Imports {
+  google.protobuf.DoubleValue dbl = 1;
+  google.protobuf.Struct struct = 2;
+  google.protobuf.Timestamp timestamp = 3;
+  google.protobuf.Duration duration = 4;
+  google.protobuf.Int32Value i32 = 5;
+  google.protobuf.Empty empty = 6;
+  Data data = 100;
+}
+
+message Data {
+  int32 attr = 1;
+  string str = 2;
+  repeated string msgs = 3;
+  Data nested_data = 4;
+  google.protobuf.Int32Value int_wrapper = 5;
+  google.protobuf.Timestamp time = 6;
+  map<string, string> map_data = 7;
+  google.protobuf.Struct struct_data = 8;
+  repeated Data repeated_data = 9;
+  repeated google.protobuf.Any repeated_any = 10;
+}
+
+service AnyTestService {
+  rpc Call(AnyTestCases) returns (AnyTestCases);
+  rpc Call1(Imports) returns (Imports);
+}
+
+message AnyIn {
+  string something = 1;
+  google.protobuf.Any any = 2;
+}
+
+message AnyOut {
+  google.protobuf.Any any = 1;
+}
+
+message AnyM {
+  string foo = 1;
+}
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..328c5ce
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -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.
+
+// Author: sven@google.com (Sven Mawson)
+//
+// Sample protos for testing.
+
+// Some of the older enums don't use CAPITALS_WITH_UNDERSCORES for testing.
+// LINT: LEGACY_NAMES
+// LINT: ALLOW_GROUPS
+
+syntax = "proto2";
+
+package proto_util_converter.testing;
+
+import "google/protobuf/util/internal/testdata/anys.proto";
+
+// A book
+message Book {
+  optional string title = 1;
+  optional Author author = 2;
+  optional uint32 length = 3;
+  optional int64 published = 4;
+  optional bytes content = 5;
+
+  optional group Data = 6 {
+    optional uint32 year = 7;
+    optional string copyright = 8;
+  }
+
+  message Label {
+    optional string key = 1;
+    optional string value = 2;
+  }
+
+  optional Publisher publisher = 9;
+  repeated Label labels = 10;
+
+  enum Type {
+    FICTION = 1;
+    KIDS = 2;
+    ACTION_AND_ADVENTURE = 3;
+    arts_and_photography = 4;
+    I18N_Tech = 5;
+  }
+  optional Type type = 11;
+
+  // Useful for testing JSON snake/camel-case conversions.
+  optional string snake_field = 12;
+
+  // Used to test type not found in type info. Messages defined in other files
+  // are not added when adding Book to type info.
+  optional AnyWrapper type_not_found = 13;
+
+  // Used to test invalid value inside of primitive repeated fields.
+  repeated int32 primitive_repeated = 14;
+
+  extensions 200 to 499;
+}
+
+// A publisher of a book, tests required fields.
+message Publisher {
+  required string name = 1;
+}
+
+// An author of a book
+message Author {
+  optional uint64 id = 1 [json_name = "@id"];
+  optional string name = 2;
+  repeated string pseudonym = 3;
+  optional bool alive = 4;
+  repeated Author friend = 5;
+}
+
+// For testing resiliency of our protostream parser.
+// Field numbers of Author are reused for something else.
+message BadAuthor {
+  optional string id = 1;         // non-length-delimited to length-delimited.
+  repeated uint64 name = 2;       // string to repeated (both length-delimited).
+  optional string pseudonym = 3;  // Repeated to optional.
+  repeated bool alive = 4 [packed = true];  // Optional to repeated.
+}
+
+// All primitive types
+message Primitive {
+  // 32 bit numbers:
+  optional fixed32 fix32 = 1;
+  optional uint32 u32 = 2;
+  optional int32 i32 = 3;
+  optional sfixed32 sf32 = 4;
+  optional sint32 s32 = 5;
+
+  // 64 bit numbers:
+  optional fixed64 fix64 = 6;
+  optional uint64 u64 = 7;
+  optional int64 i64 = 8;
+  optional sfixed64 sf64 = 9;
+  optional sint64 s64 = 10;
+
+  // The other stuff.
+  optional string str = 11;
+  optional bytes bytes = 12;
+  optional float float = 13;
+  optional double double = 14;
+  optional bool bool = 15;
+
+  // repeated 32 bit numbers:
+  repeated fixed32 rep_fix32 = 16;
+  repeated uint32 rep_u32 = 17;
+  repeated int32 rep_i32 = 18;
+  repeated sfixed32 rep_sf32 = 19;
+  repeated sint32 rep_s32 = 20;
+
+  // repeated 64 bit numbers:
+  repeated fixed64 rep_fix64 = 21;
+  repeated uint64 rep_u64 = 22;
+  repeated int64 rep_i64 = 23;
+  repeated sfixed64 rep_sf64 = 24;
+  repeated sint64 rep_s64 = 25;
+
+  // repeated other stuff:
+  repeated string rep_str = 26;
+  repeated bytes rep_bytes = 27;
+  repeated float rep_float = 28;
+  repeated double rep_double = 29;
+  repeated bool rep_bool = 30;
+}
+
+// Test packed versions of all repeated primitives.
+// The field numbers should match their non-packed version in Primitive message.
+message PackedPrimitive {
+  // repeated 32 bit numbers:
+  repeated fixed32 rep_fix32 = 16 [packed = true];
+  repeated uint32 rep_u32 = 17 [packed = true];
+  repeated int32 rep_i32 = 18 [packed = true];
+  repeated sfixed32 rep_sf32 = 19 [packed = true];
+  repeated sint32 rep_s32 = 20 [packed = true];
+
+  // repeated 64 bit numbers:
+  repeated fixed64 rep_fix64 = 21 [packed = true];
+  repeated uint64 rep_u64 = 22 [packed = true];
+  repeated int64 rep_i64 = 23 [packed = true];
+  repeated sfixed64 rep_sf64 = 24 [packed = true];
+  repeated sint64 rep_s64 = 25 [packed = true];
+
+  // repeated other stuff:
+  repeated float rep_float = 28 [packed = true];
+  repeated double rep_double = 29 [packed = true];
+  repeated bool rep_bool = 30 [packed = true];
+}
+
+// Test extensions.
+extend Book {
+  repeated Author more_author = 201;
+}
+
+// Test nested extensions.
+message NestedBook {
+  extend Book {
+    optional NestedBook another_book = 301;
+  }
+  // Recurse
+  optional Book book = 1;
+}
+
+// For testing resiliency of our protostream parser.
+// Field number of NestedBook is reused for something else.
+message BadNestedBook {
+  repeated uint32 book = 1 [packed = true];  // Packed to optional message.
+}
+
+// A recursively defined message.
+message Cyclic {
+  optional int32 m_int = 1;
+  optional string m_str = 2;
+  optional Book m_book = 3;
+  repeated Author m_author = 5;
+  optional Cyclic m_cyclic = 4;
+}
+
+// Test that two messages can have different fields mapped to the same JSON
+// name. See: https://github.com/protocolbuffers/protobuf/issues/1415
+message TestJsonName1 {
+  optional int32 one_value = 1 [json_name = "value"];
+}
+message TestJsonName2 {
+  optional int32 another_value = 1 [json_name = "value"];
+}
+
+message TestPrimitiveFieldsWithSameJsonName {
+  optional string val_str1 = 1;
+  optional string val_str_1 = 2;
+
+  optional int32 val_int321 = 3;
+  optional int32 val_int32_1 = 4;
+
+  optional uint32 val_uint321 = 5;
+  optional uint32 val_uint32_1 = 6;
+
+  optional int64 val_int641 = 7;
+  optional int64 val_int64_1 = 8;
+
+  optional uint64 val_uint641 = 9;
+  optional uint64 val_uint64_1 = 10;
+
+  optional bool val_bool1 = 11;
+  optional bool val_bool_1 = 12;
+
+  optional double val_double1 = 13;
+  optional double val_double_1 = 14;
+
+  optional float val_float1 = 15;
+  optional float val_float_1 = 16;
+}
+
+message TestRepeatedFieldsWithSameJsonName {
+  repeated string rep_str1 = 1;
+  repeated string rep_str_1 = 2;
+}
+
+message TestMessageFieldsWithSameJsonName {
+  optional Primitive prim1 = 1;
+  optional Primitive prim_1 = 2;
+}
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..79ce144
--- /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 proto_util_converter.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..af755d3
--- /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 proto_util_converter.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..9d2bc40
--- /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 proto_util_converter.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..a9fdbe6
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/maps.proto
@@ -0,0 +1,148 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto_util_converter.testing;
+
+import "google/protobuf/any.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 MapsTestCases {
+  EmptyMap empty_map = 1;
+  StringtoInt string_to_int = 2;
+  IntToString int_to_string = 3;
+  Mixed1 mixed1 = 4;
+  Mixed2 mixed2 = 5;
+  MapOfObjects map_of_objects = 6;
+
+  // Empty key tests
+  StringtoInt empty_key_string_to_int1 = 7;
+  StringtoInt empty_key_string_to_int2 = 8;
+  StringtoInt empty_key_string_to_int3 = 9;
+  BoolToString empty_key_bool_to_string = 10;
+  IntToString empty_key_int_to_string = 11;
+  Mixed1 empty_key_mixed = 12;
+  MapOfObjects empty_key_map_objects = 13;
+}
+
+message EmptyMap {
+  map<int32, int32> map = 1;
+}
+
+message StringtoInt {
+  map<string, int32> map = 1;
+}
+
+message IntToString {
+  map<int32, string> map = 1;
+}
+
+message BoolToString {
+  map<bool, string> map = 1;
+}
+
+message Mixed1 {
+  string msg = 1;
+  map<string, float> map = 2;
+}
+
+message Mixed2 {
+  enum E {
+    E0 = 0;
+    E1 = 1;
+    E2 = 2;
+    E3 = 3;
+  }
+  map<int32, bool> map = 1;
+  E ee = 2;
+}
+
+message MapOfObjects {
+  message M {
+    string inner_text = 1;
+  }
+  map<string, M> map = 1;
+}
+
+message DummyRequest {}
+
+service MapsTestService {
+  rpc Call(DummyRequest) returns (MapsTestCases);
+}
+
+message MapIn {
+  string other = 1;
+  repeated string things = 2;
+  map<string, string> map_input = 3;
+  map<string, google.protobuf.Any> map_any = 4;
+}
+
+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;
+}
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..7706af0
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/oneofs.proto
@@ -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.
+
+// Proto to test proto3 oneofs.
+syntax = "proto3";
+
+package proto_util_converter.testing.oneofs;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+
+message OneOfsRequest {
+  string value = 1;
+  oneof data {
+    string str_data = 2;
+    int32 int_data = 3;
+    // Simple message
+    Data message_data = 4;
+    MoreData more_data = 5;
+    // Well known types
+    google.protobuf.Struct struct_data = 6;
+    google.protobuf.Value value_data = 7;
+    google.protobuf.ListValue list_value_data = 8;
+    google.protobuf.Timestamp ts_data = 9;
+  }
+  google.protobuf.Any any_data = 19;
+}
+
+message RequestWithSimpleOneof {
+  string value = 1;
+  oneof data {
+    string str_data = 2;
+    int32 int_data = 3;
+    Data message_data = 4;
+    MoreData more_data = 5;
+  }
+}
+
+message Data {
+  int32 data_value = 1;
+}
+
+message MoreData {
+  string str_value = 1;
+}
+
+message Response {
+  string value = 1;
+}
diff --git a/src/google/protobuf/util/internal/testdata/proto3.proto b/src/google/protobuf/util/internal/testdata/proto3.proto
new file mode 100644
index 0000000..01434b0
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/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.
+
+syntax = "proto3";
+
+package proto_util_converter.testing;
+
+message Proto3Message {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+  NestedEnum enum_value = 1;
+}
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..a50ea87
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/struct.proto
@@ -0,0 +1,117 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto_util_converter.testing;
+
+import "google/protobuf/struct.proto";
+
+message StructTestCases {
+  StructWrapper empty_value = 1;
+  StructWrapper empty_value2 = 2;
+  StructWrapper null_value = 3;
+  StructWrapper simple_struct = 4;
+  StructWrapper longer_struct = 5;
+  StructWrapper struct_with_nested_struct = 6;
+  StructWrapper struct_with_nested_list = 7;
+  StructWrapper struct_with_list_of_nulls = 8;
+  StructWrapper struct_with_list_of_lists = 9;
+  StructWrapper struct_with_list_of_structs = 10;
+  StructWrapper struct_with_empty_list = 11;
+  StructWrapper struct_with_list_with_empty_struct = 12;
+  google.protobuf.Struct top_level_struct = 13;
+  google.protobuf.Struct top_level_struct_with_empty_list = 14;
+  google.protobuf.Struct top_level_struct_with_list_with_empty_struct = 15;
+  ValueWrapper value_wrapper_simple = 16;
+  ValueWrapper value_wrapper_with_struct = 17;
+  ValueWrapper value_wrapper_with_list = 18;
+  ValueWrapper value_wrapper_with_empty_list = 19;
+  ValueWrapper value_wrapper_with_list_with_empty_struct = 20;
+  ListValueWrapper list_value_wrapper = 21;
+  ListValueWrapper list_value_wrapper_with_empty_list = 22;
+  ListValueWrapper list_value_wrapper_with_list_with_empty_struct = 23;
+  google.protobuf.Value top_level_value_simple = 24;
+  google.protobuf.Value top_level_value_with_struct = 25;
+  google.protobuf.Value top_level_value_with_list = 26;
+  google.protobuf.Value top_level_value_with_empty_list = 27;
+  google.protobuf.Value top_level_value_with_list_with_empty_struct = 28;
+  google.protobuf.ListValue top_level_listvalue = 29;
+  google.protobuf.ListValue top_level_empty_listvalue = 30;
+  google.protobuf.ListValue top_level_listvalue_with_empty_struct = 31;
+  RepeatedValueWrapper repeated_value = 32;
+  RepeatedValueWrapper repeated_value_nested_list = 33;
+  RepeatedValueWrapper repeated_value_nested_list2 = 34;
+  RepeatedValueWrapper repeated_value_nested_list3 = 35;
+  RepeatedListValueWrapper repeated_listvalue = 36;
+  MapOfStruct map_of_struct = 37;
+  MapOfStruct map_of_struct_value = 38;
+  MapOfStruct map_of_listvalue = 39;
+}
+
+message StructWrapper {
+  google.protobuf.Struct struct = 1;
+}
+
+message ValueWrapper {
+  google.protobuf.Value value = 1;
+}
+
+message RepeatedValueWrapper {
+  repeated google.protobuf.Value values = 1;
+}
+
+message ListValueWrapper {
+  google.protobuf.ListValue shopping_list = 1;
+}
+
+message RepeatedListValueWrapper {
+  repeated google.protobuf.ListValue dimensions = 1;
+}
+
+message MapOfStruct {
+  map<string, google.protobuf.Struct> struct_map = 1;
+  map<string, google.protobuf.Value> value_map = 2;
+  map<string, google.protobuf.ListValue> listvalue_map = 3;
+}
+
+// Hack to test return types with Struct as top-level message. Struct typers
+// cannot be directly used in API requests. Hence using Dummy as request type.
+message Dummy {
+  string text = 1;
+}
+
+service StructTestService {
+  rpc Call(Dummy) returns (StructTestCases);
+}
+
+message StructType {
+  google.protobuf.Struct object = 1;
+}
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..8e87bdd
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/timestamp_duration.proto
@@ -0,0 +1,80 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto_util_converter.testing;
+
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+
+message TimestampDurationTestCases {
+  // Timestamp tests
+  TimeStampType epoch = 1;
+  TimeStampType epoch2 = 2;
+  TimeStampType mintime = 3;
+  TimeStampType maxtime = 4;
+  TimeStampType timeval1 = 5;
+  TimeStampType timeval2 = 6;
+  TimeStampType timeval3 = 7;
+  TimeStampType timeval4 = 8;
+  TimeStampType timeval5 = 9;
+  TimeStampType timeval6 = 10;
+  TimeStampType timeval7 = 11;
+  google.protobuf.Timestamp timeval8 = 12;
+
+  // Duration tests
+  DurationType zero_duration = 101;
+  DurationType min_duration = 102;
+  DurationType max_duration = 103;
+  DurationType duration1 = 104;
+  DurationType duration2 = 105;
+  DurationType duration3 = 106;
+  DurationType duration4 = 107;
+  google.protobuf.Duration duration5 = 108;
+}
+
+message TimeStampType {
+  google.protobuf.Timestamp timestamp = 1;
+}
+
+message DurationType {
+  google.protobuf.Duration duration = 1;
+}
+
+service TimestampDurationTestService {
+  rpc Call(TimestampDurationTestCases) returns (TimestampDurationTestCases);
+}
+
+message TimestampDuration {
+  google.protobuf.Timestamp ts = 1;
+  google.protobuf.Duration dur = 2;
+  repeated google.protobuf.Timestamp rep_ts = 3;
+}
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..e7a0541
--- /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 proto_util_converter.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..b6cf536
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info.cc
@@ -0,0 +1,182 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#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/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/status.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) {}
+
+  ~TypeInfoForTypeResolver() override {
+    DeleteCachedTypes(&cached_types_);
+    DeleteCachedTypes(&cached_enums_);
+  }
+
+  util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
+      StringPiece type_url) const override {
+    std::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 std::string& string_type_url =
+        *string_storage_.insert(std::string(type_url)).first;
+    std::unique_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;
+  }
+
+  const google::protobuf::Type* GetTypeByTypeUrl(
+      StringPiece type_url) const override {
+    StatusOrType result = ResolveTypeUrl(type_url);
+    return result.ok() ? result.value() : NULL;
+  }
+
+  const google::protobuf::Enum* GetEnumByTypeUrl(
+      StringPiece type_url) const override {
+    std::map<StringPiece, StatusOrEnum>::iterator it =
+        cached_enums_.find(type_url);
+    if (it != cached_enums_.end()) {
+      return it->second.ok() ? it->second.value() : NULL;
+    }
+    // Stores the string value so it can be referenced using StringPiece in the
+    // cached_enums_ map.
+    const std::string& string_type_url =
+        *string_storage_.insert(std::string(type_url)).first;
+    std::unique_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.value() : NULL;
+  }
+
+  const google::protobuf::Field* FindField(
+      const google::protobuf::Type* type,
+      StringPiece camel_case_name) const override {
+    std::map<const google::protobuf::Type*, CamelCaseNameTable>::const_iterator
+        it = indexed_types_.find(type);
+    const CamelCaseNameTable& camel_case_name_table =
+        (it == indexed_types_.end())
+            ? PopulateNameLookupTable(type, &indexed_types_[type])
+            : it->second;
+    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;
+  typedef std::map<StringPiece, StringPiece> CamelCaseNameTable;
+
+  template <typename T>
+  static void DeleteCachedTypes(std::map<StringPiece, T>* cached_types) {
+    for (typename std::map<StringPiece, T>::iterator it =
+             cached_types->begin();
+         it != cached_types->end(); ++it) {
+      if (it->second.ok()) {
+        delete it->second.value();
+      }
+    }
+  }
+
+  const CamelCaseNameTable& PopulateNameLookupTable(
+      const google::protobuf::Type* type,
+      CamelCaseNameTable* camel_case_name_table) 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
+                     << "'.";
+      }
+    }
+    return *camel_case_name_table;
+  }
+
+  TypeResolver* type_resolver_;
+
+  // Stores string values that will be referenced by StringPieces in
+  // cached_types_, cached_enums_.
+  mutable std::set<std::string> string_storage_;
+
+  mutable std::map<StringPiece, StatusOrType> cached_types_;
+  mutable std::map<StringPiece, StatusOrEnum> cached_enums_;
+
+  mutable std::map<const google::protobuf::Type*, CamelCaseNameTable>
+      indexed_types_;
+};
+}  // 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..257df5b
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info.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_UTIL_INTERNAL_TYPE_INFO_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+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 PROTOBUF_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
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..088f412
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info_test_helper.cc
@@ -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.
+
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/constants.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/internal/type_info.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 std::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) {
+  std::vector<const Descriptor*> descriptors;
+  descriptors.push_back(descriptor);
+  ResetTypeInfo(descriptors);
+}
+
+void TypeInfoTestHelper::ResetTypeInfo(const Descriptor* descriptor1,
+                                       const Descriptor* descriptor2) {
+  std::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 std::string& type_url,
+    ProtoStreamObjectSource::RenderOptions render_options) {
+  const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url);
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      return new ProtoStreamObjectSource(coded_input, type_resolver_.get(),
+                                         *type, render_options);
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Can not reach here.";
+  return nullptr;
+}
+
+ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter(
+    const std::string& type_url, strings::ByteSink* output,
+    ErrorListener* listener, const ProtoStreamObjectWriter::Options& options) {
+  const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url);
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output,
+                                         listener, options);
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Can not reach here.";
+  return nullptr;
+}
+
+DefaultValueObjectWriter* TypeInfoTestHelper::NewDefaultValueWriter(
+    const std::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 nullptr;
+}
+
+}  // 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..1110a34
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info_test_helper.h
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_TEST_HELPER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_TEST_HELPER_H__
+
+#include <memory>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+#include <google/protobuf/util/internal/type_info.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 std::vector<const Descriptor*>& descriptors);
+
+  // Convenient 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 std::string& type_url,
+      ProtoStreamObjectSource::RenderOptions render_options = {});
+
+  ProtoStreamObjectWriter* NewProtoWriter(
+      const std::string& type_url, strings::ByteSink* output,
+      ErrorListener* listener, const ProtoStreamObjectWriter::Options& options);
+
+  DefaultValueObjectWriter* NewDefaultValueWriter(const std::string& type_url,
+                                                  ObjectWriter* writer);
+
+ private:
+  TypeInfoSource type_;
+  std::unique_ptr<TypeInfo> typeinfo_;
+  std::unique_ptr<TypeResolver> type_resolver_;
+};
+}  // namespace testing
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_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..918ee17
--- /dev/null
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -0,0 +1,416 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <algorithm>
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+#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/stubs/strutil.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/stubs/map_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+bool GetBoolOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, bool default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return default_value;
+  }
+  return GetBoolFromAny(opt->value());
+}
+
+int64_t GetInt64OptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, int64_t default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return default_value;
+  }
+  return GetInt64FromAny(opt->value());
+}
+
+double GetDoubleOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, double default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return default_value;
+  }
+  return GetDoubleFromAny(opt->value());
+}
+
+std::string GetStringOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, StringPiece default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return std::string(default_value);
+  }
+  return GetStringFromAny(opt->value());
+}
+
+template <typename T>
+void ParseFromAny(const std::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_t 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();
+}
+
+std::string GetStringFromAny(const google::protobuf::Any& any) {
+  google::protobuf::StringValue s;
+  ParseFromAny(any.value(), &s);
+  return s.value();
+}
+
+const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
+  if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') {
+    return type_url.substr(kTypeUrlSize + 1);
+  } else {
+    size_t idx = type_url.rfind('/');
+    if (idx != type_url.npos) {
+      type_url.remove_prefix(idx + 1);
+    }
+    return type_url;
+  }
+}
+
+const std::string GetFullTypeWithUrl(StringPiece simple_type) {
+  return StrCat(kTypeServiceBaseUrl, "/", simple_type);
+}
+
+const google::protobuf::Option* FindOptionOrNull(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece 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 nullptr;
+}
+
+const google::protobuf::Field* FindFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece field_name) {
+  if (type != nullptr) {
+    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 nullptr;
+}
+
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name) {
+  if (type != nullptr) {
+    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 nullptr;
+}
+
+const google::protobuf::Field* FindFieldInTypeByNumberOrNull(
+    const google::protobuf::Type* type, int32_t number) {
+  if (type != nullptr) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.number() == number) {
+        return &field;
+      }
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
+  if (enum_type != nullptr) {
+    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 nullptr;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
+    const google::protobuf::Enum* enum_type, int32_t value) {
+  if (enum_type != nullptr) {
+    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 nullptr;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
+  if (enum_type != nullptr) {
+    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
+      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
+      std::string enum_name_without_underscore = enum_value.name();
+
+      // Remove underscore from the name.
+      enum_name_without_underscore.erase(
+          std::remove(enum_name_without_underscore.begin(),
+                      enum_name_without_underscore.end(), '_'),
+          enum_name_without_underscore.end());
+      // Make the name uppercase.
+      for (std::string::iterator it = enum_name_without_underscore.begin();
+           it != enum_name_without_underscore.end(); ++it) {
+        *it = ascii_toupper(*it);
+      }
+
+      if (enum_name_without_underscore == enum_name) {
+        return &enum_value;
+      }
+    }
+  }
+  return nullptr;
+}
+
+std::string EnumValueNameToLowerCamelCase(StringPiece input) {
+  std::string input_string(input);
+  std::transform(input_string.begin(), input_string.end(), input_string.begin(),
+                 ::tolower);
+  return ToCamelCase(input_string);
+}
+
+std::string ToCamelCase(StringPiece input) {
+  bool capitalize_next = false;
+  bool was_cap = true;
+  bool is_cap = false;
+  bool first_word = true;
+  std::string result;
+  result.reserve(input.size());
+
+  for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) {
+    is_cap = ascii_isupper(input[i]);
+    if (input[i] == '_') {
+      capitalize_next = true;
+      if (!result.empty()) first_word = false;
+      continue;
+    } else if (first_word) {
+      // Consider when the current character B is capitalized,
+      // first word ends when:
+      // 1) following a lowercase:   "...aB..."
+      // 2) followed by a lowercase: "...ABc..."
+      if (!result.empty() && is_cap &&
+          (!was_cap ||
+           (i + 1 < input.size() && ascii_islower(input[i + 1])))) {
+        first_word = false;
+        result.push_back(input[i]);
+      } else {
+        result.push_back(ascii_tolower(input[i]));
+        continue;
+      }
+    } else if (capitalize_next) {
+      capitalize_next = false;
+      if (ascii_islower(input[i])) {
+        result.push_back(ascii_toupper(input[i]));
+        continue;
+      } else {
+        result.push_back(input[i]);
+        continue;
+      }
+    } else {
+      result.push_back(ascii_tolower(input[i]));
+    }
+  }
+  return result;
+}
+
+std::string ToSnakeCase(StringPiece input) {
+  bool was_not_underscore = false;  // Initialize to false for case 1 (below)
+  bool was_not_cap = false;
+  std::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;
+}
+
+std::set<std::string>* well_known_types_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag 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 std::set<std::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 std::string& type_name) {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(well_known_types_init_,
+                                             InitWellKnownTypes);
+  return ContainsKey(*well_known_types_, type_name);
+}
+
+bool IsValidBoolString(StringPiece 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_REPEATED &&
+         (GetBoolOptionOrDefault(type.options(), "map_entry", false) ||
+          GetBoolOptionOrDefault(type.options(),
+                                 "google.protobuf.MessageOptions.map_entry",
+                                 false));
+}
+
+bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
+  return GetBoolOptionOrDefault(type.options(), "message_set_wire_format",
+                                false) ||
+         GetBoolOptionOrDefault(
+             type.options(),
+             "google.protobuf.MessageOptions.message_set_wire_format", false);
+}
+
+std::string DoubleAsString(double value) {
+  if (value == std::numeric_limits<double>::infinity()) return "Infinity";
+  if (value == -std::numeric_limits<double>::infinity()) return "-Infinity";
+  if (std::isnan(value)) return "NaN";
+
+  return SimpleDtoa(value);
+}
+
+std::string FloatAsString(float value) {
+  if (std::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 (std::isinf(double_value) || std::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..79d6779
--- /dev/null
+++ b/src/google/protobuf/util/internal/utility.h
@@ -0,0 +1,204 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// Size of "type.googleapis.com"
+static const int64_t kTypeUrlSize = 19;
+
+// 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.
+PROTOBUF_EXPORT bool GetBoolOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, bool default_value);
+
+// Returns int64 option value. If the option isn't found, returns the
+// default_value.
+PROTOBUF_EXPORT int64_t GetInt64OptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, int64_t default_value);
+
+// Returns double option value. If the option isn't found, returns the
+// default_value.
+PROTOBUF_EXPORT double GetDoubleOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, double default_value);
+
+// Returns string option value. If the option isn't found, returns the
+// default_value.
+PROTOBUF_EXPORT std::string GetStringOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, StringPiece 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/shareable location so
+// others can use.
+PROTOBUF_EXPORT bool GetBoolFromAny(const google::protobuf::Any& any);
+
+// Returns int64 value contained in Any type.
+PROTOBUF_EXPORT int64_t GetInt64FromAny(const google::protobuf::Any& any);
+
+// Returns double value contained in Any type.
+PROTOBUF_EXPORT double GetDoubleFromAny(const google::protobuf::Any& any);
+
+// Returns string value contained in Any type.
+PROTOBUF_EXPORT std::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'.
+PROTOBUF_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".
+PROTOBUF_EXPORT const std::string GetFullTypeWithUrl(
+    StringPiece simple_type);
+
+// Finds and returns option identified by name and option_name within the
+// provided map. Returns nullptr if none found.
+const google::protobuf::Option* FindOptionOrNull(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name);
+
+// Finds and returns the field identified by field_name in the passed tech Type
+// object. Returns nullptr 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);
+
+// Similar to FindFieldInTypeOrNull, but this looks up fields by number.
+const google::protobuf::Field* FindFieldInTypeByNumberOrNull(
+    const google::protobuf::Type* type, int32_t number);
+
+// Finds and returns the EnumValue identified by enum_name in the passed tech
+// Enum object. Returns nullptr 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 nullptr if none found.
+const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
+    const google::protobuf::Enum* enum_type, int32_t value);
+
+// Finds and returns the EnumValue identified by enum_name without underscore in
+// the passed tech Enum object. Returns nullptr if none found.
+// For Ex. if enum_name is ACTIONANDADVENTURE it can get accepted if
+// EnumValue's name is action_and_adventure or ACTION_AND_ADVENTURE.
+const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name);
+
+// Converts input to camel-case and returns it.
+PROTOBUF_EXPORT std::string ToCamelCase(const StringPiece input);
+
+// Converts enum name string to camel-case and returns it.
+std::string EnumValueNameToLowerCamelCase(const StringPiece input);
+
+// Converts input to snake_case and returns it.
+PROTOBUF_EXPORT std::string ToSnakeCase(StringPiece input);
+
+// Returns true if type_name represents a well-known type.
+PROTOBUF_EXPORT bool IsWellKnownType(const std::string& type_name);
+
+// Returns true if 'bool_string' represents a valid boolean value. Only "true",
+// "false", "0" and "1" are allowed.
+PROTOBUF_EXPORT bool IsValidBoolString(StringPiece bool_string);
+
+// Returns true if "field" is a protobuf map field based on its type.
+PROTOBUF_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.
+PROTOBUF_EXPORT std::string DoubleAsString(double value);
+PROTOBUF_EXPORT std::string FloatAsString(float value);
+
+// Convert from int32, int64, uint32, uint64, double or float to string.
+template <typename T>
+std::string ValueAsString(T value) {
+  return StrCat(value);
+}
+
+template <>
+inline std::string ValueAsString(float value) {
+  return FloatAsString(value);
+}
+
+template <>
+inline std::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).
+PROTOBUF_EXPORT bool SafeStrToFloat(StringPiece str, float* value);
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto
new file mode 100644
index 0000000..7b7100d
--- /dev/null
+++ b/src/google/protobuf/util/json_format.proto
@@ -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.
+
+// 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 = "proto2";
+
+package protobuf_unittest;
+
+message TestFlagsAndStrings {
+  required int32 A = 1;
+  repeated group RepeatedGroup = 2 {
+    required string f = 3;
+  }
+}
+
+message TestBase64ByteArrays {
+  required bytes a = 1;
+}
+
+message TestJavaScriptJSON {
+  optional int32 a = 1;
+  optional float final = 2;
+  optional string in = 3;
+  optional string Var = 4;
+}
+
+message TestJavaScriptOrderJSON1 {
+  optional int32 d = 1;
+  optional int32 c = 2;
+  optional bool x = 3;
+  optional int32 b = 4;
+  optional int32 a = 5;
+}
+
+message TestJavaScriptOrderJSON2 {
+  optional int32 d = 1;
+  optional int32 c = 2;
+  optional bool x = 3;
+  optional int32 b = 4;
+  optional int32 a = 5;
+  repeated TestJavaScriptOrderJSON1 z = 6;
+}
+
+message TestLargeInt {
+  required int64 a = 1;
+  required uint64 b = 2;
+}
+
+message TestNumbers {
+  enum MyType {
+    OK = 0;
+    WARNING = 1;
+    ERROR = 2;
+  }
+  optional MyType a = 1;
+  optional int32 b = 2;
+  optional float c = 3;
+  optional bool d = 4;
+  optional double e = 5;
+  optional uint32 f = 6;
+}
+
+
+message TestCamelCase {
+  optional string normal_field = 1;
+  optional int32 CAPITAL_FIELD = 2;
+  optional int32 CamelCaseField = 3;
+}
+
+message TestBoolMap {
+  map<bool, int32> bool_map = 1;
+}
+
+message TestRecursion {
+  optional int32 value = 1;
+  optional TestRecursion child = 2;
+}
+
+message TestStringMap {
+  map<string, string> string_map = 1;
+}
+
+message TestStringSerializer {
+  optional string scalar_string = 1;
+  repeated string repeated_string = 2;
+  map<string, string> string_map = 3;
+}
+
+message TestMessageWithExtension {
+  extensions 100 to max;
+}
+
+message TestExtension {
+  extend TestMessageWithExtension {
+    optional TestExtension ext = 100;
+  }
+  optional string value = 1;
+}
+
+enum EnumValue {
+  PROTOCOL = 0;
+  BUFFER = 1;
+  DEFAULT = 2;
+}
+
+message TestDefaultEnumValue {
+  optional EnumValue enum_value = 1 [default = DEFAULT];
+}
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..0eec9da
--- /dev/null
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -0,0 +1,194 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package proto3;
+
+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";
+import "google/protobuf/unittest.proto";
+
+option java_package = "com.google.protobuf.util";
+option java_outer_classname = "JsonFormatProto3";
+
+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;
+    google.protobuf.NullValue oneof_null_value = 6;
+  }
+}
+
+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 TestStringMap {
+  map<string, string> string_map = 1;
+}
+
+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"];
+}
+
+message TestExtensions {
+  .protobuf_unittest.TestAllExtensions extensions = 1;
+}
+
+message TestEnumValue {
+  EnumType enum_value1 = 1;
+  EnumType enum_value2 = 2;
+  EnumType enum_value3 = 3;
+}
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
new file mode 100644
index 0000000..c39c10d
--- /dev/null
+++ b/src/google/protobuf/util/json_util.cc
@@ -0,0 +1,284 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/stubs/once.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/strutil.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/status_macros.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+namespace internal {
+ZeroCopyStreamByteSink::~ZeroCopyStreamByteSink() {
+  if (buffer_size_ > 0) {
+    stream_->BackUp(buffer_size_);
+  }
+}
+
+void ZeroCopyStreamByteSink::Append(const char* bytes, size_t len) {
+  while (true) {
+    if (len <= buffer_size_) {  // NOLINT
+      memcpy(buffer_, bytes, len);
+      buffer_ = static_cast<char*>(buffer_) + len;
+      buffer_size_ -= len;
+      return;
+    }
+    if (buffer_size_ > 0) {
+      memcpy(buffer_, bytes, buffer_size_);
+      bytes += buffer_size_;
+      len -= buffer_size_;
+    }
+    if (!stream_->Next(&buffer_, &buffer_size_)) {
+      // There isn't a way for ByteSink to report errors.
+      buffer_size_ = 0;
+      return;
+    }
+  }
+}
+}  // namespace internal
+
+util::Status BinaryToJsonStream(TypeResolver* resolver,
+                                const std::string& type_url,
+                                io::ZeroCopyInputStream* binary_input,
+                                io::ZeroCopyOutputStream* json_output,
+                                const JsonPrintOptions& options) {
+  io::CodedInputStream in_stream(binary_input);
+  google::protobuf::Type type;
+  RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
+  converter::ProtoStreamObjectSource::RenderOptions render_options;
+  render_options.use_ints_for_enums = options.always_print_enums_as_ints;
+  render_options.preserve_proto_field_names =
+      options.preserve_proto_field_names;
+  converter::ProtoStreamObjectSource proto_source(&in_stream, resolver, type,
+                                                  render_options);
+  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);
+    default_value_writer.set_preserve_proto_field_names(
+        options.preserve_proto_field_names);
+    default_value_writer.set_print_enums_as_ints(
+        options.always_print_enums_as_ints);
+    return proto_source.WriteTo(&default_value_writer);
+  } else {
+    return proto_source.WriteTo(&json_writer);
+  }
+}
+
+util::Status BinaryToJsonString(TypeResolver* resolver,
+                                const std::string& type_url,
+                                const std::string& binary_input,
+                                std::string* json_output,
+                                const JsonPrintOptions& options) {
+  io::ArrayInputStream input_stream(binary_input.data(), binary_input.size());
+  io::StringOutputStream output_stream(json_output);
+  return BinaryToJsonStream(resolver, type_url, &input_stream, &output_stream,
+                            options);
+}
+
+namespace {
+class StatusErrorListener : public converter::ErrorListener {
+ public:
+  StatusErrorListener() {}
+  ~StatusErrorListener() override {}
+
+  util::Status GetStatus() { return status_; }
+
+  void InvalidName(const converter::LocationTrackerInterface& loc,
+                   StringPiece unknown_name,
+                   StringPiece message) override {
+    std::string loc_string = GetLocString(loc);
+    if (!loc_string.empty()) {
+      loc_string.append(" ");
+    }
+    status_ = util::InvalidArgumentError(
+        StrCat(loc_string, unknown_name, ": ", message));
+  }
+
+  void InvalidValue(const converter::LocationTrackerInterface& loc,
+                    StringPiece type_name,
+                    StringPiece value) override {
+    status_ = util::InvalidArgumentError(
+        StrCat(GetLocString(loc), ": invalid value ", std::string(value),
+                     " for type ", std::string(type_name)));
+  }
+
+  void MissingField(const converter::LocationTrackerInterface& loc,
+                    StringPiece missing_name) override {
+    status_ = util::InvalidArgumentError(StrCat(
+        GetLocString(loc), ": missing field ", std::string(missing_name)));
+  }
+
+ private:
+  util::Status status_;
+
+  std::string GetLocString(const converter::LocationTrackerInterface& loc) {
+    std::string loc_string = loc.ToString();
+    StripWhitespace(&loc_string);
+    if (!loc_string.empty()) {
+      loc_string = StrCat("(", loc_string, ")");
+    }
+    return loc_string;
+  }
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StatusErrorListener);
+};
+}  // namespace
+
+util::Status JsonToBinaryStream(TypeResolver* resolver,
+                                const std::string& type_url,
+                                io::ZeroCopyInputStream* json_input,
+                                io::ZeroCopyOutputStream* binary_output,
+                                const JsonParseOptions& options) {
+  google::protobuf::Type type;
+  RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
+  internal::ZeroCopyStreamByteSink sink(binary_output);
+  StatusErrorListener listener;
+  converter::ProtoStreamObjectWriter::Options proto_writer_options;
+  proto_writer_options.ignore_unknown_fields = options.ignore_unknown_fields;
+  proto_writer_options.ignore_unknown_enum_values =
+      options.ignore_unknown_fields;
+  proto_writer_options.case_insensitive_enum_parsing =
+      options.case_insensitive_enum_parsing;
+  converter::ProtoStreamObjectWriter proto_writer(
+      resolver, type, &sink, &listener, proto_writer_options);
+
+  converter::JsonStreamParser parser(&proto_writer);
+  const void* buffer;
+  int length;
+  while (json_input->Next(&buffer, &length)) {
+    if (length == 0) continue;
+    RETURN_IF_ERROR(parser.Parse(
+        StringPiece(static_cast<const char*>(buffer), length)));
+  }
+  RETURN_IF_ERROR(parser.FinishParse());
+
+  return listener.GetStatus();
+}
+
+util::Status JsonToBinaryString(TypeResolver* resolver,
+                                const std::string& type_url,
+                                StringPiece json_input,
+                                std::string* binary_output,
+                                const JsonParseOptions& options) {
+  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,
+                            options);
+}
+
+namespace {
+const char* kTypeUrlPrefix = "type.googleapis.com";
+TypeResolver* generated_type_resolver_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag generated_type_resolver_init_;
+
+std::string GetTypeUrl(const Message& message) {
+  return std::string(kTypeUrlPrefix) + "/" +
+         message.GetDescriptor()->full_name();
+}
+
+void DeleteGeneratedTypeResolver() {  // NOLINT
+  delete generated_type_resolver_;
+}
+
+void InitGeneratedTypeResolver() {
+  generated_type_resolver_ = NewTypeResolverForDescriptorPool(
+      kTypeUrlPrefix, DescriptorPool::generated_pool());
+  ::google::protobuf::internal::OnShutdown(&DeleteGeneratedTypeResolver);
+}
+
+TypeResolver* GetGeneratedTypeResolver() {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(generated_type_resolver_init_,
+                                             InitGeneratedTypeResolver);
+  return generated_type_resolver_;
+}
+}  // namespace
+
+util::Status MessageToJsonString(const Message& message, std::string* output,
+                                 const JsonOptions& options) {
+  const DescriptorPool* pool = message.GetDescriptor()->file()->pool();
+  TypeResolver* resolver =
+      pool == DescriptorPool::generated_pool()
+          ? GetGeneratedTypeResolver()
+          : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool);
+  util::Status result =
+      BinaryToJsonString(resolver, GetTypeUrl(message),
+                         message.SerializeAsString(), output, options);
+  if (pool != DescriptorPool::generated_pool()) {
+    delete resolver;
+  }
+  return result;
+}
+
+util::Status JsonStringToMessage(StringPiece input, Message* message,
+                                 const JsonParseOptions& options) {
+  const DescriptorPool* pool = message->GetDescriptor()->file()->pool();
+  TypeResolver* resolver =
+      pool == DescriptorPool::generated_pool()
+          ? GetGeneratedTypeResolver()
+          : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool);
+  std::string binary;
+  util::Status result = JsonToBinaryString(resolver, GetTypeUrl(*message),
+                                           input, &binary, options);
+  if (result.ok() && !message->ParseFromString(binary)) {
+    result = util::InvalidArgumentError(
+        "JSON transcoder produced invalid protobuf output.");
+  }
+  if (pool != DescriptorPool::generated_pool()) {
+    delete resolver;
+  }
+  return result;
+}
+
+}  // 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..0f1c4d8
--- /dev/null
+++ b/src/google/protobuf/util/json_util.h
@@ -0,0 +1,204 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// 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/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/util/type_resolver.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+}  // namespace io
+namespace util {
+
+struct JsonParseOptions {
+  // Whether to ignore unknown JSON fields during parsing
+  bool ignore_unknown_fields;
+
+  // If true, when a lowercase enum value fails to parse, try convert it to
+  // UPPER_CASE and see if it matches a valid enum.
+  // WARNING: This option exists only to preserve legacy behavior. Avoid using
+  // this option. If your enum needs to support different casing, consider using
+  // allow_alias instead.
+  bool case_insensitive_enum_parsing;
+
+  JsonParseOptions()
+      : ignore_unknown_fields(false), case_insensitive_enum_parsing(false) {}
+};
+
+struct JsonPrintOptions {
+  // 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 proto3 primitive
+  // fields with default values will be omitted in JSON output. 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;
+  // Whether to always print enums as ints. By default they are rendered as
+  // strings.
+  bool always_print_enums_as_ints;
+  // Whether to preserve proto field names
+  bool preserve_proto_field_names;
+
+  JsonPrintOptions()
+      : add_whitespace(false),
+        always_print_primitive_fields(false),
+        always_print_enums_as_ints(false),
+        preserve_proto_field_names(false) {}
+};
+
+// DEPRECATED. Use JsonPrintOptions instead.
+typedef JsonPrintOptions JsonOptions;
+
+// Converts from protobuf message to JSON and appends it to |output|. This is a
+// simple wrapper of BinaryToJsonString(). It will use the DescriptorPool of the
+// passed-in message to resolve Any types.
+PROTOBUF_EXPORT util::Status MessageToJsonString(const Message& message,
+                                                 std::string* output,
+                                                 const JsonOptions& options);
+
+inline util::Status MessageToJsonString(const Message& message,
+                                        std::string* output) {
+  return MessageToJsonString(message, output, JsonOptions());
+}
+
+// Converts from JSON to protobuf message. This is a simple wrapper of
+// JsonStringToBinary(). It will use the DescriptorPool of the passed-in
+// message to resolve Any types.
+PROTOBUF_EXPORT util::Status JsonStringToMessage(
+    StringPiece input, Message* message, const JsonParseOptions& options);
+
+inline util::Status JsonStringToMessage(StringPiece input,
+                                        Message* message) {
+  return JsonStringToMessage(input, message, JsonParseOptions());
+}
+
+// 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.
+PROTOBUF_EXPORT util::Status BinaryToJsonStream(
+    TypeResolver* resolver, const std::string& type_url,
+    io::ZeroCopyInputStream* binary_input,
+    io::ZeroCopyOutputStream* json_output, const JsonPrintOptions& options);
+
+inline util::Status BinaryToJsonStream(TypeResolver* resolver,
+                                       const std::string& type_url,
+                                       io::ZeroCopyInputStream* binary_input,
+                                       io::ZeroCopyOutputStream* json_output) {
+  return BinaryToJsonStream(resolver, type_url, binary_input, json_output,
+                            JsonPrintOptions());
+}
+
+PROTOBUF_EXPORT util::Status BinaryToJsonString(
+    TypeResolver* resolver, const std::string& type_url,
+    const std::string& binary_input, std::string* json_output,
+    const JsonPrintOptions& options);
+
+inline util::Status BinaryToJsonString(TypeResolver* resolver,
+                                       const std::string& type_url,
+                                       const std::string& binary_input,
+                                       std::string* json_output) {
+  return BinaryToJsonString(resolver, type_url, binary_input, json_output,
+                            JsonPrintOptions());
+}
+
+// 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.
+PROTOBUF_EXPORT util::Status JsonToBinaryStream(
+    TypeResolver* resolver, const std::string& type_url,
+    io::ZeroCopyInputStream* json_input,
+    io::ZeroCopyOutputStream* binary_output, const JsonParseOptions& options);
+
+inline util::Status JsonToBinaryStream(
+    TypeResolver* resolver, const std::string& type_url,
+    io::ZeroCopyInputStream* json_input,
+    io::ZeroCopyOutputStream* binary_output) {
+  return JsonToBinaryStream(resolver, type_url, json_input, binary_output,
+                            JsonParseOptions());
+}
+
+PROTOBUF_EXPORT util::Status JsonToBinaryString(
+    TypeResolver* resolver, const std::string& type_url,
+    StringPiece json_input, std::string* binary_output,
+    const JsonParseOptions& options);
+
+inline util::Status JsonToBinaryString(TypeResolver* resolver,
+                                       const std::string& type_url,
+                                       StringPiece json_input,
+                                       std::string* binary_output) {
+  return JsonToBinaryString(resolver, type_url, json_input, binary_output,
+                            JsonParseOptions());
+}
+
+namespace internal {
+// Internal helper class. Put in the header so we can write unit-tests for it.
+class PROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
+ public:
+  explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
+      : stream_(stream), buffer_(nullptr), buffer_size_(0) {}
+  ~ZeroCopyStreamByteSink() override;
+
+  void Append(const char* bytes, size_t len) override;
+
+ private:
+  io::ZeroCopyOutputStream* stream_;
+  void* buffer_;
+  int buffer_size_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyStreamByteSink);
+};
+}  // namespace internal
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..7216199
--- /dev/null
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -0,0 +1,672 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <list>
+#include <string>
+
+#include <google/protobuf/util/internal/testdata/maps.pb.h>
+#include <google/protobuf/util/json_format.pb.h>
+#include <google/protobuf/util/json_format_proto3.pb.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/util/type_resolver_util.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+
+using proto3::BAR;
+using proto3::FOO;
+using proto3::TestAny;
+using proto3::TestEnumValue;
+using proto3::TestMap;
+using proto3::TestMessage;
+using proto3::TestOneof;
+using proto_util_converter::testing::MapIn;
+
+// 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() {}
+
+  std::string ToJson(const Message& message, const JsonPrintOptions& options) {
+    std::string result;
+    GOOGLE_CHECK_OK(MessageToJsonString(message, &result, options));
+    return result;
+  }
+
+  bool FromJson(const std::string& json, Message* message,
+                const JsonParseOptions& options) {
+    return JsonStringToMessage(json, message, options).ok();
+  }
+
+  bool FromJson(const std::string& json, Message* message) {
+    return FromJson(json, message, JsonParseOptions());
+  }
+
+  std::unique_ptr<TypeResolver> resolver_;
+};
+
+TEST_F(JsonUtilTest, TestWhitespaces) {
+  TestMessage m;
+  m.mutable_message_value();
+
+  JsonPrintOptions options;
+  EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options));
+  options.add_whitespace = true;
+  EXPECT_EQ(
+      "{\n"
+      " \"messageValue\": {}\n"
+      "}\n",
+      ToJson(m, options));
+}
+
+TEST_F(JsonUtilTest, TestDefaultValues) {
+  TestMessage m;
+  JsonPrintOptions options;
+  EXPECT_EQ("{}", ToJson(m, options));
+  options.always_print_primitive_fields = true;
+  EXPECT_EQ(
+      "{\"boolValue\":false,"
+      "\"int32Value\":0,"
+      "\"int64Value\":\"0\","
+      "\"uint32Value\":0,"
+      "\"uint64Value\":\"0\","
+      "\"floatValue\":0,"
+      "\"doubleValue\":0,"
+      "\"stringValue\":\"\","
+      "\"bytesValue\":\"\","
+      "\"enumValue\":\"FOO\","
+      "\"repeatedBoolValue\":[],"
+      "\"repeatedInt32Value\":[],"
+      "\"repeatedInt64Value\":[],"
+      "\"repeatedUint32Value\":[],"
+      "\"repeatedUint64Value\":[],"
+      "\"repeatedFloatValue\":[],"
+      "\"repeatedDoubleValue\":[],"
+      "\"repeatedStringValue\":[],"
+      "\"repeatedBytesValue\":[],"
+      "\"repeatedEnumValue\":[],"
+      "\"repeatedMessageValue\":[]"
+      "}",
+      ToJson(m, options));
+
+  options.always_print_primitive_fields = true;
+  m.set_string_value("i am a test string value");
+  m.set_bytes_value("i am a test bytes value");
+  EXPECT_EQ(
+      "{\"boolValue\":false,"
+      "\"int32Value\":0,"
+      "\"int64Value\":\"0\","
+      "\"uint32Value\":0,"
+      "\"uint64Value\":\"0\","
+      "\"floatValue\":0,"
+      "\"doubleValue\":0,"
+      "\"stringValue\":\"i am a test string value\","
+      "\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
+      "\"enumValue\":\"FOO\","
+      "\"repeatedBoolValue\":[],"
+      "\"repeatedInt32Value\":[],"
+      "\"repeatedInt64Value\":[],"
+      "\"repeatedUint32Value\":[],"
+      "\"repeatedUint64Value\":[],"
+      "\"repeatedFloatValue\":[],"
+      "\"repeatedDoubleValue\":[],"
+      "\"repeatedStringValue\":[],"
+      "\"repeatedBytesValue\":[],"
+      "\"repeatedEnumValue\":[],"
+      "\"repeatedMessageValue\":[]"
+      "}",
+      ToJson(m, options));
+
+  options.preserve_proto_field_names = true;
+  m.set_string_value("i am a test string value");
+  m.set_bytes_value("i am a test bytes value");
+  EXPECT_EQ(
+      "{\"bool_value\":false,"
+      "\"int32_value\":0,"
+      "\"int64_value\":\"0\","
+      "\"uint32_value\":0,"
+      "\"uint64_value\":\"0\","
+      "\"float_value\":0,"
+      "\"double_value\":0,"
+      "\"string_value\":\"i am a test string value\","
+      "\"bytes_value\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
+      "\"enum_value\":\"FOO\","
+      "\"repeated_bool_value\":[],"
+      "\"repeated_int32_value\":[],"
+      "\"repeated_int64_value\":[],"
+      "\"repeated_uint32_value\":[],"
+      "\"repeated_uint64_value\":[],"
+      "\"repeated_float_value\":[],"
+      "\"repeated_double_value\":[],"
+      "\"repeated_string_value\":[],"
+      "\"repeated_bytes_value\":[],"
+      "\"repeated_enum_value\":[],"
+      "\"repeated_message_value\":[]"
+      "}",
+      ToJson(m, options));
+}
+
+TEST_F(JsonUtilTest, TestPreserveProtoFieldNames) {
+  TestMessage m;
+  m.mutable_message_value();
+
+  JsonPrintOptions options;
+  options.preserve_proto_field_names = true;
+  EXPECT_EQ("{\"message_value\":{}}", ToJson(m, options));
+}
+
+TEST_F(JsonUtilTest, TestAlwaysPrintEnumsAsInts) {
+  TestMessage orig;
+  orig.set_enum_value(proto3::BAR);
+  orig.add_repeated_enum_value(proto3::FOO);
+  orig.add_repeated_enum_value(proto3::BAR);
+
+  JsonPrintOptions print_options;
+  print_options.always_print_enums_as_ints = true;
+
+  std::string expected_json = "{\"enumValue\":1,\"repeatedEnumValue\":[0,1]}";
+  EXPECT_EQ(expected_json, ToJson(orig, print_options));
+
+  TestMessage parsed;
+  JsonParseOptions parse_options;
+  ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
+
+  EXPECT_EQ(proto3::BAR, parsed.enum_value());
+  EXPECT_EQ(2, parsed.repeated_enum_value_size());
+  EXPECT_EQ(proto3::FOO, parsed.repeated_enum_value(0));
+  EXPECT_EQ(proto3::BAR, parsed.repeated_enum_value(1));
+}
+
+TEST_F(JsonUtilTest, TestPrintEnumsAsIntsWithDefaultValue) {
+  TestEnumValue orig;
+  // orig.set_enum_value1(proto3::FOO)
+  orig.set_enum_value2(proto3::FOO);
+  orig.set_enum_value3(proto3::BAR);
+
+  JsonPrintOptions print_options;
+  print_options.always_print_enums_as_ints = true;
+  print_options.always_print_primitive_fields = true;
+
+  std::string expected_json =
+      "{\"enumValue1\":0,\"enumValue2\":0,\"enumValue3\":1}";
+  EXPECT_EQ(expected_json, ToJson(orig, print_options));
+
+  TestEnumValue parsed;
+  JsonParseOptions parse_options;
+  ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
+
+  EXPECT_EQ(proto3::FOO, parsed.enum_value1());
+  EXPECT_EQ(proto3::FOO, parsed.enum_value2());
+  EXPECT_EQ(proto3::BAR, parsed.enum_value3());
+}
+
+TEST_F(JsonUtilTest, TestPrintProto2EnumAsIntWithDefaultValue) {
+  protobuf_unittest::TestDefaultEnumValue orig;
+
+  JsonPrintOptions print_options;
+  // use enum as int
+  print_options.always_print_enums_as_ints = true;
+  print_options.always_print_primitive_fields = true;
+
+  // result should be int rather than string
+  std::string expected_json = "{\"enumValue\":2}";
+  EXPECT_EQ(expected_json, ToJson(orig, print_options));
+
+  protobuf_unittest::TestDefaultEnumValue parsed;
+  JsonParseOptions parse_options;
+  ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
+
+  EXPECT_EQ(protobuf_unittest::DEFAULT, parsed.enum_value());
+}
+
+TEST_F(JsonUtilTest, ParseMessage) {
+  // Some random message but good enough to verify that the parsing wrapper
+  // functions are working properly.
+  std::string input =
+      "{\n"
+      "  \"int32Value\": 1234567891,\n"
+      "  \"int64Value\": 5302428716536692736,\n"
+      "  \"floatValue\": 3.4028235e+38,\n"
+      "  \"repeatedInt32Value\": [1, 2],\n"
+      "  \"messageValue\": {\n"
+      "    \"value\": 2048\n"
+      "  },\n"
+      "  \"repeatedMessageValue\": [\n"
+      "    {\"value\": 40}, {\"value\": 96}\n"
+      "  ]\n"
+      "}\n";
+  JsonParseOptions options;
+  TestMessage m;
+  ASSERT_TRUE(FromJson(input, &m, options));
+  EXPECT_EQ(1234567891, m.int32_value());
+  EXPECT_EQ(5302428716536692736, m.int64_value());
+  EXPECT_EQ(3.402823466e+38f, m.float_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;
+  JsonPrintOptions print_options;
+  JsonParseOptions parse_options;
+  EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, print_options));
+  TestMap other;
+  ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options));
+  EXPECT_EQ(message.DebugString(), other.DebugString());
+}
+
+TEST_F(JsonUtilTest, ParsePrimitiveMapIn) {
+  MapIn message;
+  JsonPrintOptions print_options;
+  print_options.always_print_primitive_fields = true;
+  JsonParseOptions parse_options;
+  EXPECT_EQ("{\"other\":\"\",\"things\":[],\"mapInput\":{},\"mapAny\":{}}",
+            ToJson(message, print_options));
+  MapIn other;
+  ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options));
+  EXPECT_EQ(message.DebugString(), other.DebugString());
+}
+
+TEST_F(JsonUtilTest, PrintPrimitiveOneof) {
+  TestOneof message;
+  JsonPrintOptions options;
+  options.always_print_primitive_fields = true;
+  message.mutable_oneof_message_value();
+  EXPECT_EQ("{\"oneofMessageValue\":{\"value\":0}}", ToJson(message, options));
+
+  message.set_oneof_int32_value(1);
+  EXPECT_EQ("{\"oneofInt32Value\":1}", ToJson(message, options));
+}
+
+TEST_F(JsonUtilTest, TestParseIgnoreUnknownFields) {
+  TestMessage m;
+  JsonParseOptions options;
+  options.ignore_unknown_fields = true;
+  EXPECT_TRUE(FromJson("{\"unknownName\":0}", &m, options));
+}
+
+TEST_F(JsonUtilTest, TestParseErrors) {
+  TestMessage m;
+  JsonParseOptions options;
+  // Parsing should fail if the field name can not be recognized.
+  EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m, options));
+  // Parsing should fail if the value is invalid.
+  EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m, options));
+}
+
+TEST_F(JsonUtilTest, TestDynamicMessage) {
+  // Some random message but good enough to test the wrapper functions.
+  std::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";
+
+  // Create a new DescriptorPool with the same protos as the generated one.
+  DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
+  DescriptorPool pool(&database);
+  // A dynamic version of the test proto.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message(
+      factory.GetPrototype(pool.FindMessageTypeByName("proto3.TestMessage"))
+          ->New());
+  EXPECT_TRUE(FromJson(input, message.get()));
+
+  // Convert to generated message for easy inspection.
+  TestMessage generated;
+  EXPECT_TRUE(generated.ParseFromString(message->SerializeAsString()));
+  EXPECT_EQ(1024, generated.int32_value());
+  ASSERT_EQ(2, generated.repeated_int32_value_size());
+  EXPECT_EQ(1, generated.repeated_int32_value(0));
+  EXPECT_EQ(2, generated.repeated_int32_value(1));
+  EXPECT_EQ(2048, generated.message_value().value());
+  ASSERT_EQ(2, generated.repeated_message_value_size());
+  EXPECT_EQ(40, generated.repeated_message_value(0).value());
+  EXPECT_EQ(96, generated.repeated_message_value(1).value());
+
+  JsonOptions options;
+  EXPECT_EQ(ToJson(generated, options), ToJson(*message, options));
+}
+
+TEST_F(JsonUtilTest, TestParsingUnknownAnyFields) {
+  std::string input =
+      "{\n"
+      "  \"value\": {\n"
+      "    \"@type\": \"type.googleapis.com/proto3.TestMessage\",\n"
+      "    \"unknown_field\": \"UNKNOWN_VALUE\",\n"
+      "    \"string_value\": \"expected_value\"\n"
+      "  }\n"
+      "}";
+
+  TestAny m;
+  JsonParseOptions options;
+  EXPECT_FALSE(FromJson(input, &m, options));
+
+  options.ignore_unknown_fields = true;
+  EXPECT_TRUE(FromJson(input, &m, options));
+
+  TestMessage t;
+  EXPECT_TRUE(m.value().UnpackTo(&t));
+  EXPECT_EQ("expected_value", t.string_value());
+}
+
+TEST_F(JsonUtilTest, TestParsingUnknownEnumsProto2) {
+  std::string input =
+      "{\n"
+      "  \"a\": \"UNKNOWN_VALUE\"\n"
+      "}";
+  protobuf_unittest::TestNumbers m;
+  JsonParseOptions options;
+  EXPECT_FALSE(FromJson(input, &m, options));
+
+  options.ignore_unknown_fields = true;
+  EXPECT_TRUE(FromJson(input, &m, options));
+  EXPECT_FALSE(m.has_a());
+}
+
+TEST_F(JsonUtilTest, TestParsingUnknownEnumsProto3) {
+  TestMessage m;
+  {
+    JsonParseOptions options;
+    ASSERT_FALSE(options.ignore_unknown_fields);
+    std::string input =
+        "{\n"
+        "  \"enum_value\":\"UNKNOWN_VALUE\"\n"
+        "}";
+    m.set_enum_value(proto3::BAR);
+    EXPECT_FALSE(FromJson(input, &m, options));
+    ASSERT_EQ(proto3::BAR, m.enum_value());  // Keep previous value
+
+    options.ignore_unknown_fields = true;
+    EXPECT_TRUE(FromJson(input, &m, options));
+    EXPECT_EQ(0, m.enum_value());  // Unknown enum value must be decoded as 0
+  }
+  // Integer values are read as usual
+  {
+    JsonParseOptions options;
+    std::string input =
+        "{\n"
+        "  \"enum_value\":12345\n"
+        "}";
+    m.set_enum_value(proto3::BAR);
+    EXPECT_TRUE(FromJson(input, &m, options));
+    ASSERT_EQ(12345, m.enum_value());
+
+    options.ignore_unknown_fields = true;
+    EXPECT_TRUE(FromJson(input, &m, options));
+    EXPECT_EQ(12345, m.enum_value());
+  }
+
+  // Trying to pass an object as an enum field value is always treated as an
+  // error
+  {
+    JsonParseOptions options;
+    std::string input =
+        "{\n"
+        "  \"enum_value\":{}\n"
+        "}";
+    options.ignore_unknown_fields = true;
+    EXPECT_FALSE(FromJson(input, &m, options));
+    options.ignore_unknown_fields = false;
+    EXPECT_FALSE(FromJson(input, &m, options));
+  }
+  // Trying to pass an array as an enum field value is always treated as an
+  // error
+  {
+    JsonParseOptions options;
+    std::string input =
+        "{\n"
+        "  \"enum_value\":[]\n"
+        "}";
+    EXPECT_FALSE(FromJson(input, &m, options));
+    options.ignore_unknown_fields = true;
+    EXPECT_FALSE(FromJson(input, &m, options));
+  }
+}
+
+TEST_F(JsonUtilTest, TestParsingEnumIgnoreCase) {
+  TestMessage m;
+  {
+    JsonParseOptions options;
+    std::string input =
+        "{\n"
+        "  \"enum_value\":\"bar\"\n"
+        "}";
+    m.set_enum_value(proto3::FOO);
+    EXPECT_FALSE(FromJson(input, &m, options));
+    // Default behavior is case-sensitive, so keep previous value.
+    ASSERT_EQ(proto3::FOO, m.enum_value());
+  }
+  {
+    JsonParseOptions options;
+    options.case_insensitive_enum_parsing = false;
+    std::string input =
+        "{\n"
+        "  \"enum_value\":\"bar\"\n"
+        "}";
+    m.set_enum_value(proto3::FOO);
+    EXPECT_FALSE(FromJson(input, &m, options));
+    ASSERT_EQ(proto3::FOO, m.enum_value());  // Keep previous value
+  }
+  {
+    JsonParseOptions options;
+    options.case_insensitive_enum_parsing = true;
+    std::string input =
+        "{\n"
+        "  \"enum_value\":\"bar\"\n"
+        "}";
+    m.set_enum_value(proto3::FOO);
+    EXPECT_TRUE(FromJson(input, &m, options));
+    ASSERT_EQ(proto3::BAR, m.enum_value());
+  }
+}
+
+typedef std::pair<char*, int> Segment;
+// A ZeroCopyOutputStream that writes to multiple buffers.
+class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
+ public:
+  explicit SegmentedZeroCopyOutputStream(std::list<Segment> segments)
+      : segments_(segments),
+        last_segment_(static_cast<char*>(NULL), 0),
+        byte_count_(0) {}
+
+  bool Next(void** buffer, int* length) override {
+    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;
+  }
+
+  void BackUp(int length) override {
+    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;
+  }
+
+  int64_t ByteCount() const override { return byte_count_; }
+
+ private:
+  std::list<Segment> segments_;
+  Segment last_segment_;
+  int64_t 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.
+    std::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.
+    std::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, std::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, std::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),
+                std::string(buffer, kOutputBufferLength));
+    }
+  }
+}
+
+TEST_F(JsonUtilTest, TestWrongJsonInput) {
+  const char json[] = "{\"unknown_field\":\"some_value\"}";
+  io::ArrayInputStream input_stream(json, strlen(json));
+  char proto_buffer[10000];
+  io::ArrayOutputStream output_stream(proto_buffer, sizeof(proto_buffer));
+  std::string message_type = "type.googleapis.com/proto3.TestMessage";
+  TypeResolver* resolver = NewTypeResolverForDescriptorPool(
+      "type.googleapis.com", DescriptorPool::generated_pool());
+
+  auto result_status = util::JsonToBinaryStream(resolver, message_type,
+                                                &input_stream, &output_stream);
+
+  delete resolver;
+
+  EXPECT_FALSE(result_status.ok());
+  EXPECT_TRUE(util::IsInvalidArgument(result_status));
+}
+
+TEST_F(JsonUtilTest, HtmlEscape) {
+  TestMessage m;
+  m.set_string_value("</script>");
+  JsonPrintOptions options;
+  EXPECT_EQ("{\"stringValue\":\"\\u003c/script\\u003e\"}", ToJson(m, options));
+}
+
+}  // 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..30560ed
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -0,0 +1,2246 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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.
+
+#include <google/protobuf/util/message_differencer.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.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/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/util/field_comparator.h>
+
+// Always include as last one, otherwise it can break compilation
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace util {
+
+namespace {
+
+std::string PrintShortTextFormat(const google::protobuf::Message& message) {
+  std::string debug_string;
+
+  google::protobuf::TextFormat::Printer printer;
+  printer.SetSingleLineMode(true);
+  printer.SetExpandAny(true);
+
+  printer.PrintToString(message, &debug_string);
+  // Single line mode currently might have an extra space at the end.
+  if (!debug_string.empty() && debug_string[debug_string.size() - 1] == ' ') {
+    debug_string.resize(debug_string.size() - 1);
+  }
+
+  return debug_string;
+}
+
+}  // namespace
+
+// A reporter to report the total number of diffs.
+// TODO(ykzhu): we can improve this to take into account the value differencers.
+class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Reporter {
+ public:
+  NumDiffsReporter() : num_diffs_(0) {}
+
+  // Returns the total number of diffs.
+  int32_t GetNumDiffs() const { return num_diffs_; }
+  void Reset() { num_diffs_ = 0; }
+
+  // Report that a field has been added into Message2.
+  void ReportAdded(
+      const google::protobuf::Message& /* message1 */,
+      const google::protobuf::Message& /* message2 */,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+      /*field_path*/) override {
+    ++num_diffs_;
+  }
+
+  // Report that a field has been deleted from Message1.
+  void ReportDeleted(
+      const google::protobuf::Message& /* message1 */,
+      const google::protobuf::Message& /* message2 */,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+      /*field_path*/) override {
+    ++num_diffs_;
+  }
+
+  // Report that the value of a field has been modified.
+  void ReportModified(
+      const google::protobuf::Message& /* message1 */,
+      const google::protobuf::Message& /* message2 */,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+      /*field_path*/) override {
+    ++num_diffs_;
+  }
+
+ private:
+  int32_t num_diffs_;
+};
+
+// 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 std::vector<std::vector<const FieldDescriptor*> >& key_field_paths)
+      : message_differencer_(message_differencer),
+        key_field_paths_(key_field_paths) {
+    GOOGLE_CHECK(!key_field_paths_.empty());
+    for (const auto& path : key_field_paths_) {
+      GOOGLE_CHECK(!path.empty());
+    }
+  }
+  MultipleFieldsMapKeyComparator(MessageDifferencer* message_differencer,
+                                 const FieldDescriptor* key)
+      : message_differencer_(message_differencer) {
+    std::vector<const FieldDescriptor*> key_field_path;
+    key_field_path.push_back(key);
+    key_field_paths_.push_back(key_field_path);
+  }
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
+    for (const auto& path : key_field_paths_) {
+      if (!IsMatchInternal(message1, message2, parent_fields, path, 0)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  bool IsMatchInternal(
+      const Message& message1, const Message& message2,
+      const std::vector<SpecificField>& parent_fields,
+      const std::vector<const FieldDescriptor*>& key_field_path,
+      int path_index) const {
+    const FieldDescriptor* field = key_field_path[path_index];
+    std::vector<SpecificField> current_parent_fields(parent_fields);
+    if (path_index == static_cast<int64_t>(key_field_path.size() - 1)) {
+      if (field->is_map()) {
+        return message_differencer_->CompareMapField(message1, message2, field,
+                                                     &current_parent_fields);
+      } else if (field->is_repeated()) {
+        return message_differencer_->CompareRepeatedField(
+            message1, message2, field, &current_parent_fields);
+      } else {
+        return message_differencer_->CompareFieldValueUsingParentFields(
+            message1, message2, field, -1, -1, &current_parent_fields);
+      }
+    } 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_;
+  std::vector<std::vector<const FieldDescriptor*> > key_field_paths_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
+};
+
+// Preserve the order when treating repeated field as SMART_LIST. The current
+// implementation is to find the longest matching sequence from the first
+// element. The optimal solution requires to use //util/diff/lcs.h, which is
+// not open sourced yet. Overwrite this method if you want to have that.
+// TODO(ykzhu): change to use LCS once it is open sourced.
+void MatchIndicesPostProcessorForSmartList(std::vector<int>* match_list1,
+                                           std::vector<int>* match_list2) {
+  int last_matched_index = -1;
+  for (size_t i = 0; i < match_list1->size(); ++i) {
+    if (match_list1->at(i) < 0) {
+      continue;
+    }
+    if (last_matched_index < 0 || match_list1->at(i) > last_matched_index) {
+      last_matched_index = match_list1->at(i);
+    } else {
+      match_list2->at(match_list1->at(i)) = -1;
+      match_list1->at(i) = -1;
+    }
+  }
+}
+
+void AddSpecificIndex(
+    google::protobuf::util::MessageDifferencer::SpecificField* specific_field,
+    const Message& message, const FieldDescriptor* field, int index) {
+  if (field->is_map()) {
+    const Reflection* reflection = message.GetReflection();
+    specific_field->map_entry1 =
+        &reflection->GetRepeatedMessage(message, field, index);
+  }
+  specific_field->index = index;
+}
+
+void AddSpecificNewIndex(
+    google::protobuf::util::MessageDifferencer::SpecificField* specific_field,
+    const Message& message, const FieldDescriptor* field, int index) {
+  if (field->is_map()) {
+    const Reflection* reflection = message.GetReflection();
+    specific_field->map_entry2 =
+        &reflection->GetRepeatedMessage(message, field, index);
+  }
+  specific_field->new_index = index;
+}
+
+MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
+    MessageDifferencer* message_differencer)
+    : message_differencer_(message_differencer) {}
+
+bool MessageDifferencer::MapEntryKeyComparator::IsMatch(
+    const Message& message1, const Message& message2,
+    const std::vector<SpecificField>& parent_fields) const {
+  // Map entry has its key in the field with tag 1.  See the comment for
+  // map_entry in MessageOptions.
+  const FieldDescriptor* key = message1.GetDescriptor()->FindFieldByNumber(1);
+  // If key is not present in message1 and we're doing partial comparison or if
+  // map key is explicitly ignored treat the field as set instead,
+  const bool treat_as_set =
+      (message_differencer_->scope() == PARTIAL &&
+       !message1.GetReflection()->HasField(message1, key)) ||
+      message_differencer_->IsIgnored(message1, message2, key, parent_fields);
+
+  std::vector<SpecificField> current_parent_fields(parent_fields);
+  if (treat_as_set) {
+    return message_differencer_->Compare(message1, message2,
+                                         &current_parent_fields);
+  }
+  return message_differencer_->CompareFieldValueUsingParentFields(
+      message1, message2, key, -1, -1, &current_parent_fields);
+}
+
+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),
+      message_field_comparison_(EQUAL),
+      scope_(FULL),
+      repeated_field_comparison_(AS_LIST),
+      map_entry_key_comparator_(this),
+      report_matches_(false),
+      report_moves_(true),
+      report_ignores_(true),
+      output_string_(nullptr),
+      match_indices_for_smart_list_callback_(
+          MatchIndicesPostProcessorForSmartList) {}
+
+MessageDifferencer::~MessageDifferencer() {
+  for (MapKeyComparator* comparator : owned_key_comparators_) {
+    delete comparator;
+  }
+  for (IgnoreCriteria* criteria : ignore_criteria_) {
+    delete criteria;
+  }
+}
+
+void MessageDifferencer::set_field_comparator(FieldComparator* comparator) {
+  GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
+  field_comparator_kind_ = kFCBase;
+  field_comparator_.base = comparator;
+}
+
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+void MessageDifferencer::set_field_comparator(
+    DefaultFieldComparator* comparator) {
+  GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
+  field_comparator_kind_ = kFCDefault;
+  field_comparator_.default_impl = comparator;
+}
+#endif  // PROTOBUF_FUTURE_BREAKING_CHANGES
+
+void MessageDifferencer::set_message_field_comparison(
+    MessageFieldComparison comparison) {
+  message_field_comparison_ = comparison;
+}
+
+MessageDifferencer::MessageFieldComparison
+MessageDifferencer::message_field_comparison() const {
+  return message_field_comparison_;
+}
+
+void MessageDifferencer::set_scope(Scope scope) { scope_ = scope; }
+
+MessageDifferencer::Scope MessageDifferencer::scope() const { 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;
+}
+
+MessageDifferencer::RepeatedFieldComparison
+MessageDifferencer::repeated_field_comparison() const {
+  return repeated_field_comparison_;
+}
+
+void MessageDifferencer::CheckRepeatedFieldComparisons(
+    const FieldDescriptor* field,
+    const RepeatedFieldComparison& new_comparison) {
+  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 " << new_comparison
+      << " for comparison.  Field name is: " << field->full_name();
+}
+
+void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SET);
+  repeated_field_comparisons_[field] = AS_SET;
+}
+
+void MessageDifferencer::TreatAsSmartSet(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SMART_SET);
+  repeated_field_comparisons_[field] = AS_SMART_SET;
+}
+
+void MessageDifferencer::SetMatchIndicesForSmartListCallback(
+    std::function<void(std::vector<int>*, std::vector<int>*)> callback) {
+  match_indices_for_smart_list_callback_ = callback;
+}
+
+void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_LIST);
+  repeated_field_comparisons_[field] = AS_LIST;
+}
+
+void MessageDifferencer::TreatAsSmartList(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SMART_LIST);
+  repeated_field_comparisons_[field] = AS_SMART_LIST;
+}
+
+void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
+                                    const FieldDescriptor* key) {
+  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(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: " << field->full_name();
+  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 std::vector<const FieldDescriptor*>& key_fields) {
+  std::vector<std::vector<const FieldDescriptor*> > key_field_paths;
+  for (const FieldDescriptor* key_filed : key_fields) {
+    std::vector<const FieldDescriptor*> key_field_path;
+    key_field_path.push_back(key_filed);
+    key_field_paths.push_back(key_field_path);
+  }
+  TreatAsMapWithMultipleFieldPathsAsKey(field, key_field_paths);
+}
+
+void MessageDifferencer::TreatAsMapWithMultipleFieldPathsAsKey(
+    const FieldDescriptor* field,
+    const std::vector<std::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 (const auto& key_field_path : key_field_paths) {
+    for (size_t 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(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: " << field->full_name();
+  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(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: " << field->full_name();
+  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(std::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 superseding 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) {
+  std::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.SetMessages(message1, message2);
+    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 std::vector<const FieldDescriptor*>& message1_fields_arg,
+    const std::vector<const FieldDescriptor*>& message2_fields_arg) {
+  if (message1.GetDescriptor() != message2.GetDescriptor()) {
+    GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
+                << "descriptors.";
+    return false;
+  }
+
+  std::vector<SpecificField> parent_fields;
+
+  bool result = false;
+
+  FieldDescriptorArray message1_fields(message1_fields_arg.size() + 1);
+  FieldDescriptorArray message2_fields(message2_fields_arg.size() + 1);
+
+  std::copy(message1_fields_arg.cbegin(), message1_fields_arg.cend(),
+            message1_fields.begin());
+  std::copy(message2_fields_arg.cbegin(), message2_fields_arg.cend(),
+            message2_fields.begin());
+
+  // Append sentinel values.
+  message1_fields[message1_fields_arg.size()] = nullptr;
+  message2_fields[message2_fields_arg.size()] = nullptr;
+
+  std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore);
+  std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore);
+
+  // 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,
+                                 std::vector<SpecificField>* parent_fields) {
+  const Descriptor* descriptor1 = message1.GetDescriptor();
+  const Descriptor* descriptor2 = message2.GetDescriptor();
+  if (descriptor1 != descriptor2) {
+    GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
+                << "descriptors. " << descriptor1->full_name() << " vs "
+                << descriptor2->full_name();
+    return false;
+  }
+
+  // Expand google.protobuf.Any payload if possible.
+  if (descriptor1->full_name() == internal::kAnyFullTypeName) {
+    std::unique_ptr<Message> data1;
+    std::unique_ptr<Message> data2;
+    if (unpack_any_field_.UnpackAny(message1, &data1) &&
+        unpack_any_field_.UnpackAny(message2, &data2)) {
+      // Avoid DFATAL for different descriptors in google.protobuf.Any payloads.
+      if (data1->GetDescriptor() != data2->GetDescriptor()) {
+        return false;
+      }
+      return Compare(*data1, *data2, parent_fields);
+    }
+  }
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  bool unknown_compare_result = true;
+  // Ignore unknown fields in EQUIVALENT mode
+  if (message_field_comparison_ != EQUIVALENT) {
+    const UnknownFieldSet& unknown_field_set1 =
+        reflection1->GetUnknownFields(message1);
+    const 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;
+    }
+  }
+
+  FieldDescriptorArray message1_fields = RetrieveFields(message1, true);
+  FieldDescriptorArray message2_fields = RetrieveFields(message2, false);
+
+  return CompareRequestedFieldsUsingSettings(message1, message2,
+                                             message1_fields, message2_fields,
+                                             parent_fields) &&
+         unknown_compare_result;
+}
+
+FieldDescriptorArray MessageDifferencer::RetrieveFields(const Message& message,
+                                                        bool base_message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+
+  tmp_message_fields_.clear();
+  tmp_message_fields_.reserve(descriptor->field_count() + 1);
+
+  const Reflection* reflection = message.GetReflection();
+  if (descriptor->options().map_entry()) {
+    if (this->scope_ == PARTIAL && base_message) {
+      reflection->ListFields(message, &tmp_message_fields_);
+    } else {
+      // Map entry fields are always considered present.
+      for (int i = 0; i < descriptor->field_count(); i++) {
+        tmp_message_fields_.push_back(descriptor->field(i));
+      }
+    }
+  } else {
+    reflection->ListFields(message, &tmp_message_fields_);
+  }
+  // Add sentinel values to deal with the
+  // case where the number of the fields in
+  // each list are different.
+  tmp_message_fields_.push_back(nullptr);
+
+  FieldDescriptorArray message_fields(tmp_message_fields_.begin(),
+                                      tmp_message_fields_.end());
+
+  return message_fields;
+}
+
+bool MessageDifferencer::CompareRequestedFieldsUsingSettings(
+    const Message& message1, const Message& message2,
+    const FieldDescriptorArray& message1_fields,
+    const FieldDescriptorArray& message2_fields,
+    std::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).
+      FieldDescriptorArray fields_union =
+          CombineFields(message1_fields, FULL, message2_fields, FULL);
+      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.
+      FieldDescriptorArray fields_intersection =
+          CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL);
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       fields_intersection, parent_fields);
+    }
+  }
+}
+
+FieldDescriptorArray MessageDifferencer::CombineFields(
+    const FieldDescriptorArray& fields1, Scope fields1_scope,
+    const FieldDescriptorArray& fields2, Scope fields2_scope) {
+  size_t index1 = 0;
+  size_t index2 = 0;
+
+  tmp_message_fields_.clear();
+
+  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) {
+        tmp_message_fields_.push_back(fields1[index1]);
+      }
+      ++index1;
+    } else if (FieldBefore(field2, field1)) {
+      if (fields2_scope == FULL) {
+        tmp_message_fields_.push_back(fields2[index2]);
+      }
+      ++index2;
+    } else {
+      tmp_message_fields_.push_back(fields1[index1]);
+      ++index1;
+      ++index2;
+    }
+  }
+
+  tmp_message_fields_.push_back(nullptr);
+
+  FieldDescriptorArray combined_fields(tmp_message_fields_.begin(),
+                                       tmp_message_fields_.end());
+
+  return combined_fields;
+}
+
+bool MessageDifferencer::CompareWithFieldsInternal(
+    const Message& message1, const Message& message2,
+    const FieldDescriptorArray& message1_fields,
+    const FieldDescriptorArray& message2_fields,
+    std::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);
+          if (report_ignores_) {
+            reporter_->ReportIgnored(message1, message2, *parent_fields);
+          }
+          parent_fields->pop_back();
+        }
+        ++field_index1;
+        continue;
+      }
+
+      if (reporter_ != NULL) {
+        assert(field1 != 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;
+          if (field1->is_repeated()) {
+            AddSpecificIndex(&specific_field, message1, field1, i);
+          } else {
+            specific_field.index = -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);
+          if (report_ignores_) {
+            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;
+          if (field2->is_repeated()) {
+            specific_field.index = i;
+            AddSpecificNewIndex(&specific_field, message2, field2, i);
+          } else {
+            specific_field.index = -1;
+            specific_field.new_index = -1;
+          }
+
+          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 guaranteed 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);
+        if (report_ignores_) {
+          reporter_->ReportIgnored(message1, message2, *parent_fields);
+        }
+        parent_fields->pop_back();
+      }
+
+      ++field_index1;
+      ++field_index2;
+      continue;
+    }
+
+    bool fieldDifferent = false;
+    assert(field1 != NULL);
+    if (field1->is_map()) {
+      fieldDifferent =
+          !CompareMapField(message1, message2, field1, parent_fields);
+    } else if (field1->is_repeated()) {
+      fieldDifferent =
+          !CompareRepeatedField(message1, message2, field1, parent_fields);
+    } else {
+      fieldDifferent = !CompareFieldValueUsingParentFields(
+          message1, message2, field1, -1, -1, parent_fields);
+
+      if (reporter_ != nullptr) {
+        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();
+      }
+    }
+    if (fieldDifferent) {
+      if (reporter_ == nullptr) return false;
+      isDifferent = true;
+    }
+    // Increment the field indices.
+    ++field_index1;
+    ++field_index2;
+  }
+
+  return !isDifferent;
+}
+
+bool MessageDifferencer::IsMatch(
+    const FieldDescriptor* repeated_field,
+    const MapKeyComparator* key_comparator, const Message* message1,
+    const Message* message2, const std::vector<SpecificField>& parent_fields,
+    Reporter* reporter, int index1, int index2) {
+  std::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_;
+  std::string* output_string = output_string_;
+  reporter_ = reporter;
+  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;
+    if (repeated_field->is_map()) {
+      specific_field.map_entry1 = &m1;
+      specific_field.map_entry2 = &m2;
+    }
+    specific_field.index = index1;
+    specific_field.new_index = index2;
+    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::CompareMapFieldByMapReflection(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* map_field, std::vector<SpecificField>* parent_fields,
+    DefaultFieldComparator* comparator) {
+  GOOGLE_DCHECK_EQ(nullptr, reporter_);
+  GOOGLE_DCHECK(map_field->is_map());
+  GOOGLE_DCHECK(map_field_key_comparator_.find(map_field) ==
+         map_field_key_comparator_.end());
+  GOOGLE_DCHECK_EQ(repeated_field_comparison_, AS_LIST);
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+  const int count1 = reflection1->MapSize(message1, map_field);
+  const int count2 = reflection2->MapSize(message2, map_field);
+  const bool treated_as_subset = IsTreatedAsSubset(map_field);
+  if (count1 != count2 && !treated_as_subset) {
+    return false;
+  }
+  if (count1 > count2) {
+    return false;
+  }
+
+  // First pass: check whether the same keys are present.
+  for (MapIterator it = reflection1->MapBegin(const_cast<Message*>(&message1),
+                                              map_field),
+                   it_end = reflection1->MapEnd(const_cast<Message*>(&message1),
+                                                map_field);
+       it != it_end; ++it) {
+    if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) {
+      return false;
+    }
+  }
+
+  // Second pass: compare values for matching keys.
+  const FieldDescriptor* val_des = map_field->message_type()->map_value();
+  switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD, COMPAREMETHOD)                           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                                  \
+    for (MapIterator it = reflection1->MapBegin(                              \
+                         const_cast<Message*>(&message1), map_field),         \
+                     it_end = reflection1->MapEnd(                            \
+                         const_cast<Message*>(&message1), map_field);         \
+         it != it_end; ++it) {                                                \
+      MapValueConstRef value2;                                                \
+      reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2); \
+      if (!comparator->Compare##COMPAREMETHOD(*val_des,                       \
+                                              it.GetValueRef().Get##METHOD(), \
+                                              value2.Get##METHOD())) {        \
+        return false;                                                         \
+      }                                                                       \
+    }                                                                         \
+    break;                                                                    \
+  }
+    HANDLE_TYPE(INT32, Int32Value, Int32);
+    HANDLE_TYPE(INT64, Int64Value, Int64);
+    HANDLE_TYPE(UINT32, UInt32Value, UInt32);
+    HANDLE_TYPE(UINT64, UInt64Value, UInt64);
+    HANDLE_TYPE(DOUBLE, DoubleValue, Double);
+    HANDLE_TYPE(FLOAT, FloatValue, Float);
+    HANDLE_TYPE(BOOL, BoolValue, Bool);
+    HANDLE_TYPE(STRING, StringValue, String);
+    HANDLE_TYPE(ENUM, EnumValue, Int32);
+#undef HANDLE_TYPE
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      for (MapIterator it = reflection1->MapBegin(
+               const_cast<Message*>(&message1), map_field);
+           it !=
+           reflection1->MapEnd(const_cast<Message*>(&message1), map_field);
+           ++it) {
+        if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) {
+          return false;
+        }
+        bool compare_result;
+        MapValueConstRef value2;
+        reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2);
+        // Append currently compared field to the end of parent_fields.
+        SpecificField specific_value_field;
+        specific_value_field.field = val_des;
+        parent_fields->push_back(specific_value_field);
+        compare_result = Compare(it.GetValueRef().GetMessageValue(),
+                                 value2.GetMessageValue(), parent_fields);
+        parent_fields->pop_back();
+        if (!compare_result) {
+          return false;
+        }
+      }
+      break;
+    }
+  }
+  return true;
+}
+
+bool MessageDifferencer::CompareMapField(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    std::vector<SpecificField>* parent_fields) {
+  GOOGLE_DCHECK(repeated_field->is_map());
+
+  // the input FieldDescriptor is guaranteed to be repeated field.
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  // When both map fields are on map, do not sync to repeated field.
+  if (reflection1->GetMapData(message1, repeated_field)->IsMapValid() &&
+      reflection2->GetMapData(message2, repeated_field)->IsMapValid() &&
+      // TODO(jieluo): Add support for reporter
+      reporter_ == nullptr &&
+      // Users didn't set custom map field key comparator
+      map_field_key_comparator_.find(repeated_field) ==
+          map_field_key_comparator_.end() &&
+      // Users didn't set repeated field comparison
+      repeated_field_comparison_ == AS_LIST &&
+      // Users didn't set their own FieldComparator implementation
+      field_comparator_kind_ == kFCDefault) {
+    const FieldDescriptor* key_des = repeated_field->message_type()->map_key();
+    const FieldDescriptor* val_des =
+        repeated_field->message_type()->map_value();
+    std::vector<SpecificField> current_parent_fields(*parent_fields);
+    SpecificField specific_field;
+    specific_field.field = repeated_field;
+    current_parent_fields.push_back(specific_field);
+    if (!IsIgnored(message1, message2, key_des, current_parent_fields) &&
+        !IsIgnored(message1, message2, val_des, current_parent_fields)) {
+      return CompareMapFieldByMapReflection(message1, message2, repeated_field,
+                                            &current_parent_fields,
+                                            field_comparator_.default_impl);
+    }
+  }
+
+  return CompareRepeatedRep(message1, message2, repeated_field, parent_fields);
+}
+
+bool MessageDifferencer::CompareRepeatedField(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    std::vector<SpecificField>* parent_fields) {
+  GOOGLE_DCHECK(!repeated_field->is_map());
+  return CompareRepeatedRep(message1, message2, repeated_field, parent_fields);
+}
+
+bool MessageDifferencer::CompareRepeatedRep(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    std::vector<SpecificField>* parent_fields) {
+  // the input FieldDescriptor is guaranteed to be repeated field.
+  GOOGLE_DCHECK(repeated_field->is_repeated());
+  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.
+  std::vector<int> match_list1;
+  std::vector<int> match_list2;
+
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(repeated_field);
+  bool smart_list = IsTreatedAsSmartList(repeated_field);
+  bool simple_list = key_comparator == nullptr &&
+                     !IsTreatedAsSet(repeated_field) &&
+                     !IsTreatedAsSmartSet(repeated_field) && !smart_list;
+
+  // For simple lists, we avoid matching repeated field indices, saving the
+  // memory allocations that would otherwise be needed for match_list1 and
+  // match_list2.
+  if (!simple_list) {
+    // Try to match indices of the repeated fields. Return false if match fails.
+    if (!MatchRepeatedFieldIndices(message1, message2, repeated_field,
+                                   key_comparator, *parent_fields, &match_list1,
+                                   &match_list2) &&
+        reporter_ == nullptr) {
+      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.
+  int next_unmatched_index = 0;
+  for (int i = 0; i < count1; i++) {
+    if (simple_list && i >= count2) {
+      break;
+    }
+    if (!simple_list && match_list1[i] == -1) {
+      if (smart_list) {
+        if (reporter_ == nullptr) return false;
+        AddSpecificIndex(&specific_field, message1, repeated_field, i);
+        parent_fields->push_back(specific_field);
+        reporter_->ReportDeleted(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+        fieldDifferent = true;
+        // Use -2 to mark this element has been reported.
+        match_list1[i] = -2;
+      }
+      continue;
+    }
+    if (smart_list) {
+      for (int j = next_unmatched_index; j < match_list1[i]; ++j) {
+        GOOGLE_CHECK_LE(0, j);
+        if (reporter_ == nullptr) return false;
+        specific_field.index = j;
+        AddSpecificNewIndex(&specific_field, message2, repeated_field, j);
+        parent_fields->push_back(specific_field);
+        reporter_->ReportAdded(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+        fieldDifferent = true;
+        // Use -2 to mark this element has been reported.
+        match_list2[j] = -2;
+      }
+    }
+    AddSpecificIndex(&specific_field, message1, repeated_field, i);
+    if (simple_list) {
+      AddSpecificNewIndex(&specific_field, message2, repeated_field, i);
+    } else {
+      AddSpecificNewIndex(&specific_field, message2, repeated_field,
+                          match_list1[i]);
+      next_unmatched_index = match_list1[i] + 1;
+    }
+
+    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 &&
+               !specific_field.field->is_map() && report_moves_) {
+      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 (!simple_list && match_list2[i] != -1) continue;
+    if (simple_list && i < count1) continue;
+    if (!treated_as_subset) {
+      fieldDifferent = true;
+    }
+
+    if (reporter_ == NULL) continue;
+    specific_field.index = i;
+    AddSpecificNewIndex(&specific_field, message2, repeated_field, 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 (!simple_list && match_list1[i] != -1) continue;
+    if (simple_list && i < count2) continue;
+    assert(reporter_ != NULL);
+    AddSpecificIndex(&specific_field, message1, repeated_field, 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,
+    std::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;
+      AddSpecificIndex(&specific_field, message1, field, index1);
+      AddSpecificNewIndex(&specific_field, message2, field, 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 std::vector<SpecificField>& field_path) {
+  for (const SpecificField& specific_field : field_path) {
+    // Don't check indexes for map entries -- maps are unordered.
+    if (specific_field.field != nullptr && specific_field.field->is_map())
+      continue;
+    if (specific_field.index != specific_field.new_index) return true;
+  }
+  return false;
+}
+
+bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SET;
+  }
+  return GetMapKeyComparator(field) == nullptr &&
+         repeated_field_comparison_ == AS_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartSet(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SMART_SET;
+  }
+  return GetMapKeyComparator(field) == nullptr &&
+         repeated_field_comparison_ == AS_SMART_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartList(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SMART_LIST;
+  }
+  return GetMapKeyComparator(field) == nullptr &&
+         repeated_field_comparison_ == AS_SMART_LIST;
+}
+
+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 std::vector<SpecificField>& parent_fields) {
+  if (ignored_fields_.find(field) != ignored_fields_.end()) {
+    return true;
+  }
+  for (IgnoreCriteria* criteria : ignore_criteria_) {
+    if (criteria->IsIgnored(message1, message2, field, parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MessageDifferencer::IsUnknownFieldIgnored(
+    const Message& message1, const Message& message2,
+    const SpecificField& field,
+    const std::vector<SpecificField>& parent_fields) {
+  for (IgnoreCriteria* criteria : ignore_criteria_) {
+    if (criteria->IsUnknownFieldIgnored(message1, message2, field,
+                                        parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+const MessageDifferencer::MapKeyComparator*
+MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) const {
+  if (!field->is_repeated()) return NULL;
+  FieldKeyComparatorMap::const_iterator it =
+      map_field_key_comparator_.find(field);
+  if (it != map_field_key_comparator_.end()) {
+    return it->second;
+  }
+  if (field->is_map()) {
+    // field cannot already be treated as list or set since TreatAsList() and
+    // TreatAsSet() call GetMapKeyComparator() and fail if it returns non-NULL.
+    return &map_entry_key_comparator_;
+  }
+  return NULL;
+}
+
+namespace {
+
+typedef std::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::UnpackAnyField::UnpackAny(
+    const Message& any, std::unique_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 std::string& type_url = reflection->GetString(any, type_url_field);
+  std::string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
+    return false;
+  }
+
+  const Descriptor* desc =
+      any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
+          full_type_name);
+  if (desc == NULL) {
+    GOOGLE_LOG(INFO) << "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());
+  std::string serialized_value = reflection->GetString(any, value_field);
+  if (!(*data)->ParsePartialFromString(serialized_value)) {
+    GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name;
+    return false;
+  }
+  return true;
+}
+
+bool MessageDifferencer::CompareUnknownFields(
+    const Message& message1, const Message& message2,
+    const UnknownFieldSet& unknown_field_set1,
+    const UnknownFieldSet& unknown_field_set2,
+    std::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.
+  std::vector<IndexUnknownFieldPair> fields1;  // unknown_field_set1, sorted
+  std::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.
+  size_t index1 = 0;
+  size_t 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 (report_ignores_ && reporter_ != NULL) {
+        parent_field->push_back(specific_field);
+        reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
+        parent_field->pop_back();
+      }
+      if (change_type != ADDITION) ++index1;
+      if (change_type != DELETION) ++index2;
+      continue;
+    }
+
+    if (change_type == ADDITION || change_type == DELETION ||
+        change_type == MODIFICATION) {
+      if (reporter_ == NULL) {
+        // We found a difference and we have no reporter.
+        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 std::function<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,
+                 std::vector<int>* match_list1, std::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, std::vector<bool>* visited);
+
+  int count1_;
+  int count2_;
+  NodeMatchCallback match_callback_;
+  std::map<std::pair<int, int>, bool> cached_match_results_;
+  std::vector<int>* match_list1_;
+  std::vector<int>* match_list2_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MaximumMatcher);
+};
+
+MaximumMatcher::MaximumMatcher(int count1, int count2,
+                               NodeMatchCallback callback,
+                               std::vector<int>* match_list1,
+                               std::vector<int>* match_list2)
+    : count1_(count1),
+      count2_(count2),
+      match_callback_(std::move(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) {
+    std::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 paths.
+  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) {
+  std::pair<int, int> p(left, right);
+  std::map<std::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_(left, right);
+  return cached_match_results_[p];
+}
+
+bool MaximumMatcher::FindArgumentPathDFS(int v, std::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 naive 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
+  // alternative 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 MapKeyComparator* key_comparator,
+    const std::vector<SpecificField>& parent_fields,
+    std::vector<int>* match_list1, std::vector<int>* match_list2) {
+  const int count1 =
+      message1.GetReflection()->FieldSize(message1, repeated_field);
+  const int count2 =
+      message2.GetReflection()->FieldSize(message2, repeated_field);
+  const bool is_treated_as_smart_set = IsTreatedAsSmartSet(repeated_field);
+
+  match_list1->assign(count1, -1);
+  match_list2->assign(count2, -1);
+  // Ensure that we don't report differences during the matching process. Since
+  // field comparators could potentially use this message differencer object to
+  // perform further comparisons, turn off reporting here and re-enable it
+  // before returning.
+  Reporter* reporter = reporter_;
+  reporter_ = NULL;
+  NumDiffsReporter num_diffs_reporter;
+  std::vector<int32_t> num_diffs_list1;
+  if (is_treated_as_smart_set) {
+    num_diffs_list1.assign(count1, std::numeric_limits<int32_t>::max());
+  }
+
+  bool success = true;
+  // Find potential match if this is a special repeated field.
+  if (scope_ == PARTIAL) {
+    // When partial matching is enabled, Compare(a, b) && Compare(a, c)
+    // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
+    // algorithm will fail to find a maximum matching.
+    // Here we use the augmenting path algorithm.
+    auto callback = [&](int i1, int i2) {
+      return IsMatch(repeated_field, key_comparator, &message1, &message2,
+                     parent_fields, nullptr, i1, i2);
+    };
+    MaximumMatcher matcher(count1, count2, std::move(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 == nullptr);
+    int match_count = matcher.FindMaximumMatch(early_return);
+    if (match_count != count1 && early_return) return false;
+    success = success && (match_count == count1);
+  } else {
+    int start_offset = 0;
+    // If the two repeated fields are treated as sets, optimize for the case
+    // where both start with same items stored in the same order.
+    if (IsTreatedAsSet(repeated_field) || is_treated_as_smart_set ||
+        IsTreatedAsSmartList(repeated_field)) {
+      start_offset = std::min(count1, count2);
+      for (int i = 0; i < count1 && i < count2; i++) {
+        if (IsMatch(repeated_field, key_comparator, &message1, &message2,
+                    parent_fields, nullptr, i, i)) {
+          match_list1->at(i) = i;
+          match_list2->at(i) = i;
+        } else {
+          start_offset = i;
+          break;
+        }
+      }
+    }
+    for (int i = start_offset; i < count1; ++i) {
+      // Indicates any matched elements for this repeated field.
+      bool match = false;
+      int matched_j = -1;
+
+      for (int j = start_offset; j < count2; j++) {
+        if (match_list2->at(j) != -1) {
+          if (!is_treated_as_smart_set || num_diffs_list1[i] == 0 ||
+              num_diffs_list1[match_list2->at(j)] == 0) {
+            continue;
+          }
+        }
+
+        if (is_treated_as_smart_set) {
+          num_diffs_reporter.Reset();
+          match = IsMatch(repeated_field, key_comparator, &message1, &message2,
+                          parent_fields, &num_diffs_reporter, i, j);
+        } else {
+          match = IsMatch(repeated_field, key_comparator, &message1, &message2,
+                          parent_fields, nullptr, i, j);
+        }
+
+        if (is_treated_as_smart_set) {
+          if (match) {
+            num_diffs_list1[i] = 0;
+          } else if (repeated_field->cpp_type() ==
+                     FieldDescriptor::CPPTYPE_MESSAGE) {
+            // Replace with the one with fewer diffs.
+            const int32_t num_diffs = num_diffs_reporter.GetNumDiffs();
+            if (num_diffs < num_diffs_list1[i]) {
+              // If j has been already matched to some element, ensure the
+              // current num_diffs is smaller.
+              if (match_list2->at(j) == -1 ||
+                  num_diffs < num_diffs_list1[match_list2->at(j)]) {
+                num_diffs_list1[i] = num_diffs;
+                match = true;
+              }
+            }
+          }
+        }
+
+        if (match) {
+          matched_j = j;
+          if (!is_treated_as_smart_set || num_diffs_list1[i] == 0) {
+            break;
+          }
+        }
+      }
+
+      match = (matched_j != -1);
+      if (match) {
+        if (is_treated_as_smart_set && match_list2->at(matched_j) != -1) {
+          // This is to revert the previously matched index in list2.
+          match_list1->at(match_list2->at(matched_j)) = -1;
+          match = false;
+        }
+        match_list1->at(i) = matched_j;
+        match_list2->at(matched_j) = i;
+      }
+      if (!match && reporter == nullptr) return false;
+      success = success && match;
+    }
+  }
+
+  if (IsTreatedAsSmartList(repeated_field)) {
+    match_indices_for_smart_list_callback_(match_list1, match_list2);
+  }
+
+  reporter_ = reporter;
+
+  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_kind_ == kFCBase
+                                    ? field_comparator_.base
+                                    : field_comparator_.default_impl;
+  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),
+      message1_(nullptr),
+      message2_(nullptr) {}
+
+MessageDifferencer::StreamReporter::StreamReporter(io::Printer* printer)
+    : printer_(printer),
+      delete_printer_(false),
+      report_modified_aggregates_(false),
+      message1_(nullptr),
+      message2_(nullptr) {}
+
+MessageDifferencer::StreamReporter::~StreamReporter() {
+  if (delete_printer_) delete printer_;
+}
+
+void MessageDifferencer::StreamReporter::PrintPath(
+    const std::vector<SpecificField>& field_path, bool left_side) {
+  for (size_t i = 0; i < field_path.size(); ++i) {
+    SpecificField specific_field = field_path[i];
+
+    if (specific_field.field != nullptr &&
+        specific_field.field->name() == "value") {
+      // check to see if this the value label of a map value.  If so, skip it
+      // because it isn't meaningful
+      if (i > 0 && field_path[i - 1].field->is_map()) {
+        continue;
+      }
+    }
+    if (i > 0) {
+      printer_->Print(".");
+    }
+    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());
+      }
+
+      if (specific_field.field->is_map()) {
+        PrintMapKey(left_side, specific_field);
+        continue;
+      }
+    } else {
+      printer_->PrintRaw(StrCat(specific_field.unknown_field_number));
+    }
+    if (left_side && specific_field.index >= 0) {
+      printer_->Print("[$name$]", "name", StrCat(specific_field.index));
+    }
+    if (!left_side && specific_field.new_index >= 0) {
+      printer_->Print("[$name$]", "name",
+                      StrCat(specific_field.new_index));
+    }
+  }
+}
+
+
+void MessageDifferencer::StreamReporter::PrintValue(
+    const Message& message, const std::vector<SpecificField>& field_path,
+    bool left_side) {
+  const SpecificField& specific_field = field_path.back();
+  const FieldDescriptor* field = specific_field.field;
+  if (field != NULL) {
+    std::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);
+      const FieldDescriptor* fd = nullptr;
+
+      if (field->is_map() && message1_ != nullptr && message2_ != nullptr) {
+        fd = field_message.GetDescriptor()->field(1);
+        if (fd->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          output = PrintShortTextFormat(
+              field_message.GetReflection()->GetMessage(field_message, fd));
+        } else {
+          TextFormat::PrintFieldValueToString(field_message, fd, -1, &output);
+        }
+      } else {
+        output = PrintShortTextFormat(field_message);
+      }
+      if (output.empty()) {
+        printer_->Print("{ }");
+      } else {
+        if ((fd != nullptr) &&
+            (fd->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)) {
+          printer_->PrintRaw(output);
+        } 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.";
+
+  std::string output;
+  switch (unknown_field->type()) {
+    case UnknownField::TYPE_VARINT:
+      output = StrCat(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 std::string& str) {
+  printer_->Print(str.c_str());
+}
+
+void MessageDifferencer::StreamReporter::PrintMapKey(
+    bool left_side, const SpecificField& specific_field) {
+  if (message1_ == nullptr || message2_ == nullptr) {
+    GOOGLE_LOG(INFO) << "PrintPath cannot log map keys; "
+                 "use SetMessages to provide the messages "
+                 "being compared prior to any processing.";
+    return;
+  }
+
+  const Message* found_message =
+      left_side ? specific_field.map_entry1 : specific_field.map_entry2;
+  std::string key_string = "";
+  if (found_message != nullptr) {
+    // NB: the map key is always the first field
+    const FieldDescriptor* fd = found_message->GetDescriptor()->field(0);
+    if (fd->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      // Not using PrintFieldValueToString for strings to avoid extra
+      // characters
+      key_string = found_message->GetReflection()->GetString(
+          *found_message, found_message->GetDescriptor()->field(0));
+    } else {
+      TextFormat::PrintFieldValueToString(*found_message, fd, -1, &key_string);
+    }
+    if (key_string.empty()) {
+      key_string = "''";
+    }
+    printer_->PrintRaw(StrCat("[", key_string, "]"));
+  }
+}
+
+void MessageDifferencer::StreamReporter::ReportAdded(
+    const Message& /*message1*/, const Message& message2,
+    const std::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 std::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 std::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 std::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 std::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 std::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::SetMessages(const Message& message1,
+                                                     const Message& message2) {
+  message1_ = &message1;
+  message2_ = &message2;
+}
+
+void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
+    const Message& /*message1*/, const Message& /*message2*/,
+    const std::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.
+}
+
+MessageDifferencer::MapKeyComparator*
+MessageDifferencer::CreateMultipleFieldsMapKeyComparator(
+    const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
+  return new MultipleFieldsMapKeyComparator(this, key_field_paths);
+}
+
+}  // 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..f63cd54
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer.h
@@ -0,0 +1,980 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+// Sep. 2020: Added option to output map keys in path
+
+#ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+#define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+
+
+#include <functional>
+#include <map>
+#include <memory>
+#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>
+
+// Always include as last one, otherwise it can break compilation
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class DynamicMessageFactory;
+class FieldDescriptor;
+
+namespace io {
+class ZeroCopyOutputStream;
+class Printer;
+}  // namespace io
+
+namespace util {
+
+class DefaultFieldComparator;
+class FieldContext;  // declared below MessageDifferencer
+
+// Defines a collection of field descriptors.
+// In case of internal google codebase we are using absl::FixedArray instead
+// of vector. It significantly speeds up proto comparison (by ~30%) by
+// reducing the number of malloc/free operations
+typedef std::vector<const FieldDescriptor*> FieldDescriptorArray;
+
+// 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, but it's not recommended for
+// performance critical code as it leads to extra allocations.
+class PROTOBUF_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 Compare() with IgnoreField()
+  // if some fields should be ignored in the comparison. Use Compare() with
+  // TreatAsSet() if there are repeated fields where ordering does not matter.
+  //
+  // 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:
+  // https://developers.google.com/protocol-buffers/docs/proto?csw=1#optional.
+  // 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 = nullptr;
+    int unknown_field_number = -1;
+    UnknownField::Type unknown_field_type = UnknownField::Type::TYPE_VARINT;
+
+    // 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 = -1;
+
+    // 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.  If the element
+    // has not moved, "new_index" will have the same value as "index".
+    int new_index = -1;
+
+    // If "field" is a map field, point to the map entry.
+    const Message* map_entry1 = nullptr;
+    const Message* map_entry2 = nullptr;
+
+    // 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 = nullptr;
+    const UnknownFieldSet* unknown_field_set2 = nullptr;
+
+    // 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 = -1;
+    int 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.
+  // Fields will be reported in PostTraversalOrder.
+  // For example, given following proto, if both baz and mooo are changed.
+  // foo {
+  //   bar {
+  //     baz: 1
+  //     mooo: 2
+  //   }
+  // }
+  // ReportModified will be invoked with following order:
+  // 1. foo.bar.baz or foo.bar.mooo
+  // 2. foo.bar.mooo or foo.bar.baz
+  // 2. foo.bar
+  // 3. foo
+  class PROTOBUF_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 std::vector<SpecificField>& field_path) = 0;
+
+    // Reports that a field has been deleted from Message1.
+    virtual void ReportDeleted(
+        const Message& message1, const Message& message2,
+        const std::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 std::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 std::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 std::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 std::vector<SpecificField>& /* field_path */) {}
+
+    // Report that an unknown 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 std::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 PROTOBUF_EXPORT MapKeyComparator {
+   public:
+    MapKeyComparator();
+    virtual ~MapKeyComparator();
+
+    virtual bool IsMatch(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const std::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 registered 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 PROTOBUF_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 std::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 std::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.
+              // See TreatAsSet(), as below.
+    AS_SMART_LIST,  // Similar to AS_SET, but preserve the order and find the
+                    // longest matching sequence from the first matching
+                    // element. To use an optimal solution, call
+                    // SetMatchIndicesForSmartListCallback() to pass it in.
+    AS_SMART_SET,   // Similar to AS_SET, but match elements with fewest diffs.
+  };
+
+  // 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.
+  //
+  // Note that despite the name of this method, this is really
+  // comparison as multisets: if one side of the comparison has a duplicate
+  // in the repeated field but the other side doesn't, this will count as
+  // a mismatch.
+  //
+  // 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 TreatAsMap*
+  void TreatAsSet(const FieldDescriptor* field);
+  void TreatAsSmartSet(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.
+  //
+  // REQUIRES: field->is_repeated() and field not registered with TreatAsMap*
+  void TreatAsList(const FieldDescriptor* field);
+  // Note that the complexity is similar to treating as SET.
+  void TreatAsSmartList(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 std::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 std::vector<std::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);
+
+  // Initiates and returns a new instance of MultipleFieldsMapKeyComparator.
+  MapKeyComparator* CreateMultipleFieldsMapKeyComparator(
+      const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths);
+
+  // 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);
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+  void set_field_comparator(DefaultFieldComparator* comparator);
+#endif  // PROTOBUF_FUTURE_BREAKING_CHANGES
+
+  // 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);
+
+  // Returns the current message field comparison used in this differencer.
+  MessageFieldComparison message_field_comparison() const;
+
+  // 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;
+  }
+
+  // Tells the differencer whether or not to report moves (in a set or map
+  // repeated field). This method must be called before Compare. The default for
+  // a new differencer is true.
+  void set_report_moves(bool report_moves) { report_moves_ = report_moves; }
+
+  // Tells the differencer whether or not to report ignored values. This method
+  // must be called before Compare. The default for a new differencer is true.
+  void set_report_ignores(bool report_ignores) {
+    report_ignores_ = report_ignores;
+  }
+
+  // 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() const;
+
+  // 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);
+
+  // Returns the current repeated field comparison used by this differencer.
+  RepeatedFieldComparison repeated_field_comparison() const;
+
+  // 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 std::vector<const FieldDescriptor*>& message1_fields,
+      const std::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(std::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);
+
+ private:
+  // Class for processing Any deserialization.  This logic is used by both the
+  // MessageDifferencer and StreamReporter classes.
+  class UnpackAnyField {
+   private:
+    std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_;
+
+   public:
+    UnpackAnyField() = default;
+    ~UnpackAnyField() = default;
+    // If "any" is of type google.protobuf.Any, extract its payload using
+    // DynamicMessageFactory and store in "data".
+    bool UnpackAny(const Message& any, std::unique_ptr<Message>* data);
+  };
+
+ public:
+  // 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 '$'.
+  //
+  // WARNING: this reporter does not necessarily flush its output until it is
+  // destroyed. As a result, it is not safe to assume the output is valid or
+  // complete until after you destroy the reporter. For example, if you use a
+  // StreamReporter to write to a StringOutputStream, the target string may
+  // contain uninitialized data until the reporter is destroyed.
+  class PROTOBUF_EXPORT StreamReporter : public Reporter {
+   public:
+    explicit StreamReporter(io::ZeroCopyOutputStream* output);
+    explicit StreamReporter(io::Printer* printer);  // delimiter '$'
+    ~StreamReporter() override;
+
+    // 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.
+
+    void ReportAdded(const Message& message1, const Message& message2,
+                     const std::vector<SpecificField>& field_path) override;
+
+    void ReportDeleted(const Message& message1, const Message& message2,
+                       const std::vector<SpecificField>& field_path) override;
+
+    void ReportModified(const Message& message1, const Message& message2,
+                        const std::vector<SpecificField>& field_path) override;
+
+    void ReportMoved(const Message& message1, const Message& message2,
+                     const std::vector<SpecificField>& field_path) override;
+
+    void ReportMatched(const Message& message1, const Message& message2,
+                       const std::vector<SpecificField>& field_path) override;
+
+    void ReportIgnored(const Message& message1, const Message& message2,
+                       const std::vector<SpecificField>& field_path) override;
+
+    void ReportUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const std::vector<SpecificField>& field_path) override;
+
+    // Messages that are being compared must be provided to StreamReporter prior
+    // to processing
+    void SetMessages(const Message& message1, const Message& message2);
+
+   protected:
+    // Prints the specified path of fields to the buffer.
+    virtual void PrintPath(const std::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 std::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 std::string& str);
+
+   private:
+    // helper function for PrintPath that contains logic for printing maps
+    void PrintMapKey(bool left_side, const SpecificField& specific_field);
+
+    io::Printer* printer_;
+    bool delete_printer_;
+    bool report_modified_aggregates_;
+    const Message* message1_;
+    const Message* message2_;
+    MessageDifferencer::UnpackAnyField unpack_any_field_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StreamReporter);
+  };
+
+ private:
+  friend class SimpleFieldComparator;
+
+  // 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;
+
+  // A MapKeyComparator for use with map_entries.
+  class PROTOBUF_EXPORT MapEntryKeyComparator : public MapKeyComparator {
+   public:
+    explicit MapEntryKeyComparator(MessageDifferencer* message_differencer);
+    bool IsMatch(
+        const Message& message1, const Message& message2,
+        const std::vector<SpecificField>& parent_fields) const override;
+
+   private:
+    MessageDifferencer* message_differencer_;
+  };
+
+  // Returns true if field1's number() is less than field2's.
+  static bool FieldBefore(const FieldDescriptor* field1,
+                          const FieldDescriptor* field2);
+
+  // Retrieve all the set fields, including extensions.
+  FieldDescriptorArray RetrieveFields(const Message& message,
+                                      bool base_message);
+
+  // 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.
+  FieldDescriptorArray CombineFields(const FieldDescriptorArray& fields1,
+                                     Scope fields1_scope,
+                                     const FieldDescriptorArray& fields2,
+                                     Scope fields2_scope);
+
+  // 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,
+               std::vector<SpecificField>* parent_fields);
+
+  // Compares all the unknown fields in two messages.
+  bool CompareUnknownFields(const Message& message1, const Message& message2,
+                            const UnknownFieldSet&, const UnknownFieldSet&,
+                            std::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 FieldDescriptorArray& message1_fields,
+      const FieldDescriptorArray& message2_fields,
+      std::vector<SpecificField>* parent_fields);
+
+  // Compares the specified messages with the specified field lists.
+  bool CompareWithFieldsInternal(const Message& message1,
+                                 const Message& message2,
+                                 const FieldDescriptorArray& message1_fields,
+                                 const FieldDescriptorArray& message2_fields,
+                                 std::vector<SpecificField>* parent_fields);
+
+  // Compares the repeated fields, and report the error.
+  bool CompareRepeatedField(const Message& message1, const Message& message2,
+                            const FieldDescriptor* field,
+                            std::vector<SpecificField>* parent_fields);
+
+  // Compares map fields, and report the error.
+  bool CompareMapField(const Message& message1, const Message& message2,
+                       const FieldDescriptor* field,
+                       std::vector<SpecificField>* parent_fields);
+
+  // Helper for CompareRepeatedField and CompareMapField: compares and reports
+  // differences element-wise. This is the implementation for non-map fields,
+  // and can also compare map fields by using the underlying representation.
+  bool CompareRepeatedRep(const Message& message1, const Message& message2,
+                          const FieldDescriptor* field,
+                          std::vector<SpecificField>* parent_fields);
+
+  // Helper for CompareMapField: compare the map fields using map reflection
+  // instead of sync to repeated.
+  bool CompareMapFieldByMapReflection(const Message& message1,
+                                      const Message& message2,
+                                      const FieldDescriptor* field,
+                                      std::vector<SpecificField>* parent_fields,
+                                      DefaultFieldComparator* comparator);
+
+  // 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,
+      std::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 std::vector<SpecificField>& parent_fields,
+               Reporter* reporter, int index1, int index2);
+
+  // Returns true when this repeated field has been configured to be treated
+  // as a Set / SmartSet / SmartList.
+  bool IsTreatedAsSet(const FieldDescriptor* field);
+  bool IsTreatedAsSmartSet(const FieldDescriptor* field);
+
+  bool IsTreatedAsSmartList(const FieldDescriptor* field);
+  // When treating as SMART_LIST, it uses MatchIndicesPostProcessorForSmartList
+  // by default to find the longest matching sequence from the first matching
+  // element. The callback takes two vectors showing the matching indices from
+  // the other vector, where -1 means an unmatch.
+  void SetMatchIndicesForSmartListCallback(
+      std::function<void(std::vector<int>*, std::vector<int>*)> callback);
+
+  // 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 std::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 std::vector<SpecificField>& parent_fields);
+
+  // Returns MapKeyComparator* when this field has been configured to be treated
+  // as a map or its is_map() return true.  If not, returns NULL.
+  const MapKeyComparator* GetMapKeyComparator(
+      const FieldDescriptor* field) const;
+
+  // 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.
+  // Assumes the repeated field is not treated as a simple list.
+  // 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 MapKeyComparator* key_comparator,
+      const std::vector<SpecificField>& parent_fields,
+      std::vector<int>* match_list1, std::vector<int>* match_list2);
+
+  // Checks if index is equal to new_index in all the specific fields.
+  static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields);
+
+  // CHECKs that the given repeated field can be compared according to
+  // new_comparison.
+  void CheckRepeatedFieldComparisons(
+      const FieldDescriptor* field,
+      const RepeatedFieldComparison& new_comparison);
+
+  // Defines a map between field descriptors and their MapKeyComparators.
+  // Used for repeated fields when they are configured as TreatAsMap.
+  typedef std::map<const FieldDescriptor*, const MapKeyComparator*>
+      FieldKeyComparatorMap;
+
+  // Defines a set to store field descriptors.  Used for repeated fields when
+  // they are configured as TreatAsSet.
+  typedef std::set<const FieldDescriptor*> FieldSet;
+  typedef std::map<const FieldDescriptor*, RepeatedFieldComparison> FieldMap;
+
+  Reporter* reporter_;
+  DefaultFieldComparator default_field_comparator_;
+  MessageFieldComparison message_field_comparison_;
+  Scope scope_;
+  RepeatedFieldComparison repeated_field_comparison_;
+
+  FieldMap repeated_field_comparisons_;
+  // 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.
+  std::vector<MapKeyComparator*> owned_key_comparators_;
+  FieldKeyComparatorMap map_field_key_comparator_;
+  MapEntryKeyComparator map_entry_key_comparator_;
+  std::vector<IgnoreCriteria*> ignore_criteria_;
+  // Reused multiple times in RetrieveFields to avoid extra allocations
+  std::vector<const FieldDescriptor*> tmp_message_fields_;
+
+  FieldSet ignored_fields_;
+
+  union {
+    DefaultFieldComparator* default_impl;
+    FieldComparator* base;
+  } field_comparator_ = {&default_field_comparator_};
+  enum { kFCDefault, kFCBase } field_comparator_kind_ = kFCDefault;
+
+  bool report_matches_;
+  bool report_moves_;
+  bool report_ignores_;
+
+  std::string* output_string_;
+
+  // Callback to post-process the matched indices to support SMART_LIST.
+  std::function<void(std::vector<int>*, std::vector<int>*)>
+      match_indices_for_smart_list_callback_;
+
+  MessageDifferencer::UnpackAnyField unpack_any_field_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer);
+};
+
+// This class provides extra information to the FieldComparator::Compare
+// function.
+class PROTOBUF_EXPORT FieldContext {
+ public:
+  explicit FieldContext(
+      std::vector<MessageDifferencer::SpecificField>* parent_fields)
+      : parent_fields_(parent_fields) {}
+
+  std::vector<MessageDifferencer::SpecificField>* parent_fields() const {
+    return parent_fields_;
+  }
+
+ private:
+  std::vector<MessageDifferencer::SpecificField>* parent_fields_;
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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 100644
index 0000000..f8e44df
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -0,0 +1,3809 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <random>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/any_test.pb.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/map_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/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/util/message_differencer_unittest.pb.h>
+#include <google/protobuf/util/field_comparator.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+
+const FieldDescriptor* GetFieldDescriptor(const Message& message,
+                                          const std::string& field_name) {
+  std::vector<std::string> field_path =
+      Split(field_name, ".", true);
+  const Descriptor* descriptor = message.GetDescriptor();
+  const FieldDescriptor* field = nullptr;
+  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, RepeatedFieldSetOptimizationTest) {
+  util::MessageDifferencer differencer;
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestDiffMessage::Item* item1 = msg1.add_item();
+  protobuf_unittest::TestDiffMessage::Item* item2 = msg2.add_item();
+  differencer.TreatAsSet(item1->GetDescriptor()->FindFieldByName("ra"));
+  differencer.TreatAsSet(item2->GetDescriptor()->FindFieldByName("ra"));
+  for (int i = 0; i < 1000; i++) {
+    item1->add_ra(i);
+    item2->add_ra(i);
+  }
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  item2->add_ra(1001);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  item1->add_ra(1001);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  item1->add_ra(1002);
+  EXPECT_FALSE(differencer.Compare(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));
+
+  // Get map entries by index will sync map to repeated field
+  MapTestUtil::GetMapEntries(msg1, 0);
+  EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2));
+
+  // Compare values not match
+  (*msg1.mutable_map_int32_int32())[1] = 2;
+  (*msg2.mutable_map_int32_int32())[1] = 3;
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+
+  // Compare keys not match
+  msg1.Clear();
+  msg2.Clear();
+  (*msg1.mutable_map_string_string())["1"] = "";
+  (*msg2.mutable_map_string_string())["2"] = "";
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+
+  // Compare message values not match
+  msg1.Clear();
+  msg2.Clear();
+  (*msg1.mutable_map_int32_foreign_message())[1].set_c(1);
+  (*msg2.mutable_map_int32_foreign_message())[1].set_c(2);
+  EXPECT_FALSE(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 comparator, with a default fraction and margin for
+  // float and double comparison.
+  util::DefaultFieldComparator field_comparator;
+  field_comparator.SetDefaultFractionAndMargin(0.0, 10.0);
+  differencer.set_field_comparator(&field_comparator);
+
+  // Set comparison to exact, margin and fraction value should not matter.
+  field_comparator.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_comparator.set_float_comparison(
+      util::DefaultFieldComparator::APPROXIMATE);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Test out comparison with fraction.
+  field_comparator.SetDefaultFractionAndMargin(0.2, 0.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Should fail since the fraction is smaller than error.
+  field_comparator.SetDefaultFractionAndMargin(0.01, 0.0);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Should pass if either fraction or margin are satisfied.
+  field_comparator.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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  std::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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  std::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);
+
+  std::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);
+
+  std::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.
+    std::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.
+    std::vector<const FieldDescriptor*> compare_fields1;
+    std::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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  std::vector<const FieldDescriptor*> fields2;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+  msg2.GetReflection()->ListFields(msg2, &fields2);
+
+  std::default_random_engine rng;
+  std::shuffle(fields1.begin(), fields1.end(), rng);
+  std::shuffle(fields2.begin(), fields2.end(), rng);
+
+  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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+
+  std::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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  const Reflection* reflection = msg1.GetReflection();
+  reflection->ListFields(msg1, &fields1);
+
+  std::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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+
+  std::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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  std::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 != nullptr);
+  ASSERT_TRUE(optional_int64_desc != nullptr);
+  ASSERT_TRUE(default_int64_desc != nullptr);
+  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);
+
+  std::vector<const FieldDescriptor*> fields1;
+  std::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, RepeatedFieldTreatmentChangeListToSet) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  msg1.add_rv(1);
+  msg1.add_rv(2);
+  msg2.add_rv(2);
+  msg2.add_rv(1);
+
+  util::MessageDifferencer differencer;
+  differencer.TreatAsList(
+      protobuf_unittest::TestDiffMessage::descriptor()->FindFieldByName("rv"));
+  differencer.TreatAsSet(
+      protobuf_unittest::TestDiffMessage::descriptor()->FindFieldByName("rv"));
+
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldTreatmentChangeSetToList) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  msg1.add_rv(1);
+  msg1.add_rv(2);
+  msg2.add_rv(2);
+  msg2.add_rv(1);
+
+  util::MessageDifferencer differencer;
+  differencer.TreatAsSet(
+      protobuf_unittest::TestDiffMessage::descriptor()->FindFieldByName("rv"));
+  differencer.TreatAsList(
+      protobuf_unittest::TestDiffMessage::descriptor()->FindFieldByName("rv"));
+
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartListTest) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  msg1.add_rv(1);
+  msg1.add_rv(2);
+  msg1.add_rv(3);
+  msg1.add_rv(9);
+  msg1.add_rv(4);
+  msg1.add_rv(5);
+  msg1.add_rv(7);
+  msg1.add_rv(2);
+  msg2.add_rv(9);
+  msg2.add_rv(0);
+  msg2.add_rv(2);
+  msg2.add_rv(7);
+  msg2.add_rv(3);
+  msg2.add_rv(4);
+  msg2.add_rv(5);
+  msg2.add_rv(6);
+  msg2.add_rv(2);
+  // Compare
+  // a: 1,      2,    3, 9, 4, 5, 7,   2
+  // b:   9, 0, 2, 7, 3,    4, 5,   6, 2
+  std::string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_LIST);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "deleted: rv[0]: 1\n"
+      "added: rv[0]: 9\n"
+      "added: rv[1]: 0\n"
+      "moved: rv[1] -> rv[2] : 2\n"
+      "added: rv[3]: 7\n"
+      "moved: rv[2] -> rv[4] : 3\n"
+      "deleted: rv[3]: 9\n"
+      "moved: rv[4] -> rv[5] : 4\n"
+      "moved: rv[5] -> rv[6] : 5\n"
+      "deleted: rv[6]: 7\n"
+      "added: rv[7]: 6\n"
+      "moved: rv[7] -> rv[8] : 2\n",
+      diff_report);
+
+  // Compare two sub messages
+  // a: 1, 2, 3,    4, 5
+  // b:    2,    6, 4,
+  msg1.Clear();
+  msg2.Clear();
+  msg1.add_rm()->set_a(1);
+  msg1.add_rm()->set_a(2);
+  msg1.add_rm()->set_a(3);
+  msg1.add_rm()->set_a(4);
+  msg1.add_rm()->set_a(5);
+  msg2.add_rm()->set_a(2);
+  msg2.add_rm()->set_a(6);
+  msg2.add_rm()->set_a(4);
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_LIST);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "deleted: rm[0]: { a: 1 }\n"
+      "moved: rm[1] -> rm[0] : { a: 2 }\n"
+      "deleted: rm[2]: { a: 3 }\n"
+      "added: rm[1]: { a: 6 }\n"
+      "moved: rm[3] -> rm[2] : { a: 4 }\n"
+      "deleted: rm[4]: { a: 5 }\n",
+      diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem1_1, elem2_1, elem3_1;
+  protobuf_unittest::TestField elem1_2, elem2_2, elem3_2;
+
+  // Only one field is different for each pair of elememts
+  elem1_1.set_a(1);
+  elem1_2.set_a(0);
+  elem1_1.set_b(1);
+  elem1_2.set_b(1);
+  elem1_1.set_c(1);
+  elem1_2.set_c(1);
+  elem2_1.set_a(2);
+  elem2_2.set_a(2);
+  elem2_1.set_b(2);
+  elem2_2.set_b(0);
+  elem2_1.set_c(2);
+  elem2_2.set_c(2);
+  elem3_1.set_a(3);
+  elem3_2.set_a(3);
+  elem3_1.set_b(3);
+  elem3_2.set_b(0);
+  elem3_1.set_c(3);
+  elem3_2.set_c(3);
+
+  *msg1.add_rm() = elem1_1;
+  *msg1.add_rm() = elem2_1;
+  *msg1.add_rm() = elem3_1;
+  // Change the order of those elements for the second message.
+  *msg2.add_rm() = elem3_2;
+  *msg2.add_rm() = elem1_2;
+  *msg2.add_rm() = elem2_2;
+
+  std::string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: rm[0].a -> rm[1].a: 1 -> 0\n"
+      "modified: rm[1].b -> rm[2].b: 2 -> 0\n"
+      "modified: rm[2].b -> rm[0].b: 3 -> 0\n",
+      diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest_IdenticalElements) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem;
+
+  elem.set_a(1);
+  elem.set_b(1);
+  elem.set_c(1);
+
+  *msg1.add_rm() = elem;
+  *msg1.add_rm() = elem;
+  *msg2.add_rm() = elem;
+  *msg2.add_rm() = elem;
+
+  util::MessageDifferencer differencer;
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest_PreviouslyMatch) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem1_1, elem1_2;
+  protobuf_unittest::TestField elem2_1, elem2_2;
+
+  elem1_1.set_a(1);
+  elem1_1.set_b(1);
+  elem1_1.set_c(1);
+  elem1_2.set_a(1);
+  elem1_2.set_b(1);
+  elem1_2.set_c(0);
+
+  elem2_1.set_a(1);
+  elem2_1.set_b(1);
+  elem2_1.set_c(1);
+  elem2_2.set_a(1);
+  elem2_2.set_b(0);
+  elem2_2.set_c(1);
+
+  *msg1.add_rm() = elem1_1;
+  *msg1.add_rm() = elem2_1;
+  *msg2.add_rm() = elem1_2;
+  *msg2.add_rm() = elem2_2;
+
+  std::string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: rm[0].c: 1 -> 0\n"
+      "modified: rm[1].b: 1 -> 0\n",
+      diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSet_MultipleMatches) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem1_1, elem2_1, elem3_1;
+  protobuf_unittest::TestField elem2_2, elem3_2;
+
+  // Only one field is different for each pair of elememts
+  elem1_1.set_a(1);
+  elem1_1.set_b(1);
+  elem1_1.set_c(1);
+  elem2_1.set_a(2);
+  elem2_2.set_a(2);
+  elem2_1.set_b(2);
+  elem2_2.set_b(0);
+  elem2_1.set_c(2);
+  elem2_2.set_c(2);
+  elem3_1.set_a(3);
+  elem3_2.set_a(3);
+  elem3_1.set_b(3);
+  elem3_2.set_b(0);
+  elem3_1.set_c(3);
+  elem3_2.set_c(3);
+
+  // In this testcase, elem1_1 will match with elem2_2 first and then get
+  // reverted because elem2_1 matches with elem2_2 later.
+  *msg1.add_rm() = elem1_1;
+  *msg1.add_rm() = elem2_1;
+  *msg1.add_rm() = elem3_1;
+  *msg2.add_rm() = elem2_2;
+  *msg2.add_rm() = elem3_2;
+
+  std::string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: rm[1].b -> rm[0].b: 2 -> 0\n"
+      "modified: rm[2].b -> rm[1].b: 3 -> 0\n"
+      "deleted: rm[0]: { c: 1 a: 1 b: 1 }\n",
+      diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSet_MultipleMatchesNoReporter) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem1, elem2, elem3, elem4;
+  elem1.set_a(1);
+  elem2.set_a(2);
+  elem3.set_a(3);
+  elem4.set_a(4);
+
+  *msg1.add_rm() = elem1;
+  *msg1.add_rm() = elem2;
+  *msg1.add_rm() = elem3;
+  *msg2.add_rm() = elem2;
+  *msg2.add_rm() = elem3;
+  *msg2.add_rm() = elem4;
+
+  util::MessageDifferencer differencer;
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSet_NonMessageTypeTest) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  // Create 3 elements, but in different order.
+  msg1.add_rw("b");
+  msg2.add_rw("a");
+  msg1.add_rw("x");
+  msg2.add_rw("x");
+  msg1.add_rw("a");
+  msg2.add_rw("b");
+
+  std::string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "moved: rw[0] -> rw[2] : \"b\"\n"
+      "moved: rw[2] -> rw[0] : \"a\"\n",
+      diff_report);
+}
+
+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));
+  std::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");
+  std::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));
+  std::vector<std::vector<const FieldDescriptor*> > key_field_paths;
+  std::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"));
+  std::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");
+  std::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;
+  std::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);
+  std::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);
+}
+
+TEST(MessageDifferencerTest, PrintMapKeysTest) {
+  // Note that because map is unordered, the comparison
+  // output string for test evaluation cannot assume order of
+  // output of fields (IOW if two fields are deleted
+  // one cannot assume which deleted field log will be printed first).
+  // Test currently just has a single record per operation to address this.
+  // This should only be a limitation for EXPECT_EQ evaluation.
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->mutable_mp()->insert({{"key_a", 1}, {"key_b", 2}, {"key_c", 3}});
+  item = msg2.add_item();
+  item->mutable_mp()->insert({{"key_a", 1}, {"key_b", 3}, {"key_d", 4}});
+
+  util::MessageDifferencer differencer;
+  std::string diff;
+  differencer.ReportDifferencesToString(&diff);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: item[0].mp[key_b]: 2 -> 3\n"
+      "added: item[0].mp[key_d]: 4\n"
+      "deleted: item[0].mp[key_c]: 3\n",
+      diff);
+
+  google::protobuf::Any any1, any2;
+  any1.PackFrom(msg1);
+  any2.PackFrom(msg2);
+  std::string diff_with_any;
+  differencer.ReportDifferencesToString(&diff_with_any);
+  EXPECT_FALSE(differencer.Compare(any1, any2));
+  EXPECT_EQ(
+      "modified: item[0].mp[key_b]: 2 -> 3\n"
+      "added: item[0].mp[key_d]: 4\n"
+      "deleted: item[0].mp[key_c]: 3\n",
+      diff_with_any);
+}
+
+static const char* const kIgnoredFields[] = {"rm.b", "rm.m.b"};
+
+class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria {
+ public:
+  bool IsIgnored(const Message& message1, const Message& message2,
+                 const FieldDescriptor* field,
+                 const std::vector<util::MessageDifferencer::SpecificField>&
+                     parent_fields) override {
+    std::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;
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
+    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);
+  std::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);
+}
+
+// Compares fields by their index offset by one, so index 0 matches with 1, etc.
+class OffsetByOneMapKeyComparator
+    : public util::MessageDifferencer::MapKeyComparator {
+ public:
+  typedef util::MessageDifferencer::SpecificField SpecificField;
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
+    return parent_fields.back().index + 1 == parent_fields.back().new_index;
+  }
+};
+
+TEST(MessageDifferencerTest, RepeatedFieldMapTest_CustomIndexMapKeyComparator) {
+  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->set_b("one");
+  item = msg2.add_item();
+  item->set_b("zero");
+  item = msg2.add_item();
+  item->set_b("one");
+  util::MessageDifferencer differencer;
+  OffsetByOneMapKeyComparator key_comparator;
+  differencer.TreatAsMapUsingKeyComparator(GetFieldDescriptor(msg1, "item"),
+                                           &key_comparator);
+  std::string output;
+  differencer.ReportDifferencesToString(&output);
+  // With the offset by one comparator msg1.item[0] should be compared to
+  // msg2.item[1] and thus be moved, msg2.item[0] should be marked as added.
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "moved: item[0] -> item[1] : { b: \"one\" }\n"
+      "added: item[0]: { b: \"zero\" }\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");
+
+  std::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(MessageDifferencerTest, IgnoreField_SetReportIgnoresFalse) {
+  protobuf_unittest::TestField msg1;
+  protobuf_unittest::TestField msg2;
+
+  msg1.set_a(1);
+  msg1.set_b(2);
+  msg1.set_c(3);
+  msg1.add_rc(1);
+  msg1.add_rc(2);
+
+  msg2.set_a(1);
+  msg2.set_b(1);
+
+  const FieldDescriptor* a = GetFieldDescriptor(msg1, "a");
+  const FieldDescriptor* b = GetFieldDescriptor(msg1, "b");
+  const FieldDescriptor* c = GetFieldDescriptor(msg1, "c");
+  const FieldDescriptor* rc = GetFieldDescriptor(msg1, "rc");
+
+  std::vector<const FieldDescriptor*> fields;
+  fields.push_back(a);
+  fields.push_back(b);
+  fields.push_back(c);
+  fields.push_back(rc);
+
+  std::string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.set_report_ignores(false);
+  differencer.set_report_matches(true);
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.IgnoreField(c);
+  differencer.IgnoreField(rc);
+  differencer.set_scope(util::MessageDifferencer::FULL);
+  EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2, fields, fields));
+
+  EXPECT_EQ(diff_report,
+            "matched: a : 1\n"
+            "modified: b: 2 -> 1\n");
+}
+
+
+// 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() {}
+
+  ComparisonResult Compare(const Message& message_1, const Message& message_2,
+                           const FieldDescriptor* field, int index_1,
+                           int index_2,
+                           const util::FieldContext* field_context) override {
+    if (field_context) parent_fields_ = *(field_context->parent_fields());
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      return RECURSE;
+    } else {
+      return SAME;
+    }
+  }
+
+  std::vector<util::MessageDifferencer::SpecificField> parent_fields() {
+    return parent_fields_;
+  }
+
+ private:
+  std::vector<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() override {}
+
+  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_));
+    }
+  }
+
+  std::string Run(const Message& msg1, const Message& msg2) {
+    std::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;
+  }
+
+  std::string Run() { return Run(proto1_, proto2_); }
+
+  std::string RunOrder() { return Run(orderings_proto1_, orderings_proto2_); }
+
+  std::string RunEx() { return Run(proto1ex_, proto2ex_); }
+
+  std::string RunDiff() { return Run(proto1diff_, proto2diff_); }
+
+  std::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 std::string& field) { set_field_ = field; }
+
+  void field_as_map(const std::string& field, const std::string& key) {
+    map_field_ = field;
+    map_key_ = key;
+  }
+
+  void ignore_field(const std::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_;
+
+  unittest::TestMap map_proto1_;
+  unittest::TestMap map_proto2_;
+
+  UnknownFieldSet* unknown1_;
+  UnknownFieldSet* unknown2_;
+
+  bool use_equivalency_;
+  bool repeated_field_as_set_;
+
+  std::string set_field_;
+  std::string map_field_;
+  std::string map_key_;
+  std::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 doesn'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));
+}
+
+TEST_F(ComparisonTest, MapTest) {
+  Map<std::string, std::string>& map1 =
+      *map_proto1_.mutable_map_string_string();
+  map1["key1"] = "1";
+  map1["key2"] = "2";
+  map1["key3"] = "3";
+  Map<std::string, std::string>& map2 =
+      *map_proto2_.mutable_map_string_string();
+  map2["key3"] = "0";
+  map2["key2"] = "2";
+  map2["key1"] = "1";
+
+  EXPECT_EQ("modified: map_string_string[key3]: \"3\" -> \"0\"\n",
+            Run(map_proto1_, map_proto2_));
+}
+
+TEST_F(ComparisonTest, MapIgnoreKeyTest) {
+  Map<std::string, std::string>& map1 =
+      *map_proto1_.mutable_map_string_string();
+  map1["key1"] = "1";
+  map1["key2"] = "2";
+  map1["key3"] = "3";
+  Map<std::string, std::string>& map2 =
+      *map_proto2_.mutable_map_string_string();
+  map2["key4"] = "2";
+  map2["key5"] = "3";
+  map2["key6"] = "1";
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(
+      GetFieldDescriptor(map_proto1_, "map_string_string.key"));
+  EXPECT_TRUE(differencer.Compare(map_proto1_, map_proto2_));
+}
+
+TEST_F(ComparisonTest, MapRoundTripSyncTest) {
+  TextFormat::Parser parser;
+  unittest::TestMap map_reflection1;
+
+  // By setting via reflection, data exists in repeated field.
+  ASSERT_TRUE(parser.ParseFromString("map_int32_foreign_message { key: 1 }",
+                                     &map_reflection1));
+
+  // During copy, data is synced from repeated field to map.
+  unittest::TestMap map_reflection2 = map_reflection1;
+
+  // During comparison, data is synced from map to repeated field.
+  EXPECT_TRUE(
+      util::MessageDifferencer::Equals(map_reflection1, map_reflection2));
+}
+
+TEST_F(ComparisonTest, MapEntryPartialTest) {
+  TextFormat::Parser parser;
+  unittest::TestMap map1;
+  unittest::TestMap map2;
+
+  std::string output;
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  differencer.ReportDifferencesToString(&output);
+
+  ASSERT_TRUE(parser.ParseFromString(
+      "map_int32_foreign_message { key: 1 value { c: 1 } }", &map1));
+  ASSERT_TRUE(parser.ParseFromString(
+      "map_int32_foreign_message { key: 1 value { c: 2 }}", &map2));
+  EXPECT_FALSE(differencer.Compare(map1, map2));
+  EXPECT_EQ("modified: map_int32_foreign_message[1].c: 1 -> 2\n", output);
+
+  ASSERT_TRUE(
+      parser.ParseFromString("map_int32_foreign_message { key: 1 }", &map1));
+  EXPECT_TRUE(differencer.Compare(map1, map2));
+}
+
+TEST_F(ComparisonTest, MapEntryPartialEmptyKeyTest) {
+  TextFormat::Parser parser;
+  unittest::TestMap map1;
+  unittest::TestMap map2;
+  ASSERT_TRUE(parser.ParseFromString("map_int32_foreign_message {}", &map1));
+  ASSERT_TRUE(
+      parser.ParseFromString("map_int32_foreign_message { key: 1 }", &map2));
+
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  // TODO(jieluo): Remove the round trip
+  std::string serialized_value;
+  map1.SerializeToString(&serialized_value);
+  map1.ParseFromString(serialized_value);
+  EXPECT_FALSE(differencer.Compare(map1, map2));
+}
+
+TEST_F(ComparisonTest, MapEntryMissingEmptyFieldIsOkTest) {
+  TextFormat::Parser parser;
+  protobuf_unittest::TestMap msg1;
+  protobuf_unittest::TestMap msg2;
+
+  ASSERT_TRUE(parser.ParseFromString(
+      "map_string_foreign_message { key: 'key1' value {}}", &msg1));
+  ASSERT_TRUE(parser.ParseFromString(
+      "map_string_foreign_message { key: 'key1' }", &msg2));
+
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+
+  ASSERT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+// Considers strings keys as equal if they have equal lengths.
+class LengthMapKeyComparator
+    : public util::MessageDifferencer::MapKeyComparator {
+ public:
+  typedef util::MessageDifferencer::SpecificField SpecificField;
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
+    const Reflection* reflection1 = message1.GetReflection();
+    const Reflection* reflection2 = message2.GetReflection();
+    const FieldDescriptor* key_field = message1.GetDescriptor()->map_key();
+    return reflection1->GetString(message1, key_field).size() ==
+           reflection2->GetString(message2, key_field).size();
+  }
+};
+
+TEST_F(ComparisonTest, MapEntryCustomMapKeyComparator) {
+  TextFormat::Parser parser;
+  protobuf_unittest::TestMap msg1;
+  protobuf_unittest::TestMap msg2;
+
+  ASSERT_TRUE(parser.ParseFromString(
+      "map_string_foreign_message { key: 'key1' value { c: 1 }}", &msg1));
+  ASSERT_TRUE(parser.ParseFromString(
+      "map_string_foreign_message { key: 'key2' value { c: 1 }}", &msg2));
+
+  util::MessageDifferencer differencer;
+  LengthMapKeyComparator key_comparator;
+  differencer.TreatAsMapUsingKeyComparator(
+      GetFieldDescriptor(msg1, "map_string_foreign_message"), &key_comparator);
+  std::string output;
+  differencer.ReportDifferencesToString(&output);
+  // Though the above two messages have different keys for their map entries,
+  // they are considered the same by key_comparator because their lengths are
+  // equal.  However, in value comparison, all fields of the message are taken
+  // into consideration, so they are reported as different.
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: map_string_foreign_message[key1].key: \"key1\" -> \"key2\"\n",
+      output);
+  differencer.IgnoreField(
+      GetFieldDescriptor(msg1, "map_string_foreign_message.key"));
+  output.clear();
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ("ignored: map_string_foreign_message[key1].key\n", output);
+}
+
+class MatchingTest : public testing::Test {
+ public:
+  typedef util::MessageDifferencer MessageDifferencer;
+
+ protected:
+  MatchingTest() {}
+
+  ~MatchingTest() override {}
+
+  std::string RunWithResult(MessageDifferencer* differencer,
+                            const Message& msg1, const Message& msg2,
+                            bool result) {
+    std::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);
+  std::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);
+  std::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 == nullptr);
+  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;
+  std::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));
+}
+
+TEST(Anytest, TreatAsSet_DifferentType) {
+  protobuf_unittest::TestField value1;
+  value1.set_a(20);
+  value1.set_b(30);
+  protobuf_unittest::TestDiffMessage value2;
+  value2.add_rv(40);
+
+  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..0ad6792
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer_unittest.proto
@@ -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.
+
+// 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
+// LINT: ALLOW_GROUPS
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+import "google/protobuf/any.proto";
+
+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
+    map<string, int32> mp = 8;  // Test for map comparisons
+  }
+
+  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
+  repeated google.protobuf.Any rany =
+      16;  // Test for repeated Any type resolution
+  extensions 100 to 199;
+}
diff --git a/src/google/protobuf/util/package_info.h b/src/google/protobuf/util/package_info.h
new file mode 100644
index 0000000..9601920
--- /dev/null
+++ b/src/google/protobuf/util/package_info.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.
+
+// This file exists solely to document the google::protobuf::util namespace.
+// It is not compiled into anything, but it may be read by an automated
+// documentation generator.
+
+namespace google {
+
+namespace protobuf {
+
+// Utility classes.
+//
+// This package contains various utilities for message comparison, JSON
+// conversion, well known types, etc.
+namespace util {}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/time_util.cc b/src/google/protobuf/util/time_util.cc
new file mode 100644
index 0000000..9893aa3
--- /dev/null
+++ b/src/google/protobuf/util/time_util.cc
@@ -0,0 +1,514 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+#include <google/protobuf/stubs/int128.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/time.h>
+
+// Must go after other includes.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::Duration;
+using google::protobuf::Timestamp;
+
+namespace {
+static const int kNanosPerSecond = 1000000000;
+static const int kMicrosPerSecond = 1000000;
+static const int kMillisPerSecond = 1000;
+static const int kNanosPerMillisecond = 1000000;
+static const int kNanosPerMicrosecond = 1000;
+static const int kSecondsPerMinute = 60;  // Note that we ignore leap seconds.
+static const int kSecondsPerHour = 3600;
+
+template <typename T>
+T CreateNormalized(int64_t seconds, int64_t nanos);
+
+template <>
+Timestamp CreateNormalized(int64_t seconds, int64_t 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_t>(nanos));
+  return result;
+}
+
+template <>
+Duration CreateNormalized(int64_t seconds, int64_t 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_t>(nanos));
+  return result;
+}
+
+// Format nanoseconds with either 3, 6, or 9 digits depending on the required
+// precision to represent the exact value.
+std::string FormatNanos(int32_t 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);
+  }
+}
+
+std::string FormatTime(int64_t seconds, int32_t nanos) {
+  return ::google::protobuf::internal::FormatTime(seconds, nanos);
+}
+
+bool ParseTime(const std::string& value, int64_t* seconds, int32_t* nanos) {
+  return ::google::protobuf::internal::ParseTime(value, seconds, nanos);
+}
+
+void CurrentTime(int64_t* seconds, int32_t* nanos) {
+  return ::google::protobuf::internal::GetCurrentTime(seconds, nanos);
+}
+
+// Truncates the remainder part after division.
+int64_t RoundTowardZero(int64_t value, int64_t divider) {
+  int64_t result = value / divider;
+  int64_t 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
+
+// Actually define these static const integers. Required by C++ standard (but
+// some compilers don't like it).
+#ifndef _MSC_VER
+const int64_t TimeUtil::kTimestampMinSeconds;
+const int64_t TimeUtil::kTimestampMaxSeconds;
+const int64_t TimeUtil::kDurationMaxSeconds;
+const int64_t TimeUtil::kDurationMinSeconds;
+#endif  // !_MSC_VER
+
+std::string TimeUtil::ToString(const Timestamp& timestamp) {
+  return FormatTime(timestamp.seconds(), timestamp.nanos());
+}
+
+bool TimeUtil::FromString(const std::string& value, Timestamp* timestamp) {
+  int64_t seconds;
+  int32_t nanos;
+  if (!ParseTime(value, &seconds, &nanos)) {
+    return false;
+  }
+  *timestamp = CreateNormalized<Timestamp>(seconds, nanos);
+  return true;
+}
+
+Timestamp TimeUtil::GetCurrentTime() {
+  int64_t seconds;
+  int32_t nanos;
+  CurrentTime(&seconds, &nanos);
+  return CreateNormalized<Timestamp>(seconds, nanos);
+}
+
+Timestamp TimeUtil::GetEpoch() { return Timestamp(); }
+
+std::string TimeUtil::ToString(const Duration& duration) {
+  std::string result;
+  int64_t seconds = duration.seconds();
+  int32_t nanos = duration.nanos();
+  if (seconds < 0 || nanos < 0) {
+    result += "-";
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  result += StrCat(seconds);
+  if (nanos != 0) {
+    result += "." + FormatNanos(nanos);
+  }
+  result += "s";
+  return result;
+}
+
+static int64_t Pow(int64_t x, int y) {
+  int64_t result = 1;
+  for (int i = 0; i < y; ++i) {
+    result *= x;
+  }
+  return result;
+}
+
+bool TimeUtil::FromString(const std::string& value, Duration* duration) {
+  if (value.length() <= 1 || value[value.length() - 1] != 's') {
+    return false;
+  }
+  bool negative = (value[0] == '-');
+  size_t sign_length = (negative ? 1 : 0);
+  // Parse the duration value as two integers rather than a float value
+  // to avoid precision loss.
+  std::string seconds_part, nanos_part;
+  size_t pos = value.find_last_of('.');
+  if (pos == std::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_t seconds = strto64(seconds_part.c_str(), &end, 10);
+  if (end != seconds_part.c_str() + seconds_part.length()) {
+    return false;
+  }
+  int64_t nanos = strto64(nanos_part.c_str(), &end, 10);
+  if (end != nanos_part.c_str() + nanos_part.length()) {
+    return false;
+  }
+  nanos = nanos * Pow(10, static_cast<int>(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_t>(nanos));
+  return true;
+}
+
+Duration TimeUtil::NanosecondsToDuration(int64_t nanos) {
+  return CreateNormalized<Duration>(nanos / kNanosPerSecond,
+                                    nanos % kNanosPerSecond);
+}
+
+Duration TimeUtil::MicrosecondsToDuration(int64_t micros) {
+  return CreateNormalized<Duration>(
+      micros / kMicrosPerSecond,
+      (micros % kMicrosPerSecond) * kNanosPerMicrosecond);
+}
+
+Duration TimeUtil::MillisecondsToDuration(int64_t millis) {
+  return CreateNormalized<Duration>(
+      millis / kMillisPerSecond,
+      (millis % kMillisPerSecond) * kNanosPerMillisecond);
+}
+
+Duration TimeUtil::SecondsToDuration(int64_t seconds) {
+  return CreateNormalized<Duration>(seconds, 0);
+}
+
+Duration TimeUtil::MinutesToDuration(int64_t minutes) {
+  return CreateNormalized<Duration>(minutes * kSecondsPerMinute, 0);
+}
+
+Duration TimeUtil::HoursToDuration(int64_t hours) {
+  return CreateNormalized<Duration>(hours * kSecondsPerHour, 0);
+}
+
+int64_t TimeUtil::DurationToNanoseconds(const Duration& duration) {
+  return duration.seconds() * kNanosPerSecond + duration.nanos();
+}
+
+int64_t TimeUtil::DurationToMicroseconds(const Duration& duration) {
+  return duration.seconds() * kMicrosPerSecond +
+         RoundTowardZero(duration.nanos(), kNanosPerMicrosecond);
+}
+
+int64_t TimeUtil::DurationToMilliseconds(const Duration& duration) {
+  return duration.seconds() * kMillisPerSecond +
+         RoundTowardZero(duration.nanos(), kNanosPerMillisecond);
+}
+
+int64_t TimeUtil::DurationToSeconds(const Duration& duration) {
+  return duration.seconds();
+}
+
+int64_t TimeUtil::DurationToMinutes(const Duration& duration) {
+  return RoundTowardZero(duration.seconds(), kSecondsPerMinute);
+}
+
+int64_t TimeUtil::DurationToHours(const Duration& duration) {
+  return RoundTowardZero(duration.seconds(), kSecondsPerHour);
+}
+
+Timestamp TimeUtil::NanosecondsToTimestamp(int64_t nanos) {
+  return CreateNormalized<Timestamp>(nanos / kNanosPerSecond,
+                                     nanos % kNanosPerSecond);
+}
+
+Timestamp TimeUtil::MicrosecondsToTimestamp(int64_t micros) {
+  return CreateNormalized<Timestamp>(
+      micros / kMicrosPerSecond,
+      micros % kMicrosPerSecond * kNanosPerMicrosecond);
+}
+
+Timestamp TimeUtil::MillisecondsToTimestamp(int64_t millis) {
+  return CreateNormalized<Timestamp>(
+      millis / kMillisPerSecond,
+      millis % kMillisPerSecond * kNanosPerMillisecond);
+}
+
+Timestamp TimeUtil::SecondsToTimestamp(int64_t seconds) {
+  return CreateNormalized<Timestamp>(seconds, 0);
+}
+
+int64_t TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kNanosPerSecond + timestamp.nanos();
+}
+
+int64_t TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kMicrosPerSecond +
+         RoundTowardZero(timestamp.nanos(), kNanosPerMicrosecond);
+}
+
+int64_t TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kMillisPerSecond +
+         RoundTowardZero(timestamp.nanos(), kNanosPerMillisecond);
+}
+
+int64_t TimeUtil::TimestampToSeconds(const Timestamp& timestamp) {
+  return timestamp.seconds();
+}
+
+Timestamp TimeUtil::TimeTToTimestamp(time_t value) {
+  return CreateNormalized<Timestamp>(static_cast<int64_t>(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 google
+
+namespace google {
+namespace protobuf {
+namespace {
+using ::PROTOBUF_NAMESPACE_ID::util::CreateNormalized;
+using ::PROTOBUF_NAMESPACE_ID::util::kNanosPerSecond;
+
+// 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_t>(-value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32_t>(-value.nanos());
+  } else {
+    *negative = false;
+    *result = static_cast<uint64_t>(value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32_t>(value.nanos());
+  }
+}
+
+void ToDuration(const uint128& value, bool negative, Duration* duration) {
+  int64_t seconds =
+      static_cast<int64_t>(Uint128Low64(value / kNanosPerSecond));
+  int32_t nanos =
+      static_cast<int32_t>(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_t r) {  // NOLINT
+  bool negative;
+  uint128 value;
+  ToUint128(d, &value, &negative);
+  if (r > 0) {
+    value *= static_cast<uint64_t>(r);
+  } else {
+    negative = !negative;
+    value *= static_cast<uint64_t>(-r);
+  }
+  ToDuration(value, negative, &d);
+  return d;
+}
+
+Duration& operator*=(Duration& d, double r) {  // NOLINT
+  double result =
+      (static_cast<double>(d.seconds()) + d.nanos() * (1.0 / kNanosPerSecond)) *
+      r;
+  int64_t seconds = static_cast<int64_t>(result);
+  int32_t nanos = static_cast<int32_t>((result - static_cast<double>(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_t r) {  // NOLINT
+  bool negative;
+  uint128 value;
+  ToUint128(d, &value, &negative);
+  if (r > 0) {
+    value /= static_cast<uint64_t>(r);
+  } else {
+    negative = !negative;
+    value /= static_cast<uint64_t>(-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_t operator/(const Duration& d1, const Duration& d2) {
+  bool negative1, negative2;
+  uint128 value1, value2;
+  ToUint128(d1, &value1, &negative1);
+  ToUint128(d2, &value2, &negative2);
+  int64_t 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..709527e
--- /dev/null
+++ b/src/google/protobuf/util/time_util.h
@@ -0,0 +1,314 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines utilities for the Timestamp and Duration well known types.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
+
+#include <cstdint>
+#include <ctime>
+#include <ostream>
+#include <string>
+#ifdef _MSC_VER
+#ifdef _XBOX_ONE
+struct timeval {
+  int64_t tv_sec;  /* seconds */
+  int64_t tv_usec; /* and microseconds */
+};
+#else
+#include <winsock2.h>
+#endif  // _XBOX_ONE
+#else
+#include <sys/time.h>
+#endif
+
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Utility functions for Timestamp and Duration.
+class PROTOBUF_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_t kTimestampMinSeconds = -62135596800LL;
+  // For "9999-12-31T23:59:59.999999999Z".
+  static const int64_t kTimestampMaxSeconds = 253402300799LL;
+  static const int64_t kDurationMinSeconds = -315576000000LL;
+  static const int64_t 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 std::string ToString(const Timestamp& timestamp);
+  static bool FromString(const std::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 std::string ToString(const Duration& duration);
+  static bool FromString(const std::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_t nanos);
+  static Duration MicrosecondsToDuration(int64_t micros);
+  static Duration MillisecondsToDuration(int64_t millis);
+  static Duration SecondsToDuration(int64_t seconds);
+  static Duration MinutesToDuration(int64_t minutes);
+  static Duration HoursToDuration(int64_t 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_t DurationToNanoseconds(const Duration& duration);
+  static int64_t DurationToMicroseconds(const Duration& duration);
+  static int64_t DurationToMilliseconds(const Duration& duration);
+  static int64_t DurationToSeconds(const Duration& duration);
+  static int64_t DurationToMinutes(const Duration& duration);
+  static int64_t 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_t nanos);
+  static Timestamp MicrosecondsToTimestamp(int64_t micros);
+  static Timestamp MillisecondsToTimestamp(int64_t millis);
+  static Timestamp SecondsToTimestamp(int64_t 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_t TimestampToNanoseconds(const Timestamp& timestamp);
+  static int64_t TimestampToMicroseconds(const Timestamp& timestamp);
+  static int64_t TimestampToMilliseconds(const Timestamp& timestamp);
+  static int64_t 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 google
+
+namespace google {
+namespace protobuf {
+// Overloaded operators for Duration.
+//
+// Assignment operators.
+PROTOBUF_EXPORT Duration& operator+=(Duration& d1,
+                                     const Duration& d2);  // NOLINT
+PROTOBUF_EXPORT Duration& operator-=(Duration& d1,
+                                     const Duration& d2);     // NOLINT
+PROTOBUF_EXPORT Duration& operator*=(Duration& d, int64_t r);  // NOLINT
+PROTOBUF_EXPORT Duration& operator*=(Duration& d, double r);  // NOLINT
+PROTOBUF_EXPORT Duration& operator/=(Duration& d, int64_t r);  // NOLINT
+PROTOBUF_EXPORT Duration& operator/=(Duration& d, double r);  // NOLINT
+// Overload for other integer types.
+template <typename T>
+Duration& operator*=(Duration& d, T r) {  // NOLINT
+  int64_t x = r;
+  return d *= x;
+}
+template <typename T>
+Duration& operator/=(Duration& d, T r) {  // NOLINT
+  int64_t x = r;
+  return d /= x;
+}
+PROTOBUF_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;
+}
+PROTOBUF_EXPORT int64_t operator/(const Duration& d1, const Duration& d2);
+
+inline Duration operator%(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result %= d2;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const Duration& d) {
+  out << ::PROTOBUF_NAMESPACE_ID::util::TimeUtil::ToString(d);
+  return out;
+}
+
+// Overloaded operators for Timestamp
+//
+// Assignment operators.
+PROTOBUF_EXPORT Timestamp& operator+=(Timestamp& t,
+                                      const Duration& d);  // NOLINT
+PROTOBUF_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;
+}
+PROTOBUF_EXPORT Duration operator-(const Timestamp& t1, const Timestamp& t2);
+
+inline std::ostream& operator<<(std::ostream& out, const Timestamp& t) {
+  out << ::PROTOBUF_NAMESPACE_ID::util::TimeUtil::ToString(t);
+  return out;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..79e2427
--- /dev/null
+++ b/src/google/protobuf/util/time_util_test.cc
@@ -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.
+
+#include <google/protobuf/util/time_util.h>
+
+#include <cstdint>
+#include <ctime>
+
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::Duration;
+using google::protobuf::Timestamp;
+
+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 accepts 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(int64_t{315576000000}, d.seconds());
+  EXPECT_EQ(999999999, d.nanos());
+  EXPECT_TRUE(TimeUtil::FromString("-315576000000.999999999s", &d));
+  EXPECT_EQ(int64_t{-315576000000}, 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(nullptr);
+  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) *
+                                                    int64_t{315576000000}));
+  EXPECT_EQ("-315575999684.424s", TimeUtil::ToString((one_nano - one_second) *
+                                                     int64_t{315576000000}));
+  EXPECT_EQ("-315575999684.424s", TimeUtil::ToString((one_second - one_nano) *
+                                                     (int64_t{-315576000000})));
+
+  // Test / and %
+  EXPECT_EQ("0.999999999s", TimeUtil::ToString(a / 2));
+  EXPECT_EQ("-0.999999999s", TimeUtil::ToString(b / 2));
+  Duration large =
+      TimeUtil::SecondsToDuration(int64_t{315576000000}) - one_nano;
+  // We have to handle division with values beyond 64 bits.
+  EXPECT_EQ("0.999999999s", TimeUtil::ToString(large / int64_t{315576000000}));
+  EXPECT_EQ("-0.999999999s",
+            TimeUtil::ToString((-large) / int64_t{315576000000}));
+  EXPECT_EQ("-0.999999999s",
+            TimeUtil::ToString(large / (int64_t{-315576000000})));
+  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..b2e7b43
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver.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.
+
+// Defines a TypeResolver for the Any message.
+
+#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/type.pb.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class DescriptorPool;
+namespace util {
+
+// Abstract interface for a type resolver.
+//
+// Implementations of this interface must be thread-safe.
+class PROTOBUF_EXPORT TypeResolver {
+ public:
+  TypeResolver() {}
+  virtual ~TypeResolver() {}
+
+  // Resolves a type url for a message type.
+  virtual util::Status ResolveMessageType(
+      const std::string& type_url, google::protobuf::Type* message_type) = 0;
+
+  // Resolves a type url for an enum type.
+  virtual util::Status ResolveEnumType(const std::string& type_url,
+                                       google::protobuf::Enum* enum_type) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeResolver);
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..8be0efb
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -0,0 +1,370 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/status.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+using google::protobuf::Any;
+using google::protobuf::BoolValue;
+using google::protobuf::BytesValue;
+using google::protobuf::DoubleValue;
+using google::protobuf::Enum;
+using google::protobuf::EnumValue;
+using google::protobuf::Field;
+using google::protobuf::FloatValue;
+using google::protobuf::Int32Value;
+using google::protobuf::Int64Value;
+using google::protobuf::Option;
+using google::protobuf::StringValue;
+using google::protobuf::Type;
+using google::protobuf::UInt32Value;
+using google::protobuf::UInt64Value;
+
+class DescriptorPoolTypeResolver : public TypeResolver {
+ public:
+  DescriptorPoolTypeResolver(const std::string& url_prefix,
+                             const DescriptorPool* pool)
+      : url_prefix_(url_prefix), pool_(pool) {}
+
+  util::Status ResolveMessageType(const std::string& type_url,
+                                  Type* type) override {
+    std::string type_name;
+    util::Status status = ParseTypeUrl(type_url, &type_name);
+    if (!status.ok()) {
+      return status;
+    }
+
+    const Descriptor* descriptor = pool_->FindMessageTypeByName(type_name);
+    if (descriptor == NULL) {
+      return util::NotFoundError("Invalid type URL, unknown type: " +
+                                 type_name);
+    }
+    ConvertDescriptor(descriptor, type);
+    return util::Status();
+  }
+
+  util::Status ResolveEnumType(const std::string& type_url,
+                               Enum* enum_type) override {
+    std::string type_name;
+    util::Status status = ParseTypeUrl(type_url, &type_name);
+    if (!status.ok()) {
+      return status;
+    }
+
+    const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
+    if (descriptor == NULL) {
+      return util::InvalidArgumentError("Invalid type URL, unknown type: " +
+                                        type_name);
+    }
+    ConvertEnumDescriptor(descriptor, enum_type);
+    return util::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) {
+      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) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  void ConvertFieldOptions(const FieldOptions& options,
+                           RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  void ConvertEnumOptions(const EnumOptions& options,
+                          RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  void ConvertEnumValueOptions(const EnumValueOptions& options,
+                               RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  // Implementation details for Convert*Options.
+  void ConvertOptionsInternal(const Message& options,
+                              RepeatedPtrField<Option>* output) {
+    const Reflection* reflection = options.GetReflection();
+    std::vector<const FieldDescriptor*> fields;
+    reflection->ListFields(options, &fields);
+    for (const FieldDescriptor* field : fields) {
+      if (field->is_repeated()) {
+        const int size = reflection->FieldSize(options, field);
+        for (int i = 0; i < size; i++) {
+          ConvertOptionField(reflection, options, field, i, output->Add());
+        }
+      } else {
+        ConvertOptionField(reflection, options, field, -1, output->Add());
+      }
+    }
+  }
+
+  static void ConvertOptionField(const Reflection* reflection,
+                                 const Message& options,
+                                 const FieldDescriptor* field, int index,
+                                 Option* out) {
+    out->set_name(field->is_extension() ? field->full_name() : field->name());
+    Any* value = out->mutable_value();
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        value->PackFrom(
+            field->is_repeated()
+                ? reflection->GetRepeatedMessage(options, field, index)
+                : reflection->GetMessage(options, field));
+        return;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        value->PackFrom(WrapValue<DoubleValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedDouble(options, field, index)
+                : reflection->GetDouble(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        value->PackFrom(WrapValue<FloatValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedFloat(options, field, index)
+                : reflection->GetFloat(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_INT64:
+        value->PackFrom(WrapValue<Int64Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedInt64(options, field, index)
+                : reflection->GetInt64(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        value->PackFrom(WrapValue<UInt64Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedUInt64(options, field, index)
+                : reflection->GetUInt64(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_INT32:
+        value->PackFrom(WrapValue<Int32Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedInt32(options, field, index)
+                : reflection->GetInt32(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        value->PackFrom(WrapValue<UInt32Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedUInt32(options, field, index)
+                : reflection->GetUInt32(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        value->PackFrom(WrapValue<BoolValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedBool(options, field, index)
+                : reflection->GetBool(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_STRING: {
+        const std::string& val =
+            field->is_repeated()
+                ? reflection->GetRepeatedString(options, field, index)
+                : reflection->GetString(options, field);
+        if (field->type() == FieldDescriptor::TYPE_STRING) {
+          value->PackFrom(WrapValue<StringValue>(val));
+        } else {
+          value->PackFrom(WrapValue<BytesValue>(val));
+        }
+        return;
+      }
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        const EnumValueDescriptor* val =
+            field->is_repeated()
+                ? reflection->GetRepeatedEnum(options, field, index)
+                : reflection->GetEnum(options, field);
+        value->PackFrom(WrapValue<Int32Value>(val->number()));
+        return;
+      }
+    }
+  }
+
+  template <typename WrapperT, typename T>
+  static WrapperT WrapValue(T value) {
+    WrapperT wrapper;
+    wrapper.set_value(value);
+    return wrapper;
+  }
+
+  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 ||
+        descriptor->type() == FieldDescriptor::TYPE_GROUP) {
+      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);
+    }
+
+    ConvertFieldOptions(descriptor->options(), field->mutable_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());
+
+      ConvertEnumValueOptions(value_descriptor->options(),
+                              value->mutable_options());
+    }
+
+    ConvertEnumOptions(descriptor->options(), enum_type->mutable_options());
+  }
+
+  std::string GetTypeUrl(const Descriptor* descriptor) {
+    return url_prefix_ + "/" + descriptor->full_name();
+  }
+
+  std::string GetTypeUrl(const EnumDescriptor* descriptor) {
+    return url_prefix_ + "/" + descriptor->full_name();
+  }
+
+  util::Status ParseTypeUrl(const std::string& type_url,
+                            std::string* type_name) {
+    if (type_url.substr(0, url_prefix_.size() + 1) != url_prefix_ + "/") {
+      return util::InvalidArgumentError(
+          StrCat("Invalid type URL, type URLs must be of the form '",
+                       url_prefix_, "/<typename>', got: ", type_url));
+    }
+    *type_name = type_url.substr(url_prefix_.size() + 1);
+    return util::Status();
+  }
+
+  std::string DefaultValueAsString(const FieldDescriptor* descriptor) {
+    switch (descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        return StrCat(descriptor->default_value_int32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return StrCat(descriptor->default_value_int64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return StrCat(descriptor->default_value_uint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return StrCat(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 "";
+  }
+
+  std::string url_prefix_;
+  const DescriptorPool* pool_;
+};
+
+}  // namespace
+
+TypeResolver* NewTypeResolverForDescriptorPool(const std::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..7f6a4b9
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver_util.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.
+
+// Defines utilities for the TypeResolver.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+class DescriptorPool;
+namespace util {
+class TypeResolver;
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// Creates a TypeResolver that serves type information in the given descriptor
+// pool. Caller takes ownership of the returned TypeResolver.
+PROTOBUF_EXPORT TypeResolver* NewTypeResolverForDescriptorPool(
+    const std::string& url_prefix, const DescriptorPool* pool);
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#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..2780a39
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -0,0 +1,438 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 <cstdint>
+#include <limits>
+#include <memory>
+#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/unittest_custom_options.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::BoolValue;
+using google::protobuf::Enum;
+using google::protobuf::EnumValue;
+using google::protobuf::Field;
+using google::protobuf::Int32Value;
+using google::protobuf::Option;
+using google::protobuf::Type;
+using google::protobuf::UInt64Value;
+
+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 std::string& name) {
+    for (int i = 0; i < type.fields_size(); ++i) {
+      const Field& field = type.fields(i);
+      if (field.name() == name) {
+        return &field;
+      }
+    }
+    return nullptr;
+  }
+
+  bool HasField(const Type& type, Field::Cardinality cardinality,
+                Field::Kind kind, const std::string& name, int number) {
+    const Field* field = FindField(type, name);
+    if (field == nullptr) {
+      return false;
+    }
+    return field->cardinality() == cardinality && field->kind() == kind &&
+           field->number() == number;
+  }
+
+  bool CheckFieldTypeUrl(const Type& type, const std::string& name,
+                         const std::string& type_url) {
+    const Field* field = FindField(type, name);
+    if (field == nullptr) {
+      return false;
+    }
+    return field->type_url() == type_url;
+  }
+
+  bool FieldInOneof(const Type& type, const std::string& name,
+                    const std::string& oneof_name) {
+    const Field* field = FindField(type, name);
+    if (field == nullptr || 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 std::string& name) {
+    const Field* field = FindField(type, name);
+    if (field == nullptr) {
+      return false;
+    }
+    return field->packed();
+  }
+
+  const EnumValue* FindEnumValue(const Enum& type, const std::string& name) {
+    for (const EnumValue& value : type.enumvalue()) {
+      if (value.name() == name) {
+        return &value;
+      }
+    }
+    return nullptr;
+  }
+
+  bool EnumHasValue(const Enum& type, const std::string& name, int number) {
+    const EnumValue* value = FindEnumValue(type, name);
+    return value != nullptr && value->number() == number;
+  }
+
+  bool HasBoolOption(const RepeatedPtrField<Option>& options,
+                     const std::string& name, bool value) {
+    return HasOption<BoolValue>(options, name, value);
+  }
+
+  bool HasInt32Option(const RepeatedPtrField<Option>& options,
+                      const std::string& name, int32_t value) {
+    return HasOption<Int32Value>(options, name, value);
+  }
+
+  bool HasUInt64Option(const RepeatedPtrField<Option>& options,
+                       const std::string& name, uint64_t value) {
+    return HasOption<UInt64Value>(options, name, value);
+  }
+
+  template <typename WrapperT, typename T>
+  bool HasOption(const RepeatedPtrField<Option>& options,
+                 const std::string& name, T value) {
+    for (const Option& option : options) {
+      if (option.name() == name) {
+        WrapperT wrapper;
+        if (option.value().UnpackTo(&wrapper) && wrapper.value() == value) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  std::string GetTypeUrl(std::string full_name) {
+    return kUrlPrefix + std::string("/") + full_name;
+  }
+
+  template <typename T>
+  std::string GetTypeUrl() {
+    return GetTypeUrl(T::descriptor()->full_name());
+  }
+
+ protected:
+  std::unique_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_GROUP,
+                       "optionalgroup", 16));
+
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "optionalgroup",
+      GetTypeUrl<protobuf_unittest::TestAllTypes::OptionalGroup>()));
+
+  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_GROUP,
+                       "repeatedgroup", 46));
+
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "repeatedgroup",
+      GetTypeUrl<protobuf_unittest::TestAllTypes::RepeatedGroup>()));
+
+  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")));
+}
+
+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, TestCustomMessageOptions) {
+  Type type;
+  ASSERT_TRUE(
+      resolver_
+          ->ResolveMessageType(
+              GetTypeUrl<protobuf_unittest::TestMessageWithCustomOptions>(),
+              &type)
+          .ok());
+  EXPECT_TRUE(
+      HasInt32Option(type.options(), "protobuf_unittest.message_opt1", -56));
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestCustomFieldOptions) {
+  Type type;
+  ASSERT_TRUE(
+      resolver_
+          ->ResolveMessageType(
+              GetTypeUrl<protobuf_unittest::TestMessageWithCustomOptions>(),
+              &type)
+          .ok());
+  const Field* field = FindField(type, "field1");
+  ASSERT_TRUE(field != nullptr);
+  EXPECT_TRUE(HasUInt64Option(field->options(), "protobuf_unittest.field_opt1",
+                              8765432109));
+}
+
+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, TestCustomEnumOptions) {
+  Enum type;
+  ASSERT_TRUE(
+      resolver_
+          ->ResolveEnumType(
+              GetTypeUrl("protobuf_unittest.TestMessageWithCustomOptions.AnEnum"),
+              &type)
+          .ok());
+  ASSERT_TRUE(
+      HasInt32Option(type.options(), "protobuf_unittest.enum_opt1", -789));
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestCustomValueOptions) {
+  Enum type;
+  ASSERT_TRUE(
+      resolver_
+          ->ResolveEnumType(
+              GetTypeUrl("protobuf_unittest.TestMessageWithCustomOptions.AnEnum"),
+              &type)
+          .ok());
+  const EnumValue* value = FindEnumValue(type, "ANENUM_VAL2");
+  ASSERT_TRUE(value != nullptr);
+  ASSERT_TRUE(
+      HasInt32Option(value->options(), "protobuf_unittest.enum_value_opt1", 123));
+}
+
+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
new file mode 100644
index 0000000..6fe63c8
--- /dev/null
+++ b/src/google/protobuf/wire_format.cc
@@ -0,0 +1,1768 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/wire_format.h>
+
+#include <stack>
+#include <string>
+#include <vector>
+
+#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>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+const size_t kMapEntryTagByteSize = 2;
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Forward declare static functions
+static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field,
+                                          const MapValueConstRef& value);
+
+// ===================================================================
+
+bool UnknownFieldSetFieldSkipper::SkipField(io::CodedInputStream* input,
+                                            uint32_t tag) {
+  return WireFormat::SkipField(input, tag, unknown_fields_);
+}
+
+bool UnknownFieldSetFieldSkipper::SkipMessage(io::CodedInputStream* input) {
+  return WireFormat::SkipMessage(input, unknown_fields_);
+}
+
+void UnknownFieldSetFieldSkipper::SkipUnknownEnum(int field_number, int value) {
+  unknown_fields_->AddVarint(field_number, value);
+}
+
+bool WireFormat::SkipField(io::CodedInputStream* input, uint32_t tag,
+                           UnknownFieldSet* unknown_fields) {
+  int number = WireFormatLite::GetTagFieldNumber(tag);
+  // Field number 0 is illegal.
+  if (number == 0) return false;
+
+  switch (WireFormatLite::GetTagWireType(tag)) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      uint64_t value;
+      if (!input->ReadVarint64(&value)) return false;
+      if (unknown_fields != nullptr) unknown_fields->AddVarint(number, value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      uint64_t value;
+      if (!input->ReadLittleEndian64(&value)) return false;
+      if (unknown_fields != nullptr) unknown_fields->AddFixed64(number, value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      uint32_t length;
+      if (!input->ReadVarint32(&length)) return false;
+      if (unknown_fields == nullptr) {
+        if (!input->Skip(length)) return false;
+      } else {
+        if (!input->ReadString(unknown_fields->AddLengthDelimited(number),
+                               length)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      if (!input->IncrementRecursionDepth()) return false;
+      if (!SkipMessage(input, (unknown_fields == nullptr)
+                                  ? nullptr
+                                  : unknown_fields->AddGroup(number))) {
+        return false;
+      }
+      input->DecrementRecursionDepth();
+      // Check that the ending tag matched the starting tag.
+      if (!input->LastTagWas(
+              WireFormatLite::MakeTag(WireFormatLite::GetTagFieldNumber(tag),
+                                      WireFormatLite::WIRETYPE_END_GROUP))) {
+        return false;
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      return false;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32: {
+      uint32_t value;
+      if (!input->ReadLittleEndian32(&value)) return false;
+      if (unknown_fields != nullptr) unknown_fields->AddFixed32(number, value);
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
+bool WireFormat::SkipMessage(io::CodedInputStream* input,
+                             UnknownFieldSet* unknown_fields) {
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+    if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+      // Must be the end of the message.
+      return true;
+    }
+
+    if (!SkipField(input, tag, unknown_fields)) return false;
+  }
+}
+
+bool WireFormat::ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+                                                uint32_t field_number,
+                                                bool (*is_valid)(int),
+                                                UnknownFieldSet* unknown_fields,
+                                                RepeatedField<int>* values) {
+  uint32_t length;
+  if (!input->ReadVarint32(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    int value;
+    if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+            input, &value)) {
+      return false;
+    }
+    if (is_valid == nullptr || is_valid(value)) {
+      values->Add(value);
+    } else {
+      unknown_fields->AddVarint(field_number, value);
+    }
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+uint8_t* WireFormat::InternalSerializeUnknownFieldsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    target = stream->EnsureSpace(target);
+    switch (field.type()) {
+      case UnknownField::TYPE_VARINT:
+        target = WireFormatLite::WriteUInt64ToArray(field.number(),
+                                                    field.varint(), target);
+        break;
+      case UnknownField::TYPE_FIXED32:
+        target = WireFormatLite::WriteFixed32ToArray(field.number(),
+                                                     field.fixed32(), target);
+        break;
+      case UnknownField::TYPE_FIXED64:
+        target = WireFormatLite::WriteFixed64ToArray(field.number(),
+                                                     field.fixed64(), target);
+        break;
+      case UnknownField::TYPE_LENGTH_DELIMITED:
+        target = stream->WriteString(field.number(), field.length_delimited(),
+                                     target);
+        break;
+      case UnknownField::TYPE_GROUP:
+        target = WireFormatLite::WriteTagToArray(
+            field.number(), WireFormatLite::WIRETYPE_START_GROUP, target);
+        target = InternalSerializeUnknownFieldsToArray(field.group(), target,
+                                                       stream);
+        target = stream->EnsureSpace(target);
+        target = WireFormatLite::WriteTagToArray(
+            field.number(), WireFormatLite::WIRETYPE_END_GROUP, target);
+        break;
+    }
+  }
+  return target;
+}
+
+uint8_t* WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    // The only unknown fields that are allowed to exist in a MessageSet are
+    // messages, which are length-delimited.
+    if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+      target = stream->EnsureSpace(target);
+      // Start group.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetItemStartTag, target);
+
+      // Write type ID.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetTypeIdTag, target);
+      target =
+          io::CodedOutputStream::WriteVarint32ToArray(field.number(), target);
+
+      // Write message.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetMessageTag, target);
+
+      target = field.InternalSerializeLengthDelimitedNoTag(target, stream);
+
+      target = stream->EnsureSpace(target);
+      // End group.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetItemEndTag, target);
+    }
+  }
+
+  return target;
+}
+
+size_t WireFormat::ComputeUnknownFieldsSize(
+    const UnknownFieldSet& unknown_fields) {
+  size_t size = 0;
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    switch (field.type()) {
+      case UnknownField::TYPE_VARINT:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_VARINT));
+        size += io::CodedOutputStream::VarintSize64(field.varint());
+        break;
+      case UnknownField::TYPE_FIXED32:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_FIXED32));
+        size += sizeof(int32_t);
+        break;
+      case UnknownField::TYPE_FIXED64:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_FIXED64));
+        size += sizeof(int64_t);
+        break;
+      case UnknownField::TYPE_LENGTH_DELIMITED:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+        size += io::CodedOutputStream::VarintSize32(
+            field.length_delimited().size());
+        size += field.length_delimited().size();
+        break;
+      case UnknownField::TYPE_GROUP:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_START_GROUP));
+        size += ComputeUnknownFieldsSize(field.group());
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_END_GROUP));
+        break;
+    }
+  }
+
+  return size;
+}
+
+size_t WireFormat::ComputeUnknownMessageSetItemsSize(
+    const UnknownFieldSet& unknown_fields) {
+  size_t size = 0;
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    // The only unknown fields that are allowed to exist in a MessageSet are
+    // messages, which are length-delimited.
+    if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+      size += WireFormatLite::kMessageSetItemTagsSize;
+      size += io::CodedOutputStream::VarintSize32(field.number());
+
+      int field_size = field.GetLengthDelimitedSize();
+      size += io::CodedOutputStream::VarintSize32(field_size);
+      size += field_size;
+    }
+  }
+
+  return size;
+}
+
+// ===================================================================
+
+bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input,
+                                      Message* message) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  const Reflection* message_reflection = message->GetReflection();
+
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    if (WireFormatLite::GetTagWireType(tag) ==
+        WireFormatLite::WIRETYPE_END_GROUP) {
+      // Must be the end of the message.
+      return true;
+    }
+
+    const FieldDescriptor* field = nullptr;
+
+    if (descriptor != nullptr) {
+      int field_number = WireFormatLite::GetTagFieldNumber(tag);
+      field = descriptor->FindFieldByNumber(field_number);
+
+      // If that failed, check if the field is an extension.
+      if (field == nullptr && descriptor->IsExtensionNumber(field_number)) {
+        if (input->GetExtensionPool() == nullptr) {
+          field = message_reflection->FindKnownExtensionByNumber(field_number);
+        } else {
+          field = input->GetExtensionPool()->FindExtensionByNumber(
+              descriptor, field_number);
+        }
+      }
+
+      // If that failed, but we're a MessageSet, and this is the tag for a
+      // MessageSet item, then parse that.
+      if (field == nullptr && descriptor->options().message_set_wire_format() &&
+          tag == WireFormatLite::kMessageSetItemStartTag) {
+        if (!ParseAndMergeMessageSetItem(input, message)) {
+          return false;
+        }
+        continue;  // Skip ParseAndMergeField(); already taken care of.
+      }
+    }
+
+    if (!ParseAndMergeField(tag, field, message, input)) {
+      return false;
+    }
+  }
+}
+
+bool WireFormat::SkipMessageSetField(io::CodedInputStream* input,
+                                     uint32_t field_number,
+                                     UnknownFieldSet* unknown_fields) {
+  uint32_t length;
+  if (!input->ReadVarint32(&length)) return false;
+  return input->ReadString(unknown_fields->AddLengthDelimited(field_number),
+                           length);
+}
+
+bool WireFormat::ParseAndMergeMessageSetField(uint32_t field_number,
+                                              const FieldDescriptor* field,
+                                              Message* message,
+                                              io::CodedInputStream* input) {
+  const Reflection* message_reflection = message->GetReflection();
+  if (field == nullptr) {
+    // We store unknown MessageSet extensions as groups.
+    return SkipMessageSetField(
+        input, field_number, message_reflection->MutableUnknownFields(message));
+  } else if (field->is_repeated() ||
+             field->type() != FieldDescriptor::TYPE_MESSAGE) {
+    // This shouldn't happen as we only allow optional message extensions to
+    // MessageSet.
+    GOOGLE_LOG(ERROR) << "Extensions of MessageSets must be optional messages.";
+    return false;
+  } else {
+    Message* sub_message = message_reflection->MutableMessage(
+        message, field, input->GetExtensionFactory());
+    return WireFormatLite::ReadMessage(input, sub_message);
+  }
+}
+
+static bool StrictUtf8Check(const FieldDescriptor* field) {
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+bool WireFormat::ParseAndMergeField(
+    uint32_t tag,
+    const FieldDescriptor* field,  // May be nullptr for unknown
+    Message* message, io::CodedInputStream* input) {
+  const Reflection* message_reflection = message->GetReflection();
+
+  enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format;
+
+  if (field == nullptr) {
+    value_format = UNKNOWN;
+  } else if (WireFormatLite::GetTagWireType(tag) ==
+             WireTypeForFieldType(field->type())) {
+    value_format = NORMAL_FORMAT;
+  } else if (field->is_packable() &&
+             WireFormatLite::GetTagWireType(tag) ==
+                 WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    value_format = PACKED_FORMAT;
+  } else {
+    // We don't recognize this field. Either the field number is unknown
+    // or the wire type doesn't match. Put it in our unknown field set.
+    value_format = UNKNOWN;
+  }
+
+  if (value_format == UNKNOWN) {
+    return SkipField(input, tag,
+                     message_reflection->MutableUnknownFields(message));
+  } else if (value_format == PACKED_FORMAT) {
+    uint32_t length;
+    if (!input->ReadVarint32(&length)) return false;
+    io::CodedInputStream::Limit limit = input->PushLimit(length);
+
+    switch (field->type()) {
+#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                      \
+  case FieldDescriptor::TYPE_##TYPE: {                                         \
+    while (input->BytesUntilLimit() > 0) {                                     \
+      CPPTYPE value;                                                           \
+      if (!WireFormatLite::ReadPrimitive<CPPTYPE,                              \
+                                         WireFormatLite::TYPE_##TYPE>(input,   \
+                                                                      &value)) \
+        return false;                                                          \
+      message_reflection->Add##CPPTYPE_METHOD(message, field, value);          \
+    }                                                                          \
+    break;                                                                     \
+  }
+
+      HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+      HANDLE_PACKED_TYPE(SINT32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(SINT64, int64_t, Int64)
+      HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+      HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
+
+      HANDLE_PACKED_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_PACKED_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_PACKED_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(SFIXED64, int64_t, Int64)
+
+      HANDLE_PACKED_TYPE(FLOAT, float, Float)
+      HANDLE_PACKED_TYPE(DOUBLE, double, Double)
+
+      HANDLE_PACKED_TYPE(BOOL, bool, Bool)
+#undef HANDLE_PACKED_TYPE
+
+      case FieldDescriptor::TYPE_ENUM: {
+        while (input->BytesUntilLimit() > 0) {
+          int value;
+          if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+                  input, &value))
+            return false;
+          if (message->GetDescriptor()->file()->syntax() ==
+              FileDescriptor::SYNTAX_PROTO3) {
+            message_reflection->AddEnumValue(message, field, value);
+          } else {
+            const EnumValueDescriptor* enum_value =
+                field->enum_type()->FindValueByNumber(value);
+            if (enum_value != nullptr) {
+              message_reflection->AddEnum(message, field, enum_value);
+            } else {
+              // The enum value is not one of the known values.  Add it to the
+              // UnknownFieldSet.
+              int64_t sign_extended_value = static_cast<int64_t>(value);
+              message_reflection->MutableUnknownFields(message)->AddVarint(
+                  WireFormatLite::GetTagFieldNumber(tag), sign_extended_value);
+            }
+          }
+        }
+
+        break;
+      }
+
+      case FieldDescriptor::TYPE_STRING:
+      case FieldDescriptor::TYPE_GROUP:
+      case FieldDescriptor::TYPE_MESSAGE:
+      case FieldDescriptor::TYPE_BYTES:
+        // Can't have packed fields of these types: these should be caught by
+        // the protocol compiler.
+        return false;
+        break;
+    }
+
+    input->PopLimit(limit);
+  } else {
+    // Non-packed value (value_format == NORMAL_FORMAT)
+    switch (field->type()) {
+#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                            \
+  case FieldDescriptor::TYPE_##TYPE: {                                        \
+    CPPTYPE value;                                                            \
+    if (!WireFormatLite::ReadPrimitive<CPPTYPE, WireFormatLite::TYPE_##TYPE>( \
+            input, &value))                                                   \
+      return false;                                                           \
+    if (field->is_repeated()) {                                               \
+      message_reflection->Add##CPPTYPE_METHOD(message, field, value);         \
+    } else {                                                                  \
+      message_reflection->Set##CPPTYPE_METHOD(message, field, value);         \
+    }                                                                         \
+    break;                                                                    \
+  }
+
+      HANDLE_TYPE(INT32, int32_t, Int32)
+      HANDLE_TYPE(INT64, int64_t, Int64)
+      HANDLE_TYPE(SINT32, int32_t, Int32)
+      HANDLE_TYPE(SINT64, int64_t, Int64)
+      HANDLE_TYPE(UINT32, uint32_t, UInt32)
+      HANDLE_TYPE(UINT64, uint64_t, UInt64)
+
+      HANDLE_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_TYPE(SFIXED64, int64_t, Int64)
+
+      HANDLE_TYPE(FLOAT, float, Float)
+      HANDLE_TYPE(DOUBLE, double, Double)
+
+      HANDLE_TYPE(BOOL, bool, Bool)
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::TYPE_ENUM: {
+        int value;
+        if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+                input, &value))
+          return false;
+        if (field->is_repeated()) {
+          message_reflection->AddEnumValue(message, field, value);
+        } else {
+          message_reflection->SetEnumValue(message, field, value);
+        }
+        break;
+      }
+
+      // Handle strings separately so that we can optimize the ctype=CORD case.
+      case FieldDescriptor::TYPE_STRING: {
+        bool strict_utf8_check = StrictUtf8Check(field);
+        std::string value;
+        if (!WireFormatLite::ReadString(input, &value)) return false;
+        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 {
+          message_reflection->SetString(message, field, value);
+        }
+        break;
+      }
+
+      case FieldDescriptor::TYPE_BYTES: {
+        std::string value;
+        if (!WireFormatLite::ReadBytes(input, &value)) return false;
+        if (field->is_repeated()) {
+          message_reflection->AddString(message, field, value);
+        } else {
+          message_reflection->SetString(message, field, value);
+        }
+        break;
+      }
+
+      case FieldDescriptor::TYPE_GROUP: {
+        Message* sub_message;
+        if (field->is_repeated()) {
+          sub_message = message_reflection->AddMessage(
+              message, field, input->GetExtensionFactory());
+        } else {
+          sub_message = message_reflection->MutableMessage(
+              message, field, input->GetExtensionFactory());
+        }
+
+        if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag),
+                                       input, sub_message))
+          return false;
+        break;
+      }
+
+      case FieldDescriptor::TYPE_MESSAGE: {
+        Message* sub_message;
+        if (field->is_repeated()) {
+          sub_message = message_reflection->AddMessage(
+              message, field, input->GetExtensionFactory());
+        } else {
+          sub_message = message_reflection->MutableMessage(
+              message, field, input->GetExtensionFactory());
+        }
+
+        if (!WireFormatLite::ReadMessage(input, sub_message)) return false;
+        break;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool WireFormat::ParseAndMergeMessageSetItem(io::CodedInputStream* input,
+                                             Message* message) {
+  struct MSReflective {
+    bool ParseField(int type_id, io::CodedInputStream* input) {
+      const FieldDescriptor* field =
+          message_reflection->FindKnownExtensionByNumber(type_id);
+      return ParseAndMergeMessageSetField(type_id, field, message, input);
+    }
+
+    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
+      return WireFormat::SkipField(input, tag, nullptr);
+    }
+
+    const Reflection* message_reflection;
+    Message* message;
+  };
+
+  return ParseMessageSetItemImpl(
+      input, MSReflective{message->GetReflection(), message});
+}
+
+struct WireFormat::MessageSetParser {
+  const char* _InternalParse(const char* ptr, internal::ParseContext* ctx) {
+    // Parse a MessageSetItem
+    auto metadata = reflection->MutableInternalMetadata(msg);
+    enum class State { kNoTag, kHasType, kHasPayload, kDone };
+    State state = State::kNoTag;
+
+    std::string payload;
+    uint32_t type_id = 0;
+    while (!ctx->Done(&ptr)) {
+      // We use 64 bit tags in order to allow typeid's that span the whole
+      // range of 32 bit numbers.
+      uint32_t tag = static_cast<uint8_t>(*ptr++);
+      if (tag == WireFormatLite::kMessageSetTypeIdTag) {
+        uint64_t tmp;
+        ptr = ParseBigVarint(ptr, &tmp);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        if (state == State::kNoTag) {
+          type_id = tmp;
+          state = State::kHasType;
+        } else if (state == State::kHasPayload) {
+          type_id = tmp;
+          const FieldDescriptor* field;
+          if (ctx->data().pool == nullptr) {
+            field = reflection->FindKnownExtensionByNumber(type_id);
+          } else {
+            field =
+                ctx->data().pool->FindExtensionByNumber(descriptor, type_id);
+          }
+          if (field == nullptr || field->message_type() == nullptr) {
+            WriteLengthDelimited(
+                type_id, payload,
+                metadata->mutable_unknown_fields<UnknownFieldSet>());
+          } else {
+            Message* value =
+                field->is_repeated()
+                    ? reflection->AddMessage(msg, field, ctx->data().factory)
+                    : reflection->MutableMessage(msg, field,
+                                                 ctx->data().factory);
+            const char* p;
+            // We can't use regular parse from string as we have to track
+            // proper recursion depth and descriptor pools.
+            ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
+            tmp_ctx.data().pool = ctx->data().pool;
+            tmp_ctx.data().factory = ctx->data().factory;
+            GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
+                                           tmp_ctx.EndedAtLimit());
+          }
+          state = State::kDone;
+        }
+        continue;
+      } else if (tag == WireFormatLite::kMessageSetMessageTag) {
+        if (state == State::kNoTag) {
+          int32_t size = ReadSize(&ptr);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+          ptr = ctx->ReadString(ptr, size, &payload);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+          state = State::kHasPayload;
+        } else if (state == State::kHasType) {
+          // We're now parsing the payload
+          const FieldDescriptor* field = nullptr;
+          if (descriptor->IsExtensionNumber(type_id)) {
+            if (ctx->data().pool == nullptr) {
+              field = reflection->FindKnownExtensionByNumber(type_id);
+            } else {
+              field =
+                  ctx->data().pool->FindExtensionByNumber(descriptor, type_id);
+            }
+          }
+          ptr = WireFormat::_InternalParseAndMergeField(
+              msg, ptr, ctx, static_cast<uint64_t>(type_id) * 8 + 2, reflection,
+              field);
+          state = State::kDone;
+        } else {
+          int32_t size = ReadSize(&ptr);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+          ptr = ctx->Skip(ptr, size);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        }
+      } else {
+        // An unknown field in MessageSetItem.
+        ptr = ReadTag(ptr - 1, &tag);
+        if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        // Skip field.
+        ptr = internal::UnknownFieldParse(
+            tag, static_cast<std::string*>(nullptr), ptr, ctx);
+      }
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+    return ptr;
+  }
+
+  const char* ParseMessageSet(const char* ptr, internal::ParseContext* ctx) {
+    while (!ctx->Done(&ptr)) {
+      uint32_t tag;
+      ptr = ReadTag(ptr, &tag);
+      if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+      if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
+        ctx->SetLastTag(tag);
+        break;
+      }
+      if (tag == WireFormatLite::kMessageSetItemStartTag) {
+        // A message set item starts
+        ptr = ctx->ParseGroup(this, ptr, tag);
+      } else {
+        // Parse other fields as normal extensions.
+        int field_number = WireFormatLite::GetTagFieldNumber(tag);
+        const FieldDescriptor* field = nullptr;
+        if (descriptor->IsExtensionNumber(field_number)) {
+          if (ctx->data().pool == nullptr) {
+            field = reflection->FindKnownExtensionByNumber(field_number);
+          } else {
+            field = ctx->data().pool->FindExtensionByNumber(descriptor,
+                                                            field_number);
+          }
+        }
+        ptr = WireFormat::_InternalParseAndMergeField(msg, ptr, ctx, tag,
+                                                      reflection, field);
+      }
+      if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+    }
+    return ptr;
+  }
+
+  Message* msg;
+  const Descriptor* descriptor;
+  const Reflection* reflection;
+};
+
+const char* WireFormat::_InternalParse(Message* msg, const char* ptr,
+                                       internal::ParseContext* ctx) {
+  const Descriptor* descriptor = msg->GetDescriptor();
+  const Reflection* reflection = msg->GetReflection();
+  GOOGLE_DCHECK(descriptor);
+  GOOGLE_DCHECK(reflection);
+  if (descriptor->options().message_set_wire_format()) {
+    MessageSetParser message_set{msg, descriptor, reflection};
+    return message_set.ParseMessageSet(ptr, ctx);
+  }
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ReadTag(ptr, &tag);
+    if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+    if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
+      ctx->SetLastTag(tag);
+      break;
+    }
+    const FieldDescriptor* field = nullptr;
+
+    int field_number = WireFormatLite::GetTagFieldNumber(tag);
+    field = descriptor->FindFieldByNumber(field_number);
+
+    // If that failed, check if the field is an extension.
+    if (field == nullptr && descriptor->IsExtensionNumber(field_number)) {
+      if (ctx->data().pool == nullptr) {
+        field = reflection->FindKnownExtensionByNumber(field_number);
+      } else {
+        field =
+            ctx->data().pool->FindExtensionByNumber(descriptor, field_number);
+      }
+    }
+
+    ptr = _InternalParseAndMergeField(msg, ptr, ctx, tag, reflection, field);
+    if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+  }
+  return ptr;
+}
+
+const char* WireFormat::_InternalParseAndMergeField(
+    Message* msg, const char* ptr, internal::ParseContext* ctx, uint64_t tag,
+    const Reflection* reflection, const FieldDescriptor* field) {
+  if (field == nullptr) {
+    // unknown field set parser takes 64bit tags, because message set type ids
+    // span the full 32 bit range making the tag span [0, 2^35) range.
+    return internal::UnknownFieldParse(
+        tag, reflection->MutableUnknownFields(msg), ptr, ctx);
+  }
+  if (WireFormatLite::GetTagWireType(tag) !=
+      WireTypeForFieldType(field->type())) {
+    if (field->is_packable() && WireFormatLite::GetTagWireType(tag) ==
+                                    WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+      switch (field->type()) {
+#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                   \
+  case FieldDescriptor::TYPE_##TYPE: {                                      \
+    ptr = internal::Packed##CPPTYPE_METHOD##Parser(                         \
+        reflection->MutableRepeatedFieldInternal<CPPTYPE>(msg, field), ptr, \
+        ctx);                                                               \
+    return ptr;                                                             \
+  }
+
+        HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+        HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+        HANDLE_PACKED_TYPE(SINT32, int32_t, SInt32)
+        HANDLE_PACKED_TYPE(SINT64, int64_t, SInt64)
+        HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+        HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
+
+        HANDLE_PACKED_TYPE(FIXED32, uint32_t, Fixed32)
+        HANDLE_PACKED_TYPE(FIXED64, uint64_t, Fixed64)
+        HANDLE_PACKED_TYPE(SFIXED32, int32_t, SFixed32)
+        HANDLE_PACKED_TYPE(SFIXED64, int64_t, SFixed64)
+
+        HANDLE_PACKED_TYPE(FLOAT, float, Float)
+        HANDLE_PACKED_TYPE(DOUBLE, double, Double)
+
+        HANDLE_PACKED_TYPE(BOOL, bool, Bool)
+#undef HANDLE_PACKED_TYPE
+
+        case FieldDescriptor::TYPE_ENUM: {
+          auto rep_enum =
+              reflection->MutableRepeatedFieldInternal<int>(msg, field);
+          bool open_enum = false;
+          if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ||
+              open_enum) {
+            ptr = internal::PackedEnumParser(rep_enum, ptr, ctx);
+          } else {
+            return ctx->ReadPackedVarint(
+                ptr, [rep_enum, field, reflection, msg](uint64_t val) {
+                  if (field->enum_type()->FindValueByNumber(val) != nullptr) {
+                    rep_enum->Add(val);
+                  } else {
+                    WriteVarint(field->number(), val,
+                                reflection->MutableUnknownFields(msg));
+                  }
+                });
+          }
+          return ptr;
+        }
+
+        case FieldDescriptor::TYPE_STRING:
+        case FieldDescriptor::TYPE_GROUP:
+        case FieldDescriptor::TYPE_MESSAGE:
+        case FieldDescriptor::TYPE_BYTES:
+          GOOGLE_LOG(FATAL) << "Can't reach";
+          return nullptr;
+      }
+    } else {
+      // mismatched wiretype;
+      return internal::UnknownFieldParse(
+          tag, reflection->MutableUnknownFields(msg), ptr, ctx);
+    }
+  }
+
+  // Non-packed value
+  bool utf8_check = false;
+  bool strict_utf8_check = false;
+  switch (field->type()) {
+#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)        \
+  case FieldDescriptor::TYPE_##TYPE: {                    \
+    CPPTYPE value;                                        \
+    ptr = VarintParse(ptr, &value);                       \
+    if (ptr == nullptr) return nullptr;                   \
+    if (field->is_repeated()) {                           \
+      reflection->Add##CPPTYPE_METHOD(msg, field, value); \
+    } else {                                              \
+      reflection->Set##CPPTYPE_METHOD(msg, field, value); \
+    }                                                     \
+    return ptr;                                           \
+  }
+
+    HANDLE_TYPE(BOOL, uint64_t, Bool)
+    HANDLE_TYPE(INT32, uint32_t, Int32)
+    HANDLE_TYPE(INT64, uint64_t, Int64)
+    HANDLE_TYPE(UINT32, uint32_t, UInt32)
+    HANDLE_TYPE(UINT64, uint64_t, UInt64)
+
+    case FieldDescriptor::TYPE_SINT32: {
+      int32_t value = ReadVarintZigZag32(&ptr);
+      if (ptr == nullptr) return nullptr;
+      if (field->is_repeated()) {
+        reflection->AddInt32(msg, field, value);
+      } else {
+        reflection->SetInt32(msg, field, value);
+      }
+      return ptr;
+    }
+    case FieldDescriptor::TYPE_SINT64: {
+      int64_t value = ReadVarintZigZag64(&ptr);
+      if (ptr == nullptr) return nullptr;
+      if (field->is_repeated()) {
+        reflection->AddInt64(msg, field, value);
+      } else {
+        reflection->SetInt64(msg, field, value);
+      }
+      return ptr;
+    }
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)        \
+  case FieldDescriptor::TYPE_##TYPE: {                    \
+    CPPTYPE value;                                        \
+    value = UnalignedLoad<CPPTYPE>(ptr);                  \
+    ptr += sizeof(CPPTYPE);                               \
+    if (field->is_repeated()) {                           \
+      reflection->Add##CPPTYPE_METHOD(msg, field, value); \
+    } else {                                              \
+      reflection->Set##CPPTYPE_METHOD(msg, field, value); \
+    }                                                     \
+    return ptr;                                           \
+  }
+
+      HANDLE_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_TYPE(SFIXED64, int64_t, Int64)
+
+      HANDLE_TYPE(FLOAT, float, Float)
+      HANDLE_TYPE(DOUBLE, double, Double)
+
+#undef HANDLE_TYPE
+
+    case FieldDescriptor::TYPE_ENUM: {
+      uint32_t value;
+      ptr = VarintParse(ptr, &value);
+      if (ptr == nullptr) return nullptr;
+      if (field->is_repeated()) {
+        reflection->AddEnumValue(msg, field, value);
+      } else {
+        reflection->SetEnumValue(msg, field, value);
+      }
+      return ptr;
+    }
+
+    // Handle strings separately so that we can optimize the ctype=CORD case.
+    case FieldDescriptor::TYPE_STRING:
+      utf8_check = true;
+      strict_utf8_check = StrictUtf8Check(field);
+      PROTOBUF_FALLTHROUGH_INTENDED;
+    case FieldDescriptor::TYPE_BYTES: {
+      int size = ReadSize(&ptr);
+      if (ptr == nullptr) return nullptr;
+      std::string value;
+      ptr = ctx->ReadString(ptr, size, &value);
+      if (ptr == nullptr) return nullptr;
+      if (utf8_check) {
+        if (strict_utf8_check) {
+          if (!WireFormatLite::VerifyUtf8String(value.data(), value.length(),
+                                                WireFormatLite::PARSE,
+                                                field->full_name().c_str())) {
+            return nullptr;
+          }
+        } else {
+          VerifyUTF8StringNamedField(value.data(), value.length(), PARSE,
+                                     field->full_name().c_str());
+        }
+      }
+      if (field->is_repeated()) {
+        reflection->AddString(msg, field, std::move(value));
+      } else {
+        reflection->SetString(msg, field, std::move(value));
+      }
+      return ptr;
+    }
+
+    case FieldDescriptor::TYPE_GROUP: {
+      Message* sub_message;
+      if (field->is_repeated()) {
+        sub_message = reflection->AddMessage(msg, field, ctx->data().factory);
+      } else {
+        sub_message =
+            reflection->MutableMessage(msg, field, ctx->data().factory);
+      }
+
+      return ctx->ParseGroup(sub_message, ptr, tag);
+    }
+
+    case FieldDescriptor::TYPE_MESSAGE: {
+      Message* sub_message;
+      if (field->is_repeated()) {
+        sub_message = reflection->AddMessage(msg, field, ctx->data().factory);
+      } else {
+        sub_message =
+            reflection->MutableMessage(msg, field, ctx->data().factory);
+      }
+      return ctx->ParseMessage(sub_message, ptr);
+    }
+  }
+
+  // GCC 8 complains about control reaching end of non-void function here.
+  // Let's keep it happy by returning a nullptr.
+  return nullptr;
+}
+
+// ===================================================================
+
+uint8_t* WireFormat::_InternalSerialize(const Message& message, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* message_reflection = message.GetReflection();
+
+  std::vector<const FieldDescriptor*> fields;
+
+  // Fields of map entry should always be serialized.
+  if (descriptor->options().map_entry()) {
+    for (int i = 0; i < descriptor->field_count(); i++) {
+      fields.push_back(descriptor->field(i));
+    }
+  } else {
+    message_reflection->ListFields(message, &fields);
+  }
+
+  for (auto field : fields) {
+    target = InternalSerializeField(field, message, target, stream);
+  }
+
+  if (descriptor->options().message_set_wire_format()) {
+    return InternalSerializeUnknownMessageSetItemsToArray(
+        message_reflection->GetUnknownFields(message), target, stream);
+  } else {
+    return InternalSerializeUnknownFieldsToArray(
+        message_reflection->GetUnknownFields(message), target, stream);
+  }
+}
+
+uint8_t* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                        const MapKey& value, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_BYTES:
+    case FieldDescriptor::TYPE_ENUM:
+      GOOGLE_LOG(FATAL) << "Unsupported";
+      break;
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
+  case FieldDescriptor::TYPE_##FieldType:                    \
+    target = WireFormatLite::Write##CamelFieldType##ToArray( \
+        1, value.Get##CamelCppType##Value(), target);        \
+    break;
+      CASE_TYPE(INT64, Int64, Int64)
+      CASE_TYPE(UINT64, UInt64, UInt64)
+      CASE_TYPE(INT32, Int32, Int32)
+      CASE_TYPE(FIXED64, Fixed64, UInt64)
+      CASE_TYPE(FIXED32, Fixed32, UInt32)
+      CASE_TYPE(BOOL, Bool, Bool)
+      CASE_TYPE(UINT32, UInt32, UInt32)
+      CASE_TYPE(SFIXED32, SFixed32, Int32)
+      CASE_TYPE(SFIXED64, SFixed64, Int64)
+      CASE_TYPE(SINT32, SInt32, Int32)
+      CASE_TYPE(SINT64, SInt64, Int64)
+#undef CASE_TYPE
+    case FieldDescriptor::TYPE_STRING:
+      target = stream->WriteString(1, value.GetStringValue(), target);
+      break;
+  }
+  return target;
+}
+
+static uint8_t* SerializeMapValueRefWithCachedSizes(
+    const FieldDescriptor* field, const MapValueConstRef& value,
+    uint8_t* target, io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  switch (field->type()) {
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
+  case FieldDescriptor::TYPE_##FieldType:                    \
+    target = WireFormatLite::Write##CamelFieldType##ToArray( \
+        2, value.Get##CamelCppType##Value(), target);        \
+    break;
+    CASE_TYPE(INT64, Int64, Int64)
+    CASE_TYPE(UINT64, UInt64, UInt64)
+    CASE_TYPE(INT32, Int32, Int32)
+    CASE_TYPE(FIXED64, Fixed64, UInt64)
+    CASE_TYPE(FIXED32, Fixed32, UInt32)
+    CASE_TYPE(BOOL, Bool, Bool)
+    CASE_TYPE(UINT32, UInt32, UInt32)
+    CASE_TYPE(SFIXED32, SFixed32, Int32)
+    CASE_TYPE(SFIXED64, SFixed64, Int64)
+    CASE_TYPE(SINT32, SInt32, Int32)
+    CASE_TYPE(SINT64, SInt64, Int64)
+    CASE_TYPE(ENUM, Enum, Enum)
+    CASE_TYPE(DOUBLE, Double, Double)
+    CASE_TYPE(FLOAT, Float, Float)
+#undef CASE_TYPE
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      target = stream->WriteString(2, value.GetStringValue(), target);
+      break;
+    case FieldDescriptor::TYPE_MESSAGE: {
+      auto& msg = value.GetMessageValue();
+      target = WireFormatLite::InternalWriteMessage(2, msg, msg.GetCachedSize(),
+                                                    target, stream);
+    } break;
+    case FieldDescriptor::TYPE_GROUP:
+      target = WireFormatLite::InternalWriteGroup(2, value.GetMessageValue(),
+                                                  target, stream);
+      break;
+  }
+  return target;
+}
+
+class MapKeySorter {
+ public:
+  static std::vector<MapKey> SortKey(const Message& message,
+                                     const Reflection* reflection,
+                                     const FieldDescriptor* field) {
+    std::vector<MapKey> sorted_key_list;
+    for (MapIterator it =
+             reflection->MapBegin(const_cast<Message*>(&message), field);
+         it != reflection->MapEnd(const_cast<Message*>(&message), field);
+         ++it) {
+      sorted_key_list.push_back(it.GetKey());
+    }
+    MapKeyComparator comparator;
+    std::sort(sorted_key_list.begin(), sorted_key_list.end(), comparator);
+    return sorted_key_list;
+  }
+
+ private:
+  class MapKeyComparator {
+   public:
+    bool operator()(const MapKey& a, const MapKey& b) const {
+      GOOGLE_DCHECK(a.type() == b.type());
+      switch (a.type()) {
+#define CASE_TYPE(CppType, CamelCppType)                                \
+  case FieldDescriptor::CPPTYPE_##CppType: {                            \
+    return a.Get##CamelCppType##Value() < b.Get##CamelCppType##Value(); \
+  }
+        CASE_TYPE(STRING, String)
+        CASE_TYPE(INT64, Int64)
+        CASE_TYPE(INT32, Int32)
+        CASE_TYPE(UINT64, UInt64)
+        CASE_TYPE(UINT32, UInt32)
+        CASE_TYPE(BOOL, Bool)
+#undef CASE_TYPE
+
+        default:
+          GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+          return true;
+      }
+    }
+  };
+};
+
+static uint8_t* InternalSerializeMapEntry(const FieldDescriptor* field,
+                                          const MapKey& key,
+                                          const MapValueConstRef& value,
+                                          uint8_t* target,
+                                          io::EpsCopyOutputStream* stream) {
+  const FieldDescriptor* key_field = field->message_type()->field(0);
+  const FieldDescriptor* value_field = field->message_type()->field(1);
+
+  size_t size = kMapEntryTagByteSize;
+  size += MapKeyDataOnlyByteSize(key_field, key);
+  size += MapValueRefDataOnlyByteSize(value_field, value);
+  target = stream->EnsureSpace(target);
+  target = WireFormatLite::WriteTagToArray(
+      field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(size, target);
+  target = SerializeMapKeyWithCachedSizes(key_field, key, target, stream);
+  target =
+      SerializeMapValueRefWithCachedSizes(value_field, value, target, stream);
+  return target;
+}
+
+uint8_t* WireFormat::InternalSerializeField(const FieldDescriptor* field,
+                                            const Message& message,
+                                            uint8_t* target,
+                                            io::EpsCopyOutputStream* stream) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  if (field->is_extension() &&
+      field->containing_type()->options().message_set_wire_format() &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      !field->is_repeated()) {
+    return InternalSerializeMessageSetItem(field, message, target, stream);
+  }
+
+  // For map fields, we can use either repeated field reflection or map
+  // reflection.  Our choice has some subtle effects.  If we use repeated field
+  // reflection here, then the repeated field representation becomes
+  // authoritative for this field: any existing references that came from map
+  // reflection remain valid for reading, but mutations to them are lost and
+  // will be overwritten next time we call map reflection!
+  //
+  // So far this mainly affects Python, which keeps long-term references to map
+  // values around, and always uses map reflection.  See: b/35918691
+  //
+  // Here we choose to use map reflection API as long as the internal
+  // map is valid. In this way, the serialization doesn't change map field's
+  // internal state and existing references that came from map reflection remain
+  // valid for both reading and writing.
+  if (field->is_map()) {
+    const MapFieldBase* map_field =
+        message_reflection->GetMapData(message, field);
+    if (map_field->IsMapValid()) {
+      if (stream->IsSerializationDeterministic()) {
+        std::vector<MapKey> sorted_key_list =
+            MapKeySorter::SortKey(message, message_reflection, field);
+        for (std::vector<MapKey>::iterator it = sorted_key_list.begin();
+             it != sorted_key_list.end(); ++it) {
+          MapValueConstRef map_value;
+          message_reflection->LookupMapValue(message, field, *it, &map_value);
+          target =
+              InternalSerializeMapEntry(field, *it, map_value, target, stream);
+        }
+      } else {
+        for (MapIterator it = message_reflection->MapBegin(
+                 const_cast<Message*>(&message), field);
+             it !=
+             message_reflection->MapEnd(const_cast<Message*>(&message), field);
+             ++it) {
+          target = InternalSerializeMapEntry(field, it.GetKey(),
+                                             it.GetValueRef(), target, stream);
+        }
+      }
+
+      return target;
+    }
+  }
+  int count = 0;
+
+  if (field->is_repeated()) {
+    count = message_reflection->FieldSize(message, field);
+  } else if (field->containing_type()->options().map_entry()) {
+    // Map entry fields always need to be serialized.
+    count = 1;
+  } else if (message_reflection->HasField(message, field)) {
+    count = 1;
+  }
+
+  // map_entries is for maps that'll be deterministically serialized.
+  std::vector<const Message*> map_entries;
+  if (count > 1 && field->is_map() && stream->IsSerializationDeterministic()) {
+    map_entries =
+        DynamicMapSorter::Sort(message, count, message_reflection, field);
+  }
+
+  if (field->is_packed()) {
+    if (count == 0) return target;
+    target = stream->EnsureSpace(target);
+    switch (field->type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)      \
+  case FieldDescriptor::TYPE_##TYPE: {                                         \
+    auto r =                                                                   \
+        message_reflection->GetRepeatedFieldInternal<CPPTYPE>(message, field); \
+    target = stream->Write##TYPE_METHOD##Packed(                               \
+        field->number(), r, FieldDataOnlyByteSize(field, message), target);    \
+    break;                                                                     \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(ENUM, int, Enum, Enum)
+
+#undef HANDLE_PRIMITIVE_TYPE
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)      \
+  case FieldDescriptor::TYPE_##TYPE: {                                         \
+    auto r =                                                                   \
+        message_reflection->GetRepeatedFieldInternal<CPPTYPE>(message, field); \
+    target = stream->WriteFixedPacked(field->number(), r, target);             \
+    break;                                                                     \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)
+
+      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
+      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
+
+      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
+#undef HANDLE_PRIMITIVE_TYPE
+      default:
+        GOOGLE_LOG(FATAL) << "Invalid descriptor";
+    }
+    return target;
+  }
+
+  auto get_message_from_field = [&message, &map_entries, message_reflection](
+                                    const FieldDescriptor* field, int j) {
+    if (!field->is_repeated()) {
+      return &message_reflection->GetMessage(message, field);
+    }
+    if (!map_entries.empty()) {
+      return map_entries[j];
+    }
+    return &message_reflection->GetRepeatedMessage(message, field, j);
+  };
+  for (int j = 0; j < count; j++) {
+    target = stream->EnsureSpace(target);
+    switch (field->type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)     \
+  case FieldDescriptor::TYPE_##TYPE: {                                        \
+    const CPPTYPE value =                                                     \
+        field->is_repeated()                                                  \
+            ? message_reflection->GetRepeated##CPPTYPE_METHOD(message, field, \
+                                                              j)              \
+            : message_reflection->Get##CPPTYPE_METHOD(message, field);        \
+    target = WireFormatLite::Write##TYPE_METHOD##ToArray(field->number(),     \
+                                                         value, target);      \
+    break;                                                                    \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
+
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)
+
+      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
+      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
+
+      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
+#undef HANDLE_PRIMITIVE_TYPE
+
+      case FieldDescriptor::TYPE_GROUP: {
+        auto* msg = get_message_from_field(field, j);
+        target = WireFormatLite::InternalWriteGroup(field->number(), *msg,
+                                                    target, stream);
+      } break;
+
+      case FieldDescriptor::TYPE_MESSAGE: {
+        auto* msg = get_message_from_field(field, j);
+        target = WireFormatLite::InternalWriteMessage(
+            field->number(), *msg, msg->GetCachedSize(), target, stream);
+      } break;
+
+      case FieldDescriptor::TYPE_ENUM: {
+        const EnumValueDescriptor* value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedEnum(message, field, j)
+                : message_reflection->GetEnum(message, field);
+        target = WireFormatLite::WriteEnumToArray(field->number(),
+                                                  value->number(), target);
+        break;
+      }
+
+      // Handle strings separately so that we can get string references
+      // instead of copying.
+      case FieldDescriptor::TYPE_STRING: {
+        bool strict_utf8_check = StrictUtf8Check(field);
+        std::string scratch;
+        const std::string& value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedStringReference(message, field,
+                                                                 j, &scratch)
+                : message_reflection->GetStringReference(message, field,
+                                                         &scratch);
+        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());
+        }
+        target = stream->WriteString(field->number(), value, target);
+        break;
+      }
+
+      case FieldDescriptor::TYPE_BYTES: {
+        std::string scratch;
+        const std::string& value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedStringReference(message, field,
+                                                                 j, &scratch)
+                : message_reflection->GetStringReference(message, field,
+                                                         &scratch);
+        target = stream->WriteString(field->number(), value, target);
+        break;
+      }
+    }
+  }
+  return target;
+}
+
+uint8_t* WireFormat::InternalSerializeMessageSetItem(
+    const FieldDescriptor* field, const Message& message, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  target = stream->EnsureSpace(target);
+  // Start group.
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemStartTag, target);
+  // Write type ID.
+  target = WireFormatLite::WriteUInt32ToArray(
+      WireFormatLite::kMessageSetTypeIdNumber, field->number(), target);
+  // Write message.
+  auto& msg = message_reflection->GetMessage(message, field);
+  target = WireFormatLite::InternalWriteMessage(
+      WireFormatLite::kMessageSetMessageNumber, msg, msg.GetCachedSize(),
+      target, stream);
+  // End group.
+  target = stream->EnsureSpace(target);
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemEndTag, target);
+  return target;
+}
+
+// ===================================================================
+
+size_t WireFormat::ByteSize(const Message& message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* message_reflection = message.GetReflection();
+
+  size_t our_size = 0;
+
+  std::vector<const FieldDescriptor*> fields;
+
+  // Fields of map entry should always be serialized.
+  if (descriptor->options().map_entry()) {
+    for (int i = 0; i < descriptor->field_count(); i++) {
+      fields.push_back(descriptor->field(i));
+    }
+  } else {
+    message_reflection->ListFields(message, &fields);
+  }
+
+  for (const FieldDescriptor* field : fields) {
+    our_size += FieldByteSize(field, message);
+  }
+
+  if (descriptor->options().message_set_wire_format()) {
+    our_size += ComputeUnknownMessageSetItemsSize(
+        message_reflection->GetUnknownFields(message));
+  } else {
+    our_size +=
+        ComputeUnknownFieldsSize(message_reflection->GetUnknownFields(message));
+  }
+
+  return our_size;
+}
+
+size_t WireFormat::FieldByteSize(const FieldDescriptor* field,
+                                 const Message& message) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  if (field->is_extension() &&
+      field->containing_type()->options().message_set_wire_format() &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      !field->is_repeated()) {
+    return MessageSetItemByteSize(field, message);
+  }
+
+  size_t count = 0;
+  if (field->is_repeated()) {
+    if (field->is_map()) {
+      const MapFieldBase* map_field =
+          message_reflection->GetMapData(message, field);
+      if (map_field->IsMapValid()) {
+        count = FromIntSize(map_field->size());
+      } else {
+        count = FromIntSize(message_reflection->FieldSize(message, field));
+      }
+    } else {
+      count = FromIntSize(message_reflection->FieldSize(message, field));
+    }
+  } else if (field->containing_type()->options().map_entry()) {
+    // Map entry fields always need to be serialized.
+    count = 1;
+  } else if (message_reflection->HasField(message, field)) {
+    count = 1;
+  }
+
+  const size_t data_size = FieldDataOnlyByteSize(field, message);
+  size_t our_size = data_size;
+  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
+      // a GROUP
+      our_size += TagSize(field->number(), FieldDescriptor::TYPE_STRING);
+      our_size += io::CodedOutputStream::VarintSize32(data_size);
+    }
+  } else {
+    our_size += count * TagSize(field->number(), field->type());
+  }
+  return our_size;
+}
+
+size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
+                              const MapKey& value) {
+  GOOGLE_DCHECK_EQ(FieldDescriptor::TypeToCppType(field->type()), value.type());
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_BYTES:
+    case FieldDescriptor::TYPE_ENUM:
+      GOOGLE_LOG(FATAL) << "Unsupported";
+      return 0;
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
+  case FieldDescriptor::TYPE_##FieldType:                  \
+    return WireFormatLite::CamelFieldType##Size(           \
+        value.Get##CamelCppType##Value());
+
+#define FIXED_CASE_TYPE(FieldType, CamelFieldType) \
+  case FieldDescriptor::TYPE_##FieldType:          \
+    return WireFormatLite::k##CamelFieldType##Size;
+
+      CASE_TYPE(INT32, Int32, Int32);
+      CASE_TYPE(INT64, Int64, Int64);
+      CASE_TYPE(UINT32, UInt32, UInt32);
+      CASE_TYPE(UINT64, UInt64, UInt64);
+      CASE_TYPE(SINT32, SInt32, Int32);
+      CASE_TYPE(SINT64, SInt64, Int64);
+      CASE_TYPE(STRING, String, String);
+      FIXED_CASE_TYPE(FIXED32, Fixed32);
+      FIXED_CASE_TYPE(FIXED64, Fixed64);
+      FIXED_CASE_TYPE(SFIXED32, SFixed32);
+      FIXED_CASE_TYPE(SFIXED64, SFixed64);
+      FIXED_CASE_TYPE(BOOL, Bool);
+
+#undef CASE_TYPE
+#undef FIXED_CASE_TYPE
+  }
+  GOOGLE_LOG(FATAL) << "Cannot get here";
+  return 0;
+}
+
+static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field,
+                                          const MapValueConstRef& value) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_GROUP:
+      GOOGLE_LOG(FATAL) << "Unsupported";
+      return 0;
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
+  case FieldDescriptor::TYPE_##FieldType:                  \
+    return WireFormatLite::CamelFieldType##Size(           \
+        value.Get##CamelCppType##Value());
+
+#define FIXED_CASE_TYPE(FieldType, CamelFieldType) \
+  case FieldDescriptor::TYPE_##FieldType:          \
+    return WireFormatLite::k##CamelFieldType##Size;
+
+      CASE_TYPE(INT32, Int32, Int32);
+      CASE_TYPE(INT64, Int64, Int64);
+      CASE_TYPE(UINT32, UInt32, UInt32);
+      CASE_TYPE(UINT64, UInt64, UInt64);
+      CASE_TYPE(SINT32, SInt32, Int32);
+      CASE_TYPE(SINT64, SInt64, Int64);
+      CASE_TYPE(STRING, String, String);
+      CASE_TYPE(BYTES, Bytes, String);
+      CASE_TYPE(ENUM, Enum, Enum);
+      CASE_TYPE(MESSAGE, Message, Message);
+      FIXED_CASE_TYPE(FIXED32, Fixed32);
+      FIXED_CASE_TYPE(FIXED64, Fixed64);
+      FIXED_CASE_TYPE(SFIXED32, SFixed32);
+      FIXED_CASE_TYPE(SFIXED64, SFixed64);
+      FIXED_CASE_TYPE(DOUBLE, Double);
+      FIXED_CASE_TYPE(FLOAT, Float);
+      FIXED_CASE_TYPE(BOOL, Bool);
+
+#undef CASE_TYPE
+#undef FIXED_CASE_TYPE
+  }
+  GOOGLE_LOG(FATAL) << "Cannot get here";
+  return 0;
+}
+
+size_t WireFormat::FieldDataOnlyByteSize(const FieldDescriptor* field,
+                                         const Message& message) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  size_t data_size = 0;
+
+  if (field->is_map()) {
+    const MapFieldBase* map_field =
+        message_reflection->GetMapData(message, field);
+    if (map_field->IsMapValid()) {
+      MapIterator iter(const_cast<Message*>(&message), field);
+      MapIterator end(const_cast<Message*>(&message), field);
+      const FieldDescriptor* key_field = field->message_type()->field(0);
+      const FieldDescriptor* value_field = field->message_type()->field(1);
+      for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end;
+           ++iter) {
+        size_t size = kMapEntryTagByteSize;
+        size += MapKeyDataOnlyByteSize(key_field, iter.GetKey());
+        size += MapValueRefDataOnlyByteSize(value_field, iter.GetValueRef());
+        data_size += WireFormatLite::LengthDelimitedSize(size);
+      }
+      return data_size;
+    }
+  }
+
+  size_t count = 0;
+  if (field->is_repeated()) {
+    count =
+        internal::FromIntSize(message_reflection->FieldSize(message, field));
+  } else if (field->containing_type()->options().map_entry()) {
+    // Map entry fields always need to be serialized.
+    count = 1;
+  } else if (message_reflection->HasField(message, field)) {
+    count = 1;
+  }
+
+  switch (field->type()) {
+#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD)                      \
+  case FieldDescriptor::TYPE_##TYPE:                                        \
+    if (field->is_repeated()) {                                             \
+      for (size_t j = 0; j < count; j++) {                                  \
+        data_size += WireFormatLite::TYPE_METHOD##Size(                     \
+            message_reflection->GetRepeated##CPPTYPE_METHOD(message, field, \
+                                                            j));            \
+      }                                                                     \
+    } else {                                                                \
+      data_size += WireFormatLite::TYPE_METHOD##Size(                       \
+          message_reflection->Get##CPPTYPE_METHOD(message, field));         \
+    }                                                                       \
+    break;
+
+#define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD)                   \
+  case FieldDescriptor::TYPE_##TYPE:                           \
+    data_size += count * WireFormatLite::k##TYPE_METHOD##Size; \
+    break;
+
+    HANDLE_TYPE(INT32, Int32, Int32)
+    HANDLE_TYPE(INT64, Int64, Int64)
+    HANDLE_TYPE(SINT32, SInt32, Int32)
+    HANDLE_TYPE(SINT64, SInt64, Int64)
+    HANDLE_TYPE(UINT32, UInt32, UInt32)
+    HANDLE_TYPE(UINT64, UInt64, UInt64)
+
+    HANDLE_FIXED_TYPE(FIXED32, Fixed32)
+    HANDLE_FIXED_TYPE(FIXED64, Fixed64)
+    HANDLE_FIXED_TYPE(SFIXED32, SFixed32)
+    HANDLE_FIXED_TYPE(SFIXED64, SFixed64)
+
+    HANDLE_FIXED_TYPE(FLOAT, Float)
+    HANDLE_FIXED_TYPE(DOUBLE, Double)
+
+    HANDLE_FIXED_TYPE(BOOL, Bool)
+
+    HANDLE_TYPE(GROUP, Group, Message)
+    HANDLE_TYPE(MESSAGE, Message, Message)
+#undef HANDLE_TYPE
+#undef HANDLE_FIXED_TYPE
+
+    case FieldDescriptor::TYPE_ENUM: {
+      if (field->is_repeated()) {
+        for (size_t j = 0; j < count; j++) {
+          data_size += WireFormatLite::EnumSize(
+              message_reflection->GetRepeatedEnum(message, field, j)->number());
+        }
+      } else {
+        data_size += WireFormatLite::EnumSize(
+            message_reflection->GetEnum(message, field)->number());
+      }
+      break;
+    }
+
+    // Handle strings separately so that we can get string references
+    // instead of copying.
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES: {
+      for (size_t j = 0; j < count; j++) {
+        std::string scratch;
+        const std::string& value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedStringReference(message, field,
+                                                                 j, &scratch)
+                : message_reflection->GetStringReference(message, field,
+                                                         &scratch);
+        data_size += WireFormatLite::StringSize(value);
+      }
+      break;
+    }
+  }
+  return data_size;
+}
+
+size_t WireFormat::MessageSetItemByteSize(const FieldDescriptor* field,
+                                          const Message& message) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  size_t our_size = WireFormatLite::kMessageSetItemTagsSize;
+
+  // type_id
+  our_size += io::CodedOutputStream::VarintSize32(field->number());
+
+  // message
+  const Message& sub_message = message_reflection->GetMessage(message, field);
+  size_t message_size = sub_message.ByteSizeLong();
+
+  our_size += io::CodedOutputStream::VarintSize32(message_size);
+  our_size += message_size;
+
+  return our_size;
+}
+
+// Compute the size of the UnknownFieldSet on the wire.
+size_t ComputeUnknownFieldsSize(const InternalMetadata& metadata,
+                                size_t total_size, CachedSize* cached_size) {
+  total_size += WireFormat::ComputeUnknownFieldsSize(
+      metadata.unknown_fields<UnknownFieldSet>(
+          UnknownFieldSet::default_instance));
+  cached_size->Set(ToCachedSize(total_size));
+  return total_size;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
new file mode 100644
index 0000000..1acbf9e
--- /dev/null
+++ b/src/google/protobuf/wire_format.h
@@ -0,0 +1,414 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)
+//         atenasio@google.com (Chris Atenasio) (ZigZag transform)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// 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_WIRE_FORMAT_H__
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_H__
+
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class MapKey;           // map_field.h
+class UnknownFieldSet;  // unknown_field_set.h
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This class is for internal use by the protocol buffer library and by
+// protocol-compiler-generated message classes.  It must not be called
+// directly by clients.
+//
+// This class contains code for implementing the binary protocol buffer
+// wire format via reflection.  The WireFormatLite class implements the
+// non-reflection based routines.
+//
+// This class is really a namespace that contains only static methods
+class PROTOBUF_EXPORT WireFormat {
+ public:
+  // Given a field return its WireType
+  static inline WireFormatLite::WireType WireTypeForField(
+      const FieldDescriptor* field);
+
+  // Given a FieldDescriptor::Type return its WireType
+  static inline WireFormatLite::WireType WireTypeForFieldType(
+      FieldDescriptor::Type type);
+
+  // Compute the byte size of a tag.  For groups, this includes both the start
+  // and end tags.
+  static inline size_t TagSize(int field_number, FieldDescriptor::Type type);
+
+  // These procedures can be used to implement the methods of Message which
+  // handle parsing and serialization of the protocol buffer wire format
+  // using only the Reflection interface.  When you ask the protocol
+  // compiler to optimize for code size rather than speed, it will implement
+  // those methods in terms of these procedures.  Of course, these are much
+  // slower than the specialized implementations which the protocol compiler
+  // generates when told to optimize for speed.
+
+  // Read a message in protocol buffer wire format.
+  //
+  // This procedure reads either to the end of the input stream or through
+  // a WIRETYPE_END_GROUP tag ending the message, whichever comes first.
+  // It returns false if the input is invalid.
+  //
+  // Required fields are NOT checked by this method.  You must call
+  // IsInitialized() on the resulting message yourself.
+  static bool ParseAndMergePartial(io::CodedInputStream* input,
+                                   Message* message);
+
+  // This is meant for internal protobuf use (WireFormat is an internal class).
+  // This is the reflective implementation of the _InternalParse functionality.
+  static const char* _InternalParse(Message* msg, const char* ptr,
+                                    internal::ParseContext* ctx);
+
+  // Serialize a message in protocol buffer wire format.
+  //
+  // Any embedded messages within the message must have their correct sizes
+  // cached.  However, the top-level message need not; its size is passed as
+  // a parameter to this procedure.
+  //
+  // These return false iff the underlying stream returns a write error.
+  static void SerializeWithCachedSizes(const Message& message, int size,
+                                       io::CodedOutputStream* output) {
+    int expected_endpoint = output->ByteCount() + size;
+    output->SetCur(
+        _InternalSerialize(message, output->Cur(), output->EpsCopy()));
+    GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint)
+        << ": Protocol message serialized to a size different from what was "
+           "originally expected.  Perhaps it was modified by another thread "
+           "during serialization?";
+  }
+  static uint8_t* _InternalSerialize(const Message& message, uint8_t* target,
+                                     io::EpsCopyOutputStream* stream);
+
+  // Implements Message::ByteSize() via reflection.  WARNING:  The result
+  // of this method is *not* cached anywhere.  However, all embedded messages
+  // will have their ByteSize() methods called, so their sizes will be cached.
+  // Therefore, calling this method is sufficient to allow you to call
+  // WireFormat::SerializeWithCachedSizes() on the same object.
+  static size_t ByteSize(const Message& message);
+
+  // -----------------------------------------------------------------
+  // Helpers for dealing with unknown fields
+
+  // Skips a field value of the given WireType.  The input should start
+  // positioned immediately after the tag.  If unknown_fields is non-nullptr,
+  // the contents of the field will be added to it.
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag,
+                        UnknownFieldSet* unknown_fields);
+
+  // Reads and ignores a message from the input.  If unknown_fields is
+  // non-nullptr, the contents will be added to it.
+  static bool SkipMessage(io::CodedInputStream* input,
+                          UnknownFieldSet* unknown_fields);
+
+  // Read a packed enum field. If the is_valid function is not nullptr, values
+  // for which is_valid(value) returns false are appended to
+  // unknown_fields_stream.
+  static bool ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+                                             uint32_t field_number,
+                                             bool (*is_valid)(int),
+                                             UnknownFieldSet* unknown_fields,
+                                             RepeatedField<int>* values);
+
+  // Write the contents of an UnknownFieldSet to the output.
+  static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
+                                     io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeUnknownFieldsToArray(
+        unknown_fields, output->Cur(), output->EpsCopy()));
+  }
+  // Same as above, except writing directly to the provided buffer.
+  // Requires that the buffer have sufficient capacity for
+  // ComputeUnknownFieldsSize(unknown_fields).
+  //
+  // Returns a pointer past the last written byte.
+  static uint8_t* SerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target) {
+    io::EpsCopyOutputStream stream(
+        target, static_cast<int>(ComputeUnknownFieldsSize(unknown_fields)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalSerializeUnknownFieldsToArray(unknown_fields, target,
+                                                 &stream);
+  }
+  static uint8_t* InternalSerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target,
+      io::EpsCopyOutputStream* stream);
+
+  // Same thing except for messages that have the message_set_wire_format
+  // option.
+  static void SerializeUnknownMessageSetItems(
+      const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeUnknownMessageSetItemsToArray(
+        unknown_fields, output->Cur(), output->EpsCopy()));
+  }
+  // Same as above, except writing directly to the provided buffer.
+  // Requires that the buffer have sufficient capacity for
+  // ComputeUnknownMessageSetItemsSize(unknown_fields).
+  //
+  // Returns a pointer past the last written byte.
+  static uint8_t* SerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target);
+  static uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target,
+      io::EpsCopyOutputStream* stream);
+
+  // Compute the size of the UnknownFieldSet on the wire.
+  static size_t ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields);
+
+  // Same thing except for messages that have the message_set_wire_format
+  // option.
+  static size_t ComputeUnknownMessageSetItemsSize(
+      const UnknownFieldSet& unknown_fields);
+
+  // Helper functions for encoding and decoding tags.  (Inlined below and in
+  // _inl.h)
+  //
+  // This is different from MakeTag(field->number(), field->type()) in the
+  // case of packed repeated fields.
+  static uint32_t MakeTag(const FieldDescriptor* field);
+
+  // Parse a single field.  The input should start out positioned immediately
+  // after the tag.
+  static bool ParseAndMergeField(
+      uint32_t tag,
+      const FieldDescriptor* field,  // May be nullptr for unknown
+      Message* message, io::CodedInputStream* input);
+
+  // Serialize a single field.
+  static void SerializeFieldWithCachedSizes(
+      const FieldDescriptor* field,  // Cannot be nullptr
+      const Message& message, io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeField(field, message, output->Cur(),
+                                          output->EpsCopy()));
+  }
+  static uint8_t* InternalSerializeField(
+      const FieldDescriptor* field,  // Cannot be nullptr
+      const Message& message, uint8_t* target, io::EpsCopyOutputStream* stream);
+
+  // Compute size of a single field.  If the field is a message type, this
+  // will call ByteSize() for the embedded message, insuring that it caches
+  // its size.
+  static size_t FieldByteSize(const FieldDescriptor* field,  // Can't be nullptr
+                              const Message& message);
+
+  // Parse/serialize a MessageSet::Item group.  Used with messages that use
+  // option message_set_wire_format = true.
+  static bool ParseAndMergeMessageSetItem(io::CodedInputStream* input,
+                                          Message* message);
+  static void SerializeMessageSetItemWithCachedSizes(
+      const FieldDescriptor* field, const Message& message,
+      io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeMessageSetItem(
+        field, message, output->Cur(), output->EpsCopy()));
+  }
+  static uint8_t* InternalSerializeMessageSetItem(
+      const FieldDescriptor* field, const Message& message, uint8_t* target,
+      io::EpsCopyOutputStream* stream);
+  static size_t MessageSetItemByteSize(const FieldDescriptor* field,
+                                       const Message& message);
+
+  // Computes the byte size of a field, excluding tags. For packed fields, it
+  // only includes the size of the raw data, and not the size of the total
+  // length, but for other length-delimited types, the size of the length is
+  // included.
+  static size_t FieldDataOnlyByteSize(
+      const FieldDescriptor* field,  // Cannot be nullptr
+      const Message& message);
+
+  enum Operation {
+    PARSE = 0,
+    SERIALIZE = 1,
+  };
+
+  // Verifies that a string field is valid UTF8, logging an error if not.
+  // This function will not be called by newly generated protobuf code
+  // but remains present to support existing code.
+  static void VerifyUTF8String(const char* data, int size, Operation op);
+  // The NamedField variant takes a field name in order to produce an
+  // informative error message if verification fails.
+  static void VerifyUTF8StringNamedField(const char* data, int size,
+                                         Operation op, const char* field_name);
+
+ private:
+  struct MessageSetParser;
+  // Skip a MessageSet field.
+  static bool SkipMessageSetField(io::CodedInputStream* input,
+                                  uint32_t field_number,
+                                  UnknownFieldSet* unknown_fields);
+
+  // Parse a MessageSet field.
+  static bool ParseAndMergeMessageSetField(uint32_t field_number,
+                                           const FieldDescriptor* field,
+                                           Message* message,
+                                           io::CodedInputStream* input);
+  // Parses the value from the wire that belongs to tag.
+  static const char* _InternalParseAndMergeField(Message* msg, const char* ptr,
+                                                 internal::ParseContext* ctx,
+                                                 uint64_t tag,
+                                                 const Reflection* reflection,
+                                                 const FieldDescriptor* field);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat);
+};
+
+// Subclass of FieldSkipper which saves skipped fields to an UnknownFieldSet.
+class PROTOBUF_EXPORT UnknownFieldSetFieldSkipper : public FieldSkipper {
+ public:
+  UnknownFieldSetFieldSkipper(UnknownFieldSet* unknown_fields)
+      : unknown_fields_(unknown_fields) {}
+  ~UnknownFieldSetFieldSkipper() override {}
+
+  // implements FieldSkipper -----------------------------------------
+  bool SkipField(io::CodedInputStream* input, uint32_t tag) override;
+  bool SkipMessage(io::CodedInputStream* input) override;
+  void SkipUnknownEnum(int field_number, int value) override;
+
+ protected:
+  UnknownFieldSet* unknown_fields_;
+};
+
+// inline methods ====================================================
+
+inline WireFormatLite::WireType WireFormat::WireTypeForField(
+    const FieldDescriptor* field) {
+  if (field->is_packed()) {
+    return WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+  } else {
+    return WireTypeForFieldType(field->type());
+  }
+}
+
+inline WireFormatLite::WireType WireFormat::WireTypeForFieldType(
+    FieldDescriptor::Type type) {
+  // Some compilers don't like enum -> enum casts, so we implicit_cast to
+  // int first.
+  return WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(implicit_cast<int>(type)));
+}
+
+inline uint32_t WireFormat::MakeTag(const FieldDescriptor* field) {
+  return WireFormatLite::MakeTag(field->number(), WireTypeForField(field));
+}
+
+inline size_t WireFormat::TagSize(int field_number,
+                                  FieldDescriptor::Type type) {
+  // Some compilers don't like enum -> enum casts, so we implicit_cast to
+  // int first.
+  return WireFormatLite::TagSize(
+      field_number,
+      static_cast<WireFormatLite::FieldType>(implicit_cast<int>(type)));
+}
+
+inline void WireFormat::VerifyUTF8String(const char* data, int size,
+                                         WireFormat::Operation op) {
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  WireFormatLite::VerifyUtf8String(
+      data, size, static_cast<WireFormatLite::Operation>(op), nullptr);
+#else
+  // Avoid the compiler warning about unused variables.
+  (void)data;
+  (void)size;
+  (void)op;
+#endif
+}
+
+inline void WireFormat::VerifyUTF8StringNamedField(const char* data, int size,
+                                                   WireFormat::Operation op,
+                                                   const char* field_name) {
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  WireFormatLite::VerifyUtf8String(
+      data, size, static_cast<WireFormatLite::Operation>(op), field_name);
+#else
+  // Avoid the compiler warning about unused variables.
+  (void)data;
+  (void)size;
+  (void)op;
+  (void)field_name;
+#endif
+}
+
+
+inline uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  return WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+      unknown_fields, target, stream);
+}
+
+inline size_t ComputeUnknownMessageSetItemsSize(
+    const UnknownFieldSet& unknown_fields) {
+  return WireFormat::ComputeUnknownMessageSetItemsSize(unknown_fields);
+}
+
+// Compute the size of the UnknownFieldSet on the wire.
+PROTOBUF_EXPORT
+size_t ComputeUnknownFieldsSize(const InternalMetadata& metadata, size_t size,
+                                CachedSize* cached_size);
+
+size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
+                              const MapKey& value);
+
+uint8_t* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                        const MapKey& value, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream);
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_WIRE_FORMAT_H__
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
new file mode 100644
index 0000000..5ab1ca1
--- /dev/null
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -0,0 +1,818 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/wire_format_lite.h>
+
+#include <limits>
+#include <stack>
+#include <string>
+#include <vector>
+
+#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>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/stringprintf.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
+// 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;
+const int WireFormatLite::kMessageSetMessageTag;
+
+#endif
+
+// IBM xlC requires prefixing constants with WireFormatLite::
+const size_t WireFormatLite::kMessageSetItemTagsSize =
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetItemStartTag>::value +
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetItemEndTag>::value +
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetTypeIdTag>::value +
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetMessageTag>::value;
+
+const WireFormatLite::CppType
+    WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = {
+        static_cast<CppType>(0),  // 0 is reserved for errors
+
+        CPPTYPE_DOUBLE,   // TYPE_DOUBLE
+        CPPTYPE_FLOAT,    // TYPE_FLOAT
+        CPPTYPE_INT64,    // TYPE_INT64
+        CPPTYPE_UINT64,   // TYPE_UINT64
+        CPPTYPE_INT32,    // TYPE_INT32
+        CPPTYPE_UINT64,   // TYPE_FIXED64
+        CPPTYPE_UINT32,   // TYPE_FIXED32
+        CPPTYPE_BOOL,     // TYPE_BOOL
+        CPPTYPE_STRING,   // TYPE_STRING
+        CPPTYPE_MESSAGE,  // TYPE_GROUP
+        CPPTYPE_MESSAGE,  // TYPE_MESSAGE
+        CPPTYPE_STRING,   // TYPE_BYTES
+        CPPTYPE_UINT32,   // TYPE_UINT32
+        CPPTYPE_ENUM,     // TYPE_ENUM
+        CPPTYPE_INT32,    // TYPE_SFIXED32
+        CPPTYPE_INT64,    // TYPE_SFIXED64
+        CPPTYPE_INT32,    // TYPE_SINT32
+        CPPTYPE_INT64,    // TYPE_SINT64
+};
+
+const WireFormatLite::WireType
+    WireFormatLite::kWireTypeForFieldType[MAX_FIELD_TYPE + 1] = {
+        static_cast<WireFormatLite::WireType>(-1),  // invalid
+        WireFormatLite::WIRETYPE_FIXED64,           // TYPE_DOUBLE
+        WireFormatLite::WIRETYPE_FIXED32,           // TYPE_FLOAT
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_INT64
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_UINT64
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_INT32
+        WireFormatLite::WIRETYPE_FIXED64,           // TYPE_FIXED64
+        WireFormatLite::WIRETYPE_FIXED32,           // TYPE_FIXED32
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_BOOL
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED,  // TYPE_STRING
+        WireFormatLite::WIRETYPE_START_GROUP,       // TYPE_GROUP
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED,  // TYPE_MESSAGE
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED,  // TYPE_BYTES
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_UINT32
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_ENUM
+        WireFormatLite::WIRETYPE_FIXED32,           // TYPE_SFIXED32
+        WireFormatLite::WIRETYPE_FIXED64,           // TYPE_SFIXED64
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_SINT32
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_SINT64
+};
+
+bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32_t tag) {
+  // Field number 0 is illegal.
+  if (WireFormatLite::GetTagFieldNumber(tag) == 0) return false;
+  switch (WireFormatLite::GetTagWireType(tag)) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      uint64_t value;
+      if (!input->ReadVarint64(&value)) return false;
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      uint64_t value;
+      if (!input->ReadLittleEndian64(&value)) return false;
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      uint32_t length;
+      if (!input->ReadVarint32(&length)) return false;
+      if (!input->Skip(length)) return false;
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      if (!input->IncrementRecursionDepth()) return false;
+      if (!SkipMessage(input)) return false;
+      input->DecrementRecursionDepth();
+      // Check that the ending tag matched the starting tag.
+      if (!input->LastTagWas(
+              WireFormatLite::MakeTag(WireFormatLite::GetTagFieldNumber(tag),
+                                      WireFormatLite::WIRETYPE_END_GROUP))) {
+        return false;
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      return false;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32: {
+      uint32_t value;
+      if (!input->ReadLittleEndian32(&value)) return false;
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
+bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32_t tag,
+                               io::CodedOutputStream* output) {
+  // Field number 0 is illegal.
+  if (WireFormatLite::GetTagFieldNumber(tag) == 0) return false;
+  switch (WireFormatLite::GetTagWireType(tag)) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      uint64_t value;
+      if (!input->ReadVarint64(&value)) return false;
+      output->WriteVarint32(tag);
+      output->WriteVarint64(value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      uint64_t value;
+      if (!input->ReadLittleEndian64(&value)) return false;
+      output->WriteVarint32(tag);
+      output->WriteLittleEndian64(value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      uint32_t length;
+      if (!input->ReadVarint32(&length)) return false;
+      output->WriteVarint32(tag);
+      output->WriteVarint32(length);
+      // TODO(mkilavuz): Provide API to prevent extra string copying.
+      std::string temp;
+      if (!input->ReadString(&temp, length)) return false;
+      output->WriteString(temp);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      output->WriteVarint32(tag);
+      if (!input->IncrementRecursionDepth()) return false;
+      if (!SkipMessage(input, output)) return false;
+      input->DecrementRecursionDepth();
+      // Check that the ending tag matched the starting tag.
+      if (!input->LastTagWas(
+              WireFormatLite::MakeTag(WireFormatLite::GetTagFieldNumber(tag),
+                                      WireFormatLite::WIRETYPE_END_GROUP))) {
+        return false;
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      return false;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32: {
+      uint32_t value;
+      if (!input->ReadLittleEndian32(&value)) return false;
+      output->WriteVarint32(tag);
+      output->WriteLittleEndian32(value);
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
+bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+    if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+      // Must be the end of the message.
+      return true;
+    }
+
+    if (!SkipField(input, tag)) return false;
+  }
+}
+
+bool WireFormatLite::SkipMessage(io::CodedInputStream* input,
+                                 io::CodedOutputStream* output) {
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+    if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+      output->WriteVarint32(tag);
+      // Must be the end of the message.
+      return true;
+    }
+
+    if (!SkipField(input, tag, output)) return false;
+  }
+}
+
+bool FieldSkipper::SkipField(io::CodedInputStream* input, uint32_t tag) {
+  return WireFormatLite::SkipField(input, tag);
+}
+
+bool FieldSkipper::SkipMessage(io::CodedInputStream* input) {
+  return WireFormatLite::SkipMessage(input);
+}
+
+void FieldSkipper::SkipUnknownEnum(int /* field_number */, int /* value */) {
+  // Nothing.
+}
+
+bool CodedOutputStreamFieldSkipper::SkipField(io::CodedInputStream* input,
+                                              uint32_t tag) {
+  return WireFormatLite::SkipField(input, tag, unknown_fields_);
+}
+
+bool CodedOutputStreamFieldSkipper::SkipMessage(io::CodedInputStream* input) {
+  return WireFormatLite::SkipMessage(input, unknown_fields_);
+}
+
+void CodedOutputStreamFieldSkipper::SkipUnknownEnum(int field_number,
+                                                    int value) {
+  unknown_fields_->WriteVarint32(field_number);
+  unknown_fields_->WriteVarint64(value);
+}
+
+bool WireFormatLite::ReadPackedEnumPreserveUnknowns(
+    io::CodedInputStream* input, int field_number, bool (*is_valid)(int),
+    io::CodedOutputStream* unknown_fields_stream, RepeatedField<int>* values) {
+  uint32_t length;
+  if (!input->ReadVarint32(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    int value;
+    if (!ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(input, &value)) {
+      return false;
+    }
+    if (is_valid == nullptr || is_valid(value)) {
+      values->Add(value);
+    } else {
+      uint32_t tag = WireFormatLite::MakeTag(field_number,
+                                             WireFormatLite::WIRETYPE_VARINT);
+      unknown_fields_stream->WriteVarint32(tag);
+      unknown_fields_stream->WriteVarint32(value);
+    }
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+#if !defined(PROTOBUF_LITTLE_ENDIAN)
+
+namespace {
+void EncodeFixedSizeValue(float v, uint8_t* dest) {
+  WireFormatLite::WriteFloatNoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(double v, uint8_t* dest) {
+  WireFormatLite::WriteDoubleNoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(uint32_t v, uint8_t* dest) {
+  WireFormatLite::WriteFixed32NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(uint64_t v, uint8_t* dest) {
+  WireFormatLite::WriteFixed64NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(int32_t v, uint8_t* dest) {
+  WireFormatLite::WriteSFixed32NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(int64_t v, uint8_t* dest) {
+  WireFormatLite::WriteSFixed64NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(bool v, uint8_t* dest) {
+  WireFormatLite::WriteBoolNoTagToArray(v, dest);
+}
+}  // anonymous namespace
+
+#endif  // !defined(PROTOBUF_LITTLE_ENDIAN)
+
+template <typename CType>
+static void WriteArray(const CType* a, int n, io::CodedOutputStream* output) {
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+  output->WriteRaw(reinterpret_cast<const char*>(a), n * sizeof(a[0]));
+#else
+  const int kAtATime = 128;
+  uint8_t buf[sizeof(CType) * kAtATime];
+  for (int i = 0; i < n; i += kAtATime) {
+    int to_do = std::min(kAtATime, n - i);
+    uint8_t* ptr = buf;
+    for (int j = 0; j < to_do; j++) {
+      EncodeFixedSizeValue(a[i + j], ptr);
+      ptr += sizeof(a[0]);
+    }
+    output->WriteRaw(buf, to_do * sizeof(a[0]));
+  }
+#endif
+}
+
+void WireFormatLite::WriteFloatArray(const float* a, int n,
+                                     io::CodedOutputStream* output) {
+  WriteArray<float>(a, n, output);
+}
+
+void WireFormatLite::WriteDoubleArray(const double* a, int n,
+                                      io::CodedOutputStream* output) {
+  WriteArray<double>(a, n, output);
+}
+
+void WireFormatLite::WriteFixed32Array(const uint32_t* a, int n,
+                                       io::CodedOutputStream* output) {
+  WriteArray<uint32_t>(a, n, output);
+}
+
+void WireFormatLite::WriteFixed64Array(const uint64_t* a, int n,
+                                       io::CodedOutputStream* output) {
+  WriteArray<uint64_t>(a, n, output);
+}
+
+void WireFormatLite::WriteSFixed32Array(const int32_t* a, int n,
+                                        io::CodedOutputStream* output) {
+  WriteArray<int32_t>(a, n, output);
+}
+
+void WireFormatLite::WriteSFixed64Array(const int64_t* a, int n,
+                                        io::CodedOutputStream* output) {
+  WriteArray<int64_t>(a, n, output);
+}
+
+void WireFormatLite::WriteBoolArray(const bool* a, int n,
+                                    io::CodedOutputStream* output) {
+  WriteArray<bool>(a, n, output);
+}
+
+void WireFormatLite::WriteInt32(int field_number, int32_t value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteInt32NoTag(value, output);
+}
+void WireFormatLite::WriteInt64(int field_number, int64_t value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteInt64NoTag(value, output);
+}
+void WireFormatLite::WriteUInt32(int field_number, uint32_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteUInt32NoTag(value, output);
+}
+void WireFormatLite::WriteUInt64(int field_number, uint64_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteUInt64NoTag(value, output);
+}
+void WireFormatLite::WriteSInt32(int field_number, int32_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteSInt32NoTag(value, output);
+}
+void WireFormatLite::WriteSInt64(int field_number, int64_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteSInt64NoTag(value, output);
+}
+void WireFormatLite::WriteFixed32(int field_number, uint32_t value,
+                                  io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED32, output);
+  WriteFixed32NoTag(value, output);
+}
+void WireFormatLite::WriteFixed64(int field_number, uint64_t value,
+                                  io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED64, output);
+  WriteFixed64NoTag(value, output);
+}
+void WireFormatLite::WriteSFixed32(int field_number, int32_t value,
+                                   io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED32, output);
+  WriteSFixed32NoTag(value, output);
+}
+void WireFormatLite::WriteSFixed64(int field_number, int64_t value,
+                                   io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED64, output);
+  WriteSFixed64NoTag(value, output);
+}
+void WireFormatLite::WriteFloat(int field_number, float value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED32, output);
+  WriteFloatNoTag(value, output);
+}
+void WireFormatLite::WriteDouble(int field_number, double value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED64, output);
+  WriteDoubleNoTag(value, output);
+}
+void WireFormatLite::WriteBool(int field_number, bool value,
+                               io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteBoolNoTag(value, output);
+}
+void WireFormatLite::WriteEnum(int field_number, int value,
+                               io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteEnumNoTag(value, output);
+}
+
+constexpr size_t kInt32MaxSize = std::numeric_limits<int32_t>::max();
+
+void WireFormatLite::WriteString(int field_number, const std::string& value,
+                                 io::CodedOutputStream* output) {
+  // String is for UTF-8 text only
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteString(value);
+}
+void WireFormatLite::WriteStringMaybeAliased(int field_number,
+                                             const std::string& value,
+                                             io::CodedOutputStream* output) {
+  // String is for UTF-8 text only
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteRawMaybeAliased(value.data(), value.size());
+}
+void WireFormatLite::WriteBytes(int field_number, const std::string& value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteString(value);
+}
+void WireFormatLite::WriteBytesMaybeAliased(int field_number,
+                                            const std::string& value,
+                                            io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteRawMaybeAliased(value.data(), value.size());
+}
+
+
+void WireFormatLite::WriteGroup(int field_number, const MessageLite& value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_START_GROUP, output);
+  value.SerializeWithCachedSizes(output);
+  WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+
+void WireFormatLite::WriteMessage(int field_number, const MessageLite& value,
+                                  io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  const int size = value.GetCachedSize();
+  output->WriteVarint32(size);
+  value.SerializeWithCachedSizes(output);
+}
+
+uint8_t* WireFormatLite::InternalWriteGroup(int field_number,
+                                            const MessageLite& value,
+                                            uint8_t* target,
+                                            io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
+  target = value._InternalSerialize(target, stream);
+  target = stream->EnsureSpace(target);
+  return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
+}
+
+uint8_t* WireFormatLite::InternalWriteMessage(int field_number,
+                                              const MessageLite& value,
+                                              int cached_size, uint8_t* target,
+                                              io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(
+      static_cast<uint32_t>(cached_size), target);
+  return value._InternalSerialize(target, stream);
+}
+
+void WireFormatLite::WriteSubMessageMaybeToArray(
+    int /*size*/, const MessageLite& value, io::CodedOutputStream* output) {
+  output->SetCur(value._InternalSerialize(output->Cur(), output->EpsCopy()));
+}
+
+void WireFormatLite::WriteGroupMaybeToArray(int field_number,
+                                            const MessageLite& value,
+                                            io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_START_GROUP, output);
+  const int size = value.GetCachedSize();
+  WriteSubMessageMaybeToArray(size, value, output);
+  WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+
+void WireFormatLite::WriteMessageMaybeToArray(int field_number,
+                                              const MessageLite& value,
+                                              io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  const int size = value.GetCachedSize();
+  output->WriteVarint32(size);
+  WriteSubMessageMaybeToArray(size, value, output);
+}
+
+PROTOBUF_NDEBUG_INLINE static bool ReadBytesToString(
+    io::CodedInputStream* input, std::string* value);
+inline static bool ReadBytesToString(io::CodedInputStream* input,
+                                     std::string* value) {
+  uint32_t length;
+  return input->ReadVarint32(&length) && input->ReadString(value, length);
+}
+
+bool WireFormatLite::ReadBytes(io::CodedInputStream* input,
+                               std::string* value) {
+  return ReadBytesToString(input, value);
+}
+
+bool WireFormatLite::ReadBytes(io::CodedInputStream* input, std::string** p) {
+  if (*p == &GetEmptyStringAlreadyInited()) {
+    *p = new std::string();
+  }
+  return ReadBytesToString(input, *p);
+}
+
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
+                       bool emit_stacktrace) {
+  std::string stacktrace;
+  (void)emit_stacktrace;  // Parameter is used by Google-internal code.
+  std::string quoted_field_name = "";
+  if (!field_name.empty()) {
+    if (!message_name.empty()) {
+      quoted_field_name =
+          StrCat(" '", message_name, ".", field_name, "'");
+    } else {
+      quoted_field_name = StrCat(" '", field_name, "'");
+    }
+  }
+  std::string error_message =
+      StrCat("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. ",
+                   stacktrace);
+  GOOGLE_LOG(ERROR) << error_message;
+}
+
+bool WireFormatLite::VerifyUtf8String(const char* data, int size, Operation op,
+                                      const char* field_name) {
+  if (!IsStructurallyValidUTF8(data, size)) {
+    const char* operation_str = nullptr;
+    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.
+    }
+    PrintUTF8ErrorLog("", field_name, operation_str, false);
+    return false;
+  }
+  return true;
+}
+
+// this code is deliberately written such that clang makes it into really
+// efficient SSE code.
+template <bool ZigZag, bool SignExtended, typename T>
+static size_t VarintSize(const T* data, const int n) {
+  static_assert(sizeof(T) == 4, "This routine only works for 32 bit integers");
+  // is_unsigned<T> => !ZigZag
+  static_assert(
+      (std::is_unsigned<T>::value ^ ZigZag) || std::is_signed<T>::value,
+      "Cannot ZigZag encode unsigned types");
+  // is_unsigned<T> => !SignExtended
+  static_assert(
+      (std::is_unsigned<T>::value ^ SignExtended) || std::is_signed<T>::value,
+      "Cannot SignExtended unsigned types");
+  static_assert(!(SignExtended && ZigZag),
+                "Cannot SignExtended and ZigZag on the same type");
+  uint32_t sum = n;
+  uint32_t msb_sum = 0;
+  for (int i = 0; i < n; i++) {
+    uint32_t x = data[i];
+    if (ZigZag) {
+      x = WireFormatLite::ZigZagEncode32(x);
+    } else if (SignExtended) {
+      msb_sum += x >> 31;
+    }
+    // clang is so smart that it produces optimal SSE sequence unrolling
+    // the loop 8 ints at a time. With a sequence of 4
+    // cmpres = cmpgt x, sizeclass  ( -1 or 0)
+    // sum = sum - cmpres
+    if (x > 0x7F) sum++;
+    if (x > 0x3FFF) sum++;
+    if (x > 0x1FFFFF) sum++;
+    if (x > 0xFFFFFFF) sum++;
+  }
+  if (SignExtended) sum += msb_sum * 5;
+  return sum;
+}
+
+template <bool ZigZag, typename T>
+static size_t VarintSize64(const T* data, const int n) {
+  static_assert(sizeof(T) == 8, "This routine only works for 64 bit integers");
+  // is_unsigned<T> => !ZigZag
+  static_assert(!ZigZag || !std::is_unsigned<T>::value,
+                "Cannot ZigZag encode unsigned types");
+  uint64_t sum = n;
+  for (int i = 0; i < n; i++) {
+    uint64_t x = data[i];
+    if (ZigZag) {
+      x = WireFormatLite::ZigZagEncode64(x);
+    }
+    // First step is a binary search, we can't branch in sse so we use the
+    // result of the compare to adjust sum and appropriately. This code is
+    // written to make clang recognize the vectorization.
+    uint64_t tmp = x >= (static_cast<uint64_t>(1) << 35) ? -1 : 0;
+    sum += 5 & tmp;
+    x >>= 35 & tmp;
+    if (x > 0x7F) sum++;
+    if (x > 0x3FFF) sum++;
+    if (x > 0x1FFFFF) sum++;
+    if (x > 0xFFFFFFF) sum++;
+  }
+  return sum;
+}
+
+// GCC does not recognize the vectorization opportunity
+// and other platforms are untested, in those cases using the optimized
+// varint size routine for each element is faster.
+// Hence we enable it only for clang
+#if defined(__SSE__) && defined(__clang__)
+size_t WireFormatLite::Int32Size(const RepeatedField<int32_t>& value) {
+  return VarintSize<false, true>(value.data(), value.size());
+}
+
+size_t WireFormatLite::UInt32Size(const RepeatedField<uint32_t>& value) {
+  return VarintSize<false, false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::SInt32Size(const RepeatedField<int32_t>& value) {
+  return VarintSize<true, false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::EnumSize(const RepeatedField<int>& value) {
+  // On ILP64, sizeof(int) == 8, which would require a different template.
+  return VarintSize<false, true>(value.data(), value.size());
+}
+
+#else  // !(defined(__SSE4_1__) && defined(__clang__))
+
+size_t WireFormatLite::Int32Size(const RepeatedField<int32_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += Int32Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::UInt32Size(const RepeatedField<uint32_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += UInt32Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::SInt32Size(const RepeatedField<int32_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += SInt32Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::EnumSize(const RepeatedField<int>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += EnumSize(value.Get(i));
+  }
+  return out;
+}
+
+#endif
+
+// Micro benchmarks show that the SSE improved loop only starts beating
+// the normal loop on Haswell platforms and then only for >32 ints. We
+// disable this for now. Some specialized users might find it worthwhile to
+// enable this.
+#define USE_SSE_FOR_64_BIT_INTEGER_ARRAYS 0
+#if USE_SSE_FOR_64_BIT_INTEGER_ARRAYS
+size_t WireFormatLite::Int64Size(const RepeatedField<int64_t>& value) {
+  return VarintSize64<false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::UInt64Size(const RepeatedField<uint64_t>& value) {
+  return VarintSize64<false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::SInt64Size(const RepeatedField<int64_t>& value) {
+  return VarintSize64<true>(value.data(), value.size());
+}
+
+#else
+
+size_t WireFormatLite::Int64Size(const RepeatedField<int64_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += Int64Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::UInt64Size(const RepeatedField<uint64_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += UInt64Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::SInt64Size(const RepeatedField<int64_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += SInt64Size(value.Get(i));
+  }
+  return out;
+}
+
+#endif
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
new file mode 100644
index 0000000..80d3961
--- /dev/null
+++ b/src/google/protobuf/wire_format_lite.h
@@ -0,0 +1,1908 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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)
+//         atenasio@google.com (Chris Atenasio) (ZigZag transform)
+//         wink@google.com (Wink Saville) (refactored from wire_format.h)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// 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_WIRE_FORMAT_LITE_H__
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
+
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+
+// Do UTF-8 validation on string type in Debug build only
+#ifndef NDEBUG
+#define GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+#endif
+
+// Avoid conflict with iOS where <ConditionalMacros.h> #defines TYPE_BOOL.
+//
+// If some one needs the macro TYPE_BOOL in a file that includes this header,
+// it's possible to bring it back using push/pop_macro as follows.
+//
+// #pragma push_macro("TYPE_BOOL")
+// #include this header and/or all headers that need the macro to be undefined.
+// #pragma pop_macro("TYPE_BOOL")
+#undef TYPE_BOOL
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This class is for internal use by the protocol buffer library and by
+// protocol-compiler-generated message classes.  It must not be called
+// directly by clients.
+//
+// This class contains helpers for implementing the binary protocol buffer
+// wire format without the need for reflection. Use WireFormat when using
+// reflection.
+//
+// This class is really a namespace that contains only static methods.
+class PROTOBUF_EXPORT WireFormatLite {
+ public:
+  // -----------------------------------------------------------------
+  // Helper constants and functions related to the format.  These are
+  // mostly meant for internal and generated code to use.
+
+  // The wire format is composed of a sequence of tag/value pairs, each
+  // of which contains the value of one field (or one element of a repeated
+  // field).  Each tag is encoded as a varint.  The lower bits of the tag
+  // identify its wire type, which specifies the format of the data to follow.
+  // The rest of the bits contain the field number.  Each type of field (as
+  // declared by FieldDescriptor::Type, in descriptor.h) maps to one of
+  // these wire types.  Immediately following each tag is the field's value,
+  // encoded in the format specified by the wire type.  Because the tag
+  // identifies the encoding of this data, it is possible to skip
+  // unrecognized fields for forwards compatibility.
+
+  enum WireType {
+    WIRETYPE_VARINT = 0,
+    WIRETYPE_FIXED64 = 1,
+    WIRETYPE_LENGTH_DELIMITED = 2,
+    WIRETYPE_START_GROUP = 3,
+    WIRETYPE_END_GROUP = 4,
+    WIRETYPE_FIXED32 = 5,
+  };
+
+  // Lite alternative to FieldDescriptor::Type.  Must be kept in sync.
+  enum FieldType {
+    TYPE_DOUBLE = 1,
+    TYPE_FLOAT = 2,
+    TYPE_INT64 = 3,
+    TYPE_UINT64 = 4,
+    TYPE_INT32 = 5,
+    TYPE_FIXED64 = 6,
+    TYPE_FIXED32 = 7,
+    TYPE_BOOL = 8,
+    TYPE_STRING = 9,
+    TYPE_GROUP = 10,
+    TYPE_MESSAGE = 11,
+    TYPE_BYTES = 12,
+    TYPE_UINT32 = 13,
+    TYPE_ENUM = 14,
+    TYPE_SFIXED32 = 15,
+    TYPE_SFIXED64 = 16,
+    TYPE_SINT32 = 17,
+    TYPE_SINT64 = 18,
+    MAX_FIELD_TYPE = 18,
+  };
+
+  // Lite alternative to FieldDescriptor::CppType.  Must be kept in sync.
+  enum CppType {
+    CPPTYPE_INT32 = 1,
+    CPPTYPE_INT64 = 2,
+    CPPTYPE_UINT32 = 3,
+    CPPTYPE_UINT64 = 4,
+    CPPTYPE_DOUBLE = 5,
+    CPPTYPE_FLOAT = 6,
+    CPPTYPE_BOOL = 7,
+    CPPTYPE_ENUM = 8,
+    CPPTYPE_STRING = 9,
+    CPPTYPE_MESSAGE = 10,
+    MAX_CPPTYPE = 10,
+  };
+
+  // Helper method to get the CppType for a particular Type.
+  static CppType FieldTypeToCppType(FieldType type);
+
+  // Given a FieldDescriptor::Type return its WireType
+  static inline WireFormatLite::WireType WireTypeForFieldType(
+      WireFormatLite::FieldType type) {
+    return kWireTypeForFieldType[type];
+  }
+
+  // Number of bits in a tag which identify the wire type.
+  static constexpr int kTagTypeBits = 3;
+  // Mask for those bits.
+  static constexpr uint32_t kTagTypeMask = (1 << kTagTypeBits) - 1;
+
+  // Helper functions for encoding and decoding tags.  (Inlined below and in
+  // _inl.h)
+  //
+  // This is different from MakeTag(field->number(), field->type()) in the
+  // case of packed repeated fields.
+  constexpr static uint32_t MakeTag(int field_number, WireType type);
+  static WireType GetTagWireType(uint32_t tag);
+  static int GetTagFieldNumber(uint32_t tag);
+
+  // Compute the byte size of a tag.  For groups, this includes both the start
+  // and end tags.
+  static inline size_t TagSize(int field_number,
+                               WireFormatLite::FieldType type);
+
+  // Skips a field value with the given tag.  The input should start
+  // positioned immediately after the tag.  Skipped values are simply
+  // discarded, not recorded anywhere.  See WireFormat::SkipField() for a
+  // version that records to an UnknownFieldSet.
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag);
+
+  // Skips a field value with the given tag.  The input should start
+  // positioned immediately after the tag. Skipped values are recorded to a
+  // CodedOutputStream.
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag,
+                        io::CodedOutputStream* output);
+
+  // Reads and ignores a message from the input.  Skipped values are simply
+  // discarded, not recorded anywhere.  See WireFormat::SkipMessage() for a
+  // version that records to an UnknownFieldSet.
+  static bool SkipMessage(io::CodedInputStream* input);
+
+  // Reads and ignores a message from the input.  Skipped values are recorded
+  // to a CodedOutputStream.
+  static bool SkipMessage(io::CodedInputStream* input,
+                          io::CodedOutputStream* output);
+
+  // This macro does the same thing as WireFormatLite::MakeTag(), but the
+  // result is usable as a compile-time constant, which makes it usable
+  // as a switch case or a template input.  WireFormatLite::MakeTag() is more
+  // type-safe, though, so prefer it if possible.
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \
+  static_cast<uint32_t>((static_cast<uint32_t>(FIELD_NUMBER) << 3) | (TYPE))
+
+  // These are the tags for the old MessageSet format, which was defined as:
+  //   message MessageSet {
+  //     repeated group Item = 1 {
+  //       required int32 type_id = 2;
+  //       required string message = 3;
+  //     }
+  //   }
+  static constexpr int kMessageSetItemNumber = 1;
+  static constexpr int kMessageSetTypeIdNumber = 2;
+  static constexpr int kMessageSetMessageNumber = 3;
+  static const int kMessageSetItemStartTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetItemNumber, WireFormatLite::WIRETYPE_START_GROUP);
+  static const int kMessageSetItemEndTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetItemNumber, WireFormatLite::WIRETYPE_END_GROUP);
+  static const int kMessageSetTypeIdTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetTypeIdNumber, WireFormatLite::WIRETYPE_VARINT);
+  static const int kMessageSetMessageTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetMessageNumber, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+
+  // Byte size of all tags of a MessageSet::Item combined.
+  static const size_t kMessageSetItemTagsSize;
+
+  // Helper functions for converting between floats/doubles and IEEE-754
+  // uint32s/uint64s so that they can be written.  (Assumes your platform
+  // uses IEEE-754 floats.)
+  static uint32_t EncodeFloat(float value);
+  static float DecodeFloat(uint32_t value);
+  static uint64_t EncodeDouble(double value);
+  static double DecodeDouble(uint64_t value);
+
+  // Helper functions for mapping signed integers to unsigned integers in
+  // such a way that numbers with small magnitudes will encode to smaller
+  // varints.  If you simply static_cast a negative number to an unsigned
+  // number and varint-encode it, it will always take 10 bytes, defeating
+  // the purpose of varint.  So, for the "sint32" and "sint64" field types,
+  // we ZigZag-encode the values.
+  static uint32_t ZigZagEncode32(int32_t n);
+  static int32_t ZigZagDecode32(uint32_t n);
+  static uint64_t ZigZagEncode64(int64_t n);
+  static int64_t ZigZagDecode64(uint64_t n);
+
+  // =================================================================
+  // Methods for reading/writing individual field.
+
+  // Read fields, not including tags.  The assumption is that you already
+  // read the tag to determine what field to read.
+
+  // 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>
+  PROTOBUF_NDEBUG_INLINE static bool ReadPrimitive(io::CodedInputStream* 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>
+  PROTOBUF_NDEBUG_INLINE static bool ReadRepeatedPrimitive(
+      int tag_size, uint32_t tag, io::CodedInputStream* input,
+      RepeatedField<CType>* value);
+
+  // Identical to ReadRepeatedPrimitive, except will not inline the
+  // implementation.
+  template <typename CType, enum FieldType DeclaredType>
+  static bool ReadRepeatedPrimitiveNoInline(int tag_size, uint32_t tag,
+                                            io::CodedInputStream* input,
+                                            RepeatedField<CType>* value);
+
+  // Reads a primitive value directly from the provided buffer. It returns a
+  // pointer past the segment of data that was read.
+  //
+  // 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>
+  PROTOBUF_NDEBUG_INLINE static const uint8_t* ReadPrimitiveFromArray(
+      const uint8_t* buffer, CType* value);
+
+  // Reads a primitive packed field.
+  //
+  // This is only implemented for packable types.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadPackedPrimitive(
+      io::CodedInputStream* input, RepeatedField<CType>* value);
+
+  // Identical to ReadPackedPrimitive, except will not inline the
+  // implementation.
+  template <typename CType, enum FieldType DeclaredType>
+  static bool ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
+                                          RepeatedField<CType>* value);
+
+  // Read a packed enum field. If the is_valid function is not nullptr, values
+  // for which is_valid(value) returns false are silently dropped.
+  static bool ReadPackedEnumNoInline(io::CodedInputStream* input,
+                                     bool (*is_valid)(int),
+                                     RepeatedField<int>* values);
+
+  // Read a packed enum field. If the is_valid function is not nullptr, values
+  // for which is_valid(value) returns false are appended to
+  // unknown_fields_stream.
+  static bool ReadPackedEnumPreserveUnknowns(
+      io::CodedInputStream* input, int field_number, bool (*is_valid)(int),
+      io::CodedOutputStream* unknown_fields_stream, RepeatedField<int>* values);
+
+  // Read a string.  ReadString(..., std::string* value) requires an
+  // existing std::string.
+  static inline bool ReadString(io::CodedInputStream* input,
+                                std::string* value);
+  // ReadString(..., std::string** p) is internal-only, and should only be
+  // called from generated code. It starts by setting *p to "new std::string" if
+  // *p == &GetEmptyStringAlreadyInited().  It then invokes
+  // ReadString(io::CodedInputStream* input, *p).  This is useful for reducing
+  // code size.
+  static inline bool ReadString(io::CodedInputStream* input, std::string** p);
+  // Analogous to ReadString().
+  static bool ReadBytes(io::CodedInputStream* input, std::string* value);
+  static bool ReadBytes(io::CodedInputStream* input, std::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);
+
+  template <typename MessageType>
+  static inline bool ReadGroup(int field_number, io::CodedInputStream* input,
+                               MessageType* value);
+
+  template <typename MessageType>
+  static inline bool ReadMessage(io::CodedInputStream* input,
+                                 MessageType* value);
+
+  template <typename MessageType>
+  static inline bool ReadMessageNoVirtual(io::CodedInputStream* input,
+                                          MessageType* value) {
+    return ReadMessage(input, 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.
+  PROTOBUF_NDEBUG_INLINE static void WriteTag(int field_number, WireType type,
+                                              io::CodedOutputStream* output);
+
+  // Write fields, without tags.
+  PROTOBUF_NDEBUG_INLINE static void WriteInt32NoTag(
+      int32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteInt64NoTag(
+      int64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteUInt32NoTag(
+      uint32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteUInt64NoTag(
+      uint64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSInt32NoTag(
+      int32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSInt64NoTag(
+      int64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteFixed32NoTag(
+      uint32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteFixed64NoTag(
+      uint64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSFixed32NoTag(
+      int32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSFixed64NoTag(
+      int64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteFloatNoTag(
+      float value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteDoubleNoTag(
+      double value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteBoolNoTag(
+      bool value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteEnumNoTag(
+      int value, io::CodedOutputStream* output);
+
+  // Write array of primitive fields, without tags
+  static void WriteFloatArray(const float* a, int n,
+                              io::CodedOutputStream* output);
+  static void WriteDoubleArray(const double* a, int n,
+                               io::CodedOutputStream* output);
+  static void WriteFixed32Array(const uint32_t* a, int n,
+                                io::CodedOutputStream* output);
+  static void WriteFixed64Array(const uint64_t* a, int n,
+                                io::CodedOutputStream* output);
+  static void WriteSFixed32Array(const int32_t* a, int n,
+                                 io::CodedOutputStream* output);
+  static void WriteSFixed64Array(const int64_t* a, int n,
+                                 io::CodedOutputStream* output);
+  static void WriteBoolArray(const bool* a, int n,
+                             io::CodedOutputStream* output);
+
+  // Write fields, including tags.
+  static void WriteInt32(int field_number, int32_t value,
+                         io::CodedOutputStream* output);
+  static void WriteInt64(int field_number, int64_t value,
+                         io::CodedOutputStream* output);
+  static void WriteUInt32(int field_number, uint32_t value,
+                          io::CodedOutputStream* output);
+  static void WriteUInt64(int field_number, uint64_t value,
+                          io::CodedOutputStream* output);
+  static void WriteSInt32(int field_number, int32_t value,
+                          io::CodedOutputStream* output);
+  static void WriteSInt64(int field_number, int64_t value,
+                          io::CodedOutputStream* output);
+  static void WriteFixed32(int field_number, uint32_t value,
+                           io::CodedOutputStream* output);
+  static void WriteFixed64(int field_number, uint64_t value,
+                           io::CodedOutputStream* output);
+  static void WriteSFixed32(int field_number, int32_t value,
+                            io::CodedOutputStream* output);
+  static void WriteSFixed64(int field_number, int64_t value,
+                            io::CodedOutputStream* output);
+  static void WriteFloat(int field_number, float value,
+                         io::CodedOutputStream* output);
+  static void WriteDouble(int field_number, double value,
+                          io::CodedOutputStream* output);
+  static void WriteBool(int field_number, bool value,
+                        io::CodedOutputStream* output);
+  static void WriteEnum(int field_number, int value,
+                        io::CodedOutputStream* output);
+
+  static void WriteString(int field_number, const std::string& value,
+                          io::CodedOutputStream* output);
+  static void WriteBytes(int field_number, const std::string& value,
+                         io::CodedOutputStream* output);
+  static void WriteStringMaybeAliased(int field_number,
+                                      const std::string& value,
+                                      io::CodedOutputStream* output);
+  static void WriteBytesMaybeAliased(int field_number, const std::string& value,
+                                     io::CodedOutputStream* output);
+
+  static void WriteGroup(int field_number, const MessageLite& value,
+                         io::CodedOutputStream* output);
+  static void WriteMessage(int field_number, const MessageLite& value,
+                           io::CodedOutputStream* output);
+  // Like above, but these will check if the output stream has enough
+  // space to write directly to a flat array.
+  static void WriteGroupMaybeToArray(int field_number, const MessageLite& value,
+                                     io::CodedOutputStream* output);
+  static void WriteMessageMaybeToArray(int field_number,
+                                       const MessageLite& value,
+                                       io::CodedOutputStream* 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 void WriteGroupNoVirtual(int field_number,
+                                         const MessageType& value,
+                                         io::CodedOutputStream* output);
+  template <typename MessageType>
+  static inline void WriteMessageNoVirtual(int field_number,
+                                           const MessageType& value,
+                                           io::CodedOutputStream* output);
+
+  // Like above, but use only *ToArray methods of CodedOutputStream.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteTagToArray(int field_number,
+                                                         WireType type,
+                                                         uint8_t* target);
+
+  // Write fields, without tags.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32NoTagToArray(
+      uint32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64NoTagToArray(
+      uint64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32NoTagToArray(
+      uint32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64NoTagToArray(
+      uint64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatNoTagToArray(
+      float value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleNoTagToArray(
+      double value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolNoTagToArray(bool value,
+                                                               uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumNoTagToArray(int value,
+                                                               uint8_t* target);
+
+  // Write fields, without tags.  These require that value.size() > 0.
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WritePrimitiveNoTagToArray(
+      const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+      uint8_t* target);
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixedNoTagToArray(
+      const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+      uint8_t* target);
+
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32NoTagToArray(
+      const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64NoTagToArray(
+      const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32NoTagToArray(
+      const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64NoTagToArray(
+      const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatNoTagToArray(
+      const RepeatedField<float>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleNoTagToArray(
+      const RepeatedField<double>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolNoTagToArray(
+      const RepeatedField<bool>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumNoTagToArray(
+      const RepeatedField<int>& value, uint8_t* output);
+
+  // Write fields, including tags.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32ToArray(int field_number,
+                                                           int32_t value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64ToArray(int field_number,
+                                                           int64_t value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32ToArray(int field_number,
+                                                            uint32_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64ToArray(int field_number,
+                                                            uint64_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32ToArray(int field_number,
+                                                            int32_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64ToArray(int field_number,
+                                                            int64_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32ToArray(int field_number,
+                                                             uint32_t value,
+                                                             uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64ToArray(int field_number,
+                                                             uint64_t value,
+                                                             uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32ToArray(int field_number,
+                                                              int32_t value,
+                                                              uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64ToArray(int field_number,
+                                                              int64_t value,
+                                                              uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatToArray(int field_number,
+                                                           float value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleToArray(int field_number,
+                                                            double value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolToArray(int field_number,
+                                                          bool value,
+                                                          uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumToArray(int field_number,
+                                                          int value,
+                                                          uint8_t* target);
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WritePrimitiveToArray(
+      int field_number, const RepeatedField<T>& value,
+      uint8_t* (*Writer)(int, T, uint8_t*), uint8_t* target);
+
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32ToArray(
+      int field_number, const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64ToArray(
+      int field_number, const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32ToArray(
+      int field_number, const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64ToArray(
+      int field_number, const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatToArray(
+      int field_number, const RepeatedField<float>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleToArray(
+      int field_number, const RepeatedField<double>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolToArray(
+      int field_number, const RepeatedField<bool>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumToArray(
+      int field_number, const RepeatedField<int>& value, uint8_t* output);
+
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteStringToArray(
+      int field_number, const std::string& value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBytesToArray(
+      int field_number, const std::string& value, uint8_t* target);
+
+  // Whether to serialize deterministically (e.g., map keys are
+  // sorted) is a property of a CodedOutputStream, and in the process
+  // of serialization, the "ToArray" variants may be invoked.  But they don't
+  // have a CodedOutputStream available, so they get an additional parameter
+  // telling them whether to serialize deterministically.
+  static uint8_t* InternalWriteGroup(int field_number, const MessageLite& value,
+                                     uint8_t* target,
+                                     io::EpsCopyOutputStream* stream);
+  static uint8_t* InternalWriteMessage(int field_number,
+                                       const MessageLite& value,
+                                       int cached_size, uint8_t* target,
+                                       io::EpsCopyOutputStream* stream);
+
+  // 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>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteGroupNoVirtualToArray(
+      int field_number, const MessageType& value, uint8_t* target);
+  template <typename MessageType>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteMessageNoVirtualToArray(
+      int field_number, const MessageType& value, uint8_t* target);
+
+  // For backward-compatibility, the last four methods also have versions
+  // that are non-deterministic always.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteGroupToArray(
+      int field_number, const MessageLite& value, uint8_t* target) {
+    io::EpsCopyOutputStream stream(
+        target,
+        value.GetCachedSize() +
+            static_cast<int>(2 * io::CodedOutputStream::VarintSize32(
+                                     static_cast<uint32_t>(field_number) << 3)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalWriteGroup(field_number, value, target, &stream);
+  }
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteMessageToArray(
+      int field_number, const MessageLite& value, uint8_t* target) {
+    int size = value.GetCachedSize();
+    io::EpsCopyOutputStream stream(
+        target,
+        size + static_cast<int>(io::CodedOutputStream::VarintSize32(
+                                    static_cast<uint32_t>(field_number) << 3) +
+                                io::CodedOutputStream::VarintSize32(size)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalWriteMessage(field_number, value, value.GetCachedSize(),
+                                target, &stream);
+  }
+
+  // Compute the byte size of a field.  The XxSize() functions do NOT include
+  // the tag, so you must also call TagSize().  (This is because, for repeated
+  // fields, you should only call TagSize() once and multiply it by the element
+  // count, but you may have to call XxSize() for each individual element.)
+  static inline size_t Int32Size(int32_t value);
+  static inline size_t Int64Size(int64_t value);
+  static inline size_t UInt32Size(uint32_t value);
+  static inline size_t UInt64Size(uint64_t value);
+  static inline size_t SInt32Size(int32_t value);
+  static inline size_t SInt64Size(int64_t value);
+  static inline size_t EnumSize(int value);
+  static inline size_t Int32SizePlusOne(int32_t value);
+  static inline size_t Int64SizePlusOne(int64_t value);
+  static inline size_t UInt32SizePlusOne(uint32_t value);
+  static inline size_t UInt64SizePlusOne(uint64_t value);
+  static inline size_t SInt32SizePlusOne(int32_t value);
+  static inline size_t SInt64SizePlusOne(int64_t value);
+  static inline size_t EnumSizePlusOne(int value);
+
+  static size_t Int32Size(const RepeatedField<int32_t>& value);
+  static size_t Int64Size(const RepeatedField<int64_t>& value);
+  static size_t UInt32Size(const RepeatedField<uint32_t>& value);
+  static size_t UInt64Size(const RepeatedField<uint64_t>& value);
+  static size_t SInt32Size(const RepeatedField<int32_t>& value);
+  static size_t SInt64Size(const RepeatedField<int64_t>& value);
+  static size_t EnumSize(const RepeatedField<int>& value);
+
+  // These types always have the same size.
+  static constexpr size_t kFixed32Size = 4;
+  static constexpr size_t kFixed64Size = 8;
+  static constexpr size_t kSFixed32Size = 4;
+  static constexpr size_t kSFixed64Size = 8;
+  static constexpr size_t kFloatSize = 4;
+  static constexpr size_t kDoubleSize = 8;
+  static constexpr size_t kBoolSize = 1;
+
+  static inline size_t StringSize(const std::string& value);
+  static inline size_t BytesSize(const std::string& value);
+
+  template <typename MessageType>
+  static inline size_t GroupSize(const MessageType& value);
+  template <typename MessageType>
+  static inline size_t MessageSize(const MessageType& value);
+
+  // Like above, but de-virtualize the call to ByteSize().  The
+  // pointer must point at an instance of MessageType, *not* a subclass (or
+  // the subclass must not override ByteSize()).
+  template <typename MessageType>
+  static inline size_t GroupSizeNoVirtual(const MessageType& value);
+  template <typename MessageType>
+  static inline size_t MessageSizeNoVirtual(const MessageType& value);
+
+  // Given the length of data, calculate the byte size of the data on the
+  // wire if we encode the data as a length delimited field.
+  static inline size_t LengthDelimitedSize(size_t length);
+
+ private:
+  // 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>
+  PROTOBUF_NDEBUG_INLINE static bool ReadRepeatedFixedSizePrimitive(
+      int tag_size, uint32_t tag, io::CodedInputStream* input,
+      RepeatedField<CType>* value);
+
+  // Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadPackedFixedSizePrimitive(
+      io::CodedInputStream* input, RepeatedField<CType>* value);
+
+  static const CppType kFieldTypeToCppTypeMap[];
+  static const WireFormatLite::WireType kWireTypeForFieldType[];
+  static void WriteSubMessageMaybeToArray(int size, const MessageLite& value,
+                                          io::CodedOutputStream* output);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormatLite);
+};
+
+// A class which deals with unknown values.  The default implementation just
+// discards them.  WireFormat defines a subclass which writes to an
+// UnknownFieldSet.  This class is used by ExtensionSet::ParseField(), since
+// ExtensionSet is part of the lite library but UnknownFieldSet is not.
+class PROTOBUF_EXPORT FieldSkipper {
+ public:
+  FieldSkipper() {}
+  virtual ~FieldSkipper() {}
+
+  // Skip a field whose tag has already been consumed.
+  virtual bool SkipField(io::CodedInputStream* input, uint32_t tag);
+
+  // Skip an entire message or group, up to an end-group tag (which is consumed)
+  // or end-of-stream.
+  virtual bool SkipMessage(io::CodedInputStream* input);
+
+  // Deal with an already-parsed unrecognized enum value.  The default
+  // implementation does nothing, but the UnknownFieldSet-based implementation
+  // saves it as an unknown varint.
+  virtual void SkipUnknownEnum(int field_number, int value);
+};
+
+// Subclass of FieldSkipper which saves skipped fields to a CodedOutputStream.
+
+class PROTOBUF_EXPORT CodedOutputStreamFieldSkipper : public FieldSkipper {
+ public:
+  explicit CodedOutputStreamFieldSkipper(io::CodedOutputStream* unknown_fields)
+      : unknown_fields_(unknown_fields) {}
+  ~CodedOutputStreamFieldSkipper() override {}
+
+  // implements FieldSkipper -----------------------------------------
+  bool SkipField(io::CodedInputStream* input, uint32_t tag) override;
+  bool SkipMessage(io::CodedInputStream* input) override;
+  void SkipUnknownEnum(int field_number, int value) override;
+
+ protected:
+  io::CodedOutputStream* unknown_fields_;
+};
+
+// inline methods ====================================================
+
+inline WireFormatLite::CppType WireFormatLite::FieldTypeToCppType(
+    FieldType type) {
+  return kFieldTypeToCppTypeMap[type];
+}
+
+constexpr inline uint32_t WireFormatLite::MakeTag(int field_number,
+                                                  WireType type) {
+  return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
+}
+
+inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32_t tag) {
+  return static_cast<WireType>(tag & kTagTypeMask);
+}
+
+inline int WireFormatLite::GetTagFieldNumber(uint32_t tag) {
+  return static_cast<int>(tag >> kTagTypeBits);
+}
+
+inline size_t WireFormatLite::TagSize(int field_number,
+                                      WireFormatLite::FieldType type) {
+  size_t result = io::CodedOutputStream::VarintSize32(
+      static_cast<uint32_t>(field_number << kTagTypeBits));
+  if (type == TYPE_GROUP) {
+    // Groups have both a start and an end tag.
+    return result * 2;
+  } else {
+    return result;
+  }
+}
+
+inline uint32_t WireFormatLite::EncodeFloat(float value) {
+  return bit_cast<uint32_t>(value);
+}
+
+inline float WireFormatLite::DecodeFloat(uint32_t value) {
+  return bit_cast<float>(value);
+}
+
+inline uint64_t WireFormatLite::EncodeDouble(double value) {
+  return bit_cast<uint64_t>(value);
+}
+
+inline double WireFormatLite::DecodeDouble(uint64_t value) {
+  return bit_cast<double>(value);
+}
+
+// ZigZag Transform:  Encodes signed integers so that they can be
+// effectively used with varint encoding.
+//
+// varint operates on unsigned integers, encoding smaller numbers into
+// fewer bytes.  If you try to use it on a signed integer, it will treat
+// this number as a very large unsigned integer, which means that even
+// small signed numbers like -1 will take the maximum number of bytes
+// (10) to encode.  ZigZagEncode() maps signed integers to unsigned
+// in such a way that those with a small absolute value will have smaller
+// encoded values, making them appropriate for encoding using varint.
+//
+//       int32_t ->     uint32_t
+// -------------------------
+//           0 ->          0
+//          -1 ->          1
+//           1 ->          2
+//          -2 ->          3
+//         ... ->        ...
+//  2147483647 -> 4294967294
+// -2147483648 -> 4294967295
+//
+//        >> encode >>
+//        << decode <<
+
+inline uint32_t WireFormatLite::ZigZagEncode32(int32_t n) {
+  // Note:  the right-shift must be arithmetic
+  // Note:  left shift must be unsigned because of overflow
+  return (static_cast<uint32_t>(n) << 1) ^ static_cast<uint32_t>(n >> 31);
+}
+
+inline int32_t WireFormatLite::ZigZagDecode32(uint32_t n) {
+  // Note:  Using unsigned types prevent undefined behavior
+  return static_cast<int32_t>((n >> 1) ^ (~(n & 1) + 1));
+}
+
+inline uint64_t WireFormatLite::ZigZagEncode64(int64_t n) {
+  // Note:  the right-shift must be arithmetic
+  // Note:  left shift must be unsigned because of overflow
+  return (static_cast<uint64_t>(n) << 1) ^ static_cast<uint64_t>(n >> 63);
+}
+
+inline int64_t WireFormatLite::ZigZagDecode64(uint64_t n) {
+  // Note:  Using unsigned types prevent undefined behavior
+  return static_cast<int64_t>((n >> 1) ^ (~(n & 1) + 1));
+}
+
+// String is for UTF-8 text only, but, even so, ReadString() can simply
+// call ReadBytes().
+
+inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
+                                       std::string* value) {
+  return ReadBytes(input, value);
+}
+
+inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
+                                       std::string** p) {
+  return ReadBytes(input, p);
+}
+
+inline uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+    const std::string& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  return stream->WriteRaw(unknown_fields.data(),
+                          static_cast<int>(unknown_fields.size()), target);
+}
+
+inline size_t ComputeUnknownMessageSetItemsSize(
+    const std::string& unknown_fields) {
+  return unknown_fields.size();
+}
+
+// Implementation details of ReadPrimitive.
+
+template <>
+inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_INT32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
+  if (!input->ReadVarint32(&temp)) return false;
+  *value = static_cast<int32_t>(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_INT64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
+  if (!input->ReadVarint64(&temp)) return false;
+  *value = static_cast<int64_t>(temp);
+  return true;
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint32_t, WireFormatLite::TYPE_UINT32>(
+    io::CodedInputStream* input, uint32_t* value) {
+  return input->ReadVarint32(value);
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint64_t, WireFormatLite::TYPE_UINT64>(
+    io::CodedInputStream* input, uint64_t* value) {
+  return input->ReadVarint64(value);
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SINT32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
+  if (!input->ReadVarint32(&temp)) return false;
+  *value = ZigZagDecode32(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_SINT64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
+  if (!input->ReadVarint64(&temp)) return false;
+  *value = ZigZagDecode64(temp);
+  return true;
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint32_t, WireFormatLite::TYPE_FIXED32>(
+    io::CodedInputStream* input, uint32_t* value) {
+  return input->ReadLittleEndian32(value);
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint64_t, WireFormatLite::TYPE_FIXED64>(
+    io::CodedInputStream* input, uint64_t* value) {
+  return input->ReadLittleEndian64(value);
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SFIXED32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
+  if (!input->ReadLittleEndian32(&temp)) return false;
+  *value = static_cast<int32_t>(temp);
+  return true;
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_SFIXED64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
+  if (!input->ReadLittleEndian64(&temp)) return false;
+  *value = static_cast<int64_t>(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<float, WireFormatLite::TYPE_FLOAT>(
+    io::CodedInputStream* input, float* value) {
+  uint32_t temp;
+  if (!input->ReadLittleEndian32(&temp)) return false;
+  *value = DecodeFloat(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<double, WireFormatLite::TYPE_DOUBLE>(
+    io::CodedInputStream* input, double* value) {
+  uint64_t temp;
+  if (!input->ReadLittleEndian64(&temp)) return false;
+  *value = DecodeDouble(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
+    io::CodedInputStream* input, bool* value) {
+  uint64_t temp;
+  if (!input->ReadVarint64(&temp)) return false;
+  *value = temp != 0;
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+    io::CodedInputStream* input, int* value) {
+  uint32_t temp;
+  if (!input->ReadVarint32(&temp)) return false;
+  *value = static_cast<int>(temp);
+  return true;
+}
+
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<uint32_t, WireFormatLite::TYPE_FIXED32>(
+    const uint8_t* buffer, uint32_t* value) {
+  return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value);
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<uint64_t, WireFormatLite::TYPE_FIXED64>(
+    const uint8_t* buffer, uint64_t* value) {
+  return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value);
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<int32_t, WireFormatLite::TYPE_SFIXED32>(
+    const uint8_t* buffer, int32_t* value) {
+  uint32_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
+  *value = static_cast<int32_t>(temp);
+  return buffer;
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<int64_t, WireFormatLite::TYPE_SFIXED64>(
+    const uint8_t* buffer, int64_t* value) {
+  uint64_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
+  *value = static_cast<int64_t>(temp);
+  return buffer;
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<float, WireFormatLite::TYPE_FLOAT>(
+    const uint8_t* buffer, float* value) {
+  uint32_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
+  *value = DecodeFloat(temp);
+  return buffer;
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<double, WireFormatLite::TYPE_DOUBLE>(
+    const uint8_t* buffer, double* value) {
+  uint64_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
+  *value = DecodeDouble(temp);
+  return buffer;
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadRepeatedPrimitive(
+    int,  // tag_size, unused.
+    uint32_t tag, io::CodedInputStream* input, RepeatedField<CType>* values) {
+  CType value;
+  if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+  values->Add(value);
+  int elements_already_reserved = values->Capacity() - values->size();
+  while (elements_already_reserved > 0 && input->ExpectTag(tag)) {
+    if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+    values->AddAlreadyReserved(value);
+    elements_already_reserved--;
+  }
+  return true;
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
+    int tag_size, uint32_t tag, io::CodedInputStream* input,
+    RepeatedField<CType>* values) {
+  GOOGLE_DCHECK_EQ(UInt32Size(tag), static_cast<size_t>(tag_size));
+  CType value;
+  if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+  values->Add(value);
+
+  // For fixed size values, repeated values can be read more quickly by
+  // reading directly from a raw array.
+  //
+  // We can get a tight loop by only reading as many elements as can be
+  // added to the RepeatedField without having to do any resizing. Additionally,
+  // we only try to read as many elements as are available from the current
+  // buffer space. Doing so avoids having to perform boundary checks when
+  // reading the value: the maximum number of elements that can be read is
+  // known outside of the loop.
+  const void* void_pointer;
+  int size;
+  input->GetDirectBufferPointerInline(&void_pointer, &size);
+  if (size > 0) {
+    const uint8_t* buffer = reinterpret_cast<const uint8_t*>(void_pointer);
+    // The number of bytes each type occupies on the wire.
+    const int per_value_size = tag_size + static_cast<int>(sizeof(value));
+
+    // parentheses around (std::min) prevents macro expansion of min(...)
+    int elements_available =
+        (std::min)(values->Capacity() - values->size(), size / per_value_size);
+    int num_read = 0;
+    while (num_read < elements_available &&
+           (buffer = io::CodedInputStream::ExpectTagFromArray(buffer, tag)) !=
+               nullptr) {
+      buffer = ReadPrimitiveFromArray<CType, DeclaredType>(buffer, &value);
+      values->AddAlreadyReserved(value);
+      ++num_read;
+    }
+    const int read_bytes = num_read * per_value_size;
+    if (read_bytes > 0) {
+      input->Skip(read_bytes);
+    }
+  }
+  return true;
+}
+
+// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
+// the optimized code path.
+#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE)        \
+  template <>                                                             \
+  inline bool WireFormatLite::ReadRepeatedPrimitive<                      \
+      CPPTYPE, WireFormatLite::DECLARED_TYPE>(                            \
+      int tag_size, uint32_t tag, io::CodedInputStream* input,            \
+      RepeatedField<CPPTYPE>* values) {                                   \
+    return ReadRepeatedFixedSizePrimitive<CPPTYPE,                        \
+                                          WireFormatLite::DECLARED_TYPE>( \
+        tag_size, tag, input, values);                                    \
+  }
+
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32_t, TYPE_FIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64_t, TYPE_FIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32_t, TYPE_SFIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64_t, TYPE_SFIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
+
+#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+bool WireFormatLite::ReadRepeatedPrimitiveNoInline(
+    int tag_size, uint32_t tag, io::CodedInputStream* input,
+    RepeatedField<CType>* value) {
+  return ReadRepeatedPrimitive<CType, DeclaredType>(tag_size, tag, input,
+                                                    value);
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
+                                                RepeatedField<CType>* values) {
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    CType value;
+    if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+    values->Add(value);
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
+    io::CodedInputStream* input, RepeatedField<CType>* values) {
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
+  const int old_entries = values->size();
+  const int new_entries = length / static_cast<int>(sizeof(CType));
+  const int new_bytes = new_entries * static_cast<int>(sizeof(CType));
+  if (new_bytes != length) return false;
+  // We would *like* to pre-allocate the buffer to write into (for
+  // speed), but *must* avoid performing a very large allocation due
+  // to a malicious user-supplied "length" above.  So we have a fast
+  // path that pre-allocates when the "length" is less than a bound.
+  // We determine the bound by calling BytesUntilTotalBytesLimit() and
+  // BytesUntilLimit().  These return -1 to mean "no limit set".
+  // There are four cases:
+  // TotalBytesLimit  Limit
+  // -1               -1     Use slow path.
+  // -1               >= 0   Use fast path if length <= Limit.
+  // >= 0             -1     Use slow path.
+  // >= 0             >= 0   Use fast path if length <= min(both limits).
+  int64_t bytes_limit = input->BytesUntilTotalBytesLimit();
+  if (bytes_limit == -1) {
+    bytes_limit = input->BytesUntilLimit();
+  } else {
+    // parentheses around (std::min) prevents macro expansion of min(...)
+    bytes_limit =
+        (std::min)(bytes_limit, static_cast<int64_t>(input->BytesUntilLimit()));
+  }
+  if (bytes_limit >= new_bytes) {
+    // Fast-path that pre-allocates *values to the final size.
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+    values->Resize(old_entries + new_entries, 0);
+    // values->mutable_data() may change after Resize(), so do this after:
+    void* dest = reinterpret_cast<void*>(values->mutable_data() + old_entries);
+    if (!input->ReadRaw(dest, new_bytes)) {
+      values->Truncate(old_entries);
+      return false;
+    }
+#else
+    values->Reserve(old_entries + new_entries);
+    CType value;
+    for (int i = 0; i < new_entries; ++i) {
+      if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+      values->AddAlreadyReserved(value);
+    }
+#endif
+  } else {
+    // This is the slow-path case where "length" may be too large to
+    // safely allocate.  We read as much as we can into *values
+    // without pre-allocating "length" bytes.
+    CType value;
+    for (int i = 0; i < new_entries; ++i) {
+      if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+      values->Add(value);
+    }
+  }
+  return true;
+}
+
+// Specializations of ReadPackedPrimitive for the fixed size types, which use
+// an optimized code path.
+#define READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE)      \
+  template <>                                                                  \
+  inline bool                                                                  \
+  WireFormatLite::ReadPackedPrimitive<CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
+      io::CodedInputStream * input, RepeatedField<CPPTYPE> * values) {         \
+    return ReadPackedFixedSizePrimitive<CPPTYPE,                               \
+                                        WireFormatLite::DECLARED_TYPE>(        \
+        input, values);                                                        \
+  }
+
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32_t, TYPE_FIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64_t, TYPE_FIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32_t, TYPE_SFIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64_t, 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
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
+                                                 RepeatedField<CType>* values) {
+  return ReadPackedPrimitive<CType, DeclaredType>(input, values);
+}
+
+
+template <typename MessageType>
+inline bool WireFormatLite::ReadGroup(int field_number,
+                                      io::CodedInputStream* input,
+                                      MessageType* value) {
+  if (!input->IncrementRecursionDepth()) return false;
+  if (!value->MergePartialFromCodedStream(input)) return false;
+  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;
+  }
+  return true;
+}
+template <typename MessageType>
+inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input,
+                                        MessageType* value) {
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
+  std::pair<io::CodedInputStream::Limit, int> p =
+      input->IncrementRecursionDepthAndPushLimit(length);
+  if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false;
+  // Make sure that parsing stopped when the limit was hit, not at an endgroup
+  // tag.
+  return input->DecrementRecursionDepthAndPopLimit(p.first);
+}
+
+// ===================================================================
+
+inline void WireFormatLite::WriteTag(int field_number, WireType type,
+                                     io::CodedOutputStream* output) {
+  output->WriteTag(MakeTag(field_number, type));
+}
+
+inline void WireFormatLite::WriteInt32NoTag(int32_t value,
+                                            io::CodedOutputStream* output) {
+  output->WriteVarint32SignExtended(value);
+}
+inline void WireFormatLite::WriteInt64NoTag(int64_t value,
+                                            io::CodedOutputStream* output) {
+  output->WriteVarint64(static_cast<uint64_t>(value));
+}
+inline void WireFormatLite::WriteUInt32NoTag(uint32_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint32(value);
+}
+inline void WireFormatLite::WriteUInt64NoTag(uint64_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint64(value);
+}
+inline void WireFormatLite::WriteSInt32NoTag(int32_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint32(ZigZagEncode32(value));
+}
+inline void WireFormatLite::WriteSInt64NoTag(int64_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint64(ZigZagEncode64(value));
+}
+inline void WireFormatLite::WriteFixed32NoTag(uint32_t value,
+                                              io::CodedOutputStream* output) {
+  output->WriteLittleEndian32(value);
+}
+inline void WireFormatLite::WriteFixed64NoTag(uint64_t value,
+                                              io::CodedOutputStream* output) {
+  output->WriteLittleEndian64(value);
+}
+inline void WireFormatLite::WriteSFixed32NoTag(int32_t value,
+                                               io::CodedOutputStream* output) {
+  output->WriteLittleEndian32(static_cast<uint32_t>(value));
+}
+inline void WireFormatLite::WriteSFixed64NoTag(int64_t value,
+                                               io::CodedOutputStream* output) {
+  output->WriteLittleEndian64(static_cast<uint64_t>(value));
+}
+inline void WireFormatLite::WriteFloatNoTag(float value,
+                                            io::CodedOutputStream* output) {
+  output->WriteLittleEndian32(EncodeFloat(value));
+}
+inline void WireFormatLite::WriteDoubleNoTag(double value,
+                                             io::CodedOutputStream* output) {
+  output->WriteLittleEndian64(EncodeDouble(value));
+}
+inline void WireFormatLite::WriteBoolNoTag(bool value,
+                                           io::CodedOutputStream* output) {
+  output->WriteVarint32(value ? 1 : 0);
+}
+inline void WireFormatLite::WriteEnumNoTag(int value,
+                                           io::CodedOutputStream* output) {
+  output->WriteVarint32SignExtended(value);
+}
+
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline void WireFormatLite::WriteGroupNoVirtual(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_START_GROUP, output);
+  value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
+  WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline void WireFormatLite::WriteMessageNoVirtual(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  output->WriteVarint32(
+      value.MessageType_WorkAroundCppLookupDefect::GetCachedSize());
+  value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
+}
+
+// ===================================================================
+
+inline uint8_t* WireFormatLite::WriteTagToArray(int field_number, WireType type,
+                                                uint8_t* target) {
+  return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type),
+                                                target);
+}
+
+inline uint8_t* WireFormatLite::WriteInt32NoTagToArray(int32_t value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(int64_t value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(
+      static_cast<uint64_t>(value), target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32NoTagToArray(uint32_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64NoTagToArray(uint64_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32NoTagToArray(int32_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value),
+                                                     target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64NoTagToArray(int64_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value),
+                                                     target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(uint32_t value,
+                                                         uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64NoTagToArray(uint64_t value,
+                                                         uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(int32_t value,
+                                                          uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian32ToArray(
+      static_cast<uint32_t>(value), target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64NoTagToArray(int64_t value,
+                                                          uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian64ToArray(
+      static_cast<uint64_t>(value), target);
+}
+inline uint8_t* WireFormatLite::WriteFloatNoTagToArray(float value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value),
+                                                           target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleNoTagToArray(double value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value),
+                                                           target);
+}
+inline uint8_t* WireFormatLite::WriteBoolNoTagToArray(bool value,
+                                                      uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumNoTagToArray(int value,
+                                                      uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
+}
+
+template <typename T>
+inline uint8_t* WireFormatLite::WritePrimitiveNoTagToArray(
+    const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+    uint8_t* target) {
+  const int n = value.size();
+  GOOGLE_DCHECK_GT(n, 0);
+
+  const T* ii = value.data();
+  int i = 0;
+  do {
+    target = Writer(ii[i], target);
+  } while (++i < n);
+
+  return target;
+}
+
+template <typename T>
+inline uint8_t* WireFormatLite::WriteFixedNoTagToArray(
+    const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+    uint8_t* target) {
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+  (void)Writer;
+
+  const int n = value.size();
+  GOOGLE_DCHECK_GT(n, 0);
+
+  const T* ii = value.data();
+  const int bytes = n * static_cast<int>(sizeof(ii[0]));
+  memcpy(target, ii, static_cast<size_t>(bytes));
+  return target + bytes;
+#else
+  return WritePrimitiveNoTagToArray(value, Writer, target);
+#endif
+}
+
+inline uint8_t* WireFormatLite::WriteInt32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteInt32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteInt64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32NoTagToArray(
+    const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteUInt32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64NoTagToArray(
+    const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteUInt64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteSInt32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteSInt64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(
+    const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteFixed32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64NoTagToArray(
+    const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteFixed64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteSFixed32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteSFixed64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFloatNoTagToArray(
+    const RepeatedField<float>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteFloatNoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleNoTagToArray(
+    const RepeatedField<double>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteDoubleNoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteBoolNoTagToArray(
+    const RepeatedField<bool>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteBoolNoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumNoTagToArray(
+    const RepeatedField<int>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteEnumNoTagToArray, target);
+}
+
+inline uint8_t* WireFormatLite::WriteInt32ToArray(int field_number,
+                                                  int32_t value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteInt32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64ToArray(int field_number,
+                                                  int64_t value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteInt64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32ToArray(int field_number,
+                                                   uint32_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteUInt32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64ToArray(int field_number,
+                                                   uint64_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteUInt64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32ToArray(int field_number,
+                                                   int32_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteSInt32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64ToArray(int field_number,
+                                                   int64_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteSInt64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32ToArray(int field_number,
+                                                    uint32_t value,
+                                                    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
+  return WriteFixed32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64ToArray(int field_number,
+                                                    uint64_t value,
+                                                    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
+  return WriteFixed64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32ToArray(int field_number,
+                                                     int32_t value,
+                                                     uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
+  return WriteSFixed32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64ToArray(int field_number,
+                                                     int64_t value,
+                                                     uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
+  return WriteSFixed64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFloatToArray(int field_number, float value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
+  return WriteFloatNoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleToArray(int field_number,
+                                                   double value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
+  return WriteDoubleNoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteBoolToArray(int field_number, bool value,
+                                                 uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteBoolNoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumToArray(int field_number, int value,
+                                                 uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteEnumNoTagToArray(value, target);
+}
+
+template <typename T>
+inline uint8_t* WireFormatLite::WritePrimitiveToArray(
+    int field_number, const RepeatedField<T>& value,
+    uint8_t* (*Writer)(int, T, uint8_t*), uint8_t* target) {
+  const int n = value.size();
+  if (n == 0) {
+    return target;
+  }
+
+  const T* ii = value.data();
+  int i = 0;
+  do {
+    target = Writer(field_number, ii[i], target);
+  } while (++i < n);
+
+  return target;
+}
+
+inline uint8_t* WireFormatLite::WriteInt32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteInt32ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteInt64ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32ToArray(
+    int field_number, const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteUInt32ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64ToArray(
+    int field_number, const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteUInt64ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSInt32ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSInt64ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32ToArray(
+    int field_number, const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteFixed32ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64ToArray(
+    int field_number, const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteFixed64ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSFixed32ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSFixed64ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteFloatToArray(
+    int field_number, const RepeatedField<float>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteFloatToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleToArray(
+    int field_number, const RepeatedField<double>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteDoubleToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteBoolToArray(
+    int field_number, const RepeatedField<bool>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteBoolToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumToArray(
+    int field_number, const RepeatedField<int>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteEnumToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteStringToArray(int field_number,
+                                                   const std::string& value,
+                                                   uint8_t* target) {
+  // String is for UTF-8 text only
+  // WARNING:  In wire_format.cc, both strings and bytes are handled by
+  //   WriteString() to avoid code duplication.  If the implementations become
+  //   different, you will need to update that usage.
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteBytesToArray(int field_number,
+                                                  const std::string& value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
+}
+
+
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline uint8_t* WireFormatLite::InternalWriteGroupNoVirtualToArray(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
+  target = value.MessageType_WorkAroundCppLookupDefect::
+               SerializeWithCachedSizesToArray(target);
+  return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
+}
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline uint8_t* WireFormatLite::InternalWriteMessageNoVirtualToArray(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(
+      static_cast<uint32_t>(
+          value.MessageType_WorkAroundCppLookupDefect::GetCachedSize()),
+      target);
+  return value
+      .MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizesToArray(
+          target);
+}
+
+// ===================================================================
+
+inline size_t WireFormatLite::Int32Size(int32_t value) {
+  return io::CodedOutputStream::VarintSize32SignExtended(value);
+}
+inline size_t WireFormatLite::Int64Size(int64_t value) {
+  return io::CodedOutputStream::VarintSize64(static_cast<uint64_t>(value));
+}
+inline size_t WireFormatLite::UInt32Size(uint32_t value) {
+  return io::CodedOutputStream::VarintSize32(value);
+}
+inline size_t WireFormatLite::UInt64Size(uint64_t value) {
+  return io::CodedOutputStream::VarintSize64(value);
+}
+inline size_t WireFormatLite::SInt32Size(int32_t value) {
+  return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value));
+}
+inline size_t WireFormatLite::SInt64Size(int64_t value) {
+  return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value));
+}
+inline size_t WireFormatLite::EnumSize(int value) {
+  return io::CodedOutputStream::VarintSize32SignExtended(value);
+}
+inline size_t WireFormatLite::Int32SizePlusOne(int32_t value) {
+  return io::CodedOutputStream::VarintSize32SignExtendedPlusOne(value);
+}
+inline size_t WireFormatLite::Int64SizePlusOne(int64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(
+      static_cast<uint64_t>(value));
+}
+inline size_t WireFormatLite::UInt32SizePlusOne(uint32_t value) {
+  return io::CodedOutputStream::VarintSize32PlusOne(value);
+}
+inline size_t WireFormatLite::UInt64SizePlusOne(uint64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(value);
+}
+inline size_t WireFormatLite::SInt32SizePlusOne(int32_t value) {
+  return io::CodedOutputStream::VarintSize32PlusOne(ZigZagEncode32(value));
+}
+inline size_t WireFormatLite::SInt64SizePlusOne(int64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(ZigZagEncode64(value));
+}
+inline size_t WireFormatLite::EnumSizePlusOne(int value) {
+  return io::CodedOutputStream::VarintSize32SignExtendedPlusOne(value);
+}
+
+inline size_t WireFormatLite::StringSize(const std::string& value) {
+  return LengthDelimitedSize(value.size());
+}
+inline size_t WireFormatLite::BytesSize(const std::string& value) {
+  return LengthDelimitedSize(value.size());
+}
+
+
+template <typename MessageType>
+inline size_t WireFormatLite::GroupSize(const MessageType& value) {
+  return value.ByteSizeLong();
+}
+template <typename MessageType>
+inline size_t WireFormatLite::MessageSize(const MessageType& value) {
+  return LengthDelimitedSize(value.ByteSizeLong());
+}
+
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline size_t WireFormatLite::GroupSizeNoVirtual(
+    const MessageType_WorkAroundCppLookupDefect& value) {
+  return value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong();
+}
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline size_t WireFormatLite::MessageSizeNoVirtual(
+    const MessageType_WorkAroundCppLookupDefect& value) {
+  return LengthDelimitedSize(
+      value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong());
+}
+
+inline size_t WireFormatLite::LengthDelimitedSize(size_t length) {
+  // The static_cast here prevents an error in certain compiler configurations
+  // but is not technically correct--if length is too large to fit in a uint32_t
+  // then it will be silently truncated. We will need to fix this if we ever
+  // decide to start supporting serialized messages greater than 2 GiB in size.
+  return length +
+         io::CodedOutputStream::VarintSize32(static_cast<uint32_t>(length));
+}
+
+template <typename MS>
+bool ParseMessageSetItemImpl(io::CodedInputStream* input, MS ms) {
+  // This method parses a group which should contain two fields:
+  //   required int32 type_id = 2;
+  //   required data message = 3;
+
+  uint32_t last_type_id = 0;
+
+  // If we see message data before the type_id, we'll append it to this so
+  // we can parse it later.
+  std::string message_data;
+
+  enum class State { kNoTag, kHasType, kHasPayload, kDone };
+  State state = State::kNoTag;
+
+  while (true) {
+    const uint32_t tag = input->ReadTagNoLastTag();
+    if (tag == 0) return false;
+
+    switch (tag) {
+      case WireFormatLite::kMessageSetTypeIdTag: {
+        uint32_t type_id;
+        if (!input->ReadVarint32(&type_id)) return false;
+        if (state == State::kNoTag) {
+          last_type_id = type_id;
+          state = State::kHasType;
+        } else if (state == State::kHasPayload) {
+          // We saw some message data before the type_id.  Have to parse it
+          // now.
+          io::CodedInputStream sub_input(
+              reinterpret_cast<const uint8_t*>(message_data.data()),
+              static_cast<int>(message_data.size()));
+          sub_input.SetRecursionLimit(input->RecursionBudget());
+          if (!ms.ParseField(type_id, &sub_input)) {
+            return false;
+          }
+          message_data.clear();
+          state = State::kDone;
+        }
+
+        break;
+      }
+
+      case WireFormatLite::kMessageSetMessageTag: {
+        if (state == State::kHasType) {
+          // Already saw type_id, so we can parse this directly.
+          if (!ms.ParseField(last_type_id, input)) {
+            return false;
+          }
+          state = State::kDone;
+        } else if (state == State::kNoTag) {
+          // We haven't seen a type_id yet.  Append this data to message_data.
+          uint32_t length;
+          if (!input->ReadVarint32(&length)) return false;
+          if (static_cast<int32_t>(length) < 0) return false;
+          uint32_t size = static_cast<uint32_t>(
+              length + io::CodedOutputStream::VarintSize32(length));
+          message_data.resize(size);
+          auto ptr = reinterpret_cast<uint8_t*>(&message_data[0]);
+          ptr = io::CodedOutputStream::WriteVarint32ToArray(length, ptr);
+          if (!input->ReadRaw(ptr, length)) return false;
+          state = State::kHasPayload;
+        } else {
+          if (!ms.SkipField(tag, input)) return false;
+        }
+
+        break;
+      }
+
+      case WireFormatLite::kMessageSetItemEndTag: {
+        return true;
+      }
+
+      default: {
+        if (!ms.SkipField(tag, input)) return false;
+      }
+    }
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
new file mode 100644
index 0000000..f1ed951
--- /dev/null
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/wire_format.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/unittest_proto3_arena.pb.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+#define UNITTEST_PACKAGE_NAME "protobuf_unittest"
+#define PROTO2_WIREFORMAT_UNITTEST ::proto2_wireformat_unittest
+#define PROTO3_ARENA_UNITTEST ::proto3_arena_unittest
+
+// Must include after defining UNITTEST, etc.
+// clang-format off
+#include <google/protobuf/test_util.inc>
+#include <google/protobuf/wire_format_unittest.inc>
+// clang-format on
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/wire_format_unittest.inc b/src/google/protobuf/wire_format_unittest.inc
new file mode 100644
index 0000000..0e3869c
--- /dev/null
+++ b/src/google/protobuf/wire_format_unittest.inc
@@ -0,0 +1,1709 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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/stubs/logging.h>
+#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/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(WireFormatTest, EnumsInSync) {
+  // Verify that WireFormatLite::FieldType and WireFormatLite::CppType match
+  // FieldDescriptor::Type and FieldDescriptor::CppType.
+
+  EXPECT_EQ(implicit_cast<int>(FieldDescriptor::MAX_TYPE),
+            implicit_cast<int>(WireFormatLite::MAX_FIELD_TYPE));
+  EXPECT_EQ(implicit_cast<int>(FieldDescriptor::MAX_CPPTYPE),
+            implicit_cast<int>(WireFormatLite::MAX_CPPTYPE));
+
+  for (int i = 1; i <= WireFormatLite::MAX_FIELD_TYPE; i++) {
+    EXPECT_EQ(implicit_cast<int>(FieldDescriptor::TypeToCppType(
+                  static_cast<FieldDescriptor::Type>(i))),
+              implicit_cast<int>(WireFormatLite::FieldTypeToCppType(
+                  static_cast<WireFormatLite::FieldType>(i))));
+  }
+}
+
+TEST(WireFormatTest, MaxFieldNumber) {
+  // Make sure the max field number constant is accurate.
+  EXPECT_EQ((1 << (32 - WireFormatLite::kTagTypeBits)) - 1,
+            FieldDescriptor::kMaxNumber);
+}
+
+TEST(WireFormatTest, Parse) {
+  UNITTEST::TestAllTypes source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetAllFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectAllFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParseExtensions) {
+  UNITTEST::TestAllExtensions source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetAllExtensions(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectAllExtensionsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePacked) {
+  UNITTEST::TestPackedTypes source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetPackedFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectPackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePackedFromUnpacked) {
+  // Serialize using the generated code.
+  UNITTEST::TestUnpackedTypes source;
+  TestUtil::SetUnpackedFields(&source);
+  std::string data = source.SerializeAsString();
+
+  // Parse using WireFormat.
+  UNITTEST::TestPackedTypes dest;
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectPackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParseUnpackedFromPacked) {
+  // Serialize using the generated code.
+  UNITTEST::TestPackedTypes source;
+  TestUtil::SetPackedFields(&source);
+  std::string data = source.SerializeAsString();
+
+  // Parse using WireFormat.
+  UNITTEST::TestUnpackedTypes dest;
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectUnpackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePackedExtensions) {
+  UNITTEST::TestPackedExtensions source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetPackedExtensions(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectPackedExtensionsSet(dest);
+}
+
+TEST(WireFormatTest, ParseOneof) {
+  UNITTEST::TestOneof2 source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetOneof1(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectOneofSet1(dest);
+}
+
+TEST(WireFormatTest, OneofOnlySetLast) {
+  UNITTEST::TestOneofBackwardsCompatible source;
+  UNITTEST::TestOneof oneof_dest;
+  std::string data;
+
+  // Set two fields
+  source.set_foo_int(100);
+  source.set_foo_string("101");
+
+  // Serialize and parse to oneof message. Generated serializer may not order
+  // fields in tag order. Use WireFormat::SerializeWithCachedSizes instead as
+  // it sorts fields beforehand.
+  {
+    io::StringOutputStream raw_output(&data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(source, source.ByteSizeLong(),
+                                         &output);
+    ASSERT_FALSE(output.HadError());
+  }
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &oneof_dest);
+
+  // Only the last field is set.
+  EXPECT_FALSE(oneof_dest.has_foo_int());
+  EXPECT_TRUE(oneof_dest.has_foo_string());
+}
+
+TEST(WireFormatTest, ByteSize) {
+  UNITTEST::TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizeExtensions) {
+  UNITTEST::TestAllExtensions message;
+  TestUtil::SetAllExtensions(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizePacked) {
+  UNITTEST::TestPackedTypes message;
+  TestUtil::SetPackedFields(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizePackedExtensions) {
+  UNITTEST::TestPackedExtensions message;
+  TestUtil::SetPackedExtensions(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizeOneof) {
+  UNITTEST::TestOneof2 message;
+  TestUtil::SetOneof1(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, Serialize) {
+  UNITTEST::TestAllTypes message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetAllFields(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, SerializeExtensions) {
+  UNITTEST::TestAllExtensions message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetAllExtensions(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, SerializeFieldsAndExtensions) {
+  UNITTEST::TestFieldOrderings message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetAllFieldsAndExtensions(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, SerializeOneof) {
+  UNITTEST::TestOneof2 message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetOneof1(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, ParseMultipleExtensionRanges) {
+  // Make sure we can parse a message that contains multiple extensions ranges.
+  UNITTEST::TestFieldOrderings source;
+  std::string data;
+
+  TestUtil::SetAllFieldsAndExtensions(&source);
+  source.SerializeToString(&data);
+
+  {
+    UNITTEST::TestFieldOrderings dest;
+    EXPECT_TRUE(dest.ParseFromString(data));
+    EXPECT_EQ(source.DebugString(), dest.DebugString());
+  }
+
+  // Also test using reflection-based parsing.
+  {
+    UNITTEST::TestFieldOrderings dest;
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream coded_input(&raw_input);
+    EXPECT_TRUE(WireFormat::ParseAndMergePartial(&coded_input, &dest));
+    EXPECT_EQ(source.DebugString(), dest.DebugString());
+  }
+}
+
+const int kUnknownTypeId = 1550055;
+
+TEST(WireFormatTest, SerializeMessageSet) {
+  // Set up a TestMessageSet with two known messages and an unknown one.
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension)
+      ->set_i(123);
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension2::message_set_extension)
+      ->set_str("foo");
+  message_set.mutable_unknown_fields()->AddLengthDelimited(kUnknownTypeId,
+                                                           "bar");
+
+  std::string data;
+  ASSERT_TRUE(message_set.SerializeToString(&data));
+
+  // Parse back using RawMessageSet and check the contents.
+  UNITTEST::RawMessageSet raw;
+  ASSERT_TRUE(raw.ParseFromString(data));
+
+  EXPECT_EQ(0, raw.unknown_fields().field_count());
+
+  ASSERT_EQ(3, raw.item_size());
+  EXPECT_EQ(
+      UNITTEST::TestMessageSetExtension1::descriptor()->extension(0)->number(),
+      raw.item(0).type_id());
+  EXPECT_EQ(
+      UNITTEST::TestMessageSetExtension2::descriptor()->extension(0)->number(),
+      raw.item(1).type_id());
+  EXPECT_EQ(kUnknownTypeId, raw.item(2).type_id());
+
+  UNITTEST::TestMessageSetExtension1 message1;
+  EXPECT_TRUE(message1.ParseFromString(raw.item(0).message()));
+  EXPECT_EQ(123, message1.i());
+
+  UNITTEST::TestMessageSetExtension2 message2;
+  EXPECT_TRUE(message2.ParseFromString(raw.item(1).message()));
+  EXPECT_EQ("foo", message2.str());
+
+  EXPECT_EQ("bar", raw.item(2).message());
+}
+
+TEST(WireFormatTest, SerializeMessageSetVariousWaysAreEqual) {
+  // Serialize a MessageSet to a stream and to a flat array using generated
+  // code, and also using WireFormat, and check that the results are equal.
+  // Set up a TestMessageSet with two known messages and an unknown one, as
+  // above.
+
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension)
+      ->set_i(123);
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension2::message_set_extension)
+      ->set_str("foo");
+  message_set.mutable_unknown_fields()->AddLengthDelimited(kUnknownTypeId,
+                                                           "bar");
+
+  size_t size = message_set.ByteSizeLong();
+  EXPECT_EQ(size, message_set.GetCachedSize());
+  ASSERT_EQ(size, WireFormat::ByteSize(message_set));
+
+  std::string flat_data;
+  std::string stream_data;
+  std::string dynamic_data;
+  flat_data.resize(size);
+  stream_data.resize(size);
+
+  // Serialize to flat array
+  {
+    uint8_t* target =
+        reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&flat_data));
+    uint8_t* end = message_set.SerializeWithCachedSizesToArray(target);
+    EXPECT_EQ(size, end - target);
+  }
+
+  // Serialize to buffer
+  {
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&stream_data), size,
+                                       1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message_set.SerializeWithCachedSizes(&output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+
+  // Serialize to buffer with WireFormat.
+  {
+    io::StringOutputStream string_stream(&dynamic_data);
+    io::CodedOutputStream output_stream(&string_stream);
+    WireFormat::SerializeWithCachedSizes(message_set, size, &output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+
+  EXPECT_TRUE(flat_data == stream_data);
+  EXPECT_TRUE(flat_data == dynamic_data);
+}
+
+TEST(WireFormatTest, ParseMessageSet) {
+  // Set up a RawMessageSet with two known messages and an unknown one.
+  UNITTEST::RawMessageSet raw;
+
+  {
+    UNITTEST::RawMessageSet::Item* item = raw.add_item();
+    item->set_type_id(UNITTEST::TestMessageSetExtension1::descriptor()
+                          ->extension(0)
+                          ->number());
+    UNITTEST::TestMessageSetExtension1 message;
+    message.set_i(123);
+    message.SerializeToString(item->mutable_message());
+  }
+
+  {
+    UNITTEST::RawMessageSet::Item* item = raw.add_item();
+    item->set_type_id(UNITTEST::TestMessageSetExtension2::descriptor()
+                          ->extension(0)
+                          ->number());
+    UNITTEST::TestMessageSetExtension2 message;
+    message.set_str("foo");
+    message.SerializeToString(item->mutable_message());
+  }
+
+  {
+    UNITTEST::RawMessageSet::Item* item = raw.add_item();
+    item->set_type_id(kUnknownTypeId);
+    item->set_message("bar");
+  }
+
+  std::string data;
+  ASSERT_TRUE(raw.SerializeToString(&data));
+
+  // Parse as a TestMessageSet and check the contents.
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  ASSERT_TRUE(message_set.ParseFromString(data));
+
+  EXPECT_EQ(123,
+            message_set
+                .GetExtension(
+                    UNITTEST::TestMessageSetExtension1::message_set_extension)
+                .i());
+  EXPECT_EQ("foo",
+            message_set
+                .GetExtension(
+                    UNITTEST::TestMessageSetExtension2::message_set_extension)
+                .str());
+
+  ASSERT_EQ(1, message_set.unknown_fields().field_count());
+  ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED,
+            message_set.unknown_fields().field(0).type());
+  EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited());
+
+  // Also parse using WireFormat.
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet dynamic_message_set;
+  io::CodedInputStream input(reinterpret_cast<const uint8_t*>(data.data()),
+                             data.size());
+  ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set));
+  EXPECT_EQ(message_set.DebugString(), dynamic_message_set.DebugString());
+}
+
+namespace {
+std::string BuildMessageSetItemStart() {
+  std::string data;
+  {
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    coded_output.WriteTag(WireFormatLite::kMessageSetItemStartTag);
+  }
+  return data;
+}
+std::string BuildMessageSetItemEnd() {
+  std::string data;
+  {
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
+  }
+  return data;
+}
+std::string BuildMessageSetTestExtension1(int value = 123) {
+  std::string data;
+  {
+    UNITTEST::TestMessageSetExtension1 message;
+    message.set_i(value);
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    // Write the message content first.
+    WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+                             WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                             &coded_output);
+    coded_output.WriteVarint32(message.ByteSizeLong());
+    message.SerializeWithCachedSizes(&coded_output);
+  }
+  return data;
+}
+std::string BuildMessageSetItemTypeId(int extension_number) {
+  std::string data;
+  {
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
+                                extension_number, &coded_output);
+  }
+  return data;
+}
+void ValidateTestMessageSet(const std::string& test_case,
+                            const std::string& data) {
+  SCOPED_TRACE(test_case);
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    ASSERT_TRUE(message_set.ParseFromString(data));
+
+    EXPECT_EQ(123,
+              message_set
+                  .GetExtension(
+                      UNITTEST::TestMessageSetExtension1::message_set_extension)
+                  .i());
+
+    // Make sure it does not contain anything else.
+    message_set.ClearExtension(
+        UNITTEST::TestMessageSetExtension1::message_set_extension);
+    EXPECT_EQ(message_set.SerializeAsString(), "");
+  }
+  {
+    // Test parse the message via Reflection.
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    io::CodedInputStream input(reinterpret_cast<const uint8_t*>(data.data()),
+                               data.size());
+    EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
+    EXPECT_TRUE(input.ConsumedEntireMessage());
+
+    EXPECT_EQ(123,
+              message_set
+                  .GetExtension(
+                      UNITTEST::TestMessageSetExtension1::message_set_extension)
+                  .i());
+  }
+  {
+    // Test parse the message via DynamicMessage.
+    DynamicMessageFactory factory;
+    std::unique_ptr<Message> msg(
+        factory
+            .GetPrototype(
+                PROTO2_WIREFORMAT_UNITTEST::TestMessageSet::descriptor())
+            ->New());
+    msg->ParseFromString(data);
+    auto* reflection = msg->GetReflection();
+    std::vector<const FieldDescriptor*> fields;
+    reflection->ListFields(*msg, &fields);
+    ASSERT_EQ(fields.size(), 1);
+    const auto& sub = reflection->GetMessage(*msg, fields[0]);
+    reflection = sub.GetReflection();
+    EXPECT_EQ(123, reflection->GetInt32(
+                       sub, sub.GetDescriptor()->FindFieldByName("i")));
+  }
+}
+}  // namespace
+
+TEST(WireFormatTest, ParseMessageSetWithAnyTagOrder) {
+  std::string start = BuildMessageSetItemStart();
+  std::string end = BuildMessageSetItemEnd();
+  std::string id = BuildMessageSetItemTypeId(
+      UNITTEST::TestMessageSetExtension1::descriptor()->extension(0)->number());
+  std::string message = BuildMessageSetTestExtension1();
+
+  ValidateTestMessageSet("id + message", start + id + message + end);
+  ValidateTestMessageSet("message + id", start + message + id + end);
+}
+
+TEST(WireFormatTest, ParseMessageSetWithDuplicateTags) {
+  std::string start = BuildMessageSetItemStart();
+  std::string end = BuildMessageSetItemEnd();
+  std::string id = BuildMessageSetItemTypeId(
+      UNITTEST::TestMessageSetExtension1::descriptor()->extension(0)->number());
+  std::string other_id = BuildMessageSetItemTypeId(123456);
+  std::string message = BuildMessageSetTestExtension1();
+  std::string other_message = BuildMessageSetTestExtension1(321);
+
+  // Double id
+  ValidateTestMessageSet("id + other_id + message",
+                         start + id + other_id + message + end);
+  ValidateTestMessageSet("id + message + other_id",
+                         start + id + message + other_id + end);
+  ValidateTestMessageSet("message + id + other_id",
+                         start + message + id + other_id + end);
+  // Double message
+  ValidateTestMessageSet("id + message + other_message",
+                         start + id + message + other_message + end);
+  ValidateTestMessageSet("message + id + other_message",
+                         start + message + id + other_message + end);
+  ValidateTestMessageSet("message + other_message + id",
+                         start + message + other_message + id + end);
+}
+
+void SerializeReverseOrder(
+    const PROTO2_WIREFORMAT_UNITTEST::TestMessageSet& mset,
+    io::CodedOutputStream* coded_output);
+
+void SerializeReverseOrder(const UNITTEST::TestMessageSetExtension1& message,
+                           io::CodedOutputStream* coded_output) {
+  WireFormatLite::WriteTag(15,  // i
+                           WireFormatLite::WIRETYPE_VARINT, coded_output);
+  coded_output->WriteVarint64(message.i());
+  WireFormatLite::WriteTag(16,  // recursive
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                           coded_output);
+  coded_output->WriteVarint32(message.recursive().GetCachedSize());
+  SerializeReverseOrder(message.recursive(), coded_output);
+}
+
+void SerializeReverseOrder(
+    const PROTO2_WIREFORMAT_UNITTEST::TestMessageSet& mset,
+    io::CodedOutputStream* coded_output) {
+  if (!mset.HasExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension))
+    return;
+  coded_output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
+  // Write the message content first.
+  WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                           coded_output);
+  auto& message = mset.GetExtension(
+      UNITTEST::TestMessageSetExtension1::message_set_extension);
+  coded_output->WriteVarint32(message.GetCachedSize());
+  SerializeReverseOrder(message, coded_output);
+  // Write the type id.
+  uint32_t type_id = message.GetDescriptor()->extension(0)->number();
+  WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, type_id,
+                              coded_output);
+  coded_output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
+}
+
+TEST(WireFormatTest, ParseMessageSetWithDeepRecReverseOrder) {
+  std::string data;
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < 200; i++) {
+      auto m = mset->MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    message_set.ByteSizeLong();
+    // Serialize with reverse payload tag order
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    SerializeReverseOrder(message_set, &coded_output);
+  }
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
+TEST(WireFormatTest, ParseFailMalformedMessageSet) {
+  constexpr int kDepth = 5;
+  std::string data;
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < kDepth; i++) {
+      auto m = mset->MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    auto m = mset->MutableExtension(
+        UNITTEST::TestMessageSetExtension1::message_set_extension);
+    // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+    m->set_i(-1);
+
+    EXPECT_TRUE(message_set.SerializeToString(&data));
+    // Make the proto mal-formed.
+    data[data.size() - 2 - kDepth] = 0xFF;
+  }
+
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
+TEST(WireFormatTest, ParseFailMalformedMessageSetReverseOrder) {
+  constexpr int kDepth = 5;
+  std::string data;
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < kDepth; i++) {
+      auto m = mset->MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    auto m = mset->MutableExtension(
+        UNITTEST::TestMessageSetExtension1::message_set_extension);
+    // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+    m->set_i(-1);
+    // SerializeReverseOrder() assumes "recursive" is always present.
+    m->mutable_recursive();
+
+    message_set.ByteSizeLong();
+
+    // Serialize with reverse payload tag order
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    SerializeReverseOrder(message_set, &coded_output);
+  }
+
+  // Make varint for -1 malformed.
+  data[data.size() - 5 * (kDepth + 1) - 4] = 0xFF;
+
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
+TEST(WireFormatTest, ParseBrokenMessageSet) {
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  std::string input("goodbye");  // Invalid wire format data.
+  EXPECT_FALSE(message_set.ParseFromString(input));
+}
+
+TEST(WireFormatTest, RecursionLimit) {
+  UNITTEST::TestRecursiveMessage message;
+  message.mutable_a()->mutable_a()->mutable_a()->mutable_a()->set_i(1);
+  std::string data;
+  message.SerializeToString(&data);
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(4);
+    UNITTEST::TestRecursiveMessage message2;
+    EXPECT_TRUE(message2.ParseFromCodedStream(&input));
+  }
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(3);
+    UNITTEST::TestRecursiveMessage message2;
+    EXPECT_FALSE(message2.ParseFromCodedStream(&input));
+  }
+}
+
+TEST(WireFormatTest, LargeRecursionLimit) {
+  const int kLargeLimit = io::CodedInputStream::GetDefaultRecursionLimit() + 50;
+  UNITTEST::TestRecursiveMessage src, dst, *a;
+  a = src.mutable_a();
+  for (int i = 0; i < kLargeLimit - 1; i++) {
+    a = a->mutable_a();
+  }
+  a->set_i(1);
+
+  std::string data = src.SerializeAsString();
+  {
+    // Parse with default recursion limit. Should fail.
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    ASSERT_FALSE(dst.ParseFromCodedStream(&input));
+  }
+
+  {
+    // Parse with custom recursion limit. Should pass.
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(kLargeLimit);
+    ASSERT_TRUE(dst.ParseFromCodedStream(&input));
+  }
+
+  // Verifies the recursion depth.
+  int depth = 1;
+  a = dst.mutable_a();
+  while (a->has_a()) {
+    a = a->mutable_a();
+    depth++;
+  }
+
+  EXPECT_EQ(a->i(), 1);
+  EXPECT_EQ(depth, kLargeLimit);
+}
+
+TEST(WireFormatTest, UnknownFieldRecursionLimit) {
+  UNITTEST::TestEmptyMessage message;
+  message.mutable_unknown_fields()
+      ->AddGroup(1234)
+      ->AddGroup(1234)
+      ->AddGroup(1234)
+      ->AddGroup(1234)
+      ->AddVarint(1234, 123);
+  std::string data;
+  message.SerializeToString(&data);
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(4);
+    UNITTEST::TestEmptyMessage message2;
+    EXPECT_TRUE(message2.ParseFromCodedStream(&input));
+  }
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(3);
+    UNITTEST::TestEmptyMessage message2;
+    EXPECT_FALSE(message2.ParseFromCodedStream(&input));
+  }
+}
+
+TEST(WireFormatTest, ZigZag) {
+// avoid line-wrapping
+#define LL(x) static_cast<int64_t>(ULL(x))
+#define ULL(x) uint64_t{x##u}
+#define ZigZagEncode32(x) WireFormatLite::ZigZagEncode32(x)
+#define ZigZagDecode32(x) WireFormatLite::ZigZagDecode32(x)
+#define ZigZagEncode64(x) WireFormatLite::ZigZagEncode64(x)
+#define ZigZagDecode64(x) WireFormatLite::ZigZagDecode64(x)
+
+  EXPECT_EQ(0u, ZigZagEncode32(0));
+  EXPECT_EQ(1u, ZigZagEncode32(-1));
+  EXPECT_EQ(2u, ZigZagEncode32(1));
+  EXPECT_EQ(3u, ZigZagEncode32(-2));
+  EXPECT_EQ(0x7FFFFFFEu, ZigZagEncode32(0x3FFFFFFF));
+  EXPECT_EQ(0x7FFFFFFFu, ZigZagEncode32(0xC0000000));
+  EXPECT_EQ(0xFFFFFFFEu, ZigZagEncode32(0x7FFFFFFF));
+  EXPECT_EQ(0xFFFFFFFFu, ZigZagEncode32(0x80000000));
+
+  EXPECT_EQ(0, ZigZagDecode32(0u));
+  EXPECT_EQ(-1, ZigZagDecode32(1u));
+  EXPECT_EQ(1, ZigZagDecode32(2u));
+  EXPECT_EQ(-2, ZigZagDecode32(3u));
+  EXPECT_EQ(0x3FFFFFFF, ZigZagDecode32(0x7FFFFFFEu));
+  EXPECT_EQ(0xC0000000, ZigZagDecode32(0x7FFFFFFFu));
+  EXPECT_EQ(0x7FFFFFFF, ZigZagDecode32(0xFFFFFFFEu));
+  EXPECT_EQ(0x80000000, ZigZagDecode32(0xFFFFFFFFu));
+
+  EXPECT_EQ(0u, ZigZagEncode64(0));
+  EXPECT_EQ(1u, ZigZagEncode64(-1));
+  EXPECT_EQ(2u, ZigZagEncode64(1));
+  EXPECT_EQ(3u, ZigZagEncode64(-2));
+  EXPECT_EQ(ULL(0x000000007FFFFFFE), ZigZagEncode64(LL(0x000000003FFFFFFF)));
+  EXPECT_EQ(ULL(0x000000007FFFFFFF), ZigZagEncode64(LL(0xFFFFFFFFC0000000)));
+  EXPECT_EQ(ULL(0x00000000FFFFFFFE), ZigZagEncode64(LL(0x000000007FFFFFFF)));
+  EXPECT_EQ(ULL(0x00000000FFFFFFFF), ZigZagEncode64(LL(0xFFFFFFFF80000000)));
+  EXPECT_EQ(ULL(0xFFFFFFFFFFFFFFFE), ZigZagEncode64(LL(0x7FFFFFFFFFFFFFFF)));
+  EXPECT_EQ(ULL(0xFFFFFFFFFFFFFFFF), ZigZagEncode64(LL(0x8000000000000000)));
+
+  EXPECT_EQ(0, ZigZagDecode64(0u));
+  EXPECT_EQ(-1, ZigZagDecode64(1u));
+  EXPECT_EQ(1, ZigZagDecode64(2u));
+  EXPECT_EQ(-2, ZigZagDecode64(3u));
+  EXPECT_EQ(LL(0x000000003FFFFFFF), ZigZagDecode64(ULL(0x000000007FFFFFFE)));
+  EXPECT_EQ(LL(0xFFFFFFFFC0000000), ZigZagDecode64(ULL(0x000000007FFFFFFF)));
+  EXPECT_EQ(LL(0x000000007FFFFFFF), ZigZagDecode64(ULL(0x00000000FFFFFFFE)));
+  EXPECT_EQ(LL(0xFFFFFFFF80000000), ZigZagDecode64(ULL(0x00000000FFFFFFFF)));
+  EXPECT_EQ(LL(0x7FFFFFFFFFFFFFFF), ZigZagDecode64(ULL(0xFFFFFFFFFFFFFFFE)));
+  EXPECT_EQ(LL(0x8000000000000000), ZigZagDecode64(ULL(0xFFFFFFFFFFFFFFFF)));
+
+  // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
+  // were chosen semi-randomly via keyboard bashing.
+  EXPECT_EQ(0, ZigZagDecode32(ZigZagEncode32(0)));
+  EXPECT_EQ(1, ZigZagDecode32(ZigZagEncode32(1)));
+  EXPECT_EQ(-1, ZigZagDecode32(ZigZagEncode32(-1)));
+  EXPECT_EQ(14927, ZigZagDecode32(ZigZagEncode32(14927)));
+  EXPECT_EQ(-3612, ZigZagDecode32(ZigZagEncode32(-3612)));
+
+  EXPECT_EQ(0, ZigZagDecode64(ZigZagEncode64(0)));
+  EXPECT_EQ(1, ZigZagDecode64(ZigZagEncode64(1)));
+  EXPECT_EQ(-1, ZigZagDecode64(ZigZagEncode64(-1)));
+  EXPECT_EQ(14927, ZigZagDecode64(ZigZagEncode64(14927)));
+  EXPECT_EQ(-3612, ZigZagDecode64(ZigZagEncode64(-3612)));
+
+  EXPECT_EQ(LL(856912304801416),
+            ZigZagDecode64(ZigZagEncode64(LL(856912304801416))));
+  EXPECT_EQ(LL(-75123905439571256),
+            ZigZagDecode64(ZigZagEncode64(LL(-75123905439571256))));
+}
+
+TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) {
+  // At one point checks would trigger when parsing repeated fixed scalar
+  // fields.
+  UNITTEST::TestRepeatedScalarDifferentTagSizes msg1, msg2;
+  for (int i = 0; i < 100; ++i) {
+    msg1.add_repeated_fixed32(i);
+    msg1.add_repeated_int32(i);
+    msg1.add_repeated_fixed64(i);
+    msg1.add_repeated_int64(i);
+    msg1.add_repeated_float(i);
+    msg1.add_repeated_uint64(i);
+  }
+
+  // Make sure that we have a variety of tag sizes.
+  const Descriptor* desc = msg1.GetDescriptor();
+  const FieldDescriptor* field;
+  field = desc->FindFieldByName("repeated_fixed32");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_int32");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_fixed64");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_int64");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_float");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_uint64");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type()));
+
+  EXPECT_TRUE(msg2.ParseFromString(msg1.SerializeAsString()));
+  EXPECT_EQ(msg1.DebugString(), msg2.DebugString());
+}
+
+TEST(WireFormatTest, CompatibleTypes) {
+  const int64_t data = 0x100000000LL;
+  UNITTEST::Int64Message msg1;
+  msg1.set_data(data);
+  std::string serialized;
+  msg1.SerializeToString(&serialized);
+
+  // Test int64 is compatible with bool
+  UNITTEST::BoolMessage msg2;
+  ASSERT_TRUE(msg2.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<bool>(data), msg2.data());
+
+  // Test int64 is compatible with uint64
+  UNITTEST::Uint64Message msg3;
+  ASSERT_TRUE(msg3.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<uint64_t>(data), msg3.data());
+
+  // Test int64 is compatible with int32
+  UNITTEST::Int32Message msg4;
+  ASSERT_TRUE(msg4.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<int32_t>(data), msg4.data());
+
+  // Test int64 is compatible with uint32
+  UNITTEST::Uint32Message msg5;
+  ASSERT_TRUE(msg5.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<uint32_t>(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::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::FOO,
+              message.repeated_nested_enum(0));
+  }
+
+  template <class Proto>
+  void TestSerialization(Proto* message, const std::string& expected) {
+    SetProto3PrimitiveRepeatedFields(message);
+
+    size_t size = message->ByteSizeLong();
+
+    // Serialize using the generated code.
+    std::string generated_data;
+    {
+      io::StringOutputStream raw_output(&generated_data);
+      io::CodedOutputStream output(&raw_output);
+      message->SerializeWithCachedSizes(&output);
+      ASSERT_FALSE(output.HadError());
+    }
+    EXPECT_TRUE(TestUtil::EqualsToSerialized(*message, generated_data));
+
+    // Serialize using the dynamic code.
+    std::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 std::string& compatible_data) {
+    message->Clear();
+    message->ParseFromString(compatible_data);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+
+    message->Clear();
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8_t*>(compatible_data.data()),
+        compatible_data.size());
+    WireFormat::ParseAndMergePartial(&input, message);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+  }
+
+  const std::string packedTestAllTypes_;
+  const std::string packedTestUnpackedTypes_;
+  const std::string unpackedTestAllTypes_;
+  const std::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
+  // contains exactly the given bytes, which may be invalid.
+  std::string MakeInvalidEmbeddedMessage(const char* bytes, int size) {
+    const FieldDescriptor* field =
+        UNITTEST::TestAllTypes::descriptor()->FindFieldByName(
+            "optional_nested_message");
+    GOOGLE_CHECK(field != nullptr);
+
+    std::string result;
+
+    {
+      io::StringOutputStream raw_output(&result);
+      io::CodedOutputStream output(&raw_output);
+
+      WireFormatLite::WriteBytes(field->number(), std::string(bytes, size),
+                                 &output);
+    }
+
+    return result;
+  }
+
+  // Make a serialized TestAllTypes in which the field optionalgroup
+  // contains exactly the given bytes -- which may be invalid -- and
+  // possibly no end tag.
+  std::string MakeInvalidGroup(const char* bytes, int size,
+                               bool include_end_tag) {
+    const FieldDescriptor* field =
+        UNITTEST::TestAllTypes::descriptor()->FindFieldByName("optionalgroup");
+    GOOGLE_CHECK(field != nullptr);
+
+    std::string result;
+
+    {
+      io::StringOutputStream raw_output(&result);
+      io::CodedOutputStream output(&raw_output);
+
+      output.WriteVarint32(WireFormat::MakeTag(field));
+      output.WriteString(std::string(bytes, size));
+      if (include_end_tag) {
+        output.WriteVarint32(WireFormatLite::MakeTag(
+            field->number(), WireFormatLite::WIRETYPE_END_GROUP));
+      }
+    }
+
+    return result;
+  }
+};
+
+TEST_F(WireFormatInvalidInputTest, InvalidSubMessage) {
+  UNITTEST::TestAllTypes message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromString(MakeInvalidEmbeddedMessage("", 0)));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\0", 1)));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\200", 1)));
+
+  // The byte is an endgroup tag, but we aren't parsing a group.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\014", 1)));
+
+  // The byte is a valid varint but not a valid tag (bad wire type).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\017", 1)));
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidMessageWithExtraZero) {
+  std::string data;
+  {
+    // Serialize a valid proto
+    UNITTEST::TestAllTypes message;
+    message.set_optional_int32(1);
+    message.SerializeToString(&data);
+    data.push_back(0);  // Append invalid zero tag
+  }
+
+  // Control case.
+  {
+    io::ArrayInputStream ais(data.data(), data.size());
+    io::CodedInputStream is(&ais);
+    UNITTEST::TestAllTypes message;
+    // It should fail but currently passes.
+    EXPECT_TRUE(message.MergePartialFromCodedStream(&is));
+    // Parsing from the string should fail.
+    EXPECT_FALSE(message.ParseFromString(data));
+  }
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidGroup) {
+  UNITTEST::TestAllTypes message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromString(MakeInvalidGroup("", 0, true)));
+
+  // Missing end tag.  Groups cannot end at EOF.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("", 0, false)));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\0", 1, false)));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\200", 1, false)));
+
+  // The byte is an endgroup tag, but not the right one for this group.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\014", 1, false)));
+
+  // The byte is a valid varint but not a valid tag (bad wire type).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\017", 1, true)));
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidUnknownGroup) {
+  // Use TestEmptyMessage so that the group made by MakeInvalidGroup will not
+  // be a known tag number.
+  UNITTEST::TestEmptyMessage message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromString(MakeInvalidGroup("", 0, true)));
+
+  // Missing end tag.  Groups cannot end at EOF.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("", 0, false)));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\0", 1, false)));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\200", 1, false)));
+
+  // The byte is an endgroup tag, but not the right one for this group.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\014", 1, false)));
+
+  // The byte is a valid varint but not a valid tag (bad wire type).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\017", 1, true)));
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidStringInUnknownGroup) {
+  // Test a bug fix:  SkipMessage should fail if the message contains a
+  // string whose length would extend beyond the message end.
+
+  UNITTEST::TestAllTypes message;
+  message.set_optional_string("foo foo foo foo");
+  std::string data;
+  message.SerializeToString(&data);
+
+  // Chop some bytes off the end.
+  data.resize(data.size() - 4);
+
+  // Try to skip it.  Note that the bug was only present when parsing to an
+  // UnknownFieldSet.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream coded_input(&raw_input);
+  UnknownFieldSet unknown_fields;
+  EXPECT_FALSE(WireFormat::SkipMessage(&coded_input, &unknown_fields));
+}
+
+// Test differences between string and bytes.
+// Value of a string type must be valid UTF-8 string.  When UTF-8
+// validation is enabled (GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED):
+// WriteInvalidUTF8String:  see error message.
+// ReadInvalidUTF8String:  see error message.
+// WriteValidUTF8String: fine.
+// ReadValidUTF8String:  fine.
+// WriteAnyBytes: fine.
+// ReadAnyBytes: fine.
+const char* kInvalidUTF8String = "Invalid UTF-8: \xA0\xB0\xC0\xD0";
+// This used to be "Valid UTF-8: \x01\x02\u8C37\u6B4C", but MSVC seems to
+// interpret \u differently from GCC.
+const char* kValidUTF8String = "Valid UTF-8: \x01\x02\350\260\267\346\255\214";
+
+template <typename T>
+bool WriteMessage(const char* value, T* message, std::string* wire_buffer) {
+  message->set_data(value);
+  wire_buffer->clear();
+  message->AppendToString(wire_buffer);
+  return (wire_buffer->size() > 0);
+}
+
+template <typename T>
+bool ReadMessage(const std::string& wire_buffer, T* message) {
+  return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
+}
+
+class Utf8ValidationTest : public ::testing::Test {
+ protected:
+  Utf8ValidationTest() {}
+  ~Utf8ValidationTest() override {}
+  void SetUp() override {
+  }
+
+};
+
+TEST_F(Utf8ValidationTest, WriteInvalidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  EXPECT_THAT(errors,
+              testing::ElementsAre(
+                  "String field '" + std::string(UNITTEST_PACKAGE_NAME) +
+                  ".OneString.data' "
+                  "contains invalid UTF-8 data when "
+                  "serializing a protocol buffer. Use the "
+                  "'bytes' type if you intend to send raw bytes. "));
+#else
+  ASSERT_EQ(0, errors.size());
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+}
+
+
+TEST_F(Utf8ValidationTest, ReadInvalidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+  UNITTEST::OneString output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  EXPECT_THAT(errors,
+              testing::ElementsAre(
+                  "String field '" + std::string(UNITTEST_PACKAGE_NAME) +
+                  ".OneString.data' "
+                  "contains invalid UTF-8 data when "
+                  "parsing a protocol buffer. Use the "
+                  "'bytes' type if you intend to send raw bytes. "));
+
+#else
+  ASSERT_EQ(0, errors.size());
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+}
+
+
+TEST_F(Utf8ValidationTest, WriteValidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WriteMessage(kValidUTF8String, &input, &wire_buffer);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+}
+
+TEST_F(Utf8ValidationTest, ReadValidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  WriteMessage(kValidUTF8String, &input, &wire_buffer);
+  UNITTEST::OneString output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+  EXPECT_EQ(input.data(), output.data());
+}
+
+// Bytes: anything can pass as bytes, use invalid UTF-8 string to test
+TEST_F(Utf8ValidationTest, WriteArbitraryBytes) {
+  std::string wire_buffer;
+  UNITTEST::OneBytes input;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+}
+
+TEST_F(Utf8ValidationTest, ReadArbitraryBytes) {
+  std::string wire_buffer;
+  UNITTEST::OneBytes input;
+  WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+  UNITTEST::OneBytes output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+  EXPECT_EQ(input.data(), output.data());
+}
+
+TEST_F(Utf8ValidationTest, ParseRepeatedString) {
+  UNITTEST::MoreBytes input;
+  input.add_data(kValidUTF8String);
+  input.add_data(kInvalidUTF8String);
+  input.add_data(kInvalidUTF8String);
+  std::string wire_buffer = input.SerializeAsString();
+
+  UNITTEST::MoreString output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  ASSERT_EQ(2, errors.size());
+#else
+  ASSERT_EQ(0, errors.size());
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  EXPECT_EQ(wire_buffer, output.SerializeAsString());
+}
+
+// Test the old VerifyUTF8String() function, which may still be called by old
+// generated code.
+TEST_F(Utf8ValidationTest, OldVerifyUTF8String) {
+  std::string data(kInvalidUTF8String);
+
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WireFormat::VerifyUTF8String(data.data(), data.size(),
+                                 WireFormat::SERIALIZE);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  ASSERT_EQ(1, errors.size());
+  EXPECT_TRUE(
+      HasPrefixString(errors[0],
+                       "String field contains invalid UTF-8 data when "
+                       "serializing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
+#else
+  ASSERT_EQ(0, errors.size());
+#endif
+}
+
+
+TEST(RepeatedVarint, Int32) {
+  RepeatedField<int32_t> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar Int32Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::Int32Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::Int32Size(v));
+}
+
+TEST(RepeatedVarint, Int64) {
+  RepeatedField<int64_t> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar Int64Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::Int64Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::Int64Size(v));
+}
+
+TEST(RepeatedVarint, SInt32) {
+  RepeatedField<int32_t> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar SInt32Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::SInt32Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::SInt32Size(v));
+}
+
+TEST(RepeatedVarint, SInt64) {
+  RepeatedField<int64_t> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar SInt64Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::SInt64Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::SInt64Size(v));
+}
+
+TEST(RepeatedVarint, UInt32) {
+  RepeatedField<uint32_t> v;
+
+  // Insert 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar UInt32Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::UInt32Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::UInt32Size(v));
+}
+
+TEST(RepeatedVarint, UInt64) {
+  RepeatedField<uint64_t> v;
+
+  // Insert 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar UInt64Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::UInt64Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::UInt64Size(v));
+}
+
+TEST(RepeatedVarint, Enum) {
+  RepeatedField<int> v;
+
+  // Insert 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar EnumSize.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::EnumSize(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::EnumSize(v));
+}
+
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
new file mode 100644
index 0000000..40ba60a
--- /dev/null
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -0,0 +1,1979 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#include <google/protobuf/wrappers.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.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)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR DoubleValue::DoubleValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct DoubleValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DoubleValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DoubleValueDefaultTypeInternal() {}
+  union {
+    DoubleValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DoubleValueDefaultTypeInternal _DoubleValue_default_instance_;
+PROTOBUF_CONSTEXPR FloatValue::FloatValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FloatValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FloatValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FloatValueDefaultTypeInternal() {}
+  union {
+    FloatValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FloatValueDefaultTypeInternal _FloatValue_default_instance_;
+PROTOBUF_CONSTEXPR Int64Value::Int64Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/int64_t{0}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct Int64ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR Int64ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~Int64ValueDefaultTypeInternal() {}
+  union {
+    Int64Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Int64ValueDefaultTypeInternal _Int64Value_default_instance_;
+PROTOBUF_CONSTEXPR UInt64Value::UInt64Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/uint64_t{0u}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct UInt64ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UInt64ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UInt64ValueDefaultTypeInternal() {}
+  union {
+    UInt64Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UInt64ValueDefaultTypeInternal _UInt64Value_default_instance_;
+PROTOBUF_CONSTEXPR Int32Value::Int32Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct Int32ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR Int32ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~Int32ValueDefaultTypeInternal() {}
+  union {
+    Int32Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Int32ValueDefaultTypeInternal _Int32Value_default_instance_;
+PROTOBUF_CONSTEXPR UInt32Value::UInt32Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0u
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct UInt32ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UInt32ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UInt32ValueDefaultTypeInternal() {}
+  union {
+    UInt32Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UInt32ValueDefaultTypeInternal _UInt32Value_default_instance_;
+PROTOBUF_CONSTEXPR BoolValue::BoolValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/false
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct BoolValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR BoolValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~BoolValueDefaultTypeInternal() {}
+  union {
+    BoolValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 BoolValueDefaultTypeInternal _BoolValue_default_instance_;
+PROTOBUF_CONSTEXPR StringValue::StringValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct StringValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR StringValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~StringValueDefaultTypeInternal() {}
+  union {
+    StringValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StringValueDefaultTypeInternal _StringValue_default_instance_;
+PROTOBUF_CONSTEXPR BytesValue::BytesValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct BytesValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR BytesValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~BytesValueDefaultTypeInternal() {}
+  union {
+    BytesValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 BytesValueDefaultTypeInternal _BytesValue_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[9];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DoubleValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DoubleValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FloatValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FloatValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int64Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int64Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt64Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt64Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int32Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int32Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt32Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt32Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BoolValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BoolValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::StringValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::StringValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BytesValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BytesValue, _impl_.value_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DoubleValue)},
+  { 7, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FloatValue)},
+  { 14, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Int64Value)},
+  { 21, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UInt64Value)},
+  { 28, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Int32Value)},
+  { 35, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UInt32Value)},
+  { 42, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::BoolValue)},
+  { 49, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::StringValue)},
+  { 56, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::BytesValue)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_DoubleValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FloatValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Int64Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UInt64Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Int32Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UInt32Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_BoolValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_StringValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_BytesValue_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\036google/protobuf/wrappers.proto\022\017google"
+  ".protobuf\"\034\n\013DoubleValue\022\r\n\005value\030\001 \001(\001\""
+  "\033\n\nFloatValue\022\r\n\005value\030\001 \001(\002\"\033\n\nInt64Val"
+  "ue\022\r\n\005value\030\001 \001(\003\"\034\n\013UInt64Value\022\r\n\005valu"
+  "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013"
+  "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022"
+  "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001"
+  " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014B\203\001\n\023co"
+  "m.google.protobufB\rWrappersProtoP\001Z1goog"
+  "le.golang.org/protobuf/types/known/wrapp"
+  "erspb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKno"
+  "wnTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
+    false, false, 455, descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto,
+    "google/protobuf/wrappers.proto",
+    &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once, nullptr, 0, 9,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fwrappers_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fwrappers_2eproto(&descriptor_table_google_2fprotobuf_2fwrappers_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class DoubleValue::_Internal {
+ public:
+};
+
+DoubleValue::DoubleValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue)
+}
+DoubleValue::DoubleValue(const DoubleValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DoubleValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DoubleValue)
+}
+
+inline void DoubleValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+DoubleValue::~DoubleValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DoubleValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DoubleValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void DoubleValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DoubleValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DoubleValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DoubleValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // double value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 9)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr);
+          ptr += sizeof(double);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DoubleValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DoubleValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // double value = 1;
+  static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
+  double tmp_value = this->_internal_value();
+  uint64_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DoubleValue)
+  return target;
+}
+
+size_t DoubleValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DoubleValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // double value = 1;
+  static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
+  double tmp_value = this->_internal_value();
+  uint64_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    total_size += 1 + 8;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DoubleValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DoubleValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DoubleValue::GetClassData() const { return &_class_data_; }
+
+
+void DoubleValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DoubleValue*>(&to_msg);
+  auto& from = static_cast<const DoubleValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DoubleValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
+  double tmp_value = from._internal_value();
+  uint64_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DoubleValue::CopyFrom(const DoubleValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DoubleValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DoubleValue::IsInitialized() const {
+  return true;
+}
+
+void DoubleValue::InternalSwap(DoubleValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DoubleValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[0]);
+}
+
+// ===================================================================
+
+class FloatValue::_Internal {
+ public:
+};
+
+FloatValue::FloatValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue)
+}
+FloatValue::FloatValue(const FloatValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FloatValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FloatValue)
+}
+
+inline void FloatValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+FloatValue::~FloatValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FloatValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FloatValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void FloatValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FloatValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FloatValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FloatValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // float value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 13)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(ptr);
+          ptr += sizeof(float);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FloatValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FloatValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // float value = 1;
+  static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
+  float tmp_value = this->_internal_value();
+  uint32_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteFloatToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FloatValue)
+  return target;
+}
+
+size_t FloatValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FloatValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // float value = 1;
+  static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
+  float tmp_value = this->_internal_value();
+  uint32_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    total_size += 1 + 4;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FloatValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FloatValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FloatValue::GetClassData() const { return &_class_data_; }
+
+
+void FloatValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FloatValue*>(&to_msg);
+  auto& from = static_cast<const FloatValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FloatValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
+  float tmp_value = from._internal_value();
+  uint32_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FloatValue::CopyFrom(const FloatValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FloatValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FloatValue::IsInitialized() const {
+  return true;
+}
+
+void FloatValue::InternalSwap(FloatValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FloatValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[1]);
+}
+
+// ===================================================================
+
+class Int64Value::_Internal {
+ public:
+};
+
+Int64Value::Int64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value)
+}
+Int64Value::Int64Value(const Int64Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Int64Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Int64Value)
+}
+
+inline void Int64Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){int64_t{0}}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Int64Value::~Int64Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Int64Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Int64Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Int64Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Int64Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Int64Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = int64_t{0};
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Int64Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int64 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Int64Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int64Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int64 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int64Value)
+  return target;
+}
+
+size_t Int64Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int64Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int64 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Int64Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Int64Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Int64Value::GetClassData() const { return &_class_data_; }
+
+
+void Int64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Int64Value*>(&to_msg);
+  auto& from = static_cast<const Int64Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int64Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Int64Value::CopyFrom(const Int64Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Int64Value::IsInitialized() const {
+  return true;
+}
+
+void Int64Value::InternalSwap(Int64Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Int64Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[2]);
+}
+
+// ===================================================================
+
+class UInt64Value::_Internal {
+ public:
+};
+
+UInt64Value::UInt64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value)
+}
+UInt64Value::UInt64Value(const UInt64Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UInt64Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UInt64Value)
+}
+
+inline void UInt64Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){uint64_t{0u}}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+UInt64Value::~UInt64Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UInt64Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UInt64Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void UInt64Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UInt64Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt64Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = uint64_t{0u};
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UInt64Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // uint64 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UInt64Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt64Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint64 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt64Value)
+  return target;
+}
+
+size_t UInt64Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt64Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // uint64 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UInt64Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UInt64Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UInt64Value::GetClassData() const { return &_class_data_; }
+
+
+void UInt64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UInt64Value*>(&to_msg);
+  auto& from = static_cast<const UInt64Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt64Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UInt64Value::CopyFrom(const UInt64Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UInt64Value::IsInitialized() const {
+  return true;
+}
+
+void UInt64Value::InternalSwap(UInt64Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UInt64Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[3]);
+}
+
+// ===================================================================
+
+class Int32Value::_Internal {
+ public:
+};
+
+Int32Value::Int32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value)
+}
+Int32Value::Int32Value(const Int32Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Int32Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Int32Value)
+}
+
+inline void Int32Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Int32Value::~Int32Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Int32Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Int32Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Int32Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Int32Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Int32Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Int32Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int32 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Int32Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int32Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int32 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int32Value)
+  return target;
+}
+
+size_t Int32Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int32Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int32 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Int32Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Int32Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Int32Value::GetClassData() const { return &_class_data_; }
+
+
+void Int32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Int32Value*>(&to_msg);
+  auto& from = static_cast<const Int32Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int32Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Int32Value::CopyFrom(const Int32Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Int32Value::IsInitialized() const {
+  return true;
+}
+
+void Int32Value::InternalSwap(Int32Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Int32Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[4]);
+}
+
+// ===================================================================
+
+class UInt32Value::_Internal {
+ public:
+};
+
+UInt32Value::UInt32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value)
+}
+UInt32Value::UInt32Value(const UInt32Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UInt32Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UInt32Value)
+}
+
+inline void UInt32Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0u}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+UInt32Value::~UInt32Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UInt32Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UInt32Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void UInt32Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UInt32Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt32Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0u;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UInt32Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // uint32 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UInt32Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt32Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint32 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt32ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt32Value)
+  return target;
+}
+
+size_t UInt32Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt32Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // uint32 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::UInt32SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UInt32Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UInt32Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UInt32Value::GetClassData() const { return &_class_data_; }
+
+
+void UInt32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UInt32Value*>(&to_msg);
+  auto& from = static_cast<const UInt32Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt32Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UInt32Value::CopyFrom(const UInt32Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UInt32Value::IsInitialized() const {
+  return true;
+}
+
+void UInt32Value::InternalSwap(UInt32Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UInt32Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[5]);
+}
+
+// ===================================================================
+
+class BoolValue::_Internal {
+ public:
+};
+
+BoolValue::BoolValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue)
+}
+BoolValue::BoolValue(const BoolValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  BoolValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.BoolValue)
+}
+
+inline void BoolValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){false}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+BoolValue::~BoolValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.BoolValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void BoolValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void BoolValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void BoolValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.BoolValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = false;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* BoolValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // bool value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* BoolValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BoolValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // bool value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BoolValue)
+  return target;
+}
+
+size_t BoolValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BoolValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // bool value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += 1 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData BoolValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    BoolValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*BoolValue::GetClassData() const { return &_class_data_; }
+
+
+void BoolValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<BoolValue*>(&to_msg);
+  auto& from = static_cast<const BoolValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BoolValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void BoolValue::CopyFrom(const BoolValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BoolValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool BoolValue::IsInitialized() const {
+  return true;
+}
+
+void BoolValue::InternalSwap(BoolValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata BoolValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[6]);
+}
+
+// ===================================================================
+
+class StringValue::_Internal {
+ public:
+};
+
+StringValue::StringValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue)
+}
+StringValue::StringValue(const StringValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  StringValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_value().empty()) {
+    _this->_impl_.value_.Set(from._internal_value(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.StringValue)
+}
+
+inline void StringValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+StringValue::~StringValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.StringValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void StringValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.value_.Destroy();
+}
+
+void StringValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void StringValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.StringValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* StringValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.StringValue.value"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* StringValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string value = 1;
+  if (!this->_internal_value().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_value().data(), static_cast<int>(this->_internal_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.StringValue.value");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.StringValue)
+  return target;
+}
+
+size_t StringValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.StringValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string value = 1;
+  if (!this->_internal_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData StringValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    StringValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*StringValue::GetClassData() const { return &_class_data_; }
+
+
+void StringValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<StringValue*>(&to_msg);
+  auto& from = static_cast<const StringValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.StringValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_value().empty()) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void StringValue::CopyFrom(const StringValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.StringValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool StringValue::IsInitialized() const {
+  return true;
+}
+
+void StringValue::InternalSwap(StringValue* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.value_, lhs_arena,
+      &other->_impl_.value_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata StringValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[7]);
+}
+
+// ===================================================================
+
+class BytesValue::_Internal {
+ public:
+};
+
+BytesValue::BytesValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue)
+}
+BytesValue::BytesValue(const BytesValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  BytesValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_value().empty()) {
+    _this->_impl_.value_.Set(from._internal_value(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.BytesValue)
+}
+
+inline void BytesValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+BytesValue::~BytesValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.BytesValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void BytesValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.value_.Destroy();
+}
+
+void BytesValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void BytesValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.BytesValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* BytesValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // bytes value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* BytesValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BytesValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // bytes value = 1;
+  if (!this->_internal_value().empty()) {
+    target = stream->WriteBytesMaybeAliased(
+        1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BytesValue)
+  return target;
+}
+
+size_t BytesValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BytesValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // bytes value = 1;
+  if (!this->_internal_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
+        this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData BytesValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    BytesValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*BytesValue::GetClassData() const { return &_class_data_; }
+
+
+void BytesValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<BytesValue*>(&to_msg);
+  auto& from = static_cast<const BytesValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BytesValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_value().empty()) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void BytesValue::CopyFrom(const BytesValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BytesValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool BytesValue::IsInitialized() const {
+  return true;
+}
+
+void BytesValue::InternalSwap(BytesValue* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.value_, lhs_arena,
+      &other->_impl_.value_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata BytesValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[8]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DoubleValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FloatValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FloatValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FloatValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int64Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int64Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Int64Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt64Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int32Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int32Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Int32Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt32Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BoolValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BoolValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::BoolValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::StringValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::StringValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::StringValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BytesValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BytesValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::BytesValue >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
new file mode 100644
index 0000000..064bd37
--- /dev/null
+++ b/src/google/protobuf/wrappers.pb.h
@@ -0,0 +1,1741 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fwrappers_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fwrappers_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#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 3021009 < 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/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fwrappers_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fwrappers_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class BoolValue;
+struct BoolValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern BoolValueDefaultTypeInternal _BoolValue_default_instance_;
+class BytesValue;
+struct BytesValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern BytesValueDefaultTypeInternal _BytesValue_default_instance_;
+class DoubleValue;
+struct DoubleValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern DoubleValueDefaultTypeInternal _DoubleValue_default_instance_;
+class FloatValue;
+struct FloatValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern FloatValueDefaultTypeInternal _FloatValue_default_instance_;
+class Int32Value;
+struct Int32ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern Int32ValueDefaultTypeInternal _Int32Value_default_instance_;
+class Int64Value;
+struct Int64ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern Int64ValueDefaultTypeInternal _Int64Value_default_instance_;
+class StringValue;
+struct StringValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern StringValueDefaultTypeInternal _StringValue_default_instance_;
+class UInt32Value;
+struct UInt32ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern UInt32ValueDefaultTypeInternal _UInt32Value_default_instance_;
+class UInt64Value;
+struct UInt64ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern UInt64ValueDefaultTypeInternal _UInt64Value_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::BoolValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::BoolValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::BytesValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::BytesValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DoubleValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DoubleValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FloatValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FloatValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Int32Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Int32Value>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Int64Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Int64Value>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::StringValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::StringValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UInt32Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UInt32Value>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UInt64Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UInt64Value>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT DoubleValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DoubleValue) */ {
+ public:
+  inline DoubleValue() : DoubleValue(nullptr) {}
+  ~DoubleValue() override;
+  explicit PROTOBUF_CONSTEXPR DoubleValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DoubleValue(const DoubleValue& from);
+  DoubleValue(DoubleValue&& from) noexcept
+    : DoubleValue() {
+    *this = ::std::move(from);
+  }
+
+  inline DoubleValue& operator=(const DoubleValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DoubleValue& operator=(DoubleValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DoubleValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DoubleValue* internal_default_instance() {
+    return reinterpret_cast<const DoubleValue*>(
+               &_DoubleValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(DoubleValue& a, DoubleValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DoubleValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DoubleValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DoubleValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DoubleValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DoubleValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DoubleValue& from) {
+    DoubleValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DoubleValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DoubleValue";
+  }
+  protected:
+  explicit DoubleValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // double value = 1;
+  void clear_value();
+  double value() const;
+  void set_value(double value);
+  private:
+  double _internal_value() const;
+  void _internal_set_value(double value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DoubleValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    double value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FloatValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FloatValue) */ {
+ public:
+  inline FloatValue() : FloatValue(nullptr) {}
+  ~FloatValue() override;
+  explicit PROTOBUF_CONSTEXPR FloatValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FloatValue(const FloatValue& from);
+  FloatValue(FloatValue&& from) noexcept
+    : FloatValue() {
+    *this = ::std::move(from);
+  }
+
+  inline FloatValue& operator=(const FloatValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FloatValue& operator=(FloatValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FloatValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FloatValue* internal_default_instance() {
+    return reinterpret_cast<const FloatValue*>(
+               &_FloatValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(FloatValue& a, FloatValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FloatValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FloatValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FloatValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FloatValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FloatValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FloatValue& from) {
+    FloatValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FloatValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FloatValue";
+  }
+  protected:
+  explicit FloatValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // float value = 1;
+  void clear_value();
+  float value() const;
+  void set_value(float value);
+  private:
+  float _internal_value() const;
+  void _internal_set_value(float value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FloatValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    float value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Int64Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int64Value) */ {
+ public:
+  inline Int64Value() : Int64Value(nullptr) {}
+  ~Int64Value() override;
+  explicit PROTOBUF_CONSTEXPR Int64Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Int64Value(const Int64Value& from);
+  Int64Value(Int64Value&& from) noexcept
+    : Int64Value() {
+    *this = ::std::move(from);
+  }
+
+  inline Int64Value& operator=(const Int64Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Int64Value& operator=(Int64Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Int64Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Int64Value* internal_default_instance() {
+    return reinterpret_cast<const Int64Value*>(
+               &_Int64Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Int64Value& a, Int64Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Int64Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Int64Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Int64Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Int64Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Int64Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Int64Value& from) {
+    Int64Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Int64Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Int64Value";
+  }
+  protected:
+  explicit Int64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // int64 value = 1;
+  void clear_value();
+  int64_t value() const;
+  void set_value(int64_t value);
+  private:
+  int64_t _internal_value() const;
+  void _internal_set_value(int64_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Int64Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int64_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UInt64Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt64Value) */ {
+ public:
+  inline UInt64Value() : UInt64Value(nullptr) {}
+  ~UInt64Value() override;
+  explicit PROTOBUF_CONSTEXPR UInt64Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UInt64Value(const UInt64Value& from);
+  UInt64Value(UInt64Value&& from) noexcept
+    : UInt64Value() {
+    *this = ::std::move(from);
+  }
+
+  inline UInt64Value& operator=(const UInt64Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UInt64Value& operator=(UInt64Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UInt64Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UInt64Value* internal_default_instance() {
+    return reinterpret_cast<const UInt64Value*>(
+               &_UInt64Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(UInt64Value& a, UInt64Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UInt64Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UInt64Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UInt64Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UInt64Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UInt64Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UInt64Value& from) {
+    UInt64Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UInt64Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UInt64Value";
+  }
+  protected:
+  explicit UInt64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // uint64 value = 1;
+  void clear_value();
+  uint64_t value() const;
+  void set_value(uint64_t value);
+  private:
+  uint64_t _internal_value() const;
+  void _internal_set_value(uint64_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UInt64Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    uint64_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Int32Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int32Value) */ {
+ public:
+  inline Int32Value() : Int32Value(nullptr) {}
+  ~Int32Value() override;
+  explicit PROTOBUF_CONSTEXPR Int32Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Int32Value(const Int32Value& from);
+  Int32Value(Int32Value&& from) noexcept
+    : Int32Value() {
+    *this = ::std::move(from);
+  }
+
+  inline Int32Value& operator=(const Int32Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Int32Value& operator=(Int32Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Int32Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Int32Value* internal_default_instance() {
+    return reinterpret_cast<const Int32Value*>(
+               &_Int32Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    4;
+
+  friend void swap(Int32Value& a, Int32Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Int32Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Int32Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Int32Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Int32Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Int32Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Int32Value& from) {
+    Int32Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Int32Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Int32Value";
+  }
+  protected:
+  explicit Int32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // int32 value = 1;
+  void clear_value();
+  int32_t value() const;
+  void set_value(int32_t value);
+  private:
+  int32_t _internal_value() const;
+  void _internal_set_value(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Int32Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int32_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UInt32Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt32Value) */ {
+ public:
+  inline UInt32Value() : UInt32Value(nullptr) {}
+  ~UInt32Value() override;
+  explicit PROTOBUF_CONSTEXPR UInt32Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UInt32Value(const UInt32Value& from);
+  UInt32Value(UInt32Value&& from) noexcept
+    : UInt32Value() {
+    *this = ::std::move(from);
+  }
+
+  inline UInt32Value& operator=(const UInt32Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UInt32Value& operator=(UInt32Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UInt32Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UInt32Value* internal_default_instance() {
+    return reinterpret_cast<const UInt32Value*>(
+               &_UInt32Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    5;
+
+  friend void swap(UInt32Value& a, UInt32Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UInt32Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UInt32Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UInt32Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UInt32Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UInt32Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UInt32Value& from) {
+    UInt32Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UInt32Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UInt32Value";
+  }
+  protected:
+  explicit UInt32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // uint32 value = 1;
+  void clear_value();
+  uint32_t value() const;
+  void set_value(uint32_t value);
+  private:
+  uint32_t _internal_value() const;
+  void _internal_set_value(uint32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UInt32Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    uint32_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT BoolValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BoolValue) */ {
+ public:
+  inline BoolValue() : BoolValue(nullptr) {}
+  ~BoolValue() override;
+  explicit PROTOBUF_CONSTEXPR BoolValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  BoolValue(const BoolValue& from);
+  BoolValue(BoolValue&& from) noexcept
+    : BoolValue() {
+    *this = ::std::move(from);
+  }
+
+  inline BoolValue& operator=(const BoolValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline BoolValue& operator=(BoolValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const BoolValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const BoolValue* internal_default_instance() {
+    return reinterpret_cast<const BoolValue*>(
+               &_BoolValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    6;
+
+  friend void swap(BoolValue& a, BoolValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(BoolValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(BoolValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  BoolValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<BoolValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const BoolValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const BoolValue& from) {
+    BoolValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(BoolValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.BoolValue";
+  }
+  protected:
+  explicit BoolValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // bool value = 1;
+  void clear_value();
+  bool value() const;
+  void set_value(bool value);
+  private:
+  bool _internal_value() const;
+  void _internal_set_value(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.BoolValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    bool value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT StringValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.StringValue) */ {
+ public:
+  inline StringValue() : StringValue(nullptr) {}
+  ~StringValue() override;
+  explicit PROTOBUF_CONSTEXPR StringValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  StringValue(const StringValue& from);
+  StringValue(StringValue&& from) noexcept
+    : StringValue() {
+    *this = ::std::move(from);
+  }
+
+  inline StringValue& operator=(const StringValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline StringValue& operator=(StringValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const StringValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const StringValue* internal_default_instance() {
+    return reinterpret_cast<const StringValue*>(
+               &_StringValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    7;
+
+  friend void swap(StringValue& a, StringValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(StringValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(StringValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  StringValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<StringValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const StringValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const StringValue& from) {
+    StringValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(StringValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.StringValue";
+  }
+  protected:
+  explicit StringValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // string value = 1;
+  void clear_value();
+  const std::string& value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_value();
+  PROTOBUF_NODISCARD std::string* release_value();
+  void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.StringValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT BytesValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BytesValue) */ {
+ public:
+  inline BytesValue() : BytesValue(nullptr) {}
+  ~BytesValue() override;
+  explicit PROTOBUF_CONSTEXPR BytesValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  BytesValue(const BytesValue& from);
+  BytesValue(BytesValue&& from) noexcept
+    : BytesValue() {
+    *this = ::std::move(from);
+  }
+
+  inline BytesValue& operator=(const BytesValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline BytesValue& operator=(BytesValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const BytesValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const BytesValue* internal_default_instance() {
+    return reinterpret_cast<const BytesValue*>(
+               &_BytesValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    8;
+
+  friend void swap(BytesValue& a, BytesValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(BytesValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(BytesValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  BytesValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<BytesValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const BytesValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const BytesValue& from) {
+    BytesValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(BytesValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.BytesValue";
+  }
+  protected:
+  explicit BytesValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // bytes value = 1;
+  void clear_value();
+  const std::string& value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_value();
+  PROTOBUF_NODISCARD std::string* release_value();
+  void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.BytesValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// DoubleValue
+
+// double value = 1;
+inline void DoubleValue::clear_value() {
+  _impl_.value_ = 0;
+}
+inline double DoubleValue::_internal_value() const {
+  return _impl_.value_;
+}
+inline double DoubleValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DoubleValue.value)
+  return _internal_value();
+}
+inline void DoubleValue::_internal_set_value(double value) {
+  
+  _impl_.value_ = value;
+}
+inline void DoubleValue::set_value(double value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DoubleValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// FloatValue
+
+// float value = 1;
+inline void FloatValue::clear_value() {
+  _impl_.value_ = 0;
+}
+inline float FloatValue::_internal_value() const {
+  return _impl_.value_;
+}
+inline float FloatValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FloatValue.value)
+  return _internal_value();
+}
+inline void FloatValue::_internal_set_value(float value) {
+  
+  _impl_.value_ = value;
+}
+inline void FloatValue::set_value(float value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FloatValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// Int64Value
+
+// int64 value = 1;
+inline void Int64Value::clear_value() {
+  _impl_.value_ = int64_t{0};
+}
+inline int64_t Int64Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline int64_t Int64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int64Value.value)
+  return _internal_value();
+}
+inline void Int64Value::_internal_set_value(int64_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void Int64Value::set_value(int64_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Int64Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// UInt64Value
+
+// uint64 value = 1;
+inline void UInt64Value::clear_value() {
+  _impl_.value_ = uint64_t{0u};
+}
+inline uint64_t UInt64Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline uint64_t UInt64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt64Value.value)
+  return _internal_value();
+}
+inline void UInt64Value::_internal_set_value(uint64_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void UInt64Value::set_value(uint64_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt64Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// Int32Value
+
+// int32 value = 1;
+inline void Int32Value::clear_value() {
+  _impl_.value_ = 0;
+}
+inline int32_t Int32Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline int32_t Int32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int32Value.value)
+  return _internal_value();
+}
+inline void Int32Value::_internal_set_value(int32_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void Int32Value::set_value(int32_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Int32Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// UInt32Value
+
+// uint32 value = 1;
+inline void UInt32Value::clear_value() {
+  _impl_.value_ = 0u;
+}
+inline uint32_t UInt32Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline uint32_t UInt32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt32Value.value)
+  return _internal_value();
+}
+inline void UInt32Value::_internal_set_value(uint32_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void UInt32Value::set_value(uint32_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt32Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// BoolValue
+
+// bool value = 1;
+inline void BoolValue::clear_value() {
+  _impl_.value_ = false;
+}
+inline bool BoolValue::_internal_value() const {
+  return _impl_.value_;
+}
+inline bool BoolValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BoolValue.value)
+  return _internal_value();
+}
+inline void BoolValue::_internal_set_value(bool value) {
+  
+  _impl_.value_ = value;
+}
+inline void BoolValue::set_value(bool value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.BoolValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// StringValue
+
+// string value = 1;
+inline void StringValue::clear_value() {
+  _impl_.value_.ClearToEmpty();
+}
+inline const std::string& StringValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
+  return _internal_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void StringValue::set_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
+}
+inline std::string* StringValue::mutable_value() {
+  std::string* _s = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
+  return _s;
+}
+inline const std::string& StringValue::_internal_value() const {
+  return _impl_.value_.Get();
+}
+inline void StringValue::_internal_set_value(const std::string& value) {
+  
+  _impl_.value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* StringValue::_internal_mutable_value() {
+  
+  return _impl_.value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* StringValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value)
+  return _impl_.value_.Release();
+}
+inline void StringValue::set_allocated_value(std::string* value) {
+  if (value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.value_.SetAllocated(value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.value_.IsDefault()) {
+    _impl_.value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// BytesValue
+
+// bytes value = 1;
+inline void BytesValue::clear_value() {
+  _impl_.value_.ClearToEmpty();
+}
+inline const std::string& BytesValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
+  return _internal_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void BytesValue::set_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
+}
+inline std::string* BytesValue::mutable_value() {
+  std::string* _s = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
+  return _s;
+}
+inline const std::string& BytesValue::_internal_value() const {
+  return _impl_.value_.Get();
+}
+inline void BytesValue::_internal_set_value(const std::string& value) {
+  
+  _impl_.value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* BytesValue::_internal_mutable_value() {
+  
+  return _impl_.value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* BytesValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value)
+  return _impl_.value_.Release();
+}
+inline void BytesValue::set_allocated_value(std::string* value) {
+  if (value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.value_.SetAllocated(value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.value_.IsDefault()) {
+    _impl_.value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fwrappers_2eproto
diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto
new file mode 100644
index 0000000..d49dd53
--- /dev/null
+++ b/src/google/protobuf/wrappers.proto
@@ -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.
+
+// Wrappers for primitive (non-message) types. These types are useful
+// for embedding primitives in the `google.protobuf.Any` type and for places
+// where we need to distinguish between the absence of a primitive
+// typed field and its default value.
+//
+// These wrappers have no meaningful use within repeated fields as they lack
+// the ability to detect presence on individual elements.
+// These wrappers have no meaningful use within a map or a oneof since
+// individual entries of a map or fields of a oneof can already detect presence.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/wrapperspb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "WrappersProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// Wrapper message for `double`.
+//
+// The JSON representation for `DoubleValue` is JSON number.
+message DoubleValue {
+  // The double value.
+  double value = 1;
+}
+
+// Wrapper message for `float`.
+//
+// The JSON representation for `FloatValue` is JSON number.
+message FloatValue {
+  // The float value.
+  float value = 1;
+}
+
+// Wrapper message for `int64`.
+//
+// The JSON representation for `Int64Value` is JSON string.
+message Int64Value {
+  // The int64 value.
+  int64 value = 1;
+}
+
+// Wrapper message for `uint64`.
+//
+// The JSON representation for `UInt64Value` is JSON string.
+message UInt64Value {
+  // The uint64 value.
+  uint64 value = 1;
+}
+
+// Wrapper message for `int32`.
+//
+// The JSON representation for `Int32Value` is JSON number.
+message Int32Value {
+  // The int32 value.
+  int32 value = 1;
+}
+
+// Wrapper message for `uint32`.
+//
+// The JSON representation for `UInt32Value` is JSON number.
+message UInt32Value {
+  // The uint32 value.
+  uint32 value = 1;
+}
+
+// Wrapper message for `bool`.
+//
+// The JSON representation for `BoolValue` is JSON `true` and `false`.
+message BoolValue {
+  // The bool value.
+  bool value = 1;
+}
+
+// Wrapper message for `string`.
+//
+// The JSON representation for `StringValue` is JSON string.
+message StringValue {
+  // The string value.
+  string value = 1;
+}
+
+// Wrapper message for `bytes`.
+//
+// The JSON representation for `BytesValue` is JSON string.
+message BytesValue {
+  // The bytes value.
+  bytes value = 1;
+}
diff --git a/src/libprotobuf-lite.map b/src/libprotobuf-lite.map
new file mode 100644
index 0000000..3915546
--- /dev/null
+++ b/src/libprotobuf-lite.map
@@ -0,0 +1,9 @@
+{
+  global:
+    extern "C++" {
+      *google*;
+    };
+
+  local:
+    *;
+};
diff --git a/src/libprotobuf.map b/src/libprotobuf.map
new file mode 100644
index 0000000..3915546
--- /dev/null
+++ b/src/libprotobuf.map
@@ -0,0 +1,9 @@
+{
+  global:
+    extern "C++" {
+      *google*;
+    };
+
+  local:
+    *;
+};
diff --git a/src/libprotoc.map b/src/libprotoc.map
new file mode 100644
index 0000000..3915546
--- /dev/null
+++ b/src/libprotoc.map
@@ -0,0 +1,9 @@
+{
+  global:
+    extern "C++" {
+      *google*;
+    };
+
+  local:
+    *;
+};
diff --git a/src/solaris/libstdc++.la b/src/solaris/libstdc++.la
new file mode 100644
index 0000000..3edf425
--- /dev/null
+++ b/src/solaris/libstdc++.la
@@ -0,0 +1,51 @@
+# libstdc++.la - a libtool library file
+# Generated by ltmain.sh - GNU libtool 1.4a-GCC3.0 (1.641.2.256 2001/05/28 20:09:07 with GCC-local changes)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# ---
+# NOTE: This file lives in /usr/sfw/lib on Solaris 10.  Unfortunately,
+# due to an apparent bug in the Solaris 10 6/06 release,
+# /usr/sfw/lib/libstdc++.la is empty.  Below is the correct content,
+# according to
+#    http://forum.java.sun.com/thread.jspa?threadID=5073150
+# By passing LDFLAGS='-Lsrc/solaris' to configure, make will pick up
+# this copy of the file rather than the empty copy in /usr/sfw/lib.
+#
+# Also see
+#   http://www.technicalarticles.org/index.php/Compiling_MySQL_5.0_on_Solaris_10
+#
+# Note: this is for 32-bit systems.  If you have a 64-bit system,
+# uncomment the appropriate dependency_libs line below.
+# ----
+
+# The name that we can dlopen(3).
+dlname='libstdc++.so.6'
+
+# Names of this library.
+library_names='libstdc++.so.6.0.3 libstdc++.so.6 libstdc++.so'
+
+# The name of the static archive.
+old_library='libstdc++.a'
+
+# Libraries that this one depends upon.
+# 32-bit version:
+dependency_libs='-lc -lm -L/usr/sfw/lib -lgcc_s'
+# 64-bit version:
+#dependency_libs='-L/lib/64 -lc -lm -L/usr/sfw/lib/64 -lgcc_s'
+
+# Version information for libstdc++.
+current=6
+age=0
+revision=3
+
+# Is this an already installed library?
+installed=yes
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/usr/sfw/lib'